The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

AxKit::XSP::Handel::Cart - AxKit XSP Shopping Cart Taglib

SYNOPSIS

Add this taglib to AxKit in your http.conf or .htaccess:

    AxAddXSPTaglib AxKit::XSP::Handel::Cart

Add the namespace to your XSP file and use the tags:

    <xsp:page
         language="Perl"
         xmlns:xsp="http://apache.org/xsp/core/v1"
         xmlns:cart="http://today.icantfocus.com/CPAN/AxKit/XSP/Handel/Cart"
    >

    <cart:cart type="1">
        <cart:filter name="id"><request:idparam/></cart:filter>
        <cart:results>
            <cart>
                <id><cart:id/></id>
                <name><cart:name/></name>
                <description><cart:description/></description>
                <subtotal><cart:subtotal/></subtotal>
                <cart:items>
                    <cart:results>
                        <item>
                            <sku><cart:sku/></sku>
                            <description><cart:description/></description>
                            <quantity><cart:quantity/></quantity>
                            <price><cart:price/></price>
                            <total><cart:total/></total>
                        </item>
                    </cart:results>
                    </cart:no-results>
                        <message>There are currently no items in your shopping cart.</message>
                    </cart:no-results>
                </cart:items>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

DESCRIPTION

This tag library provides an interface to use Handel::Cart inside of your AxKit XSP pages.

CHANGES

Starting in version 0.09, <cart:type>, the type attribute, and the mode attribute in <cart:restore> now take the constants declared in Handel::Constants:

    <cart:type>CART_TYPE_SAVED</cart:type>

    <cart:new type="CART_TYPE_SAVED">
        ...
    </cart:new>

    <cart:restore mode="CART_MODE_APPEND">
        ...
    </cart:restore>

Starting in version 0.13, the currency formatting options from Handel::Currency are now available within the taglib:

     <cart:price format="0|1" code="USD|CAD|..." options="FMT_STANDARD|FMT_NAME|..." />

Starting in version 0.15, the currency conversion options from Handel::Currency are now available within the taglib:

    <cart:subtotal convert="0|1" from="USD|CAD|..." to="CAD|JPY|..." />

TAG HIERARCHY

    <cart:uuid/>
    <cart:new description|id|name|shopper|type="value"...>
        <cart:description>value</cart:description>
        <cart:id>value</cart:id>
        <cart:name>value</cart:name>
        <cart:shopper>value</cart:shopper>
        <cart:type>value</cart:type>
        <cart:results>
            <cart:count/>
            <cart:description/>
            <cart:id/>
            <cart:name/>
            <cart:shopper/>
            <cart:subtotal
                format="0|1"
                code="USD|CAD|..."
                options="FMT_STANDARD|FMT_NAME|..."
                convert="0|1"
                from="USD|CAD|..."
                to="CAD|JPY|..."
            />
            <cart:type/>
            <cart:add id|sku|quantity|price|description="value"...>
                <cart:description>value</cart:description>
                <cart:id>value</cart:id>
                <cart:sku>value</cart:sku>
                <cart:quantity>value</cart:quantity>
                <cart:price>value</cart:price>
                <cart:results>
                    <cart:description/>
                    <cart:id/>
                    <cart:price
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                    <cart:quantity/>
                    <cart:sku/>
                    <cart:total
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                </cart:results>
                <cart:no-results>
                    ...
                </cart:no-results>
            </cart:add>
        </cart:results>
        <cart:no-results>
            ...
        <cart:no-results>
    </cart:new>
    <cart:cart(s) description|id|name|shopper|type="value"...>
        <cart:filter name="description|id|name|shopper|type">value</cart:filter>
        <cart:results>
            <cart:add description|id|price|quantity|sku="value"...>
                <cart:description>value</cart:description>
                <cart:id>value</cart:id>
                <cart:price>value</cart:price>
                <cart:quantity>value</cart:quantity>
                <cart:sku>value</cart:sku>
                <cart:results>
                    <cart:description/>
                    <cart:id/>
                    <cart:price
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                    <cart:quantity/>
                    <cart:sku/>
                    <cart:total
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                </cart:results>
                </cart:no-results>
                    ...
                </cart:no-results>
            </cart:add>
            <cart:clear/>
            <cart:count/>
            <cart:delete description|id|price|quantity|sku="value"...>
                <cart:description>value</cart:description>
                <cart:id>value</cart:id>
                <cart:price>value</cart:price>
                <cart:quantity>value</cart:quantity>
                <cart:sku>value</cart:sku>
            </cart:delete>
            <cart:description/>
            <cart:id/>
            <cart:item(s) description|id|price|quantity|sku="value"...>
                <cart:filter name="description|id|price|quantity|sku">value</cart:filter>
                <cart:results>
                    <cart:description/>
                    <cart:id/>
                    <cart:price
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                    <cart:quantity/>
                    <cart:sku/>
                    <cart:total
                        format="0|1"
                        code="USD|CAD|..."
                        options="FMT_STANDARD|FMT_NAME|..."
                        convert="0|1"
                        from="USD|CAD|..."
                        to="CAD|JPY|..."
                    />
                    <cart:update>
                        <cart:description>value</cart:description>
                        <cart:price>value</cart:price>
                        <cart:quantity>value</cart:quantity>
                        <cart:sku>value</cart:sku>
                    </cart:update>
                </cart:results>
                <cart:no-results>
                    ...
                </cart:no-results>
            </cart:item(s)>
            <cart:name/>
            <cart:restore mode="CART_MODE_APPEND|CART_MODE_MERGE|CART_MODE_REPLACE" description|id|name|shopper|type="value"...>
                <cart:filter name="description|id|name|shopper|type">value</cart:filter>
            </cart:restore>
            <cart:save/>
            <cart:subtotal
                format="0|1"
                code="USD|CAD|..."
                options="FMT_STANDARD|FMT_NAME|..."
                convert="0|1"
                from="USD|CAD|..."
                to="CAD|JPY|..."
            />
            <cart:type/>
            <cart:update>
                <cart:description></cart:description>
                <cart:name></cart:name>
                <cart:shopper></cart:shopper>
                <cart:type></cart:type>
            </cart:update>
        </cart:results>
        <cart:no-results>
            ...
        </cart:no-results>
    </cart:cart(s)>

