erp_txns_and_accts 4.0.0 → 4.2.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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v1/biz_txn_acct_roots_controller.rb +124 -0
  3. data/app/controllers/api/v1/biz_txn_acct_types_controller.rb +130 -0
  4. data/app/controllers/api/v1/biz_txn_events_controller.rb +53 -0
  5. data/app/controllers/api/v1/biz_txn_types_controller.rb +131 -0
  6. data/app/controllers/api/v1/financial_txns_controller.rb +53 -0
  7. data/app/models/biz_txn_acct_pty_rtype.rb +1 -0
  8. data/app/models/biz_txn_acct_root.rb +130 -6
  9. data/app/models/biz_txn_acct_type.rb +2 -0
  10. data/app/models/biz_txn_event.rb +229 -49
  11. data/app/models/biz_txn_party_role_type.rb +6 -0
  12. data/app/models/biz_txn_type.rb +23 -0
  13. data/app/models/extensions/party.rb +4 -2
  14. data/app/models/financial_txn.rb +108 -19
  15. data/config/routes.rb +13 -0
  16. data/db/data_migrations/20151216210147_add_default_gl_accounts.rb +33 -0
  17. data/db/migrate/20080805000030_base_txns_and_accts.rb +129 -127
  18. data/db/migrate/20151216202856_add_nested_set_to_biz_txn_acct_roots.rb +31 -0
  19. data/db/migrate/20151231185337_add_billable_to_finanical_txn.rb +13 -0
  20. data/db/migrate/20160310163051_add_created_by_updated_by_to_erp_txns_and_accts.rb +35 -0
  21. data/db/migrate/20160628145626_upgrade_biz_txn_events_entered_date_data_type.rb +21 -0
  22. data/lib/erp_txns_and_accts/extensions/active_record/acts_as_biz_txn_event.rb +29 -15
  23. data/lib/erp_txns_and_accts/version.rb +1 -1
  24. metadata +17 -10
  25. data/db/data_migrations/20101014142230_financial_txn_types.rb +0 -15
  26. data/db/migrate/20130408195119_add_biz_txn_acct_type_id_to_biz_txn_acct_root.rb +0 -5
  27. data/db/migrate/20140523095709_add_custom_fields_to_biz_txn_events.rb +0 -10
@@ -0,0 +1,53 @@
1
+ module Api
2
+ module V1
3
+ class FinancialTxnsController < BaseController
4
+
5
+ def index
6
+ sort = nil
7
+ dir = nil
8
+ limit = nil
9
+ start = nil
10
+
11
+ unless params[:sort].blank?
12
+ sort_hash = params[:sort].blank? ? {} : Hash.symbolize_keys(JSON.parse(params[:sort]).first)
13
+ sort = sort_hash[:property] || 'description'
14
+ dir = sort_hash[:direction] || 'ASC'
15
+ limit = params[:limit] || 25
16
+ start = params[:start] || 0
17
+ end
18
+
19
+ query_filter = params[:query_filter].blank? ? {} : JSON.parse(params[:query_filter]).symbolize_keys
20
+
21
+ # hook method to apply any scopes passed via parameters to this api
22
+ financial_txns = FinancialTxn.apply_filters(query_filter)
23
+
24
+ # scope by dba_organizations if there are no parties passed as filters
25
+ unless query_filter[:parties]
26
+ dba_organizations = [current_user.party.dba_organization]
27
+ dba_organizations = dba_organizations.concat(current_user.party.dba_organization.child_dba_organizations)
28
+ financial_txns = financial_txns.scope_by_dba_organization(dba_organizations)
29
+ end
30
+
31
+ if sort and dir
32
+ financial_txns = financial_txns.order("#{sort} #{dir}")
33
+ end
34
+
35
+ total_count = financial_txns.count
36
+
37
+ if start and limit
38
+ financial_txns = financial_txns.offset(start).limit(limit)
39
+ end
40
+
41
+ render :json => {success: true, total_count: total_count, financial_txns: financial_txns.collect(&:to_data_hash)}
42
+ end
43
+
44
+ def show
45
+ financial_txn = FinancialTxn.find(params[:id])
46
+
47
+ render :json => {financial_txn: financial_txn.to_data_hash}
48
+ end
49
+
50
+
51
+ end # BizTxnEvents
52
+ end # V1
53
+ end # Api
@@ -2,6 +2,7 @@ class BizTxnAcctPtyRtype < ActiveRecord::Base
2
2
  attr_protected :created_at, :updated_at
3
3
 
4
4
  acts_as_nested_set
