Module: Invoicing::LineItem
- Defined in:
- lib/invoicing/line_item.rb
Overview
Line item objects
A line item is a single charge on an invoice or credit note, for example representing the sale of one particular product. An invoice or credit note with a non-zero total_amount
must have at least one LineItem
object associated with it, and its total_amount
must equal the sum of the net_amount
and tax_amount
values of all LineItem
objects associated with it. For details on invoices and credit notes, see the LedgerItem
module.
Many of the important principles set down in the LedgerItem
module also apply for line items; for example, once you have created a line item you generally shouldn’t change it again. If you need to correct a mistake, create an additional line item of the same type but a negative value.
Using LineItem
In all likelihood you will have different types of charges which you need to make to your customers. We store all those different types of line item in the same database table and use ActiveRecord’s single table inheritance to build a class hierarchy. You must create at least one line item model class in your application, like this:
class LineItem < ActiveRecord::Base
acts_as_line_item
belongs_to :ledger_item
end
You may then create a class hierarchy to suit your needs, for example:
class ProductSale < LineItem
belongs_to :product
def description
product.title
end
end
class ShippingCharges < LineItem
def description
"Shipping charges"
end
end
You may associate line items of any type with credit notes and invoices interchangeably. This means, for example, that if you overcharge a customer for shipping, you can send them a credit note with a ShippingCharges
line item, thus making it explicit what it is you are refunding. On a credit note/refund the line item’s net_amount
and tax_amount
should be negative. Payment
records usually do not have any associated line items.
Required methods/database columns
The following methods/database columns are required for LineItem
objects (you may give them different names, but then you need to tell acts_as_line_item
about your custom names):
type
-
String to store the class name, for ActiveRecord single table inheritance.
ledger_item
-
You should define an association
belongs_to :ledger_item, ...
which returns theLedgerItem
object (invoice/credit note) to which this line item belongs. ledger_item_id
-
A foreign key of integer type, which stores the ID of the model object returned by the
ledger_item
association. net_amount
-
A decimal column containing the monetary amount charged by this line item, not including tax. The value is typically positive on an invoice and negative on a credit note. The currency is not explicitly specified on the line item, but is taken to be the currency of the invoice or credit note to which it belongs. (This is deliberate, because you mustn’t mix different currencies within one invoice.) See the documentation of the
CurrencyValue
module for notes on suitable datatypes for monetary values.acts_as_currency_value
is automatically applied to this attribute. tax_amount
-
A decimal column containing the monetary amount of tax which is added to
net_amount
to obtain the total price. This may of course be zero if no tax applies; otherwise it should have the same sign asnet_amount
.CurrencyValue
applies as withnet_amount
. If you have several different taxes being applied, please check with your accountant. We suggest that you put VAT or sales tax in thistax_amount
column, and any other taxes (e.g. duty on alcohol or tobacco, or separate state/city taxes) in separate line items. If you are not obliged to pay tax, lucky you – put zeroes in this column and await the day when you have enough business that you do have to pay tax. description
-
A method which returns a short string explaining to your user what this line item is for. Can be a database column but doesn’t have to be.
Optional methods/database columns
The following methods/database columns are optional, but recommended for LineItem
objects:
uuid
-
A Universally Unique Identifier (UUID) string for this line item. It may seem unnecessary now, but may help you to keep track of your data later on as your system grows. If you have the
uuid
gem installed and this column is present, a UUID is automatically generated when you create a new line item. tax_point
-
A datetime column which indicates the date on which the sale is made and/or the service is provided. It is related to the
issue_date
on the associated invoice/credit note, but does not necessarily have the same value. The exact technicalities will vary by jurisdiction, but generally this is the point in time which determines into which month or which tax period you count a sale. The value may be the same ascreated_at
orupdated_at
, but not necessarily. tax_rate_id
,tax_rate
-
tax_rate_id
is a foreign key of integer type, andtax_rate
is abelongs_to
association based on it. It refers to another model in your application which represents the tax rate applied to this line item. The tax rate model object should useacts_as_tax_rate
. This attribute is necessary if you want tax calculations to be performed automatically. price_id
,price
-
price_id
is a foreign key of integer type, andprice
is abelongs_to
association based on it. It refers to another model in your application which represents the unit price (e.g. a reference to a the product, or to a particular price band of a service). The model object thus referred to should useacts_as_price
. This attribute allows you to get better reports of how much you sold of what. quantity
-
A numeric (integer or decimal) type, saying how many units of a particular product or service this line item represents. Default is 1. Note that if you specify a
quantity
, the values fornet_amount
andtax_amount
must be the cost of the given quantity as a whole; if you need to display the unit price, you can get it by dividingnet_amount
byquantity
, or by referring to theprice
association. creator_id
-
The ID of the user whose action caused this line item to be created or updated. This can be useful for audit trail purposes, particularly if you allow multiple users of your application to act on behalf of the same customer organisation.
created_at
,updated_at
-
These standard datetime columns are also recommended.
Defined Under Namespace
Modules: ActMethods Classes: ClassInfo
Instance Method Summary collapse
- #calculate_tax_amount ⇒ Object
-
#currency ⇒ Object
Returns the currency code of the ledger item to which this line item belongs.
-
#gross_amount ⇒ Object
The sum of
net_amount
andtax_amount
. -
#gross_amount_formatted ⇒ Object
gross_amount
formatted in human-readable form using the line item’s currency. -
#initialize(*args) ⇒ Object
Overrides the default constructor of
ActiveRecord::Base
whenacts_as_line_item
is called. -
#method_missing(method_id, *args) ⇒ Object
We don’t actually implement anything using
method_missing
at the moment, but use it to generate slightly more useful error messages in certain cases.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *args) ⇒ Object
We don’t actually implement anything using method_missing
at the moment, but use it to generate slightly more useful error messages in certain cases.
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/invoicing/line_item.rb', line 216 def method_missing(method_id, *args) method_name = method_id.to_s if ['ledger_item', line_item_class_info.method(:ledger_item)].include? method_name raise RuntimeError, "You need to define an association like 'belongs_to :ledger_item' on #{self.class.name}. If you " + "have defined the association with a different name, pass the option :ledger_item => :your_association_name to " + "acts_as_line_item." elsif method_name =~ /^amount/ send("net_#{method_name}", *args) else super end end |
Instance Method Details
#calculate_tax_amount ⇒ Object
197 198 199 200 |
# File 'lib/invoicing/line_item.rb', line 197 def calculate_tax_amount return unless respond_to? :net_amount_taxed self.tax_amount = net_amount_taxed - net_amount end |
#currency ⇒ Object
Returns the currency code of the ledger item to which this line item belongs.
191 192 193 194 195 |
# File 'lib/invoicing/line_item.rb', line 191 def currency ledger_item = line_item_class_info.get(self, :ledger_item) raise RuntimeError, 'Cannot determine currency for line item without a ledger item' if ledger_item.nil? ledger_item.send(:ledger_item_class_info).get(ledger_item, :currency) end |
#gross_amount ⇒ Object
The sum of net_amount
and tax_amount
.
203 204 205 206 207 |
# File 'lib/invoicing/line_item.rb', line 203 def gross_amount net_amount = line_item_class_info.get(self, :net_amount) tax_amount = line_item_class_info.get(self, :tax_amount) (net_amount && tax_amount) ? (net_amount + tax_amount) : nil end |
#gross_amount_formatted ⇒ Object
gross_amount
formatted in human-readable form using the line item’s currency.
210 211 212 |
# File 'lib/invoicing/line_item.rb', line 210 def gross_amount_formatted format_currency_value(gross_amount) end |
#initialize(*args) ⇒ Object
Overrides the default constructor of ActiveRecord::Base
when acts_as_line_item
is called. If the uuid
gem is installed, this constructor creates a new UUID and assigns it to the uuid
property when a new line item model object is created.
181 182 183 184 185 186 187 188 |
# File 'lib/invoicing/line_item.rb', line 181 def initialize(*args) super # Initialise uuid attribute if possible info = line_item_class_info if self.has_attribute?(info.method(:uuid)) && info.uuid_generator write_attribute(info.method(:uuid), info.uuid_generator.generate) end end |