TAG REFERENCE

<cart:add>

Adds an a item to the current cart. You can specify the item properties as attributes in the tag itself:

    <cart:add
        description="My New Part"
        id="11111111-1111-1111-1111-111111111111"
        sku="1234"
        quantity="1"
        price="1.23"
    />

or you can add them as child elements:

    <cart:add>
        <cart:description>My New Part</cart:description>
        <cart:id>11111111-1111-1111-1111-111111111111</cart:id>
        <cart:sku>1234</cart:sku>
        <cart:quantity>1</cart:quantity>
        <cart:price>1.23</cart:price>
    </cart:add>

or any combination of the two:

    <cart:add quantity="1">
        <cart:description>My New Part</cart:description>
        <cart:id>11111111-1111-1111-1111-111111111111</cart:id>
        <cart:sku>1234</cart:sku>
        <cart:price>1.23</cart:price>
    </cart:add>

This tag is only valid within the <cart:results> block for cart and carts. See Handel::Cart for more information about adding parts to the shopping cart.

You can also access the newly added item using the <cart:results>.

<cart:cart>

Container tag for the current cart used to load a specific cart.

If cart or its filters load more than one cart, cart will contain only the first cart. If you're looking for loop through multiple carts, try <cart:carts> instead.

    <cart:cart type="1">
        <cart:filter name="id">11111111-1111-1111-1111-111111111111</cart:filter>
        <cart:results>
            <cart>
                <id><cart:id/></id>
                <name><<cart:name/></name>
                <description><cart:description/></description>
                <subtotal><cart:subtotal/></subtotal>
                <cart:items>
                    ...
                </cart:items>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:carts>

Loops through all loaded carts.

        <cart:carts type="1">
            <cart:filter name="shopper">11111111-1111-1111-1111-111111111111</cart:filter>
            <cart:results>
                <cart>
                    <id><cart:id/></id>
                    <name><<cart:name/></name>
                    <description><cart:description/></description>
                    <subtotal><cart:subtotal/></subtotal>
                    <cart:items>
                        ...
                    </cart:items>
                </cart>
            </cart:results>
            <cart:no-results>
                <message>No carts were found matching your query.</message>
            </cart:no-results>
        </cart:carts>
    </carts>

