economic-rest 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4f478be083c1fa788177f69fc0bab5c60c175243d594a75ee6daacafd15027a
4
- data.tar.gz: 5bf39d0170a7339a082ff5c2454fde2f388b8a5260130fcc9cc73647cde74256
3
+ metadata.gz: 7fbacaa257420baadb45e16d45ad531689e6d14d3be3cdf6571ad0a8abc791d7
4
+ data.tar.gz: cd2f866670a486f601f63da4c8a1c5bdf40289db6caae73036f471aca8200818
5
5
  SHA512:
6
- metadata.gz: bcd925be4161f7c7e7b1557569275f8b10c24fea858cfe85399db97cbcf149a22258af71f29a5b086307ddfb1cc4874d52a36c99c883a0d132d13ea9b2b46f2b
7
- data.tar.gz: 914706cf3c7ea9175b682b0dcdb930c18abf502ccd06191d0d3645a88fa02da7d02a1d4c4a0e05195c1fec25b96f0fcce87fbc7f7343a8d78924b5c02f9296dc
6
+ metadata.gz: 0e923292ba32f2adf4832e261cfc38e6f3328cbdec42a19219b11c9133509a1e5e6fb15deb36ae169612dcb769edfde2058db848c42b0dfd0104de8c556252d7
7
+ data.tar.gz: 51e379f96f4907a9dfcdbd070fd3f8d6bb942456db674db9eb1e04faba186853cdf1b1a81d39fbf5bf55db031ebed3bbdbbb63047c137f5ff04fa4092cfb4bdb
data/.gitignore CHANGED
@@ -8,3 +8,6 @@
8
8
 
9
9
  # Ignore coverage
10
10
  /coverage
11
+
12
+ # Ignore environment variables
13
+ .env
@@ -0,0 +1,9 @@
1
+ {
2
+ "ruby.useLanguageServer": true,
3
+ "ruby.lint": {"standard": true},
4
+ "ruby.format": "standard",
5
+ "[ruby]": {
6
+ "editor.formatOnSave": true,
7
+ },
8
+ "editor.formatOnSaveTimeout": 1500,
9
+ }
data/Gemfile.lock CHANGED
@@ -1,23 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- economic-rest (0.3.5)
4
+ economic-rest (0.4.0)
5
+ activesupport
6
+ awesome_print
5
7
  rest-client
8
+ savon
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
13
+ activesupport (6.0.0)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 0.7, < 2)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ zeitwerk (~> 2.1, >= 2.1.8)
10
19
  addressable (2.5.2)
11
20
  public_suffix (>= 2.0.2, < 4.0)
21
+ akami (1.3.1)
22
+ gyoku (>= 0.4.0)
23
+ nokogiri
24
+ ast (2.4.0)
25
+ awesome_print (1.8.0)
26
+ builder (3.2.3)
27
+ concurrent-ruby (1.1.5)
12
28
  crack (0.4.3)
13
29
  safe_yaml (~> 1.0.0)
14
30
  docile (1.3.1)
15
31
  domain_name (0.5.20190701)
16
32
  unf (>= 0.0.5, < 1.0.0)
33
+ dotenv (2.7.4)
34
+ gyoku (1.3.1)
35
+ builder (>= 2.1.2)
17
36
  hashdiff (0.3.8)
18
37
  http-accept (1.7.0)
19
38
  http-cookie (1.0.3)
20
39
  domain_name (~> 0.5)
40
+ httpi (2.4.4)
41
+ rack
42
+ socksify
43
+ i18n (1.6.0)
44
+ concurrent-ruby (~> 1.0)
45
+ jaro_winkler (1.5.3)
21
46
  json (2.1.0)
22
47
  m (1.5.1)
23
48
  method_source (>= 0.6.7)
@@ -26,39 +51,80 @@ GEM
26
51
  mime-types (3.3)
27
52
  mime-types-data (~> 3.2015)
28
53
  mime-types-data (3.2019.0904)
54
+ mini_portile2 (2.4.0)
29
55
  minitest (5.11.3)
30
56
  netrc (0.11.0)
