Version 4 > Developer Guides > Transition Guide for Developers > Plugins and Frameworks > E-commerce

E-commerce

E-commerce and Financial reports work similarly to v3. Some significant new features have been added, however.

Shopping Cart

There is a new Cart class in the Finance framework that handles the shopping cart functionality. It inherits from the Receivable class. If you use the Pay module to generate your shopping cart views, you will not need to interact with the Cart directly. But if you need more control over the shopping cart experience, you can use the Cart class as a shopping cart API as follows:

Obtain a shopping cart object:

my $cart = new Modules::Finance::Cart();  # automatically connects to the current shopping cart

Display the cart:

$out .= $cart->show(%options);  # interactive, eg. delete from cart, change quantity, checkout
$out .= $cart->show_readonly(%options);  # only shows the cart, no interactivity

Add an item to the cart:

$cart->add(%item);  # %item describes a receivable_item

Receivable Items can now be related to each other through a parent column; this allows for multiple purchases in the cart to be related to each other as co-purchases. Removing the parent purchase will, for example, also remove the co-purchase.

Note that deleting items from the cart does not actually delete the receivable_item records any more; it merely changes the record status to deleted. Remember this when looping over the items in an invoice; use $item->is_active to determine whether the item is active (not deleted). Similarly, items can also have a status of “hidden” (do not display in end-user views) and “readonly” (do not permit the end-user to alter or delete the item).

When calling $invoice->show(%opt), use the options deleted=>1 or hidden=>1 to included deleted or hidden items in your views of the contents, as they will not be shown by default.

Callbacks to Purchased Objects

Individual line items can be related to database objects using the objtype and objid fields, as in v3. To obtain a purchased object, simply use:

my $obj = $receivable_item->purchased_object();

There are 7 standard callbacks that will be used automatically, if they exist in the purchased object:

$obj->sale_select($item); # this is called when the object is added to the cart
$obj->sale_quantity($item,$old_q,$new_q); # this is called when the quantity of the object is changed
$obj->sale_delete($item); # this is called when the object is removed from the cart
$obj->sale_activate($item); # this is called when the sale is closed and the invoice is activated
$obj->sale_complete($tem); # this is called when the sale is completed and paid in full
$obj->sale_note($item); # this is used to append purchase notes/messages to invoices and receipts
$obj->sale_validate($item,$final); # used to validate that the sale is allowed

In each case, the receivable item object is passed to the callback.

Purchase Locations

Purchased objects can define their own location for the purpose of calculating taxes and other surcharges. When the object is added to the cart, you can pass country and provstate values that will be used for this purpose. This information is saved in the receivable_item record, so no location handlers or special callbacks are needed. 

If no location information is included in the purchased object, the purchaser location will be used instead.

GL Codes

Itemized financial reports can include GL codes for each item. GL codes have 2 forms, internal and external. Internal GL codes have the format “AXX.YYY.ZZZ”:

A = 1 for sales, 2 for payments received, 3 for refunds, and 4 for payments issued

XX = the type (sales type/accounting code for sales, payment method for payments)

YYY = a purchase category identifier (eg. an event, or catalog ID)

ZZZ = a purchase subcategory identifier (eg. a fee, or product ID)

To set these GL code values, set the following fields in the receivable_item table, or in the parameters to $cart->add(...):

XX: acctcode_id

YYY: acctcode2

ZZZ: acctcode3

For example, the internal GL code 102.556.562 is a sale (1xx) of Account Code 2 (event registrations, say), relating to event 556 and fee 562.

This GL code structure allows for some generalization, grouping, and categorization, for instance 102.* is all event-registration sales, whereas 102.556.* is all sales for one particular event, and 102.556.562 is all sales for one fee. Sorting by GL code will automatically group related sales together.

GL Code Mapping

Further grouping and categorization is possible with GL code mapping. Internal GL codes can be mapped to external GL codes using the glcode table. This table defines simple rules for converting internal GL codes to external GL codes for some other accounting system. A mapping rule consists of an internal GL code, which is compared to the GL code of an actual item, and an external GL code that is used if the two match. Mapping rules can define one, two, or all three fields of the internal GL code, for example:

102 - matches any internal GL code starting with 102

102.556 - matches any internal GL code starting with 102.556

102.556.563 - matches that GL code exactly.

Example mapping rule: If event 556 is a conference with multiple different fees, but you want all conference fees to be grouped by the same external GL code, the following map rule will use “CONF2016” as the GL code for all registrations in all fees for that event.

102.556 --> CONF2016

If there are multiple mapping rules that all match, it will choose the most specific one that matches.

You can also use GL code maps to equivalence different items. For example, if you run two sessions of a course, they will end up with different internal GL codes because they are different events. If one is event 600 and the other is event 601, you can equivalence them with a simple mapping rule like:

102.601 --> 102.600

or, alternatively

102.600 --> COURSE101

102.601 --> COURSE101

Payment GL codes

Payments also use GL codes in the format "AXX.YYY.ZZZ". A is 2 for revenues, and 4 for refunds. XX is set based on the payment method. YYY is the account ID that the payment was made against, and ZZZ is the invoice that was being paid, if that information is available.

Note that payments also have a new ident field which contains a payment identifier. This is meant to be used for including an identification value such as last 4 digits of credit card, or cheque number. Keeping this in a separate field makes it more easily reported and searchable than putting it into the notes field.

End user GL code documentation is here.