ascii_invoicer 2.5.5
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.
- checksums.yaml +7 -0
- data/bin/ascii +722 -0
- data/latex/ascii-brief.cls +425 -0
- data/latex/ascii-brief.sty +46 -0
- data/lib/ascii_invoicer.rb +17 -0
- data/lib/ascii_invoicer/InvoiceProject.rb +356 -0
- data/lib/ascii_invoicer/ascii_logger.rb +64 -0
- data/lib/ascii_invoicer/filters.rb +129 -0
- data/lib/ascii_invoicer/generators.rb +209 -0
- data/lib/ascii_invoicer/hash_transformer.rb +23 -0
- data/lib/ascii_invoicer/mixins.rb +268 -0
- data/lib/ascii_invoicer/projectFileReader.rb +106 -0
- data/lib/ascii_invoicer/rfc5322_regex.rb +40 -0
- data/lib/ascii_invoicer/settings_manager.rb +62 -0
- data/lib/ascii_invoicer/texwriter.rb +105 -0
- data/lib/ascii_invoicer/tweaks.rb +25 -0
- data/lib/ascii_invoicer/version.rb +3 -0
- data/repl/ascii +2 -0
- data/settings/default-settings.yml +76 -0
- data/settings/settings_template.yml +54 -0
- data/templates/default.yml.erb +74 -0
- data/templates/document.tex.erb +87 -0
- metadata +297 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require "ascii_invoicer/version"
|
3
|
+
require "ascii_invoicer/settings_manager"
|
4
|
+
require "ascii_invoicer/InvoiceProject"
|
5
|
+
require "ascii_invoicer/hash_transformer"
|
6
|
+
require "ascii_invoicer/tweaks"
|
7
|
+
require "ascii_invoicer/mixins"
|
8
|
+
require "ascii_invoicer/ascii_logger"
|
9
|
+
rescue LoadError
|
10
|
+
require "./lib/ascii_invoicer/version"
|
11
|
+
require "./lib/ascii_invoicer/settings_manager"
|
12
|
+
require "./lib/ascii_invoicer/InvoiceProject"
|
13
|
+
require "./lib/ascii_invoicer/hash_transformer"
|
14
|
+
require "./lib/ascii_invoicer/tweaks"
|
15
|
+
require "./lib/ascii_invoicer/mixins"
|
16
|
+
require "./lib/ascii_invoicer/ascii_logger"
|
17
|
+
end
|
@@ -0,0 +1,356 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'csv'
|
3
|
+
require 'date'
|
4
|
+
require 'euro'
|
5
|
+
|
6
|
+
require File.join __dir__, 'hash_transformer.rb'
|
7
|
+
require File.join __dir__, 'projectFileReader.rb'
|
8
|
+
require File.join __dir__, 'rfc5322_regex.rb'
|
9
|
+
require File.join __dir__, 'texwriter.rb'
|
10
|
+
require File.join __dir__, 'filters.rb'
|
11
|
+
require File.join __dir__, 'generators.rb'
|
12
|
+
|
13
|
+
## TODO requirements and validity
|
14
|
+
## TODO open, YAML::parse, [transform, ] read_all, generate, validate
|
15
|
+
## TODO statemachine!!
|
16
|
+
# http://www.zenspider.com/Languages/Ruby/QuickRef.html
|
17
|
+
class InvoiceProject < LuigiProject
|
18
|
+
attr_reader :project_path, :project_folder,
|
19
|
+
:raw_data,
|
20
|
+
:status, :errors,
|
21
|
+
:settings, :defaults
|
22
|
+
|
23
|
+
attr_writer :raw_data, :defaults
|
24
|
+
|
25
|
+
include TexWriter
|
26
|
+
include Filters
|
27
|
+
include Generators
|
28
|
+
include ProjectFileReader
|
29
|
+
|
30
|
+
# keys that are in the original file and that will be filtered
|
31
|
+
@@filtered_keys=%i[
|
32
|
+
format lang created
|
33
|
+
client event manager
|
34
|
+
offer invoice canceled
|
35
|
+
messages products hours
|
36
|
+
includes
|
37
|
+
]
|
38
|
+
|
39
|
+
# keys that are not originally in the file will be generated
|
40
|
+
@@generated_keys=%i[
|
41
|
+
client_fullname
|
42
|
+
client_addressing
|
43
|
+
hours_time
|
44
|
+
hours_total
|
45
|
+
event_date
|
46
|
+
event_age
|
47
|
+
event_prettydate
|
48
|
+
caterers
|
49
|
+
offer_number
|
50
|
+
offer_costs offer_taxes offer_total offer_final
|
51
|
+
invoice_costs invoice_taxes invoice_total invoice_final
|
52
|
+
invoice_delay
|
53
|
+
invoice_paydelay
|
54
|
+
invoice_longnumber
|
55
|
+
event_calendaritems
|
56
|
+
productsbytax
|
57
|
+
]
|
58
|
+
|
59
|
+
#def initialize(project_path = nil, template_path = nil, settings = $settings, name = nil)
|
60
|
+
def initialize(hash)
|
61
|
+
@path = hash[:path]
|
62
|
+
@settings = hash[:settings]
|
63
|
+
@template_path = hash[:template_path]
|
64
|
+
@data = hash[:data]
|
65
|
+
@data ||= {}
|
66
|
+
|
67
|
+
@name = File.basename @path, '.yml'
|
68
|
+
@settings = hash[:settings]
|
69
|
+
@status = :ok
|
70
|
+
@errors = []
|
71
|
+
@defaults = {}
|
72
|
+
@defaults = @settings[:defaults] unless @settings[:defaults].nil?
|
73
|
+
|
74
|
+
@defaults['format'] = '1.0.0'
|
75
|
+
@logger = $logger
|
76
|
+
|
77
|
+
unless @template_path.nil?
|
78
|
+
create @template_path
|
79
|
+
end
|
80
|
+
|
81
|
+
open(@path) unless @path.nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
## open given .yml and parse into @raw_data
|
85
|
+
def open(project_path)
|
86
|
+
#puts "opening \"#{project_path}\""
|
87
|
+
raise "already opened another project" unless @project_path.nil?
|
88
|
+
@project_path = project_path
|
89
|
+
@project_folder = File.split(project_path)[0]
|
90
|
+
|
91
|
+
error "FILE \"#{project_path}\" does not exist!" unless File.exists?(project_path)
|
92
|
+
|
93
|
+
## setting the name
|
94
|
+
@data[:name] = File.basename File.split(@project_path)[0]
|
95
|
+
|
96
|
+
## opening the project file
|
97
|
+
begin
|
98
|
+
@raw_data = YAML::load(File.open(project_path))
|
99
|
+
rescue SyntaxError => error
|
100
|
+
@logger.warn "SyntaxError in #{project_path}, use \"edit\" to correct it.", :both
|
101
|
+
@logger.error error, :file
|
102
|
+
@status = :unparsable
|
103
|
+
return false
|
104
|
+
rescue Psych::SyntaxError => error
|
105
|
+
@logger.warn "SyntaxError in #{project_path}, use \"edit\" to correct it.", :both
|
106
|
+
@logger.error error, :file
|
107
|
+
@status = :unparsable
|
108
|
+
return false
|
109
|
+
else
|
110
|
+
@data[:valid] = true # at least for the moment
|
111
|
+
@status = :ok
|
112
|
+
@data[:project_path] = project_path
|
113
|
+
end
|
114
|
+
|
115
|
+
#load format and transform or not
|
116
|
+
@data[:format] = @raw_data['format'] ? @raw_data['format'] : "1.0.0"
|
117
|
+
if @data[:format] < "2.4.0"
|
118
|
+
begin
|
119
|
+
@raw_data = import_100 @raw_data
|
120
|
+
rescue =>error
|
121
|
+
@status = :unparsable
|
122
|
+
@logger.warn "#{error} parsing #{@project_path}"
|
123
|
+
puts $@
|
124
|
+
return false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
prepare_data()
|
129
|
+
return true
|
130
|
+
end
|
131
|
+
|
132
|
+
# displays "CANCELED: name if canceled"
|
133
|
+
def pretty_name
|
134
|
+
@data[:canceled] ? "CANCELED: #{@data[:name]}" : @data[:name]
|
135
|
+
end
|
136
|
+
|
137
|
+
# returns the name (LuigiProject Interface)
|
138
|
+
def name
|
139
|
+
@data[:name]
|
140
|
+
end
|
141
|
+
|
142
|
+
# returns the date (LuigiProject Interface)
|
143
|
+
def date
|
144
|
+
return @data[:event][:date] if @data[:event][:date]
|
145
|
+
return @data[:created] if @data[:created]
|
146
|
+
return Date.parse "01.01.0000"
|
147
|
+
end
|
148
|
+
|
149
|
+
# returns the manager
|
150
|
+
def manager
|
151
|
+
data :manager
|
152
|
+
end
|
153
|
+
|
154
|
+
def path
|
155
|
+
@project_path
|
156
|
+
end
|
157
|
+
|
158
|
+
def fill_template
|
159
|
+
project_name = @name.sub(?_, " ") #latex build fails if values contain a "_"
|
160
|
+
manager_name = @settings.manager_name
|
161
|
+
version = @settings.version
|
162
|
+
template = File.basename(@template_path, ".yml.erb")
|
163
|
+
|
164
|
+
return binding()
|
165
|
+
end
|
166
|
+
|
167
|
+
# returns index for sorting (year+invoicenumber)
|
168
|
+
def index
|
169
|
+
return @data[:invoice][:number] + date.strftime('%Y%m%d') if @data[:invoice][:number]
|
170
|
+
return "zzz" + date.strftime('%Y%m%d')
|
171
|
+
end
|
172
|
+
|
173
|
+
## currently only from 1.0.0 to 2.4.0 Format
|
174
|
+
def import_100 hash
|
175
|
+
rules = [
|
176
|
+
{ old:"client", new:"client/fullname" },
|
177
|
+
{ old:"address", new:"client/address" },
|
178
|
+
{ old:"email", new:"client/email" },
|
179
|
+
{ old:"event", new:"event/name" },
|
180
|
+
{ old:"location", new:"event/location" },
|
181
|
+
{ old:"description", new:"event/description" }, #trim
|
182
|
+
{ old:"manumber", new:"offer/number" },
|
183
|
+
{ old:"anumber", new:"offer/appendix" },
|
184
|
+
{ old:"rnumber", new:"invoice/number" },
|
185
|
+
{ old:"payed_date", new:"invoice/payed_date"},
|
186
|
+
{ old:"invoice_date", new:"invoice/date" },
|
187
|
+
{ old:"signature", new:"manager" }, #trim
|
188
|
+
#{ old:"hours/time", new:"hours/total" },
|
189
|
+
]
|
190
|
+
ht = HashTransformer.new :rules => rules, :original_hash => hash
|
191
|
+
new_hash = ht.transform()
|
192
|
+
new_hash[ 'created' ] = "01.01.0000"
|
193
|
+
|
194
|
+
date = strpdates(hash['date'])
|
195
|
+
new_hash.set_path("event/dates/0/begin", date[0])
|
196
|
+
new_hash.set_path("event/dates/0/end", date[1]) unless date[1].nil?
|
197
|
+
new_hash.set_path("event/dates/0/time/begin", new_hash.get_path("time")) if date[1].nil?
|
198
|
+
new_hash.set_path("event/dates/0/time/end", new_hash.get_path("time_end")) if date[1].nil?
|
199
|
+
|
200
|
+
new_hash['manager']= new_hash['manager'].lines.to_a[1] if new_hash['manager'].lines.to_a.length > 1
|
201
|
+
|
202
|
+
if new_hash.get_path("client/fullname").words.class == Array
|
203
|
+
new_hash.set_path("client/title", new_hash.get_path("client/fullname").lines.to_a[0].strip)
|
204
|
+
new_hash.set_path("client/last_name", new_hash.get_path("client/fullname").lines.to_a[1].strip)
|
205
|
+
new_hash.set_path("client/fullname", new_hash.get_path("client/fullname").gsub("\n",' ').strip)
|
206
|
+
else
|
207
|
+
fail_at :client_fullname
|
208
|
+
end
|
209
|
+
new_hash.set_path("offer/date", Date.today)
|
210
|
+
new_hash.set_path("invoice/date", Date.today) unless new_hash.get_path("invoice/date")
|
211
|
+
|
212
|
+
return hash
|
213
|
+
end
|
214
|
+
|
215
|
+
def products
|
216
|
+
data :products
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
def prepare_data
|
221
|
+
@@filtered_keys.each {|key| read key }
|
222
|
+
@@generated_keys.each {|key|
|
223
|
+
value = apply_generator key, @data
|
224
|
+
@data.set_path key, value, ?_, true # symbols = true
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
def validate choice = :invoice
|
229
|
+
blockers(choice).length == 0
|
230
|
+
end
|
231
|
+
|
232
|
+
def blockers choice = :invoice
|
233
|
+
inval = {} # invalidators
|
234
|
+
inval[ :minimal ] = [:client_last_name, :caterers, :manager, :products, :event_dates]
|
235
|
+
inval[ :offer ] = [:offer_number ] + inval[:minimal]
|
236
|
+
inval[ :invoice ] = inval[:offer] + [:invoice_number, :invoice_date]
|
237
|
+
inval[ :payed ] = inval[:invoice] + [:invoice_payed]
|
238
|
+
inval[ :archive ] = inval[:payed]
|
239
|
+
inval[ :calendar] = inval[:offer]
|
240
|
+
inval[choice] & @errors
|
241
|
+
end
|
242
|
+
|
243
|
+
def to_s
|
244
|
+
name
|
245
|
+
end
|
246
|
+
|
247
|
+
def to_yaml
|
248
|
+
@raw_data.to_yaml
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
#getters for path_through_document
|
253
|
+
#getting path['through']['document']
|
254
|
+
def data key = nil
|
255
|
+
return @data if key.nil?
|
256
|
+
return @data.get_path key
|
257
|
+
end
|
258
|
+
|
259
|
+
def export_filename choice, ext=""
|
260
|
+
offer_number = data 'offer/number'
|
261
|
+
invoice_number = data 'invoice/number'
|
262
|
+
name = data 'name'
|
263
|
+
date = data('event/date').strftime "%Y-%m-%d"
|
264
|
+
|
265
|
+
ext.prepend '.' unless ext.length > 0 and ext.start_with? '.'
|
266
|
+
|
267
|
+
if choice == :invoice
|
268
|
+
"#{invoice_number} #{name} #{date}#{ext}"
|
269
|
+
elsif choice == :offer
|
270
|
+
"#{offer_number} #{name}#{ext}"
|
271
|
+
else
|
272
|
+
return false
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class InvoiceProduct
|
278
|
+
attr_reader :name, :hash, :tax, :valid, :returned,
|
279
|
+
:total_invoice, :cost_offer, :cost_invoice, :cost_offer,
|
280
|
+
:tax_invoice, :tax_offer, :tax_value,
|
281
|
+
:price, :unit
|
282
|
+
|
283
|
+
def initialize(hash, settings)
|
284
|
+
@hash = hash
|
285
|
+
@name = hash[:name]
|
286
|
+
@price = hash[:price]
|
287
|
+
@unit = hash[:unit]
|
288
|
+
@amount = hash[:amount]
|
289
|
+
@settings = settings
|
290
|
+
if hash[:tax]
|
291
|
+
@tax_value = hash[:tax]
|
292
|
+
else
|
293
|
+
@tax_value = @settings[:defaults][:tax]
|
294
|
+
end
|
295
|
+
|
296
|
+
fail "TAX MUST NOT BE > 1" if @tax_value > 1
|
297
|
+
|
298
|
+
@valid = true
|
299
|
+
calculate() unless hash.nil?
|
300
|
+
end
|
301
|
+
|
302
|
+
def to_csv *args
|
303
|
+
[@name, @price, @amount, @sold, @tax_value].to_csv(*args)
|
304
|
+
end
|
305
|
+
|
306
|
+
def to_s
|
307
|
+
"#{@amount}/#{@sold} #{@name}, #{@price} cost (#{@cost_offer}|#{@cost_invoice}) total(#{@total_offer}|#{@total_invoice} #{@tax_value}) "
|
308
|
+
end
|
309
|
+
|
310
|
+
def calculate()
|
311
|
+
return false if @hash.nil?
|
312
|
+
@valid = false unless @hash[:sold].nil? or @hash[:returned].nil?
|
313
|
+
@valid = false unless @hash[:amount] and @hash[:price]
|
314
|
+
@sold = @hash[:sold]
|
315
|
+
@price = @hash[:price].to_euro
|
316
|
+
@amount = @hash[:amount]
|
317
|
+
@returned = @hash[:returned]
|
318
|
+
|
319
|
+
if @sold
|
320
|
+
@returned = @amount - @sold
|
321
|
+
elsif @returned
|
322
|
+
@sold = @amount - @returned
|
323
|
+
else
|
324
|
+
@sold = @amount
|
325
|
+
@returned = 0
|
326
|
+
end
|
327
|
+
|
328
|
+
@hash[:cost_offer] = @cost_offer = (@price * @amount).to_euro
|
329
|
+
@hash[:cost_invoice] = @cost_invoice = (@price * @sold).to_euro
|
330
|
+
|
331
|
+
@hash[:tax_offer] = @tax_offer = (@cost_offer * @tax_value)
|
332
|
+
@hash[:tax_invoice] = @tax_invoice = (@cost_invoice * @tax_value)
|
333
|
+
|
334
|
+
@hash[:total_offer] = @total_offer = (@cost_offer + @tax_offer)
|
335
|
+
@hash[:total_invoice] = @total_invoice = (@cost_invoice + @tax_invoice)
|
336
|
+
self.freeze
|
337
|
+
end
|
338
|
+
|
339
|
+
def amount choice
|
340
|
+
return @sold if choice == :invoice
|
341
|
+
return @amount if choice == :offer
|
342
|
+
return -1
|
343
|
+
end
|
344
|
+
|
345
|
+
def cost choice
|
346
|
+
return @cost_invoice if choice == :invoice
|
347
|
+
return @cost_offer if choice == :offer
|
348
|
+
return -1.to_euro
|
349
|
+
end
|
350
|
+
|
351
|
+
def tax choice
|
352
|
+
return @tax_invoice if choice == :invoice
|
353
|
+
return @tax_offer if choice == :offer
|
354
|
+
return -1.to_euro
|
355
|
+
end
|
356
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#http://stackoverflow.com/questions/6407141/how-can-i-have-ruby-logger-log-output-to-stdout-as-well-as-file
|
2
|
+
require 'logger'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class MultiIO
|
6
|
+
def initialize(*targets)
|
7
|
+
@targets = targets
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(*args)
|
11
|
+
@targets.each {|t| t.write(*args); t.flush}
|
12
|
+
end
|
13
|
+
|
14
|
+
def close
|
15
|
+
@targets.each(&:close)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class AsciiLogger
|
20
|
+
|
21
|
+
# logger.log, "message", :stdo
|
22
|
+
# logger.log, "message", :file
|
23
|
+
# logger.log, "message", :both
|
24
|
+
# log, error, info, warn, fatal, unknown
|
25
|
+
def initialize name, path
|
26
|
+
path = File.expand_path path
|
27
|
+
FileUtils.touch path
|
28
|
+
@log_file = File.open path, ?a
|
29
|
+
@known_loggers = [:file, :stdo, :both]
|
30
|
+
@known_methods = [:info, :warn, :error, :fatal, :unknown]
|
31
|
+
|
32
|
+
@file_logger = Logger.new MultiIO.new @log_file
|
33
|
+
@stdo_logger = Logger.new STDOUT
|
34
|
+
@both_logger = Logger.new MultiIO.new STDOUT, @log_file
|
35
|
+
|
36
|
+
@file_logger.progname = name
|
37
|
+
@stdo_logger.progname = name
|
38
|
+
@both_logger.progname = name
|
39
|
+
end
|
40
|
+
|
41
|
+
def log logger_name, method_name, message
|
42
|
+
raise "#{method_name}, unknown method type, use #{@known_methods}" unless @known_methods.include? method_name
|
43
|
+
raise "#{logger_name}, unknown logger type, use #{@known_loggers}" unless @known_loggers.include? logger_name
|
44
|
+
|
45
|
+
logger_name = "@#{(logger_name.to_s)}_logger".to_sym
|
46
|
+
if instance_variables.include? logger_name
|
47
|
+
logger = instance_variable_get logger_name
|
48
|
+
logger.method(method_name).call message
|
49
|
+
else
|
50
|
+
puts "ERROR: logger not found (#{logger_name})"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# imitates stdlib logger interface -> AsciiLogger::error message, {:stdo\:file\:both}
|
55
|
+
def method_missing method_name, *stuff
|
56
|
+
if @known_methods.include? method_name.to_sym
|
57
|
+
message = stuff[0]
|
58
|
+
logger = stuff[1].to_sym if stuff[1]
|
59
|
+
logger = :both unless @known_loggers.include? logger
|
60
|
+
log logger, method_name.to_sym, message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'date'
|
2
|
+
#require File.join __dir__ + '/rfc5322_regex.rb'
|
3
|
+
|
4
|
+
module Filters
|
5
|
+
|
6
|
+
|
7
|
+
def strpdates(string,pattern = nil)
|
8
|
+
return [Date.today] unless string.class == String
|
9
|
+
if pattern
|
10
|
+
return [Date.strptime(string, pattern).to_date]
|
11
|
+
else
|
12
|
+
p = string.split('.')
|
13
|
+
p_range = p[0].split('-')
|
14
|
+
|
15
|
+
if p_range.length == 1
|
16
|
+
t = Date.new p[2].to_i, p[1].to_i, p[0].to_i
|
17
|
+
return [t]
|
18
|
+
|
19
|
+
elsif p_range.length == 2
|
20
|
+
t1 = Date.new p[2].to_i, p[1].to_i, p_range[0].to_i
|
21
|
+
t2 = Date.new p[2].to_i, p[1].to_i, p_range[1].to_i
|
22
|
+
return [t1,t2]
|
23
|
+
|
24
|
+
else
|
25
|
+
fail
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_email email
|
31
|
+
email =~ $RFC5322
|
32
|
+
end
|
33
|
+
|
34
|
+
def filter_client_email email
|
35
|
+
return fail_at :client_email unless check_email email
|
36
|
+
email
|
37
|
+
end
|
38
|
+
|
39
|
+
def filter_canceled canceled
|
40
|
+
@STATUS = :canceled if @STATUS != :unparsable and canceled
|
41
|
+
canceled
|
42
|
+
end
|
43
|
+
|
44
|
+
def filter_event_dates dates
|
45
|
+
dates.each {|d|
|
46
|
+
unless d[:time].nil? or d[:end].nil? ## time and end is missleading
|
47
|
+
@logger.warn "FILTER: #{name} missleading: time and end_date"
|
48
|
+
return fail_at :event_dates
|
49
|
+
end
|
50
|
+
|
51
|
+
d[:begin] = Date.parse(d[:begin]) if d[:begin].class == String
|
52
|
+
|
53
|
+
if not d[:time].nil?
|
54
|
+
d[:time][:begin] = DateTime.strptime("#{d[:time][:begin]} #{d[:begin]}", "%H:%M %d.%m.%Y" ) if d[:time][:begin]
|
55
|
+
d[:time][:end] = DateTime.strptime("#{d[:time][:end] } #{d[:begin]}", "%H:%M %d.%m.%Y" ) if d[:time][:end]
|
56
|
+
end
|
57
|
+
|
58
|
+
if d[:end].class == String
|
59
|
+
d[:end] = Date.parse(d[:end])
|
60
|
+
else
|
61
|
+
d[:end] = d[:begin]
|
62
|
+
end
|
63
|
+
}
|
64
|
+
dates
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_event_description string
|
68
|
+
return "" unless string
|
69
|
+
string.strip
|
70
|
+
end
|
71
|
+
|
72
|
+
def filter_manager string
|
73
|
+
string.strip
|
74
|
+
end
|
75
|
+
|
76
|
+
def filter_messages messages
|
77
|
+
messages[ @data[:lang].to_sym ]
|
78
|
+
end
|
79
|
+
|
80
|
+
def filter_products products
|
81
|
+
new_products = []
|
82
|
+
products.each{|k,v|
|
83
|
+
if [String, Symbol].include? k.class
|
84
|
+
v[:name] = k
|
85
|
+
new_products.push InvoiceProduct.new v , @settings
|
86
|
+
elsif k.class == Hash
|
87
|
+
new_products.push InvoiceProduct.new k.merge(v), @settings
|
88
|
+
#new_products.push k.merge(v)
|
89
|
+
else
|
90
|
+
return k
|
91
|
+
throw :filter_error
|
92
|
+
end
|
93
|
+
}
|
94
|
+
|
95
|
+
return new_products
|
96
|
+
end
|
97
|
+
|
98
|
+
def filter_created date
|
99
|
+
return Date.parse date if date.class == String
|
100
|
+
fail_at :created_date
|
101
|
+
end
|
102
|
+
|
103
|
+
def filter_offer_date date
|
104
|
+
return Date.parse date if date.class == String
|
105
|
+
fail_at :offer_date
|
106
|
+
return Date.today
|
107
|
+
end
|
108
|
+
|
109
|
+
def filter_invoice_number number
|
110
|
+
return fail_at :invoice_number if number.nil?
|
111
|
+
"R#{number.to_s.rjust(3, ?0)}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def filter_invoice_date date
|
115
|
+
return Date.parse date if date.class == String
|
116
|
+
fail_at :invoice_date
|
117
|
+
return Date.today
|
118
|
+
end
|
119
|
+
|
120
|
+
def filter_invoice_payed_date date
|
121
|
+
return Date.parse date if date.class == String
|
122
|
+
return fail_at :invoice_payed
|
123
|
+
end
|
124
|
+
|
125
|
+
def filter_hours_salary salary
|
126
|
+
salary.to_euro
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|