[freeside-commits] branch master updated. 013646e6629fc94b4cda03c495aa56677f2de381

Ivan ivan at 420.am
Sat Jan 4 23:31:20 PST 2014


The branch, master has been updated
       via  013646e6629fc94b4cda03c495aa56677f2de381 (commit)
      from  0ce4ba640f3c216a37d78296a0e9d4dd262df2d9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 013646e6629fc94b4cda03c495aa56677f2de381
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Sat Jan 4 23:31:16 2014 -0800

    time/data/etc. unit pricing add-ons, RT#24392

diff --git a/FS/FS.pm b/FS/FS.pm
index 71a7a2f..3ff3656 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -255,6 +255,8 @@ L<FS::part_pkg> - Package definition class
 
 L<FS::part_pkg_msgcat> - Package definition localization class
 
+L<FS::part_pkg_usageprice> - Package definition usage pricing add-on class
+
 L<FS::part_pkg_currency> - Package definition local currency prices
 
 L<FS::currency_exchange> - Currency exchange rates
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 73320fa..5833d86 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2928,7 +2928,7 @@ sub tables_hashref {
                         ],
     },
 
-   'part_pkg' => {
+    'part_pkg' => {
       'columns' => [
         'pkgpart',       'serial',    '',   '', '', '', 
         'pkg',           'varchar',   '',   $char_d, '', '', 
@@ -3036,6 +3036,26 @@ sub tables_hashref {
       'index'       => [],
     },
 
+    'part_pkg_usageprice' => {
+      'columns' => [
+        'usagepricepart', 'serial',      '',      '', '', '',
+        'pkgpart',           'int',      '',      '', '', '',
+        'price',          @money_type,                '', '', 
+        'currency',         'char',  'NULL',       3, '', '',
+        'action',        'varchar',      '', $char_d, '', '',
+        'target',        'varchar',      '', $char_d, '', '',
+        'amount',        'varchar',      '', $char_d, '', '',
+      ],
+      'primary_key'  => 'usagepricepart',
+      'unique'       => [ [ 'pkgpart', 'currency', 'target' ] ],
+      'index'        => [ [ 'pkgpart' ] ],
+      'foreign_keys' => [
+                          { columns    => [ 'pkgpart' ],
+                            table      => 'part_pkg',
+                          },
+                        ],
+    },
+
     'part_pkg_link' => {
       'columns' => [
         'pkglinknum',  'serial',   '',      '', '', '',
diff --git a/FS/FS/part_pkg_usageprice.pm b/FS/FS/part_pkg_usageprice.pm
new file mode 100644
index 0000000..0fa6bca
--- /dev/null
+++ b/FS/FS/part_pkg_usageprice.pm
@@ -0,0 +1,134 @@
+package FS::part_pkg_usageprice;
+use base qw( FS::Record );
+
+use strict;
+#use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::part_pkg_usageprice - Object methods for part_pkg_usageprice records
+
+=head1 SYNOPSIS
+
+  use FS::part_pkg_usageprice;
+
+  $record = new FS::part_pkg_usageprice \%hash;
+  $record = new FS::part_pkg_usageprice { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_pkg_usageprice object represents a usage pricing add-on.
+FS::part_pkg_usageprice inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item usagepricepart
+
+primary key
+
+=item pkgpart
+
+pkgpart
+
+=item price
+
+price
+
+=item currency
+
+currency
+
+=item action
+
+action
+
+=item target
+
+target
+
+=item amount
+
+amount
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'part_pkg_usageprice'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('usagepricepart')
+    || $self->ut_number('pkgpart')
+    || $self->ut_money('price')
+    || $self->ut_currencyn('currency')
+    || $self->ut_enum('action', [ 'increment', 'set' ])
+    || $self->ut_enum('target', [ 'svc_acct.totalbytes', 'svc_acct.seconds',
+                                  'svc_conferencing.participants',
+                                  'svc_conferencing.confqualitynum'
+                                ]
+                     )
+    || $self->ut_text('amount')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::part_pkg>, L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index 7f8a707..23de7c1 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -59,6 +59,7 @@
                          }
                        $conf->config('currencies')
                    ),
+                   'usagepricepart'   => ' ',
                    'discountnum'      => 'Offer discounts for longer terms',
                    'bill_dst_pkgpart' => 'Include line item(s) from package',
                    'svc_dst_pkgpart'  => 'Include services of package',
@@ -245,6 +246,16 @@
 
                    { type => 'columnend' },
 
+                   { type     => 'tablebreak-tr-title',
+                     value    => 'Usage pricing add-ons', #better name?  just 'Usage pricing' ?  there's also CDR usage pricing, RADIUS usage pricing, etc :/
+                   },
+                   { 'field'     => 'usagepricepart',
+                     'type'      => 'part_pkg_usageprice',
+                     'o2m_table' => 'part_pkg_usageprice',
+                     'm2_label'  => ' ',
+                     'm2_error_callback' => $usageprice_error_callback,
+                   },
+
                    { 'type'  => $report_option ? 'tablebreak-tr-title'
                                                : 'hidden',
                      'value' => 'Optional report classes',
@@ -684,6 +695,28 @@ my $discount_error_callback = sub {
   $cgi->param;
 };
 
+my $usageprice_error_callback = sub {
+  my( $cgi, $object ) = @_;
+  map {
+        if ( /^usagepricepart(\d+)_price$/
+               && $cgi->param("usagepricepart$1_price") )
+        {
+          new FS::part_pkg_usageprice {
+            'usagepricepart' => $cgi->param("usagepricepart$1"),
+            'pkgpart'        => $object->pkgpart,
+            'price'          => scalar($cgi->param("usagepricepart$1_price")),
+            #'currency
+            'action'         => scalar($cgi->param("usagepricepart$1_action")),
+            'target'         => scalar($cgi->param("usagepricepart$1_target")),
+            'amount'         => scalar($cgi->param("usagepricepart$1_amount")),
+          };
+        } else {
+          ();
+        }
+      }
+  $cgi->param;
+};
+
 my $m2_error_callback_maker = sub {
   my $link_type = shift; #yay closures
   return sub {
diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi
index db4fcb9..82c4e1e 100755
--- a/httemplate/edit/process/part_pkg.cgi
+++ b/httemplate/edit/process/part_pkg.cgi
@@ -269,6 +269,10 @@ my @process_o2m = (
     'table'  => 'part_pkg_msgcat',
     'fields' => [qw( locale pkg )],
   },
+  {
+    'table'  => 'part_pkg_usageprice',
+    'fields' => [qw( price currency action target amount )],
+  }
 );
 
 </%init>
diff --git a/httemplate/elements/part_pkg_usageprice.html b/httemplate/elements/part_pkg_usageprice.html
new file mode 100644
index 0000000..5663469
--- /dev/null
+++ b/httemplate/elements/part_pkg_usageprice.html
@@ -0,0 +1,137 @@
+% unless ( $opt{'js_only'} ) {
+
+  <INPUT TYPE="hidden" NAME="<%$name%>" ID="<%$id%>" VALUE="<% $curr_value %>">
+
+  <TABLE STYLE="display:inline">
+    <TR>
+
+%     ###
+%     # price
+%     ###
+      <TD>
+        <TABLE STYLE="display:inline">
+          <TR>
+            <TD>Price</TD>
+            <TD><% $money_char %><INPUT
+              TYPE  = "text"
+              NAME  = "<%$name%>_price"
+              ID    = "<%$id%>_price"
+              VALUE = "<% scalar($cgi->param($name.'_price'))
+                            || $part_pkg_usageprice->price
+                       %>"
+              <% $onchange %>
+            ></TD>
+          </TR>
+
+% #XXX lots more work for multi-currency...  maybe larger UI changes :/
+%         foreach my $currency ( () ) {
+%         #foreach my $currency ( sort $conf->config('currencies') ) {
+            <TR>
+              <TD><% $currency %></TD>
+              <TD><% currency_symbol($currency, SYM_HTML) %><INPUT
+                TYPE  = "text"
+                NAME  = "<%$name%>_price_<%$currency%>"
+                ID    = "<%$id%>_price_<%$currency%>"
+                VALUE = "<% scalar($cgi->param($name.'_price_'.$currency))
+                              || $part_pkg_usageprice->price #XXX
+                         %>"
+                <% $onchange %>
+              ></TD>
+            </TR>
+%         }
+
+        </TABLE>
+      </TD>
+
+%     ###
+%     # action
+%     ###
+      <TD>
+        <SELECT NAME = "<%$name%>_action"
+                ID   = "<%$id%>_action"
+                <% $onchange %>
+        >
+          <OPTION VALUE="increment">Increment
+%#no set yet          <OPTION VALUE="set" <% ($cgi->param($name.'_action') || $part_pkg_usageprice->action) eq 'set' ? 'SELECTED' : '' %>>Set
+        </SELECT>
+      </TD>
+
+%     ###
+%     # target
+%     ###
+      <TD>
+        <SELECT NAME = "<%$name%>_target"
+                ID   = "<%$id%>_target"
+                <% $onchange %>
+        >
+%       foreach my $target (keys %targets) {
+          <OPTION VALUE="<% $target %>"
+                  <% ($cgi->param($name.'_target') || $part_pkg_usageprice->target) eq $target ? 'SELECTED' : '' %>
+          ><% $targets{$target}->{label} %>
+%       }
+      </TD>
+
+%     ###
+%     # amount
+%     ###
+      <TD>
+        <INPUT TYPE = "text"
+               NAME = "<%$name%>_amount"
+               ID   = "<%$id%>_amount"
+               SIZE = 5
+               VALUE = "<% scalar($cgi->param($name.'_amount'))
+                             || $part_pkg_usageprice->amount
+                        %>"
+               <% $onchange %>
+        >
+      </TD>
+
+    </TR>
+  </TABLE>
+
+% }
+<%init>
+
+tie my %targets, 'Tie::IxHash', # once?
+  #'svc_acct.totalbytes' => { label => 'Megabytes',
+  #                           mult  => 1048576,
+  #                         },
+  'svc_acct.totalbytes' => { label => 'Gigabytes',
+                             mult  => 1073741824,
+                           },
+  'svc_acct.seconds' => { label => 'Hours',
+                          mult  => 3600,
+                        },
+  'svc_conferencing.participants' => { label => 'Conference Participants',
+                                       mult  => 1,
+                                     },
+#this will take more work: set action, not increment..
+#  and then value comes from a select, not a text field
+#  'svc_conferencing.confqualitynum' => { label => 'Conference Quality',
+#                                        },
+;
+
+my( %opt ) = @_;
+
+my $conf = new FS::Conf;
+my $money_char = $conf->config('money_char') || '$';
+
+my $name = $opt{'element_name'} || $opt{'field'} || 'usagepricepart';
+my $id = $opt{'id'} || 'usagepricepart';
+
+my $curr_value = $opt{'curr_value'} || $opt{'value'};
+
+my $onchange = '';
+if ( $opt{'onchange'} ) {
+  $onchange = $opt{'onchange'};
+  $onchange .= '(this)' unless $onchange =~ /\(\w*\);?$/;
+  $onchange =~ s/\(what\);/\(this\);/g; #ugh, terrible hack.  all onchange
+                                        #callbacks should act the same
+  $onchange = 'onChange="'. $onchange. '"';
+}
+
+my $part_pkg_usageprice = $curr_value
+  ? qsearchs('part_pkg_usageprice', { 'usagepricepart' => $curr_value } )
+  : new FS::part_pkg_usageprice {};
+
+</%init>
diff --git a/httemplate/elements/tr-part_pkg_usageprice.html b/httemplate/elements/tr-part_pkg_usageprice.html
new file mode 100644
index 0000000..1b78ae4
--- /dev/null
+++ b/httemplate/elements/tr-part_pkg_usageprice.html
@@ -0,0 +1,24 @@
+%   unless ( $opt{'js_only'} ) {
+
+      <% include('tr-td-label.html', %opt) %>
+        <TD <% $cell_style %>>
+
+%   }
+%
+            <% include( '/elements/part_pkg_usageprice.html', %opt ) %>
+%
+%   unless ( $opt{'js_only'} ) {
+
+        </TD>
+      </TR>
+
+%   }
+<%init>
+
+my( %opt ) = @_;
+
+my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : '';
+
+#$opt{'label'} ||= 'XXX Something';
+
+</%init>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS.pm                                           |    2 +
 FS/FS/Schema.pm                                    |   22 +++-
 .../{agent_currency.pm => part_pkg_usageprice.pm}  |   60 ++++++---
 httemplate/edit/part_pkg.cgi                       |   33 +++++
 httemplate/edit/process/part_pkg.cgi               |    4 +
 httemplate/elements/part_pkg_usageprice.html       |  137 ++++++++++++++++++++
 ...tr-contact.html => tr-part_pkg_usageprice.html} |    4 +-
 7 files changed, 241 insertions(+), 21 deletions(-)
 copy FS/FS/{agent_currency.pm => part_pkg_usageprice.pm} (52%)
 create mode 100644 httemplate/elements/part_pkg_usageprice.html
 copy httemplate/elements/{tr-contact.html => tr-part_pkg_usageprice.html} (73%)




More information about the freeside-commits mailing list