From 31f2e890b5b3e1b0ad29a877ff67bc641ea1fc40 Mon Sep 17 00:00:00 2001 From: levinse Date: Wed, 6 Apr 2011 08:24:27 +0000 Subject: [PATCH] bulk DID order/inventory improvements, RT11291 --- FS/FS.pm | 2 + FS/FS/Mason.pm | 1 + FS/FS/Schema.pm | 22 ++++- FS/FS/did_order.pm | 43 +++------ FS/FS/did_order_item.pm | 150 +++++++++++++++++++++++++++++ FS/FS/phone_avail.pm | 7 +- FS/MANIFEST | 2 + FS/t/did_order_item.t | 5 + httemplate/browse/did_order.html | 26 ++--- httemplate/edit/did_order.html | 95 ++++++++++++++---- httemplate/edit/elements/edit.html | 3 +- httemplate/edit/process/did_order.html | 6 ++ httemplate/elements/did_order_item.html | 69 +++++++++++++ httemplate/elements/tr-did_order_item.html | 24 +++++ httemplate/misc/phone_avail-import.html | 38 +++++++- 15 files changed, 414 insertions(+), 79 deletions(-) create mode 100644 FS/FS/did_order_item.pm create mode 100644 FS/t/did_order_item.t create mode 100644 httemplate/elements/did_order_item.html create mode 100644 httemplate/elements/tr-did_order_item.html diff --git a/FS/FS.pm b/FS/FS.pm index 9a4fbce5e..0f06f4d75 100644 --- a/FS/FS.pm +++ b/FS/FS.pm @@ -172,6 +172,8 @@ L - Bulk DID order vendor class L - Bulk DID order class +L - Bulk DID order item class + L - Call Detail Record class L - Call Detail Record batch class diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index dd1871739..db54ecbd4 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -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 ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 66847b6c0..06406e636 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -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', '', '', '', diff --git a/FS/FS/did_order.pm b/FS/FS/did_order.pm index 6b199a969..f46d72bf8 100644 --- a/FS/FS/did_order.pm +++ b/FS/FS/did_order.pm @@ -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) 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 index 000000000..4408c50f5 --- /dev/null +++ b/FS/FS/did_order_item.pm @@ -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 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, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/phone_avail.pm b/FS/FS/phone_avail.pm index 8bb6a5cc3..3066ac033 100644 --- a/FS/FS/phone_avail.pm +++ b/FS/FS/phone_avail.pm @@ -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; } } diff --git a/FS/MANIFEST b/FS/MANIFEST index a293451a1..c93f1ffc2 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -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 index 000000000..cc33c1481 --- /dev/null +++ b/FS/t/did_order_item.t @@ -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"; diff --git a/httemplate/browse/did_order.html b/httemplate/browse/did_order.html index 54c2bd3fc..e844169b3 100644 --- a/httemplate/browse/did_order.html +++ b/httemplate/browse/did_order.html @@ -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; diff --git a/httemplate/edit/did_order.html b/httemplate/edit/did_order.html index a9bece9b1..25e38c72e 100644 --- a/httemplate/edit/did_order.html +++ b/httemplate/edit/did_order.html @@ -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, ) %> @@ -47,4 +62,42 @@ 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; +}; + + diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index 295ad8567..f5698d98e 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -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, diff --git a/httemplate/edit/process/did_order.html b/httemplate/edit/process/did_order.html index 0c9a3f0e0..e5948ff0b 100644 --- a/httemplate/edit/process/did_order.html +++ b/httemplate/edit/process/did_order.html @@ -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 index 000000000..263826ecc --- /dev/null +++ b/httemplate/elements/did_order_item.html @@ -0,0 +1,69 @@ +% unless ( $opt{'js_only'} ) { + + + + + +% foreach my $field ( @fields ) { +% +% my $value = ''; +% $value = $item->get($field); + + +% } + +
+ " + <% $onchange %> + >
+ <% $label{$field} %> +
+ +% } +<%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; + + diff --git a/httemplate/elements/tr-did_order_item.html b/httemplate/elements/tr-did_order_item.html new file mode 100644 index 000000000..7824aee03 --- /dev/null +++ b/httemplate/elements/tr-did_order_item.html @@ -0,0 +1,24 @@ +% unless ( $opt{'js_only'} ) { + + <% include('tr-td-label.html', %opt) %> + > + +% } +% + <% include( '/elements/did_order_item.html', %opt ) %> +% +% unless ( $opt{'js_only'} ) { + + + + +% } +<%init> + +my( %opt ) = @_; + +my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; + +$opt{'label'} ||= 'Item'; + + diff --git a/httemplate/misc/phone_avail-import.html b/httemplate/misc/phone_avail-import.html index fcbfcc398..903c17bd9 100644 --- a/httemplate/misc/phone_avail-import.html +++ b/httemplate/misc/phone_avail-import.html @@ -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). + + Vendor Order # + + + + + + <% include( '/elements/tr-input-date-field.html', { + 'name' => 'confirmed', + 'label' => 'Order Confirmed', + 'value' => $confirmed, + }) + %> + % } Import Format @@ -78,7 +92,7 @@ Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets.

Default format has the following field order: state, number, name
-Bulk format has the following field order: state, number, rate center, rate_center_abbrev +Bulk format has the following field order: state, number, rate center, rate_center_abbrev, msa, latanum

Field information:
    @@ -87,6 +101,8 @@ Field information:
  • name: optional, rate center
  • rate center: rate center (required)
  • rate_center_abbrev: rate center abbreviation +
  • msa: MSA +
  • latanum: LATA #


@@ -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); -- 2.11.0