rails_finance 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +20 -0
- data/Rakefile +32 -0
- data/app/controllers/finance/admin/assessments_controller.rb +55 -0
- data/app/controllers/finance/admin/base_controller.rb +4 -0
- data/app/controllers/finance/admin/budgets_controller.rb +83 -0
- data/app/controllers/finance/admin/expense_members_controller.rb +59 -0
- data/app/controllers/finance/admin/expenses_controller.rb +71 -0
- data/app/controllers/finance/admin/financial_taxons_controller.rb +67 -0
- data/app/controllers/finance/admin/fund_incomes_controller.rb +59 -0
- data/app/controllers/finance/admin/funds_controller.rb +58 -0
- data/app/controllers/finance/admin/home_controller.rb +8 -0
- data/app/controllers/finance/admin/stocks_controller.rb +60 -0
- data/app/controllers/finance/me/base_controller.rb +4 -0
- data/app/controllers/finance/me/budgets_controller.rb +111 -0
- data/app/controllers/finance/me/expense_members_controller.rb +73 -0
- data/app/controllers/finance/me/expenses_controller.rb +129 -0
- data/app/controllers/finance_controller/me.rb +14 -0
- data/app/models/budget/finance/fund_budget.rb +5 -0
- data/app/models/budget/finance/stock_budget.rb +5 -0
- data/app/models/expense/finance/payable_expense.rb +5 -0
- data/app/models/expense/finance/prepay_expense.rb +5 -0
- data/app/models/finance/application_record.rb +5 -0
- data/app/models/finance/assessment.rb +5 -0
- data/app/models/finance/budget.rb +7 -0
- data/app/models/finance/expense.rb +7 -0
- data/app/models/finance/expense_item.rb +5 -0
- data/app/models/finance/expense_member.rb +6 -0
- data/app/models/finance/ext/financial.rb +24 -0
- data/app/models/finance/ext/member.rb +13 -0
- data/app/models/finance/financial_taxon.rb +7 -0
- data/app/models/finance/fund.rb +6 -0
- data/app/models/finance/fund_income.rb +5 -0
- data/app/models/finance/model/assessment.rb +26 -0
- data/app/models/finance/model/budget/fund_budget.rb +5 -0
- data/app/models/finance/model/budget/stock_budget.rb +10 -0
- data/app/models/finance/model/budget.rb +152 -0
- data/app/models/finance/model/expense/payable_expense.rb +5 -0
- data/app/models/finance/model/expense/prepay_expense.rb +5 -0
- data/app/models/finance/model/expense.rb +168 -0
- data/app/models/finance/model/expense_item.rb +36 -0
- data/app/models/finance/model/expense_member.rb +130 -0
- data/app/models/finance/model/financial_taxon.rb +27 -0
- data/app/models/finance/model/fund.rb +36 -0
- data/app/models/finance/model/fund_income.rb +30 -0
- data/app/models/finance/model/stock.rb +33 -0
- data/app/models/finance/stock.rb +5 -0
- data/app/models/finance.rb +12 -0
- data/app/pdfs/borrow_expense_pdf.rb +70 -0
- data/app/pdfs/payout_expense_pdf.rb +70 -0
- data/app/pdfs/prepay_expense_pdf.rb +70 -0
- data/app/records/borrow_expense_record.rb +10 -0
- data/app/records/prepay_expense_record.rb +16 -0
- data/app/views/admin/_finance_nav.html.erb +14 -0
- data/app/views/admin/_nav_expense.html.erb +4 -0
- data/app/views/finance/admin/assessments/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/assessments/_filter_form.html.erb +9 -0
- data/app/views/finance/admin/assessments/_form.html.erb +2 -0
- data/app/views/finance/admin/assessments/_index_tbody.html.erb +2 -0
- data/app/views/finance/admin/assessments/_index_thead.html.erb +3 -0
- data/app/views/finance/admin/assessments/_index_tr.html.erb +19 -0
- data/app/views/finance/admin/assessments/_new_form.html.erb +4 -0
- data/app/views/finance/admin/assessments/_show_table.html.erb +4 -0
- data/app/views/finance/admin/assessments/index.html.erb +5 -0
- data/app/views/finance/admin/base/_nav.html.erb +3 -0
- data/app/views/finance/admin/budgets/_breadcrumb.html.erb +9 -0
- data/app/views/finance/admin/budgets/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/budgets/_filter_form.html.erb +10 -0
- data/app/views/finance/admin/budgets/_filter_table.html.erb +11 -0
- data/app/views/finance/admin/budgets/_form.html.erb +7 -0
- data/app/views/finance/admin/budgets/_index_tbody.html.erb +13 -0
- data/app/views/finance/admin/budgets/_index_thead.html.erb +6 -0
- data/app/views/finance/admin/budgets/_item_form.html.erb +17 -0
- data/app/views/finance/admin/budgets/_items.html.erb +16 -0
- data/app/views/finance/admin/budgets/_new_form.html.erb +4 -0
- data/app/views/finance/admin/budgets/_show/_breadcrumb.html.erb +6 -0
- data/app/views/finance/admin/budgets/_show_table.html.erb +62 -0
- data/app/views/finance/admin/budgets/index.html.erb +5 -0
- data/app/views/finance/admin/budgets/next.turbo_stream.erb +1 -0
- data/app/views/finance/admin/budgets/show.htmlx.erb +35 -0
- data/app/views/finance/admin/budgets/trigger.js.erb +1 -0
- data/app/views/finance/admin/expense_members/_edit_form.html.erb +3 -0
- data/app/views/finance/admin/expense_members/_form.html.erb +5 -0
- data/app/views/finance/admin/expense_members/_index_tbody.html.erb +53 -0
- data/app/views/finance/admin/expense_members/_index_thead.html.erb +12 -0
- data/app/views/finance/admin/expense_members/index.html.erb +8 -0
- data/app/views/finance/admin/expenses/_breadcrumb.html.erb +9 -0
- data/app/views/finance/admin/expenses/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/expenses/_filter_form.html.erb +10 -0
- data/app/views/finance/admin/expenses/_filter_table.html.erb +11 -0
- data/app/views/finance/admin/expenses/_form.html.erb +12 -0
- data/app/views/finance/admin/expenses/_index_tbody.html.erb +13 -0
- data/app/views/finance/admin/expenses/_index_thead.html.erb +6 -0
- data/app/views/finance/admin/expenses/_item_form.html.erb +18 -0
- data/app/views/finance/admin/expenses/_items.html.erb +20 -0
- data/app/views/finance/admin/expenses/_member_form.html.erb +16 -0
- data/app/views/finance/admin/expenses/_new_form.html.erb +4 -0
- data/app/views/finance/admin/expenses/index.html.erb +5 -0
- data/app/views/finance/admin/expenses/next.turbo_stream.erb +1 -0
- data/app/views/finance/admin/expenses/show.html.erb +121 -0
- data/app/views/finance/admin/expenses/trigger.turbo_stream.erb +1 -0
- data/app/views/finance/admin/financial_taxons/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/financial_taxons/_filter_form.html.erb +10 -0
- data/app/views/finance/admin/financial_taxons/_form.html.erb +5 -0
- data/app/views/finance/admin/financial_taxons/_index_tbody.html.erb +36 -0
- data/app/views/finance/admin/financial_taxons/_index_thead.html.erb +5 -0
- data/app/views/finance/admin/financial_taxons/_index_tr.html.erb +13 -0
- data/app/views/finance/admin/financial_taxons/_new_form.html.erb +4 -0
- data/app/views/finance/admin/financial_taxons/index.html.erb +6 -0
- data/app/views/finance/admin/fund_incomes/_breadcrumb.html.erb +7 -0
- data/app/views/finance/admin/fund_incomes/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/fund_incomes/_filter_form.html.erb +9 -0
- data/app/views/finance/admin/fund_incomes/_form.html.erb +4 -0
- data/app/views/finance/admin/fund_incomes/_index_tbody.html.erb +5 -0
- data/app/views/finance/admin/fund_incomes/_index_thead.html.erb +4 -0
- data/app/views/finance/admin/fund_incomes/_new_form.html.erb +4 -0
- data/app/views/finance/admin/fund_incomes/_show_table.html.erb +12 -0
- data/app/views/finance/admin/fund_incomes/index.html.erb +5 -0
- data/app/views/finance/admin/funds/_edit_form.html.erb +3 -0
- data/app/views/finance/admin/funds/_filter_form.html.erb +9 -0
- data/app/views/finance/admin/funds/_form.html.erb +5 -0
- data/app/views/finance/admin/funds/_index_tbody.html.erb +14 -0
- data/app/views/finance/admin/funds/_index_thead.html.erb +8 -0
- data/app/views/finance/admin/funds/_new_form.html.erb +3 -0
- data/app/views/finance/admin/funds/_show_table.html.erb +16 -0
- data/app/views/finance/admin/funds/index.html.erb +5 -0
- data/app/views/finance/admin/home/index.html.erb +6 -0
- data/app/views/finance/admin/stocks/_breadcrumb.html.erb +7 -0
- data/app/views/finance/admin/stocks/_edit_form.html.erb +4 -0
- data/app/views/finance/admin/stocks/_filter_form.html.erb +9 -0
- data/app/views/finance/admin/stocks/_form.html.erb +4 -0
- data/app/views/finance/admin/stocks/_index_tbody.html.erb +6 -0
- data/app/views/finance/admin/stocks/_index_thead.html.erb +7 -0
- data/app/views/finance/admin/stocks/_new_form.html.erb +4 -0
- data/app/views/finance/admin/stocks/_show_table.html.erb +16 -0
- data/app/views/finance/admin/stocks/index.html.erb +5 -0
- data/app/views/finance/me/budgets/_breadcrumb.html.erb +6 -0
- data/app/views/finance/me/budgets/_filter_form.html.erb +8 -0
- data/app/views/finance/me/budgets/_filter_table.html.erb +11 -0
- data/app/views/finance/me/budgets/_index_tbody.html.erb +23 -0
- data/app/views/finance/me/budgets/_index_thead.html.erb +4 -0
- data/app/views/finance/me/budgets/_items.html.erb +22 -0
- data/app/views/finance/me/budgets/_show/_breadcrumb.html.erb +6 -0
- data/app/views/finance/me/budgets/admin.html.erb +5 -0
- data/app/views/finance/me/budgets/financial_taxons.js.erb +7 -0
- data/app/views/finance/me/budgets/index.html.erb +5 -0
- data/app/views/finance/me/budgets/index.js +45 -0
- data/app/views/finance/me/budgets/submit.turbo_stream.erb +1 -0
- data/app/views/finance/me/budgets/transfer.turbo_stream.erb +1 -0
- data/app/views/finance/me/expense_members/_breadcrumb.html.erb +6 -0
- data/app/views/finance/me/expense_members/_button.html.erb +0 -0
- data/app/views/finance/me/expense_members/_filter_form.html.erb +10 -0
- data/app/views/finance/me/expense_members/_form.html.erb +9 -0
- data/app/views/finance/me/expense_members/_index_tbody.html.erb +8 -0
- data/app/views/finance/me/expense_members/_index_thead.html.erb +7 -0
- data/app/views/finance/me/expense_members/_show_items.html.erb +1 -0
- data/app/views/finance/me/expense_members/admin.html.erb +3 -0
- data/app/views/finance/me/expense_members/index.html.erb +6 -0
- data/app/views/finance/me/expense_members/items.js.erb +1 -0
- data/app/views/finance/me/expense_members/show.html.erb +62 -0
- data/app/views/finance/me/expenses/_breadcrumb.html.erb +7 -0
- data/app/views/finance/me/expenses/_edit_form.html.erb +3 -0
- data/app/views/finance/me/expenses/_filter_form.html.erb +8 -0
- data/app/views/finance/me/expenses/_filter_table.html.erb +11 -0
- data/app/views/finance/me/expenses/_index_tbody.html.erb +16 -0
- data/app/views/finance/me/expenses/_index_thead.html.erb +6 -0
- data/app/views/finance/me/expenses/_index_tr.html.erb +14 -0
- data/app/views/finance/me/expenses/_new_form.html.erb +4 -0
- data/app/views/finance/me/expenses/_show/_breadcrumb.html.erb +6 -0
- data/app/views/finance/me/expenses/_show_table.html.erb +124 -0
- data/app/views/finance/me/expenses/admin.html.erb +5 -0
- data/app/views/finance/me/expenses/confirm.html.erb +27 -0
- data/app/views/finance/me/expenses/financial_taxons.js.erb +44 -0
- data/app/views/finance/me/expenses/index.html.erb +5 -0
- data/app/views/finance/me/expenses/index.js +42 -0
- data/app/views/finance/me/expenses/show.html.erb +3 -0
- data/app/views/me/_finance_nav.html.erb +11 -0
- data/config/locales/en.attributes.yml +6 -0
- data/config/locales/en.controller.yml +21 -0
- data/config/locales/en.enum.yml +18 -0
- data/config/locales/zh.attributes.yml +65 -0
- data/config/locales/zh.controller.yml +57 -0
- data/config/locales/zh.enum.yml +38 -0
- data/config/routes.rb +63 -0
- data/lib/rails_finance/config.rb +11 -0
- data/lib/rails_finance/engine.rb +26 -0
- data/lib/rails_finance/version.rb +3 -0
- data/lib/rails_finance.rb +2 -0
- metadata +259 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module Finance
|
2
|
+
module Ext::Financial
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attribute :fund_budget, :decimal, default: 0
|
7
|
+
attribute :fund_expense, :decimal, default: 0
|
8
|
+
attribute :budget_amount, :decimal, default: 0
|
9
|
+
attribute :expense_amount, :decimal, default: 0
|
10
|
+
|
11
|
+
has_many :budgets, class_name: 'Finance::Budget', as: :financial
|
12
|
+
has_many :expenses, class_name: 'Finance::Expense', as: :financial
|
13
|
+
end
|
14
|
+
|
15
|
+
def compute_budget_amount
|
16
|
+
self.budget_amount = budgets.sum(:amount)
|
17
|
+
end
|
18
|
+
|
19
|
+
def compute_expense_amount
|
20
|
+
self.expense_amount = expenses.sum(:amount)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Finance
|
2
|
+
module Ext::Member
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :expense_members, class_name: 'Finance::ExpenseMember', dependent: :nullify
|
7
|
+
has_many :expenses, class_name: 'Finance::Expense', through: :expense_members
|
8
|
+
has_many :created_expenses, class_name: 'Finance::Expense', foreign_key: :creator_id
|
9
|
+
has_many :budgets, class_name: 'Finance::Budget'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Finance
|
2
|
+
|
3
|
+
# 估值
|
4
|
+
module Model::Assessment
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attribute :amount, :decimal, default: 0
|
9
|
+
attribute :trustee_amount, :decimal
|
10
|
+
|
11
|
+
belongs_to :organ, class_name: 'Org::Organ'
|
12
|
+
|
13
|
+
has_many :stocks
|
14
|
+
|
15
|
+
after_save :sync_assess_amount, if: -> { saved_change_to_amount? }
|
16
|
+
end
|
17
|
+
|
18
|
+
def sync_assess_amount
|
19
|
+
stocks.each do |stock|
|
20
|
+
stock.update assess_amount: amount * stock.ratio
|
21
|
+
end
|
22
|
+
self.update trustee_amount: stocks.sum(:assess_amount)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Finance
|
2
|
+
module Model::Budget
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attribute :type, :string, default: 'Finance::FundBudget'
|
7
|
+
attribute :subject, :string
|
8
|
+
attribute :amount, :decimal
|
9
|
+
attribute :note, :string
|
10
|
+
|
11
|
+
belongs_to :organ, class_name: 'Org::Organ', optional: true
|
12
|
+
belongs_to :member, class_name: 'Org::Member', optional: true
|
13
|
+
belongs_to :financial, polymorphic: true, optional: true
|
14
|
+
belongs_to :fund, optional: true
|
15
|
+
belongs_to :stock, optional: true
|
16
|
+
|
17
|
+
belongs_to :financial_taxon, optional: true
|
18
|
+
belongs_to :taxon, class_name: 'FinancialTaxon', foreign_key: :financial_taxon_id, optional: true
|
19
|
+
|
20
|
+
has_many :verifiers, -> { where(verifiable_type: 'FinancialTaxon').order(position: :asc) }, class_name: 'Auditor::Verifier', primary_key: :financial_taxon_id, foreign_key: :verifiable_id
|
21
|
+
has_many :expense_items, dependent: :destroy
|
22
|
+
has_many :expenses, dependent: :destroy
|
23
|
+
accepts_nested_attributes_for :expense_items, allow_destroy: true, reject_if: :all_blank
|
24
|
+
|
25
|
+
#validate :amount_sum
|
26
|
+
validates :subject, presence: true
|
27
|
+
|
28
|
+
has_one_attached :proof
|
29
|
+
has_one_attached :invoice
|
30
|
+
|
31
|
+
enum state: {
|
32
|
+
init: 'init',
|
33
|
+
verifying: 'verifying',
|
34
|
+
finished: 'finished',
|
35
|
+
rejected: 'rejected'
|
36
|
+
}, _default: 'init'
|
37
|
+
|
38
|
+
acts_as_notify(
|
39
|
+
:default,
|
40
|
+
only: [:subject, :amount, :type],
|
41
|
+
methods: [:creator_name, :state_i18n]
|
42
|
+
)
|
43
|
+
acts_as_notify(
|
44
|
+
:request,
|
45
|
+
only: [:subject, :amount, :type],
|
46
|
+
methods: [:creator_name]
|
47
|
+
)
|
48
|
+
|
49
|
+
after_save :sum_amount, if: -> { saved_change_to_amount? }
|
50
|
+
after_save :sum_fund_amount, if: -> { fund && saved_change_to_amount? }
|
51
|
+
after_save :sum_stock_amount, if: -> { stock && saved_change_to_amount? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def can_operate?(member)
|
55
|
+
return true if member.admin?
|
56
|
+
self.next_operator == current_member && !['init', 'rejected', 'finished'].include?(self.state)
|
57
|
+
end
|
58
|
+
|
59
|
+
def next_state_state
|
60
|
+
if ['pending_om', 'pending_cfo'].include? state
|
61
|
+
next_state_states.without('pending_md').first
|
62
|
+
else
|
63
|
+
next_state_states.first
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def next_state_states
|
68
|
+
next_states(:state) do |states|
|
69
|
+
unless self.financial_taxon.verifiers
|
70
|
+
states - ['pending_verifier']
|
71
|
+
end
|
72
|
+
|
73
|
+
if self.amount <= 5000
|
74
|
+
states - ['pending_cfo']
|
75
|
+
elsif self.amount > 5000 && self.amount <= 20000
|
76
|
+
states - ['pending_om']
|
77
|
+
elsif self.amount > 20000
|
78
|
+
states - ['pending_om', 'pending_cfo']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def do_trigger(params = {})
|
84
|
+
self.trigger_to(state: params[:state])
|
85
|
+
|
86
|
+
self.class.transaction do
|
87
|
+
self.save!
|
88
|
+
to_notification(
|
89
|
+
member: creator,
|
90
|
+
link: url_helpers.me_expenses_url(id: self.id),
|
91
|
+
verbose: true
|
92
|
+
)
|
93
|
+
if next_verifier
|
94
|
+
to_notification(
|
95
|
+
member: next_verifier.member,
|
96
|
+
link: url_helpers.admin_me_expenses_url(id: self.id),
|
97
|
+
code: :request,
|
98
|
+
verbose: true
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def amount_cn
|
105
|
+
NumHelper.to_rmb amount&.to_f || 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def details
|
109
|
+
expense_items.map do |item|
|
110
|
+
"#{item.financial_taxon&.name} #{item.note} #{item.amount}"
|
111
|
+
end.join("\n")
|
112
|
+
end
|
113
|
+
|
114
|
+
def amount_sum
|
115
|
+
unless self.amount == self.expense_members.sum(&:amount)
|
116
|
+
self.errors.add :amount, 'Amount must equal to amount sum'
|
117
|
+
end
|
118
|
+
|
119
|
+
unless self.amount == self.expense_items.sum(&:amount)
|
120
|
+
self.errors.add :amount, 'Amount must equal to cost sum'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def transfer(type)
|
125
|
+
expense = self.expenses.build(type: type)
|
126
|
+
expense.assign_attributes self.attributes.slice('financial_taxon_id', 'subject', 'amount')
|
127
|
+
expense.creator_id = member_id
|
128
|
+
expense.expendable_type = budgeting_type
|
129
|
+
expense.expendable_id = budgeting_id
|
130
|
+
expense.save!
|
131
|
+
end
|
132
|
+
|
133
|
+
def sum_amount
|
134
|
+
financial.compute_budget_amount
|
135
|
+
financial.save
|
136
|
+
end
|
137
|
+
|
138
|
+
def sum_fund_amount
|
139
|
+
fund.sum_budget_amount(financial_type)
|
140
|
+
fund.save
|
141
|
+
if financial
|
142
|
+
financial.compute_fund_budget
|
143
|
+
financial.save
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def sum_stock_amount
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Finance
|
2
|
+
module Model::Expense
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attribute :type, :string
|
7
|
+
attribute :state, :string
|
8
|
+
attribute :subject, :string
|
9
|
+
attribute :amount, :decimal
|
10
|
+
attribute :note, :string, limit: 4096
|
11
|
+
attribute :invoices_count, :integer
|
12
|
+
|
13
|
+
belongs_to :organ, class_name: 'Org::Organ', optional: true
|
14
|
+
belongs_to :creator, class_name: 'Org::Member'
|
15
|
+
|
16
|
+
belongs_to :financial, polymorphic: true, optional: true
|
17
|
+
belongs_to :budget, optional: true
|
18
|
+
belongs_to :fund, optional: true
|
19
|
+
belongs_to :stock, optional: true
|
20
|
+
belongs_to :financial_taxon
|
21
|
+
belongs_to :payout, optional: true
|
22
|
+
belongs_to :taxon, class_name: 'FinancialTaxon', foreign_key: :financial_taxon_id
|
23
|
+
belongs_to :payment_method, optional: true
|
24
|
+
|
25
|
+
has_many :verifiers, -> { where(verifiable_type: 'FinancialTaxon').order(position: :asc) }, class_name: 'Auditor::Verifier', primary_key: :financial_taxon_id, foreign_key: :verifiable_id
|
26
|
+
has_many :expense_members, dependent: :destroy
|
27
|
+
has_many :members, through: :expense_members
|
28
|
+
has_many :expense_items, dependent: :destroy
|
29
|
+
|
30
|
+
accepts_nested_attributes_for :expense_members, allow_destroy: true, reject_if: :all_blank
|
31
|
+
accepts_nested_attributes_for :expense_items, allow_destroy: true, reject_if: :all_blank
|
32
|
+
|
33
|
+
#validate :amount_sum
|
34
|
+
validates :subject, presence: true
|
35
|
+
|
36
|
+
has_one_attached :proof
|
37
|
+
has_one_attached :invoice
|
38
|
+
|
39
|
+
enum state: {
|
40
|
+
init: 'init',
|
41
|
+
verifying: 'verifying',
|
42
|
+
paying: 'paying',
|
43
|
+
upload_invoice: 'upload_invoice',
|
44
|
+
invoice_verifying: 'invoice_verifying',
|
45
|
+
finished: 'finished',
|
46
|
+
rejected: 'rejected'
|
47
|
+
}, _default: 'init'
|
48
|
+
|
49
|
+
acts_as_notify(
|
50
|
+
:default,
|
51
|
+
only: [:subject, :amount, :type],
|
52
|
+
methods: [:creator_name, :state_i18n]
|
53
|
+
)
|
54
|
+
acts_as_notify(
|
55
|
+
:request,
|
56
|
+
only: [:subject, :amount, :type],
|
57
|
+
methods: [:creator_name]
|
58
|
+
)
|
59
|
+
|
60
|
+
before_save :sync_amount
|
61
|
+
after_save :sum_amount, if: -> { saved_change_to_amount? }
|
62
|
+
after_save :sum_fund_amount, if: -> { fund && saved_change_to_amount? }
|
63
|
+
after_save :sync_items, if: -> { saved_change_to_budget_id? && budget }
|
64
|
+
end
|
65
|
+
|
66
|
+
def can_operate?(member)
|
67
|
+
return true if member.admin?
|
68
|
+
self.next_operator == current_member && !['init', 'rejected', 'finished'].include?(self.state)
|
69
|
+
end
|
70
|
+
|
71
|
+
def next_state_state
|
72
|
+
if ['pending_om', 'pending_cfo'].include? state
|
73
|
+
next_state_states.without('pending_md').first
|
74
|
+
else
|
75
|
+
next_state_states.first
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def next_state_states
|
80
|
+
next_states(:state) do |states|
|
81
|
+
unless self.financial_taxon.verifiers
|
82
|
+
states - ['pending_verifier']
|
83
|
+
end
|
84
|
+
|
85
|
+
if self.amount <= 5000
|
86
|
+
states - ['pending_cfo']
|
87
|
+
elsif self.amount > 5000 && self.amount <= 20000
|
88
|
+
states - ['pending_om']
|
89
|
+
elsif self.amount > 20000
|
90
|
+
states - ['pending_om', 'pending_cfo']
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def do_trigger(params = {})
|
96
|
+
self.trigger_to(state: params[:state])
|
97
|
+
|
98
|
+
self.class.transaction do
|
99
|
+
self.save!
|
100
|
+
to_notification(
|
101
|
+
member: creator,
|
102
|
+
link: url_helpers.me_expenses_url(id: self.id),
|
103
|
+
verbose: true
|
104
|
+
)
|
105
|
+
if next_verifier
|
106
|
+
to_notification(
|
107
|
+
member: next_verifier.member,
|
108
|
+
link: url_helpers.admin_me_expenses_url(id: self.id),
|
109
|
+
code: :request,
|
110
|
+
verbose: true
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def amount_cn
|
117
|
+
NumHelper.to_rmb amount&.to_f || 0
|
118
|
+
end
|
119
|
+
|
120
|
+
def details
|
121
|
+
expense_items.map do |item|
|
122
|
+
"#{item.financial_taxon&.name} #{item.note} #{item.amount}"
|
123
|
+
end.join("\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
def amount_sum
|
127
|
+
unless self.amount == self.expense_members.sum(&:amount)
|
128
|
+
self.errors.add :amount, 'Amount must equal to amount sum'
|
129
|
+
end
|
130
|
+
|
131
|
+
unless self.amount == self.expense_items.sum(&:amount)
|
132
|
+
self.errors.add :amount, 'Amount must equal to cost sum'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def sum_amount
|
137
|
+
return unless financial
|
138
|
+
financial.compute_expense_amount
|
139
|
+
financial.save
|
140
|
+
end
|
141
|
+
|
142
|
+
def sum_fund_amount
|
143
|
+
fund.sum_expense_amount(financial_type)
|
144
|
+
fund.save
|
145
|
+
|
146
|
+
if financial
|
147
|
+
financial.compute_fund_expense
|
148
|
+
financial.save
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def sync_amount
|
153
|
+
self.amount = self.expense_items.sum(&:amount)
|
154
|
+
end
|
155
|
+
|
156
|
+
def sync_items
|
157
|
+
budget.expense_items.update_all expense_id: self.id
|
158
|
+
end
|
159
|
+
|
160
|
+
def sync_members
|
161
|
+
self.expense_items.pluck(:member_id).compact.each do |member_id|
|
162
|
+
amount = self.expense_items.sum(:amount)
|
163
|
+
self.expense_members.create(member_id: member_id, amount: amount)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|