twinfieldrb 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.github/workflows/rspec.yml +33 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/README.md +120 -0
- data/Rakefile +1 -0
- data/lib/twinfield/abstract_model.rb +7 -0
- data/lib/twinfield/api/base_api.rb +50 -0
- data/lib/twinfield/api/finder.rb +45 -0
- data/lib/twinfield/api/o_auth_session.rb +58 -0
- data/lib/twinfield/api/process.rb +44 -0
- data/lib/twinfield/api/session.rb +170 -0
- data/lib/twinfield/browse/transaction/cost_center.rb +145 -0
- data/lib/twinfield/browse/transaction/customer.rb +413 -0
- data/lib/twinfield/browse/transaction/general_ledger.rb +144 -0
- data/lib/twinfield/configuration.rb +49 -0
- data/lib/twinfield/create/cost_center.rb +39 -0
- data/lib/twinfield/create/creditor.rb +88 -0
- data/lib/twinfield/create/debtor.rb +88 -0
- data/lib/twinfield/create/error.rb +30 -0
- data/lib/twinfield/create/general_ledger.rb +39 -0
- data/lib/twinfield/create/transaction.rb +97 -0
- data/lib/twinfield/customer.rb +612 -0
- data/lib/twinfield/helpers/parsers.rb +23 -0
- data/lib/twinfield/helpers/transaction_match.rb +40 -0
- data/lib/twinfield/request/find.rb +149 -0
- data/lib/twinfield/request/list.rb +66 -0
- data/lib/twinfield/request/read.rb +111 -0
- data/lib/twinfield/sales_invoice.rb +409 -0
- data/lib/twinfield/transaction.rb +112 -0
- data/lib/twinfield/version.rb +5 -0
- data/lib/twinfield.rb +89 -0
- data/script/boot.rb +58 -0
- data/script/console +2 -0
- data/spec/fixtures/cluster/finder/ivt.xml +1 -0
- data/spec/fixtures/cluster/processxml/columns/sales_transactions.xml +312 -0
- data/spec/fixtures/cluster/processxml/customer/create_success.xml +100 -0
- data/spec/fixtures/cluster/processxml/customer/read_success.xml +93 -0
- data/spec/fixtures/cluster/processxml/customer/update_success.xml +1 -0
- data/spec/fixtures/cluster/processxml/invoice/create_error.xml +8 -0
- data/spec/fixtures/cluster/processxml/invoice/create_final_error.xml +67 -0
- data/spec/fixtures/cluster/processxml/invoice/create_success.xml +64 -0
- data/spec/fixtures/cluster/processxml/invoice/read_not_found.xml +1 -0
- data/spec/fixtures/cluster/processxml/invoice/read_success.xml +106 -0
- data/spec/fixtures/cluster/processxml/read/deb.xml +12 -0
- data/spec/fixtures/cluster/processxml/response.xml +8 -0
- data/spec/fixtures/login/session/wsdl.xml +210 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/stubs/finder_stubs.rb +19 -0
- data/spec/stubs/processxml_stubs.rb +41 -0
- data/spec/stubs/session_stubs.rb +28 -0
- data/spec/twinfield/api/oauth_session_spec.rb +37 -0
- data/spec/twinfield/api/process_spec.rb +7 -0
- data/spec/twinfield/browse/transaction/cost_center_spec.rb +60 -0
- data/spec/twinfield/browse/transaction/general_ledger_spec.rb +60 -0
- data/spec/twinfield/browse/transaction/transaction_spec.rb +72 -0
- data/spec/twinfield/config_spec.rb +60 -0
- data/spec/twinfield/customer_spec.rb +326 -0
- data/spec/twinfield/request/find_spec.rb +24 -0
- data/spec/twinfield/request/list_spec.rb +58 -0
- data/spec/twinfield/request/read_spec.rb +26 -0
- data/spec/twinfield/sales_invoice_spec.rb +253 -0
- data/spec/twinfield/session_spec.rb +77 -0
- data/spec/twinfield/transaction_spec.rb +149 -0
- data/twinfieldrb.gemspec +24 -0
- data/wsdls/accounting/finder.wsdl +157 -0
- data/wsdls/accounting/process.wsdl +199 -0
- data/wsdls/accounting/session.wsdl +452 -0
- data/wsdls/accounting2/finder.wsdl +157 -0
- data/wsdls/accounting2/process.wsdl +199 -0
- data/wsdls/api.accounting/finder.wsdl +157 -0
- data/wsdls/api.accounting/process.wsdl +199 -0
- data/wsdls/session.wsdl +210 -0
- data/wsdls/update +10 -0
- metadata +196 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
module Twinfield
|
2
|
+
module Request
|
3
|
+
module Find
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def articles
|
7
|
+
options = {}
|
8
|
+
options.merge(office: Twinfield.configuration.company)
|
9
|
+
|
10
|
+
response = Twinfield::Api::Finder.request("ART", options)
|
11
|
+
|
12
|
+
response.body[:search_response][:data][:items][:array_of_string].values.map do |item|
|
13
|
+
{
|
14
|
+
code: item[0],
|
15
|
+
name: item[1]
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def asset_methods
|
21
|
+
options = {}
|
22
|
+
options.merge(office: Twinfield.configuration.company)
|
23
|
+
|
24
|
+
response = Twinfield::Api::Finder.request("ASM", options)
|
25
|
+
|
26
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
27
|
+
{
|
28
|
+
code: item[:string][0],
|
29
|
+
name: item[:string][1]
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def budgets
|
35
|
+
options = {}
|
36
|
+
options.merge(office: Twinfield.configuration.company)
|
37
|
+
|
38
|
+
response = Twinfield::Api::Finder.request("BDS", options)
|
39
|
+
|
40
|
+
response.body[:search_response][:data][:items][:array_of_string].values.map do |item|
|
41
|
+
{
|
42
|
+
code: item[0],
|
43
|
+
name: item[1]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def credit_management_action_codes
|
49
|
+
options = {}
|
50
|
+
options.merge(office: Twinfield.configuration.company)
|
51
|
+
|
52
|
+
response = Twinfield::Api::Finder.request("CDA", options)
|
53
|
+
|
54
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
55
|
+
{
|
56
|
+
code: item[:string][0],
|
57
|
+
name: item[:string][1]
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def sales_transactions(options = {})
|
63
|
+
options.merge(office: Twinfield.configuration.company)
|
64
|
+
|
65
|
+
response = Twinfield::Api::Finder.request("IVT", options)
|
66
|
+
|
67
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
68
|
+
{
|
69
|
+
invoice_number: item[:string][0],
|
70
|
+
amount: item[:string][1],
|
71
|
+
debtor_code: item[:string][2],
|
72
|
+
debtor_name: item[:string][3],
|
73
|
+
debit_credit: item[:string][4]
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def creditors
|
79
|
+
options = {dimtype: "CRD"}
|
80
|
+
options.merge(office: Twinfield.configuration.company)
|
81
|
+
|
82
|
+
response = Twinfield::Api::Finder.request("DIM", options)
|
83
|
+
|
84
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
85
|
+
{
|
86
|
+
code: item[:string][0],
|
87
|
+
name: item[:string][1]
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def debtors
|
93
|
+
options = {dimtype: "DEB"}
|
94
|
+
options.merge(office: Twinfield.configuration.company)
|
95
|
+
|
96
|
+
response = Twinfield::Api::Finder.request("DIM", options)
|
97
|
+
|
98
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
99
|
+
{
|
100
|
+
code: item[:string][0],
|
101
|
+
name: item[:string][1]
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def cost_centers
|
107
|
+
options = {dimtype: "KPL"}
|
108
|
+
options.merge(office: Twinfield.configuration.company)
|
109
|
+
|
110
|
+
response = Twinfield::Api::Finder.request("DIM", options)
|
111
|
+
|
112
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
113
|
+
{
|
114
|
+
code: item[:string][0],
|
115
|
+
name: item[:string][1]
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def general_ledgers(options)
|
121
|
+
options = options.merge(office: Twinfield.configuration.company)
|
122
|
+
|
123
|
+
response = Twinfield::Api::Finder.request("DIM", options)
|
124
|
+
|
125
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
126
|
+
{
|
127
|
+
code: item[:string][0],
|
128
|
+
name: item[:string][1]
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Twinfield::Request::Find.test
|
134
|
+
def test
|
135
|
+
options = {office: Twinfield.configuration.company, dimtype: "CRD"}
|
136
|
+
|
137
|
+
response = Twinfield::Api::Finder.request("DIM", options)
|
138
|
+
|
139
|
+
response.body[:search_response][:data][:items][:array_of_string].map do |item|
|
140
|
+
{
|
141
|
+
|
142
|
+
code: item[:string][0],
|
143
|
+
name: item[:string][1]
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Twinfield
|
2
|
+
module Request
|
3
|
+
module List
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def browsefields
|
7
|
+
xml_doc = xml_wrap(list(:browsefields))
|
8
|
+
|
9
|
+
array = []
|
10
|
+
xml_doc.css("browsefield").each do |xml|
|
11
|
+
array << {
|
12
|
+
code: xml.at_css("code").content,
|
13
|
+
datatype: xml.at_css("datatype").content,
|
14
|
+
finder: xml.at_css("finder").content,
|
15
|
+
dropdown: xml.at_css("dropdown").css("option").map { |opt| opt[:name] },
|
16
|
+
canorder: xml.at_css("canorder").content
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
array
|
21
|
+
end
|
22
|
+
|
23
|
+
def budgets(options)
|
24
|
+
xml_wrap(list(:budgets, options))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Twinfield::Request::List.dimensions({ dimtype: "DEB" })
|
28
|
+
def dimensions(options)
|
29
|
+
options = options.merge(office: Twinfield.configuration.company)
|
30
|
+
xml_wrap(list(:dimensions, options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def offices
|
34
|
+
xml_doc = xml_wrap(list(:offices))
|
35
|
+
|
36
|
+
array = []
|
37
|
+
xml_doc.css("office").each do |xml|
|
38
|
+
array << {
|
39
|
+
name: xml[:name],
|
40
|
+
shortname: xml[:shortname],
|
41
|
+
code: xml.content
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
array
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def list(element, options = {})
|
51
|
+
Twinfield::Api::Process.request(:process_xml_string) do
|
52
|
+
%(
|
53
|
+
<list>
|
54
|
+
<type>#{element}</type>
|
55
|
+
#{Twinfield::Api::Process.options_to_xml(options)}
|
56
|
+
</list>
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def xml_wrap(response)
|
62
|
+
Nokogiri::XML(response.body[:process_xml_string_response][:process_xml_string_result])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Twinfield
|
2
|
+
module Request
|
3
|
+
module Read
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def office(options)
|
7
|
+
xml_wrap(read(:office, options))
|
8
|
+
end
|
9
|
+
|
10
|
+
def debtor(options)
|
11
|
+
xml = xml_wrap(read(:dimensions, options.merge(dimtype: "DEB")))
|
12
|
+
|
13
|
+
if xml.at_css("dimensions").attributes["result"]&.value == "1"
|
14
|
+
[]
|
15
|
+
elsif xml.at_css("dimension").attributes["result"].value == "1"
|
16
|
+
{
|
17
|
+
status: 1,
|
18
|
+
country: xml.at_css("country").content,
|
19
|
+
city: xml.at_css("city").content,
|
20
|
+
postcode: xml.at_css("postcode").content,
|
21
|
+
address: xml.at_css("field2").content,
|
22
|
+
duedays: xml.at_css("duedays").content
|
23
|
+
}
|
24
|
+
else
|
25
|
+
{
|
26
|
+
status: 0
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Twinfield::Request::Read.sales_invoice({})
|
32
|
+
def sales_invoice(invoicenumber, invoicetype: "FACTUUR")
|
33
|
+
options = {office: Twinfield.configuration.company, code: "FACTUUR", invoicenumber: invoicenumber}
|
34
|
+
|
35
|
+
xml = xml_wrap(read(:salesinvoice, options))
|
36
|
+
|
37
|
+
if xml.at_css("dimension").attributes["result"].value == "1"
|
38
|
+
{
|
39
|
+
status: 1,
|
40
|
+
country: xml.at_css("country").content,
|
41
|
+
city: xml.at_css("city").content,
|
42
|
+
postcode: xml.at_css("postcode").content,
|
43
|
+
address: xml.at_css("field2").content,
|
44
|
+
duedays: xml.at_css("duedays").content
|
45
|
+
}
|
46
|
+
else
|
47
|
+
{
|
48
|
+
status: 0
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Twinfield::Request::Read.browse( options: { code: "000" })
|
54
|
+
def browse(options)
|
55
|
+
options = options.merge(office: Twinfield.configuration.company)
|
56
|
+
|
57
|
+
xml_wrap(read(:browse, options))
|
58
|
+
|
59
|
+
{
|
60
|
+
status: 0
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def xml_to_json(xml)
|
65
|
+
rv = {}
|
66
|
+
nokogiri = xml.is_a?(String) ? Nokogiri::XML(xml) : xml
|
67
|
+
|
68
|
+
nokogiri.children.each do |node|
|
69
|
+
twig = [xml_to_json(node)]
|
70
|
+
twig_keys = twig.map { |a| a.keys }.flatten
|
71
|
+
uniq_twig_keys = twig_keys.uniq
|
72
|
+
if uniq_twig_keys.count == 1 && "#{uniq_twig_keys.first}s" == node.name
|
73
|
+
twig = twig.map { |a| a.values }.flatten
|
74
|
+
elsif node.is_a?(Nokogiri::XML::Element) && node.children.count == 1 && node.children.first.is_a?(Nokogiri::XML::Text)
|
75
|
+
twig = node.text
|
76
|
+
if /\A\d*$/.match?(twig)
|
77
|
+
twig = twig.to_i
|
78
|
+
end
|
79
|
+
elsif node.text.strip == ""
|
80
|
+
twig = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
# do not unnecesarily wrap a hash with uniq keys in an array
|
84
|
+
if twig.is_a?(Array) && !node.name.end_with?("s") && twig.count == 1
|
85
|
+
twig = twig[0]
|
86
|
+
end
|
87
|
+
|
88
|
+
rv[node.name.to_sym] = twig if twig
|
89
|
+
end
|
90
|
+
rv
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def read(element, options = {})
|
96
|
+
Twinfield::Api::Process.request(:process_xml_string) do
|
97
|
+
%(
|
98
|
+
<read>
|
99
|
+
<type>#{element}</type>
|
100
|
+
#{Twinfield::Api::Process.options_to_xml(options)}
|
101
|
+
</read>
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def xml_wrap(response)
|
107
|
+
Nokogiri::XML(response.body[:process_xml_string_response][:process_xml_string_result])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|