collmex-ruby 0.1.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.
- data/lib/collmex.rb +35 -0
- data/lib/collmex/api.rb +361 -0
- data/lib/collmex/api/line.rb +0 -0
- data/lib/collmex/api/lines.rb +0 -0
- data/lib/collmex/request.rb +95 -0
- data/spec/lib/collmex/api_spec.rb +582 -0
- data/spec/lib/collmex/request_spec.rb +160 -0
- data/spec/lib/collmex_spec.rb +54 -0
- data/spec/spec_helper.rb +34 -0
- metadata +68 -0
data/lib/collmex.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'collmex/api'
|
2
|
+
require 'collmex/request'
|
3
|
+
|
4
|
+
module Collmex
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :customer_id
|
8
|
+
attr_accessor :username
|
9
|
+
attr_accessor :password
|
10
|
+
|
11
|
+
def csv_opts
|
12
|
+
{
|
13
|
+
:col_sep => ";"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def setup_login_data
|
19
|
+
config = YAML.load_file('config/collmex_config.yml')["development"]
|
20
|
+
Collmex.username = config["username"]
|
21
|
+
Collmex.password = config["password"]
|
22
|
+
Collmex.customer_id = config["customer_id"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset_login_data
|
26
|
+
Collmex.username = "000000"
|
27
|
+
Collmex.password = "000000"
|
28
|
+
Collmex.customer_id = "000000"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Collmex.reset_login_data
|
34
|
+
|
35
|
+
|
data/lib/collmex/api.rb
ADDED
@@ -0,0 +1,361 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
module Collmex
|
4
|
+
module Api
|
5
|
+
|
6
|
+
def self.is_a_collmex_api_line_obj? obj
|
7
|
+
obj.class.name =~ /Collmex\:\:Api/
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.line_class_exists?(class_name)
|
11
|
+
klass = Collmex::Api.const_get(class_name)
|
12
|
+
return klass.is_a?(Class)
|
13
|
+
rescue NameError
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse_line(line)
|
18
|
+
if line.is_a?(Array) and line.first.is_a?(String)
|
19
|
+
identifyer = line.first.split("_").map{ |s| s.downcase.capitalize }.join
|
20
|
+
if self.line_class_exists?(identifyer)
|
21
|
+
Collmex::Api.const_get(identifyer).new(line)
|
22
|
+
else
|
23
|
+
raise "Could not find a Collmex::Api::Line class for \"#{identifyer}\""
|
24
|
+
end
|
25
|
+
elsif line.is_a?(String) && parsed_line = CSV.parse_line(line, Collmex.csv_opts)
|
26
|
+
identifyer = parsed_line.first.split("_").map{ |s| s.downcase.capitalize }.join
|
27
|
+
if self.line_class_exists?(identifyer)
|
28
|
+
Collmex::Api.const_get(identifyer).new(parsed_line)
|
29
|
+
else
|
30
|
+
raise "Could not find a Collmex::Api::Line class for \"#{identifyer}\""
|
31
|
+
end
|
32
|
+
else
|
33
|
+
raise "Could not parse a Collmex::Api Line from #{line.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_field(value, type, opts = nil)
|
38
|
+
case type
|
39
|
+
when :string then value.to_s
|
40
|
+
when :date then Date.parse(value.to_s) unless value.nil?
|
41
|
+
when :int then value.to_i unless value.nil?
|
42
|
+
when :integer then value.to_i unless value.nil?
|
43
|
+
when :float then value.to_s.gsub(',','.').to_f unless value.nil?
|
44
|
+
when :currency then Collmex::Api.parse_currency(value) unless value.nil?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.parse_currency(str)
|
49
|
+
str = str.to_s
|
50
|
+
case str
|
51
|
+
when /\A-?\d*[\,|.]\d{0,2}\z/ then (str.gsub(',','.').to_f * 100).to_i
|
52
|
+
when /\A-?\d+\z/ then str.to_i
|
53
|
+
when /\A-?((\d){1,3})*([\.]\d{3})+([,]\d{2})\z/ then (str.gsub('.','').gsub(',','.').to_f * 100).to_i
|
54
|
+
when /\A-?((\d){1,3})*([\,]\d{3})+([.]\d{2})\z/ then (str.gsub(',','').to_f * 100).to_i
|
55
|
+
when /\A-?((\d){1,3})*([\.\,]\d{3})+\z/ then str.gsub(',','').gsub('.','').to_i * 100
|
56
|
+
else str.to_i
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.stringify(data, type)
|
61
|
+
case type
|
62
|
+
when :integer then (data.nil?)? data.to_s : data.to_i.to_s
|
63
|
+
when :string then data.to_s
|
64
|
+
when :float then sprintf("%.2f",data).gsub('.',',')
|
65
|
+
when :currency then Collmex::Api.stringify_currency(data)
|
66
|
+
when :date then data.strftime("%Y%m%d") unless data.nil?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.stringify_currency(data)
|
71
|
+
case
|
72
|
+
when data.is_a?(Integer) then sprintf("%.2f",(data.to_f / 100)).gsub('.',',')
|
73
|
+
when data.is_a?(Float) then sprintf("%.2f",(data.to_f)).gsub('.',',')
|
74
|
+
when data.is_a?(String)
|
75
|
+
int = self.parse_currency(data)
|
76
|
+
sprintf("%.2f",(int.to_f / 100)).gsub('.',',')
|
77
|
+
else data
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
module Collmex
|
86
|
+
module Api
|
87
|
+
class Line
|
88
|
+
|
89
|
+
def self.specification
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.default_hash
|
94
|
+
hash = {}
|
95
|
+
self.specification.each_with_index do |field_spec, index|
|
96
|
+
if field_spec.has_key? :fix
|
97
|
+
hash[field_spec[:name]] = field_spec[:fix]
|
98
|
+
elsif field_spec.has_key? :default
|
99
|
+
hash[field_spec[:name]] = field_spec[:default]
|
100
|
+
else
|
101
|
+
hash[field_spec[:name]] = Collmex::Api.parse_field(nil, field_spec[:type])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
hash
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.hashify(data)
|
108
|
+
hash = self.default_hash
|
109
|
+
fields_spec = self.specification
|
110
|
+
|
111
|
+
if data.is_a? Array
|
112
|
+
fields_spec.each_with_index do |field_spec, index|
|
113
|
+
if !data[index].nil? && !field_spec.has_key?(:fix)
|
114
|
+
hash[field_spec[:name]] = Collmex::Api.parse_field(data[index], field_spec[:type])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
elsif data.is_a? Hash
|
118
|
+
fields_spec.each_with_index do |field_spec, index|
|
119
|
+
if data.key?(field_spec[:name]) && !field_spec.has_key?(:fix)
|
120
|
+
hash[field_spec[:name]] = Collmex::Api.parse_field(data[field_spec[:name]], field_spec[:type])
|
121
|
+
end
|
122
|
+
end
|
123
|
+
elsif data.is_a?(String) && parsed = CSV.parse_line(data,Collmex.csv_opts)
|
124
|
+
fields_spec.each_with_index do |field_spec, index|
|
125
|
+
if !data[index].nil? && !field_spec.has_key?(:fix)
|
126
|
+
hash[field_spec[:name]] = Collmex::Api.parse_field(parsed[index], field_spec[:type])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
hash
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
def initialize(arg = nil)
|
135
|
+
#puts self.class.name
|
136
|
+
@hash = self.class.default_hash
|
137
|
+
@hash = @hash.merge(self.class.hashify(arg)) if !arg.nil?
|
138
|
+
if self.class.specification.empty? && self.class.name.to_s != "Collmex::Api::Line"
|
139
|
+
raise "#{self.class.name} has no specification"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def to_a
|
145
|
+
array = []
|
146
|
+
self.class.specification.each do |spec|
|
147
|
+
array << @hash[spec[:name]]
|
148
|
+
end
|
149
|
+
array
|
150
|
+
end
|
151
|
+
|
152
|
+
def to_stringified_array
|
153
|
+
array = []
|
154
|
+
self.class.specification.each do |spec|
|
155
|
+
array << Collmex::Api.stringify(@hash[spec[:name]], spec[:type])
|
156
|
+
end
|
157
|
+
array
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def to_csv
|
162
|
+
array = []
|
163
|
+
self.class.specification.each do |spec|
|
164
|
+
array << Collmex::Api.stringify(@hash[spec[:name]], spec[:type])
|
165
|
+
end
|
166
|
+
CSV.generate_line(array, Collmex.csv_opts)
|
167
|
+
end
|
168
|
+
|
169
|
+
def to_h
|
170
|
+
@hash
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
module Collmex
|
185
|
+
module Api
|
186
|
+
|
187
|
+
class Login < Line
|
188
|
+
def self.specification
|
189
|
+
[
|
190
|
+
{ name: :identifyer, type: :string, fix: "LOGIN" },
|
191
|
+
{ name: :username, type: :integer },
|
192
|
+
{ name: :password, type: :integer }
|
193
|
+
]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class Cmxknd < Line
|
198
|
+
def self.specification
|
199
|
+
[
|
200
|
+
{ name: :identifyer , type: :string , fix: "CMXKND" },
|
201
|
+
{ name: :customer_id , type: :integer },
|
202
|
+
{ name: :company_id , type: :integer , default: 1 },
|
203
|
+
{ name: :salutation , type: :string },
|
204
|
+
{ name: :title , type: :string },
|
205
|
+
{ name: :firstname , type: :string },
|
206
|
+
{ name: :lastname , type: :string },
|
207
|
+
{ name: :comapyn , type: :string },
|
208
|
+
{ name: :department , type: :string },
|
209
|
+
{ name: :street , type: :string },
|
210
|
+
{ name: :zipcode , type: :string },
|
211
|
+
{ name: :city , type: :string },
|
212
|
+
{ name: :annotation , type: :string },
|
213
|
+
{ name: :inactive , type: :integer },
|
214
|
+
{ name: :country , type: :string },
|
215
|
+
{ name: :phone , type: :string },
|
216
|
+
{ name: :fax , type: :string },
|
217
|
+
{ name: :email , type: :string },
|
218
|
+
{ name: :account_id , type: :string },
|
219
|
+
{ name: :blz , type: :string },
|
220
|
+
{ name: :iban , type: :string },
|
221
|
+
{ name: :bic , type: :string },
|
222
|
+
{ name: :bank_name , type: :string },
|
223
|
+
{ name: :vat_id , type: :string },
|
224
|
+
{ name: :payment_condition, type: :integer },
|
225
|
+
{ name: :dscout_group , type: :integer },
|
226
|
+
{ name: :deliver_conditions, type: :string },
|
227
|
+
{ name: :deliver_conditions_additions, type: :string },
|
228
|
+
{ name: :output_media , type: :integer },
|
229
|
+
{ name: :account_owner , type: :string },
|
230
|
+
{ name: :address_group , type: :integer },
|
231
|
+
{ name: :ebay_member , type: :string },
|
232
|
+
{ name: :price_group , type: :integer },
|
233
|
+
{ name: :currency , type: :string },
|
234
|
+
{ name: :agent , type: :integer },
|
235
|
+
{ name: :cost_unit , type: :string },
|
236
|
+
{ name: :due_to , type: :date },
|
237
|
+
{ name: :delivery_ban , type: :integer },
|
238
|
+
{ name: :building_servant , type: :integer },
|
239
|
+
{ name: :account_id_at_customer, type: :string },
|
240
|
+
{ name: :output_language , type: :integer },
|
241
|
+
{ name: :email_cc , type: :string },
|
242
|
+
{ name: :phone_2 , type: :string },
|
243
|
+
]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class Message < Line
|
248
|
+
def self.specification
|
249
|
+
[
|
250
|
+
{ name: :identifyer , type: :string , fix: "MESSAGE" },
|
251
|
+
{ name: :type , type: :string },
|
252
|
+
{ name: :id , type: :integer },
|
253
|
+
{ name: :text , type: :string },
|
254
|
+
{ name: :line , type: :integer },
|
255
|
+
]
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
def success?
|
260
|
+
if @hash.has_key?(:type) && !@hash[:type].empty? && @hash[:type] == "S"
|
261
|
+
true
|
262
|
+
else
|
263
|
+
false
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def result
|
268
|
+
if @hash.has_key?(:type) && !@hash[:type].empty?
|
269
|
+
case @hash[:type]
|
270
|
+
when "S" then :success
|
271
|
+
when "W" then :warning
|
272
|
+
when "E" then :error
|
273
|
+
else :undefined
|
274
|
+
end
|
275
|
+
else
|
276
|
+
:undefined
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class CustomerGet < Line
|
282
|
+
def self.specification
|
283
|
+
[
|
284
|
+
{ name: :identifyer , type: :string , fix: "CUSTOMER_GET" },
|
285
|
+
{ name: :id , type: :integer },
|
286
|
+
{ name: :company_id , type: :integer , default: 1 },
|
287
|
+
{ name: :searchtext , type: :string },
|
288
|
+
{ name: :due_to_review , type: :integer },
|
289
|
+
{ name: :zip_code , type: :string },
|
290
|
+
{ name: :adress_group , type: :integer },
|
291
|
+
{ name: :price_group , type: :integer },
|
292
|
+
{ name: :discout_group , type: :integer },
|
293
|
+
{ name: :agent , type: :integer },
|
294
|
+
{ name: :only_changed , type: :integer },
|
295
|
+
{ name: :system_name , type: :string },
|
296
|
+
{ name: :inactive , type: :integer },
|
297
|
+
]
|
298
|
+
|
299
|
+
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
class AccdocGet < Line
|
304
|
+
def self.specification
|
305
|
+
[
|
306
|
+
{ name: :identifyer , type: :string , fix: "ACCDOC_GET" },
|
307
|
+
{ name: :company_id , type: :integer , default: 1 },
|
308
|
+
{ name: :business_year , type: :integer },
|
309
|
+
{ name: :id , type: :integer },
|
310
|
+
{ name: :account_id , type: :integer },
|
311
|
+
{ name: :cost_unit , type: :integer },
|
312
|
+
{ name: :customer_id , type: :integer },
|
313
|
+
{ name: :provider_id , type: :integer },
|
314
|
+
{ name: :asset_id , type: :integer },
|
315
|
+
{ name: :invoice_id , type: :integer },
|
316
|
+
{ name: :jorney_id , type: :integer },
|
317
|
+
{ name: :text , type: :string },
|
318
|
+
{ name: :date_start , type: :date },
|
319
|
+
{ name: :date_end , type: :date },
|
320
|
+
{ name: :cancellattion , type: :integer },
|
321
|
+
{ name: :changed_only , type: :integer },
|
322
|
+
{ name: :system_name , type: :string },
|
323
|
+
]
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class Accdoc < Line
|
328
|
+
def self.specification
|
329
|
+
[
|
330
|
+
{ name: :identifyer , type: :string , fix: "ACCDOC" },
|
331
|
+
{ name: :company_id , type: :integer , default: 1 },
|
332
|
+
{ name: :business_year , type: :integer },
|
333
|
+
{ name: :id , type: :integer },
|
334
|
+
{ name: :accdoc_date , type: :date },
|
335
|
+
{ name: :accounted_date , type: :date },
|
336
|
+
{ name: :test , type: :string },
|
337
|
+
{ name: :position_id , type: :integer },
|
338
|
+
{ name: :account_id , type: :integer },
|
339
|
+
{ name: :account_name , type: :string },
|
340
|
+
{ name: :should_have , type: :integer },
|
341
|
+
{ name: :amount , type: :currency },
|
342
|
+
{ name: :customer_id , type: :integer },
|
343
|
+
{ name: :customer_name , type: :string },
|
344
|
+
{ name: :provider_id , type: :integer },
|
345
|
+
{ name: :provider_name , type: :string },
|
346
|
+
{ name: :asset_id , type: :integer },
|
347
|
+
{ name: :asset_name , type: :string },
|
348
|
+
{ name: :canceled_accdoc , type: :integer },
|
349
|
+
{ name: :cost_unit , type: :string },
|
350
|
+
{ name: :invoice_id , type: :string },
|
351
|
+
{ name: :customer_order_id, type: :integer },
|
352
|
+
{ name: :jorney_id , type: :integer },
|
353
|
+
{ name: :belongs_to_id , type: :integer },
|
354
|
+
{ name: :belongs_to_year , type: :integer },
|
355
|
+
{ name: :belongs_to_pos , type: :integer },
|
356
|
+
]
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module Collmex
|
5
|
+
class Request
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :commands, :http
|
9
|
+
|
10
|
+
|
11
|
+
def self.run(&block)
|
12
|
+
Request.new.tap do |request|
|
13
|
+
request.instance_eval &block if block_given?
|
14
|
+
request.execute
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def self.classify(term)
|
20
|
+
term.to_s.split("_").collect(&:capitalize).join
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def enqueue(command, args = {})
|
25
|
+
if command.is_a? Symbol
|
26
|
+
add_command Collmex::Api::const_get(self.class.classify(command)).new(args)
|
27
|
+
elsif Collmex::Api.is_a_collmex_api_line_obj?(command)
|
28
|
+
add_command command
|
29
|
+
else
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@commands = []
|
37
|
+
@raw_response = {}
|
38
|
+
|
39
|
+
add_command Collmex::Api::Login.new({username: Collmex.username, password: Collmex.password})
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def add_command(cmd)
|
44
|
+
@commands << cmd
|
45
|
+
cmd
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def self.uri
|
50
|
+
URI.parse "https://www.collmex.de/cgi-bin/cgi.exe\?#{Collmex.customer_id},0,data_exchange"
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def self.header_attributes
|
55
|
+
{"Content-Type" => "text/csv"}
|
56
|
+
end
|
57
|
+
|
58
|
+
def payload
|
59
|
+
@commands.map{ |c| c.to_csv }.join
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def parse_response
|
64
|
+
@response = @raw_response[:array].map { |l| Collmex::Api.parse_line(l) }
|
65
|
+
@response
|
66
|
+
end
|
67
|
+
|
68
|
+
def raw_response
|
69
|
+
@raw_response
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def response
|
74
|
+
@response
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def execute
|
79
|
+
@http = Net::HTTP.new(Collmex::Request.uri.host, Collmex::Request.uri.port)
|
80
|
+
@http.use_ssl = true
|
81
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
82
|
+
|
83
|
+
response = @http.request_post(Collmex::Request.uri.request_uri, self.payload, Collmex::Request.header_attributes)
|
84
|
+
|
85
|
+
response.body.force_encoding("ISO8859-1") if response.body.encoding.to_s == "ASCII-8BIT"
|
86
|
+
|
87
|
+
@raw_response[:string] = response.body.encode("UTF-8")
|
88
|
+
@raw_response[:array] = CSV.parse(@raw_response[:string], Collmex.csv_opts)
|
89
|
+
|
90
|
+
return parse_response
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|