Skip to content

Commit

Permalink
Merge pull request #64 from customink/ak/eu-quotation-updates
Browse files Browse the repository at this point in the history
Allow users to specify shipping terms and physical origin for line items
  • Loading branch information
Adam Kulisek authored Oct 27, 2020
2 parents 96edb96 + 37294f7 commit ffae838
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 19 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

This file tracks all the changes (https://keepachangelog.com/en/1.0.0/) made to the client. This allows parsers such as Dependabot to provide a clean overview in pull requests.

## [v0.10.0] - 2020-09-29

#### Added

- Quotation payload now accepts a `:delivery_term` param to specify delivery terms for quotation request
- Allow optional `physical_origin` attribute of `seller` in line item to help with specific VAT calculation use cases

#### Changed

- Update quotation validation rules to require either `state` (case of US address) or `country` (other countries) for line items with `seller` overrides that also specify `physical_origin`

## [v0.9.2] - 2020-07-07

#### Added
Expand Down
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The Vertex Client Ruby Gem provides an interface to integrate with _Vertex SMB_
response = VertexClient.quotation(
# The top level transaction date for all line items.
date: "2018-11-15",
# Optional delivery term to specify correct pricing all line items.
delivery_term: "DAP",
# The top level customer for all line items.
customer: {
code: "[email protected]",
Expand All @@ -31,7 +33,7 @@ response = VertexClient.quotation(
},
# The top level seller for all line items.
seller: {
company: "CustomInk"
company: "CustomInk",
},
line_items: [
{
Expand Down Expand Up @@ -62,6 +64,27 @@ response = VertexClient.quotation(
state: "DC",
postal_code: "20500"
}
},
{
product_code: "5400",
product_class: "123456",
quantity: 2,
price: "35.40",
# Optional transaction date override for a line item.
date: "2018-11-14",
# Optional seller override for a line item.
seller: {
company: "CustomInkStores",
# Optional physical origin of a line item
physical_origin: {
address_1: "Prujezdna 320/62",
address_2: "",
city: "Praha",
state: "",
postal_code: "100 00",
country: "CZ"
}
}
}
]
)
Expand All @@ -71,7 +94,7 @@ response.total #=> Total price plus total tax
response.subtotal #=> Total price before tax
```

#### Customer data
#### Location specific data (required for `:customer` and specified `:physical_origin` of `:seller` in `:line_items`)
You are required to specify a `state` or a `country`. The client will raise an error if none is specified.

##### US address example
Expand Down
21 changes: 13 additions & 8 deletions lib/vertex_client/payloads/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ def request_key
def transform_customer(customer)
remove_nils({
:@isTaxExempt => customer[:is_tax_exempt],
destination: remove_nils({
street_address_1: customer[:address_1],
street_address_2: customer[:address_2],
city: customer[:city],
main_division: customer[:state],
postal_code: customer[:postal_code],
country: customer[:country]
})
destination: transform_address(customer)
})
end

def transform_address(address)
return unless address
remove_nils({
street_address_1: address[:address_1],
street_address_2: address[:address_2],
city: address[:city],
main_division: address[:state],
postal_code: address[:postal_code],
country: address[:country]
})
end

Expand Down
28 changes: 20 additions & 8 deletions lib/vertex_client/payloads/quotation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ class Quotation < Base

def validate!
raise VertexClient::ValidationError.new('customer requires either state or country and postal_code') if customer_missing_location?
raise VertexClient::ValidationError.new('seller\'s physical_origin requires either state or country and postal_code') if sellers_physical_origin_missing_location?
end

def body
{}.tap do |data|
data[:'@transactionType'] = SALE_TRANSACTION_TYPE
data[:'@isTaxOnlyAdjustmentIndicator'] = true if params[:tax_only_adjustment]
data[:'@deliveryTerm'] = params[:delivery_term] if params[:delivery_term]
data[:line_item] = params[:line_items].map.with_index do |line_item, index|
transform_line_item(line_item, index, params)
end
Expand All @@ -21,23 +23,32 @@ def body
private

def customer_missing_location?
!customer_lines(params).all? { |customer| customer_destination_present?(customer) }
!customer_lines(params).all? { |customer| destination_present?(customer) }
end

def sellers_physical_origin_missing_location?
!sellers_physical_origin_lines(params).all? { |physical_origin| destination_present?(physical_origin) }
end

def transform_customer(customer_params)
super(customer_params).tap do |customer|
if customer_params[:tax_area_id].present?
customer[:destination] = { :@taxAreaId => customer_params[:tax_area_id]}
customer[:destination] = { :@taxAreaId => customer_params[:tax_area_id] }
end
end
end

def customer_lines(params)
[params[:customer], params[:line_items].map { |li| li[:customer]}].flatten.compact
[params[:customer], params[:line_items].map { |li| li[:customer] }].flatten.compact
end

def sellers_physical_origin_lines(params)
[params[:line_items].map { |li| li[:seller] && li[:seller][:physical_origin] }].flatten.compact
end

def customer_destination_present?(customer)
(us_location_present?(customer) || other_location_present?(customer)) && customer[:postal_code].present?
# The hash argument is either customer or physical_origin object
def destination_present?(hash)
(us_location_present?(hash) || other_location_present?(hash)) && hash[:postal_code].present?
end

def transform_line_item(line_item, number, defaults)
Expand All @@ -54,9 +65,10 @@ def transform_line_item(line_item, number, defaults)
end

def transform_seller(seller)
{
company: seller[:company]
}
remove_nils({
company: seller[:company],
physical_origin: transform_address(seller[:physical_origin])
})
end

def transform_product(line_item)
Expand Down
2 changes: 1 addition & 1 deletion lib/vertex_client/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module VertexClient
VERSION = '0.9.2'
VERSION = '0.10.0'
end
73 changes: 73 additions & 0 deletions test/payloads/quotation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
assert_equal({:@taxAreaId => '1337' }, payload.body[:line_item][0][:customer][:destination])
end

it 'supports sending delivery_term to body' do
working_quote_params[:delivery_term] = 'DAP'
assert_equal('DAP', payload.body[:@deliveryTerm])
end

describe 'validate!' do
describe 'for US customer' do
it 'is happy if state and postal_code are present on customer' do
Expand Down Expand Up @@ -69,5 +74,73 @@
end
end
end

describe 'for seller override' do
describe 'without physical_origin' do
it 'does not raise' do
VertexClient::Payload::Quotation.new(working_eu_quote_params).validate!
end
end

describe 'with physical_origin' do
describe 'from US' do
before(:each) do
working_eu_quote_params[:line_items][1][:seller][:physical_origin] = {
address_1: '2910 District Ave #300',
city: 'Fairfax',
postal_code: '22031',
state: 'VA'
}
end

it 'does not raise if state and postal_code are present' do
VertexClient::Payload::Quotation.new(working_eu_quote_params).validate!
end

it 'raises if physical_origin is missing state' do
working_eu_quote_params[:line_items][1][:seller][:physical_origin].delete(:state)
assert_raises VertexClient::ValidationError do
VertexClient::Payload::Quotation.new(working_eu_quote_params).body
end
end

it 'raises if physical_origin is missing postal_code' do
working_eu_quote_params[:line_items][1][:seller][:physical_origin].delete(:postal_code)
assert_raises VertexClient::ValidationError do
VertexClient::Payload::Quotation.new(working_eu_quote_params).body
end
end
end

describe 'from EU' do
before(:each) do
working_eu_quote_params[:line_items][1][:seller][:physical_origin] = {
address_1: 'Prujezdna 320/62',
city: 'Praha',
postal_code: '100 00',
country: 'CZ'
}
end

it 'does not raise if country and postal_code are present' do
VertexClient::Payload::Quotation.new(working_eu_quote_params).validate!
end

it 'raises if physical_origin is missing country' do
working_eu_quote_params[:line_items][1][:seller][:physical_origin].delete(:country)
assert_raises VertexClient::ValidationError do
VertexClient::Payload::Quotation.new(working_eu_quote_params).body
end
end

it 'raises if physical_origin is missing postal_code' do
working_eu_quote_params[:line_items][1][:seller][:physical_origin].delete(:postal_code)
assert_raises VertexClient::ValidationError do
VertexClient::Payload::Quotation.new(working_eu_quote_params).body
end
end
end
end
end
end
end

0 comments on commit ffae838

Please sign in to comment.