RT#25563: Better handling of commissions which do not have rates configured
[freeside.git] / FS / FS / part_event / Action / bill_sales_credit.pm
1 package FS::part_event::Action::bill_sales_credit;
2
3 # in this order:
4 # - pkg_sales_credit invokes NEXT, then appends the 'cust_main_sales' param
5 # - credit_bill contains the core _calc_credit logic, and also defines other
6 # params
7
8 use base qw( FS::part_event::Action::Mixin::pkg_sales_credit
9              FS::part_event::Action::Mixin::credit_bill
10              FS::part_event::Action );
11 use FS::Record qw(qsearch qsearchs);
12 use FS::Conf;
13 use Date::Format qw(time2str);
14
15 use strict;
16
17 sub description { 'Credit the sales person based on the billed amount'; }
18
19 sub eventtable_hashref {
20   { 'cust_bill' => 1 };
21 }
22
23 our $date_format;
24
25 sub do_action {
26   my( $self, $cust_bill, $cust_event ) = @_;
27
28   $date_format ||= FS::Conf->new->config('date_format') || '%x';
29
30   my $cust_main = $self->cust_main($cust_bill);
31
32   my %salesnum_sales; # salesnum => FS::sales object
33   my %salesnum_amount; # salesnum => credit amount
34   my %pkgnum_pkg; # pkgnum => FS::cust_pkg
35   my %salesnum_pkgnums; # salesnum => [ pkgnum, ... ]
36
37   my @items = qsearch('cust_bill_pkg', { invnum => $cust_bill->invnum,
38                                          pkgnum => { op => '>', value => '0' }
39                                        });
40
41   my $warning = '';
42   foreach my $cust_bill_pkg (@items) {
43     my $pkgnum = $cust_bill_pkg->pkgnum;
44     my $cust_pkg = $pkgnum_pkg{$pkgnum} ||= $cust_bill_pkg->cust_pkg;
45
46     my $salesnum = $cust_pkg->salesnum;
47     $salesnum ||= $cust_main->salesnum
48       if $self->option('cust_main_sales');
49     my $sales = $salesnum_sales{$salesnum}
50             ||= FS::sales->by_key($salesnum);
51
52     next if !$sales; #no sales person, no credit
53
54     my $amount = $self->_calc_credit($cust_bill_pkg, $sales, \$warning);
55
56     if ($amount > 0) {
57       $salesnum_amount{$salesnum} ||= 0;
58       $salesnum_amount{$salesnum} += $amount;
59       push @{ $salesnum_pkgnums{$salesnum} ||= [] }, $pkgnum;
60     }
61   }
62
63   foreach my $salesnum (keys %salesnum_amount) {
64     my $amount = sprintf('%.2f', $salesnum_amount{$salesnum});
65     next if $amount < 0.005;
66
67     my $sales = $salesnum_sales{$salesnum};
68
69     my $sales_cust_main = $sales->sales_cust_main;
70     die "No customer record for sales person ". $sales->salesperson
71       unless $sales->sales_custnum;
72
73     my $reasonnum = $self->option('reasonnum');
74
75     my $desc = 'from invoice #'. $cust_bill->display_invnum .
76                ' ('. time2str($date_format, $cust_bill->_date) . ')';
77                # could also show custnum and pkgnums here?
78     my $error = $sales_cust_main->credit(
79       $amount, 
80       \$reasonnum,
81       'eventnum'            => $cust_event->eventnum,
82       'addlinfo'            => $desc,
83       'commission_salesnum' => $sales->salesnum,
84     );
85     die "Error crediting customer ". $sales_cust_main->custnum.
86         " for sales commission: $error"
87       if $error;
88   } # foreach $salesnum
89
90   return $warning;
91
92 }
93
94 1;