shipppit-canada-post 0.5.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.
@@ -0,0 +1,96 @@
1
+ module CanadaPost
2
+ module Request
3
+ class Shipment < Base
4
+
5
+ def process_request
6
+ api_response = client(shipment_url, build_xml, shipment_headers)
7
+ response = parse_response(api_response)
8
+
9
+ if success?(response)
10
+ rate_reply_details = response[:price_quotes][:price_quote] || []
11
+ rate_reply_details = [rate_reply_details] if rate_reply_details.is_a? Hash
12
+ rate_reply_details.map do |rate_reply|
13
+ CanadaPost::Shipment.new(rate_reply)
14
+ end
15
+ else
16
+ error_message = if response[:messages]
17
+ response[:messages][:message][:description]
18
+ else
19
+ 'api_response.response'
20
+ end
21
+ raise ShipmentError, error_message
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def shipment_headers
28
+ api_url += "rs/{mailed by customer}/{mobo}/shipment"
29
+ end
30
+
31
+ def shipment_headers
32
+ {
33
+ 'Content-type' => 'application/vnd.cpc.shipment-v7+xml',
34
+ 'Accept' => 'application/vnd.cpc.shipment-v7+xml'
35
+ }
36
+ end
37
+
38
+ def build_xml
39
+ ns = "http://www.canadapost.ca/ws/shipment-v7"
40
+ builder = Nokogiri::XML::Builder.new do |xml|
41
+ xml.send(:"mailing-scenario", xmlns: ns) {
42
+ add_requested_shipment(xml)
43
+ }
44
+ end
45
+ builder.doc.root.to_xml
46
+ end
47
+
48
+ def add_requested_shipment(xml)
49
+ xml.send(:"customer-number", @customer_number)
50
+ add_package(xml)
51
+ add_services(xml)
52
+ add_shipper(xml)
53
+ add_recipient(xml)
54
+ end
55
+
56
+ def add_shipper(xml)
57
+ xml.send(:"origin-postal-code", @shipper[:postal_code])
58
+ end
59
+
60
+ def add_recipient(xml)
61
+ xml.destination {
62
+ add_destination(xml)
63
+ }
64
+ end
65
+
66
+ def add_destination(xml)
67
+ if @recipient[:country_code] == "CA"
68
+ xml.domestic {
69
+ xml.send(:"postal-code", @recipient[:postal_code])
70
+ }
71
+ elsif @recipient[:country_code] == "US"
72
+ xml.send(:"united-states") {
73
+ xml.send(:"zip-code", @recipient[:postal_code])
74
+ }
75
+ else
76
+ xml.international {
77
+ xml.send(:"country-code", @recipient[:country_code])
78
+ }
79
+ end
80
+ end
81
+
82
+ def add_services(xml)
83
+ if @service_type
84
+ xml.services {
85
+ xml.send(:"service-code", @service_type)
86
+ }
87
+ end
88
+ end
89
+
90
+ def success?(response)
91
+ response[:price_quotes]
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,232 @@
1
+ require 'canada_post/request/manifest'
2
+ module CanadaPost
3
+ module Request
4
+ class Shipping < Base
5
+
6
+ attr_accessor :sender, :destination, :package, :notification, :preferences, :settlement_info, :group_id, :mailing_date, :contract_id
7
+
8
+ def initialize(credentials, options={})
9
+ @credentials = credentials
10
+ if options.present?
11
+ @sender = options[:sender]
12
+ @destination = options[:destination]
13
+ @package = options[:package]
14
+ @notification = options[:notification]
15
+ @preferences = options[:preferences]
16
+ @settlement_info = options[:settlement_info]
17
+ @group_id = options[:group_id]
18
+ @mobo = options[:mobo]
19
+ if @mobo.present? && @mobo[:customer_number].present?
20
+ @mobo_customer = @mobo[:customer_number]
21
+ @shipping_auth = {username: @mobo[:username], password: @mobo[:password]}
22
+ else
23
+ @mobo_customer = @credentials.customer_number
24
+ @shipping_auth = {username: credentials.username, password: credentials.password}
25
+ end
26
+ @customer_number = @credentials.customer_number
27
+ @mailing_date = options[:mailing_date]
28
+ @contract_id = options[:contract_id]
29
+ @service_code = options[:service_code]
30
+ end
31
+ super(credentials)
32
+ end
33
+
34
+ def process_request
35
+ shipment_response = Hash.new
36
+ api_response = self.class.post(
37
+ shipping_url,
38
+ body: build_xml,
39
+ headers: shipping_header,
40
+ basic_auth: @shipping_auth
41
+ )
42
+ shipping_response = process_response(api_response)
43
+ shipment_response[:create_shipping] = shipping_response
44
+ unless shipping_response[:errors].present?
45
+ manifest_params = {
46
+ destination: @destination,
47
+ phone: @sender[:phone],
48
+ group_id: @group_id
49
+ }
50
+ manifest_response = CanadaPost::Request::Manifest.new(@credentials, manifest_params).process_request
51
+ shipment_response[:transmit_shipping] = manifest_response
52
+ end
53
+ shipment_response
54
+ end
55
+
56
+ def get_price(shipping_id, mobo = @credentials.customer_number)
57
+ price_url = api_url + "/rs/#{@credentials.customer_number}/#{mobo}/shipment/#{shipping_id}/price"
58
+ api_response = self.class.get(
59
+ price_url,
60
+ headers: shipping_header,
61
+ basic_auth: @authorization
62
+ )
63
+ process_response(api_response)
64
+ end
65
+
66
+ def details(shipping_id, mobo = @credentials.customer_number)
67
+ details_url = api_url + "/rs/#{@credentials.customer_number}/#{mobo}/shipment/#{shipping_id}/details"
68
+ api_response = self.class.get(
69
+ details_url,
70
+ headers: shipping_header,
71
+ basic_auth: @authorization
72
+ )
73
+ process_response(api_response)
74
+ end
75
+
76
+ def get_label(label_url)
77
+ self.class.get(
78
+ label_url,
79
+ headers: {
80
+ 'Content-type' => 'application/pdf',
81
+ 'Accept' => 'application/pdf'
82
+ },
83
+ basic_auth: @authorization
84
+ )
85
+ end
86
+
87
+ def void_shipping(shipping_id, mobo = @credentials.customer_number)
88
+ void_url = api_url + "/rs/#{@credentials.customer_number}/#{mobo}/shipment/#{shipping_id}"
89
+ api_response = self.class.delete(
90
+ void_url,
91
+ headers: shipping_header,
92
+ basic_auth: @authorization
93
+ )
94
+ puts api_response
95
+ process_response(api_response)
96
+ end
97
+
98
+ private
99
+
100
+ def api_url
101
+ @credentials.mode == "production" ? PRODUCTION_URL : TEST_URL
102
+ end
103
+
104
+ def shipping_url
105
+ base_url = api_url
106
+ if @mobo.present? && @mobo[:customer_number].present?
107
+ base_url += "/rs/#{@mobo_customer}-#{@customer_number}/#{@mobo_customer}/shipment"
108
+ else
109
+ base_url += "/rs/#{@customer_number}/#{@customer_number}/shipment"
110
+ end
111
+ base_url
112
+ end
113
+
114
+ def shipping_header
115
+ header = {
116
+ 'Content-type' => 'application/vnd.cpc.shipment-v7+xml',
117
+ 'Accept' => 'application/vnd.cpc.shipment-v7+xml'
118
+ }
119
+ if @mobo.present? && @mobo[:customer_number].present?
120
+ header['Platform-id'] = @customer_number
121
+ end
122
+ header
123
+ end
124
+
125
+ def build_xml
126
+ ns = "http://www.canadapost.ca/ws/shipment-v7"
127
+ builder = Nokogiri::XML::Builder.new do |xml|
128
+ xml.send(:"shipment", xmlns: ns) {
129
+ add_shipment_params(xml)
130
+ }
131
+ end
132
+ builder.doc.root.to_xml
133
+ end
134
+
135
+ def add_shipment_params(xml)
136
+ if @group_id.present?
137
+ xml.send(:'group-id', @group_id)
138
+ end
139
+ if @mailing_date.present?
140
+ xml.send(:'expected-mailing-date', @mailing_date)
141
+ end
142
+ sender_zip = @sender[:address_details][:postal_code].present? ? @sender[:address_details][:postal_code].gsub(' ', '') : ''
143
+ rsp = @sender[:shipping_point].present? ? @sender[:shipping_point].gsub(' ', '') : sender_zip
144
+ xml.send(:'requested-shipping-point', rsp)
145
+ xml.send(:'delivery-spec') {
146
+ add_delivery_spec(xml)
147
+ }
148
+ end
149
+
150
+ def add_delivery_spec(xml)
151
+ xml.send(:'service-code', @service_code) if @service_code.present?
152
+ xml.send(:'sender') {
153
+ add_sender(xml)
154
+ }
155
+
156
+ xml.send(:'destination') {
157
+ add_destination(xml)
158
+ }
159
+
160
+ add_package(xml)
161
+ xml.send(:'print-preferences') {
162
+ xml.send(:'output-format', '8.5x11')
163
+ }
164
+
165
+ xml.notification {
166
+ xml.send(:'email', @notification[:email])
167
+ xml.send(:'on-shipment', @notification[:on_shipment])
168
+ xml.send(:'on-exception', @notification[:on_exception])
169
+ xml.send(:'on-delivery', @notification[:on_delivery])
170
+ }
171
+
172
+ xml.preferences {
173
+ xml.send(:'show-packing-instructions', @preferences[:show_packing_instructions])
174
+ xml.send(:'show-postage-rate', @preferences[:show_postage_rate])
175
+ xml.send(:'show-insured-value', @preferences[:show_insured_value])
176
+ }
177
+
178
+ xml.send(:'settlement-info') {
179
+ contract_id = @credentials.mode == "production" ? @contract_id : TEST_CONTRACT_ID
180
+ xml.send(:'contract-id', contract_id)
181
+ if @mobo.present? && @mobo[:customer_number].present?
182
+ xml.send(:'paid-by-customer', @mobo_customer)
183
+ end
184
+ xml.send(:'intended-method-of-payment', 'Account')
185
+ }
186
+ end
187
+
188
+ def add_sender(xml)
189
+ xml.send(:'name', @sender[:name])
190
+ xml.send(:'company', @sender[:company])
191
+ xml.send(:'contact-phone', @sender[:phone])
192
+ xml.send(:'address-details') {
193
+ add_address(xml, @sender[:address_details])
194
+ }
195
+ end
196
+
197
+ def add_destination(xml)
198
+ xml.send(:'name', @destination[:name])
199
+ xml.send(:'company', @destination[:company])
200
+ xml.send(:'address-details') {
201
+ add_address(xml, @destination[:address_details])
202
+ }
203
+ end
204
+
205
+ def add_address(xml, params)
206
+ xml.send(:'address-line-1', params[:address])
207
+ xml.send(:'city', params[:city])
208
+ xml.send(:'prov-state', params[:state])
209
+ xml.send(:'country-code', params[:country])
210
+ if params[:postal_code].present?
211
+ xml.send(:'postal-zip-code', params[:postal_code].gsub(' ', ''))
212
+ end
213
+ end
214
+
215
+ def add_package(xml)
216
+ xml.send(:"parcel-characteristics") {
217
+ xml.unpackaged @package[:unpackaged].present? ? @package[:unpackaged] : false
218
+ xml.send(:"mailing-tube", @package[:mailing_tube].present? ? @package[:mailing_tube] : false)
219
+ xml.weight @package[:weight]
220
+ if @package[:dimensions]
221
+ xml.dimensions {
222
+ xml.height @package[:dimensions][:height].to_f.round(1)
223
+ xml.width @package[:dimensions][:width].to_f.round(1)
224
+ xml.length @package[:dimensions][:length].to_f.round(1)
225
+ }
226
+ end
227
+ }
228
+ end
229
+
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,68 @@
1
+ module CanadaPost
2
+ class Shipment
3
+
4
+ def initialize(options={})
5
+ @credentials = Credentials.new(options)
6
+ end
7
+
8
+ def create(options = {})
9
+ Request::Shipping.new(@credentials, options).process_request
10
+ end
11
+
12
+ def get_price(shipping_id)
13
+ Request::Shipping.new(@credentials).get_price(shipping_id)
14
+ end
15
+
16
+ def get_label(label_url)
17
+ Request::Shipping.new(@credentials).get_label(label_url)
18
+ end
19
+
20
+ def get_manifest(url)
21
+ Request::Manifest.new(@credentials).get_manifest(url)
22
+ end
23
+
24
+ def registration_token
25
+ Request::Registration.new(@credentials).get_token
26
+ end
27
+
28
+ def get_merchant_info(token)
29
+ Request::Registration.new(@credentials).merchant_info(token)
30
+ end
31
+
32
+ def get_artifact(url)
33
+ manifest = Request::Manifest.new(@credentials).get_manifest(url)
34
+ if manifest[:errors].present?
35
+ return {
36
+ status: false,
37
+ error: manifest[:errors]
38
+ }
39
+ else
40
+ artifact_link = get_artifact_link(manifest[:manifest])
41
+ artifact = Request::Manifest.new(@credentials).get_artifact(artifact_link)
42
+ return {
43
+ status: true,
44
+ artifact: artifact
45
+ }
46
+ end
47
+ end
48
+
49
+ def get_artifact_link(manifest)
50
+ links = manifest[:links]
51
+ if links.present?
52
+ links[:link].each do |link|
53
+ if link[:rel] == 'artifact'
54
+ return link[:href]
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def details(shipping_id)
61
+ Request::Shipping.new(@credentials).details(shipping_id)
62
+ end
63
+
64
+ def rate(options={})
65
+ Request::Rate.new(@credentials, options).process_request
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module CanadaPost
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ development:
2
+ :username: 'xxx'
3
+ :password: 'xxx'
4
+ :customer_number: 'xxx'
5
+ :mode: 'development'
6
+
7
+ production:
8
+ :username: 'xxx'
9
+ :password: 'xxx'
10
+ :customer_number: 'xxx'
11
+ :mode: 'production'
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'canada_post'
3
+ require 'canada_post/shipment'
4
+ require 'canada_post/client'
5
+
6
+ describe CanadaPost::Request::Manifest do
7
+ context 'missing required parameters' do
8
+ it 'does raise Rate exception' do
9
+ expect { CanadaPost::Client.new }.to raise_error(CanadaPost::RateError)
10
+ end
11
+ end
12
+
13
+ context 'required parameters present' do
14
+ it 'does create a valid instance' do
15
+ expect(CanadaPost::Client.new(canada_post_credentials)).to be_an_instance_of(CanadaPost::Client)
16
+ end
17
+ end
18
+
19
+ describe 'Shipment shipping service' do
20
+ let(:canada_post_service) { CanadaPost::Client.new(canada_post_credentials) }
21
+ let(:destination) { {name: 'nazrul recp', company: 'your company', address_details: {address: 'test dest address', city: 'Ottawa', state: 'ON', country: 'CA', postal_code: 'K1P5Z9'}} }
22
+ let(:group_id) { {value: '5241556'} }
23
+ let(:phone) { {value: '34343435'} }
24
+
25
+ context 'shipping manifest', :vcr do
26
+ let(:manifest) {
27
+ canada_post_service.manifest(
28
+ destination: destination,
29
+ phone: phone[:value],
30
+ group_id: group_id[:value]
31
+ )
32
+ }
33
+
34
+ it 'Should return empty result' do
35
+ expect(manifest[:errors]).to eq 'All groups in the transmit request were empty or all shipments were excluded; there was nothing to transmit'
36
+ end
37
+ end
38
+ end
39
+
40
+ end