simple_shipping 0.4.6

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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.metrics +6 -0
  4. data/.rspec +4 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.simplecov +43 -0
  8. data/Gemfile +26 -0
  9. data/Gemfile.lock +201 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.markdown +207 -0
  12. data/Rakefile +68 -0
  13. data/VERSION +1 -0
  14. data/coverage/.resultset.json +1579 -0
  15. data/lib/colorized_text.rb +34 -0
  16. data/lib/simple_shipping.rb +27 -0
  17. data/lib/simple_shipping/abstract.rb +11 -0
  18. data/lib/simple_shipping/abstract/builder.rb +47 -0
  19. data/lib/simple_shipping/abstract/client.rb +111 -0
  20. data/lib/simple_shipping/abstract/model.rb +40 -0
  21. data/lib/simple_shipping/abstract/request.rb +27 -0
  22. data/lib/simple_shipping/abstract/response.rb +26 -0
  23. data/lib/simple_shipping/address.rb +22 -0
  24. data/lib/simple_shipping/contact.rb +24 -0
  25. data/lib/simple_shipping/demo.rb +9 -0
  26. data/lib/simple_shipping/demo/base.rb +71 -0
  27. data/lib/simple_shipping/demo/fedex.rb +46 -0
  28. data/lib/simple_shipping/demo/ups.rb +68 -0
  29. data/lib/simple_shipping/exceptions.rb +40 -0
  30. data/lib/simple_shipping/fedex.rb +14 -0
  31. data/lib/simple_shipping/fedex/client.rb +41 -0
  32. data/lib/simple_shipping/fedex/package_builder.rb +24 -0
  33. data/lib/simple_shipping/fedex/party_builder.rb +50 -0
  34. data/lib/simple_shipping/fedex/request.rb +54 -0
  35. data/lib/simple_shipping/fedex/response.rb +5 -0
  36. data/lib/simple_shipping/fedex/shipment_builder.rb +123 -0
  37. data/lib/simple_shipping/fedex/shipment_request.rb +14 -0
  38. data/lib/simple_shipping/fedex/shipment_response.rb +12 -0
  39. data/lib/simple_shipping/package.rb +43 -0
  40. data/lib/simple_shipping/party.rb +21 -0
  41. data/lib/simple_shipping/shipment.rb +42 -0
  42. data/lib/simple_shipping/ups.rb +24 -0
  43. data/lib/simple_shipping/ups/client.rb +46 -0
  44. data/lib/simple_shipping/ups/package_builder.rb +101 -0
  45. data/lib/simple_shipping/ups/party_builder.rb +38 -0
  46. data/lib/simple_shipping/ups/request.rb +27 -0
  47. data/lib/simple_shipping/ups/response.rb +63 -0
  48. data/lib/simple_shipping/ups/ship_accept_request.rb +21 -0
  49. data/lib/simple_shipping/ups/ship_accept_response.rb +6 -0
  50. data/lib/simple_shipping/ups/ship_client.rb +70 -0
  51. data/lib/simple_shipping/ups/ship_confirm_request.rb +22 -0
  52. data/lib/simple_shipping/ups/ship_confirm_response.rb +6 -0
  53. data/lib/simple_shipping/ups/shipment_builder.rb +66 -0
  54. data/lib/simple_shipping/ups/shipment_request.rb +22 -0
  55. data/lib/simple_shipping/ups/shipment_response.rb +6 -0
  56. data/lib/simple_shipping/ups/void_client.rb +50 -0
  57. data/lib/simple_shipping/ups/void_request.rb +42 -0
  58. data/lib/simple_shipping/ups/void_response.rb +6 -0
  59. data/lib/tasks/demo.rake +58 -0
  60. data/script/ups_certification.rb +140 -0
  61. data/simple_shipping.gemspec +168 -0
  62. data/spec/fixtures/fedex_shipment_request.soap.xml.erb +85 -0
  63. data/spec/fixtures/fedex_shipment_response.soap.xml.erb +182 -0
  64. data/spec/fixtures/ups_shipment_request.soap.xml.erb +88 -0
  65. data/spec/fixtures/ups_shipment_response.soap.xml.erb +58 -0
  66. data/spec/fixtures/ups_shipment_response_with_faked_label_data.soap.xml.erb +54 -0
  67. data/spec/fixtures/ups_void_request.soap.xml.erb +29 -0
  68. data/spec/fixtures/ups_void_response.soap.xml.erb +21 -0
  69. data/spec/lib/simple_shipping/address_spec.rb +19 -0
  70. data/spec/lib/simple_shipping/contact_spec.rb +28 -0
  71. data/spec/lib/simple_shipping/exceptions_spec.rb +58 -0
  72. data/spec/lib/simple_shipping/fedex/package_builder_spec.rb +5 -0
  73. data/spec/lib/simple_shipping/fedex/party_builder_spec.rb +5 -0
  74. data/spec/lib/simple_shipping/fedex/response/shipment_reponse_spec.rb +5 -0
  75. data/spec/lib/simple_shipping/fedex/response_spec.rb +5 -0
  76. data/spec/lib/simple_shipping/fedex/shipment_builder_spec.rb +23 -0
  77. data/spec/lib/simple_shipping/package_spec.rb +32 -0
  78. data/spec/lib/simple_shipping/party_spec.rb +18 -0
  79. data/spec/lib/simple_shipping/shipment_spec.rb +35 -0
  80. data/spec/lib/simple_shipping/ups/package_builder_spec.rb +26 -0
  81. data/spec/lib/simple_shipping/ups/party_builder_spec.rb +47 -0
  82. data/spec/lib/simple_shipping/ups/response/shipment_response_spec.rb +5 -0
  83. data/spec/lib/simple_shipping/ups/response_spec.rb +33 -0
  84. data/spec/lib/simple_shipping/ups/shipment_builder_spec.rb +19 -0
  85. data/spec/requests/fedex_spec.rb +47 -0
  86. data/spec/requests/ups_spec.rb +75 -0
  87. data/spec/spec_helper.rb +47 -0
  88. data/spec/support/custom_matchers/basic_matcher.rb +13 -0
  89. data/spec/support/custom_matchers/have_attribute_matcher.rb +22 -0
  90. data/spec/support/custom_matchers/have_default_value_matcher.rb +26 -0
  91. data/spec/support/custom_matchers/have_errors_on_matcher.rb +23 -0
  92. data/spec/support/custom_matchers/validate_inclusion_of_matcher.rb +37 -0
  93. data/spec/support/custom_matchers/validate_presence_of_matcher.rb +24 -0
  94. data/spec/support/custom_matchers/validate_submodel_matcher.rb +44 -0
  95. data/spec/support/shared_behaviours/builders_behaviour.rb +9 -0
  96. data/spec/support/shared_behaviours/responses_behaviour.rb +10 -0
  97. data/tmp/metric_fu/_data/20131210.yml +9964 -0
  98. data/wsdl/fedex/ship_service_v10.wsdl +5566 -0
  99. data/wsdl/ups/Ship.wsdl +120 -0
  100. data/wsdl/ups/Void.wsdl +58 -0
  101. metadata +308 -0
