1 package FS::cust_tax_exempt_pkg;
5 use FS::Record qw( qsearch qsearchs );
6 use FS::cust_main_Mixin;
8 use FS::cust_main_county;
10 use FS::cust_credit_bill_pkg;
12 use FS::upgrade_journal;
14 # some kind of common ancestor with cust_bill_pkg_tax_location would make sense
16 @ISA = qw( FS::cust_main_Mixin FS::Record );
20 FS::cust_tax_exempt_pkg - Object methods for cust_tax_exempt_pkg records
24 use FS::cust_tax_exempt_pkg;
26 $record = new FS::cust_tax_exempt_pkg \%hash;
27 $record = new FS::cust_tax_exempt_pkg { 'column' => 'value' };
29 $error = $record->insert;
31 $error = $new_record->replace($old_record);
33 $error = $record->delete;
35 $error = $record->check;
39 An FS::cust_tax_exempt_pkg object represents a record of a customer tax
40 exemption. Whenever a package would be taxed (based on its location and
41 taxclass), but some or all of it is exempt from taxation, an
42 FS::cust_tax_exempt_pkg record is created.
44 FS::cust_tax_exempt inherits from FS::Record. The following fields are
49 =item exemptpkgnum - primary key
51 =item billpkgnum - invoice line item (see L<FS::cust_bill_pkg>) that
52 was exempted from tax.
54 =item taxtype - the object class of the tax record ('FS::cust_main_county'
57 =item taxnum - tax rate (see L<FS::cust_main_county>)
59 =item year - the year in which the exemption occurred. NULL if this
60 is a customer or package exemption rather than a monthly exemption.
62 =item month - the month in which the exemption occurred. NULL if this
63 is a customer or package exemption.
65 =item amount - the amount of revenue exempted. For monthly exemptions
66 this may be anything up to the monthly exemption limit defined in
67 L<FS::cust_main_county> for this tax. For customer exemptions it is
68 always the full price of the line item. For package exemptions it
69 may be the setup fee, the recurring fee, or the sum of those.
71 =item exempt_cust - flag indicating that the customer is tax-exempt
72 (cust_main.tax = 'Y').
74 =item exempt_cust_taxname - flag indicating that the customer is exempt
75 from the tax with this name (see L<FS::cust_main_exemption).
77 =item exempt_setup, exempt_recur: flag indicating that the package's setup
78 or recurring fee is not taxable (part_pkg.setuptax and part_pkg.recurtax).
80 =item exempt_monthly: flag indicating that this is a monthly per-customer
81 exemption (Texas tax).
91 Creates a new exemption record. To add the examption record to the database,
94 Note that this stores the hash reference, not a distinct copy of the hash it
95 points to. You can ask the object for a copy with the I<hash> method.
99 # the new method can be inherited from FS::Record, if a table method is defined
101 sub table { 'cust_tax_exempt_pkg'; }
105 Adds this record to the database. If there is an error, returns the error,
106 otherwise returns false.
110 # the insert method can be inherited from FS::Record
114 Delete this record from the database.
118 # the delete method can be inherited from FS::Record
120 =item replace OLD_RECORD
122 Replaces the OLD_RECORD with this one in the database. If there is an error,
123 returns the error, otherwise returns false.
127 # the replace method can be inherited from FS::Record
131 Checks all fields to make sure this is a valid exemption record. If there is
132 an error, returns the error, otherwise returns false. Called by the insert
137 # the check method should currently be supplied - FS::Record contains some
138 # data checking routines
143 my $error = $self->ut_numbern('exemptnum')
144 || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum')
145 || $self->ut_enum('taxtype', [ 'FS::cust_main_county', 'FS::tax_rate' ])
146 || $self->ut_foreign_keyn('creditbillpkgnum',
147 'cust_credit_bill_pkg',
149 || $self->ut_numbern('year') #check better
150 || $self->ut_numbern('month') #check better
151 || $self->ut_money('amount')
152 || $self->ut_flag('exempt_cust')
153 || $self->ut_flag('exempt_setup')
154 || $self->ut_flag('exempt_recur')
155 || $self->ut_flag('exempt_cust_taxname')
156 || $self->SUPER::check
159 $self->get('taxtype') =~ /^FS::(\w+)$/;
161 $error ||= $self->ut_foreign_key('taxnum', $rate_table, 'taxnum');
163 return $error if $error;
165 if ( $self->get('exempt_cust') ) {
166 $self->set($_ => '') for qw(
167 exempt_cust_taxname exempt_setup exempt_recur exempt_monthly month year
169 } elsif ( $self->get('exempt_cust_taxname') ) {
170 $self->set($_ => '') for qw(
171 exempt_setup exempt_recur exempt_monthly month year
173 } elsif ( $self->get('exempt_setup') || $self->get('exempt_recur') ) {
174 $self->set($_ => '') for qw(exempt_monthly month year);
175 } elsif ( $self->get('exempt_monthly') ) {
176 $self->year =~ /^\d{4}$/
177 or return "illegal exemption year: '".$self->year."'";
178 $self->month >= 1 && $self->month <= 12
179 or return "illegal exemption month: '".$self->month."'";
181 return "no exemption type selected";
187 =item cust_main_county
191 Returns the associated tax definition if it still exists in the database.
192 Otherwise returns false.
196 sub cust_main_county {
198 my $class = $self->taxtype;
199 $class->by_key($self->taxnum);
204 my $class = $self->taxtype;
205 $class->by_key($self->taxnum);
211 my $journal = 'cust_tax_exempt_pkg_flags';
212 if ( !FS::upgrade_journal->is_done($journal) ) {
213 my $sql = "UPDATE cust_tax_exempt_pkg SET exempt_monthly = 'Y' ".
214 "WHERE month IS NOT NULL";
215 dbh->do($sql) or die dbh->errstr;
216 FS::upgrade_journal->set_done($journal);
219 $journal = 'cust_tax_exempt_pkg_taxtype';
220 if ( !FS::upgrade_journal->is_done($journal) ) {
221 my $sql = "UPDATE cust_tax_exempt_pkg ".
222 "SET taxtype = 'FS::cust_main_county' WHERE taxtype IS NULL";
223 dbh->do($sql) or die dbh->errstr;
224 $sql = "UPDATE cust_tax_exempt_pkg_void ".
225 "SET taxtype = 'FS::cust_main_county' WHERE taxtype IS NULL";
226 dbh->do($sql) or die dbh->errstr;
227 FS::upgrade_journal->set_done($journal);
237 Texas tax is still a royal pain in the ass.
241 L<FS::cust_main_county>, L<FS::cust_bill_pkg>, L<FS::Record>, schema.html from
242 the base documentation.