Class: Receipt
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Receipt
- Includes:
- Models::Auditable, ReceiptDisplay, ReceiptFinancials, ReceiptPayment, ReceiptSpreadsheetIo, ReceiptTransmission, ReceiptValidations
- Defined in:
- app/models/receipt.rb
Overview
== Schema Information
Table name: receipts
Database name: primary
id :integer not null, primary key
amount :decimal(8, 2)
approved_for_refund :boolean
auth_code :string(255)
card_type :string(255)
category :string(255)
currency :string(255)
email :string
exchange_rate :float
exported :boolean default(FALSE), not null
gl_date :date
hold_for_review :boolean default(FALSE), not null
jde_number :string(255)
receipt_date :date
reference :string(255)
remark :string(255)
state :string(255)
created_at :datetime
updated_at :datetime
authorization_id :integer
bank_account_id :integer
company_id :integer
creator_id :integer
customer_id :integer
deleter_id :integer
edi_transaction_id :string
order_id :integer
payment_id :integer
updater_id :integer
Indexes
idx_customer_id_receipt_date (customer_id,receipt_date)
index_receipts_on_bank_account_id (bank_account_id)
index_receipts_on_company_id (company_id)
index_receipts_on_edi_transaction_id (edi_transaction_id) UNIQUE
index_receipts_on_hold_for_review (hold_for_review)
index_receipts_on_payment_id (payment_id)
index_receipts_on_state (state)
receipts_authorization_id_index (authorization_id)
Foreign Keys
fk_rails_... (authorization_id => legacy_authorizations.id)
fk_rails_... (bank_account_id => bank_accounts.id)
fk_rails_... (company_id => companies.id)
fk_rails_... (customer_id => parties.id)
Defined Under Namespace
Classes: SubmitToTaxjar
Constant Summary collapse
- CATEGORIES =
Categories.
['ACH', 'Cash', 'Check', 'Credit Card', 'Echeck', 'Wire Transfer', 'Amazon Pay', 'Non-Cash', 'PayPal', 'Payment Link'].freeze
- CARD_TYPES =
Recognised card types.
%w[american_express discover master visa vault].freeze
Constants included from ReceiptValidations
ReceiptValidations::WYUS_COMPANY_ID
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #amount ⇒ Object readonly
- #bank_account_id ⇒ Object readonly
- #category ⇒ Object readonly
- #company_id ⇒ Object readonly
- #currency ⇒ Object readonly
- #customer_id ⇒ Object readonly
-
#customer_name ⇒ Object
writeonly
Form fields - getters are defined below to derive from customer.
-
#customer_type ⇒ Object
writeonly
Form fields - getters are defined below to derive from customer.
- #gl_date ⇒ Object readonly
- #new_gl_date ⇒ Object
-
#process_cc_payment ⇒ Object
Returns the value of attribute process_cc_payment.
- #receipt_date ⇒ Object readonly
- #state ⇒ Object readonly
Belongs to collapse
Methods included from Models::Auditable
Has many collapse
- #communications ⇒ ActiveRecord::Relation<Communication>
- #edi_communication_logs ⇒ ActiveRecord::Relation<EdiCommunicationLog>
- #edi_documents ⇒ ActiveRecord::Relation<EdiDocument>
- #ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
- #outgoing_payment_items ⇒ ActiveRecord::Relation<OutgoingPaymentItem>
- #receipt_details ⇒ ActiveRecord::Relation<ReceiptDetail>
Class Method Summary collapse
-
.available_to_apply ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are available to apply.
-
.for_company_id ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are for company id.
-
.fully_applied ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are fully applied.
-
.states_for_select ⇒ Array<Array(String, Symbol)>
[label, value]pairs of every workflow state for select inputs.
Instance Method Summary collapse
-
#create_receipt_details(invoice, amount) ⇒ Object
Append a single Invoice-category ReceiptDetail for
amount, push the receipt's GL date forward to whichever of (current gl_date, invoice gl_date) is later, and persist. -
#evaluate_taxjar_submission ⇒ Object
Re-run TaxJar submission evaluation on every active GL-Account line.
- #has_linked_payment_items? ⇒ Boolean
- #hold_for_review? ⇒ Boolean
- #only_remarks_changed? ⇒ Boolean
-
#regenerate_invoice_pdf ⇒ Object
Re-render every linked Invoice PDF asynchronously so the new payment appears on the customer-facing document.
-
#void_receipt(reversal_dates, use_original_date: false, use_specific_date: nil) ⇒ Object
reversal_dates: a hash of transaction id containing date to use use_original_date: use the ledger transaction original date use_specific_date: use a specific date.
Methods included from ReceiptFinancials
#credit_applied_to_summary, #detail_document_balances, #funds_assigned, #no_funds_applied?, #unapplied_funds
Methods included from ReceiptPayment
#authorization_code, #category_for_authorization_type, #credit_card?, #default_cc_options, #echeck?, #payment_description
Methods included from ReceiptDisplay
#card_name, #currency_symbol, #customer_name, #customer_type, #is_not_for_a_customer?, #reference_summary, #store, #to_s
Methods included from ReceiptTransmission
#billing_address, #determine_email, #first_document, #notification_emails, #primary_transmission_contact, #send_email, #transmission_contact_points
Methods included from ReceiptSpreadsheetIo
create_receipts_from_xlsx, edit_receipts_from_xlsx, validate_data_create_receipts_from_xlsx, validate_data_edit_receipts_from_xlsx
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 Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#amount ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#bank_account_id ⇒ Object (readonly)
83 |
# File 'app/models/receipt.rb', line 83 validates :bank_account_id, presence: { unless: proc { |r| r.category == 'Non-Cash' } } |
#category ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#company_id ⇒ Object (readonly)
86 |
# File 'app/models/receipt.rb', line 86 validates :amount, :company_id, :customer_id, numericality: true |
#currency ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#customer_id ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#customer_name=(value) ⇒ Object (writeonly)
Form fields - getters are defined below to derive from customer
120 121 122 |
# File 'app/models/receipt.rb', line 120 def customer_name=(value) @customer_name = value end |
#customer_type=(value) ⇒ Object (writeonly)
Form fields - getters are defined below to derive from customer
120 121 122 |
# File 'app/models/receipt.rb', line 120 def customer_type=(value) @customer_type = value end |
#gl_date ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#new_gl_date ⇒ Object
85 |
# File 'app/models/receipt.rb', line 85 validates :new_gl_date, presence: { on: :update, unless: proc { |r| r.state_changed? or r.approved_for_refund? or r.only_remarks_changed? } } |
#process_cc_payment ⇒ Object
Returns the value of attribute process_cc_payment.
119 120 121 |
# File 'app/models/receipt.rb', line 119 def process_cc_payment @process_cc_payment end |
#receipt_date ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
#state ⇒ Object (readonly)
82 |
# File 'app/models/receipt.rb', line 82 validates :customer_id, :category, :amount, :currency, :gl_date, :receipt_date, :state, presence: true |
Class Method Details
.available_to_apply ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are available to apply. Active Record Scope
115 |
# File 'app/models/receipt.rb', line 115 scope :available_to_apply, -> { where(state: %w[unapplied partially_applied], approved_for_refund: true) } |
.for_company_id ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are for company id. Active Record Scope
117 |
# File 'app/models/receipt.rb', line 117 scope :for_company_id, ->(company_id) { where(company_id: company_id) } |
.fully_applied ⇒ ActiveRecord::Relation<Receipt>
A relation of Receipts that are fully applied. Active Record Scope
116 |
# File 'app/models/receipt.rb', line 116 scope :fully_applied, -> { where(state: 'fully_applied') } |
.states_for_select ⇒ Array<Array(String, Symbol)>
[label, value] pairs of every workflow state for select inputs.
228 229 230 |
# File 'app/models/receipt.rb', line 228 def self.states_for_select Receipt.state_machines[:state].states.map { |s| [s.human_name.titleize, s.name] }.sort end |
Instance Method Details
#bank_account ⇒ BankAccount
73 |
# File 'app/models/receipt.rb', line 73 belongs_to :bank_account, optional: true |
#communications ⇒ ActiveRecord::Relation<Communication>
78 |
# File 'app/models/receipt.rb', line 78 has_many :communications, -> { order(:id).reverse_order }, as: :resource, dependent: :nullify, inverse_of: :resource |
#create_receipt_details(invoice, amount) ⇒ Object
Append a single Invoice-category ReceiptDetail for amount, push
the receipt's GL date forward to whichever of (current gl_date,
invoice gl_date) is later, and persist. Errors are reported to
AppSignal rather than raised so callers (e.g. EDI auto-apply) can
continue.
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'app/models/receipt.rb', line 199 def create_receipt_details(invoice, amount) # Catch-up callers (Invoice#create_receipts_for_captured_payments) re-attempt # detail creation after the invoice may have been settled by another receipt # in the meantime. If the requested `amount` no longer fits in the invoice # balance, the `applied_amount_not_greater_than_invoice_balance` validation # would reject the save. Skip silently — no detail to create — instead of # reporting an AppSignal error for benign already-paid races (AppSignal #4120). if invoice.present? && amount.present? && invoice.balance.present? && amount > invoice.balance Rails.logger.info "[Receipt##{id}] skipping create_receipt_details: amount #{amount} exceeds invoice ##{invoice.id} balance #{invoice.balance}" return end effective_gl_date = [gl_date, invoice&.gl_date].compact.max self.new_gl_date = effective_gl_date receipt_details << ReceiptDetail.new(category: 'Invoice', invoice: invoice, amount: amount, gl_date: effective_gl_date) begin save! rescue StandardError => e ErrorReporting.error e, receipt_id: id, message: "Receipt details not created correctly. Receipt ID #{id}" end end |
#customer ⇒ Party
71 |
# File 'app/models/receipt.rb', line 71 belongs_to :customer, class_name: 'Party', inverse_of: :receipts, optional: true |
#edi_communication_logs ⇒ ActiveRecord::Relation<EdiCommunicationLog>
80 |
# File 'app/models/receipt.rb', line 80 has_many :edi_communication_logs, through: :edi_documents |
#edi_documents ⇒ ActiveRecord::Relation<EdiDocument>
79 |
# File 'app/models/receipt.rb', line 79 has_many :edi_documents, dependent: :destroy |
#evaluate_taxjar_submission ⇒ Object
Re-run TaxJar submission evaluation on every active GL-Account line.
Fired from after_commit; details decide individually whether to
post or void to TaxJar.
153 154 155 |
# File 'app/models/receipt.rb', line 153 def evaluate_taxjar_submission receipt_details.non_voided.gl_accounts.each(&:evaluate_taxjar_submission) end |
#has_linked_payment_items? ⇒ Boolean
221 222 223 |
# File 'app/models/receipt.rb', line 221 def has_linked_payment_items? outgoing_payment_items.not_voided.any? end |
#hold_for_review? ⇒ Boolean
238 239 240 |
# File 'app/models/receipt.rb', line 238 def hold_for_review? hold_for_review end |
#ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
76 |
# File 'app/models/receipt.rb', line 76 has_many :ledger_transactions, dependent: :destroy |
#only_remarks_changed? ⇒ Boolean
157 158 159 160 |
# File 'app/models/receipt.rb', line 157 def only_remarks_changed? all_changes = changes.keys.concat(receipt_details.map { |rd| rd.changes.keys }).flatten all_changes.any? and all_changes.all?('remark') end |
#outgoing_payment_items ⇒ ActiveRecord::Relation<OutgoingPaymentItem>
77 |
# File 'app/models/receipt.rb', line 77 has_many :outgoing_payment_items, inverse_of: :receipt, dependent: :destroy |
#receipt_details ⇒ ActiveRecord::Relation<ReceiptDetail>
75 |
# File 'app/models/receipt.rb', line 75 has_many :receipt_details, inverse_of: :receipt, dependent: :destroy |
#regenerate_invoice_pdf ⇒ Object
Re-render every linked Invoice PDF asynchronously so the new
payment appears on the customer-facing document.
234 235 236 |
# File 'app/models/receipt.rb', line 234 def regenerate_invoice_pdf receipt_details.where.not(invoice_id: nil).find_each { |rd| InvoicePdfGenerationWorker.perform_async(rd.invoice_id) } end |
#void_receipt(reversal_dates, use_original_date: false, use_specific_date: nil) ⇒ Object
reversal_dates: a hash of transaction id containing date to use
use_original_date: use the ledger transaction original date
use_specific_date: use a specific date
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'app/models/receipt.rb', line 165 def void_receipt(reversal_dates, use_original_date: false, use_specific_date: nil) Receipt.transaction do # void the receipt details receipt_details.each(&:void!) # reverse the ledger transactions ledger_transactions.each do |lt| date_to_use = use_specific_date date_to_use ||= lt.transaction_date if use_original_date date_to_use ||= reversal_dates[lt.id.to_s] lt.reverse(date_to_use) end # unoffset the credit memos and unpay the receipts receipt_details.each do |rd| if (cm = rd.credit_memo.presence) && !cm.funds_fully_offset? cm.unoffset! end rd.invoice.presence&.unpay end # void the receipt trigger_void! end end |