<cart:clear>

Deletes all items in the current shopping cart.

    <cart:cart type="0">
        <cart:filter name="shopper">11111111-1111-1111-1111-111111111111</cart:filter>
        <cart:results>
            <cart:clear/>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:count>

Returns the number of items in the current shopping cart.

    <cart:cart>
        <cart:results>
            <cart>
                <id><cart:id/></id>
                <name><<cart:name/></name>
                <description><cart:description/></description>
                <subtotal><cart:subtotal/></subtotal>
                <count><cart:count/></count>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:description>

Context aware tag to get or set the description of various other parent tags. Within <cart:cart> or <cart:carts> it returns the current carts description:

    <cart:cart>
        <cart:results>
            <description><cart:description/></description>
        </cart:results>
    </cart:cart>

Within <cart:add> or <cart:update> it sets the current cart or cart items description:

    <cart:cart>
        <cart:results>
            <cart:update>
                <cart:description>My Updated Cart Description</cart:description>
            </cart:update>

            <cart:add>
                <cart:description>My New SKU Description</cart:description>
            </cart:add>

            <cart:item sku="1234">
                <cart:results>
                    <cart:update>
                        <cart:description>My Updated SKU Description</cart:description>
                    <cart:update>
                </cart:results>
                <cart:no-results>
                    <message>The cart item could not be found for updating</message>
                </cart:no-results>
            <cart:item>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:filter>

Adds a new name/value pair to the filter used in <cart:cart>, <cart:carts>, <cart:delete>, <cart:item>, and <cart:items>. Pass the name of the pair in the name attribute and the value between the start and end filter tags:

    <cart:cart type="0">
        <cart:filter name="id">12345678-9098-7654-3212-345678909876</cart:filter>

        <cart:results>
            <cart:delete>
                <cart:filter name="sku">sku1234</cart:filter>
            <cart:delete>
        </cart:results>
        <cart:no-results>
            <message>The cart item could not be found for deletion</message>
        </cart:no-results>
    </cart:cart>

If the same attribute is specified in a filter, the child filter tag value takes precedence over the parent tags attribute.

    <cart:cart type="0">
        <!-- type == 0 -->
        <cart:filter name="type">1</cart:filter>
        <!-- type == 1 -->
    </cart:cart>

You can supply as many filters as needed to get the job done.

    <cart:cart>
        <cart:filter name="type">0</cart:filter>
        <cart:filter name="shopper">12345678-9098-7654-3212-345678909876</cart:filter>
    </cart:cart>

<cart:id>

Context aware tag to get or set the record id within various other tags. In <cart:cart> and <cart:item> it returns the record id for the object:

    <cart:cart>
        <cart:results>
            <id><cart:id/></id>
            <cart:items>
                <cart:cart:results>
                    <item>
                        <id><cart:id/></id>
                    </item>
                </cart:results>
            </cart:items>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Within <cart:add>, <cart:delete>, and <cart:new> it sets the id value used in the operation specified:

    <cart:cart>
        <cart:results>
            <cart:delete>
                <cart:id>11111111-1111-1111-1111-111111111111</cart:id>
            </cart:delete>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>
    ...
    <cart:new>
        <cart:id>11112222-3333-4444-5555-6666777788889999</cart:id>
        <cart:name>New Cart</cart:name>
    </cart:new>

It cannot be used within <cart:update> and will return a Handel::Exception::Taglib exception if you try updating the record ids which are the primary keys.

<cart:items>

Loops through all items in the current cart:

    <cart:cart>
        <cart:results>
            <cart>
                <cart:items>
                    <cart:results>
                        <item>
                            <sku><cart:sku/></sku>
                            <description><cart:description/></cart:description>
                            <name><cart:name/></name>
                            <quantity><cart:quantity/></quantity>
                            <price><cart:price/></price>
                            <total><cart:total/></total>
                        </item>
                    </cart:results>
                    <cart:no-results>
                        <message>Your shopping cart is empty</message>
                    </cart:no-results>
                </cart:items>
            <cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:name>

Context aware tag to get or set the name within various other tags. In <cart:cart> it returns the name for the cart object:

    <cart:cart>
        <cart:results>
            <name><cart:name/></name>
            ...
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Within <cart:update> and <cart:new> it sets the name value used in the operation specified:

    <cart:cart>
        <cart:results>
            <cart:update>
                <cart:name>My Updated Cart Name</cart:name>
            </cart:update>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>
    ...
    <cart:new>
        <cart:name>New Cart</cart:name>
    </cart:new>

