Import original source of WebService-Northern911 0.1
[WebService-Northern911.git] / lib / WebService / Northern911.pm
1 package WebService::Northern911;
2
3 use Digest::MD5 'md5_hex';
4 use DateTime;
5 use XML::Compile::WSDL11;
6 use XML::Compile::SOAP11;
7 use XML::Compile::Transport::SOAPHTTP;
8 use File::ShareDir 'dist_dir';
9
10 use WebService::Northern911::Response;
11
12 our $VERSION = 0.1;
13
14 =head1 NAME
15
16 WebService::Northern911 - Interface to the Northern 911 ALI database
17
18 =head1 SYNOPSIS
19
20 use WebService::Northern911;
21
22 my $n911 = WebService::Northern911->new( vendor_code => '007',
23                                   password => '280fip1@' );
24
25 my $result = $n911->AddorUpdateCustomer(
26   PHONE_NUMBER    => '4015559988',
27   FIRST_NAME      => 'John',
28   LAST_NAME       => 'Doe',
29   STREET_NUMBER   => 1024,
30   STREET_NAME     => 'Main St',
31   CITY            => 'Calgary',
32   PROVINCE_STATE  => 'AB',
33   POSTAL_CODE_ZIP => 'Z1A A2Z',
34 );
35 if ($result->is_success) {
36   print "Updated customer."
37 } else 
38   print $result->error_message;
39 }
40
41 =head1 METHODS
42
43 =over 4  
44
45 =item new OPTIONS
46
47 Creates an object to access the API.  OPTIONS must include C<vendor_code>
48 and C<password>.  By default, this will connect to the development API;
49 for access to the live service, pass C<live> => 1.
50
51 =cut
52
53 sub new {
54   my $class = shift;
55   my %opt = @_;
56   my $vendor_code = $opt{vendor_code} or die "WebService::Northern911::new() requires vendor_code\n";
57   my $password = $opt{password} or die "WebService::Northern911::new() requires password\n";
58
59   # create the interface
60   # expensive, so reuse this object as much as possible
61   my $schema = dist_dir('WebService-Northern911') . '/schema';
62   if ($opt{'live'}) {
63     $schema .= '/live';
64   } else {
65     $schema .= '/test';
66   }
67
68   # yes, that's right, we have to distribute the schema with this module.
69   # XML::Compile::WSDL11 makes the argument that
70   my $client = XML::Compile::WSDL11->new("$schema/wsdl");
71   for my $xsd (<$schema/xsd*>) {
72     $client->importDefinitions($xsd);
73   }
74
75   $client->compileCalls;
76   my $self = {
77     vendor_code => $vendor_code,
78     password    => $password,
79     client      => $client,
80   };
81   bless $self, $class;
82 }
83
84 # internal method: returns the authentication string (referred to as the 
85 # "hash" in the docs)
86
87 sub _auth {
88   my $self = shift;
89
90   my $now = DateTime->now;
91   $now->set_time_zone('UTC');
92   md5_hex($self->{vendor_code} .
93     $self->{password} .
94     $now->strftime('%Y%m%d')
95   );
96 }
97
98 # internal method: dispatch a request to the service
99
100 sub _call {
101   my $self = shift;
102   $self->{client}->call(@_);
103 }
104
105 =item AddorUpdateCustomer OPTIONS
106
107 Adds or updates a customer.  Note the idiosyncratic capitalization; this
108 is the spelling of the underlying API method.  OPTIONS may include:
109
110 - PHONE_NUMBER: 10 digits, no punctuation
111 - FIRST_NAME: customer first name, up to 38 characters
112 - LAST_NAME: customer last name or company name, up to 100 characters
113 - STREET_NUMBER: up to 10 characters
114 - STREET_NAME: up to 84 characters
115 - CITY: up to 38 characters
116 - PROVINCE_STATE: 2 letter code
117 - POSTAL_CODE_ZIP: Canadian postal code or U.S. zip code
118 - OTHER_ADDRESS_INFO: up to 250 characters
119
120 Returns a L<WebService::Northern911::Result> object.
121
122 =cut
123
124 sub AddorUpdateCustomer {
125   my $self = shift;
126   my %opt = @_;
127   my %customer = map { $_ => $opt{$_} }
128   qw( PHONE_NUMBER FIRST_NAME LAST_NAME STREET_NUMBER STREET_NAME
129       CITY PROVINCE_STATE POSTAL_CODE_ZIP OTHER_ADDRESS_INFO 
130     );
131   # according to Northern 911 support, this is for a future feature,
132   # and should always be 'N' for now
133   $customer{ENHANCED_CAPABLE} = 'N';
134
135   $customer{VENDOR_CODE} = $self->{vendor_code};
136
137   my ($answer, $trace) = $self->_call( 'AddorUpdateCustomer',
138     hash => $self->_auth,
139     customer => \%customer,
140   );
141
142   WebService::Northern911::Response->new($answer);
143 }
144
145 =item DeleteCustomer PHONE
146
147 Deletes a customer record.  PHONE must be the phone number (10 digits,
148 as in C<AddorUpdateCustomer>).
149
150 =cut
151
152 sub DeleteCustomer {
153   my $self = shift;
154   my $phone = shift;
155
156   my ($answer, $trace) = $self->_call( 'DeleteCustomer',
157     vendorCode => $self->{vendor_code},
158     hash => $self->_auth,
159     phoneNumber => $phone,
160   );
161
162   WebService::Northern911::Response->new($answer);
163 }
164
165 =item QueryCustomer PHONE
166
167 Queries a customer record.  PHONE must be the phone number.  The response
168 object will have a "customer" method which returns a hashref of customer
169 information, in the same format as the arguments to C<AddorUpdateCustomer>.
170
171 =cut
172
173 sub QueryCustomer {
174   my $self = shift;
175   my $phone = shift;
176
177   my ($answer, $trace) = $self->_call( 'QueryCustomer',
178     vendorCode => $self->{vendor_code},
179     hash => $self->_auth,
180     phoneNumber => $phone,
181   );
182
183   WebService::Northern911::Response->new($answer);
184 }
185
186 =item GetVendorDumpURL
187
188 Returns a URL to download a CSV dump of your customer data.  The response
189 object will have a 'url' method to return the URL.
190
191 Note that this feature is heavily throttled (at most once per week, unless
192 you pay for more frequent access) and the URL can only be used once.
193
194 =cut
195
196 sub GetVendorDumpURL {
197   my $self = shift;
198
199   my ($answer, $trace) = $self->_call( 'GetVendorDumpURL',
200     vendorCode => $self->{vendor_code},
201     hash => $self->_auth,
202   );
203
204   WebService::Northern911::Response->new($answer);
205 }
206
207 =back
208
209 =head1 AUTHOR
210
211 Mark Wells, <mark@freeside.biz>
212
213 Commercial support is available from Freeside Internet Services, Inc.
214
215 =head1 COPYRIGHT
216
217 Copyright (c) 2014 Mark Wells
218
219 =cut
220
221 1;