57
+ nokogiri (1.10.4)
58
+ mini_portile2 (~> 2.4.0)
59
+ nori (2.6.0)
60
+ parallel (1.17.0)
61
+ parser (2.6.4.1)
62
+ ast (~> 2.4.0)
31
63
  public_suffix (3.0.3)
64
+ rack (2.0.7)
65
+ rainbow (3.0.0)
32
66
  rake (10.5.0)
33
67
  rest-client (2.1.0)
34
68
  http-accept (>= 1.7.0, < 2.0)
35
69
  http-cookie (>= 1.0.2, < 2.0)
36
70
  mime-types (>= 1.16, < 4.0)
37
71
  netrc (~> 0.8)
72
+ rubocop (0.72.0)
73
+ jaro_winkler (~> 1.5.1)
74
+ parallel (~> 1.10)
75
+ parser (>= 2.6)
76
+ rainbow (>= 2.2.2, < 4.0)
77
+ ruby-progressbar (~> 1.7)
78
+ unicode-display_width (>= 1.4.0, < 1.7)
79
+ rubocop-performance (1.4.1)
80
+ rubocop (>= 0.71.0)
81
+ ruby-progressbar (1.10.1)
38
82
  safe_yaml (1.0.4)
83
+ savon (2.12.0)
84
+ akami (~> 1.2)
85
+ builder (>= 2.1.2)
86
+ gyoku (~> 1.2)
87
+ httpi (~> 2.3)
88
+ nokogiri (>= 1.8.1)
89
+ nori (~> 2.4)
90
+ wasabi (~> 3.4)
39
91
  simplecov (0.16.1)
40
92
  docile (~> 1.1)
41
93
  json (>= 1.8, < 3)
42
94
  simplecov-html (~> 0.10.0)
43
95
  simplecov-html (0.10.2)
96
+ socksify (1.7.1)
97
+ standard (0.1.4)
98
+ rubocop (~> 0.72.0)
99
+ rubocop-performance (~> 1.4.0)
100
+ thread_safe (0.3.6)
101
+ tzinfo (1.2.5)
102
+ thread_safe (~> 0.1)
44
103
  unf (0.1.4)
45
104
  unf_ext
46
105
  unf_ext (0.0.7.6)
106
+ unicode-display_width (1.6.0)
107
+ wasabi (3.5.0)
108
+ httpi (~> 2.0)
109
+ nokogiri (>= 1.4.2)
47
110
  webmock (3.5.1)
48
111
  addressable (>= 2.3.6)
49
112
  crack (>= 0.3.2)
50
113
  hashdiff
114
+ zeitwerk (2.1.10)
51
115
 
52
116
  PLATFORMS
53
117
  ruby
54
118
 
55
119
  DEPENDENCIES
56
120
  bundler (~> 1.17)
121
+ dotenv
57
122
  economic-rest!
58
123
  m
59
124
  minitest (~> 5.0)
60
125
  rake (~> 10.0)
61
126
  simplecov
127
+ standard
62
128
  webmock (~> 3.5)
63
129
 
64
130
  BUNDLED WITH
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Economic::Rest
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/economic/rest`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Build Status](https://semaphoreci.com/api/v1/traels-it/economic-rest/branches/master/badge.svg)](https://semaphoreci.com/traels-it/economic-rest)
4
4
 
5
5
  Ruby wrapper for the e-conomic REST API, that aims at making working with the API bearable.
6
6
  E-conomic is a web-based accounting system. For their marketing speak, see http://www.e-conomic.co.uk/about/. More details about their API at http://www.e-conomic.co.uk/integration/integration-partner/'.
@@ -25,33 +25,40 @@ Or install it yourself as:
25
25
 
26
26
  ## Usage
27
27
 
28
+ ```ruby
28
29
  require 'economic/rest'
29
30
 
30
31
  Economic::Demo.hello
32
+ ```
31
33
 
32
34
  Filter text can be added to the all query to avoid getting everything. e.g. a method for finding an accounting year for a specific date
33
35
 
36
+ ```ruby
34
37
  def get_accounting_year(date)
35
38
  Economic::AccountingYearRepo.all(filter_text: "toDate$gte:#{date}$and:fromDate$lte:#{date}")
36
39
  end