5
+ include ErpTechSvcs::Utils::DefaultNestedSetMethods
5
6
  acts_as_erp_type
6
7
 
7
8
  has_many :biz_txn_acct_party_roles
@@ -1,14 +1,134 @@
1
+ # create_table :biz_txn_acct_roots do |t|
2
+ # t.string :description
3
+ # t.string :internal_identifier
4
+ # t.integer :status
5
+ # t.integer :biz_txn_acct_id
6
+ # t.string :biz_txn_acct_type
7
+ # t.string :external_identifier
8
+ # t.string :external_id_source
9
+ # t.string :type
10
+ #
11
+ # t.integer :parent_id
12
+ # t.integer :lft
13
+ # t.integer :rgt
14
+ #
15
+ # t.references :biz_txn_acct_type
16
+ # t.timestamps
17
+ # end
18
+ #
19
+ # add_index :biz_txn_acct_roots, [:biz_txn_acct_id, :biz_txn_acct_type], :name => "btai_2"
20
+ # add_index :biz_txn_acct_roots, :biz_txn_acct_type_id, :name => "btai_3"
21
+ # add_index :biz_txn_acct_roots, :parent_id
22
+ # add_index :biz_txn_acct_roots, :lft
23
+ # add_index :biz_txn_acct_roots, :rgt
24
+
1
25
  class BizTxnAcctRoot < ActiveRecord::Base
2
26
  attr_protected :created_at, :updated_at
3
27
 
28
+ acts_as_nested_set
29
+ include ErpTechSvcs::Utils::DefaultNestedSetMethods
30
+
31
+ has_tracked_status
32
+ tracks_created_by_updated_by
33
+
4
34
  belongs_to :biz_txn_acct, :polymorphic => true
5
- belongs_to :txn_account_type, :class_name => 'BizTxnAcctType', :foreign_key => 'biz_txn_acct_type_id'
6
- has_many :biz_txn_events, :dependent => :destroy
7
- has_many :biz_txn_acct_party_roles, :dependent => :destroy
35
+ belongs_to :biz_txn_acct_type
36
+ has_many :biz_txn_events, :dependent => :destroy
37
+ has_many :biz_txn_acct_party_roles, :dependent => :destroy
8
38
 
9
39
  alias :account :biz_txn_acct
10
40
  alias :txn_events :biz_txn_events
11
41
  alias :txns :biz_txn_events
42
+ alias :txn_account_type :biz_txn_acct_type
43
+
44
+ class << self
45
+ # Filter records
46
+ #
47
+ # @param filters [Hash] a hash of filters to be applied,
48
+ # @param statement [ActiveRecord::Relation] the query being built
49
+ # @return [ActiveRecord::Relation] the query being built
50
+ def apply_filters(filters, statement=nil)
51
+ unless statement
52
+ statement = self
53
+ end
54
+
55
+ # filter by parent
56
+ if filters[:parent]
57
+ if filters[:parent].is_integer?
58
+ statement = statement.where(biz_txn_acct_roots: {parent_id: filters[:parent]})
59
+ else
60
+ statement = statement.where(biz_txn_acct_roots: {parent_id: BizTxnAcctRoot.iid(filters[:parent])})
61
+ end
62
+ end
63
+
64
+ # filter by query which will filter on description
65
+ if filters[:query]
66
+ statement = statement.where('description like ?', "%#{filters[:query].strip}%")
67
+ end
68
+
69
+ # filter by BizTxnAcctType
70
+ unless filters[:biz_txn_acct_type_iids].blank?
71
+ statement = statement.joins(:biz_txn_acct_type).where(biz_txn_acct_type: {internal_identifier: filters[:biz_txn_acct_type_iids]})
72
+ end
73
+
74
+ # filter by Status
75
+ unless filters[:status].blank?
76
+ statement = statement.with_current_status(filters[:status].split(','))
77
+ end
78
+
79
+ unless filters[:parties].blank?
80
+ data = JSON.parse(filters[:parties])
81
+
82
+ statement = statement.scope_by_party(data['party_ids'].split(','), {role_types: data['role_types']})
83
+ end
84
+
85
+ statement
86
+ end
87
+
88
+ # scope by dba organization
89
+ #
90
+ # @param dba_organization [Party] dba organization to scope by
91
+ #
92
+ # @return [ActiveRecord::Relation]
93
+ def scope_by_dba_organization(dba_organization)
94
+ scope_by_party(dba_organization, {role_types: 'dba_org'})
95
+ end
96
+
97
+ alias scope_by_dba scope_by_dba_organization
98
+
99
+ # scope by party
100
+ #
101
+ # @param party [Integer | Party | Array] either a id of Party record, a Party record, an array of Party records
102
+ # or an array of Party ids
103
+ # @param options [Hash] options to apply to this scope
104
+ # @option options [String | Array] :role_types BizTxnAcctPtyRtype internal identifiers to include in the scope,
105
+ # comma separated or an Array
106
+ #
107
+ # @return [ActiveRecord::Relation]
108
+ def scope_by_party(party, options={})
109
+ statement = joins(:biz_txn_acct_party_roles)
110
+ .where(biz_txn_acct_party_roles: {party_id: party}).uniq
111
+
112
+ if options[:role_types]
113
+ role_types = options[:role_types]
114
+ unless role_types.is_a? Array
115
+ role_types = role_types.split(',')
116
+ end
117
+
118
+ statement = statement.joins(biz_txn_acct_party_roles: :biz_txn_acct_pty_rtype)
119
+ .where(biz_txn_acct_pty_rtypes: {internal_identifier: role_types})
120
+ end
121
+
122
+ statement
123
+ end
124
+
125
+ # Look up account by internal identifier
126
+ #
127
+ # @param internal_identifier [String] Internal Identifier to look up by
128
+ def iid(internal_identifier)
129
+ where('internal_identifier = ?', internal_identifier).first
130
+ end
131
+ end
12
132
 
