Class: Shipping::Base

Inherits:
Object show all
Defined in:
lib/shipping/base.rb

Direct Known Subclasses

FedEx

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Base

Returns a new instance of Base.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/shipping/base.rb', line 30

def initialize(options = {})
	prefs = File.expand_path(options[:prefs] || RAILS_ROOT + "/config/shipping.yml")
	YAML.load(File.open(prefs)).each {|pref, value| eval("@#{pref} = #{value.inspect}")} if File.exists?(prefs)

	@required = Array.new
	@services = Array.new

	# include all provided data
	options.each do |method, value| 
		instance_variable_set("@#{method}", value)
	end
	
	case options[:carrier]
  when "fedex"
    fedex
   when "ups"
     ups
    when nil
    else
      raise ShippingError, "unknown service"
    end
end

Instance Attribute Details

#addressObject

Returns the value of attribute address.



17
18
19
# File 'lib/shipping/base.rb', line 17

def address
  @address
end

#address2Object

Returns the value of attribute address2.



17
18
19
# File 'lib/shipping/base.rb', line 17

def address2
  @address2
end

#cityObject

Returns the value of attribute city.



17
18
19
# File 'lib/shipping/base.rb', line 17

def city
  @city
end

#companyObject

Returns the value of attribute company.



17
18
19
# File 'lib/shipping/base.rb', line 17

def company
  @company
end

#countryObject

Returns the value of attribute country.



17
18
19
# File 'lib/shipping/base.rb', line 17

def country
  @country
end

#currency_codeObject

Returns the value of attribute currency_code.



26
27
28
# File 'lib/shipping/base.rb', line 26

def currency_code
  @currency_code
end

#dataObject (readonly)

Returns the value of attribute data.



12
13
14
# File 'lib/shipping/base.rb', line 12

def data
  @data
end

#declared_valueObject

Returns the value of attribute declared_value.



20
21
22
# File 'lib/shipping/base.rb', line 20

def declared_value
  @declared_value
end

#descriptionObject

Returns the value of attribute description.



20
21
22
# File 'lib/shipping/base.rb', line 20

def description
  @description
end

#discount_priceObject

Returns the value of attribute discount_price.



24
25
26
# File 'lib/shipping/base.rb', line 24

def discount_price
  @discount_price
end

#dropoff_typeObject

Returns the value of attribute dropoff_type.



26
27
28
# File 'lib/shipping/base.rb', line 26

def dropoff_type
  @dropoff_type
end

#emailObject

Returns the value of attribute email.



17
18
19
# File 'lib/shipping/base.rb', line 17

def email
  @email
end

#etaObject

Returns the value of attribute eta.



24
25
26
# File 'lib/shipping/base.rb', line 24

def eta
  @eta
end

#fedex_account=(value) ⇒ Object (writeonly)

Sets the attribute fedex_account

Parameters:

  • value

    the value to set the attribute fedex_account to.



15
16
17
# File 'lib/shipping/base.rb', line 15

def fedex_account=(value)
  @fedex_account = value
end

#fedex_meter=(value) ⇒ Object (writeonly)

Sets the attribute fedex_meter

Parameters:

  • value

    the value to set the attribute fedex_meter to.



15
16
17
# File 'lib/shipping/base.rb', line 15

def fedex_meter=(value)
  @fedex_meter = value
end

#fedex_package_weight_limit_in_lbs=(value) ⇒ Object (writeonly)

Sets the attribute fedex_package_weight_limit_in_lbs

Parameters:

  • value

    the value to set the attribute fedex_package_weight_limit_in_lbs to.



15
16
17
# File 'lib/shipping/base.rb', line 15

def fedex_package_weight_limit_in_lbs=(value)
  @fedex_package_weight_limit_in_lbs = value
end

#fedex_url=(value) ⇒ Object (writeonly)

Sets the attribute fedex_url

Parameters:

  • value

    the value to set the attribute fedex_url to.



