africompta 1.9.8

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.
@@ -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