13
133
  def to_label
14
134
  "#{description}"
@@ -32,10 +152,14 @@ class BizTxnAcctRoot < ActiveRecord::Base
32
152
  def find_parties_by_role(biz_txn_acct_pty_rtype)
33
153
  biz_txn_acct_pty_rtype = BizTxnAcctPtyRtype.iid(biz_txn_acct_pty_rtype) if biz_txn_acct_pty_rtype.is_a? String
34
154
  raise "BizTxnAcctPtyRtype #{biz_txn_acct_pty_rtype.to_s} does not exist" if biz_txn_acct_pty_rtype.nil?
35
-
155
+
36
156
  Party.joins('inner join biz_txn_acct_party_roles on biz_txn_acct_party_roles.party_id = parties.id')
37
- .where('biz_txn_acct_pty_rtype_id = ?', biz_txn_acct_pty_rtype.id)
38
- .where('biz_txn_acct_root_id = ?', self.id)
157
+ .where('biz_txn_acct_pty_rtype_id = ?', biz_txn_acct_pty_rtype.id)
158
+ .where('biz_txn_acct_root_id = ?', self.id)
159
+ end
160
+
161
+ def to_data_hash
162
+ to_hash(only: [:id, :description, :internal_identifier])
39
163
  end
40
164
 
41
165
  end
@@ -3,4 +3,6 @@ class BizTxnAcctType < ActiveRecord::Base
3
3
 
4
4
  acts_as_nested_set
5
5
  include ErpTechSvcs::Utils::DefaultNestedSetMethods
6
+
7
+ acts_as_erp_type
6
8
  end
@@ -1,65 +1,245 @@
1
+ #### Table Definition ###########################
2
+ # create_table :biz_txn_events do |t|
3
+ # t.column :description, :string
4
+ # t.column :biz_txn_acct_root_id, :integer
5
+ # t.column :biz_txn_type_id, :integer
6
+ # t.column :entered_date, :datetime
7
+ # t.column :post_date, :datetime
8
+ # t.column :biz_txn_record_id, :integer
9
+ # t.column :biz_txn_record_type, :string
10
+ # t.column :external_identifier, :string
11
+ # t.column :external_id_source, :string
12
+ # t.timestamps
13
+ # end
14
+ #
15
+ # add_index :biz_txn_events, :biz_txn_acct_root_id
16
+ # add_index :biz_txn_events, :biz_txn_type_id
17
+ # add_index :biz_txn_events, [:biz_txn_record_id, :biz_txn_record_type], :name => "btai_1"
18
+ #################################################
19
+
1
20
  class BizTxnEvent < ActiveRecord::Base
2
21
  attr_protected :created_at, :updated_at
3
22
 
23
+ has_tracked_status
24
+ tracks_created_by_updated_by
25
+
4
26
  belongs_to :biz_txn_acct_root
5
- belongs_to :biz_txn_record, :polymorphic => true
6
- has_many :biz_txn_party_roles, :dependent => :destroy
27
+ belongs_to :biz_txn_record, :polymorphic => true
28
+ has_many :biz_txn_party_roles, :dependent => :destroy
7
29
  has_many :biz_txn_event_descs, :dependent => :destroy
8
30
  has_many :base_txn_contexts, :dependent => :destroy
