dear_inventory 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +2 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +5 -0
  5. data/.rubocop.yml +84 -0
  6. data/.travis.yml +7 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +69 -0
  11. data/Rakefile +8 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/dear_inventory.gemspec +45 -0
  15. data/lib/dear_inventory.rb +79 -0
  16. data/lib/dear_inventory/config.rb +55 -0
  17. data/lib/dear_inventory/environment.rb +54 -0
  18. data/lib/dear_inventory/error.rb +16 -0
  19. data/lib/dear_inventory/errors/request.rb +40 -0
  20. data/lib/dear_inventory/errors/validation.rb +6 -0
  21. data/lib/dear_inventory/lib/date_time.rb +18 -0
  22. data/lib/dear_inventory/lib/endpoint_class.rb +57 -0
  23. data/lib/dear_inventory/lib/is_a_subclass.rb +19 -0
  24. data/lib/dear_inventory/model.rb +98 -0
  25. data/lib/dear_inventory/models/additional_attributes.rb +53 -0
  26. data/lib/dear_inventory/models/additional_charge.rb +45 -0
  27. data/lib/dear_inventory/models/address.rb +45 -0
  28. data/lib/dear_inventory/models/attachment.rb +33 -0
  29. data/lib/dear_inventory/models/inventory_movement.rb +29 -0
  30. data/lib/dear_inventory/models/sale.rb +217 -0
  31. data/lib/dear_inventory/models/sale_list.rb +133 -0
  32. data/lib/dear_inventory/models/sale_lists.rb +26 -0
  33. data/lib/dear_inventory/models/sales/credit_note.rb +75 -0
  34. data/lib/dear_inventory/models/sales/fulfilment.rb +46 -0
  35. data/lib/dear_inventory/models/sales/fulfilments/pick_pack.rb +26 -0
  36. data/lib/dear_inventory/models/sales/fulfilments/pick_pack_line.rb +57 -0
  37. data/lib/dear_inventory/models/sales/fulfilments/ship.rb +35 -0
  38. data/lib/dear_inventory/models/sales/fulfilments/ship_line.rb +45 -0
  39. data/lib/dear_inventory/models/sales/invoice.rb +86 -0
  40. data/lib/dear_inventory/models/sales/invoice_line.rb +19 -0
  41. data/lib/dear_inventory/models/sales/line.rb +59 -0
  42. data/lib/dear_inventory/models/sales/manual_journal.rb +24 -0
  43. data/lib/dear_inventory/models/sales/manual_journal_line.rb +35 -0
  44. data/lib/dear_inventory/models/sales/order.rb +49 -0
  45. data/lib/dear_inventory/models/sales/payment_line.rb +43 -0
  46. data/lib/dear_inventory/models/sales/quote.rb +50 -0
  47. data/lib/dear_inventory/models/shipping_address.rb +25 -0
  48. data/lib/dear_inventory/models/transaction.rb +41 -0
  49. data/lib/dear_inventory/parameters.rb +209 -0
  50. data/lib/dear_inventory/parameters/sale/index.rb +35 -0
  51. data/lib/dear_inventory/parameters/sale_list/index.rb +119 -0
  52. data/lib/dear_inventory/resource.rb +59 -0
  53. data/lib/dear_inventory/resources/sale.rb +22 -0
  54. data/lib/dear_inventory/resources/sale_list.rb +24 -0
  55. data/lib/dear_inventory/response.rb +75 -0
  56. data/lib/dear_inventory/validator.rb +61 -0
  57. data/lib/dear_inventory/validators/boolean.rb +18 -0
  58. data/lib/dear_inventory/validators/enum.rb +23 -0
  59. data/lib/dear_inventory/validators/guid.rb +27 -0
  60. data/lib/dear_inventory/validators/integer.rb +19 -0
  61. data/lib/dear_inventory/validators/required.rb +17 -0
  62. data/lib/dear_inventory/validators/string.rb +35 -0
  63. data/lib/dear_inventory/validators/time.rb +21 -0
  64. data/lib/dear_inventory/version.rb +6 -0
  65. data/sorbet/config +2 -0
  66. data/sorbet/rbi/gems/addressable.rbi +199 -0
  67. data/sorbet/rbi/gems/ast.rbi +48 -0
  68. data/sorbet/rbi/gems/byebug.rbi +1040 -0
  69. data/sorbet/rbi/gems/coderay.rbi +92 -0
  70. data/sorbet/rbi/gems/crack.rbi +48 -0
  71. data/sorbet/rbi/gems/domain_name.rbi +52 -0
  72. data/sorbet/rbi/gems/dotenv.rbi +68 -0
  73. data/sorbet/rbi/gems/ffi-compiler.rbi +27 -0
  74. data/sorbet/rbi/gems/ffi.rbi +560 -0
  75. data/sorbet/rbi/gems/hashdiff.rbi +66 -0
  76. data/sorbet/rbi/gems/http-cookie.rbi +93 -0
  77. data/sorbet/rbi/gems/http-form_data.rbi +76 -0
  78. data/sorbet/rbi/gems/http-parser.rbi +121 -0
  79. data/sorbet/rbi/gems/http.rbi +616 -0
  80. data/sorbet/rbi/gems/jaro_winkler.rbi +15 -0
  81. data/sorbet/rbi/gems/method_source.rbi +64 -0
  82. data/sorbet/rbi/gems/parallel.rbi +82 -0
  83. data/sorbet/rbi/gems/parser.rbi +857 -0
  84. data/sorbet/rbi/gems/pry-byebug.rbi +155 -0
  85. data/sorbet/rbi/gems/pry.rbi +1965 -0
  86. data/sorbet/rbi/gems/public_suffix.rbi +104 -0
  87. data/sorbet/rbi/gems/rainbow.rbi +118 -0
  88. data/sorbet/rbi/gems/rake.rbi +646 -0
  89. data/sorbet/rbi/gems/rspec-core.rbi +1732 -0
  90. data/sorbet/rbi/gems/rspec-expectations.rbi +388 -0
  91. data/sorbet/rbi/gems/rspec-mocks.rbi +820 -0
  92. data/sorbet/rbi/gems/rspec-support.rbi +269 -0
  93. data/sorbet/rbi/gems/rspec.rbi +15 -0
  94. data/sorbet/rbi/gems/rubocop-performance.rbi +277 -0
  95. data/sorbet/rbi/gems/rubocop-rspec.rbi +887 -0
  96. data/sorbet/rbi/gems/rubocop.rbi +6952 -0
  97. data/sorbet/rbi/gems/ruby-progressbar.rbi +305 -0
  98. data/sorbet/rbi/gems/unf.rbi +19 -0
  99. data/sorbet/rbi/gems/unicode-display_width.rbi +17 -0
  100. data/sorbet/rbi/gems/vcr.rbi +572 -0
  101. data/sorbet/rbi/gems/webmock.rbi +569 -0
  102. data/sorbet/rbi/hidden-definitions/errors.txt +11809 -0
  103. data/sorbet/rbi/hidden-definitions/hidden.rbi +20627 -0
  104. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
  105. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +276 -0
  106. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
  107. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
  108. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
  109. data/sorbet/rbi/todo.rbi +11 -0
  110. metadata +339 -0
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Parameters
6
+ module Sale
7
+ class Index < DearInventory::Parameters
8
+ extend T::Sig
9
+
10
+ fields({
11
+ id: {
12
+ property: :ID,
13
+ type: :String,
14
+ required: true,
15
+ },
16
+ combine_additional_charges: {
17
+ property: :CombineAdditionalCharges,
18
+ type: :Boolean,
19
+ required: false,
20
+ },
21
+ hide_inventory_movements: {
22
+ property: :HideInventoryMovements,
23
+ type: :Boolean,
24
+ required: false,
25
+ },
26
+ include_transactions: {
27
+ property: :IncludeTransactions,
28
+ type: :Boolean,
29
+ required: false,
30
+ },
31
+ })
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,119 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Parameters
6
+ module SaleList
7
+ class Index < DearInventory::Parameters
8
+ extend T::Sig
9
+
10
+ fields({
11
+ page: {
12
+ property: :Page,
13
+ type: :Integer,
14
+ required: false,
15
+ },
16
+ limit: {
17
+ property: :Limit,
18
+ type: :Integer,
19
+ required: false,
20
+ },
21
+ search: {
22
+ property: :Search,
23
+ type: :String,
24
+ required: false,
25
+ },
26
+ created_since: {
27
+ property: :CreatedSince,
28
+ type: :DateTime,
29
+ required: false,
30
+ },
31
+ updated_since: {
32
+ property: :UpdatedSince,
33
+ type: :DateTime,
34
+ required: false,
35
+ },
36
+ ship_by: {
37
+ property: :ShipBy,
38
+ type: :DateTime,
39
+ required: false,
40
+ },
41
+ quote_status: {
42
+ property: :QuoteStatus,
43
+ type: :Enum,
44
+ values: ["NOT AVAILABLE", "DRAFT", "AUTHORISED", "VOIDED"],
45
+ required: false,
46
+ },
47
+ order_status: {
48
+ property: :OrderStatus,
49
+ type: :Enum,
50
+ values: [
51
+ "NOT AVAILABLE", "DRAFT", "AUTHORISED", "VOIDED", "AUTH_NO_ALLOC",
52
+ "FULFILLED", "CLOSED"
53
+ ],
54
+ required: false,
55
+ },
56
+ combined_pick_status: {
57
+ property: :CombinedPickStatus,
58
+ type: :Enum,
59
+ values: [
60
+ "VOIDED", "NOT AVAILABLE", "PICKED", "PICKING", "NOT PICKED",
61
+ "PARTIALLY PICKED"
62
+ ],
63
+ required: false,
64
+ },
65
+ combined_pack_status: {
66
+ property: :CombinedPackStatus,
67
+ type: :Enum,
68
+ values: [
69
+ "VOIDED", "NOT AVAILABLE", "PACKED", "PACKING", "NOT PACKED",
70
+ "PARTIALLY PACKED"
71
+ ],
72
+ required: false,
73
+ },
74
+ combined_shipp_status: {
75
+ property: :CombinedShippStatus,
76
+ type: :Enum,
77
+ values: [
78
+ "VOIDED", "NOT AVAILABLE", "SHIPPED", "SHIPPING", "NOT SHIPPED",
79
+ "PARTIALLY SHIPPED"
80
+ ],
81
+ required: false,
82
+ },
83
+ combined_invoice_status: {
84
+ property: :CombinedInvoiceStatus,
85
+ type: :Enum,
86
+ values: ["VOIDED", "DRAFT", "AUTHORISED", "NOT AVAILABLE", "PAID"],
87
+ required: false,
88
+ },
89
+ credit_note_status: {
90
+ property: :CreditNoteStatus,
91
+ type: :Enum,
92
+ values: ["VOIDED", "DRAFT", "AUTHORISED", "NOT AVAILABLE"],
93
+ required: false,
94
+ },
95
+ external_id: {
96
+ property: :ExternalID,
97
+ type: :String,
98
+ required: false,
99
+ },
100
+ status: {
101
+ property: :Status,
102
+ type: :Enum,
103
+ values: %w[
104
+ DRAFT VOIDED ESTIMATING ESTIMATED ORDERING ORDERED BACKORDERED
105
+ PICKING PICKED PACKING PACKED SHIPPING INVOICING INVOICED CREDITED
106
+ COMPLETED
107
+ ],
108
+ required: false,
109
+ },
110
+ ready_for_shipping: {
111
+ property: :ReadyForShipping,
112
+ type: :Boolean,
113
+ required: false,
114
+ },
115
+ })
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,59 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Resource
6
+ extend T::Sig
7
+ extend DearInventory::IsASubclass
8
+
9
+ sig do
10
+ params(
11
+ action: Symbol,
12
+ model: T.class_of(DearInventory::Model),
13
+ endpoint: T.nilable(String),
14
+ params: T::Hash[Symbol, T.untyped]
15
+ ).returns(DearInventory::Response)
16
+ end
17
+ def request(action, model:, endpoint: nil, params: {})
18
+ url = resource_url(endpoint)
19
+ params = DearInventory::Parameters.convert(self.class, endpoint, params)
20
+ options = request_params(action, params)
21
+
22
+ response = HTTP.headers(headers).public_send(action, url, options)
23
+ DearInventory::Response.new(response: response, model: model)
24
+ end
25
+
26
+ private
27
+
28
+ URL_BASE = "https://inventory.dearsystems.com/ExternalApi/v2"
29
+
30
+ sig { params(endpoint: T.nilable(String)).returns(String) }
31
+ def resource_url(endpoint)
32
+ resource = T.must(self.class.name).split("::").last
33
+ url = "#{URL_BASE}/#{T.must(resource).downcase}"
34
+ url += "/#{endpoint}" unless endpoint.nil?
35
+ url
36
+ end
37
+
38
+ sig { returns(T::Hash[Symbol, String]) }
39
+ def headers
40
+ {
41
+ "Content-Type": "application/json",
42
+ "api-auth-accountid": DearInventory.config.require(:account_id),
43
+ "api-auth-applicationkey": DearInventory.config.require(:key),
44
+ }
45
+ end
46
+
47
+ sig do
48
+ params(action: Symbol, params: DearInventory::Parameters).
49
+ returns(T::Hash[Symbol, T.untyped])
50
+ end
51
+ def request_params(action, params)
52
+ if action == :get
53
+ { params: params.to_h }
54
+ else
55
+ { json: params.to_h }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Sale < Resource
6
+ class << self
7
+ extend T::Sig
8
+
9
+ # Sale
10
+ #
11
+ # @param params [Hash] URL query string parameters that conform to
12
+ # DearInventory::Parameters::Sale::Index
13
+ sig do
14
+ params(params: T::Hash[Symbol, T.untyped]).
15
+ returns(DearInventory::Response)
16
+ end
17
+ def index(params: {})
18
+ new.request(:get, params: params, model: DearInventory::Models::Sale)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class SaleList < Resource
6
+ class << self
7
+ extend T::Sig
8
+
9
+ # Sale List
10
+ #
11
+ # @param params [Hash] URL query string parameters that conform to
12
+ # DearInventory::Parameters::SaleList::Index
13
+ sig do
14
+ params(params: T::Hash[Symbol, T.untyped]).
15
+ returns(DearInventory::Response)
16
+ end
17
+ def index(params: {})
18
+ new.request(
19
+ :get, params: params, model: DearInventory::Models::SaleLists
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,75 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Response
6
+ extend T::Sig
7
+ extend DearInventory::IsASubclass
8
+
9
+ sig do
10
+ params(
11
+ model: T.class_of(DearInventory::Model),
12
+ response: HTTP::Response
13
+ ).void
14
+ end
15
+ def initialize(model:, response:)
16
+ @model = T.let(nil, T.nilable(DearInventory::Model))
17
+ @response = T.let(response, HTTP::Response)
18
+ @body = T.let(nil, T.nilable(String))
19
+ @http_status = T.let(nil, T.nilable(Integer))
20
+ @uri = T.let(nil, T.nilable(String))
21
+
22
+ assign_values(model)
23
+ raise_error unless success?
24
+ end
25
+
26
+ sig { returns(T.untyped) }
27
+ def body
28
+ @body ||= JSON.parse(@response.body.to_s)
29
+ end
30
+
31
+ sig { returns(T.nilable(String)) }
32
+ def error
33
+ # body.fetch("message", nil) if body.respond_to?(:fetch)
34
+ "Error goes here"
35
+ end
36
+
37
+ sig { returns(T::Hash[Symbol, String]) }
38
+ def headers
39
+ @response.headers
40
+ end
41
+
42
+ sig { returns(Integer) }
43
+ def http_status
44
+ @http_status ||= @response.status.code
45
+ end
46
+
47
+ sig { returns(T::Boolean) }
48
+ def success?
49
+ http_status == 200
50
+ end
51
+
52
+ sig { returns(String) }
53
+ def uri
54
+ @uri ||= @response.uri.to_s
55
+ end
56
+
57
+ private
58
+
59
+ sig { params(model: T.class_of(DearInventory::Model)).void }
60
+ def assign_values(model)
61
+ @model = model.new(body)
62
+ model.const_get(:FIELDS).each do |response_name, specifications|
63
+ define_singleton_method(specifications[:name]) do
64
+ @model.public_send(specifications[:name])
65
+ end
66
+ end
67
+ end
68
+
69
+ sig { returns(DearInventory::Error) }
70
+ def raise_error
71
+ raise T.unsafe(DearInventory::Error).
72
+ new("Unknown error (#{http_status}): #{error}", self)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,61 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ class Validator
6
+ extend T::Sig
7
+
8
+ extend T::Helpers
9
+ abstract!
10
+
11
+ DEFAULT_OPTIONS = T.let(
12
+ {
13
+ limit: nil,
14
+ max_length: nil,
15
+ values: nil,
16
+ }.freeze,
17
+ T::Hash[Symbol, T.nilable(T.any(Integer, T::Array[String]))]
18
+ )
19
+ private_constant :DEFAULT_OPTIONS
20
+
21
+ sig do
22
+ params(
23
+ field_name: Symbol,
24
+ value: T.nilable(T.any(Date, Numeric, String, T::Boolean, Time)),
25
+ options: T::Hash[Symbol, T.untyped]
26
+ ).void
27
+ end
28
+ def self.call(field_name, value, options: DEFAULT_OPTIONS)
29
+ new(field_name, value, options: options).call
30
+ end
31
+
32
+ sig do
33
+ params(
34
+ field_name: Symbol,
35
+ value: T.nilable(T.any(Date, Numeric, String, T::Boolean, Time)),
36
+ options: T::Hash[Symbol, T.untyped]
37
+ ).void
38
+ end
39
+ def initialize(field_name, value, options: DEFAULT_OPTIONS)
40
+ @field_name = T.let(field_name, Symbol)
41
+ @value =
42
+ T.let(value, T.nilable(T.any(Date, Numeric, String, T::Boolean, Time)))
43
+
44
+ @limit = T.let(options[:limit], T.nilable(Integer))
45
+ @max_length = T.let(options[:limit], T.nilable(Integer))
46
+ @values = T.let(options[:values], T.nilable(T::Array[String]))
47
+ end
48
+
49
+ private
50
+
51
+ sig { abstract.void }
52
+ def call; end
53
+
54
+ protected
55
+
56
+ sig { params(message: String).void }
57
+ def raise_error(message)
58
+ raise ValidationError, "#{@field_name} is invalid, #{message}"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ module Validators
6
+ class Boolean < DearInventory::Validator
7
+ extend T::Sig
8
+
9
+ sig { override.void }
10
+ def call
11
+ value = instance_variable_get(:@value)
12
+ return if [true, false, nil].include?(value)
13
+
14
+ raise_error("expected a Boolean but received #{value.inspect}")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module DearInventory
5
+ module Validators
6
+ class Enum < DearInventory::Validator
7
+ extend T::Sig
8
+
9
+ sig { override.void }
10
+ def call
11
+ value = instance_variable_get(:@value)
12
+ return if value.nil?
13
+ return if T.must(@values).include?(value)
14
+
15
+ raise_error(
16
+ "expected one of " \
17
+ "#{T.must(@values).map { |val| val.inspect }.join(", ")} " \
18
+ "but received #{value.inspect}"
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end