class Skr::Invoice
Invoices constitute a demand for payment for goods that have been delivered to a {Customer}. A invoice contains:
* Customer contact information * An inventory location that goods will be taken from. * The customer provided {PurchaseOrder} Number * The Payment Terms that were extended. This will control how much time the Customer has to pay the invoice in full. * One or more SKUs, the quantity desired for each and the selling price for them.
While an {Invoice} often originates with a {SalesOrder}, it does not have to. Sales that take place in a retail environment where the customer selects the goods and pays for them immediately do not require a sales order record.
Once an invoice is saved, it immediately removes the SKUs from the {SkuLoc} and generates corresponding General Ledger entries debiting the asset account and crediting the customers receivables account.
When payment is received against the Invoice
, the receivables account is debited and the payments holding account is credited.
invoice = Invoice.new( customer: Customer.find_by_code("ACME") invoice.lines.build({ sku: Sku.find_by_code('LABOR'), qty: 1, price: 8.27 }) invoice.save
Public Class Methods
# File lib/skr/models/invoice.rb, line 94 def initialize(attributes = {}) super # date must be set, otherwise things like terms that are based off of it fail self.invoice_date ||= Date.today end
Public Instance Methods
@return [DateTime] when the invoice is due
# File lib/skr/models/invoice.rb, line 111 def due_date self.terms.due_date_from(invoice_date) end
@return [Boolean] is the invoice paid in full
# File lib/skr/models/invoice.rb, line 106 def fully_paid? unpaid_amount <= 0 end
# File lib/skr/models/invoice.rb, line 115 def is_locked? GlPeriod.is_date_locked?(self.invoice_date) end
# File lib/skr/models/invoice.rb, line 119 def total_hours lines.reduce(BigDecimal.new('0')){|t, l| l.time_entry ? t + l.qty : t } end
@return [BigDecimal] total - amount_paid
# File lib/skr/models/invoice.rb, line 101 def unpaid_amount self.total - self.payments.total end
Private Instance Methods
set the state if the amount_paid was changed
# File lib/skr/models/invoice.rb, line 128 def apply_payment(pymnt) if self.fully_paid? && self.may_mark_paid? self.mark_paid! elsif self.payments.total > 0 && self.may_mark_partialy_paid? self.mark_partialy_paid! end end
# File lib/skr/models/invoice.rb, line 176 def ensure_location_matches_so if sales_order && location != sales_order.location self.errors.add(:location, "#{location.code} must match location that order was taken on (#{sales_order.location.code})") end end
# File lib/skr/models/invoice.rb, line 170 def ensure_unlocked if is_locked? self.errors.add(:invoice_date, "falls on a locked GL Period") end end
# File lib/skr/models/invoice.rb, line 136 def set_defaults if pick_ticket self.location = pick_ticket.location self.sales_order = pick_ticket.sales_order end if sales_order self.terms ||= sales_order.terms self.form ||= sales_order.form self.customer = sales_order.customer self.po_num = sales_order.po_num if self.po_num.blank? self.billing_address = sales_order.billing_address if self.billing_address.blank? self.shipping_address = sales_order.shipping_address if self.shipping_address.blank? if self.options && sales_order.options self.options.merge!(sales_order.options) else self.options = sales_order.options end end if customer_project self.customer = customer_project.customer self.po_num = customer_project.po_num if self.po_num.blank? end if customer self.form ||= customer.get_form('invoice') self.billing_address = customer.billing_address if self.billing_address.blank? self.shipping_address = customer.shipping_address if self.shipping_address.blank? end end