sportsmans-supply 1.0.0.pre.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 14cb932f540318ae3a4406f2b310c298c63c092f62be52dd31a5296ddbc058b2
4
+ data.tar.gz: f89621f47f5018f2c1b16e0ff0a50fd276c5afebc5f548bc03c67ee9d7bedf07
5
+ SHA512:
6
+ metadata.gz: fadcebdc50392fdd0686eec56b50d7a969f74d0aa32bd0a43a07ca50e07db932bee172c1d83aa344bf5822596108e55ad51259a28e97d90223b7656ecb668999
7
+ data.tar.gz: bbb4bd2ce0a8ec806a4354004cb219ab7a3563830aaac170537e9575b3e0ffbd33f0a797af3dec06b32fce4397e6b14c4ea9ef48fabf7110c8a1226001bb7a8f
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sportsmans-supply.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Jeffrey Dill
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Sportsman's Supply
2
+
3
+ Ruby library for Sportsman's Supply ERP system.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'sportsmans-supply'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install sportsmans-supply
20
+
21
+ ## Development
22
+
23
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
24
+
25
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
26
+
27
+ ## Contributing
28
+
29
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ammoready/sportsmans-supply.
30
+
31
+
32
+ ## License
33
+
34
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sportsmans-supply"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,48 @@
1
+ module SportsmansSupply
2
+ class Base
3
+
4
+ def self.connect(options = {})
5
+ requires!(options, :username, :password)
6
+
7
+ Net::FTP.open(SportsmansSupply.config.ftp_host, options[:username], options[:password]) do |ftp|
8
+ yield(ftp)
9
+ end
10
+ end
11
+
12
+ protected
13
+
14
+ def requires!(*args)
15
+ self.class.requires!(*args)
16
+ end
17
+
18
+ def self.requires!(hash, *params)
19
+ params.each do |param|
20
+ if param.is_a?(Array)
21
+ raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
22
+
23
+ valid_options = param[1..-1]
24
+ raise ArgumentError.new("Parameter: #{param.first} must be one of: #{valid_options.join(', ')}") unless valid_options.include?(hash[param.first])
25
+ else
26
+ raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
27
+ end
28
+ end
29
+ end
30
+
31
+ def connect(options)
32
+ self.class.connect(options) do |ftp|
33
+ begin
34
+ yield(ftp)
35
+ end
36
+ end
37
+ end
38
+
39
+ def get_file(filename, file_directory = nil)
40
+ connect(@options) do |ftp|
41
+ tempfile = Tempfile.new
42
+ ftp.getbinaryfile(File.join(file_directory, filename), tempfile.path)
43
+ tempfile
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,82 @@
1
+ module SportsmansSupply
2
+ class Catalog < Base
3
+
4
+ def initialize(options = {})
5
+ requires!(options, :username, :password)
6
+ @options = options
7
+ end
8
+
9
+ def self.all(options = {})
10
+ requires!(options, :username, :password)
11
+ new(options).all
12
+ end
13
+
14
+ def all
15
+ catalog_file = get_file(SportsmansSupply.config.catalog_filename, 'products')
16
+ inventory_file = get_file(SportsmansSupply.config.inventory_filename, 'pricing-availability')
17
+
18
+ inventory_data = {}
19
+ catalog_data = []
20
+
21
+ File.open(inventory_file).each_with_index do |row, i|
22
+ row = row.split(",").map(&:strip)
23
+
24
+ if i == 0
25
+ @headers = row.map(&:downcase)
26
+ next
27
+ end
28
+
29
+ inventory_data[row[@headers.index('sku')]] = {
30
+ price: row[@headers.index('rapid retail price')],
31
+ quantity: row[@headers.index('qty')].to_i
32
+ }
33
+ end
34
+
35
+ File.open(catalog_file).each_with_index do |row, i|
36
+ row = row.split("|").map(&:strip)
37
+
38
+ if i == 0
39
+ @headers = row.map(&:downcase)
40
+ next
41
+ end
42
+
43
+ description = row[@headers.index('description')]
44
+ sku = row[@headers.index('sku')]
45
+ inventory_datum = inventory_data[sku]
46
+
47
+ next if inventory_datum.nil?
48
+
49
+ catalog_data << {
50
+ mfg_number: row[@headers.index('mpn')],
51
+ upc: row[@headers.index('upc code')],
52
+ name: description,
53
+ quantity: inventory_datum[:quantity],
54
+ price: inventory_datum[:price],
55
+ map_price: row[@headers.index('map')],
56
+ msrp: row[@headers.index('msrp')],
57
+ brand: row[@headers.index('manufacturer')],
58
+ item_identifier: sku,
59
+ category: row[@headers.index('category')],
60
+ subcategory: row[@headers.index('subcategory')],
61
+ short_description: description,
62
+ long_description: row[@headers.index('detailed description')],
63
+ weight: [row[@headers.index('weight')], row[@headers.index('weight units')]].join,
64
+ features: {
65
+ dimension_length: row[@headers.index('dimensionl')],
66
+ dimension_width: row[@headers.index('dimensionw')],
67
+ dimension_height: row[@headers.index('dimensionh')],
68
+ shipping_length: row[@headers.index('shipping length')],
69
+ shipping_width: row[@headers.index('shipping width')],
70
+ shipping_height: row[@headers.index('shipping height')],
71
+ image_name: row[@headers.index('image url')],
72
+ }
73
+ }
74
+ end
75
+
76
+ [catalog_file, inventory_file].each { |f| f.close; f.unlink }
77
+
78
+ catalog_data
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ module SportsmansSupply
2
+ class Inventory < Base
3
+
4
+ def initialize(options = {})
5
+ requires!(options, :username, :password)
6
+ @options = options
7
+ end
8
+
9
+ def self.all(options = {})
10
+ requires!(options, :username, :password)
11
+ new(options).all
12
+ end
13
+ class << self; alias_method :quantity, :all; end
14
+
15
+ def all
16
+ inventory_file = get_file(SportsmansSupply.config.inventory_filename, 'pricing-availability')
17
+ inventory_data = []
18
+
19
+ File.open(inventory_file).each_with_index do |row, i|
20
+ row = row.split(",").map(&:strip)
21
+
22
+ if i == 0
23
+ @headers = row.map(&:downcase)
24
+ next
25
+ end
26
+
27
+ inventory_data << {
28
+ item_identifier: row[@headers.index('sku')],
29
+ quantity: row[@headers.index('qty')].to_i,
30
+ price: row[@headers.index('rapid retail price')].strip,
31
+ }
32
+ end
33
+
34
+ inventory_file.close
35
+ inventory_file.unlink
36
+
37
+ inventory_data
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module SportsmansSupply
2
+ class Invoice < Base
3
+
4
+ def initialize(options = {})
5
+ requires!(options, :username, :password)
6
+ @options = options
7
+ end
8
+
9
+ def self.all(options = {})
10
+ requires!(options, :username, :password)
11
+ new(options).all
12
+ end
13
+
14
+ def all
15
+ invoice_filename = connect(@options) { |ftp| ftp.nlst('/invoices/invoices*.csv').last }.split('/').last
16
+ invoice_file = get_file(invoice_filename, 'invoices')
17
+
18
+ invoice_data = []
19
+
20
+ File.open(invoice_file).each_with_index do |row, i|
21
+ row = row.split(",").map(&:strip)
22
+
23
+ if i == 0
24
+ @headers = row.map(&:downcase)
25
+ next
26
+ end
27
+
28
+ invoice_data << {
29
+ po_number: row[@headers.index('order number')],
30
+ invoice_number: row[@headers.index('invoice number')]
31
+ }
32
+ end
33
+
34
+ invoice_file.close
35
+ invoice_file.unlink
36
+
37
+ invoice_data
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,69 @@
1
+ module SportsmansSupply
2
+ class Order < Base
3
+
4
+ HEADERS = [
5
+ 'cust #', 'order id', 'status', 'order received date', 'ship method code', 'ship to name', 'ship to line 1',
6
+ 'ship to line 2', 'ship to city', 'ship to state', 'ship to zip', 'ship to country', 'ship to phone', 'cost',
7
+ 'sku/upc', 'quantity ordered'
8
+ ]
9
+
10
+ def initialize(options = {})
11
+ requires!(options, :username, :password)
12
+
13
+ @options = options
14
+ @items = []
15
+ end
16
+
17
+ def add_item(item = {})
18
+ requires!(item, :item_number, :quantity)
19
+
20
+ @items << item
21
+ end
22
+
23
+ def submit(options = {})
24
+ raise SportsmansSupply::InvalidOrder.new("Must add items with #add_item before submitting") if @items.empty?
25
+
26
+ requires!(options, :customer_number, :po_number, :shipping)
27
+ requires!(options[:shipping], :name, :address_1, :city, :state, :zip)
28
+
29
+ filename = [options[:customer_number], Time.now.strftime("%m%d%y%H%M%S"), options[:po_number]].join('_') + '.csv'
30
+ order_file = Tempfile.new(filename)
31
+
32
+ CSV.open(order_file.path, 'w+', col_sep: ",") do |csv|
33
+ csv << HEADERS
34
+
35
+ @items.each do |item|
36
+ item_data = [
37
+ options[:customer_number],
38
+ options[:po_number],
39
+ 'NEW',
40
+ Time.now.strftime("%-m/%d/%Y"),
41
+ options[:shipping][:method_code] || 'Best Way',
42
+ options[:shipping][:name],
43
+ options[:shipping][:address_1],
44
+ options[:shipping][:address_2],
45
+ options[:shipping][:city],
46
+ options[:shipping][:state],
47
+ options[:shipping][:zip],
48
+ options[:shipping][:country] || 'USA',
49
+ options[:shipping][:phone],
50
+ '',
51
+ item[:item_number],
52
+ item[:quantity]
53
+ ]
54
+
55
+ csv << item_data
56
+ end
57
+ end
58
+
59
+ connect(@options) do |ftp|
60
+ ftp.chdir('orders')
61
+ ftp.puttextfile(order_file.path, filename)
62
+ end
63
+
64
+ order_file.close
65
+ order_file.unlink
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ module SportsmansSupply
2
+ class Shipping < Base
3
+
4
+ def initialize(options = {})
5
+ requires!(options, :username, :password)
6
+ @options = options
7
+ end
8
+
9
+ def self.all(options = {})
10
+ requires!(options, :username, :password)
11
+ new(options).all
12
+ end
13
+
14
+ def all
15
+ tracking_filename = connect(@options) { |ftp| ftp.nlst('/shipping/tracking*.csv').last }.split('/').last
16
+ tracking_file = get_file(tracking_filename, 'shipping')
17
+
18
+ tracking_data = []
19
+
20
+ File.open(tracking_file).each_with_index do |row, i|
21
+ row = row.split(",").map(&:strip)
22
+
23
+ if i == 0
24
+ @headers = row.map(&:downcase)
25
+ next
26
+ end
27
+
28
+ tracking_data << {
29
+ po_number: row[@headers.index('customer po#')],
30
+ tracking_number: row[@headers.index('tracking numbers')],
31
+ carrier: row[@headers.index('actual shipping carrier')]
32
+ }
33
+ end
34
+
35
+ tracking_file.close
36
+ tracking_file.unlink
37
+
38
+ tracking_data
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ module SportsmansSupply
2
+ class User < Base
3
+
4
+ def initialize(options = {})
5
+ requires!(options, :username, :password)
6
+ @options = options
7
+ end
8
+
9
+ def self.authenticated?(options = {})
10
+ requires!(options, :username, :password)
11
+ new(options).authenticated?
12
+ end
13
+
14
+ def authenticated?
15
+ connect(@options) { |ftp| ftp.pwd }
16
+ true
17
+ rescue SportsmansSupply::NotAuthenticated, Net::FTPPermError
18
+ false
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module SportsmansSupply
2
+ VERSION = '1.0.0-pre'.freeze
3
+ end
@@ -0,0 +1,43 @@
1
+ require 'sportsmans-supply/version'
2
+
3
+ require 'csv'
4
+ require 'net/ftp'
5
+ require 'tempfile'
6
+
7
+ require 'sportsmans-supply/base'
8
+ require 'sportsmans-supply/catalog'
9
+ require 'sportsmans-supply/inventory'
10
+ require 'sportsmans-supply/invoice'
11
+ require 'sportsmans-supply/order'
12
+ require 'sportsmans-supply/shipping'
13
+ require 'sportsmans-supply/user'
14
+
15
+ module SportsmansSupply
16
+ class InvalidOrder < StandardError; end
17
+ class NotAuthenticated < StandardError; end
18
+ class FileOrDirectoryNotFound < StandardError; end
19
+
20
+ class << self
21
+ attr_accessor :config
22
+ end
23
+
24
+ def self.config
25
+ @config ||= Configuration.new
26
+ end
27
+
28
+ def self.configure
29
+ yield(config)
30
+ end
31
+
32
+ class Configuration
33
+ attr_accessor :ftp_host
34
+ attr_accessor :catalog_filename
35
+ attr_accessor :inventory_filename
36
+
37
+ def initialize
38
+ @ftp_host ||= 'www.rapidretail.net'
39
+ @catalog_filename ||= 'rr_products.csv'
40
+ @inventory_filename ||= 'rr_pricing_availability.csv'
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sportsmans-supply/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sportsmans-supply"
8
+ spec.version = SportsmansSupply::VERSION
9
+ spec.authors = ["Jeffrey Dill"]
10
+ spec.email = ["jeffdill2@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby library for Sportsman's Supply ERP system}
13
+ spec.description = %q{}
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "activesupport", "~> 5"
25
+ spec.add_development_dependency "bundler", "~> 1.12"
26
+ spec.add_development_dependency "rake", ">= 12.3.3"
27
+ spec.add_development_dependency "rspec", "~> 3.5"
28
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sportsmans-supply
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.pre
5
+ platform: ruby
6
+ authors:
7
+ - Jeffrey Dill
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-01-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ description: ''
70
+ email:
71
+ - jeffdill2@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - LICENSE.txt
78
+ - README.md
79
+ - Rakefile
80
+ - bin/console
81
+ - bin/setup
82
+ - lib/sportsmans-supply.rb
83
+ - lib/sportsmans-supply/base.rb
84
+ - lib/sportsmans-supply/catalog.rb
85
+ - lib/sportsmans-supply/inventory.rb
86
+ - lib/sportsmans-supply/invoice.rb
87
+ - lib/sportsmans-supply/order.rb
88
+ - lib/sportsmans-supply/shipping.rb
89
+ - lib/sportsmans-supply/user.rb
90
+ - lib/sportsmans-supply/version.rb
91
+ - sportsmans-supply.gemspec
92
+ homepage: ''
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.3.1
110
+ requirements: []
111
+ rubygems_version: 3.0.9
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Ruby library for Sportsman's Supply ERP system
115
+ test_files: []