snappler_contable 0.1.0
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 +15 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +315 -0
- data/Rakefile +38 -0
- data/app/models/ledger_account.rb +151 -0
- data/app/models/ledger_account_activo.rb +6 -0
- data/app/models/ledger_account_pasivo.rb +6 -0
- data/app/models/ledger_account_patrimonio_neto.rb +6 -0
- data/app/models/ledger_account_resultado_negativo.rb +6 -0
- data/app/models/ledger_account_resultado_positivo.rb +6 -0
- data/app/models/ledger_currency.rb +3 -0
- data/app/models/ledger_entry.rb +3 -0
- data/app/models/ledger_move.rb +54 -0
- data/lib/generators/snappler_contable/initializer_generator.rb +9 -0
- data/lib/generators/snappler_contable/migrate_generator.rb +24 -0
- data/lib/generators/snappler_contable/templates/snappler_contable_app_ledger_accounts.rb +17 -0
- data/lib/generators/snappler_contable/templates/snappler_contable_migrate.rb +57 -0
- data/lib/snappler_contable/ext/string.rb +5 -0
- data/lib/snappler_contable/railtie.rb +4 -0
- data/lib/snappler_contable/snappler_contable.rb +131 -0
- data/lib/snappler_contable/snappler_contable_active_record_extension.rb +172 -0
- data/lib/snappler_contable/tree_node.rb +47 -0
- data/lib/snappler_contable/version.rb +3 -0
- data/lib/snappler_contable.rb +19 -0
- data/lib/tasks/snappler_contable_tasks.rake +4 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/snappler_contable_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YTk2MmZmNzQ2YThhMTgwMThjZDhmZjgxYWY3MzU1NzkwMWQ1YmI3ZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2FmN2YyNzY1MDk5NWI2YjdmYjUxMDRmMWQ3OWQ5YWMxYTBkZDdhYw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NGU2OTJiZmU2MzQ5NmVhN2NmMmJiMDJlYmU3MTVmZWI0ZjJhNjhmMDQ0MDQy
|
10
|
+
MjI3ODg0ZmIwMWFiY2FjNjBjNjBmYjgyMjMyYWQwOGIzZjk1Y2Y5NTJjOGQ1
|
11
|
+
NjBiMGU1ZWUyNzQ4NTI2YWViMTg1MGI2NjEzMTE5NGEwNmY2NzM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YTcyMTI1OWQ0MTI4NDdjY2QzNmQ0NjA1NzBiMTU1ODZjOGExNTVjYjE1MzY4
|
14
|
+
MjA0MmYxMDJlYzY3NTE1NzE4MzcwM2I3OTU0OTYwODI2NWRkYmE0OTNkNzlk
|
15
|
+
ZDY1MmM2Y2Y3NGY1NzVjNTdjZDQ5ZTE0NGM1ZGU0N2QxNGMzNDA=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
= SnapplerContable
|
2
|
+
|
3
|
+
Esta gema agrega a una aplicacion la capacidad de manejar cuentas contables con el modelo teorico economico.
|
4
|
+
|
5
|
+
== Instalacion
|
6
|
+
|
7
|
+
Agregar esta linea al Gemfile
|
8
|
+
|
9
|
+
gem "snappler_contable"
|
10
|
+
|
11
|
+
Ejecutar
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Después de instalar se deben correr estos comandos
|
16
|
+
|
17
|
+
$ rails g snappler_contable:initializer
|
18
|
+
$ rails g snappler_contable:migrate
|
19
|
+
$ rake db:migrate
|
20
|
+
|
21
|
+
Esto va a crear el achivo:
|
22
|
+
|
23
|
+
config/initializers/snappler_contable.rb
|
24
|
+
|
25
|
+
Donde se tienen que agregar todas las operaciones contables se van a ejecutar en el sistema.
|
26
|
+
|
27
|
+
Tambien va a crear dos migraciones:
|
28
|
+
|
29
|
+
aaaammdd_snappler_contable_migrate.rb
|
30
|
+
|
31
|
+
Que crea la tabla de cuentas, de movimientos, de asientos y de monedas.
|
32
|
+
Se crean 5 registros en la tabla LedgerAccounts que son necesarios para el sistema:
|
33
|
+
|
34
|
+
LedgerAccountActivo : Activo
|
35
|
+
LedgerAccountPasivo : Pasivo
|
36
|
+
LedgerAccountPatrimonioNeto : Patrimonio Neto
|
37
|
+
LedgerAccountResultadoPositivo : Resultado Positivo
|
38
|
+
LedgerAccountResultadoNegativo : Resultado Negativo
|
39
|
+
|
40
|
+
Tambien crea la moneda por defecto:
|
41
|
+
LedgerCurrency.create(name: 'Peso', code: 'ARS')
|
42
|
+
|
43
|
+
Luego crea otra migración llamada:
|
44
|
+
|
45
|
+
aaaammdd_snappler_contable_app_ledger_accounts.rb
|
46
|
+
|
47
|
+
En la que el programador debe agregar las cuentas necesarias para el plan de cuentas de la aplicacion.
|
48
|
+
Ya están cargadas en variables de instancia las 5 cuentas originales.
|
49
|
+
Luego se usa el metodo 'add_child' para agregar cuentas hijas.
|
50
|
+
|
51
|
+
activo = LedgerAccountActivo.first #en ese momento solo existe una
|
52
|
+
sub_cuenta_activo = activo.add_child('Sub cuenta activo')
|
53
|
+
|
54
|
+
Esta función se puede usar en cualquier parte de la applicación.
|
55
|
+
La cuenta hija será de la misma clase que la clase padre.
|
56
|
+
|
57
|
+
== Uso
|
58
|
+
|
59
|
+
La gema va a trabajar con:
|
60
|
+
|
61
|
+
1) Una estructura de tipo árbol de objetos. Cada objeto es una instancia de una de las 5 sub clases de LedgerAccount.
|
62
|
+
El árbol tiene una raiz abstracta y 5 nodos:
|
63
|
+
|
64
|
+
LedgerAccountActivo : Activo
|
65
|
+
LedgerAccountPasivo : Pasivo
|
66
|
+
LedgerAccountPatrimonioNeto : Patrimonio Neto
|
67
|
+
LedgerAccountResultadoPositivo : Resultado Positivo
|
68
|
+
LedgerAccountResultadoNegativo : Resultado Negativo
|
69
|
+
|
70
|
+
Luego se agregaran las cuentas que completen el plan de cuentas específico para la aplicación.
|
71
|
+
Una vez creadas las cuentas del plan, quedaría (por ejemplo) así:
|
72
|
+
|
73
|
+
=> ROOT
|
74
|
+
1 : Activo (1)
|
75
|
+
1.1 : Disponibilidades (2)
|
76
|
+
1.1.1 : Caja (3)
|
77
|
+
1.1.2 : Bancos (4)
|
78
|
+
1.1.2.1 : Cuenta Corriente (5)
|
79
|
+
1.1.2.2 : Caja de Ahorro (6)
|
80
|
+
1.2 : Cuentas x cobrar (7)
|
81
|
+
1.3 : Bienes de cambio (8)
|
82
|
+
1.4 : Bienes de uso (9)
|
83
|
+
1.4.1 : Rodados (10)
|
84
|
+
2 : Pasivo (11)
|
85
|
+
2.1 : Proveedores (12)
|
86
|
+
2.2 : Banco pasivo (13)
|
87
|
+
2.2.1 : Prestamo (14)
|
88
|
+
3 : Patrimonio Neto (15)
|
89
|
+
3.1 : Capital Social (16)
|
90
|
+
4 : Resultado Positivo (17)
|
91
|
+
4.1 : Ventas (18)
|
92
|
+
4.2 : Diferencia de Stock (19)
|
93
|
+
4.3 : Arqueo (20)
|
94
|
+
4.3.1 : Arqueo banco (21)
|
95
|
+
4.3.2 : Arqueo caja (22)
|
96
|
+
5 : Resultado Negativo (23)
|
97
|
+
5.1 : Costo mercaderia vendida (24)
|
98
|
+
5.2 : Diferencia de Stock negativo (25)
|
99
|
+
5.3 : Arqueo negativo (26)
|
100
|
+
5.3.1 : Arqueo negativo banco (27)
|
101
|
+
5.3.2 : Arqueo negativo caja (28)
|
102
|
+
|
103
|
+
(NOTA: el número entre paréntesis es el id del objeto)
|
104
|
+
|
105
|
+
2) Un archivo de tipo 'initializer':
|
106
|
+
/config/initializers/snappler_contable.rb
|
107
|
+
|
108
|
+
# Agregar el array de operaciones validas
|
109
|
+
SnapplerContable.valid_operations = [:cobro, :pago, :deposito]
|
110
|
+
|
111
|
+
Operaciones válidas para ejecutar con la gema. Las operaciones válidas son aquellas necesarias para vincular un modelo normal de la aplicacion con una cuenta subclase de LedgerAccount.
|
112
|
+
|
113
|
+
# Moneda por defecto
|
114
|
+
SnapplerContable.default_currency = 'ARS'
|
115
|
+
Moneda usada por la gema por defecto. En particular setea 'ARS'. Para modificarla hay que crear la moneda que se desea y poner el códigod de la nueva moneda. Si se cambia se tiene que reiniciar la aplicación.
|
116
|
+
|
117
|
+
|
118
|
+
3) Modelos comunes de la aplicación, los cuales se pueden vincular con una o mas cuentas del plan de cuentas existente.
|
119
|
+
|
120
|
+
Un modelo (hijo de ActiveRecord) puede vincularse al plan de cuentas mediante la sentencia:
|
121
|
+
|
122
|
+
class Product < ActiveRecord::Base
|
123
|
+
...
|
124
|
+
|
125
|
+
act_as_snappler_contable( :accounts => [:bienes_de_cambio, :cuentas_x_cobrar],
|
126
|
+
:account_by_operation => {:pago => :bienes_de_cambio,
|
127
|
+
:cobro => :cuentas_x_cobrar})
|
128
|
+
...
|
129
|
+
end
|
130
|
+
|
131
|
+
En este caso la clase Product está vinculada con la cuenta :bienes_de_cambio y :cuentas_x_cobrar
|
132
|
+
Esto significa que las instancias de la clase Product crearán cuentas de la misma clase que :bienes_de_cambio y :cuentas_x_cobrar, y serán hijas de la cuenta respectiva.
|
133
|
+
|
134
|
+
El array :accounts contiene todas las cuentas con las que estará vinculada la clase Product.
|
135
|
+
El array :account_by_operation indica cual la cuenta padre con la que se vinculará, en función la operación que se pase por parámetro al momento de ejecutar un movimiento contable.
|
136
|
+
|
137
|
+
Esto significa que cuando se ejecute un movimiento contable con operación :pago que involucre a un objeto de tipo Product, por ejemplo "Harina", se agregará una nueva cuenta, hija de :bienes_de_pago, vinculada con el producto "Harina". El plan de cuentas quedará así:
|
138
|
+
|
139
|
+
=> ROOT
|
140
|
+
1 : Activo (1)
|
141
|
+
1.1 : Disponibilidades (2)
|
142
|
+
1.1.1 : Caja (3)
|
143
|
+
1.1.2 : Bancos (4)
|
144
|
+
1.1.2.1 : Cuenta Corriente (5)
|
145
|
+
1.1.2.2 : Caja de Ahorro (6)
|
146
|
+
1.2 : Cuentas x cobrar (7)
|
147
|
+
1.3 : Bienes de cambio (8)
|
148
|
+
1.3.1 : Bienes De Cambio Product:Harina (40)
|
149
|
+
...
|
150
|
+
|
151
|
+
Existe la posibilidad que haya modelos relacionados entre sí que tengan que vincularse con el plan de cuentas.
|
152
|
+
Un ejemplo podría ser la cuenta Bancos se va a relacionar con Objetos de tipo banco de la aplicación, y a su vez estos bancos tendran cajas de ahorro que, logicamente, tienen que estar integradas al plan de cuentas.
|
153
|
+
|
154
|
+
|
155
|
+
Plan de cuentas
|
156
|
+
=> ROOT
|
157
|
+
1 : Activo (1)
|
158
|
+
1.1 : Disponibilidades (2)
|
159
|
+
1.1.1 : Caja (3)
|
160
|
+
1.1.2 : Bancos (4)
|
161
|
+
|
162
|
+
Modelos del sistema:
|
163
|
+
Bank
|
164
|
+
BankAccount
|
165
|
+
|
166
|
+
|
167
|
+
La única relación permitida de 'belongs_to'.
|
168
|
+
|
169
|
+
En este caso los modelos quedarían así:
|
170
|
+
|
171
|
+
class Bank < ActiveRecord::Base
|
172
|
+
act_as_snappler_contable(:accounts => [:bancos],
|
173
|
+
:account_by_operation => {})
|
174
|
+
...
|
175
|
+
end
|
176
|
+
|
177
|
+
class BankAccount < Account
|
178
|
+
belongs_to :bank
|
179
|
+
act_as_snappler_contable(:accounts => [{:bancos => :bank}],
|
180
|
+
:account_by_operation => {:deposito => :bancos, :extraccion => :bancos, :transferencia => :bancos})
|
181
|
+
end
|
182
|
+
|
183
|
+
Como se ve, en la clase BankAccount, en el parametro :accounts se indica un hash:
|
184
|
+
|
185
|
+
{:bancos => :bank}
|
186
|
+
|
187
|
+
Esto significa que BanckAccount está en la rama de la cuenta contable :bancos a través del la relación "belongs_to :bank"
|
188
|
+
|
189
|
+
Entonces tendríamos una clase "inmediata" a las cuentas contables (en este caso Bank), que en su parametro :accounts indica su cuenta contable padre (:bancos), y luego clases que cuelgan de la "inmediata" (BankAccount) que en el parametro :accounts tienen que indicar cual es la cuenta contable superior, y a través de qué relación la alcanza (:bank, ya que tiene declarado un "belongs_to :bank").
|
190
|
+
|
191
|
+
Las clases hacia "abajo" no tienen límite, siempre y cuando indiquen cual es la cuenta contable superior.
|
192
|
+
El ejemplo ya no tiene significado real, pero supongamos que la cuenta puede tener una sub-cuenta, en este caso la clase se vería así:
|
193
|
+
|
194
|
+
class SubBankAccount < Account
|
195
|
+
belongs_to :bank_account
|
196
|
+
act_as_snappler_contable(:accounts => [{:bancos => :bank_account}],
|
197
|
+
:account_by_operation => {:deposito => :bancos, :extraccion => :bancos, :transferencia => :bancos})
|
198
|
+
end
|
199
|
+
|
200
|
+
De esta forma, una vez ejecutada una operación contable que involucre estos objetos, el plan de cuentas se vería así:
|
201
|
+
|
202
|
+
=> ROOT
|
203
|
+
1 : Activo (1)
|
204
|
+
1.1 : Disponibilidades (2)
|
205
|
+
1.1.1 : Caja (3)
|
206
|
+
1.1.2 : Bancos (4)
|
207
|
+
1.1.2.1 : Cuenta Corriente (5)
|
208
|
+
1.1.2.2 : Caja de Ahorro (6)
|
209
|
+
1.1.2.3 : Bancos Bank:Patagonia (41)
|
210
|
+
1.1.2.3.1 : Bancos Bank:Patagonia BankAccount:Cc Banco Patagonia (42)
|
211
|
+
1.1.2.3.1.1 : Bancos Bank:Patagonia BankAccount:Cc Banco Patagonia SubBankAccount:Sub Cc Banco Patagonia (45)
|
212
|
+
|
213
|
+
|
214
|
+
== Funciones del módulo SnapplerContable
|
215
|
+
|
216
|
+
Para operar con la gema, algunas de las operaciones se ejecutan directamente como métodos de clase de SnapplerContable.
|
217
|
+
|
218
|
+
- SnapplerContable.accounts_tree
|
219
|
+
Devuelve el plan de cuentas como un árbol.
|
220
|
+
Se imprime indentando y con el código de plan de cuentas.
|
221
|
+
El arbol implementa "each", de esa forma se puede tratar con las operaciones de coleccion conocidas.
|
222
|
+
|
223
|
+
SnapplerContable.accounts_tree.each {|a| puts a.code}
|
224
|
+
|
225
|
+
|
226
|
+
- SnapplerContable.re_code_tree
|
227
|
+
Si se llega a cambiar el código de alguna de la cuentas de la raiz, o se cambia el valor el campo 'order' se debe ejecutar el método
|
228
|
+
|
229
|
+
SnapplerContable.re_code_tree
|
230
|
+
|
231
|
+
De esta forma todos los códigos se reacomodarán.
|
232
|
+
|
233
|
+
== Funciones del modelo de cuentas contables (subclases de LedgerAccount)
|
234
|
+
|
235
|
+
- cuenta.balance
|
236
|
+
Devuelve el saldo para la cuenta.
|
237
|
+
Usa el campo 'balance_sum' que se actualiza en cada LedgerAccount a medida que se agregan movimientos LedgerMoves.
|
238
|
+
Cada cuenta tiene su saldo actualizado.
|
239
|
+
Para devolverlo se consulta por los saldos de todas las cuentas hijas.
|
240
|
+
|
241
|
+
- cuenta.balance_to(to_date)
|
242
|
+
Da el saldo calculando con los movimientos hasta la fecha 'to_date'
|
243
|
+
|
244
|
+
- cuenta.balance_from(from_date)
|
245
|
+
Da el saldo calculando con los movimientos desde la fecha 'from_date'
|
246
|
+
|
247
|
+
- cuenta.balance_from(from_date)
|
248
|
+
Da el saldo calculando con los movimientos desde la fecha 'from_date' hasta la fecha 'to_date'
|
249
|
+
|
250
|
+
Las funciones de saldo con fecha usan la tabla LedgerMoves de esta forma:
|
251
|
+
Hace el cálculo del saldo de la cuenta, teniendo en cuenta los movimientos vinculados con dicha cuenta y con todas las cuentas de su sub árbol.
|
252
|
+
El cálculo del saldo va a depender de la clase de la cuenta:
|
253
|
+
|
254
|
+
LedgerAccountActivo : debe - haber
|
255
|
+
LedgerAccountPasivo : haber - debe
|
256
|
+
LedgerAccountPatrimonioNeto : haber - debe
|
257
|
+
LedgerAccountResultadoPositivo : haber - debe
|
258
|
+
LedgerAccountResultadoNegativo : debe - haber
|
259
|
+
|
260
|
+
las operacioes cuenta.balance y cuenta.balance_to(fecha del ultimo movimiento registrado) tienen que dar lo mismo.
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
- cuenta.accounts_tree
|
265
|
+
Devuelve el sub árbol de cuentas que baja desde la cuenta sobre la que se ejecuta el comando
|
266
|
+
|
267
|
+
== Funciones agregadas por act_as_snappler_contable
|
268
|
+
|
269
|
+
- objeto_act_as_snp_contable.ledger_accounts
|
270
|
+
Devuelve un array con las cuentas contables (las crea si es necesario) vinculadas con el objeto.
|
271
|
+
|
272
|
+
|
273
|
+
= Operación contable
|
274
|
+
|
275
|
+
- SnapplerContable.op
|
276
|
+
Es la operación que registra los movimientos para la cuentas.
|
277
|
+
|
278
|
+
El formato es:
|
279
|
+
|
280
|
+
SnapplerContable.op(Colección movimientos debe, Colección movimientos haber, operación debe, operación haber )
|
281
|
+
|
282
|
+
Las colecciones de movimientos debe/haber tiene un formato análogo.
|
283
|
+
|
284
|
+
Colección movimientos debe/haber:
|
285
|
+
[{account: LedgerAccount u objeto de clase act_as_snappler_contable,
|
286
|
+
value: valor,
|
287
|
+
order: orden del movimiento (opcional) (solo funciona si TODOS los movimientos tienen order),
|
288
|
+
currency: id (integer) u objeto LedgerCurrency (opcional, ARS por defecto),
|
289
|
+
currency_ratio: cotización de la moneda (opcional, 1 por defecto),
|
290
|
+
operation: operacion para extraer cuenta contable, en caso de que account: sea objeto de clase act_as_snappler_contable (opcional) }]
|
291
|
+
|
292
|
+
La suma de los values de "Colección movimientos debe" y "Colección movimientos haber" deben ser iguales.
|
293
|
+
|
294
|
+
En caso de que en el parámetro 'account:' de alguno de los movimientos sea un objeto act_as_snappler_contable, se debe especificar la operación que extrae la cuenta contable correspondiente.
|
295
|
+
Hay que tomarla del parametro ':account_by_operation' del act_as_snappler_contable.
|
296
|
+
|
297
|
+
Si el objeto está la "Colección movimientos debe" o "Colección movimientos haber", la operación se pasa como tercer parámetro.
|
298
|
+
En caso de que haya objetos en "Coleccion movimientos debe" y "Colección movimientos haber" que deban extraerse con operaciones distintas, se pasan dos parámetros más, siendo el primero usado para la colección del debe y el segudo para el haber.
|
299
|
+
|
300
|
+
Por último, respecto a las operaciones, si dentro de alguno las colecciones de movivientos hay objetos de los que se deben extraer cuentas con operaciones distintas, el hash de movimiento soporta el parámetro :operation.
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
|
314
|
+
|
315
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'SnapplerContable'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,151 @@
|
|
1
|
+
class LedgerAccount < ActiveRecord::Base
|
2
|
+
#--------------------------------------------- RELATIION
|
3
|
+
belongs_to :contable, polymorphic: true
|
4
|
+
has_many :child_ledger_accounts, :class_name => "LedgerAccount", :foreign_key => "master_ledger_account_id", :order => 'order_column'
|
5
|
+
belongs_to :master_ledger_account, :class_name => "LedgerAccount"
|
6
|
+
#--------------------------------------------- MISC
|
7
|
+
attr_accessible :name, :code, :code_name, :master_ledger_account_id, :master_ledger_account, :contable, :balance_sum
|
8
|
+
#--------------------------------------------- VALIDATION
|
9
|
+
validates :master_ledger_account_id, :presence => true
|
10
|
+
validates :code_name, :uniqueness => true
|
11
|
+
#--------------------------------------------- CALLBACK
|
12
|
+
before_save :set_code
|
13
|
+
after_create :set_order_column
|
14
|
+
#--------------------------------------------- SCOPES
|
15
|
+
default_scope order('order_column ASC')
|
16
|
+
#--------------------------------------------- METHODS
|
17
|
+
|
18
|
+
def self.account(value)
|
19
|
+
where(:code_name => value.to_s.snp_underscore).first
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_child(name)
|
23
|
+
if self.persisted?
|
24
|
+
self.class.create(name: name, master_ledger_account: self )
|
25
|
+
else
|
26
|
+
if self.errors.count > 0
|
27
|
+
errores = " La cuenta '#{name}' no se pudo persistir porque sus campos no cumplen la validacion de LedgerAccount."
|
28
|
+
end
|
29
|
+
raise "La instancia debe estar persistida para poder agregar una cuenta hija." + errores.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_code
|
34
|
+
unless self.master_ledger_account_id == 0
|
35
|
+
unless self.order_column.nil?
|
36
|
+
self.code = "#{self.master_ledger_account.code}.#{self.order_column}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def re_code(parent_code)
|
42
|
+
self.code = "#{parent_code}#{parent_code.blank? ? '' : '.'}#{order_column}"
|
43
|
+
save
|
44
|
+
child_ledger_accounts.each do |child|
|
45
|
+
child.re_code(code)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def name=(value)
|
50
|
+
write_attribute :name, value
|
51
|
+
if (read_attribute(:code_name)).blank?
|
52
|
+
name_value = read_attribute(:name)
|
53
|
+
write_attribute :code_name, name_value.snp_underscore
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_order_column
|
58
|
+
#Solo agrega orden si la cuenta no es tope del arbol
|
59
|
+
unless self.master_ledger_account_id == 0
|
60
|
+
max = self.master_ledger_account.child_ledger_accounts.maximum(:order_column)
|
61
|
+
else
|
62
|
+
max = LedgerAccount.where(:master_ledger_account_id => 0).maximum(:order_column)
|
63
|
+
end
|
64
|
+
|
65
|
+
if max.nil?
|
66
|
+
self.order_column = 1
|
67
|
+
else
|
68
|
+
self.order_column = max + 1
|
69
|
+
end
|
70
|
+
|
71
|
+
self.save
|
72
|
+
end
|
73
|
+
|
74
|
+
def children_accounts_ids
|
75
|
+
SnapplerContable.account_sub_tree(self).collect{|account| account.id}
|
76
|
+
end
|
77
|
+
|
78
|
+
def saldo
|
79
|
+
#alias para compatibilidad
|
80
|
+
balance
|
81
|
+
end
|
82
|
+
|
83
|
+
def balance
|
84
|
+
bal = LedgerAccount.where(:id => children_accounts_ids).sum(:balance_sum)
|
85
|
+
LedgerMove.format_value(bal)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def balance_to(to_date)
|
90
|
+
dh_hash = LedgerMove.where(:ledger_account_id => children_accounts_ids).where('created_at <= ?', to_date.end_of_day).group(:dh).sum(:value)
|
91
|
+
debe = dh_hash["D"].to_i
|
92
|
+
haber = dh_hash["H"].to_i
|
93
|
+
LedgerMove.format_value(process_balance(debe, haber))
|
94
|
+
end
|
95
|
+
|
96
|
+
def balance_from(from_date)
|
97
|
+
dh_hash = LedgerMove.where(:ledger_account_id => children_accounts_ids).where('created_at >= ?', from_date.beginning_of_day).group(:dh).sum(:value)
|
98
|
+
debe = dh_hash["D"].to_i
|
99
|
+
haber = dh_hash["H"].to_i
|
100
|
+
LedgerMove.format_value(process_balance(debe, haber))
|
101
|
+
end
|
102
|
+
|
103
|
+
def balance_from_to(from_date, to_date)
|
104
|
+
dh_hash = LedgerMove.where(:ledger_account_id => children_accounts_ids).where('created_at >= ? AND created_at <= ?', from_date.beginning_of_day, to_date.end_of_day).group(:dh).sum(:value)
|
105
|
+
debe = dh_hash["D"].to_i
|
106
|
+
haber = dh_hash["H"].to_i
|
107
|
+
LedgerMove.format_value(process_balance(debe, haber))
|
108
|
+
end
|
109
|
+
|
110
|
+
def process_balance
|
111
|
+
raise "Este metodo solo se tiene que implementar en las subclases"
|
112
|
+
end
|
113
|
+
|
114
|
+
def update_balance(value, dh)
|
115
|
+
case dh.upcase
|
116
|
+
when 'D'
|
117
|
+
update_balance = process_balance(value, 0)
|
118
|
+
when 'H'
|
119
|
+
update_balance = process_balance(0, value)
|
120
|
+
end
|
121
|
+
bal = self.balance_sum
|
122
|
+
self.balance_sum = bal + update_balance
|
123
|
+
save
|
124
|
+
end
|
125
|
+
|
126
|
+
def update_balance_destroy(value, dh)
|
127
|
+
#inverse operation
|
128
|
+
ops = {'D' => 'H', 'H' => 'D'}
|
129
|
+
update_balance(value, ops[dh])
|
130
|
+
end
|
131
|
+
|
132
|
+
def accounts_tree
|
133
|
+
SnapplerContable.account_sub_tree(self)
|
134
|
+
end
|
135
|
+
|
136
|
+
def balance_sum=(val)
|
137
|
+
if val.is_a? Numeric
|
138
|
+
write_attribute :balance_sum, LedgerMove.unformat_value(val)
|
139
|
+
else
|
140
|
+
raise "El valor debe ser un numero"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def balance_sum
|
145
|
+
value_formated = read_attribute :balance_sum
|
146
|
+
LedgerMove.format_value(value_formated)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class LedgerMove < ActiveRecord::Base
|
2
|
+
#--------------------------------------------- RELATION
|
3
|
+
belongs_to :ledger_entry
|
4
|
+
belongs_to :ledger_account
|
5
|
+
belongs_to :ledger_currency
|
6
|
+
#--------------------------------------------- MISC
|
7
|
+
attr_accessible :currency_ratio, :dh, :value, :ledger_account, :ledger_currency, :currency_ratio
|
8
|
+
DIVISOR = 100.0
|
9
|
+
#--------------------------------------------- VALIDATION
|
10
|
+
|
11
|
+
#--------------------------------------------- CALLBACK
|
12
|
+
after_create :update_balance_create
|
13
|
+
after_destroy :update_balance_destroy
|
14
|
+
after_update :update_balance_update
|
15
|
+
|
16
|
+
#--------------------------------------------- SCOPES
|
17
|
+
|
18
|
+
#--------------------------------------------- METHODS
|
19
|
+
|
20
|
+
def update_balance_create
|
21
|
+
self.ledger_account.update_balance(value, dh)
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_balance_destroy
|
25
|
+
self.ledger_account.update_balance_destroy(value, dh)
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_balance_update
|
29
|
+
self.ledger_account.update_balance_destroy( self.class.format_value(value_was), dh)
|
30
|
+
self.ledger_account.update_balance(value, dh)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.format_value(value)
|
35
|
+
value / DIVISOR
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.unformat_value(value)
|
39
|
+
(value * DIVISOR).to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
def value=(val)
|
43
|
+
if val.is_a? Numeric
|
44
|
+
write_attribute :value, self.class.unformat_value(val)
|
45
|
+
else
|
46
|
+
raise "El valor debe ser un numero"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def value
|
51
|
+
value_formated = read_attribute :value
|
52
|
+
self.class.format_value(value_formated)
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module SnapplerContable
|
4
|
+
class InitializerGenerator < ::Rails::Generators::Base
|
5
|
+
def create_initializer_file
|
6
|
+
create_file "config/initializers/snappler_contable.rb", "# Agregar el array de operaciones validas\nSnapplerContable.valid_operations = [:pago]\n\n# Moneda por defecto\nSnapplerContable.default_currency = 'ARS'"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module SnapplerContable
|
5
|
+
class MigrateGenerator < ::Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
desc "add snappler_contable migration"
|
10
|
+
def self.next_migration_number(path)
|
11
|
+
unless @prev_migration_nr
|
12
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
13
|
+
else
|
14
|
+
@prev_migration_nr += 1
|
15
|
+
end
|
16
|
+
@prev_migration_nr.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def copy_migrations
|
20
|
+
migration_template "snappler_contable_migrate.rb", "db/migrate/snappler_contable_migrate.rb"
|
21
|
+
migration_template "snappler_contable_app_ledger_accounts.rb", "db/migrate/snappler_contable_app_ledger_accounts.rb"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|