15
16
17
# File 'lib/shipping/base.rb', line 15

def fedex_url=(value)
  @fedex_url = value
end

#image_typeObject

Returns the value of attribute image_type.



26
27
28
# File 'lib/shipping/base.rb', line 26

def image_type
  @image_type
end

#insured_valueObject

Returns the value of attribute insured_value.



20
21
22
# File 'lib/shipping/base.rb', line 20

def insured_value
  @insured_value
end

#itemsObject

Returns the value of attribute items.



28
29
30
# File 'lib/shipping/base.rb', line 28

def items
  @items
end

#label_typeObject

Returns the value of attribute label_type.



26
27
28
# File 'lib/shipping/base.rb', line 26

def label_type
  @label_type
end

#max_quantityObject

Returns the value of attribute max_quantity.



28
29
30
# File 'lib/shipping/base.rb', line 28

def max_quantity
  @max_quantity
end

#max_weightObject

Returns the value of attribute max_weight.



28
29
30
# File 'lib/shipping/base.rb', line 28

def max_weight
  @max_weight
end

#measure_heightObject

Returns the value of attribute measure_height.



21
22
23
# File 'lib/shipping/base.rb', line 21

def measure_height
  @measure_height
end

#measure_lengthObject

Returns the value of attribute measure_length.



21
22
23
# File 'lib/shipping/base.rb', line 21

def measure_length
  @measure_length
end

#measure_unitsObject

Returns the value of attribute measure_units.



21
22
23
# File 'lib/shipping/base.rb', line 21

def measure_units
  @measure_units
end

#measure_widthObject

Returns the value of attribute measure_width.



21
22
23
# File 'lib/shipping/base.rb', line 21

def measure_width
  @measure_width
end

#nameObject

Returns the value of attribute name.



17
18
19
# File 'lib/shipping/base.rb', line 17

def name
  @name
end

#package_totalObject

Returns the value of attribute package_total.



22
23
24
# File 'lib/shipping/base.rb', line 22

def package_total
  @package_total
end

#packaging_typeObject

Returns the value of attribute packaging_type.



22
23
24
# File 'lib/shipping/base.rb', line 22

def packaging_type
  @packaging_type
end

#pay_typeObject

Returns the value of attribute pay_type.



26
27
28
# File 'lib/shipping/base.rb', line 26

def pay_type
  @pay_type
end

#phoneObject

Returns the value of attribute phone.



17
18
19
# File 'lib/shipping/base.rb', line 17

def phone
  @phone
end

#plain_responseObject (readonly)

Returns the value of attribute plain_response.



12
13
14
# File 'lib/shipping/base.rb', line 12

def plain_response
  @plain_response
end

#priceObject

Returns the value of attribute price.



24
25
26
# File 'lib/shipping/base.rb', line 24

def price
  @price
end

#quantityObject

Returns the value of attribute quantity.



28
29
30
# File 'lib/shipping/base.rb', line 28

def quantity
  @quantity
end

#requiredObject (readonly)

Returns the value of attribute required.



12
13
14
# File 'lib/shipping/base.rb', line 12

def required
  @required
end

#responseObject (readonly)

Returns the value of attribute response.



12
13
14
# File 'lib/shipping/base.rb', line 12

def response
  @response
end

#sender_addressObject

Returns the value of attribute sender_address.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_address
  @sender_address
end

#sender_cityObject

Returns the value of attribute sender_city.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_city
  @sender_city
end

#sender_companyObject

Returns the value of attribute sender_company.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_company
  @sender_company
end

#sender_countryObject

Returns the value of attribute sender_country.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_country
  @sender_country
end

#sender_emailObject

Returns the value of attribute sender_email.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_email
  @sender_email
end

#sender_nameObject

Returns the value of attribute sender_name.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_name
  @sender_name
end

#sender_phoneObject

Returns the value of attribute sender_phone.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_phone
  @sender_phone
end

#sender_stateObject

Returns the value of attribute sender_state.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_state
  @sender_state
