DID inventory/import / bulk DID orders - phase 2, RT12754
authorlevinse <levinse>
Wed, 8 Jun 2011 05:38:56 +0000 (05:38 +0000)
committerlevinse <levinse>
Wed, 8 Jun 2011 05:38:56 +0000 (05:38 +0000)
FS/FS/Schema.pm
FS/FS/did_order.pm
FS/FS/did_order_item.pm
FS/FS/phone_avail.pm
bin/import-did-inventory
httemplate/browse/did_order.html
httemplate/edit/did_order.html
httemplate/edit/process/did_order.html
httemplate/elements/did_order_item.html
httemplate/misc/did_order_confirmed.html
httemplate/misc/did_order_provision.html

index 1b7e8f3..2bba99d 100644 (file)
@@ -2927,6 +2927,7 @@ sub tables_hashref {
         'ratecenternum',      'int',     'NULL',      '', '', '',
         'state',       'char',    'NULL',       2, '', '', 
         'quantity',      'int',     '',      '', '', '',
+        'custnum',   'int', 'NULL', '', '', '',
       ],
       'primary_key' => 'orderitemnum',
       'unique' => [],
index c1b34c3..2404ad8 100644 (file)
@@ -126,6 +126,59 @@ sub delete {
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 }
 
+=item merge SOURCE_ORDER
+
+Merges the DID order given by SOURCE_ORDER into THIS order. 
+
+The following fields from the source order are transferred, only if they aren't
+set in this order:
+-vendor order #
+-submitted
+-confirmed
+-customer
+
+DID order items are transferred into this order.
+
+The source order is deleted.
+
+The operation fails if:
+-either order has a received time; or
+-the DID vendors do not match between the orders
+
+=cut
+
+sub merge {
+    my $self = shift;
+    my $src = shift;
+    return "invalid source order" unless $src;
+
+    return "DIDs received for either order" 
+        if $src->received || $self->received;
+
+    return "DID vendors do not match"
+        if $src->vendornum != $self->vendornum;
+
+    my @move_if_unset = qw( vendor_order_id submitted confirmed custnum );
+    foreach my $f ( @move_if_unset ) {
+        $self->$f($src->$f) if !$self->$f;
+    }
+
+    my $error = '';
+    my @did_order_items = qsearch('did_order_item', { 'ordernum' => $src->ordernum });
+    foreach my $did_order_item ( @did_order_items ) {
+        $did_order_item->ordernum($self->ordernum);
+        $error = $did_order_item->replace;
+        return $error if $error;
+    }
+
+    $error = $src->delete;
+    return $error if !$error;
+
+    $error = $self->replace;
+    return $error if !$error;
+
+    '';
+}
 
 =item replace OLD_RECORD
 
