snappler_contable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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