credit for unused portion at cancellation, patch from pbowen
authorivan <ivan>
Wed, 19 Jan 2005 21:25:43 +0000 (21:25 +0000)
committerivan <ivan>
Wed, 19 Jan 2005 21:25:43 +0000 (21:25 +0000)
14 files changed:
FS/FS/cust_pkg.pm
FS/FS/part_pkg/flat.pm
FS/FS/part_pkg/flat_comission.pm
FS/FS/part_pkg/flat_comission_cust.pm
FS/FS/part_pkg/flat_comission_pkg.pm
FS/FS/part_pkg/flat_delayed.pm
FS/FS/part_pkg/prorate.pm
FS/FS/part_pkg/sesmon_hour.pm
FS/FS/part_pkg/sesmon_minute.pm
FS/FS/part_pkg/sql_external.pm
FS/FS/part_pkg/sql_generic.pm
FS/FS/part_pkg/sqlradacct_hour.pm
FS/FS/part_pkg/subscription.pm
FS/FS/part_pkg/voip_sqlradacct.pm

index 5705ac2..56da5c7 100644 (file)
@@ -376,6 +376,16 @@ sub cancel {
     }
   }
 
+  # Add a credit for remaining service
+  my $remaining_value= $self->calc_remain();
+  if ($remaining_value > 0) {
+    my $error = $self->credit($remaining_value, 'Credit for service remaining');
+    if ($error) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error crediting customer for service remaining: $error";
+    }                                                                          
+  }                                                                            
+
   unless ( $self->getfield('cancel') ) {
     my %hash = $self->hash;
     $hash{'cancel'} = time;
@@ -592,6 +602,30 @@ sub calc_recur {
   $self->part_pkg->calc_recur($self, @_);
 }
 
+=item calc_remain
+
+Calls the I<calc_remain> of the FS::part_pkg object associated with this
+billing item.
+
+=cut
+
+sub calc_recur {
+  my $self = shift;
+  $self->part_pkg->calc_remain($self, @_);
+}
+
+=item calc_cancel
+
+Calls the I<calc_cancel> of the FS::part_pkg object associated with this
+billing item.
+
+=cut
+
+sub calc_cancel {
+  my $self = shift;
+  $self->part_pkg->calc_cancel($self, @_);
+}
+
 =item cust_svc [ SVCPART ]
 
 Returns the services for this package, as FS::cust_svc objects (see
index 5721edd..131f850 100644 (file)
@@ -10,14 +10,18 @@ use FS::part_pkg;
 %info = (
   'name' => 'Flat rate (anniversary billing)',
   'fields' => {
-    'setup_fee' => { 'name' => 'Setup fee for this package',
-                     'default' => 0,
-                   },
-    'recur_fee' => { 'name' => 'Recurring fee for this package',
-                     'default' => 0,
-                    },
+    'setup_fee'     => { 'name' => 'Setup fee for this package',
+                         'default' => 0,
+                       },
+    'recur_fee'     => { 'name' => 'Recurring fee for this package',
+                         'default' => 0,
+                       },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
   },
-  'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+  'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit' ],
   #'setup' => 'what.setup_fee.value',
   #'recur' => 'what.recur_fee.value',
   'weight' => 10,
@@ -38,6 +42,37 @@ sub base_recur {
   $self->option('recur_fee');
 }
 
+sub calc_remain {
+  my ($self, $cust_pkg) = @_;
+  my $time = time;
+  my $next_bill = $cust_pkg->getfield('bill') || 0;
+  my $last_bill = $cust_pkg->last_bill || 0;
+  return 0 if    ! $self->base_recur
+              || ! $self->option('unused_credit')
+              || ! $last_bill
+              || ! $next_bill;
+
+  my $now_date = ParseDate("epoch $time");
+  my $last_date = ParseDate("epoch $last_bill");
+  my $next_date = ParseDate("epoch $next_bill");
+  my $err;
+  my $delta = DateCalc($now_date,$next_date,\$err, 0);
+  my $days_remaining = Delta_Format($delta, 4, "%dh");
+
+  my $frequency = $self->freq;
+
+  # TODO: Remove this after the frequencies are Data::Manip friendly.
+  $frequency .= "m" unless $frequency =~ /[wd]$/;
+
+  my $freq_delta = ParseDateDelta($frequency);
+  my $days = Delta_Format($freq_delta,4,"%dh");
+
+  my $recurring= $self->base_recur;
+  my $daily =  $recurring/$days;
+
+  sprintf("%.2f",($daily * $days_remaining));
+}
+
 sub is_free_options {
   qw( setup_fee recur_fee );
 }
index 9b288c3..21c03c2 100644 (file)
@@ -8,25 +8,29 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Flat rate with recurring commission per (any) active package',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                     },
-      'comission_amount' => { 'name' => 'Commission amount per month (per active package)',
-                              'default' => 0,
-                            },
-      'comission_depth'  => { 'name' => 'Number of layers',
-                              'default' => 1,
-                            },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
-    'weight' => 62,
+  'name' => 'Flat rate with recurring commission per (any) active package',
+  'fields' => {
+    'setup_fee'     => { 'name' => 'Setup fee for this package',
+                         'default' => 0,
+                       },
+    'recur_fee'     => { 'name' => 'Recurring fee for this package',
+                         'default' => 0,
+                       },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'comission_amount' => { 'name' => 'Commission amount per month (per active package)',
+                            'default' => 0,
+                          },
+    'comission_depth'  => { 'name' => 'Number of layers',
+                            'default' => 1,
+                          },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit', 'comission_depth', 'comission_amount' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+  'weight' => 62,
 );
 
 sub calc_recur {
index 8aa993c..27a93ff 100644 (file)
@@ -8,25 +8,29 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Flat rate with recurring commission per active customer',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                     },
-      'comission_amount' => { 'name' => 'Commission amount per month (per active customer)',
-                              'default' => 0,
-                            },
-      'comission_depth'  => { 'name' => 'Number of layers',
-                              'default' => 1,
-                            },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_main_ncancelled(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
-    'weight' => '60',
+  'name' => 'Flat rate with recurring commission per active customer',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_fee' => { 'name' => 'Recurring fee for this package',
+                     'default' => 0,
+                   },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'comission_amount' => { 'name' => 'Commission amount per month (per active customer)',
+                            'default' => 0,
+                          },
+    'comission_depth'  => { 'name' => 'Number of layers',
+                            'default' => 1,
+                          },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit', 'comission_depth', 'comission_amount' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar($cust_pkg->cust_main->referral_cust_main_ncancelled(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+  'weight' => '60',
 );
 
 sub calc_recur {
index befa77e..20d235c 100644 (file)
@@ -8,33 +8,37 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Flat rate with recurring commission per (selected) active package',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                     },
-      'comission_amount' => { 'name' => 'Commission amount per month (per uncancelled package)',
-                              'default' => 0,
-                            },
-      'comission_depth'  => { 'name' => 'Number of layers',
-                              'default' => 1,
-                            },
-      'comission_pkgpart' => { 'name' => 'Applicable packages<BR><FONT SIZE="-1">(hold <b>ctrl</b> to select multiple packages)</FONT>',
-                               'type' => 'select_multiple',
-                               'select_table' => 'part_pkg',
-                               'select_hash'  => { 'disabled' => '' } ,
-                               'select_key'   => 'pkgpart',
-                               'select_label' => 'pkg',
-                             },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_fee', 'comission_depth', 'comission_amount', 'comission_pkgpart' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '""; var pkgparts = ""; for ( var c=0; c < document.flat_comission_pkg.comission_pkgpart.options.length; c++ ) { if (document.flat_comission_pkg.comission_pkgpart.options[c].selected) { pkgparts = pkgparts + document.flat_comission_pkg.comission_pkgpart.options[c].value + \', \'; } } what.recur.value = \'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar( grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } ( \' + pkgparts + \'  ) } $cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
-    #'disabled' => 1,
-    'weight' => '64',
+  'name' => 'Flat rate with recurring commission per (selected) active package',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_fee' => { 'name' => 'Recurring fee for this package',
+                     'default' => 0,
+                   },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'comission_amount' => { 'name' => 'Commission amount per month (per uncancelled package)',
+                            'default' => 0,
+                          },
+    'comission_depth'  => { 'name' => 'Number of layers',
+                            'default' => 1,
+                          },
+    'comission_pkgpart' => { 'name' => 'Applicable packages<BR><FONT SIZE="-1">(hold <b>ctrl</b> to select multiple packages)</FONT>',
+                             'type' => 'select_multiple',
+                             'select_table' => 'part_pkg',
+                             'select_hash'  => { 'disabled' => '' } ,
+                             'select_key'   => 'pkgpart',
+                             'select_label' => 'pkg',
+                           },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit', 'comission_depth', 'comission_amount', 'comission_pkgpart' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '""; var pkgparts = ""; for ( var c=0; c < document.flat_comission_pkg.comission_pkgpart.options.length; c++ ) { if (document.flat_comission_pkg.comission_pkgpart.options[c].selected) { pkgparts = pkgparts + document.flat_comission_pkg.comission_pkgpart.options[c].value + \', \'; } } what.recur.value = \'my $error = $cust_pkg->cust_main->credit( \' + what.comission_amount.value + \' * scalar( grep { my $pkgpart = $_->pkgpart; grep { $_ == $pkgpart } ( \' + pkgparts + \'  ) } $cust_pkg->cust_main->referral_cust_pkg(\' + what.comission_depth.value+ \')), "commission" ); die $error if $error; \' + what.recur_fee.value + \';\'',
+  #'disabled' => 1,
+  'weight' => '64',
 );
 
 # XXX this needs to be fixed!!!
index f39783f..4a04583 100644 (file)
@@ -8,23 +8,27 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Free (or setup fee) for X days, then flat rate'.
-              ' (anniversary billing)',
-    'fields' =>  {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'free_days' => { 'name' => 'Initial free days',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                      },
-    },
-    'fieldorder' => [ 'free_days', 'setup_fee', 'recur_fee' ],
-    #'setup' => '\'my $d = $cust_pkg->bill || $time; $d += 86400 * \' + what.free_days.value + \'; $cust_pkg->bill($d); $cust_pkg_mod_flag=1; \' + what.setup_fee.value',
-    #'recur' => 'what.recur_fee.value',
-    'weight' => 50,
+  'name' => 'Free (or setup fee) for X days, then flat rate'.
+            ' (anniversary billing)',
+  'fields' =>  {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'free_days' => { 'name' => 'Initial free days',
+                     'default' => 0,
+                   },
+    'recur_fee' => { 'name' => 'Recurring fee for this package',
+                     'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+  },
+  'fieldorder' => [ 'free_days', 'setup_fee', 'recur_fee', 'unused_credit' ],
+  #'setup' => '\'my $d = $cust_pkg->bill || $time; $d += 86400 * \' + what.free_days.value + \'; $cust_pkg->bill($d); $cust_pkg_mod_flag=1; \' + what.setup_fee.value',
+  #'recur' => 'what.recur_fee.value',
+  'weight' => 50,
 );
 
 sub calc_setup {
index d27adbd..f8a4826 100644 (file)
@@ -9,20 +9,24 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'First partial month pro-rated, then flat-rate (1st of month billing)',
-    'fields' =>  {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                      },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_fee' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; my $mstart = timelocal(0,0,0,1,$mon,$year); my $mend = timelocal(0,0,0,1, $mon == 11 ? 0 : $mon+1, $year+($mon==11)); $sdate = $mstart; ( $part_pkg->freq - 1 ) * \' + what.recur_fee.value + \' / $part_pkg->freq + \' + what.recur_fee.value + \' / $part_pkg->freq * ($mend-$mnow) / ($mend-$mstart) ; \'',
-    'freq' => 'm',
-    'weight' => 20,
+  'name' => 'First partial month pro-rated, then flat-rate (1st of month billing)',
+  'fields' =>  {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_fee' => { 'name' => 'Recurring fee for this package',
+                     'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_fee', 'unused_credit' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; my $mstart = timelocal(0,0,0,1,$mon,$year); my $mend = timelocal(0,0,0,1, $mon == 11 ? 0 : $mon+1, $year+($mon==11)); $sdate = $mstart; ( $part_pkg->freq - 1 ) * \' + what.recur_fee.value + \' / $part_pkg->freq + \' + what.recur_fee.value + \' / $part_pkg->freq * ($mend-$mnow) / ($mend-$mstart) ; \'',
+  'freq' => 'm',
+  'weight' => 20,
 );
 
 sub calc_recur {
index 1f62631..41c7f25 100644 (file)
@@ -8,25 +8,29 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Base charge plus charge per-hour from the session monitor',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'recur_included_hours' => { 'name' => 'Hours included',
-                                  'default' => 0,
-                                },
-      'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
-                                 'default' => 0,
-                               },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $hours = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'',
-    'weight' => 80,
+  'name' => 'Base charge plus charge per-hour from the session monitor',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_flat' => { 'name' => 'Base monthly charge for this package',
+                      'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'recur_included_hours' => { 'name' => 'Hours included',
+                                'default' => 0,
+                              },
+    'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
+                               'default' => 0,
+                             },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_flat', 'unused_credit', 'recur_included_hours', 'recur_hourly_charge' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $hours = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'',
+  'weight' => 80,
 );
 
 sub calc_recur {
index 86affa7..fd90235 100644 (file)
@@ -8,25 +8,29 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Base charge plus charge per-minute from the session monitor',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'recur_included_min' => { 'name' => 'Minutes included',
-                                'default' => 0,
-                                },
-      'recur_minly_charge' => { 'name' => 'Additional charge per minute',
-                                'default' => 0,
+  'name' => 'Base charge plus charge per-minute from the session monitor',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_flat' => { 'name' => 'Base monthly charge for this package',
+                      'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'recur_included_min' => { 'name' => 'Minutes included',
+                              'default' => 0,
                               },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_min', 'recur_minly_charge' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $min = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 60 - \' + what.recur_included_min.value + \'; $min = 0 if $min < 0; \' + what.recur_flat.value + \' + \' + what.recur_minly_charge.value + \' * $min;\'',
-    'weight' => 80,
+    'recur_minly_charge' => { 'name' => 'Additional charge per minute',
+                              'default' => 0,
+                            },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_flat', 'unused_credit', 'recur_included_min', 'recur_minly_charge' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $min = $cust_pkg->seconds_since($cust_pkg->bill || 0) / 60 - \' + what.recur_included_min.value + \'; $min = 0 if $min < 0; \' + what.recur_flat.value + \' + \' + what.recur_minly_charge.value + \' * $min;\'',
+  'weight' => 80,
 );
 
 
index 96071fa..28a4897 100644 (file)
@@ -9,31 +9,35 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Base charge plus additional fees for external services from a configurable SQL query',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'datasrc' => { 'name' => 'DBI data source',
-                     'default' => '',
+  'name' => 'Base charge plus additional fees for external services from a configurable SQL query',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
                    },
-      'db_username' => { 'name' => 'Database username',
-                         'default' => '',
-                       },
-      'db_password' => { 'name' => 'Database password',
-                         'default' => '',
+    'recur_flat' => { 'name' => 'Base monthly charge for this package',
+                      'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
                        },
-      'query' => { 'name' => 'SQL query',
+    'datasrc' => { 'name' => 'DBI data source',
                    'default' => '',
                  },
-    },
-    'fieldorder' => [qw( setup_fee recur_flat datasrc db_username db_password query )],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => q!'my $dbh = DBI->connect("' + what.datasrc.value + '", "' + what.db_username.value + '", "' + what.db_password.value + '" ) or die $DBI::errstr; my $sth = $dbh->prepare("' + what.query.value + '") or die $dbh->errstr; my $price = ' + what.recur_flat.value + '; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_external" } $cust_pkg->cust_svc ){ my $id = $cust_svc->svc_x->id; $sth->execute($id) or die $sth->errstr; $price += $sth->fetchrow_arrayref->[0]; } $price;'!,
-    'weight' => '72',
+    'db_username' => { 'name' => 'Database username',
+                       'default' => '',
+                     },
+    'db_password' => { 'name' => 'Database password',
+                       'default' => '',
+                     },
+    'query' => { 'name' => 'SQL query',
+                 'default' => '',
+               },
+  },
+  'fieldorder' => [qw( setup_fee recur_flat unused_credit datasrc db_username db_password query )],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => q!'my $dbh = DBI->connect("' + what.datasrc.value + '", "' + what.db_username.value + '", "' + what.db_password.value + '" ) or die $DBI::errstr; my $sth = $dbh->prepare("' + what.query.value + '") or die $dbh->errstr; my $price = ' + what.recur_flat.value + '; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_external" } $cust_pkg->cust_svc ){ my $id = $cust_svc->svc_x->id; $sth->execute($id) or die $sth->errstr; $price += $sth->fetchrow_arrayref->[0]; } $price;'!,
+  'weight' => '72',
 );
 
 sub calc_recur {
index d1233e9..646957c 100644 (file)
@@ -9,39 +9,43 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Base charge plus a per-domain metered rate from a configurable SQL query',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'recur_included' => { 'name' => 'Units included',
-                            'default' => 0,
-                          },
-      'recur_unit_charge' => { 'name' => 'Additional charge per unit',
-                               'default' => 0,
-                             },
-      'datasrc' => { 'name' => 'DBI data source',
-                     'default' => '',
+  'name' => 'Base charge plus a per-domain metered rate from a configurable SQL query',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
                    },
-      'db_username' => { 'name' => 'Database username',
-                         'default' => '',
-                       },
-      'db_password' => { 'name' => 'Database username',
-                         'default' => '',
+    'recur_flat' => { 'name' => 'Base monthly charge for this package',
+                      'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
                        },
-      'query' => { 'name' => 'SQL query',
+    'recur_included' => { 'name' => 'Units included',
+                          'default' => 0,
+                        },
+    'recur_unit_charge' => { 'name' => 'Additional charge per unit',
+                             'default' => 0,
+                           },
+    'datasrc' => { 'name' => 'DBI data source',
                    'default' => '',
                  },
-    },
-    'fieldorder' => [qw( setup_fee recur_flat recur_included recur_unit_charge datasrc db_username db_password query )],
-   # 'setup' => 'what.setup_fee.value',
-   # 'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\") or die $DBI::errstr; \'',
-   #'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\", \"\' + what.db_password.value + \'\" ) or die $DBI::errstr; my $sth = $dbh->prepare(\"\' + what.query.value + \'\") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq \"svc_domain\" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge.value + \';\'',
-    #'recur' => '\'my $dbh = DBI->connect("\' + what.datasrc.value + \'", "\' + what.db_username.value + \'", "\' what.db_password.value + \'" ) or die $DBI::errstr; my $sth = $dbh->prepare("\' + what.query.value + \'") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_domain" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge + \';\'',
-    'weight' => '70',
+    'db_username' => { 'name' => 'Database username',
+                       'default' => '',
+                     },
+    'db_password' => { 'name' => 'Database username',
+                       'default' => '',
+                     },
+    'query' => { 'name' => 'SQL query',
+                 'default' => '',
+               },
+  },
+  'fieldorder' => [qw( setup_fee recur_flat unused_credit recur_included recur_unit_charge datasrc db_username db_password query )],
+ # 'setup' => 'what.setup_fee.value',
+ # 'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\") or die $DBI::errstr; \'',
+ #'recur' => '\'my $dbh = DBI->connect(\"\' + what.datasrc.value + \'\", \"\' + what.db_username.value + \'\", \"\' + what.db_password.value + \'\" ) or die $DBI::errstr; my $sth = $dbh->prepare(\"\' + what.query.value + \'\") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq \"svc_domain\" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge.value + \';\'',
+  #'recur' => '\'my $dbh = DBI->connect("\' + what.datasrc.value + \'", "\' + what.db_username.value + \'", "\' what.db_password.value + \'" ) or die $DBI::errstr; my $sth = $dbh->prepare("\' + what.query.value + \'") or die $dbh->errstr; my $units = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq "svc_domain" } $cust_pkg->cust_svc ) { my $domain = $cust_svc->svc_x->domain; $sth->execute($domain) or die $sth->errstr; $units += $sth->fetchrow_arrayref->[0]; } $units -= \' + what.recur_included.value + \'; $units = 0 if $units < 0; \' + what.recur_flat.value + \' + $units * \' + what.recur_unit_charge + \';\'',
+  'weight' => '70',
 );
 
 sub calc_recur {
index 76533d5..7ecb970 100644 (file)
@@ -8,47 +8,51 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'Base charge plus per-hour (and for data) from an SQL RADIUS radacct table',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'recur_included_hours' => { 'name' => 'Hours included',
-                                  'default' => 0,
-                                },
-      'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
-                                 'default' => 0,
-                               },
-      'recur_included_input' => { 'name' => 'Upload megabytes included',
-                                  'default' => 0,
-                                },
-      'recur_input_charge' => { 'name' =>
-                                        'Additional charge per megabyte upload',
+  'name' => 'Base charge plus per-hour (and for data) from an SQL RADIUS radacct table',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_flat' => { 'name' => 'Base monthly charge for this package',
+                      'default' => 0,
+                    },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'recur_included_hours' => { 'name' => 'Hours included',
                                 'default' => 0,
                               },
