Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shikhir-arora/3ac10dfec1ca1619c2725cb5384f8318 to your computer and use it in GitHub Desktop.
Save shikhir-arora/3ac10dfec1ca1619c2725cb5384f8318 to your computer and use it in GitHub Desktop.
# This program will take swag.csv and create a batch of USPS
# shipping labels in one PDF file for easy printing using
# the EasyPost simple shipping API.
#
# If you have any questions about EasyPost or want help
# modifying this script for other carriers or a non-US
# source address please email us anytime at contact@easypost.com
#
# Usage:
# easypost_batch_from_csv.rb
# -i filename.csv (defaults to swag.csv) (or --in)
# -b (or --buy)
#
# Requirements:
# EasyPost account: https://easypost.com
# EasyPost ruby gem: gem install easypost
require 'easypost'
require 'csv'
require 'optparse'
# command line options and defaults
OptionParser.new do |o|
o.on('-i FILENAME') { |filename| @csv_filename = filename }
o.on('--in FILENAME') { |filename| @csv_filename ||= filename }
o.on('-b') { |b| @buy = b }
o.on('--buy') { |b| @buy ||= b }
o.on('-h') { puts o; exit }
o.parse!
end
@csv_filename = 'swag.csv' unless @csv_filename
# EasyPost API key: https://easypost.com/account/keys
EasyPost.api_key = '{YOUR-API-KEY}'
def generate_batch_label(batch)
batch.refresh
raise StandardError.new("Cannot generate batch label, all shipments have not been purchased.") if batch.status[:postage_purchased] != batch.shipments.length
if batch.label_url
puts "Batch Label: #{batch.label}"
return true
end
batch.label({:file_format => 'pdf'})
print "Generating Batch Label"
while !batch.label_url
batch.refresh
sleep(3)
print "."
end
puts "\n#{batch.label_url}"
return true
end
# read csv and remove header row
csv = CSV.read(@csv_filename)
csv.shift
# look for existing batch_id in last row of csv
batch_id = csv[csv.length - 1][1]
if batch_id && batch_id.include?('batch_')
batch = EasyPost::Batch.retrieve(batch_id)
# batch completed, print total cost and postage label
if batch.status[:postage_purchased] == batch.shipments.length
batch_cost = 0
batch.shipments.each do |shipment|
shipment.refresh
batch_cost += shipment.selected_rate.rate.to_f
end
puts "Batch Successfull Purchased for Total: $#{batch_cost}"
generate_batch_label(batch)
exit
end
else
batch = nil
end
# not ready to buy yet
if @buy != true
# the batch already exists: output its status
if batch
# loop through batch shipments and calculate costs
batch_cost = 0
est_batch_cost = 0
print "Updating batch rate estimate"
batch.shipments.each do |shipment|
shipment.get_rates
if shipment.batch_status == 'created'
est_batch_cost += shipment.lowest_rate('USPS', ['!MediaMail', '!LibraryMail']).rate.to_f
else
batch_cost += shipment.selected_rate.rate.to_f
end
print '.'
end
puts "\nAlready purchased total: $#{batch_cost}"
puts "Estimated remaining cost for batch: $#{est_batch_cost}"
puts "Run with buy option (-b) to purchase postage."
exit
end
# address you'll be mailing from
from_address = EasyPost::Address.create(
:company => '{YOUR-COMPANY}',
:street1 => '{YOUR-ADDRESS}',
:city => '{YOUR-CITY}',
:state => '{YOUR-2-CHAR-STATE}',
:zip => '{YOUR-POSTAL-ZIP-CODE}',
:country => '{YOUR-2-CHAR-COUNTRY}',
:phone => '{YOUR-PHONE}',
:email => '{YOUR-EMAIL}'
)
# parcel type and weight
parcel = EasyPost::Parcel.create(
:predefined_package => 'Flat', # USPS thin flexible package perfect for t-shirt
:weight => 10.0 # 10 ounces is a rough guess for 1 t-shirt
)
# customs forms in case any of your recipients are international
customs_item = EasyPost::CustomsItem.create(
:description => 'T-shirt',
:quantity => 1,
:value => 10,
:weight => 10,
:hs_tariff_number => 610910, # http://hts.usitc.gov/ if you're not mailing t-shirts
:origin_country => 'US'
)
customs_info = EasyPost::CustomsInfo.create(
:eel_pfc => 'NOEEI 30.37(a)', # for packages up to $2500 in value
:customs_certify => true,
:customs_signer => '{YOUR-NAME}',
:contents_type => 'gift',
:contents_explanation => '',
:restriction_type => 'none',
:restriction_comments => '',
:non_delivery_option => 'return',
:customs_items => [customs_item]
)
# loop over csv and create shipments
shipments = []
csv.each do |swag_recipient|
# skip empty rows and the final batch_id row
next unless swag_recipient[0] && swag_recipient[4]
# set destination address
to_address = {
:name => swag_recipient[0],
:street1 => swag_recipient[1],
:city => swag_recipient[2],
:state => swag_recipient[3],
:zip => swag_recipient[4],
:country => swag_recipient[5]
}
shipment = {
:to_address => to_address,
:from_address => from_address,
:parcel => parcel,
:reference => swag_recipient[6]
}
if swag_recipient[5] != 'US'
shipment[:customs_info] = customs_info
end
shipments << shipment
end
batch = EasyPost::Batch.create({:shipment => shipments})
# output the completed batch_id to the csv's final row
# this allows us to query the status of a created batch
# without creating a new one each run through the script
if batch.id
CSV.open(@csv_filename, 'a') do |csv|
csv << []
csv << ['easypost_batch_id', batch[:id]]
end
end
puts batch
puts "Batch created successfully! Run with buy flag (-b) to purchase postage and generate label."
end
# buy postage for batch referenced in csv
if @buy == true
if batch
# loop through batch shipments purchasing postage
batch_cost = 0
est_batch_cost = 0
unsuccessful_count = 0
batch.shipments.each do |shipment|
shipment.get_rates
if shipment.batch_status == 'created'
begin
# buy the cheapest rate from USPS that isn't LibraryMail or MediaMail
# you can remove the service restrictions if your shipment qualifies for them
shipment.buy(shipment.lowest_rate('USPS', ['!MediaMail', '!LibraryMail']))
batch_cost += shipment.lowest_rate('USPS', ['!MediaMail', '!LibraryMail']).rate.to_f
rescue
unsuccessful_count += 1
est_batch_cost += shipment.lowest_rate('USPS', ['!MediaMail', '!LibraryMail']).rate.to_f
end
else
batch_cost += shipment.lowest_rate('USPS', ['!MediaMail', '!LibraryMail']).rate.to_f
end
end
# batch purchasing not completed successfully - rerun script
if unsuccessful_count > 0
puts "Unsuccessful Purchases: #{unsuccessful_count}"
puts "Please re-run script with buy flag to try again.\n"
puts "Already Purchased Total: $#{batch_cost}"
puts "Estimated Remaining Cost for Batch: $#{est_batch_cost}"
else
# batch purchased successfully, generate label
puts "Batch Successfull Purchased for Total: $#{batch_cost}"
generate_batch_label(batch)
end
else
puts "No batch_id found in csv, run script without buy flag first!"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment