ACL for hardware class config, RT#85057
[freeside.git] / FS / FS / cust_tax_exempt_pkg.pm
1 package FS::cust_tax_exempt_pkg;
2 use base qw( FS::cust_main_Mixin FS::Record );
3
4 use strict;
5 use FS::UID qw(dbh);
6 use FS::cust_main_county;
7 use FS::upgrade_journal;
8
9 # some kind of common ancestor with cust_bill_pkg_tax_location would make sense
10
11 =head1 NAME
12
13 FS::cust_tax_exempt_pkg - Object methods for cust_tax_exempt_pkg records
14
15 =head1 SYNOPSIS
16
17   use FS::cust_tax_exempt_pkg;
18
19   $record = new FS::cust_tax_exempt_pkg \%hash;
20   $record = new FS::cust_tax_exempt_pkg { 'column' => 'value' };
21
22   $error = $record->insert;
23
24   $error = $new_record->replace($old_record);
25
26   $error = $record->delete;
27
28   $error = $record->check;
29
30 =head1 DESCRIPTION
31
32 An FS::cust_tax_exempt_pkg object represents a record of a customer tax
33 exemption.  Whenever a package would be taxed (based on its location and
34 taxclass), but some or all of it is exempt from taxation, an 
35 FS::cust_tax_exempt_pkg record is created.
36
37 FS::cust_tax_exempt inherits from FS::Record.  The following fields are 
38 currently supported:
39
40 =over 4
41
42 =item exemptpkgnum - primary key
43
44 =item billpkgnum - invoice line item (see L<FS::cust_bill_pkg>) that 
45 was exempted from tax.
46
47 =item taxnum - tax rate (see L<FS::cust_main_county>)
48
49 =item year - the year in which the exemption occurred.  NULL if this 
50 is a customer or package exemption rather than a monthly exemption.
51
52 =item month - the month in which the exemption occurred.  NULL if this
53 is a customer or package exemption.
54
55 =item amount - the amount of revenue exempted.  For monthly exemptions
56 this may be anything up to the monthly exemption limit defined in 
57 L<FS::cust_main_county> for this tax.  For customer exemptions it is 
58 always the full price of the line item.  For package exemptions it 
59 may be the setup fee, the recurring fee, or the sum of those.
60
61 =item exempt_cust - flag indicating that the customer is tax-exempt
62 (cust_main.tax = 'Y').
63
64 =item exempt_cust_taxname - flag indicating that the customer is exempt 
65 from the tax with this name (see L<FS::cust_main_exemption>).
66
67 =item exempt_setup, exempt_recur: flag indicating that the package's setup
68 or recurring fee is not taxable (part_pkg.setuptax and part_pkg.recurtax).
69
70 =item exempt_monthly: flag indicating that this is a monthly per-customer
71 exemption (Texas tax).
72
73 =back
74
75 =head1 METHODS
76
77 =over 4
78
79 =item new HASHREF
80
81 Creates a new exemption record.  To add the examption record to the database,
82 see L<"insert">.
83
84 Note that this stores the hash reference, not a distinct copy of the hash it
85 points to.  You can ask the object for a copy with the I<hash> method.
86
87 =cut
88
89 # the new method can be inherited from FS::Record, if a table method is defined
90
91 sub table { 'cust_tax_exempt_pkg'; }
92
93 =item insert
94
95 Adds this record to the database.  If there is an error, returns the error,
96 otherwise returns false.
97
98 =cut
99
100 # the insert method can be inherited from FS::Record
101
102 =item delete
103
104 Delete this record from the database.
105
106 =cut
107
108 # the delete method can be inherited from FS::Record
109
110 =item replace OLD_RECORD
111
112 Replaces the OLD_RECORD with this one in the database.  If there is an error,
113 returns the error, otherwise returns false.
114
115 =cut
116
117 # the replace method can be inherited from FS::Record
118
119 =item check
120
121 Checks all fields to make sure this is a valid exemption record.  If there is
122 an error, returns the error, otherwise returns false.  Called by the insert
123 and replace methods.
124
125 =cut
126
127 # the check method should currently be supplied - FS::Record contains some
128 # data checking routines
129
130 sub check {
131   my $self = shift;
132
133   my $error = $self->ut_numbern('exemptnum')
134     || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum')
135     || $self->ut_foreign_key('taxnum', 'cust_main_county', 'taxnum')
136     || $self->ut_foreign_keyn('creditbillpkgnum',
137                               'cust_credit_bill_pkg',
138                               'creditbillpkgnum')
139     || $self->ut_numbern('year') #check better
140     || $self->ut_numbern('month') #check better
141     || $self->ut_money('amount')
142     || $self->ut_flag('exempt_cust')
143     || $self->ut_flag('exempt_setup')
144     || $self->ut_flag('exempt_recur')
145     || $self->ut_flag('exempt_cust_taxname')
146     || $self->SUPER::check
147   ;
148
149   return $error if $error;
150
151   if ( $self->get('exempt_cust') ) {
152     $self->set($_ => '') for qw(
153       exempt_cust_taxname exempt_setup exempt_recur exempt_monthly month year
154     );
155   } elsif ( $self->get('exempt_cust_taxname')  ) {
156     $self->set($_ => '') for qw(
157       exempt_setup exempt_recur exempt_monthly month year
158     );
159   } elsif ( $self->get('exempt_setup') || $self->get('exempt_recur') ) {
160     $self->set($_ => '') for qw(exempt_monthly month year);
161   } elsif ( $self->get('exempt_monthly') ) {
162     $self->year =~ /^\d{4}$/
163         or return "illegal exemption year: '".$self->year."'";
164     $self->month >= 1 && $self->month <= 12
165         or return "illegal exemption month: '".$self->month."'";
166   } else {
167     return "no exemption type selected";
168   }
169
170   '';
171 }
172
173 =item cust_main_county
174
175 Returns the associated tax definition if it still exists in the database.
176 Otherwise returns false.
177
178 =cut
179
180 # do not remove; this can't be autogenerated
181
182 sub cust_main_county {
183   my $self = shift;
184   if ( $self->taxtype eq 'FS::cust_main_county' ) {
185     return FS::cust_main_county->by_key($self->taxnum);
186   }
187   '';
188 }
189
190 sub _upgrade_data {
191   my $class = shift;
192
193   my $journal = 'cust_tax_exempt_pkg_flags';
194   if ( !FS::upgrade_journal->is_done($journal) ) {
195     my $sql = "UPDATE cust_tax_exempt_pkg SET exempt_monthly = 'Y' ".
196               "WHERE month IS NOT NULL";
197     dbh->do($sql) or die dbh->errstr;
198     FS::upgrade_journal->set_done($journal);
199   }
200 }
201
202 =back
203
204 =head1 BUGS
205
206 Texas tax is still a royal pain in the ass.
207
208 =head1 SEE ALSO
209
210 L<FS::cust_main_county>, L<FS::cust_bill_pkg>, L<FS::Record>, schema.html from
211 the base documentation.
212
213 =cut
214
215 1;
216