Javascript ES6, 229 * 80% * 75% * 50% = 68.7 bytes
===
Test Input
--
I'm using the following test data:

    var A1=[
      5,6,7,            // => 5-7     # (a) group pages 
      2,3,              // => 2-3,5-7 # (b) must be properly sorted
      -9,-8,-7,         // => -10--8  # (c) allow negative numbers
      29,30,31,32,      // => 29-2    # (d) lower last digit implies increasing the 10s place
      9,10,11,12,       // => 9-11    # NOT 9-2
      36,37,38,39,40,41,42,43,44,45,46,47, 
                        // => 36-47   # NOT 36-7
      99,100,101,102,   // => 99-102  # NOT 99-2
      109,110,111,112,  // => 109-2   # NOT 109-12
    ],
    // more tests, not specified in the question
    A2=[
      120,124,       // => 120,124 # (e) handle single pages
    ],
    A3=[
      135,136,135    // => 135-6   # (f) handle duplicates
    ];

Basic: 229 bytes
---    
This version satisfies the requirements of the question (a) with all bonuses (c,d,e), but hangs on single pages. It can also handle duplicates(f)

    F=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e9+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
    F(A1.concat(A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 135-136

(The output above shows spaces instead of actual newlines for brevity)

Single pages: 233 bytes
--

This slightly longer version additionally satisfies (e) and displays single pages as a range with equal lower and upper limits

    G=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e9+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u-l&u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
    G(A1.concat(A2,A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 120 124