friendly_shipping 0.4.6 → 0.4.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6474cdfc41f6c366bbc23ec531346f569a820250
4
- data.tar.gz: f54265c3fac066e54892c1430f6b28d7f65d027a
3
+ metadata.gz: a74d755729d634f9a26b89c9cf7fe9de4f0f9c6f
4
+ data.tar.gz: d55595a012e01a25af70df3f0c7d6d20e1107b6c
5
5
  SHA512:
6
- metadata.gz: bbc3d24cf5f1c690f13e33b5bfd3fc0857f071fb8d4ee79bea1fa08df8f93eab900b6cd233c4627022c9e1c6dcae7056ba0a3140e99882be038c6f192a46eea7
7
- data.tar.gz: bf83d0948e27ad4dc2c8cbf45643d70bd7d7563986901a0bc782cc119cd3c8aac7ac3f1aec19edf86fd37541b7bf36e6467edf971fb3dd193752c9552d7d3ebf
6
+ metadata.gz: 43ad0e0432113fcd26fb0f3472bc2ebf8c64a0d9a4b9b25b0618831a6ecb2a66a97d55f9764d11387c0ce68f6923a3c190d087ea2f40ee39004df4c0c336890a
7
+ data.tar.gz: 6c86ce696207eeb0bc1274485769f53070806a11314df7981d684bd2d0cb9eddb1699c22592f2ff90c4484c3b9a9caf398eb7deb597d4c15136e0148ed231375
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.4.7] - 2019-11-28
8
+
9
+ ### Changed
10
+ - UPS Service: Add timing support
11
+ - UPS Service: Add indicator for address type changes when quoting rates
12
+ - USPS Service: Add timing support
13
+ - Explicitly set Money rounding mode
14
+
7
15
  ## [0.4.6] - 2019-11-28
8
16
 
9
17
  ### Changed
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "physical"
4
+ require "money"
5
+
6
+ # Explicitly configure the default rounding mode to avoid deprecation warnings
7
+ Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
4
8
 
5
9
  require "friendly_shipping/version"
6
10
  require "friendly_shipping/request"
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'money'
5
4
 
6
5
  module FriendlyShipping
7
6
  module Services
@@ -8,6 +8,7 @@ require 'friendly_shipping/services/ups/serialize_address_validation_request'
8
8
  require 'friendly_shipping/services/ups/serialize_rating_service_selection_request'
9
9
  require 'friendly_shipping/services/ups/serialize_shipment_accept_request'
10
10
  require 'friendly_shipping/services/ups/serialize_shipment_confirm_request'
11
+ require 'friendly_shipping/services/ups/serialize_time_in_transit_request'
11
12
  require 'friendly_shipping/services/ups/serialize_void_shipment_request'
12
13
  require 'friendly_shipping/services/ups/parse_address_validation_response'
13
14
  require 'friendly_shipping/services/ups/parse_address_classification_response'
@@ -15,9 +16,11 @@ require 'friendly_shipping/services/ups/parse_city_state_lookup_response'
15
16
  require 'friendly_shipping/services/ups/parse_rate_response'
16
17
  require 'friendly_shipping/services/ups/parse_shipment_confirm_response'
17
18
  require 'friendly_shipping/services/ups/parse_shipment_accept_response'
19
+ require 'friendly_shipping/services/ups/parse_time_in_transit_response'
18
20
  require 'friendly_shipping/services/ups/parse_void_shipment_response'
19
21
  require 'friendly_shipping/services/ups/shipping_methods'
20
22
  require 'friendly_shipping/services/ups/label_options'
23
+ require 'friendly_shipping/services/ups/timing_options'
21
24
 
22
25
  module FriendlyShipping
23
26
  module Services
@@ -42,6 +45,7 @@ module FriendlyShipping
42
45
  rates: '/ups.app/xml/Rate',
43
46
  ship_confirm: '/ups.app/xml/ShipConfirm',
44
47
  ship_accept: '/ups.app/xml/ShipAccept',
