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.
- 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: []
|