+sub insert {
+ my $self = shift;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $error = $self->SUPER::insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+
+ my $payable = $self->cust_bill_pkg->payable($self->setuprecur);
+ my $taxable = $self->_is_taxable ? $payable : 0;
+ my $part_pkg = $self->cust_bill_pkg->part_pkg;
+ my $freq = $part_pkg ? $part_pkg->freq || 1 : 1;# assume unchanged
+ my $taxable_per_month = sprintf("%.2f", $taxable / $freq );
+ my $credit_per_month = sprintf("%.2f", $self->amount / $freq ); #pennies?
+
+ if ($taxable_per_month >= 0) { #panic if its subzero?
+ my $groupby = 'taxnum,year,month';
+ my $sum = 'SUM(amount)';
+ my @exemptions = qsearch(
+ {
+ 'select' => "$groupby, $sum AS amount",
+ 'table' => 'cust_tax_exempt_pkg',
+ 'hashref' => { billpkgnum => $self->billpkgnum },
+ 'extra_sql' => "GROUP BY $groupby HAVING $sum > 0",
+ }
+ );
+ foreach my $exemption ( @exemptions ) {
+ next if $taxable_per_month >= $exemption->amount;
+ my $amount = $exemption->amount - $taxable_per_month;
+ if ($amount > $credit_per_month) {
+ "cust_bill_pkg ". $self->billpkgnum. " Reducing.\n";
+ $amount = $credit_per_month;
+ }
+ my $cust_tax_exempt_pkg = new FS::cust_tax_exempt_pkg {
+ 'billpkgnum' => $self->billpkgnum,
+ 'creditbillpkgnum' => $self->creditbillpkgnum,
+ 'amount' => 0-$amount,
+ map { $_ => $exemption->$_ } split(',', $groupby)
+ };
+ my $error = $cust_tax_exempt_pkg->insert;
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "error inserting cust_tax_exempt_pkg: $error";
+ }
+ }
+ }
+
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ '';
+
+}
+
+#helper functions for above
+sub _is_taxable {
+ my $self = shift;
+ my $part_pkg = $self->cust_bill_pkg->part_pkg;
+
+ return 0 unless $part_pkg; #XXX fails for tax on tax
+
+ my $method = $self->setuprecur. 'tax';
+ return 0 if $part_pkg->$method =~ /^Y$/i;
+
+ if ($self->billpkgtaxlocationnum) {
+ my $location_object = $self->cust_bill_pkg_tax_Xlocation;
+ my $tax_object = $location_object->cust_main_county;
+ return 0 if $tax_object && $self->tax_object->$method =~ /^Y$/i;
+ } #elsif ($self->billpkgtaxratelocationnum) { ... }
+
+ 1;
+}