bulk DID order/inventory improvements, RT11291
authorlevinse <levinse>
Wed, 6 Apr 2011 08:24:27 +0000 (08:24 +0000)
committerlevinse <levinse>
Wed, 6 Apr 2011 08:24:27 +0000 (08:24 +0000)
15 files changed:
FS/FS.pm
FS/FS/Mason.pm
FS/FS/Schema.pm
FS/FS/did_order.pm
FS/FS/did_order_item.pm [new file with mode: 0644]
FS/FS/phone_avail.pm
FS/MANIFEST
FS/t/did_order_item.t [new file with mode: 0644]
httemplate/browse/did_order.html
httemplate/edit/did_order.html
httemplate/edit/elements/edit.html
httemplate/edit/process/did_order.html
httemplate/elements/did_order_item.html [new file with mode: 0644]
httemplate/elements/tr-did_order_item.html [new file with mode: 0644]
httemplate/misc/phone_avail-import.html

index 9a4fbce..0f06f4d 100644 (file)
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -172,6 +172,8 @@ L<FS::did_vendor> - Bulk DID order vendor class
 
 L<FS::did_order> - Bulk DID order class
 
+L<FS::did_order_item> - Bulk DID order item class
+
 L<FS::cdr> - Call Detail Record class
 
 L<FS::cdr_batch> - Call Detail Record batch class
