跳转到内容

Offers shapes

此内容尚不支持你的语言。

From Adminium 0.3.19, add-ons 1.0.9.

An app that builds on Offers & gift cards does not import anything from it. The app writes, on its own tables and under its own column names, the rules below. Each group of rules is a shape. The add-on’s manifest lists the four shapes, and its source has a check, shapeFit, that an app runs in its own tests to hold its tables to them.

A column named here is a column the app must have under a name of its choosing; the rule names the app’s own column. “Adminium writes it” means the app never sends a value for it.

discountable@1 — an order whose price may be lowered

Section titled “discountable@1 — an order whose price may be lowered”

Three tables: the order, its lines, and the codes typed on it.

Table Column What it is
order subtotal the sum of its lines’ amounts (a rollup)
order discount the order’s reduction: the sum of its lines’. Adminium writes it
order net subtotal − discount (a formula)
order discount_kind, discount_value, discount_reason, discount_by a reduction staff give by hand: percent or amount, how much, a link to an Offers reason, and who gave it (Adminium writes the last)
order a state, or a column that is set when the order is paid, and when it is cancelled
lines link to the order, amount, discount the line’s price times its quantity; its reduction. Adminium writes discount
lines item what the line sells: a link to the app’s own item, and optionally its category, its type, a tag
codes link to the order, typed what the customer typed
codes code_id, voucher_id links to the Offers code or voucher it turned out to be. Adminium writes them
codes removed_at set when the customer takes a code off again

The order’s table carries the adjust rule, which names these columns, and one posting into the ledger offers / value with the action redeem: what was used is counted when the order is paid and given back when it is cancelled.

{
"adjust": {
"by": { "addOn": "offers" },
"lines": [{ "table": "lines", "via": "order_id", "price": "amount", "discount": "discount",
"what": [{ "column": "item", "as": "item" }] }],
"order": { "discount": "discount",
"staff": { "kind": "discount_kind", "value": "discount_value",
"reason": "discount_reason", "by": "discount_by" } },
"codes": { "table": "codes", "via": "order_id", "typed": "typed",
"code": "code_id", "voucher": "voucher_id", "removed": "removed_at" },
"uses": "uses"
},
"postings": [{
"id": "uses",
"into": { "addOn": "offers", "ledger": "value", "action": "redeem" },
"post": { "on": { "column": "paid_at", "set": true } },
"reverse": { "on": { "column": "cancelled_at", "set": true } },
"map": { "reason": "discount_reason" }
}]
}

A line that loads a gift card is left out of every reduction (excludes), and a line that sells a voucher names it (paidBy), where the same table also carries the two sale shapes below. Each sale shape says so itself (inAdjust on its lines part), so Adminium Designer writes the two words into the price rule whichever shape it adds first; by hand, write them on the rule’s line.

card-payment@1 — a payment a gift card makes

Section titled “card-payment@1 — a payment a gift card makes”

Two tables: the order (its due: what is still to pay) and its payments.

Column What it is
link to the order which order the payment is for
card_code what was typed or scanned
card_id the gift card found by that code (a lookup over Offers’ cards). Adminium writes it
card_last4 the card’s last four characters, kept beside the payment for a receipt
amount what the card paid: never more than is due, never more than the card holds. Adminium writes it
card_balance_after what the card holds afterwards. Adminium writes it
voided_at set when the payment is taken back: the card gets what it paid, less anything already refunded

One posting with the action spend, when the payment row is created, undone when voided_at is set. A table that holds cash payments beside card payments names which rows are the card’s with only — otherwise every rule of the posting is applied to the cash rows too.

A refund to the card is a posting of its own with the action refund, on the app’s refunds table: it names the payment row and the amount, and is refused above what that payment took.

card-sale@1 — a line that sells or tops up a gift card

Section titled “card-sale@1 — a line that sells or tops up a gift card”
Column What it is
link to the order the order whose payment makes the card active
gift_card_id the card the line loads (an inactive card made for the sale, or a card being topped up)
load_amount how much goes on it

One posting with the action issue, when the order is paid; undone when it is cancelled, taking back no more than the card still holds. A gift card cannot pay for a gift card: a table that carries card-payment@1 refuses a card payment on an order with such a line.

voucher-sale@1 — a line that sells a voucher or a pack

Section titled “voucher-sale@1 — a line that sells a voucher or a pack”
Column What it is
link to the order the order whose payment makes the voucher usable
voucher_id the voucher or pack the line sells (made waiting for its sale)
amount what it was sold for: a pack’s uses each carry their share of it
tax_later yes where tax is charged when the voucher is used, not when it is sold

One posting with the action sell, when the order is paid; undone when it is cancelled, unless the voucher has been used since.

The four shapes are in the add-on’s manifest (addOn.shapes) and, one file each, in its source (packages/offers/src/shapes/ in the add-ons repository), beside the check that reads them (src/testing/fit.ts, the function shapeFit). An app copies the shape files it adopts and that one file into its own repository, and calls it in its own tests with its manifest, which of its tables stands for which part, and the shapes:

const pairings = [
{ table: 'orders', shape: 'discountable@1', part: 'order' },
{ table: 'order_lines', shape: 'discountable@1', part: 'lines' },
{ table: 'order_codes', shape: 'discountable@1', part: 'codes' },
];
expect(shapeFit(manifest, pairings, [discountable])).toEqual([]);

It answers a list of what does not fit: a column that is missing or of another type, a rule that names the wrong column, a posting that fires at another point. An empty list is a fit. Because the files are copied, an app’s tests do not need the add-on installed.