<cart:new>

Creates a new shopping cart using the supplied attributes and child tags:

    <cart:new type="1">
        <cart:id>22222222-2222-2222-2222-222222222222</cart:id>
        <cart:shopper><request:shopper/></cart:shopper>
        <cart:name>New Cart</cart:name>
    </cart:new>

The child tags take precedence over the attributes of the same name. new must be a top level tag within it's declared namespace. It will throw an Handel::Exception::Taglib exception otherwise.

<cart:price>

Context aware tag to get or set the price of a cart item. In <cart:add> and <cart:update> it sets the price:

    <cart:cart>
        <cart:results>
            <cart:add>
                <cart:price>1.24</cart:price>
            </cart:add>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

In <cart:item> or <cart:items> it returns the price for the cart item:

    <cart:cart>
        <cart:results>
            <cart>
                <cart:items>
                    <cart:results>
                        <item>
                            <price><cart:price/></price>
                        </item>
                    </cart:results>
                    <cart:no-results>
                        <message>Your shopping cart is empty</message>
                    </cart:no-results>
                </cart:items>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Currency Formatting

Starting in version 0.13, the currency formatting options from Handel::Currency are now available within the taglib if Locale::Currency::Format is installed.

     <cart:price format="0|1" code="USD|CAD|..." options="FMT_STANDARD|FMT_NAME|..." />
format

Toggle switch that enables or disables currency formatting. If empty, unspecified, or set to 0, no formatting will take place and the result price (usually in decimal form) is returned unaltered.

If format is set to anything else, the default formatting will be applied. See Handel::Currency for the default currency formatting settings.

code

If formatting is enabled, the code attribute specifies the desired three letter ISO currency code to be used when formatting currency. See Locale::Currency::Format for the available codes.

If you are also using the currency conversion options below, the value of to will always be used first, even if code is not empty. If to is empty and code is also empty, the HandelCurrencyCode configuration setting will be used instead.

options

If formatting is enabled, the options attribute specifies the desired formatting options to be used when formatting currency. See Locale::Currency::Format for the available options.

Currency Conversion

Starting in version 0.15, the currency conversion options from Handel::Currency are now available within the taglib if Finance::Currency::Convert::WebserviceX is installed.

    <cart:price convert="0|1" from="USD|CAD|..." to="CAD|JPY|..." />
convert

Toggle switch that enables or disables currency conversion. If empty, unspecified, or set to 0, no currency conversion will take place and the result price is returned unaltered.

If convert is set to anything else, the default conversion will be applied. See Handel::Currency for the default currency conversion settings.

from

If conversion is enabled, the from attribute specifies the three letter ISO currency code of the price to be converted. If no from is specified, the HandelCurrencyCode configuration setting will be used instead. See Locale::Currency for the available codes.

to

If conversion is enabled, the to attribute specifies what the current price should be converted to. If no to is specified, the code attribute from the formatting options above will be used instead. If both to and code are empty, the HandelCurrencyCode configuration setting will be used as a last resort.

If you try to convert from and to the same currency, the price is returned as is.

Precedence

If you are using both the currency conversion and the currency formatting options, the conversion will be performed first, then the result will be formatted.

<cart:quantity>

Context aware tag to get or set the quantity of a cart item. In <cart:add> and <cart:update> it sets the quantity:

    <cart:cart>
        <cart:results>
            <cart:add>
                <cart:quantity>1.24</cart:quantity>
            </cart:add>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

In <cart:item> or <cart:items> it returns the quantity for the cart item:

    <cart:cart>
        <cart:results>
            <cart>
                <cart:items>
                    <cart:results>
                        <item>
                            <quantity><cart:quantity/></quantity>
                        </item>
                    </cart:results>
                    <cart:no-results>
                        <message>The item requested could not be found for updating</message>
                    </cart:no-results>
                </cart:items>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:update>

Updates the current cart values:

    <cart:cart>
        <cart:results>
            <cart:update>
                <cart:name>My Updated Cart Name</cart:update>
            <cart:update>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:id> is not valid within an update statement.

