ship_compliant 0.1.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/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +47 -0
- data/cucumber.yml +9 -0
- data/features/add_update_brand.feature +20 -0
- data/features/add_update_product.feature +24 -0
- data/features/check_compliance_of_sales_order_with_address_validations.feature +18 -0
- data/features/commit_sales_order.feature +6 -0
- data/features/get_inventory_details.feature +7 -0
- data/features/get_sales_order_extended.feature +15 -0
- data/features/search_sales_orders.feature +13 -0
- data/features/step_definitions/brand_steps.rb +73 -0
- data/features/step_definitions/commit_sales_order/all_shipments.rb +15 -0
- data/features/step_definitions/compliance_check/available_product_steps.rb +175 -0
- data/features/step_definitions/compliance_check/missing_product_steps.rb +102 -0
- data/features/step_definitions/compliance_check/noncompliant_product.rb +102 -0
- data/features/step_definitions/credential_steps.rb +8 -0
- data/features/step_definitions/inventory_steps.rb +36 -0
- data/features/step_definitions/product_steps.rb +140 -0
- data/features/step_definitions/sales_order_extended_steps.rb +79 -0
- data/features/step_definitions/search_order_steps.rb +87 -0
- data/features/step_definitions/void_order_steps.rb +27 -0
- data/features/support/env.rb +14 -0
- data/features/void_sales_order.feature +11 -0
- data/fixtures/vcr_cassettes/brand_already_exists.yml +1038 -0
- data/fixtures/vcr_cassettes/brand_ignore_existing.yml +1037 -0
- data/fixtures/vcr_cassettes/brand_update_existing.yml +1037 -0
- data/fixtures/vcr_cassettes/brand_valid.yml +1037 -0
- data/fixtures/vcr_cassettes/commit_salesorder_all_shipments.yml +1034 -0
- data/fixtures/vcr_cassettes/compliance_available_product.yml +1075 -0
- data/fixtures/vcr_cassettes/compliance_missing_product.yml +1046 -0
- data/fixtures/vcr_cassettes/compliance_noncompliant_product.yml +1082 -0
- data/fixtures/vcr_cassettes/ignore_existing_product.yml +1035 -0
- data/fixtures/vcr_cassettes/invalid_search_sales_orders.yml +1038 -0
- data/fixtures/vcr_cassettes/inventory_details_for_everything.yml +1037 -0
- data/fixtures/vcr_cassettes/product_already_exists.yml +1036 -0
- data/fixtures/vcr_cassettes/product_invalid_brand.yml +1036 -0
- data/fixtures/vcr_cassettes/product_valid_brand.yml +1035 -0
- data/fixtures/vcr_cassettes/sales_order_extended.yml +1042 -0
- data/fixtures/vcr_cassettes/sales_order_missing.yml +1034 -0
- data/fixtures/vcr_cassettes/search_sales_orders.yml +1039 -0
- data/fixtures/vcr_cassettes/update_product.yml +1035 -0
- data/fixtures/vcr_cassettes/void_order.yml +1033 -0
- data/fixtures/vcr_cassettes/void_voided_order.yml +1034 -0
- data/lib/ship_compliant.rb +62 -0
- data/lib/ship_compliant/add_update_brand.rb +50 -0
- data/lib/ship_compliant/add_update_brand_result.rb +6 -0
- data/lib/ship_compliant/add_update_product.rb +66 -0
- data/lib/ship_compliant/add_update_product_result.rb +6 -0
- data/lib/ship_compliant/address.rb +87 -0
- data/lib/ship_compliant/address/suggested_address.rb +37 -0
- data/lib/ship_compliant/base_result.rb +43 -0
- data/lib/ship_compliant/channel_details.rb +31 -0
- data/lib/ship_compliant/check_compliance.rb +41 -0
- data/lib/ship_compliant/check_compliance_result.rb +95 -0
- data/lib/ship_compliant/client.rb +54 -0
- data/lib/ship_compliant/commit_sales_order.rb +48 -0
- data/lib/ship_compliant/commit_sales_order_result.rb +30 -0
- data/lib/ship_compliant/compliance_rule.rb +30 -0
- data/lib/ship_compliant/configuration.rb +46 -0
- data/lib/ship_compliant/error_result.rb +41 -0
- data/lib/ship_compliant/freight_sales_tax_rate.rb +8 -0
- data/lib/ship_compliant/get_inventory_details.rb +31 -0
- data/lib/ship_compliant/get_inventory_details_result.rb +41 -0
- data/lib/ship_compliant/get_sales_order_extended.rb +23 -0
- data/lib/ship_compliant/get_sales_order_extended_result.rb +65 -0
- data/lib/ship_compliant/inventory_product.rb +95 -0
- data/lib/ship_compliant/order_search.rb +92 -0
- data/lib/ship_compliant/package.rb +13 -0
- data/lib/ship_compliant/product_attributes.rb +98 -0
- data/lib/ship_compliant/product_sales_tax_rate.rb +23 -0
- data/lib/ship_compliant/sales_tax_rate.rb +22 -0
- data/lib/ship_compliant/search_sales_order_summary.rb +30 -0
- data/lib/ship_compliant/search_sales_orders.rb +53 -0
- data/lib/ship_compliant/search_sales_orders_result.rb +106 -0
- data/lib/ship_compliant/shipment.rb +59 -0
- data/lib/ship_compliant/shipment_compliance.rb +28 -0
- data/lib/ship_compliant/shipment_sales_tax_rate.rb +15 -0
- data/lib/ship_compliant/version.rb +3 -0
- data/lib/ship_compliant/void_sales_order.rb +42 -0
- data/lib/ship_compliant/void_sales_order_result.rb +20 -0
- data/ship_compliant.gemspec +33 -0
- data/spec/fixtures/add_update_product.xml +22 -0
- data/spec/fixtures/check_compliance.xml +125 -0
- data/spec/fixtures/coreservice.wsdl +1341 -0
- data/spec/fixtures/search_sales_orders.xml +52 -0
- data/spec/fixtures/void_order_failure.xml +31 -0
- data/spec/fixtures/void_order_success.xml +22 -0
- data/spec/lib/ship_compliant/add_update_brand_result_spec.rb +7 -0
- data/spec/lib/ship_compliant/add_update_brand_spec.rb +58 -0
- data/spec/lib/ship_compliant/add_update_product_result_spec.rb +7 -0
- data/spec/lib/ship_compliant/add_update_product_spec.rb +52 -0
- data/spec/lib/ship_compliant/address/suggested_address_spec.rb +28 -0
- data/spec/lib/ship_compliant/address_spec.rb +123 -0
- data/spec/lib/ship_compliant/base_result_spec.rb +127 -0
- data/spec/lib/ship_compliant/channel_details_spec.rb +40 -0
- data/spec/lib/ship_compliant/check_compliance_result_spec.rb +135 -0
- data/spec/lib/ship_compliant/check_compliance_spec.rb +43 -0
- data/spec/lib/ship_compliant/client_spec.rb +73 -0
- data/spec/lib/ship_compliant/commit_sales_order_result_spec.rb +32 -0
- data/spec/lib/ship_compliant/commit_sales_order_spec.rb +38 -0
- data/spec/lib/ship_compliant/compliance_rule_spec.rb +47 -0
- data/spec/lib/ship_compliant/configuration_spec.rb +47 -0
- data/spec/lib/ship_compliant/error_result_spec.rb +47 -0
- data/spec/lib/ship_compliant/freight_sales_tax_rate_spec.rb +7 -0
- data/spec/lib/ship_compliant/get_inventory_details_result_spec.rb +87 -0
- data/spec/lib/ship_compliant/get_inventory_details_spec.rb +35 -0
- data/spec/lib/ship_compliant/get_sales_order_extended_result_spec.rb +84 -0
- data/spec/lib/ship_compliant/get_sales_order_extended_spec.rb +39 -0
- data/spec/lib/ship_compliant/inventory_product_spec.rb +116 -0
- data/spec/lib/ship_compliant/order_search_spec.rb +21 -0
- data/spec/lib/ship_compliant/package_spec.rb +26 -0
- data/spec/lib/ship_compliant/product_attributes_spec.rb +36 -0
- data/spec/lib/ship_compliant/product_sales_tax_rate_spec.rb +22 -0
- data/spec/lib/ship_compliant/sales_tax_rate_spec.rb +21 -0
- data/spec/lib/ship_compliant/search_sales_order_summary_spec.rb +56 -0
- data/spec/lib/ship_compliant/search_sales_orders_result_spec.rb +121 -0
- data/spec/lib/ship_compliant/search_sales_orders_spec.rb +42 -0
- data/spec/lib/ship_compliant/shipment_compliance_spec.rb +46 -0
- data/spec/lib/ship_compliant/shipment_sales_tax_rate_spec.rb +20 -0
- data/spec/lib/ship_compliant/shipment_spec.rb +106 -0
- data/spec/lib/ship_compliant/void_sales_order_result_spec.rb +7 -0
- data/spec/lib/ship_compliant/void_sales_order_spec.rb +41 -0
- data/spec/spec_helper.rb +50 -0
- metadata +366 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
class << self
|
3
|
+
attr_accessor :ship_compliant_client
|
4
|
+
end
|
5
|
+
|
6
|
+
# Returns an instance of +Client+.
|
7
|
+
def self.client
|
8
|
+
self.ship_compliant_client ||= new_client_from_wsdl(configuration.wsdl)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Replaces #client with custom WSDL
|
12
|
+
#
|
13
|
+
# ShipCompliant.wsdl = 'https://ws-dev.shipcompliant.com/Services/1.2/ProductService.asmx?WSDL'
|
14
|
+
def self.wsdl=(wsdl)
|
15
|
+
self.ship_compliant_client = new_client_from_wsdl(wsdl)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Creates a new client from a WSDL url.
|
21
|
+
def self.new_client_from_wsdl(wsdl)
|
22
|
+
Client.new(wsdl: wsdl, log: configuration.log, filters: %W[PartnerKey Username Password])
|
23
|
+
end
|
24
|
+
|
25
|
+
class Client < Savon::Client
|
26
|
+
# "Backup" original #call from Savon::Client
|
27
|
+
alias_method :savon_call, :call
|
28
|
+
|
29
|
+
# Adds the required security credentials and formats
|
30
|
+
# the message to match the ShipCompliant structure.
|
31
|
+
#
|
32
|
+
# ShipCompliant.client.call(:some_operation, {
|
33
|
+
# 'SomeKey' => 'SomeValue'
|
34
|
+
# })
|
35
|
+
def call(operation, locals = {})
|
36
|
+
locals['Security'] = ShipCompliant.configuration.credentials
|
37
|
+
|
38
|
+
response = savon_call(operation, message: {
|
39
|
+
'Request' => locals
|
40
|
+
})
|
41
|
+
|
42
|
+
get_result_from_response(operation, response)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def get_result_from_response(operation, response)
|
48
|
+
key = operation.to_s
|
49
|
+
resp_key = (key + '_response').to_sym
|
50
|
+
result_key = (key + '_result').to_sym
|
51
|
+
response.to_hash.fetch(resp_key, {}).fetch(result_key, {})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::CommitSalesOrder
|
3
|
+
#
|
4
|
+
# This method takes in a Sales Order Key in the request and saves the order
|
5
|
+
# if it has previously been checked for compliance.
|
6
|
+
#
|
7
|
+
# - If the CommitOption is set to “AllShipments”, all the shipments in the sales order will be committed.
|
8
|
+
# - If it is set to “CompliantShipments”, just the non-committed compliant sales orders will be committed.
|
9
|
+
#
|
10
|
+
# Please keep in mind that if “CompliantShipments” is selected, it will be of
|
11
|
+
# great value to the customer if the non-compliant, non-committed orders were
|
12
|
+
# flagged as such for further review.
|
13
|
+
#
|
14
|
+
# If the CommitOption is not specified, zero shipments will be committed.
|
15
|
+
# This allows the integrator to get the commit status of the shipments in a
|
16
|
+
# sales order without committing any of them.
|
17
|
+
#
|
18
|
+
# result = ShipCompliant::CommitSalesOrder.call({
|
19
|
+
# commit_options: 'AllShipments',
|
20
|
+
# payments: nil,
|
21
|
+
# sales_tax_collected: 0,
|
22
|
+
# sales_order_key: 'ORDER-KEY'
|
23
|
+
# })
|
24
|
+
#
|
25
|
+
# puts result.success? #=> true
|
26
|
+
# puts "The following shipments were committed."
|
27
|
+
#
|
28
|
+
# puts result.committed_shipments #=> ['1', '2', ...]
|
29
|
+
class CommitSalesOrder
|
30
|
+
|
31
|
+
# Marks a SalesOrder as committed.
|
32
|
+
#
|
33
|
+
# Returns an instance of ShipCompliant::CommitSalesOrderResult.
|
34
|
+
#
|
35
|
+
# ShipCompliant::CommitSalesOrder.call({
|
36
|
+
# commit_options: 'CompliantShipments',
|
37
|
+
# payments: nil,
|
38
|
+
# sales_tax_collected: 0,
|
39
|
+
# sales_order_key: 'ORDER-KEY'
|
40
|
+
# })
|
41
|
+
def self.call(commit_data)
|
42
|
+
commit_data.deep_transform_keys! { |key| key.to_s.camelize }
|
43
|
+
result = ShipCompliant.client.call(:commit_sales_order, commit_data)
|
44
|
+
CommitSalesOrderResult.new(result)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::CommitSalesOrderResult
|
3
|
+
#
|
4
|
+
# Wraps the response of +CommitSalesOrder+ and provides methods to quickly
|
5
|
+
# access shipments, and the committed shipment keys.
|
6
|
+
class CommitSalesOrderResult < Struct.new(:response)
|
7
|
+
include BaseResult
|
8
|
+
|
9
|
+
# Returns an array of shipment objects.
|
10
|
+
#
|
11
|
+
# puts result.shipments #=> [
|
12
|
+
# {
|
13
|
+
# key: 'SHIPMENT-KEY',
|
14
|
+
# is_committed: true/false
|
15
|
+
# }
|
16
|
+
# ]
|
17
|
+
def shipments
|
18
|
+
Array.wrap(response[:shipments][:shipment_commit_response])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Gets the keys for committed shipments.
|
22
|
+
#
|
23
|
+
# puts result.committed_shipments #=> ['SHIPMENT-1', 'SHIPMENT-2', ...]
|
24
|
+
def committed_shipments
|
25
|
+
shipments
|
26
|
+
.select { |s| s[:is_committed] == true }
|
27
|
+
.map { |s| s[:key] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
class ComplianceRule < Struct.new(:response)
|
3
|
+
|
4
|
+
# Returns the +ComplianceDescription+.
|
5
|
+
def compliance_description
|
6
|
+
response[:compliance_description]
|
7
|
+
end
|
8
|
+
|
9
|
+
# Checks if the current compliance rule was met.
|
10
|
+
def compliant?
|
11
|
+
response[:is_compliant]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the +RuleDescription+.
|
15
|
+
def rule_description
|
16
|
+
response[:rule_description]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the +LicenseRelationship+.
|
20
|
+
def license_relationship
|
21
|
+
response[:license_relationship]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the +RuleType+.
|
25
|
+
def rule_type
|
26
|
+
response[:rule_type]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
class << self
|
3
|
+
attr_accessor :configuration
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.configure
|
7
|
+
yield(configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configuration
|
11
|
+
@configuration ||= Configuration.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Stores runtime configuration to authenticate user.
|
15
|
+
#
|
16
|
+
# ShipCompliant.configure do |c|
|
17
|
+
# c.partner_key = 'XXXX-XX-XXXXX'
|
18
|
+
# c.username = 'bob@example.com'
|
19
|
+
# c.password = 'secret'
|
20
|
+
# c.log = true # savon log
|
21
|
+
# end
|
22
|
+
class Configuration
|
23
|
+
attr_accessor :partner_key, :username, :password
|
24
|
+
attr_accessor :wsdl, :log
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@log = true
|
28
|
+
@wsdl = 'https://ws-dev.shipcompliant.com/services/1.2/coreservice.asmx?WSDL'
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a +Hash+ for authenticating each API request.
|
32
|
+
#
|
33
|
+
# {
|
34
|
+
# 'PartnerKey' => 'XXXX-XX-XXXXX',
|
35
|
+
# 'Username' => 'bob@example.com',
|
36
|
+
# 'Password' => 'secret'
|
37
|
+
# }
|
38
|
+
def credentials
|
39
|
+
{
|
40
|
+
'PartnerKey' => partner_key,
|
41
|
+
'Username' => username,
|
42
|
+
'Password' => password
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
class ErrorResult < Struct.new(:error)
|
3
|
+
|
4
|
+
# Gets the error code as an integer.
|
5
|
+
#
|
6
|
+
# puts "ERROR ##{error.code}" #=> 404
|
7
|
+
def code
|
8
|
+
error[:code].to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
# Gets the key of the item with an error.
|
12
|
+
#
|
13
|
+
# puts error.key #=> 'ORDER-123'
|
14
|
+
def key
|
15
|
+
error[:key]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Gets the error message.
|
19
|
+
#
|
20
|
+
# puts "ERROR: #{error.message}" #=> 'I don't think it's a good idea,
|
21
|
+
# Yogi'
|
22
|
+
def message
|
23
|
+
error[:message]
|
24
|
+
end
|
25
|
+
|
26
|
+
# The object type that had the error.
|
27
|
+
#
|
28
|
+
# puts error.target #=> 'SalesOrder'
|
29
|
+
def target
|
30
|
+
error[:target]
|
31
|
+
end
|
32
|
+
|
33
|
+
# The type of error that occured.
|
34
|
+
#
|
35
|
+
# puts error.type #=> 'Validation'
|
36
|
+
def type
|
37
|
+
error[:type]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::GetInventoryDetails
|
3
|
+
#
|
4
|
+
# Provides inventory details for each Product on a Fulfillment Location,
|
5
|
+
# Fulfillment Account basis.
|
6
|
+
#
|
7
|
+
# result = ShipCompliant::GetInventoryDetails.call
|
8
|
+
# product = result.products_for_location('WineShipping').first
|
9
|
+
#
|
10
|
+
# product.inventory_levels #=> {
|
11
|
+
# available: 25,
|
12
|
+
# reserved: 13
|
13
|
+
# }
|
14
|
+
class GetInventoryDetails
|
15
|
+
|
16
|
+
# Returns inventory details for the specified criteria. The method may be
|
17
|
+
# called without any parameters to return all products with Available
|
18
|
+
# inventory.
|
19
|
+
#
|
20
|
+
# ShipCompliant::GetInventoryDetails.call({
|
21
|
+
# brand_key: 'BRAND-KEY',
|
22
|
+
# fulfillment_location: 'WineShipping'
|
23
|
+
# })
|
24
|
+
def self.call(query = {})
|
25
|
+
query.deep_transform_keys! { |k| k.to_s.camelize }
|
26
|
+
result = ShipCompliant.client.call(:get_inventory_details, query)
|
27
|
+
GetInventoryDetailsResult.new(result)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::GetInventoryDetailsResult
|
3
|
+
#
|
4
|
+
# Wraps the result of +GetInventoryDetails+ and provides methods to access
|
5
|
+
# locations and products for a location
|
6
|
+
class GetInventoryDetailsResult < Struct.new(:response)
|
7
|
+
include BaseResult
|
8
|
+
|
9
|
+
# Returns an array of +InventoryLocation+ nodes.
|
10
|
+
#
|
11
|
+
# result.locations[0][:sub_inventory_code] #=> 'SUB-CODE'
|
12
|
+
def locations
|
13
|
+
Array.wrap(response[:inventory_locations]).map do |location|
|
14
|
+
location[:inventory_location]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Finds a location by +FulfillmentLocation+.
|
19
|
+
#
|
20
|
+
# result.location('WineShipping')[:supplier] #=> 'LOCATION-SUPPLIER'
|
21
|
+
def location(key)
|
22
|
+
location = locations.select { |l| l[:fulfillment_location] == key }.first
|
23
|
+
|
24
|
+
return {} if location.nil?
|
25
|
+
location
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns an array of ShipCompliant::InventoryProduct.
|
29
|
+
#
|
30
|
+
# result.products_for_location('WineShipping').each do |product|
|
31
|
+
# puts product.product_key
|
32
|
+
# puts "\t#{product.description}"
|
33
|
+
# puts "---\n"
|
34
|
+
# end
|
35
|
+
def products_for_location(key)
|
36
|
+
Array.wrap(location(key)[:inventory_products]).map do |product|
|
37
|
+
InventoryProduct.new(product[:inventory_product])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::GetSalesOrderExtended
|
3
|
+
#
|
4
|
+
# This method takes in a Sales Order Key and returns detailed data about the
|
5
|
+
# sales order, including compliance status.
|
6
|
+
#
|
7
|
+
# Use this method to query the full details of a sales order and the
|
8
|
+
# shipments in the sales order.
|
9
|
+
class GetSalesOrderExtended
|
10
|
+
|
11
|
+
# Finds a +SalesOrder+ by the +SalesOrderKey+.
|
12
|
+
#
|
13
|
+
# Returns an instance of ShipCompliant::GetSalesOrderExtendedResult.
|
14
|
+
def self.by_order_key(order_key)
|
15
|
+
result = ShipCompliant.client.call(:get_sales_order_extended, {
|
16
|
+
'SalesOrderKey' => order_key
|
17
|
+
})
|
18
|
+
|
19
|
+
GetSalesOrderExtendedResult.new(result)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::GetSalesOrderExtendedResult
|
3
|
+
#
|
4
|
+
# Wraps the response of +GetSalesOrderExtended+ and provides methods to
|
5
|
+
# quickly access compliace rules of a shipment, the billing address,
|
6
|
+
# shipments, and channel details.
|
7
|
+
class GetSalesOrderExtendedResult < Struct.new(:response)
|
8
|
+
include BaseResult
|
9
|
+
|
10
|
+
# Returns an array of the +ShipmentComplianceResponse+ node as a Hash.
|
11
|
+
#
|
12
|
+
# sales_order.shipment_compliance_rules.each do |shipment|
|
13
|
+
# puts "SHIPMENT '#{shipment[:key]}' IS NOT COMPLIANT" unless shipment[:is_compliant]
|
14
|
+
# end
|
15
|
+
def shipment_compliance_rules
|
16
|
+
Array.wrap(response[:compliance_results][:sales_order][:shipments][:shipment_compliance_response]).map do |shipment|
|
17
|
+
shipment
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Finds all the compliance rules for a shipment.
|
22
|
+
# Returns an instance of ShipmentCompliance.
|
23
|
+
#
|
24
|
+
# shipment_compliance = sales_order.compliance_rules_for_shipment('SHIPMENT-KEY')
|
25
|
+
# puts shipment_compliance.compliant? #=> false
|
26
|
+
def compliance_rules_for_shipment(shipment_key)
|
27
|
+
shipment = shipment_compliance_rules.select { |s| s[:key] == shipment_key }.first
|
28
|
+
ShipmentCompliance.new(shipment)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a ShipCompliant::Address with the customer's billing information.
|
32
|
+
#
|
33
|
+
# puts sales_order.bill_to.state #=> 'AK'
|
34
|
+
def bill_to
|
35
|
+
Address.new(response[:sales_order][:bill_to])
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns an array of +Shipment+ nodes as a Hash.
|
39
|
+
#
|
40
|
+
# sales_order.shipments.each do |shipment|
|
41
|
+
# puts shipment[:ship_date] #=> DateTime
|
42
|
+
# end
|
43
|
+
def shipments
|
44
|
+
Array.wrap(response[:sales_order][:shipments]).map do |shipment|
|
45
|
+
shipment[:shipment]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Finds a shipment by +ShipmentKey+. Returns an instance of ShipCompliant::Shipment.
|
50
|
+
#
|
51
|
+
# shipment = sales_order.find_shipment('1')
|
52
|
+
# puts shipment.ship_date #=> DateTime
|
53
|
+
def find_shipment(shipment_key)
|
54
|
+
shipment = shipments.select { |s| s[:shipment_key] == shipment_key }.first
|
55
|
+
Shipment.new(shipment)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the +OrderChannelDetails+ node as an instance of ShipCompliant::ChannelDetails.
|
59
|
+
#
|
60
|
+
# puts sales_order.channel_details.order_channel #=> 'MyOrders'
|
61
|
+
def channel_details
|
62
|
+
ChannelDetails.new(response[:order_channel_details])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module ShipCompliant
|
2
|
+
# == ShipCompliant::InventoryProduct
|
3
|
+
#
|
4
|
+
# InventoryProduct is a value object that has methods to access product data from GetInventoryDetails.
|
5
|
+
#
|
6
|
+
# products = @inventory_results.products_for_location('WineShipping')
|
7
|
+
#
|
8
|
+
# products.each do |product|
|
9
|
+
# puts "[%s] %s" % [product.product_key, product.description]
|
10
|
+
#
|
11
|
+
# product.inventory_levels.each do |type, quantity|
|
12
|
+
# puts "%s are %s" % [quantity, type]
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
class InventoryProduct < Struct.new(:product)
|
16
|
+
|
17
|
+
# Returns the +DefaultCase+ of a product.
|
18
|
+
def default_case
|
19
|
+
product[:default_case]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the +ProductKey+ of a product.
|
23
|
+
def product_key
|
24
|
+
product[:product_key]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the +ProductType+ of a product.
|
28
|
+
def product_type
|
29
|
+
product[:product_type]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the +Description+ of a product.
|
33
|
+
def description
|
34
|
+
product[:description]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the +UnitPrice+ of a product as a float.
|
38
|
+
def unit_price
|
39
|
+
product[:unit_price].to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the +FulfillmentSku+ of a product.
|
43
|
+
def fulfillment_sku
|
44
|
+
product[:fulfillment_sku]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the +PercentAlcohol+ of a product as a float.
|
48
|
+
def percent_alcohol
|
49
|
+
product[:percent_alcohol].to_f
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the +Vintage+ of a product as an integer.
|
53
|
+
def vintage
|
54
|
+
product[:vintage].to_i
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the +VolumeAmount+ of a product as a float.
|
58
|
+
def volume_amount
|
59
|
+
product[:volume_amount].to_f
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the +VolumeML+ of a product as a float.
|
63
|
+
def volume_ml
|
64
|
+
product[:volume_ml].to_f
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the +VolumeUnit+ of a product.
|
68
|
+
def volume_unit
|
69
|
+
product[:volume_unit]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns a Hash of inventory levels.
|
73
|
+
#
|
74
|
+
# - The key is the +InventoryType+.
|
75
|
+
# - The value is +Quantity+ as a float.
|
76
|
+
#
|
77
|
+
# product.inventory_levels #=> {
|
78
|
+
# available: 2,
|
79
|
+
# on_hold: 2,
|
80
|
+
# back_order: 4
|
81
|
+
# }
|
82
|
+
def inventory_levels
|
83
|
+
levels = {}
|
84
|
+
|
85
|
+
product[:inventory_levels][:inventory_level].each do |level|
|
86
|
+
key = level[:inventory_type].underscore.to_sym
|
87
|
+
value = level[:quantity].to_f
|
88
|
+
|
89
|
+
levels[key] = value
|
90
|
+
end
|
91
|
+
|
92
|
+
levels
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|