SnapplerContable

Esta gema agrega a una aplicacion la capacidad de manejar cuentas contables con el modelo teorico economico.

Instalacion

Agregar esta linea al Gemfile

gem "snappler_contable"

Ejecutar

$ bundle install

Después de instalar se deben correr estos comandos

$ rails g snappler_contable:initializer
$ rails g snappler_contable:migrate
$ rake db:migrate

Esto va a crear el achivo:

config/initializers/snappler_contable.rb

Donde se tienen que agregar todas las operaciones contables se van a ejecutar en el sistema.

Tambien va a crear dos migraciones:

aaaammdd_snappler_contable_migrate.rb

Que crea la tabla de cuentas, de movimientos, de asientos y de monedas. Se crean 5 registros en la tabla LedgerAccounts que son necesarios para el sistema:

LedgerAccountActivo : Activo
LedgerAccountPasivo : Pasivo
LedgerAccountPatrimonioNeto : Patrimonio Neto
LedgerAccountResultadoPositivo : Resultado Positivo
LedgerAccountResultadoNegativo : Resultado Negativo

Tambien crea la moneda por defecto:

LedgerCurrency.create(name: 'Peso', code: 'ARS')

Luego crea otra migración llamada:

aaaammdd_snappler_contable_app_ledger_accounts.rb

En la que el programador debe agregar las cuentas necesarias para el plan de cuentas de la aplicacion. Ya están cargadas en variables de instancia las 5 cuentas originales. Luego se usa el metodo ‘add_child’ para agregar cuentas hijas.

activo = LedgerAccountActivo.first #en ese momento solo existe una
sub_cuenta_activo = activo.add_child('Sub cuenta activo')

Esta función se puede usar en cualquier parte de la applicación. La cuenta hija será de la misma clase que la clase padre.

Uso

La gema va a trabajar con: 1) Una estructura de tipo árbol de objetos. Cada objeto es una instancia de una de las 5 sub clases de LedgerAccount. El árbol tiene una raiz abstracta y 5 nodos:

LedgerAccountActivo : Activo
LedgerAccountPasivo : Pasivo
LedgerAccountPatrimonioNeto : Patrimonio Neto
LedgerAccountResultadoPositivo : Resultado Positivo
LedgerAccountResultadoNegativo : Resultado Negativo

Luego se agregaran las cuentas que completen el plan de cuentas específico para la aplicación. Una vez creadas las cuentas del plan, quedaría (por ejemplo) así:

=> ROOT
    1 : Activo (1)
        1.1 : Disponibilidades (2)
            1.1.1 : Caja (3)
            1.1.2 : Bancos (4)
                1.1.2.1 : Cuenta Corriente (5)
                1.1.2.2 : Caja de Ahorro (6)
        1.2 : Cuentas x cobrar (7)
        1.3 : Bienes de cambio (8)
        1.4 : Bienes de uso (9)
            1.4.1 : Rodados (10)
    2 : Pasivo (11)
        2.1 : Proveedores (12)
        2.2 : Banco pasivo (13)
            2.2.1 : Prestamo (14)
    3 : Patrimonio Neto (15)
        3.1 : Capital Social (16)
    4 : Resultado Positivo (17)
        4.1 : Ventas (18)
        4.2 : Diferencia de Stock (19)
        4.3 : Arqueo (20)
            4.3.1 : Arqueo banco (21)
            4.3.2 : Arqueo caja (22)
    5 : Resultado Negativo (23)
        5.1 : Costo mercaderia vendida (24)
        5.2 : Diferencia de Stock negativo (25)
        5.3 : Arqueo negativo (26)
            5.3.1 : Arqueo negativo banco (27)
            5.3.2 : Arqueo negativo caja (28)

(NOTA: el número entre paréntesis es el id del objeto)

2) Un archivo de tipo ‘initializer’: /config/initializers/snappler_contable.rb # Agregar el array de operaciones validas SnapplerContable.valid_operations = [:cobro, :pago, :deposito]

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.