48
+ timings: '/ups.app/xml/TimeInTransit',
45
49
  void: '/ups.app/xml/Void',
46
50
  }.freeze
47
51
 
@@ -58,7 +62,7 @@ module FriendlyShipping
58
62
  end
59
63
 
60
64
  # Get rates for a shipment
61
- # @param [Physical::Shipment] location The shipment we want to get rates for
65
+ # @param [Physical::Shipment] shipment The shipment we want to get rates for
62
66
  # @return [Result<ApiResult<Array<Rate>>>] The rates returned from UPS encoded in a
63
67
  # `FriendlyShipping::ApiResult` object.
64
68
  def rate_estimates(shipment, debug: false)
@@ -75,6 +79,27 @@ module FriendlyShipping
75
79
  end
76
80
  end
77
81
 
82
+ # Get timing information for a shipment
83
+ # @param [Physical::Shipment] shipment The shipment we want to estimate timings for
84
+ # @param [FriendlyShipping::Services::Ups::TimingOptions] Options for this call
85
+ def timings(shipment, options:, debug: false)
86
+ time_in_transit_request_xml = SerializeTimeInTransitRequest.call(
87
+ shipment: shipment,
88
+ options: options
89
+ )
90
+ time_in_transit_url = base_url + RESOURCES[:timings]
91
+
92
+ request = FriendlyShipping::Request.new(
93
+ url: time_in_transit_url,
94
+ body: access_request_xml + time_in_transit_request_xml,
95
+ debug: debug
96
+ )
97
+
98
+ client.post(request).bind do |response|
99
+ ParseTimeInTransitResponse.call(response: response, request: request)
100
+ end
101
+ end
102
+
78
103
  def labels(shipment, options:, debug: false)
79
104
  ## Method body starts
80
105
  ship_confirm_request_xml = SerializeShipmentConfirmRequest.call(
@@ -32,16 +32,24 @@ module FriendlyShipping
32
32
  rated_shipment.at('NegotiatedRates/NetSummaryCharges/GrandTotal')
33
33
  )&.last
34
34
 
35
+ rated_shipment_warnings = rated_shipment.css('RatedShipmentWarning').map { |e| e.text.strip }
36
+ if rated_shipment_warnings.any? { |e| e.match?(/to Residential/) }
37
+ new_address_type = 'residential'
38
+ elsif rated_shipment_warnings.any? { |e| e.match?(/to Commercial/) }
39
+ new_address_type = 'commercial'
40
+ end
41
+
35
42
  FriendlyShipping::Rate.new(
36
43
  shipping_method: shipping_method,
37
44
  amounts: { total: total },
38
- warnings: [rated_shipment.at("RatedShipmentWarning")&.text].compact,
45
+ warnings: rated_shipment_warnings,
39
46
  errors: [],
40
47
  data: {
41
48
  insurance_price: insurance_price,
42
49
  negotiated_rate: negotiated_rate,
43
- days_to_delivery: days_to_delivery
44
- }
50
+ days_to_delivery: days_to_delivery,
51
+ new_address_type: new_address_type
52
+ }.compact
45
53
  )
46
54
  end
