active_shipping 0.11.2 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/active_shipping/shipping/carriers.rb +3 -2
- data/lib/active_shipping/shipping/carriers/canada_post_pws.rb +9 -5
- data/lib/active_shipping/shipping/carriers/fedex.rb +2 -11
- data/lib/active_shipping/shipping/carriers/stamps.rb +876 -0
- data/lib/active_shipping/shipping/carriers/ups.rb +7 -1
- data/lib/active_shipping/shipping/carriers/usps.rb +1 -0
- data/lib/active_shipping/shipping/rate_estimate.rb +1 -1
- data/lib/active_shipping/version.rb +1 -1
- metadata +41 -67
- data/lib/active_shipping/shipping/carriers/ups.rb.orig +0 -456
- data/lib/active_shipping/shipping/carriers/usps.rb.orig +0 -616
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f30ed059c7a905d31613a80cce7cfa7eb90ecfc3
|
4
|
+
data.tar.gz: 392d4af7ca46e7359d409a1391ba4804e1d97076
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 49441958f4cd2fc4b105b22f23d99cab2478f54ef32d898d6f38c2731bbbc5b9044f82c5dc100392e299dc507533fbe4bea51aa88da021d779984ee99de0d2fd
|
7
|
+
data.tar.gz: 8d85605d2b34f39f2fa886cfa770b12fed22c20739c3155dc7d8b79fd9a45a5b7259c862cb6f00f0fa11365d91ca64914131034e8735b67c4819cf766c520026
|
@@ -8,15 +8,16 @@ require 'active_shipping/shipping/carriers/kunaki'
|
|
8
8
|
require 'active_shipping/shipping/carriers/canada_post'
|
9
9
|
require 'active_shipping/shipping/carriers/new_zealand_post'
|
10
10
|
require 'active_shipping/shipping/carriers/canada_post_pws'
|
11
|
+
require 'active_shipping/shipping/carriers/stamps'
|
11
12
|
|
12
13
|
module ActiveMerchant
|
13
14
|
module Shipping
|
14
15
|
module Carriers
|
15
16
|
class <<self
|
16
17
|
def all
|
17
|
-
[BenchmarkCarrier, BogusCarrier, UPS, USPS, FedEx, Shipwire, Kunaki, CanadaPost, NewZealandPost, CanadaPostPWS]
|
18
|
+
[BenchmarkCarrier, BogusCarrier, UPS, USPS, FedEx, Shipwire, Kunaki, CanadaPost, NewZealandPost, CanadaPostPWS, Stamps]
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
22
|
-
end
|
23
|
+
end
|
@@ -79,7 +79,11 @@ module ActiveMerchant
|
|
79
79
|
response = ssl_get(tracking_url(pin), headers(options, TRACK_MIMETYPE))
|
80
80
|
parse_tracking_response(response)
|
81
81
|
rescue ActiveMerchant::ResponseError, ActiveMerchant::Shipping::ResponseError => e
|
82
|
-
|
82
|
+
if e.response
|
83
|
+
error_response(e.response.body, CPPWSTrackingResponse)
|
84
|
+
else
|
85
|
+
CPPWSTrackingResponse.new(false, e.message, {}, {:carrier => @@name})
|
86
|
+
end
|
83
87
|
rescue InvalidPinFormatError => e
|
84
88
|
CPPWSTrackingResponse.new(false, "Invalid Pin Format", {}, {:carrier => @@name})
|
85
89
|
end
|
@@ -293,7 +297,7 @@ module ActiveMerchant
|
|
293
297
|
options = {
|
294
298
|
:carrier => @@name,
|
295
299
|
:service_name => root_node.get_text('service-name').to_s,
|
296
|
-
:expected_date => Date.parse(expected_date),
|
300
|
+
:expected_date => expected_date.blank? ? nil : Date.parse(expected_date),
|
297
301
|
:changed_date => change_date.blank? ? nil : Date.parse(change_date),
|
298
302
|
:change_reason => root_node.get_text('changed-expected-delivery-reason').to_s.strip,
|
299
303
|
:destination_postal_code => root_node.get_text('destination-postal-id').to_s,
|
@@ -767,9 +771,9 @@ module ActiveMerchant
|
|
767
771
|
earliest = occurrences.sort_by { |occurrence| time_of_occurrence occurrence }.first
|
768
772
|
|
769
773
|
{
|
770
|
-
city: earliest.get_text('event-site'),
|
771
|
-
province: earliest.get_text('event-province'),
|
772
|
-
address_1: earliest.get_text('event-retail-location-id'),
|
774
|
+
city: earliest.get_text('event-site').to_s,
|
775
|
+
province: earliest.get_text('event-province').to_s,
|
776
|
+
address_1: earliest.get_text('event-retail-location-id').to_s,
|
773
777
|
country: 'Canada'
|
774
778
|
}
|
775
779
|
end
|
@@ -326,12 +326,11 @@ module ActiveMerchant
|
|
326
326
|
end
|
327
327
|
|
328
328
|
def build_location_node(name, location)
|
329
|
-
|
329
|
+
XmlNode.new(name) do |xml_node|
|
330
330
|
xml_node << XmlNode.new('Address') do |address_node|
|
331
331
|
address_node << XmlNode.new('StreetLines', location.address1) if location.address1
|
332
332
|
address_node << XmlNode.new('StreetLines', location.address2) if location.address2
|
333
333
|
address_node << XmlNode.new('City', location.city) if location.city
|
334
|
-
address_node << XmlNode.new('StateOrProvinceCode', location.state) if location.state
|
335
334
|
address_node << XmlNode.new('PostalCode', location.postal_code)
|
336
335
|
address_node << XmlNode.new("CountryCode", location.country_code(:alpha2))
|
337
336
|
|
@@ -362,7 +361,7 @@ module ActiveMerchant
|
|
362
361
|
|
363
362
|
delivery_range = delivery_range_from(transit_time, max_transit_time, delivery_timestamp, options)
|
364
363
|
|
365
|
-
currency =
|
364
|
+
currency = rated_shipment.get_text('RatedShipmentDetails/ShipmentRateDetail/TotalNetCharge/Currency').to_s
|
366
365
|
rate_estimates << RateEstimate.new(origin, destination, @@name,
|
367
366
|
self.class.service_name_for_code(service_type),
|
368
367
|
:service_code => service_code,
|
@@ -516,14 +515,6 @@ module ActiveMerchant
|
|
516
515
|
ssl_post(test ? TEST_URL : LIVE_URL, request.gsub("\n",''))
|
517
516
|
end
|
518
517
|
|
519
|
-
def handle_incorrect_currency_codes(currency)
|
520
|
-
case currency
|
521
|
-
when /UKL/i then 'GBP'
|
522
|
-
when /SID/i then 'SGD'
|
523
|
-
else currency
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
518
|
def parse_transit_times(times)
|
528
519
|
results = []
|
529
520
|
times.each do |day_count|
|
@@ -0,0 +1,876 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
module ActiveMerchant
|
5
|
+
module Shipping
|
6
|
+
|
7
|
+
# Stamps.com integration for rating, tracking, address validation, and label generation
|
8
|
+
# Integration ID can be requested from Stamps.com
|
9
|
+
|
10
|
+
class Stamps < Carrier
|
11
|
+
self.ssl_version = :SSLv3
|
12
|
+
|
13
|
+
cattr_reader :name
|
14
|
+
@@name = 'Stamps'
|
15
|
+
|
16
|
+
attr_reader :last_swsim_method
|
17
|
+
|
18
|
+
LIVE_URL = 'https://swsim.stamps.com/swsim/swsimv34.asmx'
|
19
|
+
TEST_URL = 'https://swsim.testing.stamps.com/swsim/swsimv34.asmx'
|
20
|
+
NAMESPACE = 'http://stamps.com/xml/namespace/2014/01/swsim/swsimv34'
|
21
|
+
|
22
|
+
REQUIRED_OPTIONS = [:integration_id, :username, :password].freeze
|
23
|
+
|
24
|
+
PACKAGE = [
|
25
|
+
'Postcard',
|
26
|
+
'Letter',
|
27
|
+
'Large Envelope or Flat',
|
28
|
+
'Thick Envelope',
|
29
|
+
'Package',
|
30
|
+
'Flat Rate Box',
|
31
|
+
'Small Flat Rate Box',
|
32
|
+
'Large Flat Rate Box',
|
33
|
+
'Flat Rate Envelope',
|
34
|
+
'Flat Rate Padded Envelope',
|
35
|
+
'Large Package',
|
36
|
+
'Oversized Package',
|
37
|
+
'Regional Rate Box A',
|
38
|
+
'Regional Rate Box B',
|
39
|
+
'Regional Rate Box C',
|
40
|
+
'Legal Flat Rate Envelope'
|
41
|
+
].freeze
|
42
|
+
|
43
|
+
US_POSSESSIONS = ["AS", "FM", "GU", "MH", "MP", "PW", "PR", "VI"]
|
44
|
+
|
45
|
+
SERVICE_TYPES = {
|
46
|
+
'US-FC' => 'USPS First-Class Mail',
|
47
|
+
'US-MM' => 'USPS Media Mail',
|
48
|
+
'US-PM' => 'USPS Priority Mail',
|
49
|
+
'US-BP' => 'USPS BP',
|
50
|
+
'US-LM' => 'USPS LM',
|
51
|
+
'US-XM' => 'USPS Express Mail',
|
52
|
+
'US-EMI' => 'USPS Express Mail International',
|
53
|
+
'US-PMI' => 'USPS Priority Mail International',
|
54
|
+
'US-FCI' => 'USPS First Class Mail International',
|
55
|
+
'US-CM' => 'USPS Critical Mail',
|
56
|
+
'US-PS' => 'USPS Parcel Select'
|
57
|
+
}
|
58
|
+
|
59
|
+
ADD_ONS = {
|
60
|
+
'SC-A-HP' => 'Hidden Postage',
|
61
|
+
'SC-A-INS' => 'Insurance',
|
62
|
+
'SC-A-INSRM' => 'Insurance for Registered Mail',
|
63
|
+
'US-A-CM' => 'Certified Mail',
|
64
|
+
'US-A-COD' => 'Collect on Delivery',
|
65
|
+
'US-A-COM' => 'Certificate of Mailing',
|
66
|
+
'US-A-DC' => 'USPS Delivery Confirmation',
|
67
|
+
'US-A-ESH' => 'USPS Express - Sunday / Holiday Guaranteed',
|
68
|
+
'US-A-INS' => 'USPS Insurance',
|
69
|
+
'US-A-NDW' => 'USPS Express - No Delivery on Saturdays',
|
70
|
+
'US-A-RD' => 'Restricted Delivery',
|
71
|
+
'US-A-REG' => 'Registered Mail',
|
72
|
+
'US-A-RR' => 'Return Receipt Requested',
|
73
|
+
'US-A-RRM' => 'Return Receipt for Merchandise',
|
74
|
+
'US-A-SC' => 'USPS Signature Confirmation',
|
75
|
+
'US-A-SH' => 'Special Handling',
|
76
|
+
'US-A-NND' => 'Notice of non-delivery',
|
77
|
+
'US-A-SR' => 'Unknow Service Name SR',
|
78
|
+
'US-A-RRE' => 'Unknow Service Name RRE'
|
79
|
+
}
|
80
|
+
|
81
|
+
CARRIER_PICKUP_LOCATION = {
|
82
|
+
'FrontDoor' => 'Packages are at front door',
|
83
|
+
'BackDoor' => 'Packages are at back door',
|
84
|
+
'SideDoor' => 'Packages are at side door',
|
85
|
+
'KnockOnDoorOrRingBell' => 'Knock on door or ring bell',
|
86
|
+
'MailRoom' => 'Packages are in mail room',
|
87
|
+
'Office' => 'Packages are in office',
|
88
|
+
'Reception' => 'Packages are at reception area',
|
89
|
+
'InOrAtMailbox' => 'Packages are in mail box',
|
90
|
+
'Other' => 'Other Location'
|
91
|
+
}
|
92
|
+
|
93
|
+
PRINT_LAYOUTS = [
|
94
|
+
'Normal',
|
95
|
+
'NormalLeft',
|
96
|
+
'NormalRight',
|
97
|
+
'Normal4X6',
|
98
|
+
'Normal6X4',
|
99
|
+
'Normal75X2',
|
100
|
+
'NormalReceipt',
|
101
|
+
'NormalCN22',
|
102
|
+
'NormalCP72',
|
103
|
+
'Normal4X6CN22',
|
104
|
+
'Normal6X4CN22',
|
105
|
+
'Normal4X6CP72',
|
106
|
+
'Normal6X4CP72',
|
107
|
+
'Normal4X675',
|
108
|
+
'Normal4X675CN22',
|
109
|
+
'Normal4X675CP72',
|
110
|
+
'Return',
|
111
|
+
'ReturnCN22',
|
112
|
+
'ReturnCP72',
|
113
|
+
'Return4X675',
|
114
|
+
'Return4X675CN22',
|
115
|
+
'Return4X675CP72',
|
116
|
+
'SDC3510',
|
117
|
+
'SDC3520',
|
118
|
+
'SDC3530',
|
119
|
+
'SDC3610',
|
120
|
+
'SDC3710',
|
121
|
+
'SDC3810',
|
122
|
+
'SDC3820',
|
123
|
+
'SDC3910',
|
124
|
+
'Envelope9',
|
125
|
+
'Envelope10',
|
126
|
+
'Envelope11',
|
127
|
+
'Envelope12',
|
128
|
+
'EnvelopePersonal',
|
129
|
+
'EnvelopeMonarch',
|
130
|
+
'EnvelopeInvitation',
|
131
|
+
'EnvelopeGreeting'
|
132
|
+
]
|
133
|
+
|
134
|
+
IMAGE_TYPE = [
|
135
|
+
'Auto',
|
136
|
+
'Epl',
|
137
|
+
'Gif',
|
138
|
+
'Jpg',
|
139
|
+
'Pdf',
|
140
|
+
'Png',
|
141
|
+
'Zpl'
|
142
|
+
]
|
143
|
+
|
144
|
+
def account_info
|
145
|
+
request = build_get_account_info_request
|
146
|
+
response = commit(:GetAccountInfo, request)
|
147
|
+
end
|
148
|
+
|
149
|
+
def purchase_postage(purchase_amount, control_total)
|
150
|
+
request = build_purchase_postage_request(purchase_amount, control_total)
|
151
|
+
response = commit(:PurchasePostage, request)
|
152
|
+
end
|
153
|
+
|
154
|
+
def purchase_status(transaction_id)
|
155
|
+
request = build_get_purchase_status(transaction_id)
|
156
|
+
response = commit(:GetPurchaseStatus, request)
|
157
|
+
end
|
158
|
+
|
159
|
+
def validate_address(address, options = {})
|
160
|
+
address = standardize_address(address)
|
161
|
+
|
162
|
+
request = build_cleanse_address_request(address)
|
163
|
+
response = commit(:CleanseAddress, request)
|
164
|
+
end
|
165
|
+
|
166
|
+
def find_rates(origin, destination, package, options = {})
|
167
|
+
origin = standardize_address(origin)
|
168
|
+
destination = standardize_address(destination)
|
169
|
+
|
170
|
+
request = build_rate_request(origin, destination, package, options)
|
171
|
+
response = commit(:GetRates, request)
|
172
|
+
end
|
173
|
+
|
174
|
+
def create_shipment(origin, destination, package, line_items = [], options = {})
|
175
|
+
origin = standardize_address(origin)
|
176
|
+
destination = standardize_address(destination)
|
177
|
+
|
178
|
+
request = build_create_indicium_request(origin, destination, package, line_items, options)
|
179
|
+
response = commit(:CreateIndicium, request)
|
180
|
+
end
|
181
|
+
|
182
|
+
def find_tracking_info(shipment_id, options = {})
|
183
|
+
request = build_track_shipment_request(shipment_id, options)
|
184
|
+
response = commit(:TrackShipment, request)
|
185
|
+
end
|
186
|
+
|
187
|
+
def namespace
|
188
|
+
NAMESPACE
|
189
|
+
end
|
190
|
+
|
191
|
+
def clear_authenticator
|
192
|
+
@authenticator = nil
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
def requirements
|
198
|
+
REQUIRED_OPTIONS
|
199
|
+
end
|
200
|
+
|
201
|
+
def save_swsim_method(swsim_method)
|
202
|
+
@last_swsim_method = swsim_method
|
203
|
+
end
|
204
|
+
|
205
|
+
def international?(address)
|
206
|
+
! (['US', nil] + US_POSSESSIONS).include?(address.country_code)
|
207
|
+
end
|
208
|
+
|
209
|
+
def standardize_address(address)
|
210
|
+
if US_POSSESSIONS.include?(address.country_code)
|
211
|
+
new_address = address.to_hash
|
212
|
+
new_address[:province] = new_address[:country]
|
213
|
+
new_address[:country] = 'US'
|
214
|
+
Location.new(new_address)
|
215
|
+
else
|
216
|
+
address
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def domestic?(address)
|
221
|
+
address.country_code(:alpha2) == 'US' || address.country_code(:alpha2).nil?
|
222
|
+
end
|
223
|
+
|
224
|
+
def authenticator
|
225
|
+
get_authenticator unless @authenticator
|
226
|
+
@authenticator
|
227
|
+
end
|
228
|
+
|
229
|
+
def renew_authenticator(request)
|
230
|
+
old_authenticator = authenticator
|
231
|
+
clear_authenticator
|
232
|
+
request.sub(old_authenticator, authenticator)
|
233
|
+
end
|
234
|
+
|
235
|
+
def get_authenticator
|
236
|
+
request = build_authenticate_user_request
|
237
|
+
response = commit(:AuthenticateUser, request)
|
238
|
+
end
|
239
|
+
|
240
|
+
def build_header
|
241
|
+
xml = Builder::XmlMarkup.new
|
242
|
+
xml.instruct!
|
243
|
+
xml.soap(:Envelope, {
|
244
|
+
'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
245
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
246
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
247
|
+
'xmlns:tns' => 'http://stamps.com/xml/namespace/2014/01/swsim/swsimv34'
|
248
|
+
}) do
|
249
|
+
xml.soap :Body do
|
250
|
+
yield(xml)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def build_authenticate_user_request
|
256
|
+
build_header do |xml|
|
257
|
+
xml.tns :AuthenticateUser do
|
258
|
+
xml.tns :Credentials do
|
259
|
+
xml.tns(:IntegrationID, @options[:integration_id])
|
260
|
+
xml.tns(:Username, @options[:username])
|
261
|
+
xml.tns(:Password, @options[:password])
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def build_get_account_info_request
|
268
|
+
build_header do |xml|
|
269
|
+
xml.tns :GetAccountInfo do
|
270
|
+
xml.tns(:Authenticator, authenticator)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def build_purchase_postage_request(purchase_amount, control_total)
|
276
|
+
build_header do |xml|
|
277
|
+
xml.tns :PurchasePostage do
|
278
|
+
xml.tns(:Authenticator, authenticator)
|
279
|
+
xml.tns(:PurchaseAmount, purchase_amount)
|
280
|
+
xml.tns(:ControlTotal, control_total)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def build_get_purchase_status(transaction_id)
|
286
|
+
build_header do |xml|
|
287
|
+
xml.tns :GetPurchaseStatus do
|
288
|
+
xml.tns(:Authenticator, authenticator)
|
289
|
+
xml.tns(:TransactionID, transaction_id)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def build_cleanse_address_request(address)
|
295
|
+
build_header do |xml|
|
296
|
+
xml.tns :CleanseAddress do
|
297
|
+
xml.tns(:Authenticator, authenticator)
|
298
|
+
add_address(xml, address)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def add_address(xml, address, object_type = :Address)
|
304
|
+
xml.tns object_type do
|
305
|
+
xml.tns(:FullName, address.name) unless address.name.blank?
|
306
|
+
xml.tns(:Company, address.company) unless address.company.blank?
|
307
|
+
xml.tns(:Address1, address.address1)
|
308
|
+
xml.tns(:Address2, address.address2) unless address.address2.blank?
|
309
|
+
xml.tns(:Address3, address.address3) unless address.address3.blank?
|
310
|
+
xml.tns(:City, address.city) unless address.city.blank?
|
311
|
+
if domestic?(address)
|
312
|
+
xml.tns(:State, address.state) unless address.state.blank?
|
313
|
+
|
314
|
+
zip = (address.postal_code || '').match(/^(\d{5})?-?(\d{4})?$/)
|
315
|
+
xml.tns(:ZIPCode, zip[1]) unless zip[1].nil?
|
316
|
+
xml.tns(:ZIPCodeAddOn, zip[2]) unless zip[2].nil?
|
317
|
+
else
|
318
|
+
xml.tns(:Province, address.province) unless address.province.blank?
|
319
|
+
xml.tns(:PostalCode, address.postal_code) unless address.postal_code.blank?
|
320
|
+
end
|
321
|
+
xml.tns(:Country, address.country_code) unless address.country_code.blank?
|
322
|
+
xml.tns(:PhoneNumber, address.phone) unless address.phone.blank?
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def build_rate_request(origin, destination, package, options)
|
327
|
+
build_header do |xml|
|
328
|
+
xml.tns :GetRates do
|
329
|
+
xml.tns(:Authenticator, authenticator)
|
330
|
+
add_rate(xml, origin, destination, package, options)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def add_rate(xml, origin, destination, package, options)
|
336
|
+
value = package.value ? '%.2f' % (package.value.to_f / 100) : nil
|
337
|
+
options[:insured_value] ||= value
|
338
|
+
options[:declared_value] ||= value if international?(destination)
|
339
|
+
|
340
|
+
xml.tns :Rate do
|
341
|
+
xml.tns(:FromZIPCode, origin.postal_code) unless origin.postal_code.blank?
|
342
|
+
xml.tns(:ToZIPCode, destination.postal_code) unless destination.postal_code.blank?
|
343
|
+
xml.tns(:ToCountry, destination.country_code) unless destination.country_code.blank?
|
344
|
+
xml.tns(:ServiceType, options[:service]) unless options[:service].blank?
|
345
|
+
xml.tns(:PrintLayout, options[:print_layout]) unless options[:print_layout].blank?
|
346
|
+
xml.tns(:WeightOz, [package.ounces, 1].max)
|
347
|
+
xml.tns(:PackageType, options[:package_type] || 'Package')
|
348
|
+
xml.tns(:Length, package.inches(:length)) if package.inches(:length)
|
349
|
+
xml.tns(:Width, package.inches(:width)) if package.inches(:width)
|
350
|
+
xml.tns(:Height, package.inches(:height)) if package.inches(:height)
|
351
|
+
xml.tns(:ShipDate, options[:ship_date] || Date.today)
|
352
|
+
xml.tns(:InsuredValue, options[:insured_value]) unless options[:insured_value].blank?
|
353
|
+
xml.tns(:CODValue, options[:cod_value]) unless options[:cod_value].blank?
|
354
|
+
xml.tns(:DeclaredValue, options[:declared_value]) unless options[:declared_value].blank?
|
355
|
+
|
356
|
+
machinable = if package.options.has_key?(:machinable)
|
357
|
+
package.options[:machinable] ? true : false
|
358
|
+
else
|
359
|
+
USPS.package_machinable?(package)
|
360
|
+
end
|
361
|
+
|
362
|
+
xml.tns(:NonMachinable, true) unless machinable
|
363
|
+
|
364
|
+
xml.tns(:RectangularShaped, ! package.cylinder?)
|
365
|
+
xml.tns(:GEMNotes, options[:gem_notes]) unless options[:gem_notes].blank?
|
366
|
+
|
367
|
+
add_ons = Array(options[:add_ons])
|
368
|
+
unless add_ons.empty?
|
369
|
+
xml.tns(:AddOns) do
|
370
|
+
add_ons.each do |add_on|
|
371
|
+
xml.tns(:AddOnV5) do
|
372
|
+
xml.tns(:AddOnType, add_on)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
xml.tns(:ToState, destination.province) unless destination.province.blank?
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def build_create_indicium_request(origin, destination, package, line_items, options)
|
383
|
+
build_header do |xml|
|
384
|
+
xml.tns :CreateIndicium do
|
385
|
+
xml.tns(:Authenticator, authenticator)
|
386
|
+
xml.tns(:IntegratorTxID, options[:integrator_tx_id] || SecureRandom::uuid)
|
387
|
+
|
388
|
+
add_rate(xml, origin, destination, package, options)
|
389
|
+
add_address(xml, origin, :From)
|
390
|
+
add_address(xml, destination, :To)
|
391
|
+
add_customs(xml, line_items, options) unless options[:content_type].blank?
|
392
|
+
|
393
|
+
xml.tns(:SampleOnly, options[:sample_only]) unless options[:sample_only].blank?
|
394
|
+
xml.tns(:ImageType, options[:image_type]) unless options[:image_type].blank?
|
395
|
+
xml.tns(:EltronPrinterDPIType, options[:label_resolution]) unless options[:label_resolution].blank?
|
396
|
+
xml.tns(:memo, options[:memo]) unless options[:memo].blank?
|
397
|
+
xml.tns(:deliveryNotification, options[:delivery_notification]) unless options[:delivery_notification].blank?
|
398
|
+
|
399
|
+
add_shipment_notification(xml, options) unless options[:email].blank?
|
400
|
+
|
401
|
+
xml.tns(:horizontalOffset, options[:horizontal_offset]) unless options[:horizontal_offest].blank?
|
402
|
+
xml.tns(:verticalOffset, options[:vertical_offset]) unless options[:vertical_offest].blank?
|
403
|
+
xml.tns(:printDensity, options[:print_density]) unless options[:print_density].blank?
|
404
|
+
xml.tns(:rotationDegrees, options[:rotation]) unless options[:rotation].blank?
|
405
|
+
xml.tns(:printMemo, options[:print_memo]) unless options[:print_memo].blank?
|
406
|
+
xml.tns(:printInstructions, options[:print_instructions]) unless options[:print_instructions].blank?
|
407
|
+
xml.tns(:ReturnImageData, options[:return_image_data]) unless options[:return_image_data].blank?
|
408
|
+
xml.tns(:InternalTransactionNumber, options[:internal_transaction_number]) unless options[:internal_transaction_number].blank?
|
409
|
+
xml.tns(:PaperSize, options[:paper_size]) unless options[:paper_size].blank?
|
410
|
+
|
411
|
+
add_label_recipient_info(xml, options) unless options[:label_email_address].blank?
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def add_shipment_notification(xml, options)
|
417
|
+
xml.tns :ShipmentNotification do
|
418
|
+
xml.tns(:Email, options[:email])
|
419
|
+
xml.tns(:CCToAccountHolder, options[:cc_to_account_holder]) unless options[:cc_to_account_holder].blank?
|
420
|
+
xml.tns(:UseCompanyNameInFromLine, options[:use_company_name_in_from_name]) unless options[:use_company_name_in_from_line].blank?
|
421
|
+
xml.tns(:UseCompanyNameInSubject, options[:use_company_name_in_subject]) unless options[:use_company_name_in_subject].blank?
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def add_customs(xml, line_items, options)
|
426
|
+
xml.tns :Customs do
|
427
|
+
xml.tns(:ContentType, options[:content_type])
|
428
|
+
xml.tns(:Comments, options[:comments]) unless options[:comments].blank?
|
429
|
+
xml.tns(:LicenseNumber, options[:license_number]) unless options[:license_number].blank?
|
430
|
+
xml.tns(:CertificateNumber, options[:certificate_number]) unless options[:certificate_number].blank?
|
431
|
+
xml.tns(:InvoiceNumber, options[:invoice_number]) unless options[:invoice_number].blank?
|
432
|
+
xml.tns(:OtherDescribe, options[:other_describe]) unless options[:other_describe].blank?
|
433
|
+
|
434
|
+
xml.tns :CustomsLines do
|
435
|
+
line_items.each do |customs_line|
|
436
|
+
xml.tns :CustomsLine do
|
437
|
+
xml.tns(:Description, customs_line.name)
|
438
|
+
xml.tns(:Quantity, customs_line.quantity)
|
439
|
+
xml.tns(:Value, '%.2f' % (customs_line.value.to_f / 100))
|
440
|
+
xml.tns(:WeightOz, customs_line.ounces) unless customs_line.ounces.blank?
|
441
|
+
xml.tns(:HSTariffNumber, customs_line.hs_code.tr('.', '')[0..5]) unless customs_line.hs_code.blank?
|
442
|
+
xml.tns(:CountryOfOrigin, customs_line.options[:country]) unless customs_line.options[:country].blank?
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def add_label_recipient_info(xml, options)
|
450
|
+
xml.tns :LabelRecipientInfo do
|
451
|
+
xml.tns(:EmailAddress, options[:label_email_address])
|
452
|
+
xml.tns(:Name, options[:name]) unless options[:name].blank?
|
453
|
+
xml.tns(:Note, options[:note]) unless options[:note].blank?
|
454
|
+
xml.tns(:CopyToOriginator, options[:copy_to_originator]) unless options[:copy_to_originator].blank?
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def build_track_shipment_request(shipment_id, options)
|
459
|
+
build_header do |xml|
|
460
|
+
xml.tns :TrackShipment do
|
461
|
+
xml.tns(:Authenticator, authenticator)
|
462
|
+
xml.tns(options[:stamps_tx_id] ? :StampsTxID : :TrackingNumber, shipment_id)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def commit(swsim_method, request)
|
468
|
+
save_request(request)
|
469
|
+
save_swsim_method(swsim_method)
|
470
|
+
parse(ssl_post(request_url, request, 'Content-Type' => 'text/xml', 'SOAPAction' => soap_action(swsim_method)))
|
471
|
+
rescue ActiveMerchant::ResponseError => e
|
472
|
+
parse(e.response.body)
|
473
|
+
end
|
474
|
+
|
475
|
+
def request_url
|
476
|
+
test_mode? ? TEST_URL : LIVE_URL
|
477
|
+
end
|
478
|
+
|
479
|
+
def soap_action(method)
|
480
|
+
[NAMESPACE, method].join('/')
|
481
|
+
end
|
482
|
+
|
483
|
+
def parse(xml)
|
484
|
+
response_options = {}
|
485
|
+
response_options[:xml] = xml
|
486
|
+
response_options[:request] = last_request
|
487
|
+
response_options[:test] = test_mode?
|
488
|
+
|
489
|
+
document = REXML::Document.new(xml)
|
490
|
+
child_element = document.get_elements('//soap:Body/*').first
|
491
|
+
parse_method = 'parse_' + child_element.name.underscore
|
492
|
+
if respond_to?(parse_method, true)
|
493
|
+
send(parse_method, child_element, response_options)
|
494
|
+
else
|
495
|
+
Response.new(false, "Unknown response object #{child_element.name}", response_options)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def parse_fault(fault, response_options)
|
500
|
+
@authenticator = fault.get_text('detail/authenticator').value if fault.get_text('detail/authenticator')
|
501
|
+
|
502
|
+
error_code = if fault.elements['detail/stamps_exception']
|
503
|
+
fault.elements['detail/stamps_exception'].attributes['code']
|
504
|
+
elsif fault.elements['detail/sdcerror']
|
505
|
+
fault.elements['detail/sdcerror'].attributes['code']
|
506
|
+
else
|
507
|
+
nil
|
508
|
+
end
|
509
|
+
|
510
|
+
# Renew the Authenticator if it has expired and retry the request
|
511
|
+
if error_code and error_code.downcase == '002b0202'
|
512
|
+
request = renew_authenticator(last_request)
|
513
|
+
commit(last_swsim_method, request)
|
514
|
+
else
|
515
|
+
raise ResponseError.new(fault.get_text('faultstring').to_s)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def parse_authenticate_user_response(authenticate_user, response_options)
|
520
|
+
parse_authenticator(authenticate_user)
|
521
|
+
end
|
522
|
+
|
523
|
+
def parse_authenticator(response)
|
524
|
+
@authenticator = response.get_text('Authenticator').value
|
525
|
+
end
|
526
|
+
|
527
|
+
def parse_get_account_info_response(account_info_response, response_options)
|
528
|
+
parse_authenticator(account_info_response)
|
529
|
+
|
530
|
+
account_info = account_info_response.elements['AccountInfo']
|
531
|
+
response_options[:customer_id] = account_info.get_text('CustomerID').to_s
|
532
|
+
response_options[:meter_number] = account_info.get_text('MeterNumber').to_s
|
533
|
+
response_options[:user_id] = account_info.get_text('UserID').to_s
|
534
|
+
response_options[:max_postage_balance] = account_info.get_text('MaxPostageBalance').to_s
|
535
|
+
response_options[:lpo_city] = account_info.get_text('LPOCity').to_s
|
536
|
+
response_options[:lpo_state] = account_info.get_text('LPOState').to_s
|
537
|
+
response_options[:lpo_zip] = account_info.get_text('LPOZip').to_s
|
538
|
+
|
539
|
+
postage_balance_node = account_info.elements['PostageBalance']
|
540
|
+
response_options[:available_postage] = postage_balance_node.get_text('AvailablePostage').to_s
|
541
|
+
response_options[:control_total] = postage_balance_node.get_text('ControlTotal').to_s
|
542
|
+
|
543
|
+
capabilities_node = account_info.elements['Capabilities']
|
544
|
+
response_options[:can_print_shipping] = capabilities_node.get_text('CanPrintShipping').to_s == 'true'
|
545
|
+
response_options[:can_use_cost_codes] = capabilities_node.get_text('CanUseCostCodes').to_s == 'true'
|
546
|
+
response_options[:can_use_hidden_postage] = capabilities_node.get_text('CanUseHiddenPostage').to_s == 'true'
|
547
|
+
response_options[:can_purchase_sdc_insurance] = capabilities_node.get_text('CanPurchaseSDCInsurance').to_s == 'true'
|
548
|
+
response_options[:can_print_memo] = capabilities_node.get_text('CanPrintMemoOnShippingLabel').to_s == 'true'
|
549
|
+
response_options[:can_print_international] = capabilities_node.get_text('CanPrintInternational').to_s == 'true'
|
550
|
+
response_options[:can_purchase_postage] = capabilities_node.get_text('CanPurchasePostage').to_s == 'true'
|
551
|
+
response_options[:can_edit_cost_codes] = capabilities_node.get_text('CanEditCostCodes').to_s == 'true'
|
552
|
+
response_options[:must_use_cost_codes] = capabilities_node.get_text('MustUseCostCodes').to_s == 'true'
|
553
|
+
response_options[:can_view_online_reports] = capabilities_node.get_text('CanViewOnlineReports').to_s == 'true'
|
554
|
+
response_options[:per_print_limit] = capabilities_node.get_text('PerPrintLimit').to_s
|
555
|
+
|
556
|
+
StampsAccountInfoResponse.new(true, '', {}, response_options)
|
557
|
+
end
|
558
|
+
|
559
|
+
def parse_purchase_postage_response(postage, response_options)
|
560
|
+
parse_authenticator(postage)
|
561
|
+
|
562
|
+
response_options[:purchase_status] = postage.get_text('PurchaseStatus').to_s
|
563
|
+
response_options[:rejection_reason] = postage.get_text('RejectionReason').to_s if postage.get_text('RejectionReason')
|
564
|
+
response_options[:transaction_id] = postage.get_text('TransactionID').to_s if postage.get_text('TransactionID')
|
565
|
+
|
566
|
+
balance = postage.elements['PostageBalance']
|
567
|
+
response_options[:available_postage] = balance.get_text('AvailablePostage').to_s
|
568
|
+
response_options[:control_total] = balance.get_text('ControlTotal').to_s if balance.get_text('ControlTotal')
|
569
|
+
|
570
|
+
StampsPurchasePostageResponse.new(true, '', {}, response_options)
|
571
|
+
end
|
572
|
+
alias_method :parse_get_purchase_status_response, :parse_purchase_postage_response
|
573
|
+
|
574
|
+
def parse_cleanse_address_response(cleanse_address, response_options)
|
575
|
+
parse_authenticator(cleanse_address)
|
576
|
+
|
577
|
+
response_options[:address_match] = cleanse_address.get_text('AddressMatch').to_s == 'true'
|
578
|
+
response_options[:city_state_zip_ok] = cleanse_address.get_text('CityStateZipOK').to_s == 'true'
|
579
|
+
|
580
|
+
address = cleanse_address.elements['Address']
|
581
|
+
response_options[:cleanse_hash] = address.get_text('CleanseHash').to_s if address.get_text('CleanseHash')
|
582
|
+
response_options[:override_hash] = address.get_text('OverrideHash').to_s if address.get_text('OverrideHash')
|
583
|
+
|
584
|
+
address_node = cleanse_address.elements['Address']
|
585
|
+
indicator_node = cleanse_address.get_text('ResidentialDeliveryIndicatorType').to_s
|
586
|
+
po_box_node = cleanse_address.get_text('IsPOBox').to_s
|
587
|
+
response_options[:address] = parse_address(address_node, indicator_node, po_box_node)
|
588
|
+
|
589
|
+
candidate_addresses = cleanse_address.get_elements('CandidateAddresses/Address')
|
590
|
+
response_options[:candidate_addresses] = candidate_addresses.map do |candidate_address|
|
591
|
+
parse_address(candidate_address)
|
592
|
+
end
|
593
|
+
|
594
|
+
StampsCleanseAddressResponse.new(true, '', {}, response_options)
|
595
|
+
end
|
596
|
+
|
597
|
+
def parse_address(address_node, residential_indicator_node = nil, po_box_node = nil)
|
598
|
+
address = {}
|
599
|
+
|
600
|
+
address[:name] = address_node.get_text('FullName').to_s if address_node.get_text('FullName')
|
601
|
+
address[:company] = address_node.get_text('Company').to_s if address_node.get_text('Company')
|
602
|
+
address[:address1] = address_node.get_text('Address1').to_s if address_node.get_text('Address1')
|
603
|
+
address[:address2] = address_node.get_text('Address2').to_s if address_node.get_text('Address2')
|
604
|
+
address[:address3] = address_node.get_text('Address3').to_s if address_node.get_text('Address3')
|
605
|
+
address[:city] = address_node.get_text('City').to_s if address_node.get_text('City')
|
606
|
+
address[:country] = address_node.get_text('Country').to_s if address_node.get_text('Country')
|
607
|
+
address[:phone] = address_node.get_text('PhoneNumber').to_s if address_node.get_text('PhoneNumber')
|
608
|
+
|
609
|
+
if address[:country] == 'US' || address[:country].nil?
|
610
|
+
address[:state] = address_node.get_text('State').to_s if address_node.get_text('State')
|
611
|
+
|
612
|
+
address[:postal_code] = address_node.get_text('ZIPCode').to_s if address_node.get_text('ZIPCode')
|
613
|
+
address[:postal_code] += '-' + address_node.get_text('ZIPCodeAddOn').to_s if address_node.get_text('ZIPCodeAddOn')
|
614
|
+
else
|
615
|
+
address[:province] = address_node.get_text('Province').to_s if address_node.get_text('Province')
|
616
|
+
address[:postal_code] = address_node.get_text('PostalCode').to_s if address_node.get_text('PostalCode')
|
617
|
+
end
|
618
|
+
|
619
|
+
address[:address_type] = if residential_indicator_node == 'Yes'
|
620
|
+
'residential'
|
621
|
+
elsif residential_indicator_node == 'No'
|
622
|
+
'commercial'
|
623
|
+
elsif po_box_node == 'true'
|
624
|
+
'po_box'
|
625
|
+
else
|
626
|
+
nil
|
627
|
+
end
|
628
|
+
|
629
|
+
Location.new(address)
|
630
|
+
end
|
631
|
+
|
632
|
+
def parse_get_rates_response(get_rates, response_options)
|
633
|
+
parse_authenticator(get_rates)
|
634
|
+
|
635
|
+
response_options[:estimates] = get_rates.get_elements('Rates/Rate').map do |rate|
|
636
|
+
parse_rate(rate)
|
637
|
+
end
|
638
|
+
|
639
|
+
RateResponse.new(true, '', {}, response_options)
|
640
|
+
end
|
641
|
+
|
642
|
+
def parse_rate(rate)
|
643
|
+
rate_options = {}
|
644
|
+
|
645
|
+
origin = Location.new(zip: rate.get_text('FromZIPCode').to_s)
|
646
|
+
|
647
|
+
location_values = {}
|
648
|
+
location_values[:zip] = rate.get_text('ToZIPCode').to_s if rate.get_text('ToZIPCode')
|
649
|
+
location_values[:country] = rate.get_text('ToCountry').to_s if rate.get_text('ToCountry')
|
650
|
+
destination = Location.new(location_values)
|
651
|
+
|
652
|
+
service_name = SERVICE_TYPES[rate.get_text('ServiceType').to_s]
|
653
|
+
|
654
|
+
rate_options[:service_code] = rate.get_text('ServiceType').to_s
|
655
|
+
rate_options[:currency] = 'USD'
|
656
|
+
rate_options[:shipping_date] = Date.parse(rate.get_text('ShipDate').to_s)
|
657
|
+
|
658
|
+
if delivery_days = rate.get_text('DeliverDays')
|
659
|
+
delivery_days = delivery_days.to_s.split('-')
|
660
|
+
rate_options[:delivery_range] = delivery_days.map { |day| rate_options[:shipping_date] + day.to_i.days }
|
661
|
+
end
|
662
|
+
|
663
|
+
rate_options[:total_price] = rate.get_text('Amount').to_s
|
664
|
+
|
665
|
+
rate_options[:add_ons] = parse_add_ons(rate)
|
666
|
+
rate_options[:packages] = parse_package(rate)
|
667
|
+
|
668
|
+
add_ons = rate_options[:add_ons]
|
669
|
+
if add_ons['SC-A-INS'] and add_ons['SC-A-INS'][:amount]
|
670
|
+
rate_options[:insurance_price] = add_ons['SC-A-INS'][:amount]
|
671
|
+
elsif add_ons['US-A-INS'] and add_ons['US-A-INS'][:amount]
|
672
|
+
rate_options[:insurance_price] = add_ons['US-A-INS'][:amount]
|
673
|
+
end
|
674
|
+
|
675
|
+
StampsRateEstimate.new(origin, destination, @@name, service_name, rate_options)
|
676
|
+
end
|
677
|
+
|
678
|
+
def parse_add_ons(rate)
|
679
|
+
add_ons = {}
|
680
|
+
rate.get_elements('AddOns/AddOnV5').each do |add_on|
|
681
|
+
add_on_type = add_on.get_text('AddOnType').to_s
|
682
|
+
|
683
|
+
add_on_details = {}
|
684
|
+
add_on_details[:missing_data] = add_on.get_text('MissingData').to_s if add_on.get_text('MissingData')
|
685
|
+
add_on_details[:amount] = add_on.get_text('Amount').to_s if add_on.get_text('Amount')
|
686
|
+
|
687
|
+
prohibited_with = add_on.get_elements('ProhibitedWithAnyOf/AddOnTypeV5').map { |p| p.text }
|
688
|
+
add_on_details[:prohibited_with] = prohibited_with unless prohibited_with.empty?
|
689
|
+
|
690
|
+
add_ons[add_on_type] = add_on_details
|
691
|
+
end
|
692
|
+
|
693
|
+
add_ons
|
694
|
+
end
|
695
|
+
|
696
|
+
def parse_package(rate)
|
697
|
+
weight = rate.get_text('WeightOz').to_s.to_f
|
698
|
+
|
699
|
+
dimensions = ['Length', 'Width', 'Height'].map do |dim|
|
700
|
+
rate.get_text(dim) ? rate.get_text(dim).to_s.to_f : nil
|
701
|
+
end
|
702
|
+
dimensions.compact!
|
703
|
+
|
704
|
+
package_options = { units: :imperial }
|
705
|
+
|
706
|
+
if value = rate.get_text('InsuredValue') || rate.get_text('DeclaredValue')
|
707
|
+
package_options[:value] = value.to_s.to_f
|
708
|
+
package_options[:currency] = 'USD'
|
709
|
+
end
|
710
|
+
|
711
|
+
Package.new(weight, dimensions, package_options)
|
712
|
+
end
|
713
|
+
|
714
|
+
def parse_create_indicium_response(indicium, response_options)
|
715
|
+
parse_authenticator(indicium)
|
716
|
+
|
717
|
+
response_options[:shipping_id] = indicium.get_text('IntegratorTxID').to_s
|
718
|
+
response_options[:tracking_number] = indicium.get_text('TrackingNumber').to_s if indicium.get_text('TrackingNumber')
|
719
|
+
response_options[:stamps_tx_id] = indicium.get_text('StampsTxID').to_s
|
720
|
+
response_options[:label_url] = indicium.get_text('URL').to_s if indicium.get_text('URL')
|
721
|
+
response_options[:available_postage] = indicium.get_text('PostageBalance/AvailablePostage').to_s
|
722
|
+
response_options[:control_total] = indicium.get_text('PostageBalance/ControlTotal').to_s
|
723
|
+
response_options[:image_data] = Base64.decode64(indicium.get_text('ImageData/base64Binary').to_s) if indicium.get_text('ImageData/base64Binary')
|
724
|
+
response_options[:rate] = parse_rate(indicium.elements['Rate'])
|
725
|
+
|
726
|
+
StampsShippingResponse.new(true, '', {}, response_options)
|
727
|
+
end
|
728
|
+
|
729
|
+
def parse_track_shipment_response(track_shipment, response_options)
|
730
|
+
parse_authenticator(track_shipment)
|
731
|
+
|
732
|
+
response_options[:carrier] = @@name
|
733
|
+
|
734
|
+
shipment_events = track_shipment.get_elements('TrackingEvents/TrackingEvent').map do |event|
|
735
|
+
unless response_options[:status]
|
736
|
+
response_options[:status_code] = event.get_text('TrackingEventType').to_s
|
737
|
+
response_options[:status] = response_options[:status_code].underscore.to_sym
|
738
|
+
end
|
739
|
+
|
740
|
+
response_options[:delivery_signature] = event.get_text('SignedBy').to_s if event.get_text('SignedBy')
|
741
|
+
|
742
|
+
description = event.get_text('Event').to_s
|
743
|
+
|
744
|
+
timestamp = event.get_text('Timestamp').to_s
|
745
|
+
date, time = timestamp.split('T')
|
746
|
+
year, month, day = date.split('-')
|
747
|
+
hour, minute, second = time.split(':')
|
748
|
+
zoneless_time = Time.utc(year, month, day, hour, minute, second)
|
749
|
+
|
750
|
+
location = Location.new(
|
751
|
+
city: event.get_text('City').to_s,
|
752
|
+
state: event.get_text('State').to_s,
|
753
|
+
zip: event.get_text('Zip').to_s,
|
754
|
+
country: event.get_text('Country').to_s
|
755
|
+
)
|
756
|
+
|
757
|
+
ShipmentEvent.new(description, zoneless_time, location)
|
758
|
+
end
|
759
|
+
|
760
|
+
response_options[:shipment_events] = shipment_events.sort_by(&:time)
|
761
|
+
response_options[:delivered] = response_options[:status] == :delivered
|
762
|
+
|
763
|
+
TrackingResponse.new(true, '', {}, response_options)
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
class StampsAccountInfoResponse < Response
|
768
|
+
attr_reader :customer_id, :meter_number, :user_id, :available_postage, :control_total, :max_postage_balance, :lpo
|
769
|
+
attr_reader :can_print_shipping, :can_use_cost_codes, :can_use_hidden_postage, :can_purchase_sdc_insurance, :can_print_international
|
770
|
+
attr_reader :can_print_memo, :can_purchase_postage, :can_edit_cost_codes, :must_use_cost_codes, :can_view_online_reports, :per_print_limit
|
771
|
+
|
772
|
+
alias_method :can_print_shipping?, :can_print_shipping
|
773
|
+
alias_method :can_use_cost_codes?, :can_use_cost_codes
|
774
|
+
alias_method :can_use_hidden_postage?, :can_use_hidden_postage
|
775
|
+
alias_method :can_purchase_sdc_insurance?, :can_purchase_sdc_insurance
|
776
|
+
alias_method :can_print_international?, :can_print_international
|
777
|
+
alias_method :can_print_memo?, :can_print_memo
|
778
|
+
alias_method :can_purchase_postage?, :can_purchase_postage
|
779
|
+
alias_method :can_edit_cost_codes?, :can_edit_cost_codes
|
780
|
+
alias_method :must_use_cost_codes?, :must_use_cost_codes
|
781
|
+
alias_method :can_view_online_reports?, :can_view_online_reports
|
782
|
+
|
783
|
+
def initialize(success, message, params = {}, options = {})
|
784
|
+
super
|
785
|
+
@customer_id = options[:customer_id]
|
786
|
+
@meter_number = options[:meter_number]
|
787
|
+
@user_id = options[:user_id]
|
788
|
+
@available_postage = options[:available_postage]
|
789
|
+
@control_total = options[:control_total]
|
790
|
+
@max_postage_balance = options[:max_postage_balance]
|
791
|
+
@lpo = Location.new(
|
792
|
+
city: options[:lpo_city],
|
793
|
+
state: options[:lpo_state],
|
794
|
+
zip: options[:lpo_zip]
|
795
|
+
)
|
796
|
+
@can_print_shipping = options[:can_print_shipping]
|
797
|
+
@can_use_cost_codes = options[:can_use_cost_codes]
|
798
|
+
@can_use_hidden_postage = options[:can_use_hidden_postage]
|
799
|
+
@can_purchase_sdc_insurance = options[:can_purchase_sdc_insurance]
|
800
|
+
@can_print_memo = options[:can_print_memo]
|
801
|
+
@can_print_international = options[:can_print_international]
|
802
|
+
@can_purchase_postage = options[:can_purchase_postage]
|
803
|
+
@can_edit_cost_codes = options[:can_edit_cost_codes]
|
804
|
+
@must_use_cost_codes = options[:must_use_cost_codes]
|
805
|
+
@can_view_online_reports = options[:can_view_online_reports]
|
806
|
+
@per_print_limit = options[:per_print_limit]
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
class StampsPurchasePostageResponse < Response
|
811
|
+
attr_reader :purchase_status, :transaction_id, :available_postage, :control_total, :rejection_reason
|
812
|
+
|
813
|
+
def initialize(success, message, params = {}, options = {})
|
814
|
+
super
|
815
|
+
@purchase_status = options[:purchase_status]
|
816
|
+
@transaction_id = options[:transaction_id]
|
817
|
+
@available_postage = options[:available_postage]
|
818
|
+
@control_total = options[:control_total]
|
819
|
+
@rejection_reason = options[:rejection_reason]
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
class StampsCleanseAddressResponse < Response
|
824
|
+
attr_reader :address, :address_match, :city_state_zip_ok, :candidate_addresses, :cleanse_hash, :override_hash
|
825
|
+
|
826
|
+
alias_method :address_match?, :address_match
|
827
|
+
alias_method :city_state_zip_ok?, :city_state_zip_ok
|
828
|
+
|
829
|
+
def initialize(success, message, params = {}, options = {})
|
830
|
+
super
|
831
|
+
@address = options[:address]
|
832
|
+
@address_match = options[:address_match]
|
833
|
+
@city_state_zip_ok = options[:city_state_zip_ok]
|
834
|
+
@candidate_addresses = options[:candidate_addresses]
|
835
|
+
@cleanse_hash = options[:cleanse_hash]
|
836
|
+
@override_hash = options[:override_hash]
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
class StampsRateEstimate < RateEstimate
|
841
|
+
attr_reader :add_ons
|
842
|
+
|
843
|
+
def initialize(origin, destination, carrier, service_name, options={})
|
844
|
+
super
|
845
|
+
@add_ons = options[:add_ons]
|
846
|
+
end
|
847
|
+
|
848
|
+
def available_add_ons
|
849
|
+
add_ons.keys
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
class StampsShippingResponse < ShippingResponse
|
854
|
+
|
855
|
+
include PostsData
|
856
|
+
|
857
|
+
self.ssl_version = :SSLv3
|
858
|
+
|
859
|
+
attr_reader :rate, :stamps_tx_id, :label_url, :available_postage, :control_total
|
860
|
+
|
861
|
+
def initialize(success, message, params = {}, options = {})
|
862
|
+
super
|
863
|
+
@rate = options[:rate]
|
864
|
+
@stamps_tx_id = options[:stamps_tx_id]
|
865
|
+
@label_url = options[:label_url]
|
866
|
+
@image_data = options[:image_data]
|
867
|
+
@available_postage = options[:available_postage]
|
868
|
+
@control_total = options[:control_total]
|
869
|
+
end
|
870
|
+
|
871
|
+
def image
|
872
|
+
@image_data ||= ssl_get(label_url)
|
873
|
+
end
|
874
|
+
end
|
875
|
+
end
|
876
|
+
end
|