iVendNextDevelopers Request a sandbox

S31 — Parent item groups in coupons and promotions (pp_pgx)

A shop sets up a coupon for Supplements and expects it to cover every supplement. But the till's coupon and promotion engines match an item's own item group exactly. A row naming the parent group Supplements matches only items placed directly in it, never those in Supplements › Protein.

This sample's service, outside the shop, writes the parent out as its child groups and keeps it that way: when the coupon is saved, and when a new group is added under the parent. It is for an iVendNext Partner building for a shop whose item groups are a tree.

The doors it combines: an outside app on the event feed, and the record API. The limit: a row appears a few seconds after the save, not in the same save. A promotion's buy and get rows are reported, never written out (below).

What happens

A person The service
saves a coupon whose get rows name a parent group adds one get row per child group (children, their children, …), each copying the parent row's quantity, discount and flags
saves a promotion whose exclusion rows name a parent group adds one exclusion row per child group
adds an item group under a listed parent adds it to every coupon and promotion that lists the parent
removes the parent row, or moves a group out from under it removes the rows the service added that no listed parent covers any more, and only those (a child another listed parent still covers stays)
removes a child row the service added leaves it removed: it is not added back while a listed parent covers it; it comes back if the parent leaves and is listed again
has added a child row of their own leaves it alone, and never removes it
names a parent group in a promotion's buy or get row reports it (FLAG), and changes nothing

Why not a promotion's buy and get rows. Each buy row and each get row is counted and filled on its own. A child row there would add a condition to meet or a line to give, and change the offer. The report says so and asks the person to list the child groups, or to set the offer on the items.

Coupons have no item-group exclusions at this version: a coupon's exclusion rows name customer groups only.

What the shop does

  1. Install the manifest (manifest.json). It declares only the feed registration PP PGX Groups (Coupon, Promotion Bonus Buys Master, Item Group). It installs switched off.

  2. Make the service's user. A role with read and write on Coupon and Promotion Bonus Buys Master, and read on Item Group; an integration user with that role and its API key (recipes/integration_user.md). Choose that user on the feed registration.

  3. Run the service where the partner runs services (recipes/event_feed.md):

    PGX_KEY=… PGX_SECRET=… python3 samples/s31_parent_groups/expander.py reconcile --base https://shop.example   # once, for what exists
    PGX_KEY=… PGX_SECRET=… python3 samples/s31_parent_groups/expander.py run --base https://shop.example --watch 15
    

Where it shows. On the coupon or promotion in Desk: the added rows, in their table. At the till: the coupon or the exclusion now covers the child groups' items.

What leaves the shop. The service reads coupons, promotions and item groups, and writes coupon and promotion rows. With these rights its key can change any coupon or promotion.

When the service is down or slow

Ownership

The rows have no marker field, so the service keeps its own list of the rows it added (state/pgx.sqlite, table ours). It writes that list in the same transaction as the event.

The files

File What
manifest.json the feed registration, and nothing else
groups.py the core: which rows a record needs, pure, no shop
expander.py the service: the feed, the record API, the ownership store
tests/ the core and the service against an in-memory shop · canaries.py

Run it

python3 -m unittest discover -s samples/s31_parent_groups/tests -p 'test_*.py'
python3 samples/s31_parent_groups/tests/canaries.py
python3 tools/check/check.py samples/s31_parent_groups

Technical notes

What was proven where

Why this way (R6)

Needs this serves

This page in the kit