economic-rest 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/Gemfile.lock +98 -96
- data/README.md +87 -1
- data/economic-rest.gemspec +6 -7
- data/lib/economic/accounting_year_repo.rb +2 -0
- data/lib/economic/attribute.rb +9 -0
- data/lib/economic/base_repo.rb +7 -12
- data/lib/economic/configuration.rb +7 -0
- data/lib/economic/credentials.rb +26 -0
- data/lib/economic/customer_contact_repo.rb +2 -0
- data/lib/economic/customer_repo.rb +2 -0
- data/lib/economic/invoice.rb +0 -25
- data/lib/economic/invoices/booked_repo.rb +1 -1
- data/lib/economic/invoices/drafts_repo.rb +2 -0
- data/lib/economic/invoices/repo.rb +1 -1
- data/lib/economic/line.rb +0 -21
- data/lib/economic/model.rb +99 -0
- data/lib/economic/models/accounting_year.rb +9 -0
- data/lib/economic/models/attention.rb +8 -0
- data/lib/economic/models/customer.rb +41 -0
- data/lib/economic/models/customer_group.rb +11 -0
- data/lib/economic/models/customers/contact.rb +19 -0
- data/lib/economic/models/invoice.rb +32 -0
- data/lib/economic/models/invoices/booked.rb +11 -0
- data/lib/economic/models/invoices/draft.rb +9 -0
- data/lib/economic/models/layout.rb +9 -0
- data/lib/economic/models/line.rb +21 -0
- data/lib/economic/models/note.rb +9 -0
- data/lib/economic/models/payment_term.rb +10 -0
- data/lib/economic/models/product.rb +22 -0
- data/lib/economic/models/recipient.rb +17 -0
- data/lib/economic/models/reference.rb +11 -0
- data/lib/economic/models/sales_person.rb +7 -0
- data/lib/economic/models/unit.rb +8 -0
- data/lib/economic/models/vat_zone.rb +10 -0
- data/lib/economic/models/vendor_reference.rb +7 -0
- data/lib/economic/nested_base_repo.rb +0 -5
- data/lib/economic/orders/repo.rb +1 -1
- data/lib/economic/relation.rb +17 -0
- data/lib/economic/repo.rb +127 -0
- data/lib/economic/repos/accounting_year.rb +6 -0
- data/lib/economic/repos/customer.rb +6 -0
- data/lib/economic/repos/customers/contact.rb +21 -0
- data/lib/economic/repos/invoices/booked.rb +19 -0
- data/lib/economic/repos/invoices/draft.rb +8 -0
- data/lib/economic/repos/invoices/drafts/line.rb +26 -0
- data/lib/economic/response/pagination.rb +16 -0
- data/lib/economic/response.rb +51 -0
- data/lib/economic/rest/version.rb +1 -1
- data/lib/economic/rest.rb +41 -6
- metadata +52 -34
- data/lib/economic/concerns/soap_methods.rb +0 -217
- data/lib/economic/soap_api.rb +0 -24
@@ -0,0 +1,99 @@
|
|
1
|
+
module Economic
|
2
|
+
class Model
|
3
|
+
class << self
|
4
|
+
def field(name, as: nil)
|
5
|
+
(@attributes ||= []) << Attribute.new(name:, as:)
|
6
|
+
attr_accessor name
|
7
|
+
end
|
8
|
+
|
9
|
+
def relation(name, as: nil, multiple: false, klass: nil)
|
10
|
+
(@relations ||= []) << Relation.new(name:, as:, multiple:, klass:)
|
11
|
+
attr_accessor name
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_json(json)
|
15
|
+
from_hash(JSON.parse(json))
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_hash(hash)
|
19
|
+
translated_attributes = translate_attributes(hash)
|
20
|
+
translated_relations = translate_relations(hash, translated_attributes)
|
21
|
+
new(**translated_relations)
|
22
|
+
end
|
23
|
+
|
24
|
+
def translate_attributes(hash)
|
25
|
+
economic_attribute_names = attributes.map(&:economic_name)
|
26
|
+
attributes_hash = hash.slice(*economic_attribute_names)
|
27
|
+
|
28
|
+
attributes_hash.each_with_object({}) do |(key, value), result|
|
29
|
+
attribute = attributes.find { |attr| attr.as.to_s == key || attr.name.to_s.camelize(:lower) == key }
|
30
|
+
result[attribute.name] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def translate_relations(hash, translated_attributes)
|
35
|
+
return translated_attributes unless relations&.any?
|
36
|
+
|
37
|
+
economic_relation_names = relations.map(&:economic_name)
|
38
|
+
relations_hash = hash.slice(*economic_relation_names)
|
39
|
+
|
40
|
+
relations_hash.each_with_object(translated_attributes) do |(key, value), result|
|
41
|
+
relation = relations.find { |rel| rel.as.to_s == key || rel.name.to_s.camelize(:lower) == key }
|
42
|
+
result[relation.name] = relation.multiple? ? value.map { relation.klass.from_hash(_1) } : relation.klass.from_hash(value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def inherited(subclass)
|
47
|
+
return if self == Economic::Model
|
48
|
+
|
49
|
+
attributes.each do |attribute|
|
50
|
+
subclass.attributes << attribute
|
51
|
+
end
|
52
|
+
relations.each do |relation|
|
53
|
+
subclass.relations << relation
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def attributes
|
58
|
+
@attributes ||= []
|
59
|
+
end
|
60
|
+
|
61
|
+
def relations
|
62
|
+
@relations ||= []
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(**kwargs)
|
67
|
+
valid_keys = self.class.attributes.map(&:name) + (self.class.relations&.map(&:name) || [])
|
68
|
+
invalid_keys = kwargs.keys - valid_keys
|
69
|
+
raise ArgumentError, "invalid keys: #{invalid_keys.join(", ")}" unless invalid_keys.empty?
|
70
|
+
|
71
|
+
self.class.attributes.each { |attribute| instance_variable_set :"@#{attribute.name}", kwargs[attribute.name] }
|
72
|
+
self.class.relations&.each { |relation| instance_variable_set :"@#{relation.name}", relation_value(relation, kwargs) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_h
|
76
|
+
result = {}
|
77
|
+
self.class.attributes.each_with_object(result) { |attribute, hash| hash[attribute.economic_name] = instance_variable_get :"@#{attribute.name}" }
|
78
|
+
self.class.relations&.each_with_object(result) { |relation, hash| hash[relation.economic_name] = relation_to_h(relation) }
|
79
|
+
result.compact
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_json
|
83
|
+
to_h.to_json
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def relation_value(relation, kwargs)
|
89
|
+
relation.multiple? ? (kwargs[relation.name] || []) : kwargs[relation.name]
|
90
|
+
end
|
91
|
+
|
92
|
+
def relation_to_h(relation)
|
93
|
+
value = instance_variable_get(:"@#{relation.name}")
|
94
|
+
return if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
95
|
+
|
96
|
+
relation.multiple? ? value.map(&:to_h) : value.to_h
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
class Customer < Economic::Model
|
4
|
+
field :id, as: :customerNumber
|
5
|
+
field :address
|
6
|
+
field :balance
|
7
|
+
field :barred
|
8
|
+
field :city
|
9
|
+
field :contacts
|
10
|
+
field :corporate_identification_number
|
11
|
+
field :country
|
12
|
+
field :credit_limit
|
13
|
+
field :currency
|
14
|
+
field :delivery_locations
|
15
|
+
field :due_amount
|
16
|
+
field :ean
|
17
|
+
field :email
|
18
|
+
field :last_updated
|
19
|
+
field :name
|
20
|
+
field :mobile_phone
|
21
|
+
field :p_number
|
22
|
+
field :public_entry_number
|
23
|
+
field :telephone_and_fax_number
|
24
|
+
field :vat_number
|
25
|
+
field :website
|
26
|
+
field :zip
|
27
|
+
|
28
|
+
# field :attention
|
29
|
+
# field :customer_contact
|
30
|
+
relation :customer_group
|
31
|
+
# field :default_delivery_location
|
32
|
+
# field :invoices
|
33
|
+
# relation :layout
|
34
|
+
relation :payment_terms
|
35
|
+
# field :sales_person
|
36
|
+
# field :templates
|
37
|
+
# field :totals
|
38
|
+
relation :vat_zone
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
module Customers
|
4
|
+
class Contact < Economic::Model
|
5
|
+
field :id, as: :customerContactNumber
|
6
|
+
field :deleted
|
7
|
+
field :e_invoice_id
|
8
|
+
field :email
|
9
|
+
field :email_notifications
|
10
|
+
field :name
|
11
|
+
field :notes
|
12
|
+
field :phone
|
13
|
+
field :sort_key
|
14
|
+
|
15
|
+
relation :customer
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
class Invoice < Economic::Model
|
4
|
+
field :currency
|
5
|
+
field :date
|
6
|
+
field :due_date
|
7
|
+
field :exchange_rate
|
8
|
+
field :gross_amount
|
9
|
+
field :gross_amount_in_base_currency
|
10
|
+
field :margin_in_base_currency
|
11
|
+
field :margin_percentage
|
12
|
+
field :net_amount
|
13
|
+
field :rounding_amount
|
14
|
+
field :vat_amount
|
15
|
+
field :remainder
|
16
|
+
field :cost_price_in_base_currency
|
17
|
+
field :net_amount_in_base_currency
|
18
|
+
|
19
|
+
relation :lines, multiple: true
|
20
|
+
relation :customer
|
21
|
+
relation :payment_terms
|
22
|
+
relation :recipient
|
23
|
+
relation :notes
|
24
|
+
relation :references
|
25
|
+
relation :layout
|
26
|
+
# relation :delivery
|
27
|
+
# relation :delivery_location
|
28
|
+
# relation :pdf
|
29
|
+
# relation :project
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
class Line < Economic::Model
|
4
|
+
field :id, as: :lineNumber
|
5
|
+
field :description
|
6
|
+
field :sort_key
|
7
|
+
field :quantity
|
8
|
+
field :unit_net_price
|
9
|
+
field :discount_percentage
|
10
|
+
field :unit_cost_price
|
11
|
+
field :margin_in_base_currency
|
12
|
+
field :margin_percentage
|
13
|
+
field :total_net_amount
|
14
|
+
|
15
|
+
relation :product
|
16
|
+
relation :unit
|
17
|
+
# relation :delivery
|
18
|
+
# relation :departmental_distribution
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
class Product < Economic::Model
|
4
|
+
field :id, as: :productNumber
|
5
|
+
field :bar_code
|
6
|
+
field :barred
|
7
|
+
field :cost_price
|
8
|
+
field :description
|
9
|
+
field :last_updated
|
10
|
+
field :name
|
11
|
+
field :recommended_price
|
12
|
+
field :sales_price
|
13
|
+
|
14
|
+
# field :departmental_distribution
|
15
|
+
# relation :inventory
|
16
|
+
# field :invoices
|
17
|
+
# field :pricing
|
18
|
+
# relation :product_group
|
19
|
+
# relation :unit
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Economic
|
2
|
+
module Models
|
3
|
+
class Recipient < Economic::Model
|
4
|
+
field :address
|
5
|
+
field :name
|
6
|
+
field :city
|
7
|
+
field :country
|
8
|
+
field :ean
|
9
|
+
field :mobile_phone
|
10
|
+
field :public_entry_number
|
11
|
+
field :zip
|
12
|
+
|
13
|
+
relation :vat_zone
|
14
|
+
relation :attention
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -17,11 +17,6 @@ module Economic
|
|
17
17
|
"#{kebab(model.class.name.demodulize.pluralize)}/#{model.id_key}/#{endpoint_name}"
|
18
18
|
end
|
19
19
|
|
20
|
-
def send(model, on:)
|
21
|
-
warn "use #{self}.save(). #{self}.send() is deprecated"
|
22
|
-
save(model, on: on)
|
23
|
-
end
|
24
|
-
|
25
20
|
def save(model, on:)
|
26
21
|
super(model, url: nested_endpoint_url(on))
|
27
22
|
end
|
data/lib/economic/orders/repo.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Economic
|
2
|
+
class Relation < Data.define(:name, :as, :multiple, :klass)
|
3
|
+
def economic_name
|
4
|
+
return as.to_s unless as.to_s.blank?
|
5
|
+
|
6
|
+
name.to_s.camelize(:lower)
|
7
|
+
end
|
8
|
+
|
9
|
+
def klass
|
10
|
+
super&.constantize || "Economic::Models::#{name.to_s.classify}".constantize
|
11
|
+
end
|
12
|
+
|
13
|
+
def multiple?
|
14
|
+
multiple
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Economic
|
2
|
+
class Repo
|
3
|
+
ROOT = "https://restapi.e-conomic.com".freeze
|
4
|
+
DEFAULT_QUERY_PARAMS = {skippages: 0, pagesize: 1000}.freeze
|
5
|
+
|
6
|
+
def initialize(credentials: Economic::Credentials.fetch!)
|
7
|
+
@credentials = credentials
|
8
|
+
raise Economic::MissingCredentialsError if credentials.missing?
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :credentials
|
12
|
+
|
13
|
+
def all(filter: nil)
|
14
|
+
response = make_request(method: :get, query: {filter:})
|
15
|
+
|
16
|
+
entries = response.collection
|
17
|
+
while response.pagination.next_page?
|
18
|
+
uri = build_uri(response.pagination.next_page)
|
19
|
+
response = make_request(uri:, method: :get)
|
20
|
+
entries += response.collection
|
21
|
+
end
|
22
|
+
|
23
|
+
entries
|
24
|
+
end
|
25
|
+
|
26
|
+
def find(id_or_model)
|
27
|
+
make_request(id_or_model:, method: :get).entity
|
28
|
+
end
|
29
|
+
|
30
|
+
def create(model)
|
31
|
+
make_request(method: :post, data: model).entity
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(model)
|
35
|
+
make_request(id_or_model: model, method: :put, data: model).entity
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy(id_or_model)
|
39
|
+
make_request(id_or_model:, method: :delete)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def make_request(method:, uri: url, id_or_model: nil, data: nil, query: nil)
|
45
|
+
uri = build_uri(uri, id_or_model:, query:)
|
46
|
+
request = build_request(uri)
|
47
|
+
args = [method, uri, data&.to_json, headers].compact
|
48
|
+
response = request.public_send(*args)
|
49
|
+
|
50
|
+
parse_response(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_request(uri)
|
54
|
+
http = Net::HTTP.new(uri.hostname, Net::HTTP.https_default_port)
|
55
|
+
http.use_ssl = true
|
56
|
+
|
57
|
+
http
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_uri(uri, id_or_model: nil, query: nil)
|
61
|
+
uri = id_or_model.present? ? "#{uri}/#{id_or_model.try(:id) || id_or_model}" : uri
|
62
|
+
uri = URI(uri)
|
63
|
+
uri.query = URI.encode_www_form(query.with_defaults(DEFAULT_QUERY_PARAMS).compact) if query.present?
|
64
|
+
|
65
|
+
uri
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_response(response)
|
69
|
+
case response.code
|
70
|
+
when "200", "201"
|
71
|
+
Economic::Response.from_json(response.body)
|
72
|
+
when "204"
|
73
|
+
true
|
74
|
+
when "400"
|
75
|
+
raise BadRequestError, response.body
|
76
|
+
when "401"
|
77
|
+
raise UnauthorizedError, response.body
|
78
|
+
when "403"
|
79
|
+
raise ForbiddenError, response.body
|
80
|
+
when "404"
|
81
|
+
raise NotFoundError, response.body
|
82
|
+
when "500"
|
83
|
+
raise InternalError, response.body
|
84
|
+
else
|
85
|
+
raise Error, "#{response.code} - #{response.body}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def url
|
90
|
+
"#{ROOT}/#{endpoint}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def endpoint
|
94
|
+
resource_name.pluralize.underscore.dasherize
|
95
|
+
end
|
96
|
+
|
97
|
+
def resource_name
|
98
|
+
self.class.to_s[17..]
|
99
|
+
end
|
100
|
+
|
101
|
+
def headers
|
102
|
+
{
|
103
|
+
"X-AppSecretToken": credentials.app_secret_token,
|
104
|
+
"X-AgreementGrantToken": credentials.agreement_grant_token,
|
105
|
+
"Content-Type": "application/json"
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class BadRequestError < StandardError
|
111
|
+
end
|
112
|
+
|
113
|
+
class UnauthorizedError < StandardError
|
114
|
+
end
|
115
|
+
|
116
|
+
class ForbiddenError < StandardError
|
117
|
+
end
|
118
|
+
|
119
|
+
class NotFoundError < StandardError
|
120
|
+
end
|
121
|
+
|
122
|
+
class InternalError < StandardError
|
123
|
+
end
|
124
|
+
|
125
|
+
class Error < StandardError
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Economic
|
2
|
+
module Repos
|
3
|
+
module Customers
|
4
|
+
class Contact < Economic::Repo
|
5
|
+
def initialize(parent, credentials: Economic::Credentials.fetch!)
|
6
|
+
@parent = parent
|
7
|
+
super(credentials:)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attr_reader :parent
|
13
|
+
|
14
|
+
def endpoint
|
15
|
+
fragments = resource_name.pluralize.underscore.dasherize.split("/")
|
16
|
+
fragments.insert(1, "/#{parent.id}/").join
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Economic
|
2
|
+
module Repos
|
3
|
+
module Invoices
|
4
|
+
class Booked < Economic::Repo
|
5
|
+
def create(model, send_by: nil)
|
6
|
+
hash = model.to_h
|
7
|
+
hash[:sendBy] = send_by if send_by.to_s == "ean"
|
8
|
+
super(hash)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def endpoint
|
14
|
+
resource_name.underscore.dasherize
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Economic
|
2
|
+
module Repos
|
3
|
+
module Invoices
|
4
|
+
module Drafts
|
5
|
+
class Line < Economic::Repo
|
6
|
+
def create(draft_invoice_model_or_id, lines)
|
7
|
+
draft_invoice_id = draft_invoice_model_or_id.try(:id) || draft_invoice_model_or_id
|
8
|
+
draft_invoice = Economic::Models::Invoices::Draft.new(lines: lines)
|
9
|
+
|
10
|
+
uri = URI("#{Economic::Repo::ROOT}/invoices/drafts/#{draft_invoice_id}/lines")
|
11
|
+
|
12
|
+
make_request(uri: uri, method: :post, data: draft_invoice)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def parse_response(response)
|
18
|
+
JSON.parse(response.body)["lines"].map do |line_data|
|
19
|
+
Economic::Models::Line.from_hash(**line_data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Economic
|
2
|
+
class Response::Pagination < Economic::Model
|
3
|
+
field :max_page_size_allowed
|
4
|
+
field :skip_pages
|
5
|
+
field :page_size
|
6
|
+
field :results
|
7
|
+
field :results_without_filter
|
8
|
+
field :first_page
|
9
|
+
field :next_page
|
10
|
+
field :last_page
|
11
|
+
|
12
|
+
def next_page?
|
13
|
+
next_page.present?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|