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.
Files changed (56) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +315 -0
  4. data/Rakefile +38 -0
  5. data/app/models/ledger_account.rb +151 -0
  6. data/app/models/ledger_account_activo.rb +6 -0
  7. data/app/models/ledger_account_pasivo.rb +6 -0
  8. data/app/models/ledger_account_patrimonio_neto.rb +6 -0
  9. data/app/models/ledger_account_resultado_negativo.rb +6 -0
  10. data/app/models/ledger_account_resultado_positivo.rb +6 -0
  11. data/app/models/ledger_currency.rb +3 -0
  12. data/app/models/ledger_entry.rb +3 -0
  13. data/app/models/ledger_move.rb +54 -0
  14. data/lib/generators/snappler_contable/initializer_generator.rb +9 -0
  15. data/lib/generators/snappler_contable/migrate_generator.rb +24 -0
  16. data/lib/generators/snappler_contable/templates/snappler_contable_app_ledger_accounts.rb +17 -0
  17. data/lib/generators/snappler_contable/templates/snappler_contable_migrate.rb +57 -0
  18. data/lib/snappler_contable/ext/string.rb +5 -0
  19. data/lib/snappler_contable/railtie.rb +4 -0
  20. data/lib/snappler_contable/snappler_contable.rb +131 -0
  21. data/lib/snappler_contable/snappler_contable_active_record_extension.rb +172 -0
  22. data/lib/snappler_contable/tree_node.rb +47 -0
  23. data/lib/snappler_contable/version.rb +3 -0
  24. data/lib/snappler_contable.rb +19 -0
  25. data/lib/tasks/snappler_contable_tasks.rake +4 -0
  26. data/test/dummy/README.rdoc +261 -0
  27. data/test/dummy/Rakefile +7 -0
  28. data/test/dummy/app/assets/javascripts/application.js +15 -0
  29. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  30. data/test/dummy/app/controllers/application_controller.rb +3 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  33. data/test/dummy/config/application.rb +59 -0
  34. data/test/dummy/config/boot.rb +10 -0
  35. data/test/dummy/config/database.yml +25 -0
  36. data/test/dummy/config/environment.rb +5 -0
  37. data/test/dummy/config/environments/development.rb +37 -0
  38. data/test/dummy/config/environments/production.rb +67 -0
  39. data/test/dummy/config/environments/test.rb +37 -0
  40. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/test/dummy/config/initializers/inflections.rb +15 -0
  42. data/test/dummy/config/initializers/mime_types.rb +5 -0
  43. data/test/dummy/config/initializers/secret_token.rb +7 -0
  44. data/test/dummy/config/initializers/session_store.rb +8 -0
  45. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  46. data/test/dummy/config/locales/en.yml +5 -0
  47. data/test/dummy/config/routes.rb +58 -0
  48. data/test/dummy/config.ru +4 -0
  49. data/test/dummy/public/404.html +26 -0
  50. data/test/dummy/public/422.html +26 -0
  51. data/test/dummy/public/500.html +25 -0
  52. data/test/dummy/public/favicon.ico +0 -0
  53. data/test/dummy/script/rails +6 -0
  54. data/test/snappler_contable_test.rb +7 -0
  55. data/test/test_helper.rb +15 -0
  56. metadata +127 -0