end

#sender_zipObject

Returns the value of attribute sender_zip.



18
19
20
# File 'lib/shipping/base.rb', line 18

def sender_zip
  @sender_zip
end

#service_typeObject

Returns the value of attribute service_type.



22
23
24
# File 'lib/shipping/base.rb', line 22

def service_type
  @service_type
end

#servicesObject (readonly)

Returns the value of attribute services.



12
13
14
# File 'lib/shipping/base.rb', line 12

def services
  @services
end

#ship_dateObject

Returns the value of attribute ship_date.



26
27
28
# File 'lib/shipping/base.rb', line 26

def ship_date
  @ship_date
end

#stateObject

Returns the value of attribute state.



17
18
19
# File 'lib/shipping/base.rb', line 17

def state
  @state
end

#time_in_transitObject

Returns the value of attribute time_in_transit.



24
25
26
# File 'lib/shipping/base.rb', line 24

def time_in_transit
  @time_in_transit
end

#transaction_typeObject

Returns the value of attribute transaction_type.



20
21
22
# File 'lib/shipping/base.rb', line 20

def transaction_type
  @transaction_type
end

#ups_license_number=(value) ⇒ Object (writeonly)

Sets the attribute ups_license_number

Parameters:

  • value

    the value to set the attribute ups_license_number to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_license_number=(value)
  @ups_license_number = value
end

#ups_password=(value) ⇒ Object (writeonly)

Sets the attribute ups_password

Parameters:

  • value

    the value to set the attribute ups_password to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_password=(value)
  @ups_password = value
end

#ups_shipper_number=(value) ⇒ Object (writeonly)

Sets the attribute ups_shipper_number

Parameters:

  • value

    the value to set the attribute ups_shipper_number to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_shipper_number=(value)
  @ups_shipper_number = value
end

#ups_tool=(value) ⇒ Object (writeonly)

Sets the attribute ups_tool

Parameters:

  • value

    the value to set the attribute ups_tool to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_tool=(value)
  @ups_tool = value
end

#ups_url=(value) ⇒ Object (writeonly)

Sets the attribute ups_url

Parameters:

  • value

    the value to set the attribute ups_url to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_url=(value)
  @ups_url = value
end

#ups_user=(value) ⇒ Object (writeonly)

Sets the attribute ups_user

Parameters:

  • value

    the value to set the attribute ups_user to.



14
15
16
# File 'lib/shipping/base.rb', line 14

def ups_user=(value)
  @ups_user = value
end

#weightObject

Returns the value of attribute weight.



20
21
22
# File 'lib/shipping/base.rb', line 20

def weight
  @weight
end

#weight_eachObject

Returns the value of attribute weight_each.



28
29
30
# File 'lib/shipping/base.rb', line 28

def weight_each
  @weight_each
end

#weight_unitsObject

Returns the value of attribute weight_units.



20
21
22
# File 'lib/shipping/base.rb', line 20

def weight_units
  @weight_units
end

#zipObject

Returns the value of attribute zip.



17
18
19
# File 'lib/shipping/base.rb', line 17

def zip
  @zip
end

Class Method Details

.plainObject



290
# File 'lib/shipping/base.rb', line 290

def @response.plain; @response_plain; end

.state_from_zip(zip) ⇒ Object

Raises:



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/shipping/base.rb', line 187