<cart:results>

Contains the results for the current action. both the singular and plural forms are valid for your syntactic sanity:

    <cart:cart>
        <cart:result>
            ...
        </cart:result>
    </cart:result>

    <cart:carts>
        <cart:results>

        </cart:results?
    </cart:carts>

<cart:no-results>

The anti-results or 'not found' tag. This tag is executed when cart, carts, item, or items fails to find a match for it's filters. As with <cart:results>, both the singular and plural forms are available for your enjoyment:

    <cart:cart>
        <cart:no-result>
            ...
        </cart:no-result>
    </cart:result>

    <cart:carts>
        <cart:no-results>

        </cart:no-results?
    </cart:carts>

<cart:restore>

Restores another cart into the current cart.

    <cart:restore mode="CART_MODE_APPEND">
        <cart:filter name="id">11111111-1111-1111-1111-111111111111</cart:filter>
    </cart:restore>

See Handel::Constants for the available mode values.

<cart:save>

Saves the current cart by setting its type to CART_TYPE_SAVED:

    <cart:cart>
        <cart:results>
            <cart:save/>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:shopper>

Context aware tag that gets or sets the shopper id for the current cart.

<cart:sku>

Context aware tag to get or set the sku of a cart item. In <cart:add> and <cart:update> it sets the sku:

    <cart:cart>
        <cart:results>
            <cart:add>
                <cart:sku>sku1234</cart:sku>
            </cart:add>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

In <cart:item> or <cart:items> it returns the sku for the current cart item:

    <cart:cart>
        <cart:results>
            <cart>
                <cart:items>
                        <cart:results>
                            <item>
                                <sku><cart:sku/></sku>
                            </item>
                        </cart:results>
                        <cart:no-results>
                            <message>Your shopping cart is empty</message>
                        </cart:no-results>
                </cart:items>
            </cart>
        <cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

<cart:subtotal>

Returns the subtotal of the items in the current cart:

    <cart:cart>
        <cart:results>
            <subtotal><cart:subtotal/></subtotal>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Starting in version 0.13, the currency formatting options from Handel::Currency are now available within the taglib.

     <cart:subtotal format="0|1" code="USD|CAD|..." options="FMT_STANDARD|FMT_NAME|..." />

Starting in version 0.15, the currency conversion options from Handel::Currency are now available within the taglib.

    <cart:subtotal convert="0|1" from="USD|CAD|..." to="CAD|JPY|..." />

See <cart:price> above for further details about price formatting.

<cart:total>

Returns the total of the current cart item:

    <cart:cart>
        <cart:results>
            <cart>
                <cart:items>
                    <cart:results>
                        <item>
                            <total><cart:total/></total>
                        </item>
                    </cart:results>
                    <cart:no-results>
                        <message>Your shopping cart is empty</message>
                    </cart:no-results>
                </cart:items>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Starting in version 0.13, the currency formatting options from Handel::Currency are now available within the taglib.

     <cart:total format="0|1" code="USD|CAD|..." options="FMT_STANDARD|FMT_NAME|..." />

Starting in version 0.15, the currency conversion options from Handel::Currency are now available within the taglib.

    <cart:total convert="0|1" from="USD|CAD|..." to="CAD|JPY|..." />

See <cart:price> above for further details about price formatting.

<cart:type>

Context aware tag to get or set the type within various other tags. In <cart:cart> or <cart:carts> it returns the type for the object:

    <cart:cart>
        <cart:results>
            <cart>
                <type><cart:type/></type>
            </cart>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>

Within <cart:update> and <cart:new> it sets the type value used in the operation specified:

    <cart:cart>
        <cart:results>
            <cart:update>
                <cart:type>1</cart:type>
            </cart:update>
        </cart:results>
        <cart:no-results>
            <message>The cart requested could not be found.</message>
        </cart:no-results>
    </cart:cart>
    ...
    <cart:new>
        <cart:type>1</cart:type>
    </cart:new>

<cart:uuid/>

This tag returns a new uuid/guid for use in new and add in the following format:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

For those like me who always type the wrong thing, <cart:guid/<gt> returns the same things as <cart:uuid/<gt>.

AUTHOR

    Christopher H. Laco
    CPAN ID: CLACO
    claco@chrislaco.com
    http://today.icantfocus.com/blog/