@@ -0,0 +1,17 @@
1
+ class SnapplerContableAppLedgerAccounts < ActiveRecord::Migration
2
+ def self.up
3
+ activo = LedgerAccountActivo.first
4
+ # sub_cuenta_activo_1 = activo.add_child("Sub Cuenta Activo 1")
5
+ # sub_cuenta_activo_2 = activo.add_child("Sub Cuenta Activo 2")
6
+ # sub_sub_cuenta_activo = sub_cuenta_activo_2.add_child("Sub Sub Cuenta Activo 1")
7
+
8
+ pasivo = LedgerAccountPasivo.first
9
+ patrimonio_neto = LedgerAccountPatrimonioNeto.first
10
+ resultado_positivo = LedgerAccountResultadoPositivo.first
11
+ resultado_negativo = LedgerAccountResultadoNegativo.first
12
+ end
13
+
14
+ def self.down
15
+ LedgerAccount.destroy_all("master_ledger_account_id <> 0")
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ class SnapplerContableMigrate < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :ledger_accounts do |t|
4
+ t.string :name
5
+ t.integer :balance_sum, :default => 0
6
+ t.string :code
7
+ t.string :code_name
8
+ t.integer :order_column
9
+ t.references :contable, :polymorphic => true
10
+ t.integer :master_ledger_account_id
11
+ t.string :type
12
+
13
+ t.timestamps
14
+ end
15
+ add_index :ledger_accounts, :contable_id
16
+
17
+ #Las primeras 5 deben existir
18
+ aa = LedgerAccountActivo.create(name: 'Activo', code: '1', master_ledger_account_id: '0')
19
+ ap = LedgerAccountPasivo.create(name: 'Pasivo', code: '2', master_ledger_account_id: '0')
20
+ apn = LedgerAccountPatrimonioNeto.create(name: 'Patrimonio Neto', code: '3', master_ledger_account_id: '0')
21
+ arp = LedgerAccountResultadoPositivo.create(name: 'Resultado Positivo', code: '4', master_ledger_account_id: '0')
22
+ arn = LedgerAccountResultadoNegativo.create(name: 'Resultado Negativo', code: '5', master_ledger_account_id: '0')
23
+
24
+ create_table :ledger_moves do |t|
25
+ t.references :ledger_entry
26
+ t.references :ledger_account
27
+ t.string :dh, :limit => 1
28
+ t.integer :value, :default => 0
29
+ t.references :ledger_currency
30
+ t.float :currency_ratio
31
+
32
+ t.timestamps
33
+ end
34
+ add_index :ledger_moves, :ledger_entry_id
35
+ add_index :ledger_moves, :ledger_account_id
36
+ add_index :ledger_moves, :ledger_currency_id
37
+
38
+ create_table :ledger_entries do |t|
39
+ t.timestamps
40
+ end
41
+
42
+ create_table :ledger_currencies do |t|
43
+ t.string :name
44
+ t.string :code
45
+
46
+ t.timestamps
47
+ end
48
+ LedgerCurrency.create(name: 'Peso', code: 'ARS')
49
+ end
50
+
51
+ def self.down
52
+ drop_table :ledger_accounts
53
+ drop_table :ledger_moves
54
+ drop_table :ledger_entries
55
+ drop_table :ledger_currencies
56
+ end
57
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def snp_underscore
3
+ self.underscore.gsub(' ', '_')
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module SnapplerContable
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,131 @@
1
+
2
+ module SnapplerContable
3
+
4
+ def self.default_currency=(default_currency)
5
+ @my_default_currrency = default_currency
6
+ end
7
+
8
+ def self.default_currency
9
+ #@my_default_currrency
10
+ LedgerCurrency.find_by_code(@my_default_currrency)
11
+ end
12
+
13
+ def self.valid_operations=(operations)
14
+ @my_valid_operations = operations
15
+ end
16
+
17
+
18
+ def self.valid_operations
19
+ @my_valid_operations
20
+ end
21
+
22
+
23
+ def self.accounts_tree
24
+ tree = TreeNode.new(nil, true)
25
+ tree.add_child_ledger_accounts(LedgerAccount.where(:master_ledger_account_id => 0))
26
+ return tree
27
+ end
28
+
29
+ def self.account_sub_tree(ledger_account)
30
+ tree = TreeNode.new(nil, true)
31
+ tree.add_child_ledger_accounts([ledger_account])
32
+ return tree
33
+ end
34
+
35
+ def self.re_code_tree
36
+ LedgerAccount.where(:master_ledger_account_id => 0).each do |account|
37
+ account.re_code('')
38
+ end
39
+ end
40
+
41
+ def self.extract_accounts(moves_array, operation, debe_haber)
42
+
43
+ res_accounts = []
44
+ moves_array.each do |move|
45
+ move[:dh] = debe_haber
46
+ if move.key? :account
47
+ acc = move[:account]
48
+ if (acc.class.to_s == 'LedgerAccount') or (acc.class.superclass.to_s == 'LedgerAccount')
49
+ res_accounts << move
50
+ else
51
+ if move.key? :operation
52
+ oper = move[:operation]
53
+ else
54
+ oper = operation
55
+ end
56
+ if oper.nil?
57
+ raise "No se puede extraer la cuenta del objeto #{acc.class.to_s} con operation == nil"
58
+ else
59
+ unless acc.nil?
60
+ if acc.respond_to? "get_ledger_account_by_operation"
61
+ move[:account] = acc.get_ledger_account_by_operation(oper)
62
+ res_accounts << move
63
+ else
64
+ raise "La clase #{acc.class.to_s} no implementa el modulo contable."
65
+ end
66
+ else
67
+ raise "Se paso como cuenta un objeto Nil"
68
+ end
69
+ end
70
+ end
71
+ else
72
+ raise "El hash de movimiento no tiene :account - #{move}"
73
+ end
74
+ unless move.key? :value
75
+ raise "El hash de movimiento no tiene :value - #{move}"
76
+ end
77
+ end
78
+ return res_accounts
79
+ end
80
+
81
+ def self.op(array_debe, array_haber, operation_debe = nil, operation_haber = nil)
82
+
83
+ if operation_haber.nil?
84
+ operation_haber = operation_debe
85
+ end
86
+
87
+ #TODO Verificar si viene el mismo objeto en el debe y el haber y pedir DOS operaciones
88
+ debe_accounts = extract_accounts(array_debe, operation_debe, 'D')
89
+ haber_accounts = extract_accounts(array_haber, operation_haber, 'H')
90
+
91
+ total_debe = debe_accounts.inject(0){|init, move| init + move[:value] }
92
+ total_haber = haber_accounts.inject(0){|init, move| init + move[:value] }
93
+
94
+ if total_haber != total_debe
95
+ raise "Las sumas del DEBE y HABER son diferentes - debe: #{total_debe} haber: #{total_haber}"
96
+ end
97
+
98
+ all_moves = debe_accounts + haber_accounts
99
+
100
+ #verificando si todos los movimientos tienen orden
101
+ if all_moves.inject(true){|res, move| res & (move.key? :order)}
102
+ all_moves.sort!{|a, b| a[:order] <=> b[:order]}
103
+ end
104
+
105
+ dc = SnapplerContable.default_currency
106
+
107
+ le = LedgerEntry.create
108
+ all_moves.each do |m|
109
+ if m.key? :currency
110
+ if m[:currency].is_a? Numeric
111
+ m[:currency] = LedgerCurrency.find(m[:currency])
112
+ end
113
+ unless m.key? :currency_ratio
114
+ m[:currency_ratio] = 1
115
+ end
116
+ else
117
+ m[:currency] = dc
118
+ m[:currency_ratio] = 1
119
+ end
120
+ le.ledger_moves.build(ledger_account: m[:account], value: m[:value], dh: m[:dh], ledger_currency: m[:currency], currency_ratio: m[:currency_ratio])
121
+ end
122
+
123
+ if le.save
124
+ le
125
+ else
126
+ le.destroy
127
+ raise "Fallo la creacion del movimiento: #{all_moves}"
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,172 @@
1
+ module SnapplerContable
2
+ module SnapplerContableActiveRecordExtension
3
+
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ # add your static(class) methods here
10
+ module ClassMethods
11
+ #act_as_snappler_contable(:accounts => [:acc_1, :acc_2],
12
+ # :account_by_operation => {:oper_1 => :acc_1, :oper_2 => :acc_2})
13
+ #
14
+ def act_as_snappler_contable(config_hash = nil)
15
+ if config_hash.nil? or config_hash.class.to_s != "Hash"
16
+ raise "\nError en la declaracion de act_as_snappler_contable en la clase #{name}\nUso de act_as_snappler_contable:\n #act_as_snappler_contable(:accounts => [:acc_1, :acc_2],\n # :account_by_operation => {:oper_1 => :acc_1,\n # :oper_2 => :acc_2})\n"
17
+ end
18
+
19
+ if config_hash.key? :accounts
20
+
21
+ ledger_account_aux = config_hash[:accounts]
22
+ @my_ledger_accounts = {}
23
+ ledger_account_aux.each do |account|
24
+ #si es hash, esta relacionado con otro objeto
25
+ if account.is_a? Hash
26
+ account.each_pair do |key, value|
27
+ @my_ledger_accounts[key] = value unless @my_ledger_accounts.key? key
28
+ end
29
+ else
30
+ @my_ledger_accounts[account] = nil unless @my_ledger_accounts.key? account
31
+ end
32
+ end
33
+
34
+ @my_ledger_accounts.each_key do |code_name|
35
+
36
+ if LedgerAccount.find_by_code_name(code_name.to_s.snp_underscore).nil?
37
+ raise "La cuenta '#{code_name}' (code_name: '#{code_name.to_s.snp_underscore}') no existe como cuenta contable LedgerAccount"
38
+ end
39
+
40
+ end
41
+ else
42
+ raise "La clase '#{self.class}' no declara cuentas en 'act_as_snappler_contable{:accounts => []}'"
43
+ end
44
+
45
+ if config_hash.key? :account_by_operation
46
+ @my_op_account_hash = config_hash[:account_by_operation]
47
+ #chequea que todas las operaciones existan
48
+ valid_ops = SnapplerContable.valid_operations
49
+ @my_op_account_hash.each_pair do |oper, acc|
50
+ unless valid_ops.include? oper
51
+ raise "La clase #{self.name} declara la operacion ':#{oper}', que no existe como operacion valida en 'config/initializers/snappler_contable.rb'"
52
+ end
53
+ unless @my_ledger_accounts.include? acc
54
+ raise "La clase #{self.name} indica: ':#{oper} => :#{acc}', pero la cuenta '#{acc}' no esta incluida en 'act_as_snappler_contable{:accounts => []}'"
55
+ end
56
+ end
57
+ else
58
+ raise "La clase '#{self.class}' no declara cuenta por operacion en 'act_as_snappler_contable{:account_by_operation => []}'"
59
+ end
60
+
61
+ #Definicion de metodos
62
+
63
+ define_method(:get_parent_belongs_to) do |ledger_account_code_name|
64
+ parent_belongs_to = self.class.get_my_ledger_accounts[ledger_account_code_name]
65
+
66
+ unless parent_belongs_to.nil?
67
+ unless self.respond_to? parent_belongs_to
68
+ raise "No existe la relacion 'belongs_to :#{parent_belongs_to}' en la clase #{self.class}"
69
+ end
70
+
71
+ if eval("self.#{parent_belongs_to.to_s}").nil?
72
+ raise "El objeto de la relacion belongs_to :#{parent_belongs_to} es nil. Class #{self.class} belongs_to :#{parent_belongs_to} - id: #{self.id}"
73
+ end
74
+
75
+ parent_object = eval("self.#{parent_belongs_to.to_s}")
76
+
77
+ return parent_belongs_to, parent_object
78
+
79
+ else
80
+ return nil, nil
81
+ end
82
+ end
83
+
84
+ define_method(:get_name_and_code_name) do |ledger_account_code_name|
85
+
86
+ parent_belongs_to, parent_object = get_parent_belongs_to(ledger_account_code_name)
87
+ if parent_belongs_to.nil?
88
+
89
+ name_aux = ledger_account_code_name.to_s.titleize + " "
90
+ code_name_aux = name_aux
91
+ else
92
+
93
+ parent_object_account = parent_object.get_ledger_account_by_code_name(ledger_account_code_name)
94
+ parent_name_aux, parent_code_name_aux = parent_object.get_name_and_code_name(ledger_account_code_name)
95
+ name_aux = parent_name_aux + " "
96
+ code_name_aux = parent_code_name_aux + " "
97
+ end
98
+ name_aux += self.class.to_s
99
+ name_aux += ":"
100
+
101
+ #TODO configuracion del campo "name" para que pueda tomar otro campo para nombre
102
+ name_aux += (self.respond_to?(:name)) ? self.name.to_s.titleize : self.id.to_s
103
+ code_name_aux += "#{self.class.to_s} #{self.id.to_s}"
104
+ code_name_aux = code_name_aux.snp_underscore
105
+ return name_aux, code_name_aux
106
+ end
107
+
108
+
109
+ define_method(:get_ledger_account_by_operation) do |operation|
110
+ if SnapplerContable.valid_operations.include? operation
111
+ ledger_account_code_name = self.class.get_my_accounts_by_operation[operation]
112
+ if ledger_account_code_name.blank?
113
+ raise "La operacion ':#{operation.to_s}' no esta incluida como :account_by_operation en la sentencia 'act_as_snappler_contable' de la clase #{self.class.to_s.titleize}"
114
+ else
115
+ return get_ledger_account_by_code_name(ledger_account_code_name)
116
+ end
117
+ else
118
+ raise "La operacion ':#{operation.to_s}' no esta incluida como valid_operation en 'config/initializers/snappler_contable.rb'"
119
+ end
120
+ end
121
+
122
+ define_method(:get_ledger_account_by_code_name) do |ledger_account_code_name|
123
+ if self.class.get_my_ledger_accounts.include? ledger_account_code_name
124
+ if self.persisted?
125
+ name_aux, code_name_aux = get_name_and_code_name(ledger_account_code_name)
126
+ res_ledger_account = LedgerAccount.find_by_code_name(code_name_aux)
127
+ if res_ledger_account.nil?
128
+ #no existe la cuenta relacionada, se crea
129
+ #verifica que no este en relacion belongs_to
130
+ parent_belongs_to, parent_object = get_parent_belongs_to(ledger_account_code_name)
131
+ if parent_belongs_to.nil?
132
+ master_ledger_account = LedgerAccount.find_by_code_name(ledger_account_code_name.to_s)
133
+ else
134
+ master_ledger_account = parent_object.get_ledger_account_by_code_name(ledger_account_code_name)
135
+ end
136
+ if not master_ledger_account.nil?
137
+ #uso la clase del padre para crear la cuenta de objeto
138
+ res_ledger_account = master_ledger_account.class.create(name: name_aux, code_name: code_name_aux, master_ledger_account: master_ledger_account, contable: self )
139
+ return res_ledger_account
140
+ else
141
+ raise "No existe la cuenta padre #{ledger_account_code_name.to_s}"
142
+ end
143
+ else
144
+ #se devuelve la cuenta relacionada
145
+ return res_ledger_account
146
+ end
147
+ else
148
+ raise "El objeto de clase #{self.class} aun no esta persistido, no tiene cuenta #{ledger_account_code_name.to_s} asociada"
149
+ end
150
+ else
151
+ raise "La clase '#{self.class.to_s.titleize}' no esta vinculada a la cuenta #{ledger_account_code_name.to_s}"
152
+ end
153
+ end
154
+
155
+ define_method(:ledger_accounts) do
156
+ res = self.class.get_my_ledger_accounts.map{|a| a.first}
157
+ res.map{|acc_code_name| get_ledger_account_by_code_name(acc_code_name)}
158
+ end
159
+ end
160
+
161
+ def get_my_accounts_by_operation
162
+ @my_op_account_hash
163
+ end
164
+
165
+ def get_my_ledger_accounts
166
+ @my_ledger_accounts
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,47 @@
1
+ module SnapplerContable
2
+ class TreeNode
3
+
4
+ include Enumerable
5
+
6
+ attr_accessor :object, :childrens, :root
7
+
8
+ def initialize(account, root=false)
9
+ if root
10
+ @object = 'ROOT'
11
+ else
12
+ @object = account
13
+ end
14
+ @childrens = []
15
+ @root = root
16
+ end
17
+
18
+ def add_child_ledger_accounts(accounts)
19
+ accounts.each do |account|
20
+ node = TreeNode.new(account)
21
+ childrens << node
22
+ node.add_child_ledger_accounts(account.child_ledger_accounts)
23
+ end
24
+ end
25
+
26
+ def name
27
+ root ? 'ROOT' : "#{object.code} : #{object.name} (#{object.id})"
28
+ end
29
+
30
+ def to_s(indent=0)
31
+ res = (' ' * indent) + "#{name}\n"
32
+ res = res + @childrens.map{ |child| " " + child.to_s(indent + 4)}.join("\n")
33
+ res.gsub("\n\n", "\n")
34
+ end
35
+
36
+ def each(&block)
37
+ unless root
38
+ block.call object
39
+ end
40
+ childrens.each do |child|
41
+ child.each(&block)
42
+ end
43
+ self
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module SnapplerContable
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ require "snappler_contable/ext/string"
2
+ require "snappler_contable/snappler_contable_active_record_extension"
3
+ require "snappler_contable/snappler_contable"
4
+ require "snappler_contable/tree_node"
5
+
6
+ module SnapplerContable
7
+
8
+ # To setup run $ rails generate snappler_contable:install
9
+ def self.setup
10
+ yield self
11
+ end
12
+
13
+ class ActiveRecord::Base
14
+ include SnapplerContableActiveRecordExtension
15
+ end
16
+
17
+ end
18
+
19
+ require 'snappler_contable/railtie' if defined?(Rails)
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :snappler_contable do
3
+ # # Task goes here
4
+ # end