def self.state_from_zip(zip)
zip = zip.to_i
{
	(99500...99929) => "AK", 
	(35000...36999) => "AL", 
	(71600...72999) => "AR", 
	(75502...75505) => "AR", 
	(85000...86599) => "AZ", 
	(90000...96199) => "CA", 
	(80000...81699) => "CO", 
	(6000...6999) => "CT", 
	(20000...20099) => "DC", 
	(20200...20599) => "DC", 
	(19700...19999) => "DE", 
	(32000...33999) => "FL", 
	(34100...34999) => "FL", 
	(30000...31999) => "GA", 
	(96700...96798) => "HI", 
	(96800...96899) => "HI", 
	(50000...52999) => "IA", 
	(83200...83899) => "ID", 
	(60000...62999) => "IL", 
	(46000...47999) => "IN", 
	(66000...67999) => "KS", 
	(40000...42799) => "KY", 
	(45275...45275) => "KY", 
	(70000...71499) => "LA", 
	(71749...71749) => "LA", 
	(1000...2799) => "MA", 
	(20331...20331) => "MD", 
	(20600...21999) => "MD", 
	(3801...3801) => "ME", 
	(3804...3804) => "ME", 
	(3900...4999) => "ME", 
	(48000...49999) => "MI", 
	(55000...56799) => "MN", 
	(63000...65899) => "MO", 
	(38600...39799) => "MS", 
	(59000...59999) => "MT", 
	(27000...28999) => "NC", 
	(58000...58899) => "ND", 
	(68000...69399) => "NE", 
	(3000...3803) => "NH", 
	(3809...3899) => "NH", 
	(7000...8999) => "NJ", 
	(87000...88499) => "NM", 
	(89000...89899) => "NV", 
	(400...599) => "NY", 
	(6390...6390) => "NY", 
	(9000...14999) => "NY", 
	(43000...45999) => "OH", 
	(73000...73199) => "OK", 
	(73400...74999) => "OK", 
	(97000...97999) => "OR", 
	(15000...19699) => "PA", 
	(2800...2999) => "RI", 
	(6379...6379) => "RI", 
	(29000...29999) => "SC", 
	(57000...57799) => "SD", 
	(37000...38599) => "TN", 
	(72395...72395) => "TN", 
	(73300...73399) => "TX", 
	(73949...73949) => "TX", 
	(75000...79999) => "TX", 
	(88501...88599) => "TX", 
	(84000...84799) => "UT", 
	(20105...20199) => "VA", 
	(20301...20301) => "VA", 
	(20370...20370) => "VA", 
	(22000...24699) => "VA", 
	(5000...5999) => "VT", 
	(98000...99499) => "WA", 
	(49936...49936) => "WI", 
	(53000...54999) => "WI", 
	(24700...26899) => "WV", 
	(82000...83199) => "WY"
	}.each do |range, state|
		return state if range.include? zip
	end

	raise ShippingError, "Invalid zip code"
end

Instance Method Details

#boxesObject

Attempt to package items in multiple boxes efficiently This doesn’t use the bin-packing algorithm, but instead attempts to mirror how people pack boxes – since people will most likely be packing them. – It attempts to pack like items whenever possible. @items: array of weights @weight_each: can be used instead of array of items @variation_threshold: how much variety you’ll allow (default to 10% variation [e.g. 10 items, 10 each]) @weight_threshold: the minimum weight a box must be to close (default .5, i.e. half full by weight) @quantity_threshold: the minimum full a box must be to close (default .5, i.e. half full by the number of items that will fit)



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/shipping/base.rb', line 72

