summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorivan <ivan>2009-01-08 01:45:22 +0000
committerivan <ivan>2009-01-08 01:45:22 +0000
commit2b8ffc98529637ffddfe7cbf6b4f9b8deb90f0fa (patch)
treebfd6fad6189838b809f405b3e83f613f4e436537 /FS
parent619b9c20b1c2c76d439284bd6d023e5d5d9dbc7d (diff)
start adding package locations, RT#4499
Diffstat (limited to 'FS')
-rw-r--r--FS/FS.pm2
-rw-r--r--FS/FS/Conf.pm7
-rw-r--r--FS/FS/Schema.pm57
-rw-r--r--FS/FS/cust_location.pm175
-rw-r--r--FS/FS/cust_main.pm168
-rw-r--r--FS/FS/cust_pkg.pm32
-rw-r--r--FS/MANIFEST2
-rw-r--r--FS/t/cust_location.t5
8 files changed, 389 insertions, 59 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index 7e9b04eb2..c4be977f1 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -222,6 +222,8 @@ L<FS::cust_pkg_reason> - Package reason class
L<FS::cust_main> - Customer class
+L<FS::cust_main_location> - Customer location class
+
L<FS::cust_main_Mixin> - Mixin class for records that contain fields from cust_main
L<FS::cust_main_invoice> - Invoice destination class
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 5d5616938..9c9c6aaaf 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -2001,6 +2001,13 @@ worry that config_items is freeside-specific and icky.
'section' => 'billing',
'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the shipping address instead. Note: Tax reports can take a long time when enabled.',
'type' => 'checkbox',
+ }
+,
+ {
+ 'key' => 'tax-pkg_address',
+ 'section' => 'billing',
+ 'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the package address instead (when present). Note: Tax reports can take a long time when enabled.',
+ 'type' => 'checkbox',
},
{
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 17665b132..ecf017e3b 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -671,6 +671,28 @@ sub tables_hashref {
],
},
+ #eventually use for billing & ship from cust_main too
+ #for now, just cust_pkg locations
+ 'cust_location' => {
+ 'columns' => [
+ 'locationnum', 'serial', '', '', '', '',
+ 'custnum', 'int', '', '', '', '',
+ 'address1', 'varchar', '', $char_d, '', '',
+ 'address2', 'varchar', 'NULL', $char_d, '', '',
+ 'city', 'varchar', '', $char_d, '', '',
+ 'county', 'varchar', 'NULL', $char_d, '', '',
+ 'state', 'varchar', 'NULL', $char_d, '', '',
+ 'zip', 'varchar', 'NULL', 10, '', '',
+ 'country', 'char', '', 2, '', '',
+ 'geocode', 'varchar', 'NULL', 20, '', '',
+ ],
+ 'primary_key' => 'locationnum',
+ 'unique' => [],
+ 'index' => [ [ 'custnum' ],
+ [ 'county' ], [ 'state' ], [ 'country' ], [ 'zip' ],
+ ],
+ },
+
'cust_main_invoice' => {
'columns' => [
'destnum', 'serial', '', '', '', '',
@@ -938,26 +960,27 @@ sub tables_hashref {
'cust_pkg' => {
'columns' => [
- 'pkgnum', 'serial', '', '', '', '',
- 'custnum', 'int', '', '', '', '',
- 'pkgpart', 'int', '', '', '', '',
- 'otaker', 'varchar', '', 32, '', '',
- 'setup', @date_type, '', '',
- 'bill', @date_type, '', '',
- 'last_bill', @date_type, '', '',
- 'susp', @date_type, '', '',
- 'adjourn', @date_type, '', '',
- 'cancel', @date_type, '', '',
- 'expire', @date_type, '', '',
- 'change_date', @date_type, '', '',
- 'change_pkgnum', 'int', 'NULL', '', '', '',
- 'change_pkgpart', 'int', 'NULL', '', '', '',
- 'manual_flag', 'char', 'NULL', 1, '', '',
- 'quantity', 'int', 'NULL', '', '', '',
+ 'pkgnum', 'serial', '', '', '', '',
+ 'custnum', 'int', '', '', '', '',
+ 'pkgpart', 'int', '', '', '', '',
+ 'locationnum', 'int', 'NULL', '', '', '',
+ 'otaker', 'varchar', '', 32, '', '',
+ 'setup', @date_type, '', '',
+ 'bill', @date_type, '', '',
+ 'last_bill', @date_type, '', '',
+ 'susp', @date_type, '', '',
+ 'adjourn', @date_type, '', '',
+ 'cancel', @date_type, '', '',
+ 'expire', @date_type, '', '',
+ 'change_date', @date_type, '', '',
+ 'change_pkgnum', 'int', 'NULL', '', '', '',
+ 'change_pkgpart', 'int', 'NULL', '', '', '',
+ 'manual_flag', 'char', 'NULL', 1, '', '',
+ 'quantity', 'int', 'NULL', '', '', '',
],
'primary_key' => 'pkgnum',
'unique' => [],
- 'index' => [ ['custnum'], ['pkgpart'],
+ 'index' => [ ['custnum'], ['pkgpart'], [ 'locationnum' ],
['setup'], ['last_bill'], ['bill'], ['susp'], ['adjourn'],
['expire'], ['cancel'],
['change_date'],
diff --git a/FS/FS/cust_location.pm b/FS/FS/cust_location.pm
new file mode 100644
index 000000000..0544dcfba
--- /dev/null
+++ b/FS/FS/cust_location.pm
@@ -0,0 +1,175 @@
+package FS::cust_location;
+
+use strict;
+use base qw( FS::Record );
+use Locale::Country;
+use FS::Record qw( qsearch ); #qsearchs );
+use FS::cust_main;
+use FS::cust_main_county;
+
+=head1 NAME
+
+FS::cust_location - Object methods for cust_location records
+
+=head1 SYNOPSIS
+
+ use FS::cust_location;
+
+ $record = new FS::cust_location \%hash;
+ $record = new FS::cust_location { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_location object represents a customer location. FS::cust_location
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item locationnum
+
+primary key
+
+=item custnum
+
+custnum
+
+=item address1
+
+Address line one (required)
+
+=item address2
+
+Address line two (optional)
+
+=item city
+
+City
+
+=item county
+
+County (optional, see L<FS::cust_main_county>)
+
+=item state
+
+State (see L<FS::cust_main_county>)
+
+=item zip
+
+Zip
+
+=item country
+
+Country (see L<FS::cust_main_county>)
+
+=item geocode
+
+Geocode
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new location. To add the location to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_location'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid location. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+#some false laziness w/cust_main, but since it should eventually lose these
+#fields anyway...
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('locationnum')
+ || $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
+ || $self->ut_text('address1')
+ || $self->ut_textn('address2')
+ || $self->ut_text('city')
+ || $self->ut_textn('county')
+ || $self->ut_textn('state')
+ || $self->ut_country('country')
+ || $self->ut_zip('zip', $self->country)
+ || $self->ut_alphan('geocode')
+ ;
+ return $error if $error;
+
+ unless ( qsearch('cust_main_county', {
+ 'country' => $self->country,
+ 'state' => '',
+ } ) ) {
+ return "Unknown state/county/country: ".
+ $self->state. "/". $self->county. "/". $self->country
+ unless qsearch('cust_main_county',{
+ 'state' => $self->state,
+ 'county' => $self->county,
+ 'country' => $self->country,
+ } );
+ }
+
+ $self->SUPER::check;
+}
+
+=item country_full
+
+Returns this locations's full country name
+
+=cut
+
+sub country_full {
+ my $self = shift;
+ code2country($self->country);
+}
+
+=back
+
+=head1 BUGS
+
+Not yet used for cust_main billing and shipping addresses.
+
+=head1 SEE ALSO
+
+L<FS::cust_main_county>, L<FS::cust_pkg>, L<FS::Record>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index da1d3e195..2b94dca33 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -135,101 +135,181 @@ FS::Record. The following fields are currently supported:
=over 4
-=item custnum - primary key (assigned automatically for new customers)
+=item custnum
-=item agentnum - agent (see L<FS::agent>)
+Primary key (assigned automatically for new customers)
-=item refnum - Advertising source (see L<FS::part_referral>)
+=item agentnum
+
+Agent (see L<FS::agent>)
+
+=item refnum
+
+Advertising source (see L<FS::part_referral>)
+
+=item first
+
+First name
-=item first - name
+=item last
-=item last - name
+Last name
-=item ss - social security number (optional)
+=item ss
-=item company - (optional)
+Cocial security number (optional)
+
+=item company
+
+(optional)
=item address1
-=item address2 - (optional)
+=item address2
+
+(optional)
=item city
-=item county - (optional, see L<FS::cust_main_county>)
+=item county
-=item state - (see L<FS::cust_main_county>)
+(optional, see L<FS::cust_main_county>)
+
+=item state
+
+(see L<FS::cust_main_county>)
=item zip
-=item country - (see L<FS::cust_main_county>)
+=item country
+
+(see L<FS::cust_main_county>)
-=item daytime - phone (optional)
+=item daytime
-=item night - phone (optional)
+phone (optional)
-=item fax - phone (optional)
+=item night
-=item ship_first - name
+phone (optional)
-=item ship_last - name
+=item fax
-=item ship_company - (optional)
+phone (optional)
+
+=item ship_first
+
+Shipping first name
+
+=item ship_last
+
+Shipping last name
+
+=item ship_company
+
+(optional)
=item ship_address1
-=item ship_address2 - (optional)
+=item ship_address2
+
+(optional)
=item ship_city
-=item ship_county - (optional, see L<FS::cust_main_county>)
+=item ship_county
+
+(optional, see L<FS::cust_main_county>)
+
+=item ship_state
-=item ship_state - (see L<FS::cust_main_county>)
+(see L<FS::cust_main_county>)
=item ship_zip
-=item ship_country - (see L<FS::cust_main_county>)
+=item ship_country
-=item ship_daytime - phone (optional)
+(see L<FS::cust_main_county>)
-=item ship_night - phone (optional)
+=item ship_daytime
-=item ship_fax - phone (optional)
+phone (optional)
-=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+=item ship_night
-=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
+phone (optional)
-=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
+=item ship_fax
+
+phone (optional)
+
+=item payby
+
+Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+
+=item payinfo
+
+Payment Information (See L<FS::payinfo_Mixin> for data format)
+
+=item paymask
+
+Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
=item paycvv
Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card
-=item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
+=item paydate
+
+Expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
+
+=item paystart_month
+
+Start date month (maestro/solo cards only)
+
+=item paystart_year
+
+Start date year (maestro/solo cards only)
-=item paystart_month - start date month (maestro/solo cards only)
+=item payissue
-=item paystart_year - start date year (maestro/solo cards only)
+Issue number (maestro/solo cards only)
-=item payissue - issue number (maestro/solo cards only)
+=item payname
-=item payname - name on card or billing name
+Name on card or billing name
-=item payip - IP address from which payment information was received
+=item payip
-=item tax - tax exempt, empty or `Y'
+IP address from which payment information was received
-=item otaker - order taker (assigned automatically, see L<FS::UID>)
+=item tax
-=item comments - comments (optional)
+Tax exempt, empty or `Y'
-=item referral_custnum - referring customer number
+=item otaker
-=item spool_cdr - Enable individual CDR spooling, empty or `Y'
+Order taker (assigned automatically, see L<FS::UID>)
-=item dundate - a suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+=item comments
-=item squelch_cdr - Discourage individual CDR printing, empty or `Y'
+Comments (optional)
+
+=item referral_custnum
+
+Referring customer number
+
+=item spool_cdr
+
+Enable individual CDR spooling, empty or `Y'
+
+=item dundate
+
+A suggestion to events (see L<FS::part_bill_event">) to delay until this unix timestamp
+
+=item squelch_cdr
+
+Discourage individual CDR printing, empty or `Y'
=back
@@ -2905,6 +2985,11 @@ Only return events for the specified eventtable (by default, events of all event
Explicitly pass the objects to be tested (typically used with eventtable).
+=item testonly
+
+Set to true to return the objects, but not actually insert them into the
+database.
+
=back
=cut
@@ -2935,7 +3020,8 @@ sub due_cust_event {
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
- $self->select_for_update; #mutex
+ $self->select_for_update #mutex
+ unless $opt{testonly};
###
# 1: find possible events (initial search)
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 70f23df9b..03cec75b8 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -13,6 +13,7 @@ use FS::cust_main_Mixin;
use FS::cust_svc;
use FS::part_pkg;
use FS::cust_main;
+use FS::cust_location;
use FS::type_pkgs;
use FS::pkg_svc;
use FS::cust_bill_pkg;
@@ -106,7 +107,7 @@ inherits from FS::Record. The following fields are currently supported:
=item pkgnum
-primary key (assigned automatically for new billing items)
+Primary key (assigned automatically for new billing items)
=item custnum
@@ -116,6 +117,10 @@ Customer (see L<FS::cust_main>)
Billing item definition (see L<FS::part_pkg>)
+=item locationnum
+
+Optional link to package location (see L<FS::location>)
+
=item setup
date
@@ -435,6 +440,7 @@ sub check {
$self->ut_numbern('pkgnum')
|| $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
|| $self->ut_numbern('pkgpart')
+ || $self->ut_foreign_keyn('locationnum', 'location', 'locationnum')
|| $self->ut_numbern('setup')
|| $self->ut_numbern('bill')
|| $self->ut_numbern('susp')
@@ -1569,6 +1575,30 @@ sub cust_main {
qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
}
+=item cust_location
+
+Returns the location object, if any (see L<FS::cust_location>).
+
+=cut
+
+sub cust_location {
+ my $self = shift;
+ return '' unless $self->locationnum;
+ qsearchs( 'cust_main', { 'locationnum' => $self->locationnum } );
+}
+
+=item cust_location_or_main
+
+If this package is associated with a location, returns the locaiton (see
+L<FS::cust_location>), otherwise returns the customer (see L<FS::cust_main>).
+
+=cut
+
+sub cust_location_or_main {
+ my $self = shift;
+ $self->cust_location || $self->cust_main;
+}
+
=item seconds_since TIMESTAMP
Returns the number of seconds all accounts (see L<FS::svc_acct>) in this
diff --git a/FS/MANIFEST b/FS/MANIFEST
index c3252425b..21d721dcb 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -427,3 +427,5 @@ FS/cust_bill_pkg_display.pm
t/cust_bill_pkg_display.t
FS/cust_pkg_detail.pm
t/cust_pkg_detail.t
+FS/cust_location.pm
+t/cust_location.t
diff --git a/FS/t/cust_location.t b/FS/t/cust_location.t
new file mode 100644
index 000000000..e98372d72
--- /dev/null
+++ b/FS/t/cust_location.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_location;
+$loaded=1;
+print "ok 1\n";