9
31
  has_many :biz_txn_agreement_roles
10
32
  has_many :agreements, :through => :biz_txn_agreement_roles
11
-
33
+
34
+ before_destroy :destroy_biz_txn_relationships
35
+
12
36
  #wrapper for...
13
37
  #belongs_to :biz_txn_type
14
38
  belongs_to_erp_type :biz_txn_type
15
- #syntactic sugar
16
- alias :txn_type :biz_txn_type
17
- alias :txn_type= :biz_txn_type=
18
- alias :txn :biz_txn_record
19
- alias :txn= :biz_txn_record=
20
- alias :account :biz_txn_acct_root
21
- alias :account= :biz_txn_acct_root=
22
- alias :descriptions :biz_txn_event_descs
23
-
24
- # serialize ExtJs attributes
25
- is_json :custom_fields
26
-
27
-
28
- #helps when looping through transactions comparing types
29
- def txn_type_iid
30
- biz_txn_type.internal_identifier if biz_txn_type
31
- end
32
-
33
- def account_root
34
- biz_txn_acct_root
35
- end
36
-
37
- def amount
38
- if biz_txn_record.respond_to? :amount
39
- biz_txn_record.amount
40
- else
41
- nil
42
- end
43
- end
44
-
45
- def amount_string
46
- if biz_txn_record.respond_to? :amount_string
47
- biz_txn_record.amount_string
48
- else
49
- "n/a"
50
- end
51
- end
52
-
53
- def create_dependent_txns
54
- #Template Method
55
- end
56
-
57
- def to_label
39
+
40
+ #syntactic sugar
41
+ alias :txn_type :biz_txn_type
42
+ alias :txn_type= :biz_txn_type=
43
+ alias :txn :biz_txn_record
44
+ alias :txn= :biz_txn_record=
45
+ alias :account :biz_txn_acct_root
46
+ alias :account= :biz_txn_acct_root=
47
+ alias :descriptions :biz_txn_event_descs
48
+
49
+ class << self
50
+ # Filter records
51
+ #
52
+ # @param filters [Hash] a hash of filters to be applied,
53
+ # @param statement [ActiveRecord::Relation] the query being built
54
+ # @return [ActiveRecord::Relation] the query being built
55
+ def apply_filters(filters, statement=nil)
56
+ unless statement
57
+ statement = self
58
+ end
59
+
60
+ biz_txn_event_tbl = BizTxnEvent.arel_table
61
+
62
+ # filter by query which will filter on description
63
+ if filters[:query]
64
+ statement = statement.where('description like ?', "%#{filters[:query].strip}%")
65
+ end
66
+
67
+ # filter by WorkEffortType
68
+ unless filters[:biz_txn_type_iids].blank?
69
+ statement = statement.where(biz_txn_type_id: BizTxnType.where(internal_identifier: filters[:biz_txn_type_iids]))
70
+ end
71
+
72
+ # filter by Status
73
+ unless filters[:status].blank?
74
+ statement = statement.with_current_status(filters[:status].split(','))
75
+ end
76
+
77
+ # filter by start_at
78
+ unless filters[:start_date].blank?
79
+ statement = statement.where(biz_txn_event_tbl[:entered_date].gteq(Time.parse(filters[:start_date])))
80
+ end
81
+
82
+ # filter by end_at
83
+ unless filters[:end_date].blank?
84
+ statement = statement.where(biz_txn_event_tbl[:entered_date].lteq(Time.parse(filters[:end_date])))
85
+ end
86
+
87
+ unless filters[:parties].blank?
88
+ data = JSON.parse(filters[:parties])
89
+
90
+ statement = statement.scope_by_party(data['party_ids'].split(','), {role_types: data['role_types']})
91
+ end
92
+
93
+ statement
94
+ end
95
+
96
+ #
97
+ # scoping helpers
98
+ #
99
+
100
+ # scope by dba organization
101
+ #
102
+ # @param dba_organization [Party] dba organization to scope by
103
+ #
104
+ # @return [ActiveRecord::Relation]
105
+ def scope_by_dba_organization(dba_organization)
106
+ scope_by_party(dba_organization, {role_types: 'dba_org'})
107
+ end
108
+
109
+ alias scope_by_dba scope_by_dba_organization
110
+
111
+ # scope by party
112
+ #
113
+ # @param party [Integer | Party | Array] either a id of Party record, a Party record, an array of Party records
114
+ # or an array of Party ids
115
+ # @param options [Hash] options to apply to this scope
116
+ # @option options [String | Array] :role_types BizTxnPartyRoleType internal identifiers to include in the scope,
117
+ # comma separated or an Array
118
+ #
119
+ # @return [ActiveRecord::Relation]
120
+ def scope_by_party(party, options={})
121
+ statement = joins("inner join biz_txn_party_roles on biz_txn_party_roles.biz_txn_event_id = biz_txn_events.id")
122
+ .where("biz_txn_party_roles.party_id" => party).uniq
123
+
124
+ if options[:role_types]
125
+ role_types = options[:role_types]
126
+ unless role_types.is_a? Array
127
+ role_types = role_types.split(',')
128
+ end
129
+
130
+ statement = statement.joins("inner join biz_txn_party_role_types
131
+ on biz_txn_party_role_types.id = biz_txn_party_roles.biz_txn_party_role_type_id")
132
+ .where(biz_txn_party_role_types: {internal_identifier: role_types})
133
+ end
134
+
135
+ statement
136
+ end
137
+ end
138
+
139
+ # Get the dba_organization related to this BizTxnEvent
140
+ #
141
+ # @return [Party] returns a Party if the dba organization was found
142
+ def dba_organization
143
+ dba_org_role_type = BizTxnPartyRoleType.find_or_create('dba_org', 'DBA Organization')
144
+
145
+ biz_txn_party_role = biz_txn_party_roles.where('biz_txn_party_roles.biz_txn_party_role_type_id' => dba_org_role_type).first
146
+
147
+ if biz_txn_party_role
148
+ biz_txn_party_role.party
149
+ end
150
+ end
151
+
152
+ alias dba_org dba_organization
153
+
154
+ def destroy_biz_txn_relationships
155
+ BizTxnRelationship.where("txn_event_id_from = ? or txn_event_id_to = ?", self.id, self.id).destroy_all
156
+ end
157
+
158
+ # helps when looping through transactions comparing types
159
+ #
160
+ def txn_type_iid
161
+ biz_txn_type.internal_identifier if biz_txn_type
162
+ end
163
+
164
+ # get biz_txn_acct_root
165
+ #
166
+ # @return [BizTxnAcctRoot]
167
+ def account_root
168
+ biz_txn_acct_root
169
+ end
170
+
171
+ # get the amount of this txn if it responds to amount
172
+ #
173
+ # @return [BigDecimal | nil]
174
+ def amount
175
+ if biz_txn_record.respond_to? :amount
176
+ biz_txn_record.amount
177
+ else
178
+ nil
179
+ end
180
+ end
181
+
182
+ # get the amount of this txn as a string if it responds to amount_string
183
+ #
184
+ # @return [String | nil]
185
+ def amount_string
186
+ if biz_txn_record.respond_to? :amount_string
187
+ biz_txn_record.amount_string
188
+ else
189
+ "n/a"
190
+ end
191
+ end
192
+
193
+ # gets the first party related to this BizTxnEvent with the given BizTxnPartyRoleType
194
+ #
195
+ # @param role_type [BizTxnPartyRoleType | String] BizTxnPartyRoleType or internal identifier of BizTxnPartyRoleType
196
+ # @return [Party | nil]
197
+ def find_party_by_role_type(role_type)
198
+ role_type = role_type.is_a?(String) ? BizTxnPartyRoleType.iid(role_type) : role_type
199
+
200
+ biz_txn_party_role = biz_txn_party_roles.where(:biz_txn_party_role_type_id => role_type.id).first
201
+
202
+ if biz_txn_party_role
203
+ biz_txn_party_role.party
204
+ end
205
+ end
206
+
207
+ # returns description of this BizTxnEvent
208
+ #
209
+ # @return [String]
210
+ def to_label
58
211
  "#{description}"
59
- end
212
+ end
60
213
 
61
- def to_s
214
+ # returns description of this BizTxnEvent
215
+ #
216
+ # @return [String]
217
+ def to_s
62
218
  "#{description}"
63
- end
219
+ end
220
+
221
+ # converts this record a hash data representation
222
+ #
223
+ # @return [Hash]
224
+ def to_data_hash
225
+ data = to_hash(only: [:id,
226
+ :description,
227
+ :entered_date,
228
+ :post_date,
229
+ :external_identifier,
230
+ :external_id_source,
231
+ :created_at,
232
+ :updated_at])
233
+
234
+ data[:status] = self.try(:current_status_application).try(:to_data_hash)
235
+
236
+ data
237
+ end
238
+
239
+ # template method to create dependent BizTxnEvents
240
+ #
241
+ def create_dependent_txns
242
+ #Template Method
243
+ end
64
244
 
65
245
  end