1 package FS::part_pkg::agent;
2 #use base qw(FS::part_pkg::recur_Common);
3 use base qw(FS::part_pkg::prorate);
6 use vars qw($DEBUG $me %info);
8 use FS::Record qw( qsearch );
14 $me = '[FS::part_pkg::agent]';
17 'name' => 'Wholesale billing based on package prices, for master customers of an agent.',
18 'shortname' => 'Wholesale billing for agent (package prices)',
19 'inherit_fields' => [qw( prorate global_Mixin)],
21 #'recur_method' => { 'name' => 'Recurring fee method',
23 # #'options' => \%recur_method,
25 # 'select_options' => \%recur_Common::recur_method,
27 'cutoff_day' => { 'name' => 'Billing Day (1 - 28)',
30 'add_full_period'=> { 'name' => 'When prorating first month, also bill '.
31 'for one full period after that',
35 'no_pkg_prorate' => { 'name' => 'Disable prorating bulk packages (charge full price for packages active only a portion of the month)',
39 'display_separate_cust'=> { 'name' => 'Separate customer from package display on invoices',
43 'cost_only' => { 'name' => 'Bill wholesale on cost only, disabling the price fallback',
49 'fieldorder' => [qw( cutoff_day add_full_period no_pkg_prorate display_separate_cust cost_only) ],
55 #some false laziness-ish w/bulk.pm... not a lot
58 my($cust_pkg, $sdate, $details, $param ) = @_;
60 my $last_bill = $cust_pkg->last_bill;
62 return sprintf("%.2f", $self->SUPER::calc_recur(@_) )
63 unless $$sdate > $last_bill;
65 my $conf = new FS::Conf;
66 my $money_char = $conf->config('money_char') || '$';
67 my $date_format = $conf->config('date_format') || '%m/%d/%Y';
69 my $total_agent_charge = 0;
71 warn "$me billing for agent packages from ". time2str('%x', $last_bill).
72 " to ". time2str('%x', $$sdate). "\n"
75 my $prorate_ratio = ( $$sdate - $last_bill )
76 / ( $self->add_freq($last_bill) - $last_bill );
78 #almost always just one,
79 #unless you have multiple agents with same master customer0
80 my @agents = qsearch('agent', { 'agent_custnum' => $cust_pkg->custnum } );
82 foreach my $agent (@agents) {
84 warn "$me billing for agent ". $agent->agent. "\n"
87 #not the most efficient to load them all into memory,
88 #but good enough for our current needs
89 my @cust_main = qsearch('cust_main', { 'agentnum' => $agent->agentnum } );
91 foreach my $cust_main (@cust_main) {
93 warn "$me billing agent charges for ". $cust_main->name_short. "\n"
96 #make sure setup dates are filled in
97 my $error = $cust_main->bill( time => $$sdate );
98 die "Error pre-billing agent customer: $error" if $error;
100 my @cust_pkg = grep { my $setup = $_->get('setup');
101 my $cancel = $_->get('cancel');
103 #$setup <= $$sdate # ?
104 $setup < $$sdate # END
105 && ( ! $cancel || $cancel > $last_bill ) #START
107 $cust_main->all_pkgs;
109 my $cust_details = 0;
111 foreach my $cust_pkg ( @cust_pkg ) {
113 warn "$me billing agent charges for pkgnum ". $cust_pkg->pkgnum. "\n"
116 my $pkg_details = '';
118 my $cust_location = $cust_pkg->cust_location;
119 $pkg_details .= $cust_location->locationname. ': '
120 if $cust_location->locationname;
122 my $part_pkg = $cust_pkg->part_pkg;
124 # + something to identify package... primary service probably
125 # no... package def for now
126 $pkg_details .= $part_pkg->pkg. ': ';
130 my $quantity = $cust_pkg->quantity || 1;
132 my $pkg_setup_fee = $part_pkg->setup_cost;
133 $pkg_setup_fee ||= $part_pkg->option('setup_fee')
134 unless $self->option('cost_only');
135 $pkg_setup_fee ||= 0;
137 my $pkg_base_recur = $part_pkg->recur_cost;
138 $pkg_base_recur ||= $part_pkg->base_recur_permonth($cust_pkg)
139 unless $self->option('cost_only');
140 $pkg_base_recur ||= 0;
142 my $pkg_start = $cust_pkg->get('setup');
143 if ( $pkg_start < $last_bill ) {
144 $pkg_start = $last_bill;
145 } elsif ( $pkg_setup_fee ) {
146 $pkg_charge += $quantity * $pkg_setup_fee;
147 $pkg_details .= $money_char.
148 sprintf('%.2f setup', $quantity * $pkg_setup_fee );
149 $pkg_details .= sprintf(" ($quantity \@ $money_char". '%.2f)',
152 $pkg_details .= ', ';
155 my $pkg_end = $cust_pkg->get('cancel');
156 $pkg_end = ( !$pkg_end || $pkg_end > $$sdate ) ? $$sdate : $pkg_end;
158 my $pkg_recur_charge = $prorate_ratio * $pkg_base_recur;
159 $pkg_recur_charge *= ( $pkg_end - $pkg_start )
160 / ( $$sdate - $last_bill )
161 unless $self->option('no_pkg_prorate');
163 my $recur_charge += $pkg_recur_charge;
165 if ( $recur_charge ) {
166 $pkg_details .= $money_char.
167 sprintf('%.2f', $quantity * $recur_charge );
168 $pkg_details .= sprintf(" ($quantity \@ $money_char". '%.2f)',
171 $pkg_details .= ' ('. time2str($date_format, $pkg_start).
172 ' - '. time2str($date_format, $pkg_end ). ')';
175 $pkg_charge += $quantity * $recur_charge;
178 if ( $self->option('display_separate_cust') ) {
179 push @$details, $cust_main->name.':' unless $cust_details++;
180 push @$details, ' '.$pkg_details;
182 push @$details, $cust_main->name_short.': '. $pkg_details;
186 $total_agent_charge += $pkg_charge;
190 push @$details, ' ' if $cust_details;
192 } #foreach $cust_main
196 my $charges = $total_agent_charge + $self->SUPER::calc_recur(@_); #prorate
198 sprintf('%.2f', $charges );
202 sub can_discount { 0; }
204 sub hide_svc_detail { 1; }
208 sub can_usageprice { 0; }