friendly_shipping 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
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