def boxes
  # See if we're dealing with an array of items
  if @items.length > 0
    @items.each {|item| item[:total_weight] = item[:weight] * item[:quantity]} # get weight totals
    props = @items.inject({:weights => [], :quantities => [], :total_weights => []}) {|h, item| h[:weights] << item[:weight];h[:quantities] << item[:quantity]; h[:total_weights] << item[:total_weight];h}
    @quantity = props[:quantities].sum
    total_weight = props[:total_weights].sum
    
    # check to see if these are all the same weight
    if props[:weights].uniq.length == 1
      itemized = false
      @weight_each = props[:weights].uniq[0]
    else
      itemized = true
    end
  else
    @required = ['quantity', 'weight_each']
    total_weight = @quantity.to_f * @weight_each
    itemized = false
  end
  
  max_weight = @max_weight || 150 # Fed Ex and UPS commercial max
  max_quantity = @max_quantity || @quantity
  variation_threshold = @variation_threshold || 0.1 # default to 10% variation (e.g. 10 items, 10 each)
  weight_threshold = @weight_threshold || 0.5 # default to half full
  quantity_threshold = @quantity_threshold || 0.5 #default to half full
  box = Array.new
  
  # See if boxes should be divided by weight or number
  bw = total_weight / max_weight
  bq = @quantity.to_f / max_quantity
  min_boxes = [bw.ceil, bq.ceil].max.to_i

  # work with list of items
  if itemized
    leftovers = Array.new
    variation = @items.length / @quantity.to_f # this shows us how much repetition there is

    # First, we attempt to pack like items/weights
    # we can skip this if variation is really high
    if variation < variation_threshold
      @items.each do |item|
        while item[:quantity] > 0
          max = (@max_weight / item[:weight]).truncate # how many of this weight can be packed in
          this_num = [max, @max_quantity, item[:quantity]].min # should we pack by weight, number avail, or quantity
          this_weight = this_num * item[:weight]
          item[:quantity] -= this_num
          
          # if we haven't met the threshold
          if (this_weight / @max_weight) <= weight_threshold and (this_num / @max_quantity) <= quantity_threshold
            leftovers  << {:weight => this_weight, :quantity => this_num, :item => item[:id]}
          else #otherwise, pack it
            box << {:weight => this_weight, :quantity => this_num, :item => item[:id]}
          end
        end
      end
    else
      leftovers = @items
    end

    # Then, we pack all the leftovers
    leftover_box = {:weight => @max_weight, :quantity => @max_quantity}
    this_box = {:weight => 0.0, :quantity => 0}       
    leftovers.each do |item|
      for i in 1..item[:quantity]
        leftover_box[:weight] -= item[:weight]
        leftover_box[:quantity] -= 1
        if leftover_box[:weight] > 0 and leftover_box[:quantity] > 0
          this_box[:weight] += item[:weight]
          this_box[:quantity] += 1
        elsif leftover_box[:weight] = 0 and leftover_box[:quantity] >= 0
          this_box[:weight] += item[:weight]
          this_box[:quantity] += 1
          box << {:weight => this_box[:weight], :quantity => this_box[:quantity]}
          leftover_box = {:weight => @max_weight, :quantity => @max_quantity}
          this_box = {:weight => 0.0, :quantity => 0}
        else
          box << {:weight => this_box[:weight], :quantity => this_box[:quantity]}
          leftover_box = {:weight => @max_weight, :quantity => @max_quantity}
          this_box = {:weight => 0.0, :quantity => 0}
        end
      end
    end
    if this_box[:weight] > 0.0 and this_box[:quantity] > 0
      box << {:weight => this_box[:weight], :quantity => this_box[:quantity]}
    end
              
    inefficiency = box.length / min_boxes

  else # pack super efficiently
    if bw > bq
      box_weight = max_weight
      box_quantity = max_weight / @weight_each
    else
      box_weight = max_quantity * @weight_each
      box_quantity = max_quantity
    end
    
    # fill the rest of the boxes
    num_boxes = min_boxes - 1
    (num_boxes).times do
      box << {:weight => box_weight, :quantity => box_quantity}
    end
    
    # if there is an uneven number for packaging
    if @quantity % min_boxes != 0 or num_boxes == 0
      excess_q = @quantity - (box_quantity * num_boxes)
      excess_w = excess_q * @weight_each
      box << {:weight => excess_w, :quantity => excess_q}
    end
    inefficiency = 0
  end
  return box
end

#fedexObject

Initializes an instance of Shipping::FedEx with the same instance variables as the base object



54
55
56
# File 'lib/shipping/base.rb', line 54

def fedex
	Shipping::FedEx.new prepare_vars
end

#upsObject

Initializes an instance of Shipping::UPS with the same instance variables as the base object



59
60
61
# File 'lib/shipping/base.rb', line 59

def ups
	Shipping::UPS.new prepare_vars
end