workarea-valken-shipping 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 230124e4ac5db27cfd29ae6ab6a71d79342365a0510fcf3c9c5677d72588e229
4
+ data.tar.gz: 60cd8040bc385b9b7de3ccfbae148f8662ff3756ff51ae8eef7efdfaac968f71
5
+ SHA512:
6
+ metadata.gz: c2fcd56f5131127418c269eef0322ccdc0dbd4b18eb17f6da5a2c57ab0deaae60b0a53192e87d834da77ffe8adcb561e9e6c95a5b1b10dd46c52e8ff1d9c5558
7
+ data.tar.gz: 800918f479596701f9a0c2d13884a3e94c781ad4e95047780a8c8cf30d2a4e14714bc5e19d61f0d0b0d646317e9dc43b54dd15c3cf68541400dd0f276fd9887e
@@ -0,0 +1,20 @@
1
+ Copyright 2020 sushmitha02
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # Valken::Shipping
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'valken-shipping'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install valken-shipping
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Valken::Shipping'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ load 'rails/tasks/statistics.rake'
18
+
19
+ require 'bundler/gem_tasks'
20
+
21
+ require 'rake/testtask'
22
+
23
+ Rake::TestTask.new(:test) do |t|
24
+ t.libs << 'test'
25
+ t.pattern = 'test/**/*_test.rb'
26
+ t.verbose = false
27
+ end
28
+
29
+ task default: :test
@@ -0,0 +1,59 @@
1
+ module Workarea
2
+ module AddressesHelper
3
+ def country_options
4
+ return [[Country['US'].name, Country['US'].alpha2]] if is_usa_only?
5
+ Workarea.config.countries.map do |country|
6
+ [country.name, country.alpha2]
7
+ end
8
+ end
9
+
10
+ def region_options
11
+ @region_options ||= Workarea.config.countries.reduce([]) do |memo, country|
12
+ regions = country.subdivisions
13
+ .map { |id, region| [region.translations[I18n.locale.to_s] || region.name, id] }
14
+ .sort_by { |name, id| name || id }
15
+
16
+ memo << [country.name, regions]
17
+ memo
18
+ end
19
+ end
20
+
21
+ def is_usa_only?
22
+
23
+ orders = current_order rescue nil
24
+ return false if orders.blank? || orders.items.blank?
25
+
26
+ usa_only_attribute = Workarea.config.shipping_attributes[:usa_only]
27
+ product_attributes = orders.items.map(&:product_attributes)
28
+ return product_attributes.map{ |item| item[:details][:en][usa_only_attribute] }.flatten.include?("true")
29
+ end
30
+
31
+ def formatted_address(address)
32
+ pieces = {
33
+ recipient: "#{address.first_name} #{address.last_name}\n#{address.company}".strip,
34
+ street: "#{address.street} #{address.street_2}".strip,
35
+ city: address.city,
36
+ region: address.region_name,
37
+ region_short: address.region,
38
+ postalcode: address.postal_code,
39
+ country: address.country.alpha2
40
+ }
41
+
42
+ address_format = address.country.address_format || Country['US'].address_format
43
+ result = pieces.reduce(address_format) do |memo, (name, value)|
44
+ memo.gsub(/{{#{name}}}/, html_escape(value.to_s))
45
+ end
46
+
47
+ if address.phone_number.present?
48
+ formatted_phone = number_to_phone(
49
+ address.phone_number,
50
+ extension: address.phone_extension
51
+ )
52
+
53
+ result << "\n#{formatted_phone}"
54
+ end
55
+
56
+ result.gsub(/\n/, tag(:br)).html_safe
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,16 @@
1
+ module Workarea
2
+ decorate Checkout::ShippingOptions, with: :valken do
3
+ decorated do
4
+ class NoAvailableShippingOption < RuntimeError; end
5
+ end
6
+
7
+ def all_options
8
+ @all_options ||=
9
+ begin
10
+ packaging = Packaging.new(order, shipping)
11
+ shipping.find_method_options(order, shipping)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,262 @@
1
+ module Workarea
2
+ decorate Shipping, with: :valken do
3
+ decorated do
4
+ field :tracking_number, type: String
5
+ end
6
+
7
+ class_methods do
8
+ end
9
+
10
+ def order
11
+ @order
12
+ end
13
+
14
+ def shipping
15
+ @shipping
16
+ end
17
+
18
+
19
+ def default_options(packages)
20
+ return [] if address.blank? || packages.blank?
21
+ shipping_option = Workarea.config.gateways.shipping
22
+
23
+ origin = ActiveShipping::Location.new(Workarea.config.shipping_origin)
24
+ response = shipping_option.find_rates(
25
+ origin,
26
+ address.to_active_shipping,
27
+ packages
28
+ )
29
+ response.rates.sort_by(&:price).map do |rate|
30
+ ShippingOption.from_rate_estimate(rate)
31
+ end
32
+ end
33
+
34
+ def find_method_options(order, shipping)
35
+ @order ||= order
36
+ @shipping ||= shipping
37
+ carrier_data = []
38
+
39
+ packaging = Packaging.new(order, shipping)
40
+ return [] if packaging.packages.blank?
41
+
42
+ return default_options(packaging.packages) if Workarea.config.gateways.ups_carrier.class == ActiveShipping::Workarea
43
+
44
+ shipping_options_api = get_final_shipping_options(collect_carrier_data)
45
+ return [] if @error.present?
46
+
47
+ carrier_data.push(shipping_options_api) if shipping_options_api.present? && shipping_options_api.any?
48
+
49
+ if Workarea.config.gateways.ups_carrier.class != ActiveShipping::Workarea
50
+ carrier_data.push(get_ltl_shipping)
51
+ carrier_data.push(get_free_shipping) if Workarea.config.show_free_shipping
52
+ else
53
+ return []
54
+ end
55
+
56
+ carrier_data.flatten.reverse
57
+ end
58
+
59
+ def get_final_shipping_options(rates)
60
+ options = []
61
+
62
+ if is_ground
63
+ ground_rate = rates.detect{|rate| rate.service_code == "GROUND_HOME_DELIVERY" || rate.service_code == "03" }
64
+ return [] if ground_rate.blank?
65
+
66
+ description = "#{ground_rate.delivery_date.strftime('%A, %B %d, %Y')}"
67
+ days_to_deliver = (ground_rate.delivery_date - Date.today).to_i
68
+
69
+ label = Workarea.config.shipping_rates[(days_to_deliver - 1)]
70
+ return options.push(create_shipping_options(ground_rate, label, description))
71
+ end
72
+
73
+ rates.each_with_index do |rate, index|
74
+ description = "#{rate.delivery_date.strftime('%A, %B %d, %Y')}"
75
+ label = Workarea.config.shipping_rates[index]
76
+ options.push(create_shipping_options(rate, label, description))
77
+ end
78
+ options
79
+ end
80
+
81
+ # If the carrier is ups then it will print ups data...or if carrier is fedex then prinnt fedex data...
82
+ # else if it is not both then choose cheapest price.
83
+ def collect_carrier_data
84
+ return get_ups_data if is_ups
85
+ return get_fedex_data if is_fedex
86
+ return get_none_data unless is_ups && is_fedex
87
+ end
88
+
89
+ # UPS data.
90
+ def get_ups_data
91
+ @ups_options ||= get_options(Workarea.config.gateways.ups_carrier, Workarea.config.shipping_rates)
92
+ end
93
+
94
+ # FedEx data.
95
+ def get_fedex_data
96
+ @fedex_response ||= get_options(Workarea.config.gateways.fedex_carrier, Workarea.config.shipping_rates)
97
+ end
98
+
99
+ # If the product is not ups or fedex then it will choose the cheapest price among ups and fedex annd print the value.
100
+ def get_none_data
101
+ return [] if get_ups_data.blank? || get_fedex_data.blank?
102
+ final_options = []
103
+ temp_options = get_fedex_data + get_ups_data
104
+ return [] unless temp_options.any?
105
+
106
+ delivery_dates = temp_options.map(&:delivery_date).uniq.sort
107
+ delivery_dates.each_with_index do |date, index|
108
+ selected_rates = temp_options.select {|rate| rate.delivery_date == date}
109
+ final_options.push(selected_rates.sort_by(&:price).first)
110
+ end
111
+ return final_options
112
+
113
+ end
114
+
115
+ # Free shipping option.
116
+ def get_free_shipping
117
+ ShippingOption.new(
118
+ carrier: "Free Shipping",
119
+ name: "Valken Economy",
120
+ sub_name: "5 - 9 Business Days",
121
+ service_code: "Free",
122
+ price: Money.new(0.0, "USD"),
123
+ tax_code: "TAX01"
124
+ )
125
+ end
126
+
127
+ # Calculating the ltl shipping rates based on the conditions.
128
+ def get_ltl_shipping
129
+ weight_price = 0
130
+ case weight_convertion
131
+ when 0..2
132
+ weight_price = 5
133
+ when 2..15
134
+ weight_price = 15
135
+ when 15..200
136
+ weight_price = (1 * weight_convertion)
137
+ when 200..2500
138
+ weight_price = 200
139
+ else
140
+ weight_price = ((weight_convertion / 2500).ceil()) * 200
141
+ end
142
+
143
+ ShippingOption.new(
144
+ carrier: "LTL Shipping",
145
+ name: "Valken Standard",
146
+ sub_name: "3 - 5 Business Days",
147
+ service_code: "LTL01",
148
+ price: Money.new(weight_price * 100, "USD"),
149
+ tax_code: "TAX01"
150
+ )
151
+ end
152
+
153
+ # Returns the total weight.
154
+ def weight_convertion
155
+ packaging = Packaging.new(order, shipping)
156
+ return 0 if packaging.packages.blank?
157
+ full_weight = 0
158
+ packaging.packages.each do |item_package|
159
+ new_weight = item_package.weight.convert_to(:lb)
160
+ full_weight += new_weight.value
161
+ end
162
+ full_weight
163
+ end
164
+
165
+ # 1. Sending a call to carrier and get shipping rates
166
+ # 2. Based on service codes in config, filter the shipping rates
167
+ # 3. If error, return empty array
168
+ def get_options(carrier, service_code)
169
+ packaging = Packaging.new(order, shipping)
170
+ return [] if @shipping.address.blank? || packaging.packages.blank?
171
+ shipping_option = carrier || Workarea.config.gateways.shipping
172
+
173
+ origin = ActiveShipping::Location.new(Workarea.config.shipping_origin)
174
+ begin
175
+ response = shipping_option.find_rates(
176
+ origin,
177
+ @shipping.address.to_active_shipping,
178
+ packaging.packages
179
+ )
180
+ if carrier.class == ActiveShipping::Workarea
181
+ response.rates.sort_by(&:price).map do |rate|
182
+ ShippingOption.from_rate_estimate(rate)
183
+ end
184
+ else
185
+ filter_shipping_rates(response.rates, service_code)
186
+ end
187
+ rescue ActiveShipping::ResponseError => e
188
+ @error = e
189
+ return []
190
+ end
191
+ end
192
+
193
+ # Sort rates by delevry date and pick 1st three rates
194
+ # Find cheapest rate for those three rates
195
+ # Push all the cheap option for 1, 2, & 3 days into an array and return
196
+ def filter_shipping_rates(rates, service_code)
197
+ filtered_rates = []
198
+ # find and sort all delivery dates and pick 1st three
199
+ all_delivery_dates = rates.map { |rate| rate.delivery_date }
200
+ # sorting the uniq delivery dates and reversing those delivery dates.
201
+ uniq_delivery_dates = all_delivery_dates.compact.sort.uniq[0..2]
202
+
203
+ # removing overnight. Assuming the 3rd option is always overnight
204
+ uniq_delivery_dates.pop if uniq_delivery_dates.length == 3
205
+
206
+ # For each delivery dates, find cheapest rates and create shipping option and push
207
+ uniq_delivery_dates.each_with_index do |date, index|
208
+ selected_rates = rates.select {|rate| rate.delivery_date.present? && rate.delivery_date == date}
209
+ cheap_rate = selected_rates.sort_by(&:price).first
210
+ description = "#{cheap_rate.delivery_date.strftime('%A, %B %d, %Y')}"
211
+
212
+ filtered_rates.push(cheap_rate)
213
+ end
214
+ filtered_rates
215
+ end
216
+
217
+ # creating a ShippingOption
218
+ def create_shipping_options(rate, rate_label = nil, description = nil)
219
+ ShippingOption.new(
220
+ carrier: rate.carrier,
221
+ name: rate_label.keys.join || rate.service_name,
222
+ sub_name: rate_label.values.join,
223
+ service_code: rate.service_code,
224
+ description: description,
225
+ delivery_date: rate.delivery_date,
226
+ price: Money.new(rate.price, rate.currency),
227
+ tax_code: Shipping::Service.find_tax_code(
228
+ rate.carrier,
229
+ rate.service_name
230
+ )
231
+ )
232
+ end
233
+
234
+ # Selecting the shipping carrier based on order items
235
+ #
236
+ # If the product is type hazmat then it returns ups...or if product is type gun then it returns fedex
237
+ # else if product is not both type then it returns none
238
+ def is_fedex
239
+ carrier_type_attribute = Workarea.config.shipping_attributes[:carrier_type]
240
+ product_carrier_type = product_details.map{ |item| item[:en][carrier_type_attribute] }.flatten
241
+ product_carrier_type.include?("FEDEX")
242
+ end
243
+
244
+ def is_ups
245
+ carrier_type_attribute = Workarea.config.shipping_attributes[:carrier_type]
246
+ product_carrier_type = product_details.map{ |item| item[:en][carrier_type_attribute] }.flatten
247
+ product_carrier_type.include?("UPS")
248
+ end
249
+
250
+ def is_ground
251
+ ground_ship_attribute = Workarea.config.shipping_attributes[:ground_shipping_only]
252
+ product_carrier_type = product_details.map{ |item| item[:en][ground_ship_attribute] }.flatten
253
+ product_carrier_type.include?("true")
254
+ end
255
+
256
+ def product_details
257
+ # product_attributes = @order.items.map(&:product_attributes)
258
+
259
+ @product_details ||= Catalog::Product.in(id: @order.items.to_a.map(&:product_id)).pluck(:details)
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,10 @@
1
+ module Workarea
2
+ decorate ShippingOption, with: :valken do
3
+ decorated do
4
+ attr_reader :description, :sub_name, :delivery_date
5
+ end
6
+
7
+ class_methods do
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module Workarea
2
+ decorate Packaging, with: :valken do
3
+ decorated do
4
+ end
5
+
6
+ def find_shipping_sku(sku)
7
+ shipping_skus.detect { |s| s.id == sku } || Shipping::Sku.new(id: sku, weight: find_sku_weight(sku))
8
+ end
9
+
10
+ def find_sku_weight(sku)
11
+ product_by_sku = Catalog::Product.find_by_sku(sku).variants
12
+ sku_data = product_by_sku.detect {|variant| variant.sku == sku }
13
+ sku_weight = is_pounds(sku_data) ? convert_to_lb(sku_data.weight || 0) : (sku_data.weight || 0)
14
+ sku_weight
15
+ end
16
+
17
+ def convert_to_lb(weight)
18
+ unit = Measured::Weight.new(weight, :lb)
19
+ ounce_unit = unit.convert_to(:oz)
20
+ ounce_unit.value
21
+ end
22
+
23
+ def is_pounds(sku_data)
24
+ sku_data.weight_unit == "lb"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ Workarea::Configuration.define_fields do
2
+ fieldset 'Shipping', namespaced: false do
3
+ field 'Shipping Attributes',
4
+ type: :hash,
5
+ default: {
6
+ 'usa_only' => 'usa only',
7
+ 'carrier_type' => 'Type',
8
+ 'ground_shipping_only' => 'ground shipping only'
9
+ },
10
+ description: 'Mapping of product details keys with shipping logic. Note: This maps only the keys not the values.'
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ Workarea.configure do |config|
2
+ ActiveShipping::Carriers.register :UPS, 'active_shipping/carriers/ups'
3
+
4
+ config.weight_table = {"2": 5, "15": 15, "200": 1, "2500": 200}
5
+
6
+ config.shipping_rates = [
7
+ {"Valken Overnight" => "Overnight"},
8
+ {"Valken Express 2-Day" => "2 Business Days"},
9
+ {"Valken Express 3-Day" => "3 Business Days"}
10
+ ]
11
+ config.ups_options = {"12"=> "Valken Express 3-Day", "01"=> "Valken Overnight", "02"=> "Valken Express 2-Day"}
12
+ config.fedex_options = {"STANDARD_OVERNIGHT"=> "Valken Overnight", "FEDEX_2_DAY"=> "Valken Express 2-Day", "GROUND_HOME_DELIVERY"=> "Valken Express 3-Day"}
13
+ end
14
+ Valken::Shipping.auto_initialize_gateway
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :valken_shipping do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,42 @@
1
+ require 'workarea'
2
+ require 'workarea/storefront'
3
+ require 'workarea/admin'
4
+ require "valken/shipping/engine"
5
+
6
+ module Valken
7
+ module Shipping
8
+
9
+ def self.ups_credentials
10
+ return {} unless Rails.application.secrets.ups_carrier.present?
11
+ Rails.application.secrets.ups_carrier.symbolize_keys
12
+ end
13
+
14
+ def self.fedex_credentials
15
+ return {} unless Rails.application.secrets.fedex_carrier.present?
16
+ Rails.application.secrets.fedex_carrier.symbolize_keys
17
+ end
18
+
19
+ def self.ups_gateway=(gateway)
20
+ Workarea.config.gateways.ups_carrier = gateway
21
+ end
22
+
23
+ def self.fedex_gateway=(gateway)
24
+ Workarea.config.gateways.fedex_carrier = gateway
25
+ end
26
+
27
+ def self.auto_initialize_gateway
28
+ if ups_credentials.present? && fedex_credentials.present?
29
+ if Rails.env.test?
30
+ self.ups_gateway = ActiveShipping::Workarea.new
31
+ self.fedex_gateway = ActiveShipping::Workarea.new
32
+ else
33
+ self.ups_gateway = ActiveShipping::UPS.new ups_credentials
34
+ self.fedex_gateway = ActiveShipping::FedEx.new fedex_credentials
35
+ end
36
+ else
37
+ self.ups_gateway = ActiveShipping::Workarea.new
38
+ self.fedex_gateway = ActiveShipping::Workarea.new
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,6 @@
1
+ module Valken
2
+ module Shipping
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Valken
2
+ module Shipping
3
+ VERSION = '2.0.0'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: workarea-valken-shipping
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - sushmitha02
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.4
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 5.2.4.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 5.2.4
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.2.4.2
33
+ description: Choosing multiple carrier shipping options
34
+ email:
35
+ - sushmitha.h@trikatechnologies.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - MIT-LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - app/assets/config/valken_shipping_manifest.js
44
+ - app/helpers/workarea/addresses_helper.rb
45
+ - app/models/workarea/checkout/shipping_options.decorator
46
+ - app/models/workarea/shipping.decorator
47
+ - app/models/workarea/shipping_option.decorator
48
+ - app/services/workarea/packaging.decorator
49
+ - config/initializers/shipping_configuration.rb
50
+ - config/initializers/workarea.rb
51
+ - config/routes.rb
52
+ - lib/tasks/valken/shipping_tasks.rake
53
+ - lib/valken/shipping.rb
54
+ - lib/valken/shipping/engine.rb
55
+ - lib/valken/shipping/version.rb
56
+ homepage: https://github.com/sushmitha02
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.0.8
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: shipping options
79
+ test_files: []