shipppit-canada-post 0.5.0

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