africompta 1.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,257 @@
1
+ # This is the interface to AfriCompta. It is called through different
2
+ # Post/Get-handlers over HTTP
3
+
4
+
5
+ $VERSION = 0x1120
6
+
7
+ class ACaccess < RPCQooxdooPath
8
+ def self.parse(r, p, q)
9
+ dputs(2) { "in ACaccess: #{p} - #{q.inspect}" }
10
+ method = p.gsub(/^\/acaccess\/merge\//, '')
11
+ dputs(3) { "Calling method #{method} of #{r}" }
12
+ case r
13
+ when /GET/
14
+ ret = self.get(method)
15
+ when /POST/
16
+ ret = self.post(method, q)
17
+ end
18
+ dputs(3) { "Result is #{ret.inspect}" }
19
+ ret
20
+ end
21
+
22
+ def self.print_movements(start, stop)
23
+ start, stop = start.to_i, stop.to_i
24
+ dputs(2) { "Doing print_movements from #{start.class}:#{start}"+
25
+ " to #{stop.class}:#{stop}" }
26
+ ret = ''
27
+ # Movements.search_all.select{|m|
28
+ # mi = m.rev_index
29
+ # m and mi and mi >= start and mi <= stop
30
+ Movements.search_index_range(start, stop).each { |m|
31
+ if start > 0
32
+ dputs(4) { "Mer: Movement #{m.desc}, #{m.value}" }
33
+ end
34
+ ret += m.to_s + "\n"
35
+ }
36
+ dputs(3) { "Found movements: #{ret.inspect}" }
37
+ ret
38
+ end
39
+
40
+ def self.print_movements_actual(start, stop)
41
+ start, stop = start.to_i, stop.to_i
42
+ dputs(2) { "Doing print_movements_actual from #{start.class}:#{start}"+
43
+ " to #{stop.class}:#{stop}" }
44
+ ret = ''
45
+ actual_ids = []
46
+ AccountRoot.actual.get_tree { |a|
47
+ actual_ids.push a.id
48
+ }
49
+ movs = Movements.search_all.select { |m|
50
+ mi = m.rev_index
51
+ m and mi and mi >= start and mi <= stop and actual_ids.find(m.account_src_id)
52
+ }
53
+ dputs(2) { "Found #{movs.length} movements between #{start}..#{stop}" }
54
+ movs.each { |m|
55
+ if start > 0
56
+ dputs(4) { "Mer: Movement #{m.desc}, #{m.value}" }
57
+ ai = actual_ids.find(m.account_src_id.id)
58
+ dputs(4) { "movement_src is #{m.account_src_id.inspect} from #{ai.inspect}" }
59
+ dputs(4) { "actual_ids is #{actual_ids.inspect}" }
60
+ end
61
+ ret += m.to_s + "\n"
62
+ }
63
+ dputs(3) { "Found movements: #{ret.inspect}" }
64
+ ret
65
+ end
66
+
67
+ def self.accounts_fetch_old(user)
68
+ ret = ''
69
+
70
+ Accounts.matches_by_account_id(0).to_a.concat(
71
+ Accounts.matches_by_account_id(nil)).sort { |a, b|
72
+ a.global_id <=> b.global_id }.each { |a|
73
+ dputs(2) { "Found one root-account #{a.rev_index} - #{a.path_id}" }
74
+ if a.global_id
75
+ dputs(3) { "It's global" }
76
+ a.get_tree { |acc|
77
+ dputs(4) { "In get_tree #{acc.path_id}: #{acc.deleted == true} - #{acc.rev_index}" }
78
+ if acc.rev_index > user.account_index
79
+ dputs(4) { "Found account #{acc.name} with index #{acc.rev_index}" }
80
+ ret += "#{acc.to_s}\n"
81
+ end
82
+ }
83
+ else
84
+ dputs(3) { "It's not global" }
85
+ end
86
+ dputs(3) { 'Will search for next' }
87
+ }
88
+ ret
89
+ end
90
+
91
+ def self.accounts_fetch(user)
92
+ Accounts.data.select { |_k, v| v._rev_index > user.account_index }.
93
+ collect { |k, _v| Accounts.get_data_instance(k) }.
94
+ sort_by { |a| a.path }.
95
+ collect { |a| a.to_s }.
96
+ join("\n")
97
+ end
98
+
99
+ def self.get(p)
100
+ # Two cases:
101
+ # path/arg/user,pass - arg is used
102
+ # path/user,pass - arg is nil
103
+ path, arg, id = p.split("/")
104
+ arg, id = id, arg if not id
105
+ user, pass = id.split(",")
106
+
107
+ log_msg 'ACaccess.get', "get-merge-path #{path} - #{arg} with " +
108
+ "user #{user} and pass #{pass}"
109
+ u = Users.match_by_name(user)
110
+ u_local = Users.match_by_name('local')
111
+ if not (u and u.pass == pass)
112
+ return "User #{user} not known with pass #{pass}"
113
+ end
114
+
115
+ case path
116
+ when /accounts_get(.*)/
117
+ # Gets all accounts available (to that user) that have been changed
118
+ # since the last update, again, do it from the root(s), else we have
119
+ # a problem for children without parents
120
+ ret = ''
121
+ dputs(2) { "user index is: #{u.account_index}" }
122
+ # Returns only one account
123
+ if $1 == '_one'
124
+ return Accounts.match_by_global_id(arg).to_s
125
+ end
126
+ if $1 == '_all'
127
+ dputs(2) { 'Putting all accounts' }
128
+ ret = Accounts.search_all.collect { |acc|
129
+ dputs(4) { "Found account #{acc.name} with index #{acc.rev_index}" }
130
+ acc.to_s(true)
131
+ }.join("\n")
132
+ elsif $1 == '_count'
133
+ ret += Accounts.search_all.size.to_s
134
+ elsif $1 == '_part'
135
+ acc_start, acc_end = arg.split(",")
136
+ dputs(2) { "Putting accounts #{acc_start}..#{acc_end}" }
137
+ Accounts.search_all.select { |acc|
138
+ acc.rev_index >= acc_start.to_i and acc.rev_index <= acc_end.to_i
139
+ }.each { |acc|
140
+ dputs(4) { "Found account #{acc.name} with index #{acc.rev_index}" }
141
+ ret += "#{acc.to_s(true)}\n"
142
+ }
143
+ else
144
+ dputs(2) { 'Starting to search accounts' }
145
+ t = Time.now
146
+ ret += ACaccess.accounts_fetch(u)
147
+ dputs(2) { "Found #{ret.count("\n")} after #{Time.now - t} seconds" }
148
+ end
149
+ dputs(3) { 'Finished search' }
150
+ return ret
151
+
152
+ # Gets all movements (for the accounts of that user)
153
+ when /movements_get(.*)/
154
+ dputs(2) { "movements_get#{$1} with #{arg.inspect}" }
155
+ start, stop = u.movement_index + 1, u_local.movement_index - 1
156
+ # Returns only one account
157
+ if $1 == '_one'
158
+ return Movements.match_by_global_id(arg).to_s
159
+ end
160
+ if $1 == '_all_actual'
161
+ start, stop = arg.split(/,/)
162
+ ret = print_movements_actual(start, stop)
163
+ else
164
+ if $1 == '_all'
165
+ start, stop = arg.split(/,/)
166
+ end
167
+ ret = print_movements(start, stop)
168
+ end
169
+ dputs(2) { "Sending a total of #{ret.length}" }
170
+ dputs(3) { "Sending:\n #{ret.inspect}" }
171
+ return ret
172
+
173
+ when 'version'
174
+ return $VERSION.to_s
175
+
176
+ when 'index'
177
+ return [u_local.account_index, u_local.movement_index].join(",")
178
+
179
+ when 'local_id'
180
+ return u_local.full
181
+
182
+ when 'reset_user_indexes'
183
+ u.update_account_index
184
+ u.update_movement_index
185
+
186
+ when 'reset_user_account_indexes'
187
+ u.update_account_index
188
+
189
+ when 'reset_user_movement_indexes'
190
+ u.update_movement_index
191
+
192
+ when 'movement_delete'
193
+ dputs(3) { "Going to delete movement #{arg}" }
194
+ while mov = Movements.match_by_global_id(arg)
195
+ dputs(3) { "Found movement #{mov.inspect}" }
196
+ mov.delete
197
+ end
198
+ dputs(3) { 'Finished deleting' }
199
+ end
200
+ return ''
201
+ end
202
+
203
+ def self.post(path, input)
204
+ dputs(5) { "self.post with #{path} and #{input.inspect}" }
205
+ log_msg 'ACaccess.post', "post-merge-path #{path} with " +
206
+ "user #{input['user']} and pass #{input['pass']}"
207
+ user, pass = input['user'], input['pass']
208
+ u = Users.match_by_name(user)
209
+ if not (u and u.pass == pass)
210
+ dputs(1) { "Didn't find user #{user}" }
211
+ return "User #{user} not known with pass #{pass}"
212
+ end
213
+ case path
214
+ # Retrieves id of the path of the account
215
+ when /account_get_id/
216
+ account = input['account']
217
+ dputs(2) { "account_get_id with path #{account}" }
218
+ a = Accounts.get_id_by_path(account)
219
+ a and return a
220
+ dputs(2) { "didn't find anything" }
221
+ return nil
222
+
223
+ when 'movements_put'
224
+ dputs(3) { "Going to put some movements: #{input['movements'].inspect}" }
225
+ movs = ActiveSupport::JSON.decode(input['movements'])
226
+ dputs(3) { "movs is now #{movs.inspect}" }
227
+ if movs.size > 0
228
+ movs.each { |m|
229
+ if mov = Movements.from_json(m)
230
+ dputs(2) { "Saved movement #{mov.global_id}" }
231
+ else
232
+ dputs(0) { "Error: couldn't create movement from #{m.inspect}" }
233
+ end
234
+ u.update_movement_index
235
+ }
236
+ end
237
+ when 'movement_delete'
238
+ dputs(3) { 'Going to delete movement' }
239
+ while mov = Movements.match_by_global_id(input['global_id'])
240
+ dputs(3) { "Found movement #{mov.inspect}" }
241
+ mov.delete
242
+ end
243
+ dputs(3) { 'Finished deleting' }
244
+ when 'account_put'
245
+ dputs(3) { "Going to put account #{input['account'].inspect}" }
246
+ acc = Accounts.from_s(input['account'])
247
+ u.update_account_index
248
+ dputs(2) { "Saved account #{acc.global_id}" }
249
+ when 'account_delete'
250
+ dputs(3) { 'Going to delete account' }
251
+ acc = Accounts.match_by_global_id(input['global_id'])
252
+ acc.delete(true)
253
+ end
254
+ return 'ok'
255
+ end
256
+ end
257
+
@@ -0,0 +1,77 @@
1
+ # AfriCompta - handler of a simple accounting-system for "Gestion"
2
+ #
3
+ # What follows are some definitions used by other modules
4
+
5
+ require 'digest/md5'
6
+
7
+ # We want a simple time-print
8
+ class Time
9
+ def to_s
10
+ day.to_s + '/' + month.to_s
11
+ end
12
+
13
+ def to_ss
14
+ to_s + '/' + year.to_s
15
+ end
16
+ end
17
+
18
+ class Date
19
+ def month_s
20
+ %w(janvier février mars avril mai juin
21
+ juillet août septembre octobre novembre décembre)[month-1]
22
+ end
23
+
24
+ def to_s_eu
25
+ strftime('%d/%m/%y')
26
+ end
27
+
28
+ def to_s_euy
29
+ strftime('%d/%m/%Y')
30
+ end
31
+
32
+ def Date.from_s(s)
33
+ # Do some date-magic, so that we can give either the day, day and month or
34
+ # a complete date. The rest is filled up with todays date.
35
+ date = []
36
+ if s.index('/')
37
+ date = s.split('/')
38
+ else
39
+ date = s.split('-').reverse
40
+ end
41
+ da = Date.today
42
+ d = [da.day, da.month, da.year]
43
+ date += d.last(3 - date.size)
44
+ if date[2].to_s.size > 2
45
+ date = Date.strptime(date.join('/'), '%d/%m/%Y')
46
+ else
47
+ date = Date.strptime(date.join('/'), '%d/%m/%y')
48
+ end
49
+ return date
50
+ end
51
+ end
52
+
53
+ class SQLiteAC < SQLite
54
+ def configure(config)
55
+ super(config, 'compta', 'compta.db')
56
+ end
57
+ end
58
+
59
+ class Float
60
+ def round(precision = 0)
61
+ if precision > 0
62
+ return (self * 10**precision).round / 10.0**precision
63
+ else
64
+ return super()
65
+ end
66
+ end
67
+ end
68
+
69
+ module ACQooxView
70
+ def self.load_entities(preload = true)
71
+ require 'africompta/acaccess'
72
+ Dir[File.dirname(__FILE__) + '/entities/*.rb'].each { |f|
73
+ dputs(2) { "Adding #{f}" }
74
+ require(f)
75
+ }
76
+ end
77
+ end
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/ruby -I../QooxView -wKU
2
+
3
+ DEBUG_LVL=5
4
+ VERSION_AFRICOMPTA='1.9.8'
5
+ require 'fileutils'
6
+
7
+ AFRICOMPTA_DIR=File.dirname(__FILE__)
8
+ CONFIG_FILE='config.yaml'
9
+ if not FileTest.exists? CONFIG_FILE
10
+ puts "Config-file doesn't exist"
11
+ print 'Do you want me to copy a standard one? [Y/n] '
12
+ if gets.chomp.downcase != 'n'
13
+ FileUtils.cp 'config.yaml.default', 'config.yaml'
14
+ end
15
+ end
16
+
17
+ begin
18
+ require 'qooxview'
19
+ require 'africompta/acqooxview'
20
+ rescue Exception => e
21
+ puts e.inspect
22
+ puts e.to_s
23
+ puts e.backtrace
24
+
25
+ dputs( 0 ){ "#{e.inspect}" }
26
+ dputs( 0 ){ "#{e.to_s}" }
27
+ puts e.backtrace
28
+
29
+ puts "Couldn't start AfriCompta - perhaps missing libraries?"
30
+ exit
31
+ end
32
+
33
+ Welcome.nologin
34
+ QooxView::init( 'entities', 'views')
35
+
36
+ # Autosave every 2 minutes
37
+ if ConfigBase.autosave == %w(true)
38
+ $autosave = Thread.new{
39
+ loop {
40
+ sleep 2 * 60
41
+ Entities.save_all
42
+ }
43
+ }
44
+ end
45
+
46
+ trap('SIGINT') {
47
+ throw :ctrl_c
48
+ }
49
+
50
+ $profiling = get_config( nil, :profiling )
51
+ catch :ctrl_c do
52
+ begin
53
+ webrick_port = get_config( 3302, :Webrick, :port )
54
+ dputs(2){"Starting at port #{webrick_port}" }
55
+ if $profiling
56
+ require 'rubygems'
57
+ require 'perftools'
58
+ PerfTools::CpuProfiler.start("/tmp/#{$profiling}") do
59
+ QooxView::startWeb webrick_port
60
+ end
61
+ else
62
+ QooxView::startWeb webrick_port
63
+ end
64
+ rescue Exception => e
65
+ dputs( 0 ){ "#{e.inspect}" }
66
+ dputs( 0 ){ "#{e.to_s}" }
67
+ puts e.backtrace
68
+ dputs( 0 ){ 'Saving all' }
69
+ Entities.save_all
70
+ end
71
+ end
72
+
73
+ if get_config( true, :autosave )
74
+ $autosave.kill
75
+ end
76
+
77
+ if $profiling
78
+ puts "Now run the following:
79
+ pprof.rb --pdf /tmp/#{$profiling} > /tmp/#{$profiling}.pdf
80
+ open /tmp/#{$profiling}.pdf
81
+ CPUPROFILE_FREQUENCY=500
82
+ "
83
+ end