# Moneda por defecto SnapplerContable.default_currency = ‘ARS’ 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.

3) Modelos comunes de la aplicación, los cuales se pueden vincular con una o mas cuentas del plan de cuentas existente.

Un modelo (hijo de ActiveRecord) puede vincularse al plan de cuentas mediante la sentencia: class Product < ActiveRecord::Base

	  ...

act_as_snappler_contable( :accounts => [:bienes_de_cambio, :cuentas_x_cobrar], :account_by_operation => => :bienes_de_cambio, :cobro => :cuentas_x_cobrar) … end

En este caso la clase Product está vinculada con la cuenta :bienes_de_cambio y :cuentas_x_cobrar 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.

El array :accounts contiene todas las cuentas con las que estará vinculada la clase Product. 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.

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í:

=> ROOT
    1 : Activo (1)
        1.1 : Disponibilidades (2)
            1.1.1 : Caja (3)
            1.1.2 : Bancos (4)
                1.1.2.1 : Cuenta Corriente (5)
                1.1.2.2 : Caja de Ahorro (6)
        1.2 : Cuentas x cobrar (7)
        1.3 : Bienes de cambio (8)
            1.3.1 : Bienes De Cambio Product:Harina (40)
    ...

Existe la posibilidad que haya modelos relacionados entre sí que tengan que vincularse con el plan de cuentas. 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.

Plan de cuentas

=> ROOT
    1 : Activo (1)
        1.1 : Disponibilidades (2)
            1.1.1 : Caja (3)
            1.1.2 : Bancos (4)

Modelos del sistema:

Bank
  BankAccount

La única relación permitida de ‘belongs_to’.

En este caso los modelos quedarían así: class Bank < ActiveRecord::Base act_as_snappler_contable(:accounts => [:bancos], :account_by_operation => {}) … end

class BankAccount < Account belongs_to :bank

act_as_snappler_contable(:accounts => [=> :bank],

:account_by_operation => {:deposito => :bancos, :extraccion => :bancos, :transferencia => :bancos})

end

Como se ve, en la clase BankAccount, en el parametro :accounts se indica un hash: => :bank

Esto significa que BanckAccount está en la rama de la cuenta contable :bancos a través del la relación “belongs_to :bank”

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”).

Las clases hacia “abajo” no tienen límite, siempre y cuando indiquen cual es la cuenta contable superior. 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í: class SubBankAccount < Account belongs_to :bank_account act_as_snappler_contable(:accounts => [=> :bank_account],

:account_by_operation => {:deposito => :bancos, :extraccion => :bancos, :transferencia => :bancos})

end

De esta forma, una vez ejecutada una operación contable que involucre estos objetos, el plan de cuentas se vería así:

=> ROOT
    1 : Activo (1)
        1.1 : Disponibilidades (2)
            1.1.1 : Caja (3)
            1.1.2 : Bancos (4)
                1.1.2.1 : Cuenta Corriente (5)
                1.1.2.2 : Caja de Ahorro (6)
                1.1.2.3 : Bancos Bank:Patagonia (41)
                    1.1.2.3.1 : Bancos Bank:Patagonia BankAccount:Cc Banco Patagonia (42)
                        1.1.2.3.1.1 : Bancos Bank:Patagonia BankAccount:Cc Banco Patagonia SubBankAccount:Sub Cc Banco Patagonia (45)

Funciones del módulo SnapplerContable

Para operar con la gema, algunas de las operaciones se ejecutan directamente como métodos de clase de SnapplerContable.

  • SnapplerContable.accounts_tree

Devuelve el plan de cuentas como un árbol. Se imprime indentando y con el código de plan de cuentas. El arbol implementa “each”, de esa forma se puede tratar con las operaciones de coleccion conocidas.

SnapplerContable.accounts_tree.each {|a| puts a.code}

  • SnapplerContable.re_code_tree

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

SnapplerContable.re_code_tree

De esta forma todos los códigos se reacomodarán.

Funciones del modelo de cuentas contables (subclases de LedgerAccount)

  • cuenta.balance

