africompta 1.9.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +74 -0
- data/TODO +31 -0
- data/Test/ac_account.rb +128 -0
- data/Test/ac_africompta.rb +1001 -0
- data/Test/ac_big.rb +62 -0
- data/Test/ac_movement.rb +59 -0
- data/Test/ac_sqlite.rb +139 -0
- data/Test/config_test.yaml +31 -0
- data/Test/db.testGestion +0 -0
- data/Test/test.rb +39 -0
- data/VERSION +140 -0
- data/africompta.gemspec +20 -0
- data/lib/africompta/acaccess.rb +257 -0
- data/lib/africompta/acqooxview.rb +77 -0
- data/lib/africompta/africompta.rb +83 -0
- data/lib/africompta/entities/account.rb +995 -0
- data/lib/africompta/entities/acschemas.rb +16 -0
- data/lib/africompta/entities/movement.rb +292 -0
- data/lib/africompta/entities/remote.rb +27 -0
- data/lib/africompta/entities/users.rb +55 -0
- data/lib/africompta/views/edit/movement.rb +8 -0
- data/lib/africompta/views/edit/tabs.rb +8 -0
- data/lib/africompta/views/report/annual.rb +3 -0
- data/lib/africompta/views/report/tabs.rb +3 -0
- data/lib/africompta.rb +2 -0
- metadata +84 -0
@@ -0,0 +1,292 @@
|
|
1
|
+
DEBUG_SLOW=4
|
2
|
+
class Movements < Entities
|
3
|
+
attr_reader :check_state, :check_progress
|
4
|
+
|
5
|
+
def setup_data
|
6
|
+
@default_type = :SQLiteAC
|
7
|
+
@data_field_id = :id
|
8
|
+
value_int :index
|
9
|
+
|
10
|
+
value_entity_account :account_src_id
|
11
|
+
value_entity_account :account_dst_id
|
12
|
+
value_float :value
|
13
|
+
value_str :desc
|
14
|
+
value_date :date
|
15
|
+
value_int :revision
|
16
|
+
value_str :global_id
|
17
|
+
value_int :rev_index
|
18
|
+
end
|
19
|
+
|
20
|
+
def migration_1(m)
|
21
|
+
dputs(1) { "Migrating #{m.id}" }
|
22
|
+
m.rev_index = m.id
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_json(str)
|
26
|
+
self.from_s(ActiveSupport::JSON.decode(str)['str'])
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.get_accounts(src, dst)
|
30
|
+
[Accounts.match_by_global_id(src), Accounts.match_by_global_id(dst)]
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.mbgi(global_id)
|
34
|
+
self.match_by_global_id(global_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.from_s(str)
|
38
|
+
str.force_encoding(Encoding::UTF_8)
|
39
|
+
dputs(3) { "Getting movement from #{str.inspect}" }
|
40
|
+
desc, str = str.split("\r")
|
41
|
+
global_id, value, date, src, dst = str.split("\t")
|
42
|
+
#date = Time.parse(date).to_ss
|
43
|
+
date = Date.strptime(date, '%Y-%m-%d')
|
44
|
+
value = value.to_f
|
45
|
+
a_src, a_dst = self.get_accounts(src, dst)
|
46
|
+
if not a_src or not a_dst
|
47
|
+
dputs(0) { "Couldn't parse #{str.inspect}: " +
|
48
|
+
(a_src ? '' : "account #{src} not found. ") +
|
49
|
+
(a_dst ? '' : "account #{dst} not found") }
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
# Does the movement already exist?
|
53
|
+
dputs(DEBUG_SLOW) { 'from_s 1'
|
54
|
+
}
|
55
|
+
our_m = nil
|
56
|
+
if not (our_m = self.mbgi(global_id))
|
57
|
+
dputs(3) { 'New movement' }
|
58
|
+
our_m = self.create(desc, date, value,
|
59
|
+
a_src, a_dst)
|
60
|
+
dputs(DEBUG_SLOW) { 'from_s 2' }
|
61
|
+
our_m.global_id = global_id
|
62
|
+
else
|
63
|
+
dputs(1) { "Overwriting movement\n#{our_m.to_json.inspect} with" }
|
64
|
+
# And update it
|
65
|
+
our_m.set(desc, date, value, a_src.id, a_dst.id)
|
66
|
+
dputs(1) { "#{our_m.to_json.inspect}" }
|
67
|
+
dputs(2) { "Now we're #{our_m.rev_index}:#{our_m.id} -> #{global_id}" }
|
68
|
+
end
|
69
|
+
dputs(DEBUG_SLOW) { 'from_s 3' }
|
70
|
+
return our_m
|
71
|
+
end
|
72
|
+
|
73
|
+
def create(desc, date, value, source, dest)
|
74
|
+
return nil if source == dest
|
75
|
+
dputs(DEBUG_SLOW) { 'create - 1' }
|
76
|
+
if date.class == String
|
77
|
+
date = Date.strptime(date, '%Y-%m-%d')
|
78
|
+
end
|
79
|
+
t = super(:desc => desc, :date => date,
|
80
|
+
:value => 0, :account_src_id => source.id, :account_dst_id => dest.id)
|
81
|
+
dputs(DEBUG_SLOW) { 'create - 2' }
|
82
|
+
t.value = value
|
83
|
+
dputs(DEBUG_SLOW) { 'create - 3' }
|
84
|
+
t.global_id = Users.match_by_name('local').full + '-' + t.id.to_s
|
85
|
+
dputs(DEBUG_SLOW) { 'create - 4' }
|
86
|
+
dputs(1) { "Created #{t.to_json.inspect}" }
|
87
|
+
t
|
88
|
+
end
|
89
|
+
|
90
|
+
def search_index_range(from, to)
|
91
|
+
@data.select { |k, v|
|
92
|
+
v._rev_index && v._rev_index >= from && v._rev_index <= to
|
93
|
+
}.map { |k, v|
|
94
|
+
get_data_instance(k)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_account(db, id)
|
99
|
+
db.execute("select * from compta_accounts where id=#{id}").first[4]
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_against_db(file)
|
103
|
+
# First build
|
104
|
+
# in_db - content of 'file' in .to_s format
|
105
|
+
# in_local - content available locally in .to_s format
|
106
|
+
in_db, diff, in_local = [], [], []
|
107
|
+
|
108
|
+
dputs(3) { 'Searching all movements' }
|
109
|
+
@check_state = 'Collect local'
|
110
|
+
@check_progress = 0.0
|
111
|
+
in_local = Movements.search_all_.reject { |m| m.value.to_f.round(3) == 0.0 }
|
112
|
+
progress_step = 1.0 / (in_local.size + 1)
|
113
|
+
dputs(3) { "Movements total: #{in_local.size}" }
|
114
|
+
|
115
|
+
@check_state = 'Collect local'
|
116
|
+
in_local = in_local.collect { |a|
|
117
|
+
@check_progress += progress_step
|
118
|
+
a.to_s
|
119
|
+
}
|
120
|
+
|
121
|
+
dputs(3) { 'Going to check all movements' }
|
122
|
+
@check_state = 'Collect file-DB'
|
123
|
+
@check_progress = 0.0
|
124
|
+
SQLite3::Database.new(file) do |db|
|
125
|
+
db.execute('select id, desc, global_id, value, date, account_src_id, account_dst_id '+
|
126
|
+
'from compta_movements').each do |row|
|
127
|
+
@check_progress += progress_step
|
128
|
+
#dputs(3) { "Looking at #{row}" }
|
129
|
+
|
130
|
+
id_, desc_, gid_, value_, date_, src_, dst_ = row
|
131
|
+
if value_.to_f.round(3) != 0.0
|
132
|
+
in_db.push "#{desc_}\r#{gid_}\t" +
|
133
|
+
"#{sprintf('%.3f', value_.to_f.round(3))}\t#{date_.to_s}\t"+
|
134
|
+
"#{get_account(db, src_)}\t#{get_account(db, dst_)}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Now compare what is available only in db and what is available only locally
|
140
|
+
dputs(3) { 'Verifying movements on one side only' }
|
141
|
+
@check_state = 'On one side'
|
142
|
+
@check_progress = 0.0
|
143
|
+
in_db.delete_if { |a|
|
144
|
+
@check_progress += progress_step
|
145
|
+
in_local.delete(a)
|
146
|
+
}
|
147
|
+
|
148
|
+
# And search for accounts with same global-id but different content
|
149
|
+
dputs(3) { 'Verifying mixed-up movements' }
|
150
|
+
(in_db + in_local).sort_by { |a| a.match(/\r(.*?)\t/)[1] }
|
151
|
+
@check_state = 'Mixed-up'
|
152
|
+
@check_progress = 0.0
|
153
|
+
progress_step = 1.0 / (in_db.size + 1)
|
154
|
+
in_db.delete_if { |a|
|
155
|
+
@check_progress += progress_step
|
156
|
+
gid = a.match(/\r(.*?)\t/)[1]
|
157
|
+
if c = in_local.find { |b| b =~ /\r#{gid}\t/ }
|
158
|
+
diff.push [a, c]
|
159
|
+
in_local.delete c
|
160
|
+
end
|
161
|
+
}
|
162
|
+
|
163
|
+
@check_state = 'Done'
|
164
|
+
[in_db, diff, in_local]
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
class Movement < Entity
|
171
|
+
|
172
|
+
def init_instance
|
173
|
+
end
|
174
|
+
|
175
|
+
def data_set(f, v)
|
176
|
+
if f != :_rev_index
|
177
|
+
dputs(3){"Updating index for field #{f.inspect}"}
|
178
|
+
new_index
|
179
|
+
end
|
180
|
+
super(f, v)
|
181
|
+
end
|
182
|
+
|
183
|
+
def new_index
|
184
|
+
u_l = Users.match_by_name('local')
|
185
|
+
self.rev_index = u_l.movement_index.to_i
|
186
|
+
u_l.movement_index = self.rev_index + 1
|
187
|
+
dputs(3) { "index is #{self.rev_index} and date is --#{self.date}--" }
|
188
|
+
dputs(3) { "User('local').rev_index is: " + Users.match_by_name('local').movement_index.to_s }
|
189
|
+
end
|
190
|
+
|
191
|
+
def get_index
|
192
|
+
return self.rev_index
|
193
|
+
end
|
194
|
+
|
195
|
+
def is_in_account(a)
|
196
|
+
return (a == account_src or a == account_dst)
|
197
|
+
end
|
198
|
+
|
199
|
+
def value=(v)
|
200
|
+
if account_src and account_dst
|
201
|
+
dputs(3) { 'value=' + v.to_s + ':' + account_src.total.to_s }
|
202
|
+
diff = value.to_f - v.to_f
|
203
|
+
account_src.total = account_src.total.to_f + (diff * account_src.multiplier)
|
204
|
+
account_dst.total = account_dst.total.to_f - (diff * account_dst.multiplier)
|
205
|
+
end
|
206
|
+
data_set(:_value, v)
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_value(account)
|
210
|
+
account_side = (account_src == account ? -1 : 1)
|
211
|
+
dputs(5) { "account_src #{account_src.inspect} == account #{account.inspect}" }
|
212
|
+
dputs(5) { "Account_side = #{account_side}" }
|
213
|
+
value.to_f * account.multiplier.to_f * account_side
|
214
|
+
end
|
215
|
+
|
216
|
+
def get_other_account(account)
|
217
|
+
account_src == account ? account_dst : account_src
|
218
|
+
end
|
219
|
+
|
220
|
+
def move_from_to(from, to)
|
221
|
+
v = self.value
|
222
|
+
self.value = 0
|
223
|
+
if account_src_id == from
|
224
|
+
self.account_src_id = to
|
225
|
+
end
|
226
|
+
if account_dst_id == from
|
227
|
+
self.account_dst_id = to
|
228
|
+
end
|
229
|
+
self.value = v
|
230
|
+
end
|
231
|
+
|
232
|
+
def set(desc, date, value, source, dest)
|
233
|
+
dputs(3) { 'self.value ' + self.value.to_s + ' - ' + value.to_s }
|
234
|
+
self.value = 0
|
235
|
+
self.account_src_id, self.account_dst_id = source, dest
|
236
|
+
if false
|
237
|
+
# Do some date-magic, so that we can give either the day, day and month or
|
238
|
+
# a complete date. The rest is filled up with todays date.
|
239
|
+
date = date.split('/')
|
240
|
+
da = Date.today
|
241
|
+
d = [da.day, da.month, da.year]
|
242
|
+
date += d.last(3 - date.size)
|
243
|
+
if date[2].to_s.size > 2
|
244
|
+
self.date = Date.strptime(date.join('/'), '%d/%m/%Y')
|
245
|
+
else
|
246
|
+
self.date = Date.strptime(date.join('/'), '%d/%m/%y')
|
247
|
+
end
|
248
|
+
else
|
249
|
+
self.date = Date.from_s(date.to_s)
|
250
|
+
end
|
251
|
+
self.desc, self.value = desc, value
|
252
|
+
dputs(DEBUG_SLOW) { 'Getting new index' }
|
253
|
+
self.new_index
|
254
|
+
dputs(DEBUG_SLOW) { 'Date ' + self.date.to_s }
|
255
|
+
end
|
256
|
+
|
257
|
+
def to_s
|
258
|
+
dputs(5) { "I am: #{to_hash.inspect} - my id is: #{global_id}" }
|
259
|
+
"#{desc}\r#{global_id}\t" +
|
260
|
+
"#{sprintf('%.3f', value.to_f.round(3))}\t#{date.to_s}\t" +
|
261
|
+
account_src.global_id.to_s + "\t" +
|
262
|
+
account_dst.global_id.to_s
|
263
|
+
end
|
264
|
+
|
265
|
+
def to_json
|
266
|
+
ActiveSupport::JSON.encode(:str => to_s)
|
267
|
+
end
|
268
|
+
|
269
|
+
# Copying over data from old AfriCompta
|
270
|
+
def account_src
|
271
|
+
account_src_id
|
272
|
+
end
|
273
|
+
|
274
|
+
def account_dst
|
275
|
+
account_dst_id
|
276
|
+
end
|
277
|
+
|
278
|
+
def delete
|
279
|
+
dputs(DEBUG_SLOW) { "Deleting movement #{desc}" }
|
280
|
+
src, dst = account_src, account_dst
|
281
|
+
dputs(3) { "totals before: #{src.get_path}=#{src.total}, " +
|
282
|
+
"#{dst.get_path}=#{dst.total}" }
|
283
|
+
self.value = 0
|
284
|
+
dputs(3) { "totals after: #{src.get_path}=#{src.total}, " +
|
285
|
+
"#{dst.get_path}=#{dst.total}" }
|
286
|
+
super
|
287
|
+
end
|
288
|
+
|
289
|
+
def value_form
|
290
|
+
Account.total_form(value)
|
291
|
+
end
|
292
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Remotes < Entities
|
2
|
+
|
3
|
+
def create( d )
|
4
|
+
r = super( d )
|
5
|
+
d.has_key?( :account_index ) || r.account_index = 0
|
6
|
+
d.has_key?( :movement_index ) || r.movement_index = 0
|
7
|
+
r
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup_data
|
11
|
+
value_str :url
|
12
|
+
value_str :name
|
13
|
+
value_str :pass
|
14
|
+
value_int :account_index
|
15
|
+
value_int :movement_index
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Remote < Entity
|
20
|
+
def update_movement_index
|
21
|
+
self.movement_index = Users.match_by_name('local').movement_index - 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_account_index
|
25
|
+
self.account_index = Users.match_by_name('local').account_index - 1
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Users < Entities
|
2
|
+
|
3
|
+
def setup_data
|
4
|
+
@default_type = :SQLiteAC
|
5
|
+
@data_field_id = :id
|
6
|
+
|
7
|
+
value_str :name
|
8
|
+
value_str :full
|
9
|
+
value_str :pass
|
10
|
+
#value_array :accounts
|
11
|
+
# The last account_index that got transmitted
|
12
|
+
value_int :account_index
|
13
|
+
# The last movement_index that got transmitted
|
14
|
+
value_int :movement_index
|
15
|
+
end
|
16
|
+
|
17
|
+
def load
|
18
|
+
super
|
19
|
+
if Users.search_by_name('local').count == 0
|
20
|
+
user = Users.create('local', Digest::MD5.hexdigest((rand 2**128).to_s).to_s,
|
21
|
+
rand(2 ** 128).to_s)
|
22
|
+
dputs(1) { "Created local user #{user}" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def migration_1(u)
|
27
|
+
u.account_index ||= 0
|
28
|
+
u.movement_index ||= 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def create(name, full = nil, pass = nil)
|
32
|
+
if not full or not pass
|
33
|
+
dputs(2) { "Creating with hash: #{name.inspect}" }
|
34
|
+
name, full, pass = name[:name], name[:full], name[:pass]
|
35
|
+
end
|
36
|
+
new_user = super(:name => name, :full => full, :pass => pass)
|
37
|
+
new_user.account_index, new_user.movement_index = 0, 0
|
38
|
+
new_user
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class User < Entity
|
43
|
+
def update_movement_index
|
44
|
+
self.movement_index = Users.match_by_name('local').movement_index - 1
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_account_index
|
48
|
+
self.account_index = Users.match_by_name('local').account_index - 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_all
|
52
|
+
update_movement_index
|
53
|
+
update_account_index
|
54
|
+
end
|
55
|
+
end
|
data/lib/africompta.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: africompta
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.9.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Linus Gasser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: qooxview
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: With this module you can have a simple accounting-system
|
28
|
+
email: ineiti@linusetviviane.ch
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- ".gitignore"
|
34
|
+
- Gemfile
|
35
|
+
- Gemfile.lock
|
36
|
+
- TODO
|
37
|
+
- Test/ac_account.rb
|
38
|
+
- Test/ac_africompta.rb
|
39
|
+
- Test/ac_big.rb
|
40
|
+
- Test/ac_movement.rb
|
41
|
+
- Test/ac_sqlite.rb
|
42
|
+
- Test/config_test.yaml
|
43
|
+
- Test/db.testGestion
|
44
|
+
- Test/test.rb
|
45
|
+
- VERSION
|
46
|
+
- africompta.gemspec
|
47
|
+
- lib/africompta.rb
|
48
|
+
- lib/africompta/acaccess.rb
|
49
|
+
- lib/africompta/acqooxview.rb
|
50
|
+
- lib/africompta/africompta.rb
|
51
|
+
- lib/africompta/entities/account.rb
|
52
|
+
- lib/africompta/entities/acschemas.rb
|
53
|
+
- lib/africompta/entities/movement.rb
|
54
|
+
- lib/africompta/entities/remote.rb
|
55
|
+
- lib/africompta/entities/users.rb
|
56
|
+
- lib/africompta/views/edit/movement.rb
|
57
|
+
- lib/africompta/views/edit/tabs.rb
|
58
|
+
- lib/africompta/views/report/annual.rb
|
59
|
+
- lib/africompta/views/report/tabs.rb
|
60
|
+
homepage: https://github.com/ineiti/AfriCompta
|
61
|
+
licenses:
|
62
|
+
- GPLv3
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.2.2
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Africompta-module for QooxView
|
84
|
+
test_files: []
|