-      'recur_included_output' => { 'name' => 'Download megabytes included',
-                                   'default' => 0,
-                                },
-      'recur_output_charge' => { 'name' =>
-                                       'Additional charge per megabyte download',
+    'recur_hourly_charge' => { 'name' => 'Additional charge per hour',
+                               'default' => 0,
+                             },
+    'recur_included_input' => { 'name' => 'Upload megabytes included',
                                 'default' => 0,
                               },
-      'recur_included_total' => { 'name' =>
-                                       'Total megabytes included',
-                                  'default' => 0,
-                                },
-      'recur_total_charge' => { 'name' =>
-                                 'Additional charge per megabyte total',
+    'recur_input_charge' => { 'name' =>
+                                      'Additional charge per megabyte upload',
+                              'default' => 0,
+                            },
+    'recur_included_output' => { 'name' => 'Download megabytes included',
+                                 'default' => 0,
+                              },
+    'recur_output_charge' => { 'name' =>
+                                     'Additional charge per megabyte download',
+                              'default' => 0,
+                            },
+    'recur_included_total' => { 'name' =>
+                                     'Total megabytes included',
                                 'default' => 0,
                               },
-    },
-    'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; my $input = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctInputOctets\" ) / 1048576; my $output = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctOutputOctets\" ) / 1048576; my $total = $input + $output - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; my $totalcharge = sprintf(\"%.2f\", \' + what.recur_total_charge.value + \' * $total); my $inputcharge = sprintf(\"%.2f\", \' + what.recur_input_charge.value + \' * $input); my $outputcharge = sprintf(\"%.2f\", \' + what.recur_output_charge.value + \' * $output); my $hourscharge = sprintf(\"%.2f\", \' + what.recur_hourly_charge.value + \' * $hours); if ( \' + what.recur_total_charge.value + \' > 0 ) { push @details, \"Last month\\\'s data \". sprintf(\"%.1f\", $total). \" megs: \\\$$totalcharge\" } if ( \' + what.recur_input_charge.value + \' > 0 ) { push @details, \"Last month\\\'s download \". sprintf(\"%.1f\", $input). \" megs: \\\$$inputcharge\" } if ( \' + what.recur_output_charge.value + \' > 0 ) { push @details, \"Last month\\\'s upload \". sprintf(\"%.1f\", $output). \" megs: \\\$$outputcharge\" } if ( \' + what.recur_hourly_charge.value + \' > 0 ) { push @details, \"Last month\\\'s time \". sprintf(\"%.1f\", $hours). \" hours: \\\$$hourscharge\"; } \' + what.recur_flat.value + \' + $hourscharge + $inputcharge + $outputcharge + $totalcharge ;\'',
-    'weight' => 40,
+    'recur_total_charge' => { 'name' =>
+                               'Additional charge per megabyte total',
+                              'default' => 0,
+                            },
+  },
+  'fieldorder' => [qw( setup_fee recur_flat unused_credit recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; my $input = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctInputOctets\" ) / 1048576; my $output = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, \"AcctOutputOctets\" ) / 1048576; my $total = $input + $output - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; my $totalcharge = sprintf(\"%.2f\", \' + what.recur_total_charge.value + \' * $total); my $inputcharge = sprintf(\"%.2f\", \' + what.recur_input_charge.value + \' * $input); my $outputcharge = sprintf(\"%.2f\", \' + what.recur_output_charge.value + \' * $output); my $hourscharge = sprintf(\"%.2f\", \' + what.recur_hourly_charge.value + \' * $hours); if ( \' + what.recur_total_charge.value + \' > 0 ) { push @details, \"Last month\\\'s data \". sprintf(\"%.1f\", $total). \" megs: \\\$$totalcharge\" } if ( \' + what.recur_input_charge.value + \' > 0 ) { push @details, \"Last month\\\'s download \". sprintf(\"%.1f\", $input). \" megs: \\\$$inputcharge\" } if ( \' + what.recur_output_charge.value + \' > 0 ) { push @details, \"Last month\\\'s upload \". sprintf(\"%.1f\", $output). \" megs: \\\$$outputcharge\" } if ( \' + what.recur_hourly_charge.value + \' > 0 ) { push @details, \"Last month\\\'s time \". sprintf(\"%.1f\", $hours). \" hours: \\\$$hourscharge\"; } \' + what.recur_flat.value + \' + $hourscharge + $inputcharge + $outputcharge + $totalcharge ;\'',
+  'weight' => 40,
 );
 
 sub calc_recur {
index d057b6b..e03573b 100644 (file)
@@ -9,20 +9,20 @@ use FS::part_pkg;
 @ISA = qw(FS::part_pkg::flat);
 
 %info = (
-    'name' => 'First partial month full charge, then flat-rate (1st of month billing)',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_fee' => { 'name' => 'Recurring fee for this package',
-                       'default' => 0,
-                      },
-    },
-    'fieldorder' => [ 'setup_fee', 'recur_fee' ],
-    #'setup' => 'what.setup_fee.value',
-    #'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; $sdate = timelocal(0,0,0,1,$mon,$year); \' + what.recur_fee.value',
-    'freq' => 'm',
-    'weight' => 30,
+  'name' => 'First partial month full charge, then flat-rate (1st of month billing)',
+  'fields' => {
+    'setup_fee' => { 'name' => 'Setup fee for this package',
+                     'default' => 0,
+                   },
+    'recur_fee' => { 'name' => 'Recurring fee for this package',
+                     'default' => 0,
+                   },
+  },
+  'fieldorder' => [ 'setup_fee', 'recur_fee' ],
+  #'setup' => 'what.setup_fee.value',
+  #'recur' => '\'my $mnow = $sdate; my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate) )[0,1,2,3,4,5]; $sdate = timelocal(0,0,0,1,$mon,$year); \' + what.recur_fee.value',
+  'freq' => 'm',
+  'weight' => 30,
 );
 
 sub calc_recur {
index b9db39f..a6a3a38 100644 (file)
@@ -7,31 +7,35 @@ use FS::part_pkg;
 #use FS::rate;
 use FS::rate_prefix;
 
-@ISA = qw(FS::part_pkg);
+@ISA = qw(FS::part_pkg::flat);
 
 $DEBUG = 1;
 
 %info = (
-    'name' => 'VoIP rating by plan of CDR records in an SQL RADIUS radacct table',
-    'fields' => {
-      'setup_fee' => { 'name' => 'Setup fee for this package',
-                       'default' => 0,
-                     },
-      'recur_flat' => { 'name' => 'Base monthly charge for this package',
-                        'default' => 0,
-                      },
-      'ratenum'   => { 'name' => 'Rate plan',
-                       'type' => 'select',
-                       'select_table' => 'rate',
-                       'select_key'   => 'ratenum',
-                       'select_label' => 'ratename',
-                     },
-      'ignore_unrateable' => { 'name' => 'Ignore calls for which not rate prefix can be found (otherwise they are fatal)',
-                               'type' => 'checkbox',
-                             },
-    },
-    'fieldorder' => [qw( setup_fee recur_flat ratenum ignore_unrateable )],
-    'weight' => 40,
+  'name' => 'VoIP rating by plan of CDR records in an SQL RADIUS radacct table',
+  'fields' => {
+    'setup_fee'     => { 'name' => 'Setup fee for this package',
+                         'default' => 0,
+                       },
+    'recur_flat'     => { 'name' => 'Base monthly charge for this package',
+                          'default' => 0,
+                        },
+    'unused_credit' => { 'name' => 'Credit the customer for the unused portion'.
+                                   ' of service at cancellation',
+                         'type' => 'checkbox',
+                       },
+    'ratenum'   => { 'name' => 'Rate plan',
+                     'type' => 'select',
+                     'select_table' => 'rate',
+                     'select_key'   => 'ratenum',
+                     'select_label' => 'ratename',
+                   },
+    'ignore_unrateable' => { 'name' => 'Ignore calls for which not rate prefix can be found (otherwise they are fatal)',
+                             'type' => 'checkbox',
+                           },
+  },
+  'fieldorder' => [qw( setup_fee recur_flat unused_credit ratenum ignore_unrateable )],
+  'weight' => 40,
 );
 
 sub calc_setup {