index dd18717..db54ecb 100644 (file)
@@ -278,6 +278,7 @@ if ( -e $addl_handler_use_file ) {
   use FS::hardware_class;
   use FS::hardware_type;
   use FS::hardware_status;
+  use FS::did_order_item;
   # Sammath Naur
 
   if ( $FS::Mason::addl_handler_use ) {
index 66847b6..06406e6 100644 (file)
@@ -3092,6 +3092,8 @@ sub tables_hashref {
         'station',     'char',    'NULL',       4, '', '',
         'name',        'varchar', 'NULL', $char_d, '', '',
         'rate_center_abbrev', 'varchar', 'NULL', $char_d, '', '',
+        'latanum',      'int',     'NULL',      '', '', '',
+        'msa',        'varchar', 'NULL', $char_d, '', '',
         'ordernum',      'int',     'NULL',      '', '', '',
         'svcnum',      'int',     'NULL',      '', '', '',
         'availbatch', 'varchar',  'NULL', $char_d, '', '',
@@ -3127,16 +3129,28 @@ sub tables_hashref {
       'index'  => [],
     },
     
-    'did_order' => {
+    'did_order_item' => {
       'columns' => [
-        'ordernum',    'serial',      '',      '', '', '', 
-        'vendornum',   'int',       '',      '', '', '', 
-        'vendor_order_id',   'varchar',  '',   $char_d, '', '', 
+        'orderitemnum',    'serial',      '',      '', '', '', 
+        'ordernum',    'int',      '',      '', '', '', 
         'msa',        'varchar', 'NULL', $char_d, '', '',
+        'npa',      'int',     'NULL',      '', '', '',
         'latanum',      'int',     'NULL',      '', '', '',
         'rate_center',        'varchar', 'NULL', $char_d, '', '',
         'state',       'char',    'NULL',       2, '', '', 
         'quantity',      'int',     '',      '', '', '',
+      ],
+      'primary_key' => 'orderitemnum',
+      'unique' => [],
+      'index'  => [],
+    },
+
+    'did_order' => {
+      'columns' => [
+        'ordernum',    'serial',      '',      '', '', '', 
+        'vendornum',   'int',       '',      '', '', '', 
+        'vendor_order_id',   'varchar',  'NULL',   $char_d, '', '', 
+        'custnum',   'int', 'NULL', '', '', '',
         'submitted',      'int',     '',      '', '', '',
         'confirmed',      'int',     'NULL',      '', '', '',
         'received',      'int',     'NULL',      '', '', '',
index 6b199a9..f46d72b 100644 (file)
@@ -1,7 +1,7 @@
 package FS::did_order;
 
 use strict;
-use base qw( FS::Record );
+use base qw( FS::o2m_Common FS::Record );
 use FS::Record qw( qsearch qsearchs );
 
 =head1 NAME
@@ -42,26 +42,6 @@ vendornum
 
 vendor_order_id
 
-=item msa
-
-msa
-
-=item latanum
-
-latanum
-
-=item rate_center
-
-rate_center
-
-=item state
-
-state
-
-=item quantity
-
-quantity
-
 =item submitted
 
 submitted
@@ -137,12 +117,7 @@ sub check {
   my $error = 
     $self->ut_numbern('ordernum')
     || $self->ut_foreign_key('vendornum', 'did_vendor', 'vendornum' )
-    || $self->ut_text('vendor_order_id')
-    || $self->ut_textn('msa')
-    || $self->ut_foreign_keyn('latanum', 'lata', 'latanum')
-    || $self->ut_textn('rate_center')
-    || $self->ut_textn('state')
-    || $self->ut_number('quantity')
+    || $self->ut_textn('vendor_order_id')
     || $self->ut_number('submitted')
     || $self->ut_numbern('confirmed')
     || $self->ut_numbern('received')
@@ -152,9 +127,19 @@ sub check {
   $self->SUPER::check;
 }
 
-=back
+=item did_order_item
+
+Returns the did_order_items (see L<FS::did_order_item>) associated with this bulk DID order.
 
-=head1 BUGS
+=cut
+
+sub did_order_item {
+  my $self = shift;
+  qsearch( 'did_order_item', { 'ordernum' => $self->ordernum } );
+}
+
+
+=back
 
 =head1 SEE ALSO
 
diff --git a/FS/FS/did_order_item.pm b/FS/FS/did_order_item.pm
new file mode 100644 (file)
index 0000000..4408c50
--- /dev/null
@@ -0,0 +1,150 @@
+package FS::did_order_item;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::did_order_item - Object methods for did_order_item records
+
+=head1 SYNOPSIS
+
+  use FS::did_order_item;
+
+  $record = new FS::did_order_item \%hash;
+  $record = new FS::did_order_item { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::did_order_item object represents an item in a bulk DID order.
+FS::did_order_item inherits from FS::Record.  
+The following fields are currently supported:
+
+=over 4
+
+=item orderitemnum
+
+primary key
+
+=item ordernum
+
+ordernum
+
+=item msa
+
+msa
+
+=item npa
+
+npa
+
+=item latanum
+
+latanum
+
+=item rate_center
+
+rate_center
+
+=item state
+
+state
+
+=item quantity
+
+quantity
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new DID order item.  To add it 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
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'did_order_item'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=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.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid DID order item.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('orderitemnum')
+    || $self->ut_number('ordernum')
+    || $self->ut_textn('msa')
+    || $self->ut_numbern('npa')
+    || $self->ut_foreign_keyn('latanum', 'lata', 'latanum')
+    || $self->ut_textn('rate_center')
+    || $self->ut_textn('state')
+    || $self->ut_number('quantity')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index 8bb6a5c..3066ac0 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use vars qw( @ISA $DEBUG $me );
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::cust_svc;
+use FS::Misc::DateTime qw( parse_datetime );
 
 @ISA = qw(FS::cust_main_Mixin FS::Record);
 
@@ -190,9 +191,9 @@ sub process_batch_import {
   };
 
   my $opt = { 'table'   => 'phone_avail',
-              'params'  => [ 'availbatch', 'exportnum', 'countrycode', 'ordernum' ],
+              'params'  => [ 'availbatch', 'exportnum', 'countrycode', 'ordernum', 'vendor_order_id', 'confirmed' ],
               'formats' => { 'default' => [ 'state', $numsub, 'name' ],
-                            'bulk' => [ 'state', $numsub, 'name', 'rate_center_abbrev' ],
+                            'bulk' => [ 'state', $numsub, 'name', 'rate_center_abbrev', 'msa', 'latanum' ],
                           },
              'postinsert_callback' => sub {  
                    my $record = shift;
@@ -201,6 +202,8 @@ sub process_batch_import {
                                                { 'ordernum' => $record->ordernum } );
                        if($did_order && !$did_order->received) {
                            $did_order->received(time);
+                           $did_order->confirmed(parse_datetime($record->confirmed));
+                           $did_order->vendor_order_id($record->vendor_order_id);
                            $did_order->replace;
                        }
                    }
index a293451..c93f1ff 100644 (file)
@@ -588,3 +588,5 @@ FS/hardware_type.pm
 t/hardware_type.t
 FS/hardware_status.pm
 t/hardware_status.t
+FS/did_order_item.pm
+t/did_order_item.t
diff --git a/FS/t/did_order_item.t b/FS/t/did_order_item.t
new file mode 100644 (file)
index 0000000..cc33c14
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::did_order_item;
+$loaded=1;
+print "ok 1\n";
index 54c2bd3..e844169 100644 (file)
@@ -4,15 +4,16 @@
                  'name'        => 'bulk DID orders',
                  'disableable' => 0,
                  'query'       => { 'table'     => 'did_order',
-                                   'addl_from' => 'left join did_vendor using (vendornum) 
-                                                   left join lata using (latanum)',
+                                   'addl_from' => 'left join did_vendor using (vendornum) ',
                                     'hashref'   => {},
                                     'order_by' => 'ORDER BY ordernum',
                                   },
                  'count_query' => $count_query,
                  'header'      => $header,
                  'fields'      => $fields,
-                 'links'       => $links,
+                 'links'       => [
+                                   [ $p.'edit/did_order.html?', 'ordernum' ],
+                                 ],
              )
 %>
 <%init>
@@ -28,31 +29,22 @@ my $html_init =
 
 my $count_query = 'SELECT COUNT(*) FROM did_order';
 
-my $link = [ $p.'edit/did_order.html?', 'ordernum' ];
-
 my $display_date = sub {
     my $date = shift;
     return '' unless $date;
     time2str($date_format, $date);
 };
 
-my $header = [ '#', 'Vendor',' Vendor Order #', 'MSA', 'LATA #', 'LATA', 
-               'Rate Center', 'State', 'Quantity', 'Submitted', 'Confirmed',
-               'Received', 
+my $header = [ '#', 'Vendor',' Vendor Order #',  
+               'Submitted', 'Confirmed', 'Customer', 'Received', 
            ];
-my $links  = [ ];
 my $fields = [  sub {
                    my $did_order = shift;
-                   if($did_order->received) {
-                       push @$links, $link;
-                   }
-                   else {
-                       return $did_order->ordernum;
-                   }
-               }, 'vendorname', 'vendor_order_id', 'msa', 'latanum',
-               'description', 'rate_center', 'state', 'quantity', 
+                   $did_order->ordernum;
+               }, 'vendorname', 'vendor_order_id', 
                sub { &$display_date(shift->submitted); }, 
                sub { &$display_date(shift->confirmed); }, 
+               'custnum',
                sub { 
                    my $did_order = shift;
                    my $ordernum = $did_order->ordernum;
index a9bece9..25e38c7 100644 (file)
@@ -6,39 +6,54 @@
                               table => 'did_vendor',
                               disable_empty => 1,
                             },
-                            'vendor_order_id',
-                            'msa',
-                            { field => 'latanum',
-                              type => 'select-table',
-                              name_col => 'description',
-                              table => 'lata',
-                              disable_empty => 1,
-                              label_showkey => 1,
-                            },
-                            'rate_center',
-                            { field => 'state',
-                              type => 'select-state',
-                              country => 'US',
-                            },
-                            'quantity',
+                            { field => 'vendor_order_id',
+                             type => 'hidden',
+                           },
                             { field => 'confirmed',
-                              type => 'input-date-field',
+                              type => 'hidden',
                             },
+                           'custnum',
+                           { type => 'tablebreak-tr-title',
+                             value => 'Order Items',
+                           },
+                           { 'field' => 'orderitemnum',
+                             'type' => 'did_order_item',
+                             'o2m_table' => 'did_order_item',
+                             'm2_label' => 'Item',
+                             'm2_error_callback' => $m2_error_callback,
+                           },
+                            #'msa',
+                            #{ field => 'latanum',
+                            #  type => 'select-table',
+                            #  name_col => 'description',
+                            #  table => 'lata',
+                            #  disable_empty => 1,
+                            #  label_showkey => 1,
+                            #},
+                            #'rate_center',
+                            #{ field => 'state',
+                            #  type => 'select-state',
+                            #  country => 'US',
+                            #},
+                            #'quantity',
                           ],
               'labels' => { 
                             'ordernum'        => 'Order',
                             'vendornum'       => 'Vendor',
                             'vendor_order_id' => 'Vendor Order #',
-                            'msa'             => 'MSA',
-                            'latanum'         => 'LATA',
-                            'rate_center'     => 'Rate Center',
-                            'state'           => 'State',
-                            'quantity'        => 'Quantity',
+                           'custnum'         => 'Customer',
+                            #'msa'             => 'MSA',
+                            #'latanum'         => 'LATA',
+                            #'rate_center'     => 'Rate Center',
+                            #'state'           => 'State',
+                            #'quantity'        => 'Quantity',
                             'confirmed'       => 'Confirmation Date',
+                           'orderitemnum'     => 'Item',
                           },
               'viewall_dir' => 'browse',
               'table' => 'did_order',
               'name' => 'Bulk DID Order',
+             'field_callback' => $field_callback,
            )
           
 %>
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Import');
 
+
+my $field_callback = sub {
+  my ($cgi, $object, $field_hashref ) = @_;
+  if ($object->ordernum) {
+    $field_hashref->{type} = 'text'
+       if $field_hashref->{field} eq 'vendor_order_id';
+    $field_hashref->{type} = 'input-date-field'
+       if $field_hashref->{field} eq 'confirmed';
+  }
+};
+
+my $m2_error_callback = sub {
+  my($cgi, $object) = @_;
+
+  #process_o2m fields in process/did_order.html
+  my @fields = qw( msa npa latanum rate_center state quantity );
+  my @gfields = ( '', map "_$_", @fields );
+
+  map {
+        if ( /^orderitemnum(\d+)$/ ) {
+          my $num = $1;
+          if ( grep $cgi->param("orderitemnum$num$_"), @gfields ) {
+            my $x = new FS::did_order_item {
+              'orderitemnum' => scalar($cgi->param("orderitemnum$num")),
+              map { $_ => scalar($cgi->param("orderitemnum${num}_$_")) } @fields,
+            };
+            $x;
+          } else {
+            ();
+          }
+        } else {
+          ();
+        }
+      }
+      $cgi->param;
+};
+
+
 </%init>
index 295ad85..f5698d9 100644 (file)
@@ -272,6 +272,7 @@ Example:
 %     'options'       => $f->{'options'},
 %     'labels'        => $f->{'labels'},
 %     'multiple'      => $f->{'multiple'},
+%     'label_showkey' => $f->{'label_showkey'},
 %     'disable_empty' => $f->{'disable_empty'},
 %     #select-reason
 %     'reason_class'  => $f->{'reason_class'},
@@ -439,7 +440,7 @@ Example:
 %       }
 %       warn "layer values: ". Dumper($layer_values)
 %         if $opt{'debug'};
-%
+%      
 %       my @existing = &{ $include_sub }(
 %         'label'        => $ex_label,
 %         'fieldnum'     => $fieldnum,
index 0c9a3f0..e5948ff 100644 (file)
@@ -2,6 +2,10 @@
                'table'       => 'did_order',
                'viewall_dir' => 'browse',
               'value_callback' => $value_callback,
+                'process_o2m' => {
+                  'table'  => 'did_order_item',
+                  'fields' => \@item_fields,
+                },
            )
 %>
 <%init>
@@ -15,6 +19,8 @@ my $value_callback = sub {
      ($field =~ /ed$/ && $value !~ /^\d+$/) ? parse_datetime($value) : $value;
 };
 
+my @item_fields = qw( msa npa latanum rate_center state quantity );
+
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Import');
 
diff --git a/httemplate/elements/did_order_item.html b/httemplate/elements/did_order_item.html
new file mode 100644 (file)
index 0000000..263826e
--- /dev/null
@@ -0,0 +1,69 @@
+% unless ( $opt{'js_only'} ) {
+
+  <INPUT TYPE="hidden" NAME="<%$name%>" ID="<%$id%>" VALUE="<% $curr_value %>">
+
+  <TABLE>
+    <TR>
+%     foreach my $field ( @fields ) {
+%
+%       my $value = '';
+%         $value = $item->get($field);
+
+        <TD>
+          <INPUT TYPE  = "text"
+                 NAME  = "<%$name%>_<%$field%>"
+                 ID    = "<%$id%>_<%$field%>"
+                 SIZE  = "<% $size{$field} || 15 %>"
+                 VALUE = "<% scalar($cgi->param($name."_$field"))
+                             || $value |h %>"
+                 <% $onchange %>
+          ><BR>
+          <FONT SIZE="-1"><% $label{$field} %></FONT>
+        </TD>
+%     }
+    </TR>
+  </TABLE>
+
+% }
+<%init>
+
+my( %opt ) = @_;
+
+my $name = $opt{'element_name'} || $opt{'field'} || 'orderitemnum';
+my $id = $opt{'id'} || 'orderitemnum';
+
+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 $item;
+if ( $curr_value ) {
+  $item = qsearchs('did_order_item', { 'orderitemnum' => $curr_value } );
+} else {
+  $item = new FS::did_order_item {};
+}
+
+my %size = ( 'npa' => 3, 
+            'latanum' => 3,
+            'state' => 2,
+            'quantity' => 3,);
+
+tie my %label, 'Tie::IxHash',
+  'msa'        => 'MSA',
+  'npa'        => 'NPA',
+  'latanum'         => 'LATA #',
+  'rate_center'        => 'Rate Center',
+  'state' => 'State',
+  'quantity' => 'Quantity',
+;
+
+my @fields = keys %label;
+
+</%init>
diff --git a/httemplate/elements/tr-did_order_item.html b/httemplate/elements/tr-did_order_item.html
new file mode 100644 (file)
index 0000000..7824aee
--- /dev/null
@@ -0,0 +1,24 @@
+%   unless ( $opt{'js_only'} ) {
+
+      <% include('tr-td-label.html', %opt) %>
+        <TD <% $cell_style %>>
+
+%   }
+%
+            <% include( '/elements/did_order_item.html', %opt ) %>
+%
+%   unless ( $opt{'js_only'} ) {
+
+        </TD>
+      </TR>
+
+%   }
+<%init>
+
+my( %opt ) = @_;
+
+my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : '';
+
+$opt{'label'} ||= 'Item';
+
+</%init>
index fcbfcc3..903c17b 100644 (file)
@@ -7,7 +7,7 @@ Import a file containing phone numbers (DIDs).
               'name'      => 'PhonenumImportForm',
               'action'    => 'process/phone_avail-import.html',
               'num_files' => 1,
-              'fields'    => [ 'format', 'availbatch', 'exportnum', 'countrycode', 'ordernum' ],
+              'fields'    => [ 'format', 'availbatch', 'exportnum', 'countrycode', 'ordernum', 'confirmed', 'vendor_order_id' ],
               'message'   => 'DID import successful',
               'url'       => $p."search/phone_avail.html?availbatch=$availbatch",
           )
@@ -25,6 +25,20 @@ Import a file containing phone numbers (DIDs).
            <INPUT TYPE="hidden" NAME="ordernum" VALUE="<% $ordernum %>">
        </TD>
     </TR>
+    <TR>
+       <TD ALIGN="RIGHT">Vendor Order #</TD>
+       <TD>
+           <INPUT TYPE="text" NAME="vendor_order_id" VALUE="<% $vendor_order_id %>">
+       </TD>
+    </TR>
+    
+    <% include( '/elements/tr-input-date-field.html', {
+                   'name' => 'confirmed',
+                   'label' => 'Order Confirmed',
+                   'value' => $confirmed,
+           })
+    %>
+
 % } 
   <TR>
     <TD ALIGN="RIGHT">Import Format</TD>
@@ -78,7 +92,7 @@ Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets.
 <BR><BR>
 
 <b>Default</b> format has the following field order: <i>state, number, name</i><br>
-<b>Bulk</b> format has the following field order: <i>state, number, rate center, rate_center_abbrev</i>
+<b>Bulk</b> format has the following field order: <i>state, number, rate center, rate_center_abbrev, msa, latanum</i>
 <BR><BR>
 Field information:
 <ul>
@@ -87,6 +101,8 @@ Field information:
   <li><i>name</i>: optional, rate center
   <li><i>rate center</i>: rate center (required)
   <li><i>rate_center_abbrev</i>: rate center abbreviation
+  <li><i>msa</i>: MSA
+  <li><i>latanum</i>: LATA #
 </ul>
 <BR><BR>
 
@@ -102,11 +118,23 @@ my $conf = new FS::Conf;
 my $ordernum = $cgi->param('ordernum');
 $ordernum = '' unless $ordernum =~ /^\d+$/;
 
-die 'invalid ordernum' 
-    unless (!$ordernum || qsearchs('did_order', { 'ordernum' => $ordernum }));
+my $vendor_order_id = '';
+my $confirmed = '';
+
+my $order = '';
+$order = qsearchs('did_order', { 'ordernum' => $ordernum } ) 
+    if $ordernum;
+
+die 'invalid ordernum' unless (!$ordernum || $order);
 
 my $format = 'default';
-$format = 'bulk' if $ordernum;
+
+if ( $order ) {
+    $format = 'bulk';
+    $confirmed = $order->confirmed;
+    $vendor_order_id = $order->vendor_order_id;
+}
+
 
 my $availbatch =
   time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time);