active_shipping 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|