Devuelve el saldo para la cuenta. Usa el campo ‘balance_sum’ que se actualiza en cada LedgerAccount a medida que se agregan movimientos LedgerMoves. Cada cuenta tiene su saldo actualizado. Para devolverlo se consulta por los saldos de todas las cuentas hijas.

  • cuenta.balance_to(to_date)

Da el saldo calculando con los movimientos hasta la fecha ‘to_date’

  • cuenta.balance_from(from_date)

Da el saldo calculando con los movimientos desde la fecha ‘from_date’

  • cuenta.balance_from(from_date)

Da el saldo calculando con los movimientos desde la fecha ‘from_date’ hasta la fecha ‘to_date’

Las funciones de saldo con fecha usan la tabla LedgerMoves de esta forma: 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. El cálculo del saldo va a depender de la clase de la cuenta:

LedgerAccountActivo : debe - haber
LedgerAccountPasivo : haber - debe
LedgerAccountPatrimonioNeto : haber - debe
LedgerAccountResultadoPositivo : haber - debe
LedgerAccountResultadoNegativo : debe - haber

las operacioes cuenta.balance y cuenta.balance_to(fecha del ultimo movimiento registrado) tienen que dar lo mismo.

  • cuenta.accounts_tree

Devuelve el sub árbol de cuentas que baja desde la cuenta sobre la que se ejecuta el comando

Funciones agregadas por act_as_snappler_contable

  • objeto_act_as_snp_contable.ledger_accounts

Devuelve un array con las cuentas contables (las crea si es necesario) vinculadas con el objeto.

  • objeto_act_as_snp_contable.get_ledger_account_by_code_name(:symbol)

Devuelve la cuenta contable asocidada (las crea si es necesario) vinculadas con el objeto.

Operación contable

  • SnapplerContable.op

Es la operación que registra los movimientos para la cuentas.

El formato es: SnapplerContable.op(Colección movimientos debe, Colección movimientos haber, operación debe, operación haber )

Las colecciones de movimientos debe/haber tiene un formato análogo.

Colección movimientos debe/haber: [{account: LedgerAccount u objeto de clase act_as_snappler_contable, value: valor, order: orden del movimiento (opcional) (solo funciona si TODOS los movimientos tienen order), currency: id (integer) u objeto LedgerCurrency (opcional, ARS por defecto), currency_ratio: cotización de la moneda (opcional, 1 por defecto), operation: operacion para extraer cuenta contable, en caso de que account: sea objeto de clase act_as_snappler_contable (opcional) }]

La suma de los values de “Colección movimientos debe” y “Colección movimientos haber” deben ser iguales.

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. Hay que tomarla del parametro ‘:account_by_operation’ del act_as_snappler_contable.

Si el objeto está la “Colección movimientos debe” o “Colección movimientos haber”, la operación se pasa como tercer parámetro. 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.

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.







————————————————————————————————————————- v1.1 FIXES

* El calculo ahora las operaciones se hacen en enteros Y DESPUES se transforman
* La funcion 'unformat_value(value)' de LedgerMove hace un round antes de tl .to_i, elimina el bug del flotante

FEATURES / CHANGES

* Currencies ahora tiene un campo para el simbolo 'sym', ($, u$s, etc)
* Agregado monedas dolar y euro
* Ahora la gema es multicurrency funcional:
    El método 'balance' ahora devuelve un hash {ID_CURRENCY => AMOUNT, ID_CURRENCY => AMOUNT}
* IMPORTANTE!!! El método 'SnapplerContable.op' en versiones viejas va a fallar, ya que en esta Version cambia como recive
los parámetros
    Ejemplo:
        Version Vieja: 
            SnapplerContable.op(array_debe, array_haber, operation_debe = nil, operation_haber = nil)

        Version Actual: 
            SnapplerContable.op(array_debe, array_haber, params_hash => {:operation_debe => nil, :operation_haber => nil, :date => nil})

    Agregado el campo date a la operacion para buscar entre esa fecha y no con el 'created_at' de antes