dear_inventory 0.2.0

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.
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