@@ -0,0 +1,21 @@
1
+ module SimpleShipping::Ups
2
+ # Shipping accept request.
3
+ class ShipAcceptRequest < Request
4
+ def initialize(credentials, shipment_digest, options = {})
5
+ @credentials = credentials
6
+ @shipment_digest = shipment_digest
7
+ @options = options
8
+ @type = :prcoess_ship_accept
9
+ end
10
+
11
+ # :nodoc:
12
+ def body
13
+ { 'common:Request' => {
14
+ 'common:RequestOption' => REQUEST_OPTION
15
+ },
16
+ 'ShipmentDigest' => @shipment_digest,
17
+ :order! => ['common:Request', 'ShipmentDigest']
18
+ }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ # A wrapper for UPS response
2
+ module SimpleShipping::Ups
3
+ # Response to {ShipAcceptRequest}.
4
+ class ShipAcceptResponse < Response
5
+ end
6
+ end
@@ -0,0 +1,70 @@
1
+ module SimpleShipping::Ups
2
+ # Required credentials:
3
+ # * _username_
4
+ # * _password_
5
+ # * _access_license_number_
6
+ #
7
+ # = Usage
8
+ # client = SimpleShipping::Ups::ShipClient.new(:username => "USER NAME",
9
+ # :password => "PASSWORD",
10
+ # :access_license_number => "LICENSE NUMBER")
11
+ # client.request(shipper, recipient, package) # => #<SimpleShipping::Ups::Response ...>
12
+ class ShipClient < Client
13
+ set_required_credentials :username, :password, :access_license_number
14
+
15
+ set_wsdl_document File.join(SimpleShipping::WSDL_DIR, "ups/Ship.wsdl")
16
+ set_production_address "https://onlinetools.ups.com/webservices/Ship"
17
+ set_testing_address "https://wwwcie.ups.com/webservices/Ship"
18
+
19
+ # @param shipper [::SimpleShipping::Party]
20
+ # @param recipient [::SimpleShipping::Party]
21
+ # @param package [::SimpleShipping::Package]
22
+ # @param options [Hash] ({})
23
+ #
24
+ # @return [::SimpleShipping::ShipmentResponse]
25
+ #
26
+ # @raise [::SimpleShipping::RequestError] in case of SOAP errors
27
+ def shipment_request(shipper, recipient, package, options = {})
28
+ shipment = create_shipment(shipper, recipient, package, options)
29
+ request = ShipmentRequest.new(@credentials, shipment, options)
30
+ execute(request)
31
+ end
32
+
33
+ # Send shipment confirmation request.
34
+ def ship_confirm_request(shipper, recipient, package, options = {})
35
+ shipment = create_shipment(shipper, recipient, package, options)
36
+ request = ShipConfirmRequest.new(@credentials, shipment, options)
37
+ execute(request)
38
+ end
39
+
40
+
41
+ # Perform shipping accept request.
42
+ def ship_accept_request(shipment_digest, options = {})
43
+ request = ShipAcceptRequest.new(@credentials, shipment_digest, options)
44
+ execute(request)
45
+ end
46
+
47
+ # @param [Hash] options Savon client options
48
+ def client_options(options = {})
49
+ super.deep_merge(
50
+ :namespaces => {
51
+ # Savon parses have WSDL instead of XMLSchema which is not accepted by UPS
52
+ # So we have to again set namespace explicitly :( -- aignatev 20130204
53
+ 'xmlns:ship' => "http://www.ups.com/XMLSchema/XOLTWS/Ship/v1.0"
54
+ }
55
+ )
56
+ end
57
+ protected :client_options
58
+
59
+
60
+ # Perform ShipmentRequest to UPS service.
61
+ def execute(request)
62
+ savon_response = @client.call(request.type, :message => request.body)
63
+ log_response(savon_response)
64
+ request.response(savon_response)
65
+ rescue Savon::SOAPFault => e
66
+ raise SimpleShipping::RequestError.new(e)
67
+ end
68
+ private :execute
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ module SimpleShipping::Ups
2
+ # Request to verify a shipment was delivered.
3
+ class ShipConfirmRequest < Request
4
+ def initialize(credentials, shipment, options = {})
5
+ @credentials = credentials
6
+ @shipment = shipment
7
+ @options = options
8
+ @type = :process_ship_confirm
9
+ end
10
+
11
+ # Builds a request from {Shipment shipment} object.
12
+ def body
13
+ { 'common:Request' => {
14
+ 'common:RequestOption' => REQUEST_OPTION
15
+ },
16
+ 'Shipment' => ShipmentBuilder.build(@shipment, @options),
17
+ 'LabelSpecification' => label_specification,
18
+ :order! => ['common:Request', 'Shipment', 'LabelSpecification']
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ # A wrapper for a UPS response.
2
+ module SimpleShipping::Ups
3
+ # Response to {ShipConfirmResponse}.
4
+ class ShipConfirmResponse < Response
5
+ end
6
+ end
@@ -0,0 +1,66 @@
1
+ module SimpleShipping::Ups
2
+ # Builds shipment element for UPS SOAP service.
3
+ class ShipmentBuilder < SimpleShipping::Abstract::Builder
4
+ # The type of payment for this shipment.
5
+ PAYMENT_TYPE = '01' # 01 - Transportation, 02 - Duties and Taxes
6
+
7
+ # Service codes in UPS terminology.
8
+ SERVICE_TYPES = {:next_day_air => '01',
9
+ :second_day_air => '02',
10
+ :ground => '03',
11
+ :express => '07',
12
+ :expedited => '08',
13
+ :standard => '11',
14
+ :three_day_select => '12',
15
+ :next_day_air_saver => '13',
16
+ :next_day_air_early_am => '14',
17
+ :express_plus => '54',
18
+ :second_day_air_am => '59',
19
+ :saver => '65',
20
+ :today_standard => '82',
21
+ :today_dedicated_courier => '83',
22
+ :today_intercity => '84',
23
+ :today_express => '85',
24
+ :today_express_saver => '86'}
25
+
26
+ set_default_opts :service_type => :second_day_air
27
+
28
+ # Return a hash for Savon representing a shipment model.
29
+ def build
30
+ { 'Shipper' => PartyBuilder.build(@model.shipper, :shipper => true),
31
+ 'ShipTo' => PartyBuilder.build(@model.recipient),
32
+ 'PaymentInformation' => build_payment_info,
33
+ 'Service' => build_service,
34
+ 'Package' => PackageBuilder.build(@model.package),
35
+ :order! => ['Shipper', 'ShipTo', 'PaymentInformation', 'Service', 'Package'] }
36
+ end
37
+
38
+ # Return the PaymentInformation hash.
39
+ def build_payment_info
40
+ {'ShipmentCharge' => build_shipment_charge }
41
+ end
42
+
43
+ # Return the shipment charge for the PaymentInformation hash.
44
+ def build_shipment_charge
45
+ result = {'Type' => PAYMENT_TYPE, :order! => ['Type']}
46
+ if @model.payor == :shipper
47
+ result['BillShipper'] = {'AccountNumber' => @model.shipper.account_number}
48
+ result[:order!] << 'BillShipper'
49
+ else
50
+ result['BillReceiver'] = {'AccountNumber' => @model.recipient.account_number}
51
+ result[:order!] << 'BillReceiver'
52
+ end
53
+ result
54
+ end
55
+
56
+ # Return the hash representing the Service.
57
+ def build_service
58
+ {'Code' => SERVICE_TYPES[@opts[:service_type]]}
59
+ end
60
+
61
+ # Validate that the service type is included.
62
+ def validate
63
+ validate_inclusion_of(:service_type, SERVICE_TYPES)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ module SimpleShipping::Ups
2
+ # Shipment request model.
3
+ class ShipmentRequest < Request
4
+ def initialize(credentials, shipment, options = {})
5
+ @credentials = credentials
6
+ @shipment = shipment
7
+ @options = options
8
+ @type = :process_shipment
9
+ end
10
+
11
+ # Builds a request from {Shipment shipment} object.
12
+ def body
13
+ { 'common:Request' => {
14
+ 'common:RequestOption' => REQUEST_OPTION
15
+ },
16
+ 'Shipment' => ShipmentBuilder.build(@shipment, @options),
17
+ 'LabelSpecification' => label_specification,
18
+ :order! => ['common:Request', 'Shipment', 'LabelSpecification']
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ # A wrapper for a UPS ShipmentResponse.
2
+ module SimpleShipping::Ups
3
+ # Response to ShipmentRequest.
4
+ class ShipmentResponse < Response
5
+ end
6
+ end
@@ -0,0 +1,50 @@
1
+ module SimpleShipping::Ups
2
+ # Required credentials:
3
+ # * _username_
4
+ # * _password_
5
+ # * _access_license_number_
6
+ #
7
+ # = Usage
8
+ # client = SimpleShipping::Ups::VoidClient.new(:username => "USER NAME",
9
+ # :password => "PASSWORD",
10
+ # :access_license_number => "LICENSE NUMBER")
11
+ # client.request(shipper, recipient, package) # => #<SimpleShipping::Ups::Response ...>
12
+ class VoidClient < Client
13
+ set_required_credentials :username, :password, :access_license_number
14
+
15
+ set_wsdl_document File.join(SimpleShipping::WSDL_DIR, "ups/Void.wsdl")
16
+ set_production_address "https://onlinetools.ups.com/webservices/Void"
17
+ set_testing_address "https://wwwcie.ups.com/webservices/Void"
18
+
19
+ # Build VoidRequest and perform the request.
20
+ #
21
+ # @param shipment_identification_number [String]
22
+ # @param options [Hash]
23
+ def void_request(shipment_identification_number, options = {})
24
+ request = VoidRequest.new(@credentials, shipment_identification_number, options)
25
+ execute(request)
26
+ end
27
+
28
+ # @param [Hash] options Savon client options
29
+ def client_options(options = {})
30
+ super.deep_merge(
31
+ :namespaces => {
32
+ # Savon parses have WSDL instead of XMLSchema which is not accepted by UPS
33
+ # So we have to again set namespace explicitly :( -- aignatev 20130204
34
+ 'xmlns:void' => "http://www.ups.com/XMLSchema/XOLTWS/Void/v1.1"
35
+ }
36
+ )
37
+ end
38
+ protected :client_options
39
+
40
+ # Perform ShipmentRequest to UPS service.
41
+ def execute(request)
42
+ savon_response = @client.call(request.type, :message => request.body)
43
+ log_response(savon_response)
44
+ request.response(savon_response)
45
+ rescue Savon::SOAPFault => err
46
+ raise SimpleShipping::RequestError.new(err)
47
+ end
48
+ private :execute
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ module SimpleShipping::Ups
2
+ # UPS request to void shipment.
3
+ class VoidRequest < Request
4
+
5
+ # @param credentials [Hash]
6
+ # @param shipment_identification_number [String]
7
+ # @param options [Hash]
8
+ def initialize(credentials, shipment_identification_number, options = {})
9
+ @credentials = credentials
10
+ @shipment_identification_number = shipment_identification_number
11
+ @tracking_number = options[:tracking_number]
12
+ @options = options
13
+ @type = :process_void
14
+ end
15
+
16
+ # Build a request from a {Shipment shipment} object.
17
+ def body
18
+ {
19
+ 'common:Request' => {
20
+ 'common:RequestOption' => REQUEST_OPTION
21
+ },
22
+ 'VoidShipment' => void_shipment,
23
+ :order! => ['common:Request', 'VoidShipment']
24
+ }
25
+ end
26
+
27
+ # Data for VoidShipment.
28
+ #
29
+ # @return [Hash]
30
+ def void_shipment
31
+ data = { 'ShipmentIdentificationNumber' => @shipment_identification_number }
32
+
33
+ if @tracking_number
34
+ data['TrackingNumber'] = @tracking_number
35
+ data[:order!] = ['ShipmentIdentificationNumber', 'TrackingNumber']
36
+ end
37
+
38
+ data
39
+ end
40
+ private :void_shipment
41
+ end
42
+ end
@@ -0,0 +1,6 @@
1
+ # A wrapper for a UPS response.
2
+ module SimpleShipping::Ups
3
+ # Response to VoidRequest.
4
+ class VoidResponse < Response
5
+ end
6
+ end
@@ -0,0 +1,58 @@
1
+ namespace :demo do
2
+ task :environment do
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.require
6
+
7
+ $LOAD_PATH.unshift File.expand_path('../../', __FILE__)
8
+
9
+ require 'simple_shipping'
10
+ require 'RMagick'
11
+ end
12
+
13
+
14
+ namespace :fedex do
15
+ desc 'Call real FedEx API with shipment_request'
16
+ task :shipment_request, [:credentials_file, :output_filename] => :environment do |task, args|
17
+ args.with_defaults(:output_filename => File.join(Dir.tmpdir, 'fedex_shipment_request_output.png'))
18
+
19
+ credentials = YAML.load_file(args[:credentials_file])['fedex'].symbolize_keys!
20
+
21
+ demo = SimpleShipping::Demo::Fedex.new(credentials)
22
+ resp = demo.shipment_request
23
+ img = Magick::Image.read_inline(resp.label_image_base64).first
24
+
25
+ img.write(args[:output_filename])
26
+ puts "Label received. #{args[:output_filename]} written"
27
+ end
28
+ end
29
+
30
+ namespace :ups do
31
+ desc 'Call real UPS API with shipment_request'
32
+ task :shipment_request, [:credentials_file, :output_filename] => :environment do |task, args|
33
+ args.with_defaults(:output_filename => File.join(Dir.tmpdir, 'ups_shipment_request_output.png'))
34
+
35
+ credentials = YAML.load_file(args[:credentials_file])['ups'].symbolize_keys!
36
+
37
+ demo = SimpleShipping::Demo::Ups.new(credentials)
38
+
39
+ resp = demo.shipment_request
40
+ img = Magick::Image.read_inline(resp.label_image_base64).first
41
+
42
+ img.write(args[:output_filename])
43
+ puts "Label received. #{args[:output_filename]} written"
44
+ end
45
+
46
+ desc 'Call real UPS API with void_request'
47
+ task :void_request, [:credentials_file] => :environment do |task, args|
48
+ credentials = YAML.load_file(args[:credentials_file])['ups'].symbolize_keys!
49
+ demo = SimpleShipping::Demo::Ups.new(credentials)
50
+
51
+ begin
52
+ resp = demo.void_request
53
+ rescue SimpleShipping::RequestError => exc
54
+ raise exc unless exc.message =~ /No shipment found within the allowed void period/
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'rubygems'
6
+ require 'simple_shipping'
7
+ require 'simple_shipping/ups'
8
+ require 'RMagick'
9
+ require 'fileutils'
10
+ require 'forgery'
11
+ require 'yaml'
12
+
13
+ package_path_base = File.expand_path('../ups_certification_package/', __FILE__)
14
+ FileUtils.rm_rf(package_path_base) if File.directory?(package_path_base)
15
+
16
+ # YAML file with credentials
17
+ unless credentials_file = ARGV.pop
18
+ abort "Usage:\n #{$0} <PATH_TO_CREDENTIALS.yml>"
19
+ end
20
+
21
+ CREDENTIALS = YAML.load_file(credentials_file )['ups'].symbolize_keys!
22
+ ACCOUNT_NUMBER = CREDENTIALS.delete(:account_number)
23
+
24
+ 5.times do |iteration|
25
+ package_path = File.join(package_path_base, iteration.to_s)
26
+ FileUtils.mkdir_p(package_path)
27
+
28
+ shipper_address = SimpleShipping::Address.new(
29
+ :country_code => 'US',
30
+ :state_code => 'IL',
31
+ :postal_code => '60201',
32
+ :city => Forgery::Address.city,
33
+ :street_line => Forgery::Address.street_address
34
+ )
35
+ shipper_contact = SimpleShipping::Contact.new(
36
+ :person_name => Forgery::Name.full_name,
37
+ :phone_number => Forgery::Address.phone
38
+ )
39
+ shipper = SimpleShipping::Party.new(
40
+ :address => shipper_address,
41
+ :contact => shipper_contact,
42
+ :account_number => ACCOUNT_NUMBER
43
+ )
44
+ recipient_address = SimpleShipping::Address.new(
45
+ :country_code => 'US',
46
+ :state_code => 'SC',
47
+ :postal_code => '29072',
48
+ :city => Forgery::Address.city,
49
+ :street_line => Forgery::Address.street_address
50
+ )
51
+ recipient_contact = SimpleShipping::Contact.new(
52
+ :person_name => Forgery::Name.full_name,
53
+ :phone_number => Forgery::Address.phone
54
+ )
55
+ recipient = SimpleShipping::Party.new(
56
+ :address => recipient_address,
57
+ :contact => recipient_contact
58
+ )
59
+ package = SimpleShipping::Package.new(
60
+ :weight => 0.5,
61
+ :packaging_type => :envelope,
62
+ :insured_value => iteration * 250.0,
63
+ :declared_value => iteration * 250.0
64
+ )
65
+
66
+ confirm_path = File.join(package_path, "confirm")
67
+ FileUtils.mkdir_p(confirm_path)
68
+
69
+ confirm_client = SimpleShipping::Ups::ShipClient.new(
70
+ :debug => true,
71
+ :debug_path => confirm_path,
72
+ :credentials => CREDENTIALS
73
+ )
74
+
75
+ puts "CONFIRM REQUEST #{iteration}"
76
+ confirm = confirm_client.ship_confirm_request(shipper, recipient, package)
77
+
78
+ accept_path = File.join(package_path, "accept")
79
+ FileUtils.mkdir_p(accept_path)
80
+ accept_client = SimpleShipping::Ups::ShipClient.new(
81
+ :debug => true,
82
+ :debug_path => accept_path,
83
+ :credentials => CREDENTIALS
84
+ )
85
+
86
+ puts "ACCEPT REQUEST #{iteration}"
87
+ accept = accept_client.ship_accept_request(confirm.digest)
88
+
89
+ puts "SAVING LABEL HTML"
90
+ File.open(File.join(package_path, "label.html"), "w") {|f| f.write accept.label_html}
91
+
92
+ puts "SAVING LABEL GIF"
93
+ image_name = "label#{accept.tracking_number}.gif"
94
+ img = Magick::Image.read_inline(accept.label_image_base64).first
95
+ img.write(File.join(package_path, image_name))
96
+
97
+
98
+ # Apparently, the HTML version is OK:
99
+ # http://www.corecommerce.com/kb/328/ups_label_certification_requiring_39th_file
100
+ if accept.receipt_html
101
+ puts "SAVING HIGH VALUE REPORT HTML"
102
+ File.open(File.join(package_path, "high_value_report.html"), "w") {|f| f.write accept.receipt_html}
103
+ end
104
+ end
105
+
106
+ VOID_NUMBERS = [
107
+ # A successful XML response will be returned for a shipment level void request.
108
+ ['1ZISDE016691676846'],
109
+ # A successful XML response will be returned for a shipment level void request.
110
+ ['1Z2220060290602143'],
111
+ # A successful XML response will be returned for a package level void request. The request will void the package in the shipment.
112
+ ['1Z2220060294314162', '1Z2220060291994175'],
113
+ # A successful XML response will be returned for a package level void request. The request will void the package in the shipment. .
114
+ ['1Z2220060292690189', '1Z2220060292002190'],
115
+
116
+ # Multiple tracking numbers for each shipment identifier. These don't seem to
117
+ # work, but implementing them is unnecessary.
118
+
119
+ # A successful XML response will be returned for a package level void request. The request will void all the packages.
120
+ # ['1ZISDE016691609089', '1ZISDE016694068891'],
121
+ # A successful XML response will be returned for a package level void request. The request will void all the packages.
122
+ # ['1ZISDE016691609089', '1ZISDE016690889305'],
123
+ # A successful XML response will be returned with a partial void for a package level void request. The request will void package 1Z2220060293874210 but package 1Z2220060292634221 cannot be voided.
124
+ # ['1Z2220060290530202', '1Z2220060293874210'],
125
+ # A successful XML response will be returned with a partial void for a package level void request. The request will void package 1Z2220060293874210 but package 1Z2220060292634221 cannot be voided.
126
+ # ['1Z2220060290530202', '1Z2220060292634221']
127
+ ]
128
+
129
+ VOID_NUMBERS.each do |identifier, tracking_number|
130
+ package_path = File.join(package_path_base, "void/#{identifier}")
131
+ FileUtils.mkdir_p(package_path)
132
+
133
+ void_client = SimpleShipping::Ups::VoidClient.new(
134
+ :debug => true,
135
+ :debug_path => package_path,
136
+ :credentials => CREDENTIALS
137
+ )
138
+ puts "VOID REQUEST: #{identifier}"
139
+ void_client.void_request(identifier, :tracking_number => tracking_number)
140
+ end