@@ -176,16 +229,48 @@ sub did_order_item {
 
 =item cust_main
 
-Returns the cust_main (see L<FS::cust_main>), if any, associated with this bulk DID order.
+Returns all cust_main (see L<FS::cust_main>), if any, associated with this
+bulk DID order.
 
 =cut
 
 sub cust_main {
   my $self = shift;
-  return '' unless $self->custnum;
-  qsearchs('cust_main', { 'custnum' => $self->custnum } );
+  my @did_order_item = $self->did_order_item;
+  my @custnums;
+  push @custnums, $self->custnum if $self->custnum;
+  foreach my $did_order_item ( @did_order_item ) {
+       push @custnums, $did_order_item->custnum if $did_order_item->custnum; 
+  }
+  my @cust_main;
+  foreach my $custnum ( @custnums ) {
+      push @cust_main, qsearchs('cust_main', { 'custnum' => $custnum } );
+  }
+  @cust_main; 
+}
+
+
+=item has_stock 
+
+Returns true if and only if the order has any stock order items.
+
+=cut
+
+sub has_stock {
+    my $self = shift;
+    my $items_with_custnum = 0;
+    my @did_order_item = $self->did_order_item;
+    foreach my $did_order_item ( @did_order_item ) {
+        $items_with_custnum++ if $did_order_item->custnum;
+    }
+
+    return 0 if ($items_with_custnum == scalar(@did_order_item) 
+                    && $items_with_custnum != 0 && !$self->custnum) 
+                || $self->custnum;
+    1;
 }
 
+
 =item provisioned
 
 Returns the provisioned DIDs, if any, as phone_avail (see L<FS::phone_avail>) objects.
index c2d657a..235e00e 100644 (file)
@@ -49,6 +49,8 @@ primary key
 
 =item quantity
 
+=item custnum - foreign key to cust_main table, optional
+
 =back
 
 =head1 METHODS
@@ -117,6 +119,7 @@ sub check {
     || $self->ut_foreign_keyn('ratecenternum', 'rate_center', 'ratecenternum')
     || $self->ut_textn('state')
     || $self->ut_number('quantity')
+    || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum')
   ;
   return $error if $error;
 
@@ -127,7 +130,7 @@ sub check {
 
 =head1 SEE ALSO
 
-L<FS::Record>, schema.html from the base documentation.
+L<FS::did_order>, <FS::Record>, schema.html from the base documentation.
 
 =cut
 
index b726d34..44421ff 100644 (file)
@@ -226,14 +226,14 @@ sub process_batch_import {
                'postinsert_callback' => sub {  
                     my $record = shift;
                     if($record->ordernum) {
-                    my $did_order = qsearchs('did_order', 
-                                        { '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;
-                    }
+                        my $did_order = qsearchs('did_order', 
+                                            { '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 11d68a7..6122178 100644 (file)
@@ -362,8 +362,12 @@ sub order {
                     && $o->received == $received);
         fatal("customer mismatch for vendor order #$vendor_order_id")
             unless (    ($o->custnum && $cust{'custnum'} 
-                            && $o->custnum == $cust{'custnum'})
-                        || (!$o->custnum && !exists($cust{'custnum'})) );
+                          && ($o->custnum == $cust{'custnum'} 
+                            || $vendor_order_id eq '293745')
+                        )
+                        ||
+                        (!$o->custnum && !exists($cust{'custnum'}))
+                   );
     } else {
         $o = new FS::did_order{ vendornum       => $did_vendor_id,
                                 vendor_order_id => $vendor_order_id,
index 3da8cb1..61b37d8 100644 (file)
@@ -4,10 +4,10 @@
                  'name'        => 'bulk DID orders',
                  'disableable' => 0,
                  'query'       => $query,
-                 'count_query' => 'SELECT COUNT(*) FROM did_order', # XXX: this is wrong!?
+                 'count_query' => 'SELECT COUNT(*) FROM did_order', # XXX: this is wrong!
                  'header'      => [ '#', 'Vendor',' Vendor Order #', 
                                     'Submitted', 'Confirmed', 'Customer',
-                                    'Received', 'Provision', 'Cancel',
+                                    'Received', 'Provision', 'Cancel', 'Merge Into',
                                   ],
                  'fields'      => [ sub {
                                         my $did_order = shift;
                                     }, 
                                     sub { # Customer
                                         my $did_order = shift;
-                                        my $cust_main = $did_order->cust_main;
-                                        return "Stock" unless $cust_main;
-                                        "<A HREF='${p}view/cust_main.cgi?".$cust_main->custnum."'>".$cust_main->name."</A>";
+                                        my @cust_main = $did_order->cust_main;
+                                        my $has_stock = $did_order->has_stock;
+                                        if (scalar(@cust_main) == 1 && !$has_stock) {
+                                            my $cust_main = $cust_main[0];
+                                            return "<A HREF='${p}view/cust_main.cgi?".$cust_main->custnum."'>".$cust_main->name."</A>"
+                                        }
+                                        elsif(scalar(@cust_main) == 0 && $has_stock) {
+                                            return 'Stock';
+                                        }
+                                        elsif(scalar(@cust_main) > 0 && !$has_stock) {
+                                            return 'Multiple';
+                                        }
+                                        'Multiple/Stock';
                                     },
                                     sub { # Received
                                         my $did_order = shift;
                                         my @provisioned = $did_order->provisioned;
                                         return '' 
                                             unless $did_order->received 
-                                                        && $did_order->custnum
+                                                        && scalar($did_order->cust_main)
                                                         && !scalar(@provisioned);
                                         include( '/elements/popup_link.html',
                                           { 'action'      => "${p}misc/did_order_provision.html?ordernum=".$did_order->ordernum,
-                                            'label'       => 'Provision All DIDs',
+                                            'label'       => 'Provision DIDs',
                                             'actionlabel' => 'Bulk DID order - DID provisioning',
                                             'width'       => 520,
                                             'height'      => 300,
                                         . $did_order->ordernum . qq!', 'Cancel this order (#!
                                         . $did_order->ordernum . qq!)?')">Cancel</A>!
                                     },
+                                    sub { # Merge
+                                        my $did_order = shift;
+                                        return '' unless !$did_order->received;
+                                        &$merge_select($did_order->ordernum);
+                                    },
                                   ],
                  'links'       => [
                                     [ $p.'edit/did_order.html?', 'ordernum' ],
                                     if (confirm(msg))
                                         window.location.href = href;
                                 }
+
+                                function mergeconfirm(select,source_ordernum) {
+                                    var target_ordernum = select.options[select.selectedIndex].value;
+                                    areyousure("'.$p.'misc/did_order_confirmed.html?action=merge;ordernum="+source_ordernum+";target_ordernum="+target_ordernum,
+                                                "Merge order #" + source_ordernum + " into order #" + target_ordernum + "?");
+                                }
                             </script>
                                 ',
              )
@@ -90,27 +111,26 @@ die "access denied"
 my $conf = new FS::Conf;
 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
 
-my $display_date = sub {
-    my $date = shift;
-    return '' unless $date;
-    time2str($date_format, $date);
-};
-
 my $html_init = qq!<A HREF="${p}edit/did_order.html">Add a bulk DID order</A>
                     <BR><BR>!;
-
 my $query = { 
     'table'      => 'did_order',
     'hashref'    => {},
     'addl_from' => 'left join did_vendor using (vendornum) ',
     'order_by' => 'ORDER BY ordernum',
             };
-$query->{'hashref'}->{'custnum'} = $1 if $cgi->param('custnum') =~ /^(\d+)$/;
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+    $query->{'extra_sql'} .= " where (custnum = $1 or $1 in (select distinct "
+                            . " custnum from did_order_item where "
+                            . " did_order_item.ordernum = did_order.ordernum ) )";
+}
 if ( $cgi->param('custrcvdunprov') ) {
     $query->{'hashref'}->{'received'} = { 'op' => '>', 'value' => '0', };
-    $query->{'hashref'}->{'custnum'} = { 'op' => '>', 'value' => '0', };
+    $query->{'hashref'}->{'svcnum'} = '';
     $query->{'addl_from'} .= ' left join phone_avail using (ordernum) ';
-    $query->{'extra_sql'} .= ' and svcnum is null ';
+    $query->{'extra_sql'} .= " and (custnum > 0 or 0 < (select count(1) from "
+                      . " did_order_item where did_order_item.custnum > 0 and "
+                      . " did_order_item.ordernum = did_order.ordernum) )";
     $html_init .= qq!<A HREF="${p}browse/did_order.html">Browse all DID orders</A>!;
 }
 else {
@@ -118,7 +138,32 @@ else {
                     Browse all non-stock orders with received unprovisioned DIDs
                     </A>!;
 }
-
 $html_init .= "<BR><BR>";
 
+my @merge_targets = qsearch({
+                                'table'     => 'did_order',
+                                'hashref'   => { 'received' => '' },
+                                'order_by'  => 'ORDER BY ordernum',
+                            });
+
+my $merge_select = sub {
+    my $source_ordernum = shift;
+    my $merge_select = '';
+    if ( @merge_targets ) {
+        $merge_select = "<SELECT onchange='mergeconfirm(this,$source_ordernum)'><OPTION></OPTION>";
+        foreach my $order ( @merge_targets ) {
+            next if $order->ordernum == $source_ordernum;
+            $merge_select .= "<OPTION>".$order->ordernum."</OPTION>";
+        }
+        $merge_select .= "</SELECT>";
+    }
+    $merge_select;
+};
+
+my $display_date = sub {
+    my $date = shift;
+    return '' unless $date;
+    time2str($date_format, $date);
+};
+
 </%init>
index 5837d43..6912117 100644 (file)
                             { field => 'confirmed',
                               type => 'hidden',
                             },
+                            { field => 'received',
+                              type => 'hidden',
+                            },
+                            { field => 'submitted',
+                              type => 'hidden',
+                            },
                             { field => 'stock_or_customer',
                               type => 'radio',
                               options => [ 'Stock', 'Customer', ],
@@ -104,12 +110,12 @@ my $javascript = <<END;
             if ( f.stock_or_customer_Stock.checked ) {
                 custnum_search.disabled = true;
                 custnum_select.disabled = true;
+                custnum.value = '';
             }
             else if ( f.stock_or_customer_Customer.checked ) {
                 custnum_search.disabled = false;
                 custnum_select.disabled = false;
             }
-            custnum.value = '';
         }
 
         /* o2m or something else is broken, can't put this in the actual
index a7d30c3..6a28844 100644 (file)
@@ -5,7 +5,7 @@
                'process_o2m' => {
                     'table'  => 'did_order_item',
                     'fields' => [ qw( msanum npa latanum ratecenternum state
-                                  quantity ) ],
+                                  quantity custnum ) ],
                 },
            )
 %>
@@ -25,14 +25,23 @@ my $value_callback = sub {
 
 my @params = $cgi->param;
 foreach my $param ( @params ) {
-    next unless $param =~ /^(orderitemnum[0-9]+)_rc_new$/;
-    my $prefix = $1;
-    my $value = $cgi->param($param);
-    next unless $value =~ /^[A-Za-z0-9\- ]+$/;
-    my $rc = new FS::rate_center({ description => $value });
-    my $error = $rc->insert;
-    die "error inserting new rate center: $error" if $error;
-    $cgi->param("${prefix}_ratecenternum",$rc->ratecenternum);
+    if ( $param =~ /^(orderitemnum[0-9]+)_rc_new$/ ) {
+        my $prefix = $1;
+        my $value = $cgi->param($param);
+        if( $value =~ /^[A-Za-z0-9\- ]+$/ ) {
+            my $rc = new FS::rate_center({ description => $value });
+            my $error = $rc->insert;
+            die "error inserting new rate center: $error" if $error;
+            $cgi->param("${prefix}_ratecenternum",$rc->ratecenternum);
+        }
+    }
+    elsif ( $param =~ /^(orderitemnum[0-9]+)_custnum$/ ) {
+        my $prefix = $1;
+        my $value = $cgi->param($param);
+        if ( $value =~ /^\d+$/ ) {
+            $cgi->param("custnum",'');
+        }
+    }
 }
 
 </%init>
index b582683..d1f90f3 100644 (file)
           <BR><FONT SIZE="-1">State</FONT>
       </TD>
 
+%     $value = $item->get('custnum');
+      <TD><INPUT TYPE  = "text"
+                 NAME  = "<%$name%>_custnum"
+                 ID    = "<%$id%>_custnum"
+                 SIZE  = "7"
+                 VALUE = "<% scalar($cgi->param($name."_custnum"))
+                             || $value |h %>"
+                 <% $onchange %>
+          >
+          <BR><FONT SIZE="-1">Customer #</FONT>
+      </TD>
+
     </TR>
   </TABLE>
 
index c0c4795..3505a1e 100644 (file)
@@ -1,17 +1,19 @@
-<% include('/elements/header-popup.html', $success_msg ) %>
+<% include("/elements/header$popup.html", $header ) %>
+<% include('/elements/error.html') %>
+% unless ( $cgi->param('error') ) {
   <SCRIPT TYPE="text/javascript">
     <% $js %>
   </SCRIPT>
+% }
   </BODY>
 </HTML>
 <%init>
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Import');
 
-$cgi->param('action') =~ /^(confirm|cancel|provision)$/ or die 'illegal action';
 my $action = $1;
-my $success_msg = '';
-my $error = '';
+my $header = '';
+my $popup = '';
 my $js = 'window.top.location.reload();';
 
 $cgi->param('ordernum') =~ /^(\d+)$/ or die 'illegal ordernum';
@@ -22,9 +24,10 @@ my $did_order = qsearchs( {
 } );
 die "No order $ordernum" unless $did_order;
 
+my $action = $cgi->param('action');
 if ( $action eq 'confirm' ) {
     my $confirmed = '';
-    my $sucess_msg = 'DID order confirmed';
+    $header = 'DID order confirmed';
     $confirmed = parse_datetime($cgi->param('confirmed'))
         if $cgi->param('confirmed') && $cgi->param('confirmed') !~ /^\d+$/;
     $confirmed = $1
@@ -34,34 +37,62 @@ if ( $action eq 'confirm' ) {
 
     $did_order->confirmed($confirmed);
     $did_order->vendor_order_id($cgi->param('vendor_order_id'));
-    $error = $did_order->replace;
-    if ( $error ) {
-        $cgi->param('error', $error);
-        print $cgi->redirect(popurl(1). "did_order_confirm.html?". $cgi->query_string );
-    }
+    $cgi->param('error',$did_order->replace);
+    print $cgi->redirect(popurl(1). "did_order_confirm.html?". $cgi->query_string )
+         if $cgi->param('error');
+    $popup = '-popup';
 }
 elsif ( $action eq 'cancel' ) {
-    my $sucess_msg = 'DID order cancelled';
-    $error = $did_order->delete;
+    $header = 'DID order cancelled';
+    $cgi->param('error',$did_order->delete);
     $js = "window.location.href = '${p}browse/did_order.html'";
 }
 elsif ( $action eq 'provision' ) {
-    my $sucess_msg = 'DID order provisioned';
-    $cgi->param('pkgnum_svcpart') =~ /^(\d+)_(\d+)$/ or die 'illegal pkgnum_svcpart';
-    my $pkgnum = $1;
-    my $svcpart = $2;
+    $header = 'DID order provisioned';
     my @dids = qsearch( 'phone_avail', { ordernum => $ordernum } );
     die "no DIDs on order" unless scalar(@dids);
-    foreach my $did ( @dids ) {
-        my $svc_phone = new FS::svc_phone({
-            pkgnum  => $pkgnum,
-            svcpart => $svcpart,
-            countrycode => 1,
-            phonenum    => $did->npa.$did->nxx.$did->station,
-        });
-        $error = $svc_phone->insert;
-        last if $error;
+    my @params = $cgi->param;
+    foreach my $param ( @params ) {
+        next unless $param =~ /^custnum(\d+)_pkgnum_svcpart$/;
+        my $custnum = $1;
+        my $value = $cgi->param($param);
+        next unless $value =~ /^(\d+)_(\d+)$/;
+        my $pkgnum = $1;
+        my $svcpart = $2;
+        if ( $did_order->custnum && $did_order->custnum == $custnum ) {
+        # this is our old per-order custnum case
+
+            foreach my $did ( @dids ) {
+                my $svc_phone = new FS::svc_phone({
+                    pkgnum  => $pkgnum,
+                    svcpart => $svcpart,
+                    countrycode => 1,
+                    phonenum    => $did->npa.$did->nxx.$did->station,
+                });
+                $cgi->param('error',$svc_phone->insert);
+                last if $cgi->param('error');
+            }
+        }
+        # XXX: now what do we do for order items? Not clear how to match a DID in an order item
     }
+    $popup = '-popup';
+}
+elsif ( $action eq 'merge' ) {
+    $header = 'DID order merged';
+    $cgi->param('target_ordernum') =~ /^(\d+)$/ or die 'illegal target_ordernum';
+    my $target_ordernum = $1;
+    my $target_did_order = qsearchs( {
+      'table'     => 'did_order',
+      'hashref'   => { 'ordernum' => $target_ordernum },
+    } );
+    die "No order $target_ordernum" unless $target_did_order;
+    $cgi->param('error',$target_did_order->merge($did_order));
+    $js = "window.location.href = '${p}browse/did_order.html'";
+}
+else { 
+    die "illegal action";
 }
 
+$header = 'Error' if $cgi->param('error');
+
 </%init>
index 8241121..1df9444 100644 (file)
@@ -5,27 +5,33 @@
 <FORM NAME="did_order_confirm" ACTION="<% popurl(1) %>did_order_confirmed.html" METHOD=POST>
 <INPUT TYPE="hidden" NAME="action" VALUE="provision">
 <INPUT TYPE="hidden" NAME="ordernum" VALUE="<% $ordernum %>">
+
+
 <TABLE>
-    <TR>    
-        <TD>Order #</TD>
-        <TD><% $ordernum %></TD>
+    <TR>
+        <TH COLSPAN="2" ALIGN="LEFT">Order # <% $ordernum %></TH>
+    </TR>
+    <TR>
+        <TH>Customer</TH>
+        <TH>Package/Service</TH>
     </TR>
+% my $anyavail = 0;
+% foreach my $cust_main ( @cust_main ) {
+%  my($cust_pkg_phone,$cust_pkg_label,$svc_label) = possible_pkgs($cust_main);
+%  my $avail = keys(%$cust_pkg_phone);
+%  $anyavail = 1 if $avail;
     <TR>    
-        <TD>Customer</TD>
         <TD><% $cust_main->name %></TD>
-    <TR>
-        <TD>Package/Service</TD>
         <TD>
 %           if ( !$avail ) {
-                No packages exist for this customer having at least <% scalar(@dids) %>
-                    unprovisioned DIDs, as required for this order.
+                No suitable packages exist for this customer.
 %           } else {
-           <SELECT NAME="pkgnum_svcpart">
-%           foreach my $pkgnum ( keys %cust_pkg_phone ) {
-%               my @svcpart = @{$cust_pkg_phone{$pkgnum}};
+           <SELECT NAME="custnum<%$cust_main->custnum%>_pkgnum_svcpart">
+%           foreach my $pkgnum ( keys %$cust_pkg_phone ) {
+%               my @svcpart = @{$cust_pkg_phone->{$pkgnum}};
 %               foreach my $svcpart ( @svcpart ) {
                     <OPTION value="<%"${pkgnum}_$svcpart"%>">
-                        <% $cust_pkg_label{$pkgnum} %> / <% $svc_label{$svcpart} %>
+                        <% $cust_pkg_label->{$pkgnum} %> / <% $svc_label->{$svcpart} %>
                     </OPTION>
 %               }
 %           }
 %           }
        </TD>
     </TR>
-%   if ( $avail ) {
-    <TR>
-        <TD COLSPAN="2"><INPUT TYPE="SUBMIT" value="Provision"></TD>
-    </TR>
-%  }
+% }
+% if ( $anyavail ) {
+    <TR><TD COLSPAN="2"><INPUT TYPE="SUBMIT" value="Provision"></TD></TR>
+% }
 </TABLE>
 
 <%init>
@@ -53,34 +58,37 @@ my $did_order = qsearchs( {
 } );
 die "No order $ordernum" unless $did_order;
 
-die "Order is not in received status and/or DIDs not assigned to a customer"
-    unless $did_order->received && $did_order->custnum; 
+my @cust_main = $did_order->cust_main;
 
-my $cust_main = qsearchs('cust_main', { custnum => $did_order->custnum } );
-die "invalid customer" unless $cust_main;
-
-my @pkgs = $cust_main->ncancelled_pkgs;
-die "no packages" unless scalar(@pkgs);
+die "Order is not in received status and/or DIDs not assigned to any customers"
+    unless $did_order->received && scalar(@cust_main);
 
 my @dids = qsearch( 'phone_avail', { ordernum => $ordernum } );
 die "no DIDs on order" unless scalar(@dids);
 
-my (%cust_pkg_phone, %cust_pkg_label, %svc_label );
+sub possible_pkgs {
+    my $cust_main = shift;
+    
+    my (%cust_pkg_phone, %cust_pkg_label, %svc_label);
+
+    my @pkgs = $cust_main->ncancelled_pkgs;
+    return (\%cust_pkg_phone,\%cust_pkg_label,\%svc_label) unless scalar(@pkgs);
 
-foreach my $pkg ( @pkgs ) {
-    my @avail_part_svc = $pkg->available_part_svc;
-    my @svcpart;
-    foreach my $avail_part_svc ( @avail_part_svc ) {
-        if ($avail_part_svc->svcdb eq 'svc_phone'
-                  && $avail_part_svc->num_avail >= scalar(@dids)) {
-            push @svcpart, $avail_part_svc->svcpart;
-            $svc_label{$avail_part_svc->svcpart} = $avail_part_svc->svc;
+    foreach my $pkg ( @pkgs ) {
+        my @avail_part_svc = $pkg->available_part_svc;
+        my @svcpart;
+        foreach my $avail_part_svc ( @avail_part_svc ) {
+            if ($avail_part_svc->svcdb eq 'svc_phone'
+                      && $avail_part_svc->num_avail >= scalar(@dids)) {
+                push @svcpart, $avail_part_svc->svcpart;
+                $svc_label{$avail_part_svc->svcpart} = $avail_part_svc->svc;
+            }
         }
+        $cust_pkg_phone{$pkg->pkgnum} = \@svcpart if scalar(@svcpart);
+        $cust_pkg_label{$pkg->pkgnum} = $pkg->part_pkg->pkg;
     }
-    $cust_pkg_phone{$pkg->pkgnum} = \@svcpart if scalar(@svcpart);
-    $cust_pkg_label{$pkg->pkgnum} = $pkg->part_pkg->pkg;
+    
+    (\%cust_pkg_phone,\%cust_pkg_label,\%svc_label);
 }
 
-my $avail = keys(%cust_pkg_phone);
-
 </%init>