40
+ ```
37
41
 
38
42
  note: you need to use Lower Camel Case for variable names.
39
- Filter Operators
43
+
44
+ ### Filter Operators
40
45
 
41
46
  The allowed filtering operators are:
42
47
 
43
- Operator Syntax
44
- Equals “$eq:”
45
- Not equals “$ne:”
46
- Greater than “$gt:”
47
- Greater than or equal “$gte:”
48
- Less than “$lt:”
49
- Less than or equal “$lte:”
50
- Substring match “$like:”
51
- And also “$and:”
52
- Or else “$or:”
53
- In “$in:”
54
- Not In “$nin:”
48
+ | Operator | Syntax |
49
+ | -------- | --------- |
50
+ | Equals | `$eq:` |
51
+ | Not equals | `$ne:` |
52
+ | Greater than | `$gt:` |
53
+ | Greater than or equal | `$gte:` |
54
+ | Less than | `$lt:` |
55
+ | Less than or equal | `$lte:` |
56
+ | Substring match | `$like:` |
57
+ | And also | `$and:` |
58
+ | Or else | `$or:` |
59
+ | In | `$in:` |
60
+ | Not In | `$nin:` |
61
+
55
62
  copy pasta from https://restdocs.e-conomic.com/#specifying-operator-affinity
56
63
 
57
64
  ## Development
@@ -29,6 +29,11 @@ The documentation can be found at https://restdocs.e-conomic.com'
29
29
  spec.add_development_dependency "rake", "~> 10.0"
30
30
  spec.add_development_dependency "simplecov"
31
31
  spec.add_development_dependency "webmock", "~> 3.5"
32
+ spec.add_development_dependency "dotenv"
33
+ spec.add_development_dependency "standard"
32
34
 
35
+ spec.add_dependency "savon"
33
36
  spec.add_dependency "rest-client"
37
+ spec.add_dependency "activesupport"
38
+ spec.add_dependency "awesome_print"
34
39
  end
data/lib/economic/base.rb CHANGED
@@ -12,8 +12,8 @@ module Economic
12
12
  (@attributes ||= []).push(name)
13
13
  end
14
14
 
15
- def self.add_relation(name, fields)
16
- (@relations ||= []).push(name: name, fields: fields)
15
+ def self.add_relation(name, fields, multiple)
16
+ (@relations ||= []).push(name: name, fields: fields, multiple: multiple)
17
17
  end
18
18
 
19
19
  def self.field(name, id: false)
@@ -22,13 +22,19 @@ module Economic
22
22
  alias_method snake_case(economic_cased_attibute_name), economic_cased_attibute_name
23
23
  alias_method "#{snake_case(economic_cased_attibute_name)}=", "#{economic_cased_attibute_name}="
24
24
  alias_method "id_key", economic_cased_attibute_name if id
25
+ alias_method "id_key=", "#{economic_cased_attibute_name}=" if id
25
26
  add_attribute economic_cased_attibute_name
26
27
  end
27
28
 
28
- def self.relation(name, fields:)
29
+ def self.relation(name, fields:, multiple: false)
29
30
  economic_cased_attibute_name = name.to_s
30
- add_relation economic_cased_attibute_name, fields
31
- attr_reader economic_cased_attibute_name
31
+ add_relation economic_cased_attibute_name, fields, multiple
32
+ if multiple
33
+ attr_accessor economic_cased_attibute_name
34
+ alias_method "#{snake_case(economic_cased_attibute_name)}=", "#{economic_cased_attibute_name}="
35
+ else
36
+ attr_reader economic_cased_attibute_name
37
+ end
32
38
  alias_method snake_case(economic_cased_attibute_name), economic_cased_attibute_name
33
39
  end
34
40
 
@@ -39,10 +45,18 @@ module Economic
39
45
  end
40
46
 
41
47
  self.class.relations&.each do |relation_hash|
42
- name = relation_hash[:name]
43
- related_model = model_class(name).new(@internal_hash[name])
44
-
45
- instance_variable_set("@#{name}", related_model)
48
+ if relation_hash[:multiple]
49
+ relation_name = relation_hash[:name]
50
+ model_name = relation_hash[:name].singularize
51
+ related_model_array = @internal_hash[relation_name]&.map { |data|
52
+ model_class(model_name).new(data)
53
+ }
54
+ instance_variable_set("@#{relation_name}", related_model_array)
55
+ else
56
+ name = relation_hash[:name]
57
+ related_model = model_class(name).new(@internal_hash[name])
58
+ instance_variable_set("@#{name}", related_model)
59
+ end
46
60
  end
47
61
  end
48
62
 
@@ -56,12 +70,21 @@ module Economic
56
70
  end
57
71
 
58
72
  self.class.relations&.each do |relation_hash|
59
- relation_name = relation_hash[:name]
60
- relation_fields = relation_hash[:fields]
73
+ if relation_hash[:multiple]
74
+ relation_name = relation_hash[:name]
75
+ relation_fields = relation_hash[:fields]
76
+
77
+ arr = public_send(relation_name).map { |relation| relation_data = relation.to_h(only_fields: relation_fields) }
78
+
79
+ return_hash[relation_name] = arr
80
+ else
81
+ relation_name = relation_hash[:name]
82
+ relation_fields = relation_hash[:fields]
61
83
 
62
- relation_data = public_send(relation_name).to_h(only_fields: relation_fields)
84
+ relation_data = public_send(relation_name).to_h(only_fields: relation_fields)
63
85
 
64
- return_hash[relation_name] = relation_data unless relation_data.empty?
86
+ return_hash[relation_name] = relation_data unless relation_data.empty?
87
+ end
65
88
  end
66
89
  return_hash
67
90
  end
@@ -57,6 +57,12 @@ module Economic
57
57
 
58
58
  private
59
59
 
60
+ def destroy(id)
61
+ response = send_request(method: :delete, url: endpoint_url + "/" + id.to_s)
62
+
63
+ JSON.parse(response.body)["message"] == "Deleted #{model.to_s.split("::").last.downcase}."
64
+ end
65
+
60
66
  def model
61
67
  scopes = name.split("::")
62
68
  scopes[1] = scopes[1][0...-1] if scopes.count == 3
@@ -73,6 +79,9 @@ module Economic
73
79
  end
74
80
  end_p = end_p.gsub("Journals", "Journals-Experimental")
75
81
  end_p = end_p.gsub("Selfs", "Self")
82
+ # PaymentTerms is named with a plural s for a single record, but the end point is still just paymentterms.
83
+ # Therefore the endpoint gets substituted
84
+ end_p = end_p.gsub("PaymentTermss", "PaymentTerms")
76
85
  kebab(end_p)
77
86
  end
78
87
 
@@ -0,0 +1,183 @@
1
+ require "active_support/concern"
2
+
3
+ module Economic
4
+ module SoapMethods
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def find(id)
9
+ result = Economic::SoapAPI.call(
10
+ soap_method_names[:find][:method],
11
+ message: {soap_method_names[:find][:handle] => {Id: id}}
12
+ )
13
+
14
+ model.build_from_soap_api(result)
15
+ end
16
+
17
+ def all
18
+ result = Economic::SoapAPI.call(
19
+ soap_method_names[:all][:method],
20
+ )
21
+
22
+ ids = result_array(result[soap_method_names[:all][:handle]]).map { |record|
23
+ record[:id].to_i
24
+ }
25
+
26
+ find_all_records(ids)
27
+ end
28
+
29
+ def send(model)
30
+ # There is a current_invoice_create_from_data_array method for bulk creation of invoices as well, but bulk
31
+ # creation is not supported by the e-conomic REST api or any other REST api. To avoid implementing
32
+ # functionality that will be removed once e-conomic finish the REST api, we only use the standard create end
33
+ # point
34
+
35
+ result = Economic::SoapAPI.call(
36
+ soap_method_names[:send][:method], message: {
37
+ soap_method_names[:send][:handle] => {
38
+ Number: model.customer.customerNumber,
39
+ },
40
+ }
41
+ )
42
+
43
+ model.id_key = result[:id]
44
+
45
+ create_lines(model) if model.lines.any?
46
+
47
+ find(result[:id].to_i)
48
+ end
49
+
50
+ def find_lines(invoice_id)
51
+ result = Economic::SoapAPI.call(
52
+ soap_method_names[:find_lines][:method],
53
+ message: {soap_method_names[:find_lines][:handle] => {Id: invoice_id}}
54
+ )
55
+
56
+ return if result.nil?
57
+
58
+ line_ids = result_array(result[soap_method_names[:find_lines][:line_handle]]).map { |line|
59
+ line[:number].to_i
60
+ }
61
+
62
+ find_all_lines(invoice_id, line_ids)
63
+ end
64
+
65
+ def destroy(id)
66
+ # The SoapAPI raises an exception if the record you try to delete is missing
67
+
68
+ result = Economic::SoapAPI.call(
69
+ soap_method_names[:destroy][:method],
70
+ message: {soap_method_names[:destroy][:handle] => {Id: id}}
71
+ )
72
+
73
+ true
74
+ rescue Savon::SOAPFault
75
+ false
76
+ end
77
+
78
+ private
79
+
80
+ # Since the soap api returns hashes, if there is a single record, and arrays, if there are more, this method
81
+ # wraps a response in an array, if it is not already.
82
+ def result_array(result)
83
+ return result if result.is_a? Array
84
+
85
+ [result]
86
+ end
87
+
88
+ def create_lines(model)
89
+ Economic::SoapAPI.call(
90
+ soap_method_names[:create_lines][:method], message: {
91
+ dataArray: build_line_data_array(model),
92
+ }
93
+ )
94
+ end
95
+
96
+ def find_all_lines(invoice_id, line_ids)
97
+ result = Economic::SoapAPI.call(
98
+ soap_method_names[:find_all_lines][:method],
99
+ message: {soap_method_names[:find_all_lines][:handle] => line_ids_array(invoice_id, line_ids, handle: soap_method_names[:find_all_lines][:line_handle])}
100
+ )
101
+
102
+ result_array(result[soap_method_names[:find_all_lines][:data]]).map do |data|
103
+ Economic::Line.build_from_soap_api(data)
104
+ end
105
+ end
106
+
107
+ def find_all_records(invoice_ids)
108
+ result = Economic::SoapAPI.call(
109
+ soap_method_names[:find_all_records][:method],
110
+ message: {
111
+ entityHandles: ids_array(invoice_ids, handle: soap_method_names[:find_all_records][:handle]),
112
+ }
113
+ )
114
+
115
+ result[soap_method_names[:find_all_records][:data]].map do |data|
116
+ model.build_from_soap_api(data)
117
+ end
118
+ end
119
+
120
+ def line_ids_array(order_id, line_ids, handle:)
121
+ arr = [handle => []]
122
+
123
+ line_ids.each do |line_id|
124
+ arr.first[handle].push(
125
+ {
126
+ Id: order_id,
127
+ Number: line_id,
128
+ }
129
+ )
130
+ end
131
+
132
+ arr
133
+ end
134
+
135
+ def ids_array(invoice_ids, handle:)
136
+ arr = [handle => []]
137
+
138
+ invoice_ids.each do |invoice_id|
139
+ arr.first[handle].push(
140
+ {
141
+ Id: invoice_id,
142
+ }
143
+ )
144
+ end
145
+
146
+ arr
147
+ end
148
+
149
+ def build_line_data_array(order)
150
+ arr = [soap_method_names[:create_lines][:line_data_handle] => []]
151
+
152
+ order.lines.each do |line|
153
+ arr.first[soap_method_names[:create_lines][:line_data_handle]].push(
154
+ {
155
+ :Handle => {
156
+ Id: order.id_key,
157
+ Number: line.line_number, # must be sent - does not have to fit with the next linenumber
158
+ },
159
+ :Id => order.id_key,
160
+ :Number => line.line_number, # must be sent - does not have to fit with the next linenumber
161
+ soap_method_names[:create_lines][:model_handle] => {
162
+ Id: order.id_key,
163
+ },
164
+ :Description => line.description,
165
+ :DeliveryDate => line.delivery.delivery_date,
166
+ :UnitHandle => {Number: line.unit.unit_number},
167
+ :ProductHandle => {Number: line.product.product_number},
168
+ :Quantity => line.quantity,
169
+ :UnitNetPrice => line.unit_net_price,
170
+ :DiscountAsPercent => line.discount_percentage,
171
+ :UnitCostPrice => line.unit_cost_price,
172
+ :TotalNetAmount => line.total_net_amount, # TODO: Should this not be sent?
173
+ :TotalMargin => line.margin_in_base_currency,
174
+ :MarginAsPercent => line.margin_percentage,
175
+ }
176
+ )
177
+ end
178
+
179
+ arr
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,56 @@
1
+ module Economic
2
+ class Invoice < Base
3
+ # currency, customer, date, layout, paymentTerms, recipient, recipient.name, recipient.vatZone
4
+ field :currency
5
+ field :date
6
+ field :dueDate
7
+ field :exchangeRate
8
+ field :grossAmount
9
+ field :grossAmountInBaseCurrency
10
+ field :marginInBaseCurrency
11
+ field :marginPercentage
12
+ field :netAmount
13
+ field :roundingAmount
14
+ field :vatAmount
15
+ field :draftInvoiceNumber, id: true # This changes name depending on its type (draft, unpaid etc)
16
+
17
+ relation :customer, fields: [:customerNumber]
18
+ # relation :delivery, fields: []
19
+ # relation :deliveryLocation, fields: []
20
+ relation :layout, fields: [:layoutNumber]
21
+ # relation :notes, fields: []
22
+ relation :paymentTerms, fields: [:paymentTermsNumber]
23
+ # relation :pdf, fields: []
24
+ # relation :project, fields: []
25
+ relation :recipient, fields: [:name]
26
+ relation :references, fields: [:other]
27
+ relation :lines, fields: [:lineNumber], multiple: true
28
+
29
+ def self.build_from_soap_api(data)
30
+ hash = {
31
+ "currency" => data[:currency_handle][:code],
32
+ "date" => data[:date].to_date,
33
+ "dueDate" => data[:due_date].to_date,
34
+ "exchangeRate" => data[:exchange_rate],
35
+ "grossAmount" => data[:gross_amount],
36
+ # where is grossAmountInBaseCurrency?
37
+ "lines" => repo.find_lines(data[:handle][:id]),
38
+ "marginInBaseCurrency" => data[:margin],
39
+ "marginPercentage" => data[:margin_as_percent],
40
+ "netAmount" => data[:net_amount],
41
+ "roundingAmount" => data[:rounding_amount],
42
+ "vatAmount" => data[:vat_amount],
43
+ "draftInvoiceNumber" => data[:handle][:id], # TODO: What about id?
44
+ "customer" => {"customerNumber" => data[:debtor_handle][:id].to_i},
45
+ "layout" => {"layoutNumber" => data[:layout_handle][:id].to_i},
46
+ "paymentTerms" => {"paymentTermsNumber" => data[:term_of_payment_handle][:id].to_i},
47
+ }
48
+
49
+ new(hash)
50
+ end
51
+
52
+ def self.repo
53
+ Economic::Invoices::DraftsRepo
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class BookedRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,42 @@
1
+ module Economic
2
+ module Invoices
3
+ class DraftsRepo < Economic::Invoices::Repo
4
+ include Economic::SoapMethods
5
+
6
+ class << self
7
+ def soap_method_names
8
+ {
9
+ find: {method: :current_invoice_get_data, handle: :entityHandle},
10
+ all: {method: :current_invoice_get_all, handle: :current_invoice_handle},
11
+ send: {method: :current_invoice_create, handle: :debtorHandle},
12
+ find_lines: {
13
+ method: :current_invoice_get_lines,
14
+ handle: :currentInvoiceHandle,
15
+ line_handle: :current_invoice_line_handle,
16
+ },
17
+ create_lines: {
18
+ method: :current_invoice_line_create_from_data_array,
19
+ line_data_handle: :CurrentInvoiceLineData,
20
+ model_handle: :InvoiceHandle,
21
+ },
22
+ find_all_lines: {
23
+ method: :current_invoice_line_get_data_array,
24
+ handle: :entityHandles,
25
+ data: :current_invoice_line_data,
26
+ line_handle: :CurrentInvoiceLineHandle,
27
+ },
28
+ find_all_records: {
29
+ method: :current_invoice_get_data_array,
30
+ handle: :CurrentInvoiceHandle,
31
+ data: :current_invoice_data,
32
+ },
33
+ destroy: {
34
+ method: :current_invoice_delete,
35
+ handle: :currentInvoiceHandle,
36
+ },
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class NotDueRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class OverdueRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class PaidRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class Repo < Economic::BaseRepo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class SentRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Economic
2
+ module Invoices
3
+ class UnpaidRepo < Economic::Invoices::Repo
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,39 @@
1
+ module Economic
2
+ class Line < Base
3
+ field :lineNumber
4
+ field :description
5
+ field :sortKey
6
+ field :quantity
7
+ field :unitNetPrice
8
+ field :discountPercentage
9
+ field :unitCostPrice
10
+ field :marginInBaseCurrency
11
+ field :marginPercentage
12
+ field :totalNetAmount
13
+
14
+ relation :product, fields: [:productNumber]
15
+ relation :unit, fields: [:unitNumber, :name]
16
+ relation :delivery, fields: [:address, :zip, :city, :country, :deliveryDate]
17
+
18
+ def self.build_from_soap_api(data)
19
+ # This is not instantiated with the hash, as lines are never pulled out by themselves, but always as part of
20
+ # a invoice or order
21
+ {
22
+ "lineNumber" => data[:number].to_i,
23
+ "description" => data[:description],
24
+ "quantity" => data[:quantity].to_f,
25
+ "unitNetPrice" => data[:unit_net_price].to_f,
26
+ "discountPercentage" => data[:discount_as_percent].to_f,
27
+ "unitCostPrice" => data[:unit_cost_price].to_f,
28
+ "totalNetAmount" => data[:total_net_amount].to_f,
29
+ "marginPercentage" => data[:margin_as_percent].to_f,
30
+ "marginInBaseCurrency" => data[:total_margin].to_f,
31
+ "product" => {"productNumber" => data[:product_handle][:number]},
32
+ # Unmapped values in soap
33
+ # delivery_date
34
+ # :accrual_start_date => nil,
35
+ # :accrual_end_date => nil
36
+ }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,4 @@
1
+ module Economic
2
+ class PaymentTermsRepo < Economic::BaseRepo
3
+ end
4
+ end
data/lib/economic/rest.rb CHANGED
@@ -1,8 +1,14 @@
1
1
  require "economic/rest/version"
2
+ require "dotenv/load"
2
3
  require "rest-client"
4
+ require "savon"
5
+ require "awesome_print"
6
+ require "active_support/inflector"
3
7
 
4
8
  require "economic/base_repo"
5
9
  require "economic/base"
10
+ require "economic/soap_api"
11
+ require "economic/concerns/soap_methods"
6
12
 
7
13
  require "economic/currency"
8
14
  require "economic/vat_zone"
@@ -19,6 +25,7 @@ require "economic/layout"
19
25
  require "economic/layout_repo"
20
26
  require "economic/notes"
21
27
  require "economic/payment_terms"
28
+ require "economic/payment_terms_repo"
22
29
  require "economic/pdf"
23
30
  require "economic/project"
24
31
  require "economic/recipient"
@@ -38,6 +45,16 @@ require "economic/orders/drafts_repo"
38
45
  require "economic/orders/sent_repo"
39
46
  require "economic/product_group_repo"
40
47
 
48
+ require "economic/invoices/repo"
49
+ require "economic/invoice"
50
+ require "economic/invoices/drafts_repo"
51
+ require "economic/invoices/booked_repo"
52
+ require "economic/invoices/not_due_repo"
53
+ require "economic/invoices/overdue_repo"
54
+ require "economic/invoices/paid_repo"
55
+ require "economic/invoices/sent_repo"
56
+ require "economic/invoices/unpaid_repo"
57
+
41
58
  require "economic/journal_repo"
42
59
  require "economic/journal"
43
60
  require "economic/journal_voucher_repo"
@@ -49,10 +66,12 @@ require "economic/accounting_year_repo"
49
66
  require "economic/unit"
50
67
  require "economic/unit_repo"
51
68
 
52
- require 'economic/user'
69
+ require "economic/user"
70
+
53
71
  require "economic/company"
54
72
  require "economic/self"
55
73
  require "economic/self_repo"
74
+ require "economic/line"
56
75
 
57
76
  module Economic
58
77
  class Demo
@@ -1,5 +1,5 @@
1
1
  module Economic
2
2
  module Rest
3
- VERSION = "0.3.6".freeze
3
+ VERSION = "0.4.0".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,24 @@
1
+ module Economic
2
+ class SoapAPI
3
+ URL = "https://api.e-conomic.com/secure/api1/EconomicWebService.asmx?WSDL".freeze
4
+
5
+ class << self
6
+ def call(method, message: {})
7
+ response = client.call(method, message: message, cookies: auth_cookies)
8
+
9
+ response.body["#{method}_response".to_sym]["#{method}_result".to_sym]
10
+ end
11
+
12
+ def auth_cookies
13
+ @auth_cookies ||= client.call(:connect_with_token, message: {token: Economic::Session.agreement_grant_token, appToken: Economic::Session.app_secret_token}).http.cookies
14
+ end
15
+
16
+ def client
17
+ @client ||= Savon.client {
18
+ wsdl(URL)
19
+ convert_request_keys_to :none # or one of [:lower_camelcase, :upcase, :none]
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: economic-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Klogborg
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-26 00:00:00.000000000 Z
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,48 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dotenv
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: standard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: savon
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
97
139
  - !ruby/object:Gem::Dependency
98
140
  name: rest-client
99
141
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +150,34 @@ dependencies:
108
150
  - - ">="
109
151
  - !ruby/object:Gem::Version
110
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: activesupport
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: awesome_print
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
111
181
  description:
112
182
  email:
113
183
  - klogborg@traels.it
@@ -116,6 +186,7 @@ extensions: []
116
186
  extra_rdoc_files: []
117
187
  files:
118
188
  - ".gitignore"
189
+ - ".vscode/settings.json"
119
190
  - CODE_OF_CONDUCT.md
120
191
  - Gemfile
121
192
  - Gemfile.lock
@@ -130,6 +201,7 @@ files:
130
201
  - lib/economic/base.rb
131
202
  - lib/economic/base_repo.rb
132
203
  - lib/economic/company.rb
204
+ - lib/economic/concerns/soap_methods.rb
133
205
  - lib/economic/currency.rb
134
206
  - lib/economic/customer.rb
135
207
  - lib/economic/customer_group.rb
@@ -137,11 +209,21 @@ files:
137
209
  - lib/economic/customer_repo.rb
138
210
  - lib/economic/delivery.rb
139
211
  - lib/economic/inventory.rb
212
+ - lib/economic/invoice.rb
213
+ - lib/economic/invoices/booked_repo.rb
214
+ - lib/economic/invoices/drafts_repo.rb
215
+ - lib/economic/invoices/not_due_repo.rb
216
+ - lib/economic/invoices/overdue_repo.rb
217
+ - lib/economic/invoices/paid_repo.rb
218
+ - lib/economic/invoices/repo.rb
219
+ - lib/economic/invoices/sent_repo.rb
220
+ - lib/economic/invoices/unpaid_repo.rb
140
221
  - lib/economic/journal.rb
141
222
  - lib/economic/journal_repo.rb
142
223
  - lib/economic/journal_voucher_repo.rb
143
224
  - lib/economic/layout.rb
144
225
  - lib/economic/layout_repo.rb
226
+ - lib/economic/line.rb
145
227
  - lib/economic/notes.rb
146
228
  - lib/economic/order.rb
147
229
  - lib/economic/orders/archived_repo.rb
@@ -149,6 +231,7 @@ files:
149
231
  - lib/economic/orders/repo.rb
150
232
  - lib/economic/orders/sent_repo.rb
151
233
  - lib/economic/payment_terms.rb
234
+ - lib/economic/payment_terms_repo.rb
152
235
  - lib/economic/pdf.rb
153
236
  - lib/economic/pricing.rb
154
237
  - lib/economic/pricing_repo.rb
@@ -164,6 +247,7 @@ files:
164
247
  - lib/economic/self.rb
165
248
  - lib/economic/self_repo.rb
166
249
  - lib/economic/session.rb
250
+ - lib/economic/soap_api.rb
167
251
  - lib/economic/unit.rb
168
252
  - lib/economic/unit_repo.rb
169
253
  - lib/economic/user.rb