Class: Voucher
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Voucher
- Includes:
- Models::Auditable
- Defined in:
- app/models/voucher.rb
Overview
== Schema Information
Table name: vouchers
Database name: primary
id :integer not null, primary key
category :string(255)
currency :string(255)
exchange_rate :float
gl_date :date
invoice_date :date
invoice_number :string(255)
payment_terms :string(255)
reference_number :string(255) not null
reversal_date :date
state :string(255)
created_at :datetime
updated_at :datetime
business_unit_id :integer
company_id :integer
creator_id :integer
order_id :integer
supplier_id :integer
updater_id :integer
Indexes
index_vouchers_on_business_unit_id (business_unit_id)
index_vouchers_on_category (category)
index_vouchers_on_company_id (company_id)
index_vouchers_on_currency (currency)
index_vouchers_on_gl_date (gl_date)
index_vouchers_on_invoice_date (invoice_date)
index_vouchers_on_invoice_number (invoice_number)
index_vouchers_on_order_id (order_id)
index_vouchers_on_payment_terms (payment_terms)
index_vouchers_on_reference_number (reference_number)
index_vouchers_on_state (state)
supplier_id_invoice_number (supplier_id,invoice_number)
Constant Summary collapse
- CATEGORIES =
%w[voucher debit_memo commission].freeze
- REFERENCE_NUMBER_PATTERN =
/^PV(\d+)$/i
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Instance Attribute Summary collapse
- #business_unit_id ⇒ Object readonly
- #category ⇒ Object readonly
- #company_id ⇒ Object readonly
- #currency ⇒ Object readonly
- #gl_date ⇒ Object readonly
- #invoice_date ⇒ Object readonly
- #invoice_number ⇒ Object readonly
- #order_id ⇒ Object readonly
-
#order_ref ⇒ Object
Returns the value of attribute order_ref.
- #payment_terms ⇒ Object readonly
- #supplier_id ⇒ Object readonly
-
#supplier_type ⇒ Object
Returns the value of attribute supplier_type.
Belongs to collapse
Methods included from Models::Auditable
Has many collapse
- #ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
- #outgoing_payment_items ⇒ ActiveRecord::Relation<OutgoingPaymentItem>
- #uploads ⇒ ActiveRecord::Relation<Upload>
- #voucher_items ⇒ ActiveRecord::Relation<VoucherItem>
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<Voucher>
A relation of Vouchers that are active.
- .build_gl_entries_from_csv(file_path) ⇒ Object
- .get_next_reference_number ⇒ Object
- .states_for_select ⇒ Object
- .voucher_count(company_id = nil, where_conditions = nil, where_not_conditions = nil) ⇒ Object
-
.with_lazy_loads ⇒ ActiveRecord::Relation<Voucher>
A relation of Vouchers that are with lazy loads.
Instance Method Summary collapse
- #all_items_fully_paid? ⇒ Boolean
- #all_payments_voided? ⇒ Boolean
- #amount_to_distribute ⇒ Object
- #balance ⇒ Object
- #can_be_voided? ⇒ Boolean
- #currency_symbol ⇒ Object
- #distribute_to_gl(_temporary_account_id = nil, ledger_entries = []) ⇒ Object
- #editing_locked? ⇒ Boolean
- #intercompany_posting_assign_ledger_project ⇒ Object
- #reverse(date) ⇒ Object
- #supplier_name ⇒ Object
- #to_s ⇒ Object
- #total ⇒ Object
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::EventPublishable
Instance Attribute Details
#business_unit_id ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#category ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#company_id ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#currency ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#gl_date ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#invoice_date ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#invoice_number ⇒ Object (readonly)
65 |
# File 'app/models/voucher.rb', line 65 validates :invoice_number, uniqueness: { scope: :supplier_id, message: 'is already in use on another voucher for this supplier', unless: :voided? } |
#order_id ⇒ Object (readonly)
59 |
# File 'app/models/voucher.rb', line 59 validates :order_id, presence: { if: proc { |v| v.category == 'commission' } } |
#order_ref ⇒ Object
Returns the value of attribute order_ref.
86 87 88 |
# File 'app/models/voucher.rb', line 86 def order_ref @order_ref end |
#payment_terms ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#supplier_id ⇒ Object (readonly)
58 |
# File 'app/models/voucher.rb', line 58 validates :category, :company_id, :supplier_id, :invoice_date, :gl_date, :currency, :business_unit_id, :payment_terms, presence: true |
#supplier_type ⇒ Object
Returns the value of attribute supplier_type.
86 87 88 |
# File 'app/models/voucher.rb', line 86 def supplier_type @supplier_type end |
Class Method Details
.active ⇒ ActiveRecord::Relation<Voucher>
A relation of Vouchers that are active. Active Record Scope
84 |
# File 'app/models/voucher.rb', line 84 scope :active, -> { where.not(state: 'voided') } |
.build_gl_entries_from_csv(file_path) ⇒ Object
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'app/models/voucher.rb', line 337 def self.build_gl_entries_from_csv(file_path) ledger_entries = [] CSV.foreach(file_path, headers: true) do |row| account = LedgerCompanyAccount.joins(:company, :ledger_detail_account).where(companies: { number: row['company'] }, ledger_accounts: { number: row['account'] }).first project = LedgerDetailProject.where(project_number: row['project']).first ledger_entries << { account_id: account.try(:id), account_ref: account.try(:identifier), project_id: project.try(:id), project_ref: project.try(:project_number), amount: row['amount'], business_unit_id: BusinessUnit.where(number: row['business_unit']).first.try(:id), remark: row['description'] } end ledger_entries end |
.get_next_reference_number ⇒ Object
358 359 360 361 |
# File 'app/models/voucher.rb', line 358 def self.get_next_reference_number seq = Voucher.find_by_sql("SELECT nextval('voucher_reference_numbers_seq') AS reference_number") seq[0].reference_number.to_s end |
.states_for_select ⇒ Object
134 135 136 |
# File 'app/models/voucher.rb', line 134 def self.states_for_select Voucher.state_machines[:state].states.map { |s| [s.human_name.titleize, s.name] }.sort end |
.voucher_count(company_id = nil, where_conditions = nil, where_not_conditions = nil) ⇒ Object
126 127 128 129 130 131 132 |
# File 'app/models/voucher.rb', line 126 def self.voucher_count(company_id = nil, where_conditions = nil, where_not_conditions = nil) v = Voucher.order('id') v = v.where(company_id: company_id) unless company_id.nil? v = v.where(where_conditions) unless where_conditions.nil? v = v.where.not(where_not_conditions) unless where_not_conditions.nil? v.count end |
.with_lazy_loads ⇒ ActiveRecord::Relation<Voucher>
A relation of Vouchers that are with lazy loads. Active Record Scope
80 81 82 83 |
# File 'app/models/voucher.rb', line 80 scope :with_lazy_loads, -> { includes({ voucher_items: :tax_rate }, :business_unit, :company, :supplier, { ledger_transactions: [:company, { ledger_entries: { ledger_company_account: %i[company ledger_detail_account] } }] }) } |
Instance Method Details
#all_items_fully_paid? ⇒ Boolean
170 171 172 173 |
# File 'app/models/voucher.rb', line 170 def all_items_fully_paid? # force reload of the voucher items as sometimes it's referring to already loaded stale objects voucher_items.reload.all?(&:fully_paid?) end |
#all_payments_voided? ⇒ Boolean
175 176 177 |
# File 'app/models/voucher.rb', line 175 def all_payments_voided? outgoing_payment_items.reload.all?(&:voided?) end |
#amount_to_distribute ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'app/models/voucher.rb', line 195 def amount_to_distribute amount = BigDecimal(0) voucher_items.each do |vi| amount += case vi.tax_type when 'V' (vi.gross_amount - vi.tax_amount) when 'U' (vi.gross_amount + vi.tax_amount) else vi.gross_amount end end amount end |
#balance ⇒ Object
156 157 158 159 160 |
# File 'app/models/voucher.rb', line 156 def balance return 0 if voided? total - voucher_items.all.to_a.sum { |vi| vi.outgoing_payment_items.applied.sum(:amount) } end |
#business_unit ⇒ BusinessUnit
50 |
# File 'app/models/voucher.rb', line 50 belongs_to :business_unit, optional: true |
#can_be_voided? ⇒ Boolean
179 180 181 |
# File 'app/models/voucher.rb', line 179 def can_be_voided? unpaid? or paid? end |
#currency_symbol ⇒ Object
333 334 335 |
# File 'app/models/voucher.rb', line 333 def currency_symbol Money::Currency.new(currency).symbol end |
#distribute_to_gl(_temporary_account_id = nil, ledger_entries = []) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'app/models/voucher.rb', line 210 def distribute_to_gl(_temporary_account_id = nil, ledger_entries = []) transaction do case category when 'voucher_logging' # trade_accounts_payable_company_account = LedgerCompanyAccount.for_company_and_account(company.id, TRADE_ACCOUNTS_PAYABLE_ACCOUNT) # temporary_company_account = LedgerCompanyAccount.find(temporary_account_id) # # raise "Unable to find all necessary accounts to post to" if trade_accounts_payable_company_account.nil? or temporary_company_account.nil? # # ap_amount = -total # temp_amount = BigDecimal("0") # tax_accounts = {} # # voucher_items.each do |vi| # case vi.tax_type # when "N/A" # temp_amount += vi.gross_amount # when "S" # temp_amount += vi.gross_amount # when "U" # tax_account = LedgerCompanyAccount.where(:company_id => company.id, :ledger_detail_account_id => vi.tax_rate.use_tax_account_id).first # raise "Cannot find use tax account for tax rate id: #{vi.tax_rate_id}" if tax_account.nil? # tax_accounts[tax_account.id] = tax_accounts[tax_account.id].nil? ? -vi.tax_amount : (tax_accounts[tax_account.id] += -vi.tax_amount) # temp_amount += (vi.gross_amount + vi.tax_amount) # when "V" # tax_account = LedgerCompanyAccount.where(:company_id => company.id, :ledger_detail_account_id => vi.tax_rate.sales_tax_credit_account_id).first # raise "Cannot find output tax account for tax rate id: #{vi.tax_rate_id}" if tax_account.nil? # tax_accounts[tax_account.id] = tax_accounts[tax_account.id].nil? ? vi.tax_amount : (tax_accounts[tax_account.id] += vi.tax_amount) # # add the (gross_amount - tax_amount) to be distributed # # for tax only lines this would be 0 # temp_amount += vi.gross_amount - vi.tax_amount # end # end # # transaction = LedgerTransaction.new(:company => company, :transaction_type => "VOUCHER", :transaction_date => gl_date, :currency => currency, :voucher => self, :exchange_rate => exchange_rate) # transaction.ledger_entries << LedgerEntry.new(:ledger_company_account => trade_accounts_payable_company_account, :currency => currency, :amount => ap_amount) # transaction.ledger_entries << LedgerEntry.new(:ledger_company_account => temporary_company_account, :currency => currency, :amount => temp_amount) # tax_accounts.each do |account_id, amount| # transaction.ledger_entries << LedgerEntry.new(:ledger_company_account_id => account_id, :currency => currency, :amount => amount) # end # # transaction.save! # # # need to when 'voucher', 'debit_memo', 'commission' default_offset_account = if supplier.gl_offset_account.present? LedgerCompanyAccount.for_company_and_account(company.id, supplier.gl_offset_account.number) else LedgerCompanyAccount.for_company_and_account(company.id, TRADE_ACCOUNTS_PAYABLE_ACCOUNT) end raise 'Unable to find all necessary accounts to post to' if default_offset_account.nil? accounts = { default_offset_account => { amount: 0, business_unit: nil } } tax_accounts = {} voucher_items.each do |vi| case vi.tax_type when 'U' tax_account = LedgerCompanyAccount.where(company_id: company.id, ledger_detail_account_id: vi.tax_rate.use_tax_account_id).first raise "Cannot find use tax account for tax rate id: #{vi.tax_rate_id}" if tax_account.nil? tax_accounts[tax_account.id] = tax_accounts[tax_account.id].nil? ? -vi.tax_amount : (tax_accounts[tax_account.id] += -vi.tax_amount) when 'V' tax_account = LedgerCompanyAccount.where(company_id: company.id, ledger_detail_account_id: vi.tax_rate.sales_tax_credit_account_id).first raise "Cannot find output tax account for tax rate id: #{vi.tax_rate_id}" if tax_account.nil? tax_accounts[tax_account.id] = tax_accounts[tax_account.id].nil? ? vi.tax_amount : (tax_accounts[tax_account.id] += vi.tax_amount) end if vi.gl_offset_account.present? accounts[vi.gl_offset_account] ||= { amount: 0, business_unit: vi.business_unit } accounts[vi.gl_offset_account][:amount] += -vi.gross_amount else accounts[default_offset_account][:amount] += -vi.gross_amount end end transaction = LedgerTransaction.new(company: company, transaction_type: 'VOUCHER', transaction_date: gl_date, currency: currency, voucher: self, exchange_rate: exchange_rate) accounts.each do |account, details| unless details[:amount].zero? transaction.ledger_entries << LedgerEntry.new(ledger_company_account: account, currency: currency, amount: details[:amount], business_unit: details[:business_unit]) end end tax_accounts.each do |account_id, amount| transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: account_id, currency: currency, amount: amount) end ledger_entries.each do |le| transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: le['account_id'], currency: currency, amount: le['amount'], description: le['remark'], ledger_detail_project_id: le['project_id'], business_unit_id: le['business_unit_id']) end transaction.save! intercompany_posting_assign_ledger_project gl_completed! end end end |
#editing_locked? ⇒ Boolean
183 184 185 |
# File 'app/models/voucher.rb', line 183 def editing_locked? !draft? or voided? end |
#intercompany_posting_assign_ledger_project ⇒ Object
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'app/models/voucher.rb', line 313 def intercompany_posting_assign_ledger_project itercompany_postings_entries = [] ledger_transactions.first.ledger_entries.each do |le| if le.ledger_company_account.ledger_detail_account && le.ledger_company_account.ledger_detail_account.number == INTERCOMPANY_TRANSFERS_ACCOUNT itercompany_postings_entries << { ledger_company_account_id: le.ledger_company_account_id, company_id: le.ledger_company_account.company_id } end end return unless itercompany_postings_entries.length > 1 ledger_transactions.first.ledger_entries.each do |le| le.update(ledger_detail_project_id: Company.find(itercompany_postings_entries.last[:company_id]).ledger_project_id) if le.ledger_company_account_id == itercompany_postings_entries.first[:ledger_company_account_id] le.update(ledger_detail_project_id: Company.find(itercompany_postings_entries.first[:company_id]).ledger_project_id) if le.ledger_company_account_id == itercompany_postings_entries.last[:ledger_company_account_id] end end |
#ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
54 |
# File 'app/models/voucher.rb', line 54 has_many :ledger_transactions |
#outgoing_payment_items ⇒ ActiveRecord::Relation<OutgoingPaymentItem>
55 |
# File 'app/models/voucher.rb', line 55 has_many :outgoing_payment_items, through: :voucher_items |
#reverse(date) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'app/models/voucher.rb', line 138 def reverse(date) raise 'Reversal date required' if date.nil? Voucher.transaction do self.reversal_date = date save! payments = outgoing_payment_items.collect(&:payment).uniq payments.each do |p| p.reversal_date = reversal_date p.state_event = 'void' p.save! end reload self.state_event = 'void' save! end end |
#supplier ⇒ Party
49 |
# File 'app/models/voucher.rb', line 49 belongs_to :supplier, class_name: 'Party', inverse_of: :vouchers, optional: true |
#supplier_name ⇒ Object
187 188 189 |
# File 'app/models/voucher.rb', line 187 def supplier_name supplier.try(:full_name) end |
#to_s ⇒ Object
122 123 124 |
# File 'app/models/voucher.rb', line 122 def to_s "Voucher ##{reference_number}" end |
#total ⇒ Object
329 330 331 |
# File 'app/models/voucher.rb', line 329 def total voucher_items.sum(:gross_amount) end |
#uploads ⇒ ActiveRecord::Relation<Upload>
56 |
# File 'app/models/voucher.rb', line 56 has_many :uploads, as: :resource, dependent: :destroy |
#voucher_items ⇒ ActiveRecord::Relation<VoucherItem>
53 |
# File 'app/models/voucher.rb', line 53 has_many :voucher_items, inverse_of: :voucher, dependent: :destroy |