Two patterns built on the feed, and the nudge
Part 3 of 4 · Reading iVendNext's events reliably
Back: The labels, the reconciliation and the reference clientNext: Technical notes
7. Two patterns built on the feed
A value judged only when it changes
A limit that should hold for a new or changed value only, such as an item's Max Discount (max_discount) set over the retailer's ceiling. A save rule of kind threshold judges the value on every save, so an old record already over the limit is refused at its next unrelated edit. From POS build 2.0.0.654 the threshold rule takes judge_on_change and refuses only a new or changed value at the save itself (save rules page): use it. Before that build, or to flag rather than refuse, your service judges it on the feed. The client's changed remembers the last value it saw, in the same transaction as the event (tools/feed_client/feed_client.py, two tests):
def handle(ev, db):
doc = shop.get(ev["doc_type"], ev["doc_name"])
new, before = F.changed(db, ev["doc_type"], ev["doc_name"], "max_discount", doc.get("max_discount"))
first_sight = new and before is None and ev["event"] != "item.created"
if new and not first_sight and float(doc.get("max_discount") or 0) > CEILING:
flag(doc, before) # your own record, a notification, or the shop's *Sales to review*: never a silent revert
The first time the service sees an existing record it only remembers the value: a record already over the limit before the service started is not flagged at its first unrelated edit. A new record is judged at once.
The doors it combines: the event feed and your service. The limit: the save is not refused: the value is judged seconds later, and your service flags it. A value edited twice between two polls is judged once, on the value it holds when read. A record changed before the service first saw it is remembered, not judged.
A settings record that drives rules
The retailer's people change one settings record (a record type of your own named Default, as S22's PP LYL Settings). Its values reach the records that enforce them: a save rule's limit (Retail Save Rule, its value) and a notification's recipients (Notification, its recipients rows). From POS build 2.0.0.654 a save rule reads its limit and role from a settings record itself (value_from_type, save rules page), with nothing to copy; a notification's recipients still are not. Before that build, and for recipients, your service copies them when the settings record's event arrives (tick your settings record type on the feed registration). S22's service/settings_sync.py is the function, standalone and tested (two tests); S22's own settings hold no limit or recipients, so S22 does not call it:
LINKS = [{"from": "max_redemption_percent", "record_type": "Retail Save Rule", "record": "PP LYL Redemption cap", "field": "value"},
{"from": "approver_emails", "record_type": "Notification", "record": "PP LYL Big redemption", "recipients": True}]
settings_sync.sync(shop, shop.get("PP LYL Settings", "Default"), LINKS) # writes only what differs
The records it writes are exactly the ones its links name. Give the service's role write on those records and nothing else. A replayed event writes nothing. A notification's rows that name a role or a field of the document are kept. The limit: for the seconds between the settings save and the copy, the rule holds the old value.
Appendix A — the nudge (was the webhook recipe)
A webhook is a doorbell, not a parcel: optional, for when you want to pull now instead of on your next poll. The retailer may create a Webhook on Integration Sync Log, after insert, conditioned on your application's name, sending no content — {"app": "<your application>"} — signed with a secret (recipes/webhook_receiver.md §2 for the signature check). On a valid nudge, run one poll. Never treat the nudge as the event: it can be lost, delayed or repeated, and the queue is the record. We have not tested the nudge yet; it is configuration only.
Back: The labels, the reconciliation and the reference clientNext: Technical notes