47
55
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class Ups
6
+ class ParseTimeInTransitResponse
7
+ def self.call(request:, response:)
8
+ parsing_result = ParseXMLResponse.call(response.body, 'TimeInTransitResponse')
9
+ parsing_result.fmap do |xml|
10
+ origin_country_code = xml.at('TransitResponse/TransitFrom/AddressArtifactFormat/CountryCode').text
11
+ timings = xml.root.xpath('//TransitResponse/ServiceSummary').map do |service_summary|
12
+ # First find the shipping method
13
+ service_description = service_summary.at('Service/Description').text.gsub(/\s+/, ' ').strip
14
+ shipping_method = SHIPPING_METHODS.detect do |potential_shipping_method|
15
+ potential_shipping_method.name.starts_with?(service_description) &&
16
+ potential_shipping_method.origin_countries.map(&:code).include?(origin_country_code)
17
+ end
18
+
19
+ # Figure out the dates and times
20
+ delivery_date = service_summary.at('EstimatedArrival/Date').text
21
+ delivery_time = service_summary.at('EstimatedArrival/Time').text
22
+ delivery = Time.parse("#{delivery_date} #{delivery_time}")
23
+ pickup_date = service_summary.at('EstimatedArrival/PickupDate').text
24
+ pickup_time = service_summary.at('EstimatedArrival/PickupTime').text
25
+ pickup = Time.parse("#{pickup_date} #{pickup_time}")
26
+
27
+ # Some additional data
28
+ guaranteed = service_summary.at('Guaranteed/Code').text == 'Y'
29
+ business_transit_days = service_summary.at('EstimatedArrival/BusinessTransitDays').text
30
+
31
+ FriendlyShipping::Timing.new(
32
+ shipping_method: shipping_method,
33
+ pickup: pickup,
34
+ delivery: delivery,
35
+ guaranteed: guaranteed,
36
+ properties: {
37
+ business_transit_days: business_transit_days
38
+ }
39
+ )
40
+ end
41
+
42
+ FriendlyShipping::ApiResult.new(
43
+ timings,
44
+ original_request: request,
45
+ original_response: response
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class Ups
6
+ class SerializeTimeInTransitRequest
7
+ def self.call(shipment:, options:)
8
+ xml_builder = Nokogiri::XML::Builder.new do |xml|
9
+ xml.TimeInTransitRequest do
10
+ xml.Request do
11
+ if options.customer_context
12
+ xml.TransactionReference do
13
+ xml.CustomerContext(options.customer_context)
14
+ end
15
+ end
16
+ xml.RequestAction('TimeInTransit')
17
+ end
18
+ xml.TransitFrom do
19
+ xml.AddressArtifactFormat do
20
+ xml.PoliticalDivision2(shipment.origin.city)
21
+ xml.PoliticalDivision1(shipment.origin.region.code)
22
+ xml.CountryCode(shipment.origin.country.code)
23
+ xml.PostcodePrimaryLow(shipment.origin.zip)
24
+ end
25
+ end
26
+ xml.TransitTo do
27
+ xml.AddressArtifactFormat do
28
+ # We no longer include the destination city since it doesn't seem to change the timing
29
+ # result and can prevent the time in transit request from succeeding when invalid.
30
+ xml.CountryCode(shipment.destination.country.code)
31
+ xml.PostcodePrimaryLow(shipment.destination.zip)
32
+ end
33
+ end
34
+ xml.ShipmentWeight do
35
+ xml.UnitOfMeasurement do
36
+ xml.Code('LBS')
37
+ end
38
+ shipment_weight = shipment.packages.map(&:weight).inject(Measured::Weight(0, :pounds), :+)
39
+ xml.Weight(shipment_weight.convert_to(:pounds).value.to_f.round(3))
40
+ end
41
+ xml.InvoiceLineTotal do
42
+ xml.CurrencyCode(options.invoice_total.currency.iso_code)
43
+ xml.MonetaryValue(options.invoice_total.to_f.round(2))
44
+ end
45
+ xml.PickupDate(options.pickup.strftime('%Y%m%d'))
46
+ end
47
+ end
48
+ xml_builder.to_xml
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class Ups
6
+ # Options for getting timing information from UPS
7
+ # @attribute [Time] pickup When the shipment will be picked up
8
+ # @attribute [Money] invoice_total How much the items in the shipment are worth
9
+ # As this is not super important for getting timing information, we use a default
10
+ # value of 50 USD here.
11
+ # @attribute [Boolean] documents_only Does the shipment only contain documents?
12
+ # @attribute [String] customer_context A string to connect request and response in the calling code
13
+ class TimingOptions
14
+ attr_reader :pickup,
15
+ :invoice_total,
16
+ :documents_only,
17
+ :customer_context
18
+
19
+ def initialize(
20
+ pickup: Time.now,
21
+ invoice_total: Money.new(5000, 'USD'),
22
+ documents_only: false,
23
+ customer_context: nil
24
+ )
25
+ @pickup = pickup
26
+ @invoice_total = invoice_total
27
+ @documents_only = documents_only
28
+ @customer_context = customer_context
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,9 +5,12 @@ require 'friendly_shipping/services/usps/shipping_methods'
5
5
  require 'friendly_shipping/services/usps/serialize_address_validation_request'
6
6
  require 'friendly_shipping/services/usps/serialize_city_state_lookup_request'
7
7
  require 'friendly_shipping/services/usps/serialize_rate_request'
8
+ require 'friendly_shipping/services/usps/serialize_time_in_transit_request'
8
9
  require 'friendly_shipping/services/usps/parse_address_validation_response'
9
10
  require 'friendly_shipping/services/usps/parse_city_state_lookup_response'
10
11
  require 'friendly_shipping/services/usps/parse_rate_response'
12
+ require 'friendly_shipping/services/usps/parse_time_in_transit_response'
13
+ require 'friendly_shipping/services/usps/timing_options'
11
14
 
12
15
  module FriendlyShipping
13
16
  module Services
@@ -29,7 +32,8 @@ module FriendlyShipping
29
32
  RESOURCES = {
30
33
  address_validation: 'Verify',
31
34
  city_state_lookup: 'CityStateLookup',
32
- rates: 'RateV4'
35
+ rates: 'RateV4',
36
+ timings: 'SDCGetLocations'
33
37
  }.freeze
34
38
 
35
39
  def initialize(login:, test: true, client: HttpClient.new)
@@ -66,6 +70,19 @@ module FriendlyShipping
66
70
  end
67
71
  end
68
72
 
73
+ # Get timing estimates from USPS
74
+ #
75
+ # @param [Physical::Shipment] shipment The shipment we want to estimate. Only destination zip and origin zip are used.
76
+ # @param [FriendlyShipping::Services::Usps::TimingOptions] options Options for the timing estimate call
77
+ def timings(shipment, options:, debug: false)
78
+ timings_request_xml = SerializeTimeInTransitRequest.call(shipment: shipment, options: options, login: login)
79
+ request = build_request(api: :timings, xml: timings_request_xml, debug: debug)
80
+
81
+ client.post(request).bind do |response|
82
+ ParseTimeInTransitResponse.call(response: response, request: request)
83
+ end
84
+ end
85
+
69
86
  # Validate an address.
70
87
  # @param [Physical::Location] location The address we want to verify
71
88
  # @return [Result<ApiResult<Array<Physical::Location>>>] The response data from UPS encoded in a
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'friendly_shipping/services/usps/parse_xml_response'
4
+ require 'friendly_shipping/timing'
5
+
6
+ module FriendlyShipping
7
+ module Services
8
+ class Usps
9
+ class ParseTimeInTransitResponse
10
+ class << self
11
+ # Parse a response from USPS' time in transit API
12
+ #
13
+ # @param [FriendlyShipping::Request] request The request that was used to obtain this Response
14
+ # @param [FriendlyShipping::Response] response The response that USPS returned
15
+ # @return [Result<ApiResult<Array<FriendlyShipping::Timing>>>] When successfully parsing, an array of timings in a Success Monad.
16
+ def call(request:, response:)
17
+ # Filter out error responses and directly return a failure
18
+ parsing_result = ParseXMLResponse.call(response.body, 'SDCGetLocationsResponse')
19
+ parsing_result.fmap do |xml|
20
+ expedited_commitments = xml.xpath('//Expedited')
21
+ expedited_timings = parse_expedited_commitment_nodes(expedited_commitments)
22
+
23
+ non_expedited_commitments = xml.xpath('//NonExpedited')
24
+ non_expedited_timings = parse_non_expedited_commitment_nodes(non_expedited_commitments)
25
+
26
+ ApiResult.new(
27
+ expedited_timings + non_expedited_timings,
28
+ original_request: request,
29
+ original_response: response
30
+ )
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def parse_expedited_commitment_nodes(expedited_commitment_nodes)
37
+ # All Expedited Commitments have the same acceptance date
38
+ effective_acceptance_date = Time.parse(expedited_commitment_nodes.at('EAD').text)
39
+ expedited_commitment_nodes.xpath('Commitment').map do |commitment_node|
40
+ shipping_method = SHIPPING_METHODS.detect do |potential_shipping_method|
41
+ potential_shipping_method.name == MAIL_CLASSES[commitment_node.at('MailClass').text]
42
+ end
43
+ commitment_sequence = commitment_node.at('CommitmentSeq').text
44
+ properties = COMMITMENT_SEQUENCES[commitment_sequence]
45
+ scheduled_delivery_time = properties.delete(:commitment_time)
46
+ scheduled_delivery_date = commitment_node.at('SDD').text
47
+ parsed_delivery_time = Time.parse("#{scheduled_delivery_date} #{scheduled_delivery_time}")
48
+ guaranteed = commitment_node.at('IsGuaranteed').text == '1'
49
+
50
+ FriendlyShipping::Timing.new(
51
+ shipping_method: shipping_method,
52
+ pickup: effective_acceptance_date,
53
+ delivery: parsed_delivery_time,
54
+ guaranteed: guaranteed,
55
+ properties: properties
56
+ )
57
+ end
58
+ end
59
+
60
+ def parse_non_expedited_commitment_nodes(non_expedited_commitment_nodes)
61
+ non_expedited_commitment_nodes.map do |commitment_node|
62
+ shipping_method = SHIPPING_METHODS.detect do |potential_shipping_method|
63
+ potential_shipping_method.name == MAIL_CLASSES[commitment_node.at('MailClass').text]
64
+ end
65
+ # We cannot find a shipping method for Mail Classes 4 and 5 because USPS' docs are not clear
66
+ next unless shipping_method
67
+
68
+ properties = {
69
+ commitment: commitment_node.at('SvcStdMsg').text,
70
+ destination_type: NON_EXPEDITED_DESTINATION_TYPES[commitment_node.at('NonExpeditedDestType').text]
71
+ }
72
+ scheduled_delivery_date = commitment_node.at('SchedDlvryDate').text
73
+ parsed_delivery_time = Time.parse(scheduled_delivery_date)
74
+ effective_acceptance_date = Time.parse(commitment_node.at('EAD').text)
75
+
76
+ FriendlyShipping::Timing.new(
77
+ shipping_method: shipping_method,
78
+ pickup: effective_acceptance_date,
79
+ delivery: parsed_delivery_time,
80
+ guaranteed: false,
81
+ properties: properties
82
+ )
83
+ end.compact
84
+ end
85
+
86
+ # The USPS docs say the following:
87
+ #
88
+ # Valid Values:
89
+ # “0” = All Mail Classes
90
+ # “1” = Priority Mail Express
91
+ # “2” = Priority Mail
92
+ # “3” = First Class Mail
93
+ # “4” = Marketing Mail
94
+ # “5” = Periodicals
95
+ # “6” = Package Services
96
+ #
97
+ # However, no shipping methods really map to "Marketing Mail" or "Periodicals".
98
+ # This will likely be somewhat more work in the future.
99
+ MAIL_CLASSES = {
100
+ '1' => 'Priority Mail Express',
101
+ '2' => 'Priority',
102
+ '3' => 'First-Class',
103
+ '6' => 'First-Class Package Service'
104
+ }.freeze
105
+
106
+ # This code carries a few details about the shipment:
107
+ # - What USPS commits to (1-Day, 2-Day or 3-Day delivery)
108
+ # - what time the package should arrive
109
+ # - Whether the package is sent from post office to post office ('Hold For Pickup')
110
+ # A0110 1-Day at 10:30 AM
111
+ # B0110 1-Day at 10:30 AM HFPU
112
+ # A0112 1-Day at 12:00 PM
113
+ # A0115 1-Day at 3:00 PM
114
+ # B0115 1-Day at 3:00 PM HFPU
115
+ # A0210 2-Day at 10:30 AM
116
+ # A0212 2-Day at 12:00 PM
117
+ # A0215 2-Day at 3:00 PM
118
+ # B0210 2-Day at 10:30 AM HFPU
119
+ # B0215 2-Day at 3:00 PM HFPU
120
+ # C0100 1-Day Street
121
+ # C0200 2-Day Street
122
+ # C0300 3-Day Street
123
+ # D0100 1-Day PO Box
124
+ # D0200 2-Day PO Box
125
+ # D0300 3-Day PO Box
126
+ # E0100 1-Day HFPU
127
+ # E0200 2-Day HFPU
128
+ # E0300 3-Day HFPU
129
+ COMMITMENT_SEQUENCES = {
130
+ 'A0110' => {
131
+ commitment: '1-Day',
132
+ commitment_time: '10:30 AM',
133
+ },
134
+ 'B0110' => {
135
+ commitment: '1-Day',
136
+ commitment_time: '10:30 AM',
137
+ destination_type: :hold_for_pickup
138
+ },
139
+ 'A0112' => {
140
+ commitment: '1-Day',
141
+ commitment_time: '12:00 PM',
142
+ },
143
+ 'A0115' => {
144
+ commitment: '1-Day',
145
+ commitment_time: '3:00 PM',
146
+ },
147
+ 'B0115' => {
148
+ commitment: '1-Day',
149
+ commitment_time: '3:00 PM',
150
+ destination_type: :hold_for_pickup
151
+ },
152
+ 'A0210' => {
153
+ commitment: '2-Day',
154
+ commitment_time: '10:30 AM',
155
+ },
156
+ 'A0212' => {
157
+ commitment: '2-Day',
158
+ commitment_time: '12:00 PM',
159
+ },
160
+ 'A0215' => {
161
+ commitment: '2-Day',
162
+ commitment_time: '3:00 PM',
163
+ },
164
+ 'B0210' => {
165
+ commitment: '2-Day',
166
+ commitment_time: '10:30 AM',
167
+ destination_type: :hold_for_pickup
168
+ },
169
+ 'C0100' => {
170
+ commitment: '1-Day',
171
+ destination_type: :street
172
+ },
173
+ 'C0200' => {
174
+ commitment: '2-Day',
175
+ destination_type: :street
176
+ },
177
+ 'C0300' => {
178
+ commitment: '3-Day',
179
+ destination_type: :street
180
+ },
181
+ 'D0100' => {
182
+ commitment: '1-Day',
183
+ destination_type: :po_box
184
+ },
185
+ 'D0200' => {
186
+ commitment: '2-Day',
187
+ destination_type: :po_box
188
+ },
189
+ 'D0300' => {
190
+ commitment: '3-Day',
191
+ destination_type: :po_box
192
+ },
193
+ 'E0100' => {
194
+ commitment: '1-Day',
195
+ destination_type: :hold_for_pickup
196
+ },
197
+ 'E0200' => {
198
+ commitment: '2-Day',
199
+ destination_type: :hold_for_pickup
200
+ },
201
+ 'E0300' => {
202
+ commitment: '3-Day',
203
+ destination_type: :hold_for_pickup
204
+ },
205
+ }.freeze
206
+
207
+ # Things are different for non-expedited shipping methods.
208
+ NON_EXPEDITED_DESTINATION_TYPES = {
209
+ '1' => :street,
210
+ '2' => :po_box,
211
+ '3' => :hold_for_pickup
212
+ }.freeze
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class Usps
6
+ class SerializeTimeInTransitRequest
7
+ def self.call(shipment:, options:, login:)
8
+ xml_builder = Nokogiri::XML::Builder.new do |xml|
9
+ xml.SDCGetLocationsRequest(USERID: login) do
10
+ xml.MailClass 0 # all mail classes
11
+ xml.OriginZIP shipment.origin.zip
12
+ xml.DestinationZIP shipment.destination.zip
13
+ xml.AcceptDate options.pickup.strftime('%d-%b-%Y')
14
+ xml.NonEMDetail true
15
+ end
16
+ end
17
+ xml_builder.to_xml
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class Usps
6
+ class TimingOptions
7
+ attr_reader :pickup, :shipping_method
8
+
9
+ def initialize(
10
+ pickup: Time.now,
11
+ shipping_method: nil
12
+ )
13
+ @pickup = pickup
14
+ @shipping_method = shipping_method
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ class Timing
5
+ attr_reader :shipping_method,
6
+ :pickup,
7
+ :delivery,
8
+ :guaranteed,
9
+ :properties
10
+
11
+ def initialize(
12
+ shipping_method:,
13
+ pickup:,
14
+ delivery:,
15
+ guaranteed: false,
16
+ properties: {}
17
+ )
18
+ @shipping_method = shipping_method
19
+ @pickup = pickup
20
+ @delivery = delivery
21
+ @guaranteed = guaranteed
22
+ @properties = properties
23
+ end
24
+
25
+ def time_in_transit
26
+ delivery - pickup
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FriendlyShipping
4
- VERSION = "0.4.6"
4
+ VERSION = "0.4.7"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_shipping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.6
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-02 00:00:00.000000000 Z
11
+ date: 2019-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: data_uri
@@ -194,6 +194,7 @@ files:
194
194
  - lib/friendly_shipping/services/ups/parse_rate_response.rb
195
195
  - lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb
196
196
  - lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb
197
+ - lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb
197
198
  - lib/friendly_shipping/services/ups/parse_void_shipment_response.rb
198
199
  - lib/friendly_shipping/services/ups/parse_xml_response.rb
199
200
  - lib/friendly_shipping/services/ups/serialize_access_request.rb
@@ -205,8 +206,10 @@ files:
205
206
  - lib/friendly_shipping/services/ups/serialize_shipment_accept_request.rb
206
207
  - lib/friendly_shipping/services/ups/serialize_shipment_address_snippet.rb
207
208
  - lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb
209
+ - lib/friendly_shipping/services/ups/serialize_time_in_transit_request.rb
208
210
  - lib/friendly_shipping/services/ups/serialize_void_shipment_request.rb
209
211
  - lib/friendly_shipping/services/ups/shipping_methods.rb
212
+ - lib/friendly_shipping/services/ups/timing_options.rb
210
213
  - lib/friendly_shipping/services/ups_freight.rb
211
214
  - lib/friendly_shipping/services/ups_freight/generate_commodity_information.rb
212
215
  - lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb
@@ -225,13 +228,17 @@ files:
225
228
  - lib/friendly_shipping/services/usps/parse_city_state_lookup_response.rb
226
229
  - lib/friendly_shipping/services/usps/parse_package_rate.rb
227
230
  - lib/friendly_shipping/services/usps/parse_rate_response.rb
231
+ - lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb
228
232
  - lib/friendly_shipping/services/usps/parse_xml_response.rb
229
233
  - lib/friendly_shipping/services/usps/serialize_address_validation_request.rb
230
234
  - lib/friendly_shipping/services/usps/serialize_city_state_lookup_request.rb
231
235
  - lib/friendly_shipping/services/usps/serialize_rate_request.rb
236
+ - lib/friendly_shipping/services/usps/serialize_time_in_transit_request.rb
232
237
  - lib/friendly_shipping/services/usps/shipping_methods.rb
238
+ - lib/friendly_shipping/services/usps/timing_options.rb
233
239
  - lib/friendly_shipping/shipment_options.rb
234
240
  - lib/friendly_shipping/shipping_method.rb
241
+ - lib/friendly_shipping/timing.rb
235
242
  - lib/friendly_shipping/types.rb
236
243
  - lib/friendly_shipping/version.rb
237
244
  homepage: https://github.com/friendly_cart/friendly_shipping