158b5cf58e6ef1db92ed6cf37cc22b953cd23a63
[freeside.git] / FS / FS / cust_main / API.pm
1 package FS::cust_main::API;
2
3 use strict;
4 use FS::Conf;
5 use FS::part_tag;
6 use FS::Record qw( qsearchs );
7
8 =item API_getinfo FIELD => VALUE, ...
9
10 =cut
11
12 #some false laziness w/ClientAPI::Myaccount customer_info/customer_info_short
13
14 use vars qw(
15   @cust_main_addl_fields @cust_main_editable_fields @location_editable_fields
16 );
17 @cust_main_addl_fields = qw(
18   agentnum salesnum refnum classnum usernum referral_custnum
19 );
20 @cust_main_editable_fields = qw(
21   first last company daytime night fax mobile
22 );
23 #  locale
24 #  payby payinfo payname paystart_month paystart_year payissue payip
25 #  ss paytype paystate stateid stateid_state
26 @location_editable_fields = qw(
27   address1 address2 city county state zip country
28 );
29
30 sub API_getinfo {
31   my( $self, %opt ) = @_;
32
33   my %return = (
34     'error'           => '',
35     'display_custnum' => $self->display_custnum,
36     'name'            => $self->first. ' '. $self->get('last'),
37     'balance'         => $self->balance,
38     'status'          => $self->status,
39     'statuscolor'     => $self->statuscolor,
40   );
41
42   $return{$_} = $self->get($_)
43     foreach @cust_main_editable_fields;
44
45   unless ( $opt{'selfservice'} ) {
46     $return{$_} = $self->get($_)
47       foreach @cust_main_addl_fields;
48   }
49
50   for (@location_editable_fields) {
51     $return{$_} = $self->bill_location->get($_)
52       if $self->bill_locationnum;
53     $return{'ship_'.$_} = $self->ship_location->get($_)
54       if $self->ship_locationnum;
55   }
56
57   my @invoicing_list = $self->invoicing_list;
58   $return{'invoicing_list'} =
59     join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list );
60   $return{'postal_invoicing'} =
61     0 < ( grep { $_ eq 'POST' } @invoicing_list );
62
63   #generally, the more useful data from the cust_main record the better.
64   # well, tell me what you want
65
66   return \%return;
67
68 }
69
70
71 #or maybe all docs go in FS::API ?  argh
72
73 =item API_insert
74
75 Class method (constructor).
76
77 Example:
78
79   use FS::cust_main;
80   FS::cust_main->API_insert(
81     'agentnum' => 1,
82     'refnum'   => 1,
83     'first'    => 'Harvey',
84     'last'     => 'Black',
85     'address1' => '5354 Pink Rabbit Lane',
86     'city'     => 'Farscape',
87     'state'    => 'CA',
88     'zip'      => '54144',
89
90     'invoicing_list' => 'harvey2@example.com',
91   );
92
93 =cut
94
95 #certainly false laziness w/ClientAPI::Signup new_customer/new_customer_minimal
96 # but approaching this from a clean start / back-office perspective
97 #  i.e. no package/service, no immediate credit card run, etc.
98
99 sub API_insert {
100   my( $class, %opt ) = @_;
101
102   my $conf = new FS::Conf;
103
104   #default agentnum like signup_server-default_agentnum?
105  
106   #same for refnum like signup_server-default_refnum?
107
108   my $cust_main = new FS::cust_main ( { # $class->new( {
109       'payby'  => 'BILL',
110       'tagnum' => [ FS::part_tag->default_tags ],
111
112       map { $_ => $opt{$_} } qw(
113         agentnum salesnum refnum agent_custid referral_custnum
114         last first company 
115         daytime night fax mobile
116         payby payinfo paydate paycvv payname
117       ),
118
119   } );
120
121   my @invoicing_list = $opt{'invoicing_list'}
122                          ? split( /\s*\,\s*/, $opt{'invoicing_list'} )
123                          : ();
124   push @invoicing_list, 'POST' if $opt{'postal_invoicing'};
125
126   my ($bill_hash, $ship_hash);
127   foreach my $f (FS::cust_main->location_fields) {
128     # avoid having to change this in front-end code
129     $bill_hash->{$f} = $opt{"bill_$f"} || $opt{$f};
130     $ship_hash->{$f} = $opt{"ship_$f"};
131   }
132
133   my $bill_location = FS::cust_location->new($bill_hash);
134   my $ship_location;
135   # we don't have an equivalent of the "same" checkbox in selfservice^Wthis API
136   # so is there a ship address, and if so, is it different from the billing 
137   # address?
138   if ( length($ship_hash->{address1}) > 0 and
139           grep { $bill_hash->{$_} ne $ship_hash->{$_} } keys(%$ship_hash)
140          ) {
141
142     $ship_location = FS::cust_location->new( $ship_hash );
143   
144   } else {
145     $ship_location = $bill_location;
146   }
147
148   $cust_main->set('bill_location' => $bill_location);
149   $cust_main->set('ship_location' => $ship_location);
150
151   my $error = $cust_main->insert( {}, \@invoicing_list );
152   return { 'error'   => $error } if $error;
153   
154   return { 'error'   => '',
155            'custnum' => $cust_main->custnum,
156          };
157
158 }
159
160 sub API_update {
161
162  my( $class, %opt ) = @_;
163
164   my $conf = new FS::Conf;
165
166   my $custnum = $opt{'custnum'}
167     or return { 'error' => "no customer record" };
168
169   my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
170     or return { 'error' => "unknown custnum $custnum" };
171
172   my $new = new FS::cust_main { $cust_main->hash };
173
174   $new->set( $_ => $opt{$_} )
175     foreach grep { exists $opt{$_} } qw(
176         agentnum salesnum refnum agent_custid referral_custnum
177         last first company
178         daytime night fax mobile
179         payby payinfo paydate paycvv payname
180       ),
181
182   my @invoicing_list;
183   if ( exists $opt{'invoicing_list'} || exists $opt{'postal_invoicing'} ) {
184     @invoicing_list = split( /\s*\,\s*/, $opt{'invoicing_list'} );
185     push @invoicing_list, 'POST' if $opt{'postal_invoicing'};
186   } else {
187     @invoicing_list = $cust_main->invoicing_list;
188   }
189
190   if ( exists( $opt{'address1'} ) ) {
191     my $bill_location = FS::cust_location->new({
192         map { $_ => $opt{$_} } @location_editable_fields
193     });
194     $bill_location->set('custnum' => $custnum);
195     my $error = $bill_location->find_or_insert;
196     die $error if $error;
197
198     # if this is unchanged from before, cust_main::replace will ignore it
199     $new->set('bill_location' => $bill_location);
200   }
201
202   if ( exists($opt{'ship_address1'}) && length($opt{"ship_address1"}) > 0 ) {
203     my $ship_location = FS::cust_location->new({
204         map { $_ => $opt{"ship_$_"} } @location_editable_fields
205     });
206
207     $ship_location->set('custnum' => $custnum);
208     my $error = $ship_location->find_or_insert;
209     die $error if $error;
210
211    $new->set('ship_location' => $ship_location);
212
213    } elsif (exists($opt{'ship_address1'} ) && !grep { length($opt{"ship_$_"}) } @location_editable_fields ) {
214       my $ship_location = $new->bill_location;
215      $new->set('ship_location' => $ship_location);
216    }
217
218   my $error = $new->replace( $cust_main, \@invoicing_list );
219   return { 'error'   => $error } if $error;
220
221   return { 'error'   => '',
222          };  
223 }
224
225 1;