rsr_group 0.1.6 → 1.0.0.pre

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da0117d9236b24b6cc871f4076d6ef25ec407150
4
- data.tar.gz: 67a6400b5a745cd85996619c79df541d80fcc5d8
3
+ metadata.gz: 7c9bf20350d6ad63a809ab9b1ec14ed29dec0acb
4
+ data.tar.gz: 0cdadb5c40579b6abe6d28fa55e68dd486f9e27d
5
5
  SHA512:
6
- metadata.gz: 25e0da72c0ffd17fec273a2a7dce18853e04787d4906a22abde1b97addf7b999e56a29f8e2ce76ce3cd0c06282b8b66274ae235ff42e1365bda8fc2dd6724006
7
- data.tar.gz: 747385a866206a1aa8e7ca927b6c4d14e5529fee074d186d3ea840310be804e2567d5f876ab7b2215f58512be107f7d14371ca4d3807b79c9974e6bc5d68fab2
6
+ metadata.gz: d608e462128d6ab5e7dcef36f317c5b028e21ce9d47329c5b5b4eacff091a363028fa66b2b1afc505fb7faa7fabc83689848c6de0120d0061aaaa242d92e5d87
7
+ data.tar.gz: 1ecd0f05f172f4a071df7e5c74c16e4367ad2cc9e269f67011cdf3bbb853e7f5d7a2f369d68b87370665d470f4c7f5b1f9d0b2f3f2db07a686e024e620c0807c
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ samples/*
11
+ script/*
data/config.rb.example ADDED
@@ -0,0 +1,5 @@
1
+ RsrGroup.configure do |config|
2
+ config.ftp_host = "ftp.example.com"
3
+ config.submission_dir = File.join("htdocs", "eo", "incoming")
4
+ config.vendor_email = "admin@example.com"
5
+ end
data/lib/rsr_group.rb CHANGED
@@ -7,9 +7,37 @@ require 'net/ftp'
7
7
  require 'rsr_group/base'
8
8
  require 'rsr_group/department'
9
9
  require 'rsr_group/inventory'
10
+ require 'rsr_group/order'
11
+ require 'rsr_group/order_detail'
12
+ require 'rsr_group/order_ffl'
13
+ require 'rsr_group/order_recipient'
10
14
  require 'rsr_group/user'
11
15
 
12
16
  module RsrGroup
13
17
  class NotAuthenticated < StandardError; end
14
18
  class UnknownDepartment < 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 :submission_dir
35
+ attr_accessor :vendor_email
36
+
37
+ def initialize
38
+ @ftp_host ||= "ftp.rsrgroup.com"
39
+ @submission_dir ||= File.join("eo", "incoming")
40
+ @vendor_email ||= nil
41
+ end
42
+ end
15
43
  end
@@ -1,13 +1,22 @@
1
1
  module RsrGroup
2
2
  class Base
3
3
 
4
- FTP_HOST = 'ftp.rsrgroup.com'
4
+ SHIPPING_CARRIERS = %w(UPS USPS)
5
+
6
+ SHIPPING_METHODS = {
7
+ "Grnd" => "Ground",
8
+ "1Day" => "Next Day Air",
9
+ "2Day" => "2nd Day Air",
10
+ "3Day" => "3 Day Select",
11
+ "NDam" => "Next Day Early AM",
12
+ "NDAS" => "Next Day Air Saver",
13
+ "PRIO" => "Priority"
14
+ }
5
15
 
6
16
  protected
7
17
 
8
- # Wrapper to `self.requires!` that can be used as an instance method.
9
- def requires!(*args)
10
- self.class.requires!(*args)
18
+ def self.ftp_host
19
+ RsrGroup.config.ftp_host
11
20
  end
12
21
 
13
22
  def self.requires!(hash, *params)
@@ -23,16 +32,22 @@ module RsrGroup
23
32
  end
24
33
  end
25
34
 
35
+ def ftp_host
36
+ self.class.ftp_host
37
+ end
38
+
39
+ # Wrapper to `self.requires!` that can be used as an instance method.
40
+ def requires!(*args)
41
+ self.class.requires!(*args)
42
+ end
43
+
26
44
  def connect(options = {})
27
45
  requires!(options, :username, :password)
28
46
 
29
- Net::FTP.open(FTP_HOST, options[:username], options[:password]) do |ftp|
47
+ Net::FTP.open(ftp_host, options[:username], options[:password]) do |ftp|
30
48
  ftp.passive = true
31
49
  yield ftp
32
50
  end
33
- # TODO: Disable this rescue for now, so we can figure out what's happening when used in an actual app.
34
- # rescue Net::FTPPermError
35
- # raise RsrGroup::NotAuthenticated
36
51
  end
37
52
 
38
53
  end
@@ -0,0 +1,84 @@
1
+ module RsrGroup
2
+ class Order < Base
3
+
4
+ attr_reader :credentials
5
+ attr_reader :identifier
6
+ attr_reader :timestamp
7
+ attr_reader :sequence_number
8
+ attr_accessor :recipients
9
+
10
+ LINE_TYPES = {
11
+ "00" => "file_header",
12
+ "10" => "order_header",
13
+ "11" => "ffl_dealer",
14
+ "20" => "order_detail",
15
+ "90" => "order_trailer",
16
+ "99" => "file_trailer"
17
+ }
18
+
19
+ def initialize(options = {})
20
+ requires!(options, :sequence_number, :username, :password, :identifier)
21
+
22
+ @credentials = options.select { |k, v| [:username, :password].include?(k) }
23
+ @identifier = options[:identifier]
24
+ @sequence_number = "%04d" % options[:sequence_number] # Leading zeros are required
25
+ @timestamp = Time.now.strftime("%Y%m%e")
26
+ @recipients = options[:recipients] || []
27
+ end
28
+
29
+ def header
30
+ ["FILEHEADER", LINE_TYPES.key("file_header"), customer_number, @timestamp, @sequence_number].join(";")
31
+ end
32
+
33
+ def footer
34
+ ["FILETRAILER", LINE_TYPES.key("file_trailer"), ("%05d" % recipients.length)].join(";")
35
+ end
36
+
37
+ def filename
38
+ name = ["EORD", customer_number, timestamp, sequence_number].join("-")
39
+ [name, ".txt"].join
40
+ end
41
+
42
+ def recipients
43
+ @recipients ||= []
44
+ end
45
+
46
+ def to_txt
47
+ txt = header + "\n"
48
+ recipients.each do |recipient|
49
+ txt += (recipient.to_single_line + "\n")
50
+ if recipient.ffl
51
+ txt += (recipient.ffl.to_single_line + "\n")
52
+ end
53
+ recipient.items.each do |item|
54
+ txt += (item.to_single_line + "\n")
55
+ end
56
+ txt += recipient.trailer + "\n"
57
+ end
58
+ txt += footer
59
+ end
60
+
61
+ def submit!
62
+ connect(@credentials) do |ftp|
63
+ ftp.chdir(RsrGroup.config.submission_dir)
64
+ io = StringIO.new(to_txt)
65
+ begin
66
+ ftp.storlines("STOR " + filename, io)
67
+ ensure
68
+ io.close
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def customer_number
76
+ credentials[:username]
77
+ end
78
+
79
+ def items
80
+ recipients.map(&:items).flatten.compact
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,29 @@
1
+ module RsrGroup
2
+ class OrderDetail < Base
3
+
4
+ attr_reader :order_identifier
5
+ attr_reader :quantity
6
+
7
+ def initialize(options = {})
8
+ requires!(options, :order_identifier, :rsr_stock_number, :quantity, :shipping_carrier, :shipping_method)
9
+
10
+ @order_identifier = options[:order_identifier]
11
+ @rsr_stock_number = options[:rsr_stock_number]
12
+ @quantity = (options[:quantity].is_a?(Integer) ? ("%05d" % options[:quantity]) : options[:quantity])
13
+ @shipping_carrier = options[:shipping_carrier]
14
+ @shipping_method = options[:shipping_method]
15
+ end
16
+
17
+ def to_single_line
18
+ [
19
+ order_identifier,
20
+ Order::LINE_TYPES.key("order_detail"),
21
+ @rsr_stock_number,
22
+ @quantity,
23
+ @shipping_carrier,
24
+ @shipping_method
25
+ ].join(";")
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ module RsrGroup
2
+ class OrderFFL < Base
3
+
4
+ attr_reader :order_identifier
5
+
6
+ def initialize(options = {})
7
+ requires!(options, :order_identifier, :licence_number, :name, :zip)
8
+
9
+ @options = options
10
+ @order_identifier = options[:order_identifier]
11
+ end
12
+
13
+ def to_single_line
14
+ [
15
+ order_identifier,
16
+ Order::LINE_TYPES.key("ffl_dealer"),
17
+ @options[:licence_number],
18
+ @options[:name],
19
+ @options[:zip],
20
+ ].join(";")
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,55 @@
1
+ module RsrGroup
2
+ class OrderRecipient < Base
3
+
4
+ attr_reader :order_identifier
5
+ attr_accessor :ffl
6
+ attr_accessor :items
7
+
8
+ def initialize(options = {})
9
+ requires!(options, :order_identifier, :shipping_name, :address_one, :city, :state, :zip)
10
+
11
+ @ffl = options[:ffl]
12
+ @items = options[:items] || []
13
+ @options = options
14
+ @order_identifier = options[:order_identifier]
15
+ end
16
+
17
+ def items
18
+ @items ||= []
19
+ end
20
+
21
+ def to_single_line
22
+ [
23
+ order_identifier,
24
+ Order::LINE_TYPES.key("order_header"),
25
+ @options[:shipping_name],
26
+ @options[:attn],
27
+ @options[:address_one],
28
+ @options[:address_two],
29
+ @options[:city],
30
+ @options[:state],
31
+ @options[:zip],
32
+ @options[:phone],
33
+ (@options[:email].nil? ? "N" : "Y"),
34
+ @options[:email],
35
+ RsrGroup.config.vendor_email,
36
+ nil
37
+ ].join(";")
38
+ end
39
+
40
+ def trailer
41
+ [
42
+ order_identifier,
43
+ Order::LINE_TYPES.key("order_trailer"),
44
+ ("%07d" % quantity_sum)
45
+ ].join(";")
46
+ end
47
+
48
+ private
49
+
50
+ def quantity_sum
51
+ items.map(&:quantity).map(&:to_i).inject(:+)
52
+ end
53
+
54
+ end
55
+ end
@@ -1,3 +1,3 @@
1
1
  module RsrGroup
2
- VERSION = "0.1.6"
2
+ VERSION = "1.0.0.pre"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsr_group
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 1.0.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Campbell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-15 00:00:00.000000000 Z
11
+ date: 2016-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,10 +84,15 @@ files:
84
84
  - Rakefile
85
85
  - bin/console
86
86
  - bin/setup
87
+ - config.rb.example
87
88
  - lib/rsr_group.rb
88
89
  - lib/rsr_group/base.rb
89
90
  - lib/rsr_group/department.rb
90
91
  - lib/rsr_group/inventory.rb
92
+ - lib/rsr_group/order.rb
93
+ - lib/rsr_group/order_detail.rb
94
+ - lib/rsr_group/order_ffl.rb
95
+ - lib/rsr_group/order_recipient.rb
91
96
  - lib/rsr_group/user.rb
92
97
  - lib/rsr_group/version.rb
93
98
  - rsr_group.gemspec
@@ -106,9 +111,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
111
  version: '2.0'
107
112
  required_rubygems_version: !ruby/object:Gem::Requirement
108
113
  requirements:
109
- - - ">="
114
+ - - ">"
110
115
  - !ruby/object:Gem::Version
111
- version: '0'
116
+ version: 1.3.1
112
117
  requirements: []
113
118
  rubyforge_project:
114
119
  rubygems_version: 2.6.7