Vendors / Open source & self-hostable
ERPNext / Frappe POS
ERPNext / Frappe POS (Frappe Technologies)
dossier live
- Claims in scope
- 258
- Scored
- 258
- Assessed
- 258
- Unknown
- 0
- Not applicable
- 56
- Values challenged
- 199
Identity
- Owner
- Frappe Technologies Pvt. Ltd.
- Founded
- Frappe Technologies Pvt. Ltd., Mumbai, India; ERPNext development began 2008, first public release 2010. Frappe Framework and ERPNext are developed in the open at github.com/frappe.
- Scale
- unknown. Frappe Cloud's marketplace page states 342+ apps listed and github.com/frappe/erpnext is a large, active repository. Frappe publishes no customer count, ARR or restaurant-location figure. Any "X thousand companies" number in circulation is marketing, not audited.
- Who it is for
- NOT a restaurant ICP. The real buyer is a 10-250 employee SMB or mid-market manufacturer/distributor/retailer that wants a full ERP (GL, AP/AR, inventory, BOM, manufacturing, HR) and is willing to self-host or hire an implementation partner. Heaviest adoption in India, the UAE/GCC and Africa, where localised tax (GST, VAT) and a zero licence cost dominate. The POS inside it is a single-screen retail/counter POS — the POS Profile and POS Invoice doctypes were read in full for this pass and contain no table, seat, course, modifier or kitchen concept. Restaurants on the Frappe stack overwhelmingly buy a third-party marketplace app (URY, POSNext, GETPOS, KLiK PoS, POS Restaurant, Retail Suite) rather than core ERPNext — see cloud.frappe.io/marketplace. Frappe's own restaurant/hotel module, github.com/frappe/hospitality, was archived read-only on 2023-10-04.
- Site
- https://erpnext.com/
Pricing
transparency: partial · unit: mixed · processor lock-in: no
- Software
- The software itself is free. license.txt in github.com/frappe/erpnext is the GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 — GPL-3.0, not AGPL-3.0. Note the vendor contradicts itself: frappe.io/erpnext/pricing describes ERPNext as 'AGPL-3.0 licensed' while the repository ships GPL-3.0. Self-hosting costs $0 in licence. Frappe Cloud managed hosting is priced inconsistently across two first-party pages, both retrieved 2026-08-02, and the figures should be read as a range rather than a rate card. frappe.io/erpnext/pricing: Sites '$5 onwards /mo' (₹410 onwards/mo); Servers '$20 onwards /mo' (₹1,800 onwards/mo); Premium Servers '$125 onwards /mo' (₹5,400 onwards/mo). frappe.io/cloud/pricing, the canonical Frappe Cloud page: Sites '$5 onwards /mo' (₹410 onwards/mo); Servers '$40 onwards /mo' (₹3,600 onwards/mo) — with no premium tier listed at all and no ₹1,800 figure anywhere. Only the $5 Sites floor survives cross-checking; server pricing is $20–$40 depending which vendor page you read. Billing is explicitly not per user — 'pay only for what you use, and not per user' — it is per site and per server. 14-day free trial. Enterprise plans are 'Speak to our solution consultants', i.e. quote-only. Every published figure is an 'onwards' floor, which is why transparency is scored partial rather than published: there is an entry price but no full rate card.
- Card processing
- Not applicable — Frappe is not a payment processor and takes no share of card volume. No card rates are published because no card acceptance is sold. The POS Profile payments table maps Modes of Payment to GL accounts, not to an acquirer.
- Contract
- Month-to-month, pay-as-you-use on Frappe Cloud; no minimum term is stated on the pricing page. Self-hosted has no contract at all.
- Early termination
- None can apply to self-hosting. For Frappe Cloud no ETF is stated on the pricing page, but the terms of service were not retrieved in this pass, so an affirmative "no ETF" clause could not be verified.
API posture
public API: open
- Cost to integrate
- $0. No partner fee, no certification fee and no revenue share is charged for API access — the API is part of the free GPL-3.0 software. Frappe publishes no marketplace/partner commercial terms, so app-listing economics on cloud.frappe.io/marketplace remain unknown.
- Webhooks
- Native Webhook doctype, configurable per DocType and per document event, with conditions, custom headers, and either form-urlencoded or Jinja-templated JSON payloads. When a webhook secret is set, Frappe adds an X-Frappe-Webhook-Signature header carrying a base64-encoded HMAC-SHA256 hash of the payload, and a request log records every successful transmission. Retry and backoff behaviour is not documented. Source: https://docs.frappe.io/framework/user/en/guides/integration/webhooks
- Data export on exit
- Structurally the strongest in this peer group. Self-hosted operators hold the MariaDB/Postgres database outright. Frappe ships a Data Export / Data Import tool, `bench backup` produces a full site tarball, and every DocType (Sales Invoice, POS Invoice, Customer, Item, Loyalty Point Entry, Employee Checkin) is readable and writable over REST. There is no vendor gate on exit. Frappe Cloud's post-termination retention window was not located.
- Notes
- The API is auto-generated for every DocType — /api/resource/:doctype with GET/POST/PUT/DELETE, plus filters, field selection, ordering and pagination. Auth is token (api_key:api_secret), session cookie, or OAuth 2.0 bearer token. Rate limiting is real but site-configurable rather than a published quota: site_config.json takes `limit` (seconds of processing per window) and `window` (seconds); responses carry X-RateLimit-Limit/Used/Remaining/Reset and Retry-After, with HTTP 429 over limit. Custom Fields, Client Script and Server Script let an operator add fields and run server-side logic with no engineering engagement — a genuine differentiator against every closed POS in this set.
Capabilities
Every claim is binary and checkable. Grades: A primary documentation · B product documentation · C pricing or feature page · D marketing claim · E third-party reporting · F inference with no source. A yes on a differentiator claim requires A or B.
Order capture & FOH workflow
Provides a graphical floor-plan editor where an operator can draw sections, place tables of varying shape/capacity, save multiple floor-plan layouts per location, and assign sections to servers.
order-capture-floor-plan-editor
Restaurant Table/floor concepts lived only in the hospitality app, which Frappe archived read-only on Oct 4, 2023. Core POS is a retail item grid. https://github.com/frappe/hospitality · retrieved 2026-08-01
Order lines can be tagged to a seat number at entry, and the check can be split by seat afterward without re-keying items.
order-capture-seat-level
POS Invoice was read field by field: there is no seat, cover or guest-number field and no per-seat grouping on the items table. Seats existed only in frappe/hospitality, archived read-only 2023-10-04. Regrade: the previous cell cited first-party documentation at grade E. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Items can be assigned to courses and held, with a fire-next-course action available from a handheld or terminal that releases only that course to the kitchen.
order-capture-coursing-hold-fire
Searched the vendor's own words - course/coursing/fire/hold/seat/modifier, plus 'Kitchen' as a send destination - anchored at word boundaries. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: zero real word-boundary hits for \bcourse\b|\bfire\b|\bcoursing\b in either repository (32 files match unanchored, every one of them noise: Leaflet's .fire() event dispatcher, jQuery, and 'of course' in a changelog); \bseat\b resolves to eight lines of a chair BOM in test_bom_creator.py; \bkitchen\b resolves to two chart-of-accounts templates (a GL account named Kitchen in the Singapore F&B and UAE charts). The POS line item that would have to carry a course number and a hold flag is POS Invoice Item, and its 98-field field_order (quoted) runs barcode -> item_code -> qty -> uom -> rate -> warehouse with no course, no hold, no fire, no send-destination field. The Restaurant module that once held these ideas was deleted from core by erpnext/patches/v14_0/delete_hospitality_doctypes.py, which drops Module Def 'Restaurant' and the Custom Fields Sales Invoice.restaurant_table and Price List.restaurant_menu - so this is 'removed at v14', not 'never existed'. Positive control: \bPOS Profile\b returns 53 files / 125 lines in the same corpus, so the search would have found a POS-side feature if one existed. Scope: core erpnext v16.34.1 + frappe v16.33.0 only; frappe/hospitality (archived read-only) and Frappe Cloud marketplace apps (URY, POSNext, GETPOS) are outside this census and are not claimed against. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json · retrieved 2026-09-06 adversarially verified
Supports splitting a check by item, by seat, by even N-way, and by arbitrary dollar/percentage amount, and merging checks or tables back together, including after partial payment.
order-capture-split-merge
Searched split/merge/transfer in the vendor's vocabulary - 'POS Invoice Merge Log', 'Merge Invoices Based On', 'consolidated_invoice' - plus split/seat/share over the POS page source. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. The trap here is that ERPNext DOES ship a doctype with 'merge' in its name, so an unanchored search reads as a hit. Reading it: POS Invoice Merge Log merges SUBMITTED POS Invoices into one consolidated Sales Invoice at shift close, and its only grouping key is the quoted Select - Customer or Customer Group. It is an accounting consolidation, the inverse of splitting a check. Invariance: zero occurrences of split/merge/transfer as an order operation across the eight POS page scripts (erpnext/selling/page/point_of_sale/*.js); the only 'split' hits there are JavaScript String.split() on serial numbers and shortcut keys. POS Invoice does carry a `payments` child table (multiple Mode of Payment rows on one invoice), i.e. split TENDER; it carries no second invoice reference, no seat field and no share/percentage allocator, i.e. no split CHECK. Positive control: \bPOS Profile\b = 53 files, \bLoyalty Program\b = 22 files in the same corpus. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json · retrieved 2026-09-06 adversarially verified
Opens a bar tab against a card pre-authorization with a configurable auth amount, supports incremental re-auth as the tab grows, and auto-closes stale tabs at end of day. differentiator
order-capture-bar-tab-preauth
Searched the payment vocabulary: 'Mode of Payment', pre-auth/preauthoriz, card reader, pinpad, semi-integrated, EMV, tokenis/tokeniz. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: pre.?auth|preauthoriz returns two lines in the whole corpus, both OAuth (frappe/integrations/oauth2.py and a server_script.js comment) - zero payment pre-authorisation anywhere; \bcard reader\b|\bpin ?pad\b|semi.?integrat returns one line, inside a base64 email test fixture; tokeni[sz] returns eight files, all of them full-text search tokenisers and PDF utilities, none a card vault. The artefact that would have to carry a card tender type is Mode of Payment, and its `type` Select enumerates exactly Cash / Bank / General / Phone (quoted) - there is no Card type, no acquirer, no auth/capture split and no incremental-auth field, because ERPNext performs no card processing itself: a Mode of Payment is only a link to a GL Account. Positive control: \bRazorpay\b (7 files), \bStripe\b (5), \bPayPal\b (12) all fire - the gateways ERPNext does ship are online invoice-payment redirects via Payment Request, not card-present terminals. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json · retrieved 2026-09-06 adversarially verified
An open check can be transferred between servers, tables, and devices, and the transfer is recorded in an audit log naming both employees.
order-capture-transfer-audit
Searched the ownership vocabulary an open-check transfer needs: server/employee assignment, table, 'restaurant_table', transfer, handover, and Frappe's own audit primitive 'Version'. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the POS Invoice header field_order (185 fields; its opening run quoted) has no server, no employee, no table and no assigned-user field - the only actor recorded is the framework's `owner`. \bhandheld\b|\btableside\b returns zero files in either repository; there is no transfer action in any of the eight point_of_sale/*.js scripts. The table concept existed and was removed: erpnext/patches/v14_0/delete_hospitality_doctypes.py deletes the Custom Field Sales Invoice.restaurant_table at v14. Frappe's Version doctype would log a change of `owner` on a draft POS Invoice, but that is generic document versioning, not a transfer workflow naming both employees, and nothing in the POS UI invokes it. Positive control: \bPOS Profile\b = 53 files; POS Profile itself ships `applicable_for_users` (a POS Profile User child table), proving the corpus does surface POS-side user assignment where it exists - it exists for till access, not for check ownership. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Ships a first-party handheld ordering app running natively on the handheld device (not a remote/mirrored desktop session) that can send to kitchen and take a card payment tableside.
order-capture-native-handheld
Searched for a shipped mobile client in the vendor's terms and the platform's: Page/desk page, android, ios, App Store, Play Store, Capacitor, Cordova, React Native, Flutter, PWA, service worker, manifest.json, handheld, tableside. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: progressive web app|\bPWA\b|manifest.json|service.?worker returns ZERO files across both repositories; \bhandheld\b|\btableside\b returns ZERO files; the native-framework pattern returns 11 files, every one noise (Font Awesome CSS, fingerprintjs, Leaflet, jSignature, and four apple-mobile-web-app meta tags in frappe/www/desk.html, which only ask iOS Safari to hide its chrome). The artefact itself: the POS is registered as a Frappe `Page` (quoted) - a desk route rendered by point_of_sale.js in the same browser bundle as the rest of the desk. There is no separate mobile package, no offline service worker and, per Mode of Payment's Cash/Bank/General/Phone type list, no card-payment path to run tableside. Positive control: \bPOS Profile\b = 53 files and the eight point_of_sale/*.js scripts are all present in the corpus, so a shipped client would have been visible. Scope: core erpnext v16.34.1 + frappe v16.33.0; marketplace handheld apps on Frappe Cloud are outside this census. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.json · retrieved 2026-09-06 adversarially verified
With the internet down, terminals and handhelds can still create orders, apply modifiers, send to kitchen, and tender cash, and the vendor publishes what does and does not work offline.
order-capture-offline-order-entry
Offline order entry was never shipped. frappe/erpnext#29068 "POS offline mode", opened 2021-12-29 and labelled feature-request and inactive, is CLOSED without implementation; it proposed an Application Cache plus a WebSQL local store for master data and pending receipts. The browser-based offline POS was removed after v12 and nothing replaced it in core; the offline products in circulation (POS Awesome, POSNext, GPOS) are third-party apps. Corrected on verification: the issue is closed, not open, as this record and four sibling cells previously stated. https://github.com/frappe/erpnext/issues/29068 · retrieved 2026-08-02 adversarially verified
Guest QR at-table ordering writes items onto the same open check as server-entered items, rather than creating a separate order ticket. differentiator
order-capture-qr-same-check
POS Invoice was read field by field: no open-check or table state and no ordering-channel origin field, so there is no persistent check for a scanned QR order to join. Guest and table ordering existed only in frappe/hospitality, archived read-only 2023-10-04. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Offers a first-party self-order kiosk that renders the same menu and modifier tree as the POS with no separate menu build, and the vendor documents ADA/accessibility conformance for it. differentiator
order-capture-kiosk-first-party
Searched \bkiosk\b, self-order, unattended, guest/anonymous access to the POS page, and ADA/WCAG/accessibility conformance. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \bkiosk\b returns ZERO files across both repositories - not a noisy zero, an absolute one. The artefact that would have to be opened to a guest is the Point of Sale Page record, and its access control (quoted) restricts it to the Retail domain and to four staff roles (Accounts User, Accounts Manager, Sales User, Sales Manager); a Frappe Page with a non-empty `roles` list is unreachable without an authenticated User holding one of them, so the POS cannot render as a guest-facing kiosk. No ADA/WCAG conformance statement exists for it anywhere in the 1,863-page docs census either. Positive control: \bPOS Profile\b = 53 files, and frappe DOES ship guest-facing surfaces (Web Form, Portal Settings) that the same search finds - so guest access would have been detectable. Scope: core erpnext v16.34.1 + frappe v16.33.0; kiosk apps sold on the Frappe Cloud marketplace are outside this census. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.json · retrieved 2026-09-06 adversarially verified
Supports drive-thru-specific order flow: order-point/pay-window/pickup-window separation, order sequencing or tandem-lane assignment, and pull-forward or parking-spot assignment.
order-capture-drive-thru
POS Profile is the complete POS configuration doctype and its full field list was read (payment methods, item groups, customer groups, print settings, price list, write-off, taxes, item-selector flags). It enumerates no drive-thru order point, lane or vehicle-queue setting. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Captures and reports drive-thru speed-of-service timers by segment (order, total, window) tied to individual orders.
order-capture-drive-thru-timers
POS Invoice records only document creation, modification and posting timestamps. There are no lane-stage events (arrive, order, pay, present), so no drive-thru interval can be measured. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Vendor ships a first-party AI voice ordering agent for phone and/or drive-thru that injects orders directly as POS orders, or publishes a documented API partner program for third-party voice AI. differentiator
order-capture-voice-ai
Searched voice order|voice ai|conversational, plus the vendor's actual telephony vocabulary: Telephony module, Call Log, Telephony Call Type, Incoming Call Settings, Voice Call Settings, Twilio, Exotel. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: voice order|voice ai|conversational returns ZERO files across both repositories. What DOES exist is an erpnext Telephony module whose entire doctype list is call_log, incoming_call_handling_schedule, incoming_call_settings, telephony_call_type, voice_call_settings - screen-pop plumbing that links an inbound call to a Contact and writes nothing into a cart. Correction worth recording: the shipped telephony PROVIDERS have been removed from both repos - Twilio left frappe at v13 (frappe/patches/v13_0/remove_twilio_settings.py deletes Twilio Settings and Twilio Number Group) and Exotel left erpnext at v15 (the quoted patch deletes Exotel Settings and tells operators to install github.com/frappe/exotel_integration). So at v16 there is not even a first-party call provider, let alone a voice agent or a documented voice-AI partner programme. Positive control: \bExotel\b = 3 files and \bTwilio\b = 1 file, so the search finds telephony strings where they survive. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/remove_exotel_integration.py · retrieved 2026-09-06 adversarially verified
Supports order throttling: per-channel capacity limits per time slot with automatic quote-time extension when kitchen load exceeds a configured threshold. differentiator
order-capture-throttling
POS Profile is the complete POS configuration doctype and its full field list was read; it contains no order-pacing, capacity or quoted-time setting, and core ships no first-party ordering channel to throttle. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Accepts future-dated/scheduled orders with a per-channel lead time and automatically injects them into the make queue at a computed fire time rather than on receipt.
order-capture-scheduled-orders
Searched the scheduling vocabulary: Sales Order delivery_date, Delivery Schedule Item, Item Lead Time, plus \bslot\b, time slot, throttle, pacing, fire time, make queue. Corpus: erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both. INVARIANCE: the field that would have to carry a fire time is Sales Order.delivery_date, and its fieldtype is Date, not Datetime (quoted) -- a promised time cannot be expressed to the hour. Delivery Schedule Item repeats the same Date. PRECISION, because the corpus does contain a Time field and it must not be misread: Sales Order also carries transaction_time, fieldtype Time, default 'Now' -- but it is gated by depends_on / mandatory_depends_on 'is_internal_customer', it stamps when the order was PLACED, and it is read by no scheduling, queueing or dispatch code. It is an intercompany-transfer timestamp, not a promise or a fire time. Item Lead Time exists but its fields are buffer_time / manufacturing_time_in_mins / purchase_time / capacity_per_day -- manufacturing capacity planning, not per-channel order lead time -- and no per-channel dimension exists anywhere. There is nothing to inject into either: \bkitchen\b resolves only to two chart-of-accounts templates, and the Restaurant module was deleted at v14 by erpnext/patches/v14_0/delete_hospitality_doctypes.py. POSITIVE CONTROL: \bDelivery Trip\b returns 20 files, so dispatch-bearing objects are visible to this search where they exist. Bound to core at these tags. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/doctype/sales_order/sales_order.json · retrieved 2026-09-06 adversarially verified
Provides a distinct catering order flow with quotes, deposits, balance-due tracking, and a delivery/event schedule separate from the standard order queue.
order-capture-catering
Not a catering flow, but the ERP primitives are exact: Quotation, Sales Order, advance Payment Entry for deposits, and native AR balance-due tracking. https://docs.frappe.io/erpnext/quotation · retrieved 2026-08-01
Pushes an order-ready signal back to third-party marketplaces (e.g. DoorDash) from POS or KDS state, rather than requiring a tablet tap. differentiator
order-capture-order-ready-signal
Searched for the marketplaces themselves in the vendor's namespace - doordash, ubereats, uber eats, grubhub, deliveroo, postmates - and for the module that would house such a connector. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the marketplace-name pattern returns ZERO files across both repositories. The artefact is erpnext's own module manifest (quoted excerpt): 21 modules, and the only one named for integrations is 'ERPNext Integrations', whose doctype directory at v16.34.1 contains exactly one entry - plaid_settings (bank-feed aggregation). There is no marketplace connector to push an order-ready event to, and no KDS state to derive one from (\bkitchen\b = two chart-of-accounts templates). Positive control: \bPlaid\b and \bDelivery Trip\b (20 files) both fire, so shipped integrations and dispatch objects are visible to this search. Scope: core erpnext v16.34.1 + frappe v16.33.0; marketplace connectors sold on the Frappe Cloud marketplace are outside this census and are not claimed against. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/modules.txt · retrieved 2026-09-06 adversarially verified
Voids, comps, and discounts require a reason code and can be gated behind role-based manager approval, with all instances recorded in an exception report.
order-capture-void-comp-controls
Shortfall: no reason codes and no shipped void or comp exception report. What exists is generic — Role Permission Manager gates cancel and amend, the allow_discount_change and allow_rate_change flags on POS Profile gate price overrides, and Frappe’s submit/cancel/amend model plus the Version log attribute every change to a named user. Regrade: first-party vendor documentation is grade B, not E. https://docs.frappe.io/erpnext/pos-profile · retrieved 2026-08-02
Menu, modifiers & pricing engine
Payments & money movement
The POS operates with third-party payment processors of the merchant's choosing (documented list of supported processors/gateways) rather than requiring the vendor's in-house processing. differentiator
payments-processor-choice
Shortfall: the documented gateway flow is an online payment link, not card-present POS acceptance. Zero processor lock-in is structural — Frappe sells no processing and takes no share of card volume. Payment Request states that "ERPNext can email the request with an online payment link when a Payment Gateway Account is configured", and the Stripe guide documents configuring "Publishable Key, Secret Key" under "Explore > Integrations > Stripe Settings", which creates a Payment Gateway Account linked to an account head in the chart of accounts. Neither page mentions a terminal, a reader or an acquirer connection at the till. Re-cited on verification from the pricing page, which is grade C and names no gateway at all. https://docs.frappe.io/erpnext/stripe-integration · retrieved 2026-08-02 adversarially verified
Vendor publishes card-processing pricing publicly (a specific flat rate or interchange-plus markup) rather than quote-only. differentiator
payments-published-rates
Not applicable — Frappe is not a payment processor, so there are no card rates to publish. https://frappe.io/erpnext/pricing · retrieved 2026-08-01
Native dual-pricing / cash-discount mode stores two prices per item and prints both cash and card totals on the guest check and receipt. differentiator
payments-dual-pricing
No cash-discount or card-surcharge field exists in POS Profile, and no card or BIN data enters ERPNext because the payments table is a Mode of Payment to GL account mapping, not an acquirer connection. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Surcharging engine automatically excludes debit and prepaid cards via BIN/product-code detection, enforces the network percentage cap, and can be enabled or disabled per location. differentiator
payments-surcharge-guardrails
Searched the vendor vocabulary for card surcharging: /\bsurcharge/i, /\bBIN\b/i, /\binterchange\b/i, /\bcard.?type\b/i over the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero hits for /\bsurcharge/i anywhere in erpnext v16.34.1 or frappe v16.33.0. /\bBIN\b/i returns 101 files and every one is the Stock module "Bin" doctype (stock_projected_qty, test_bin, production_plan) -- an inventory bin, not a Bank Identification Number: that is the trap on this cell. In the docs census /\bsurcharg/i returns 3 pages and all three are Indian tax-template vocabulary ("a tax, levy, or surcharge", "surcharge, cess, or levy" in types-in-tax-template and tax-on-another-tax-amount), not card surcharging. POSITIVE CONTROL: /\bMode of Payment\b/ returns 62 files and the whole Pricing Rule engine is present, so the search does reach the accounting and pricing surfaces where a surcharge rule would live. ARTEFACT: the complete field list of Sales Invoice Payment -- the child table that IS the tender row on every POS Invoice -- has nine fields, none of which carries a card product code, a BIN, a network percentage cap or a per-location surcharge toggle. No BIN-level card data can reach ERPNext because no card data reaches it at all. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json · retrieved 2026-09-06 adversarially verified
All first-party payment terminals accept EMV chip and NFC contactless including Apple Pay and Google Pay.
payments-emv-nfc
Two searches. (1) Code census for the acceptance vocabulary: /\bEMV\b/i, /\bNFC\b/i, /\bcontactless\b/i, /\bapple pay\b/i, /\bgoogle pay\b/i, /\bterminal\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for NFC, contactless, Apple Pay or Google Pay in either repository; /\bEMV\b/i survives on exactly one line, inside frappe/tests/data/email_with_image.txt (a base64 blob) -- the EMV substring trap; /\bterminal\b/i is 12 files of bench CLI shell vocabulary plus a Colombian chart-of-accounts account name. Zero hits for EMV/NFC/contactless across the docs census as well. (2) The claim is about FIRST-PARTY payment terminals, which is a claim about what Frappe sells, and the vendor answers that in its own Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) under Support Exclusions. POSITIVE CONTROL: the same SLA does enumerate what Frappe supplies and charges for -- hosting plans, a product warranty entitlement above the $50 Frappe Cloud plan, priority/phone support, L2 bug support -- so a terminal programme would be named there if one existed. Frappe ships no payment terminal, so no first-party terminal accepts EMV or NFC. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Accepts contactless payments directly on a phone (Tap to Pay on iPhone and/or Android tap-to-pay) with no separate card reader. differentiator
payments-softpos-tap-to-pay
The POS Profile payments table links Modes of Payment to accounts; there is no reader, terminal or tap-to-phone SDK to configure. Frappe sells no card acceptance at all. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Vendor ships a handheld that takes EMV/NFC payment at the table, including tip prompt and check splitting, without carrying the card away.
payments-pay-at-table
POS Invoice has no table or open-check state and no card-present path — it is submitted and settled at the till — so there is nothing for a guest to pay against at the table. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Guest can scan a QR code on the printed check or table tent to view and pay the check from their own phone, with the payment closing the check in the POS automatically. differentiator
payments-qr-guest-pay
CORRECTION -- the existing rationale is wrong in both directions. (1) It says ERPNext prints a UPI QR "in the India localization"; the India localisation was DELETED from core in v14 by erpnext/patches/v14_0/remove_india_localisation.py ("India-specific regional features have been moved to a separate app") and /\bupi\b/i in the v16 census survives only in bank_statement_import test fixtures. (2) It says nothing closes the check automatically, but it does. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. Searched the vendor vocabulary: request_for_payment, process_phone_payment, Payment Request, Mode of Payment type. INVARIANCE: POS Invoice exposes a request_for_payment action that saves the invoice, calls create_payment_request, and pushes a gateway payment request to the customer's own contact_mobile; Mode of Payment.type is a Select whose complete option set is "Cash / Bank / General / Phone"; and pos_payment.js subscribes to the realtime event process_phone_payment and calls this.events.submit_invoice() once the received amount covers the grand total -- i.e. the guest pays from their own phone and the check closes in the POS automatically. What is absent is the QR half: nothing renders a payment QR onto a POS receipt or table tent. Frappe's only QR generator (PyQRCode, frappe/www/qrcode.html) serves two-factor-authentication enrolment. POSITIVE CONTROL: /qr.?code/i does return 17 files across both repos, so a receipt QR would have surfaced. Pay-from-own-phone with automatic check closure: present. Scan-a-QR-on-the-check: absent. Partial. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.js · retrieved 2026-09-06 adversarially verified
Supports both pre-auth-then-tip-adjust and on-device tip prompt flows, with a documented batch/adjust window and a manager screen for unadjusted tips.
payments-tip-adjust
Searched the gratuity and auth/capture vocabulary: /\btip\b/i, /\bgratuity\b/i, /\bpre.auth\b/i, /\bauth.?code\b/i, /\bcapture\b/i, /\bbatch\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\btip\b/i anchored at word boundaries survives in 10 files across both repositories and every one is noise -- leaflet.css, a hint string in financial_report_template.js, GitHub workflow YAML; unanchored "tip" is 574 files of "multiple"/"description". Zero word-boundary hits for pre-auth or store-and-forward in either repo. ARTEFACT: Sales Invoice Payment, the child table carrying every tender line on a POS Invoice, has exactly nine fields (default, mode_of_payment, amount, reference_no, column_break_3, account, type, base_amount, clearance_date). No tip field, no adjusted amount, no authorisation code, no batch/settlement window -- so there is nothing to adjust after the fact and no unadjusted-tip queue to surface on a manager screen. POSITIVE CONTROL: the sibling POS money concept IS modelled on the parent doctype -- POS Invoice carries loyalty_points, loyalty_amount, redeem_loyalty_points and loyalty_program -- which proves a POS-specific money field would appear in these field lists if it existed. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json · retrieved 2026-09-06 adversarially verified
Configurable tip pooling and distribution rules (by hours worked, sales, role percentage, or points) that produce a per-employee tip allocation exportable to payroll. differentiator
payments-tip-pooling
POS Invoice enumerates no tip or gratuity field of any kind, so no tips are captured and nothing exists to pool, allocate or distribute. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Card payments can be captured while the internet is down via store-and-forward, with configurable per-transaction and cumulative offline limits. differentiator
payments-offline-store-and-forward
Offline POS is frappe/erpnext#29068, a feature request opened 2021-12-29, labelled feature-request and inactive and closed without implementation, rather than a shipped capability. ERPNext also performs no card authorization, so there is no offline card capture to store and forward. https://github.com/frappe/erpnext/issues/29068 · retrieved 2026-08-02
Vendor publicly documents who bears the loss when a stored offline transaction declines on reconnect, and surfaces a post-reconnect report of failed offline payments. differentiator
payments-offline-decline-liability
Two halves, and only one of them is a code question. (1) THE ANTECEDENT: the ERPNext POS cannot transact offline at all. erpnext.PointOfSale.Controller's constructor calls check_opening_entry(), a frappe.call round trip, before rendering anything, so with no server the POS never boots; zero word-boundary hits for service worker or store-and-forward in erpnext v16.34.1 (5,170 files) or frappe v16.33.0 (3,634 files), tree API truncated:false for both; the only 'offline' survivors touching POS are the v7/v9 changelogs for a mode that was removed. Nothing can be stored for later forwarding. (2) THE CLAIM ITSELF is about VENDOR PUBLICATION and is settled by the vendor's own agreements: the Service Level Agreement (last updated 18 June 2026) and the Frappe Cloud Service and Support Agreement (effective 1 April 2026), both retrieved 2026-09-06 at 200 from the twelve-page docs.frappe.io/legal space. Neither mentions offline transactions, declines on reconnect, loss allocation, or a post-reconnect failed-payment report. POSITIVE CONTROL: the same SLA does publish response and resolution commitments by issue priority and enumerates its Support Exclusions explicitly at 2.3, so a liability position would sit there if one were published. https://docs.frappe.io/legal/policies/service-level-agreement · retrieved 2026-09-06 adversarially verified
First-party gift cards with real-time balance tracking, redeemable across every location in the group and through the online-ordering channel.
payments-gift-cards
Searched /\bgift.card/i, /\bstored.value\b/i, /\bwallet\b/i over the code census and the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: "Gift Card" DOES exist in erpnext v16.34.1 -- but only as one of two literal values of Coupon Code.coupon_type (DF.Literal["Promotional", "Gift Card"]), where it generates a random 10-character hash, forces maximum_use = 1 in validate(), and links to a Pricing Rule. It is a single-use discount code, not a stored-value instrument: no balance field, no redemption ledger, and it is not a Mode of Payment (Mode of Payment.type is Cash/Bank/General/Phone). The vendor says so itself in the FAQ of its own Coupon Code documentation page, quoted here. POSITIVE CONTROL: the genuinely balance-tracking, cross-location money feature in this stack -- Loyalty Program with Loyalty Point Entry -- is present in 54 files and is wired into POS Invoice and pos_payment.js, which proves the corpus would show a gift-card balance object if one existed. No first-party gift-card product exists in core ERPNext. https://docs.frappe.io/erpnext/coupon-code · retrieved 2026-09-06 adversarially verified
House/on-account tabs with per-account credit limits, running balance, and periodic statement or invoice generation.
payments-house-accounts
Verified in part and it holds: the Customer doc covers per-company credit-limit rows evaluated against submitted exposure, and points to the Accounts Receivable report. Minor correction — 'periodic Statement of Accounts' is not on the cited page, so trim that specific to avoid an unsupported detail inside an otherwise sound yes. https://docs.frappe.io/erpnext/customer · retrieved 2026-08-01 adversarially verified
A single check can be settled with multiple tenders and split by seat, by item, by even shares, or by arbitrary amount, with no hard cap below eight ways.
payments-split-tender
POS Profile defines multiple Modes of Payment and one invoice can be settled across several of them with no low cap. No splitting by seat, item, or even shares. https://docs.frappe.io/erpnext/pos-profile · retrieved 2026-08-01
Voids, refunds, discounts, and no-sales require role-based authorization (manager PIN or approval) and write to an immutable audit log identifying the approver.
payments-refund-void-controls
Frappe's submit/cancel/amend model makes submitted documents immutable and the Version log attributes every change to a user with a timestamp; Role Permission Manager gates cancel and amend rights. No manager-PIN-at-terminal approval prompt and no approver field. https://docs.frappe.io/erpnext/pos-profile · retrieved 2026-08-01
In-product dispute/chargeback dashboard that lists open disputes and allows evidence submission assembled from the POS transaction record. differentiator
payments-chargeback-tooling
Searched the dispute vocabulary: /\bchargeback\b/i, /\bdispute\b/i, /\brepresentment\b/i, /\bretrieval request\b/i over the code census, and /\bchargeback\b/i over the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for chargeback, representment or retrieval request in erpnext v16.34.1 or frappe v16.33.0; /\bdispute\b/i survives on exactly one line, in test_journal_entry.py, as an ordinary English word in a test comment. Zero chargeback hits across the docs census. ARTEFACT: Sales Invoice Payment is the complete tender record for a POS sale -- a Mode of Payment link, an amount, a GL account, a Read Only type fetched from Mode of Payment, a clearance date and a free-text reference_no. There is no acquirer reference, no card network, no processor transaction identifier a dispute could be raised against, and therefore no object a dispute dashboard could be built over. POSITIVE CONTROL: /\bPayment Gateway\b/ does return 14 files (Payment Gateway Account, Payment Request), so ERPNext's payment-adjacent surface IS in the corpus -- and that surface stops at handing off to a gateway. Disputes belong to whichever processor the operator contracts separately. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json · retrieved 2026-09-06 adversarially verified
Tokenized card-on-file for a guest profile, reusable across online ordering, phone orders, and in-store, with no PAN stored by the merchant. differentiator
payments-card-on-file
Searched for a vault in the vendor's and the industry's words: /\btokeniz/i, /\bcard.on.file\b/i, /\bPAN\b/i, /\bvault\b/i, /\bsaved card\b/i over the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero hits for card-on-file, vault or saved card; /\btokeniz/i survives in 7 files and every one is TEXT tokenisation -- frappe/search/sqlite_search.py (FTS tokenizer), the gettext javascript extractor, jquery.min.js -- not payment tokenisation. ARTEFACT: Sales Invoice Payment carries nine fields and the only free-text one is reference_no; there is no token, no card fingerprint, no expiry, and no customer payment-method child table on Customer or Contact anywhere in the tree. The gateway path that does exist (Payment Request -> Payment Gateway Account -> controller.request_for_payment) hands the payer to the gateway's own hosted flow and receives back a status, so any tokenisation lives inside the processor and is not reusable across ERPNext channels. POSITIVE CONTROL: /\bPayment Gateway\b/ = 14 files and /payment_gateway/ = 11 files, so the gateway surface is present and searchable; it contains no vault. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json · retrieved 2026-09-06 adversarially verified
Vendor publishes its deposit schedule and offers a next-day or same-day/instant funding option. differentiator
payments-payout-timing
The claim is about what the VENDOR PUBLISHES, so it is settled by the vendor's published commercial terms, not by a doctype. Frappe's two published agreements -- the Frappe Cloud Service and Support Agreement (effective 1 April 2026) and the Enterprise Support Agreement (effective 1 January 2026), both in the twelve-page docs.frappe.io/legal space, all twelve fetched 2026-09-06 at 200 -- describe hosting subscriptions, plan tiers, a product warranty gated at the $50 Frappe Cloud plan, and support turnaround tables. Neither mentions merchant settlement, a deposit schedule, a payout, or a funding option, because Frappe is not an acquirer and money never passes through it. CORROBORATION from the code census (erpnext v16.34.1, 5,170 files + frappe v16.33.0, 3,634 files, GitHub tree API truncated:false): zero word-boundary hits for payout, deposit schedule, next-day funding or instant funding; Mode of Payment, the doctype defining every tender ERPNext knows, types each tender Cash / Bank / General / Phone and maps it to a GL Account -- an accounting classification, not a funding relationship. POSITIVE CONTROL: the same legal corpus does state turnarounds and fee terms where Frappe takes on an obligation (the SLA's response/resolution tables, Enterprise 9.4 price-change terms), so a deposit schedule would appear there if one existed. Docs bound: the full 1,863-page docs.frappe.io census (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12), not the 1,544-page erpnext+framework subset. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
Vendor provides point-to-point encryption and a current PCI DSS 4.x Attestation of Compliance / P2PE listing available to merchants on request.
payments-p2pe-pci4
Searched the attestation vocabulary: /\bPCI\b/i, /\bP2PE\b/i, /\bAoC\b/i, /\bSAQ\b/i, /\bPTS\b/i over the code census and over the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for PCI, P2PE, AoC, SAQ or PTS in erpnext v16.34.1, in frappe v16.33.0, or on any of the 1,863 docs pages. An absence is not an attestation, so I went to the place an attestation WOULD be published: Frappe's own certifications page (quoted here) and the "Compliance & Certifications" section of the Frappe Cloud security FAQ (docs.frappe.io/cloud/faq/architecture-and-security, fetched today: "Yes, we are certified under ISO 9001:2015, ISO 27001:2022, and SOC-2 Type-2 standards."). Both are CLOSED ENUMERATIONS of the vendor's compliance posture and both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2 -- no PCI DSS of any version and no validated P2PE listing. POSITIVE CONTROL: the same page publishes real, dated attestations with a certifying body (ISOQAR recertification Dec 2024, ISMS upgraded to ISO 27001:2022, surveillance audit Dec 2025, SOC-2 Type-2 achieved 2025), so it is a page that reports attestations when they exist. Frappe provides no P2PE and publishes no PCI DSS 4.x AoC. https://frappe.io/quality-and-information-security · retrieved 2026-09-06 adversarially verified
Delivery, dispatch & third-party channels
Product includes a native in-house driver module: drivers are first-class entities with clock-in/out, assignment state (in-store / on-run / returning), and per-driver run history reportable from the POS itself (not via a third-party add-on).
delivery-driver-roster
Searched the vendor's words: 'Driver', 'Vehicle', 'Delivery Trip', clock-in, dispatch state. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial, and pins the exact shortfall. First-class entities: Driver is its own doctype (naming series HR-DRI-, linked to Employee, Vehicle and Address) and Delivery Trip is a submittable document with a driver link and a status, so per-driver run history is reportable straight out of the Delivery Trip list. The claimed dispatch state machine is absent and the quoted field is why: Driver's only status enum is Active / Suspended / Left -- an employment state, not in-store / on-run / returning. Clock-in is absent from the POS specifically: 'address' and 'clock' both return zero hits across all nine files of erpnext/selling/page/point_of_sale/, and I checked my own control -- 'shift' does return three hits and every one is a keyboard modifier (Shift+Ctrl+C, shift+ctrl+backspace, oEvent.shiftKey), a reader trap, not a work shift. Positive control: 'customer' returns 121 hits in pos_item_cart.js alone. Attendance lives in Frappe HR, a separate app outside this census. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/driver/driver.json · retrieved 2026-09-06 adversarially verified
Provides a dedicated dispatch/expo screen showing undispatched orders, driver availability, and elapsed time per order, with multi-order run batching (assigning 2+ orders to one driver as a single run).
delivery-dispatch-board
Searched the vendor's words: 'Delivery Trip', 'Delivery Stop', 'Driver', dispatch board, expo screen, driver availability, elapsed time. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'dispatch board', 'expo screen', word-anchored 'expo', 'driver availability'. Delivery Trip IS a real document -- it batches 2+ stops onto one driver, so the multi-order run in the claim genuinely exists -- but its only progress signal is a five-value read-only Select, and Driver's own status enum is Active/Suspended/Left, so nothing in the model expresses undispatched-vs-assigned, driver availability, or an elapsed timer. Positive control: 'Delivery Trip' 21 files, 'optimize_route' 2 files -- the search finds the feature that is there. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.json · retrieved 2026-09-06 adversarially verified
Dispatch includes a live map view with geocoded stops and system-generated route sequencing (turn order optimization) for a multi-stop run, not just a static address list. differentiator
delivery-route-map
Verified and can be upgraded from inferred to documented: 'Using Google Maps, the best route for the deliveries will be calculated' and Delivery Trip will 'calculate the estimated arrival time for the deliveries. This data is fetched from Google Maps.' One correction — the doc does not state that the operator must supply a Google Maps API key, so drop that as an asserted fact even though it is likely true. https://docs.frappe.io/erpnext/delivery-trip · retrieved 2026-08-01 adversarially verified
Captures live driver GPS position from a driver-facing mobile app and surfaces it back to the dispatch screen. differentiator
delivery-driver-tracking
Searched: 'Driver', GPS, current_location, live location, watchPosition, navigator.geolocation, driver location. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: the Driver doctype's field list carries identity, licence and contact only -- no position, no last-seen, no heartbeat -- and Delivery Stop's lat/lng are hidden Google-Maps geocodes of the STOP address, not the driver. Word-anchored 'GPS' returns two hits, both the name of a sponsor company (Startrack GPS, Guatemala) in sponsors.md and a v6 changelog -- a name trap, not a feature. 'current_location' returns nine hits, all in asset_movement.py (fixed asset locations). navigator.geolocation appears twice: leaflet's bundled library and a one-shot getCurrentPosition that centres the generic Geolocation map field; watchPosition appears once, inside leaflet. Positive control: 'Delivery Trip' 21 files and Driver resolves to a real doctype. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/driver/driver.json · retrieved 2026-09-06 adversarially verified
Delivery areas can be defined as arbitrary map polygons or by drive-time isochrones, not solely as a radius or a ZIP/postcode list. differentiator
delivery-zones-polygon
Searched the vendor's words: 'Territory', 'delivery zone', polygon, isochrone, geofence. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'delivery zone', 'delivery_zone', isochrone, geofence in either repository and zero non-base64 lines for any of them across the 1,863-page docs census. Territory -- the only area concept ERPNext has -- is a nested-set label (lft/rgt/parent_territory) carrying no geometry at all. Adversarial check that survived: 'polygon' DOES hit 9 files, and frappe ships a Geolocation fieldtype backed by leaflet-draw that stores drawn GeoJSON polygons; but no delivery-facing doctype uses it, and the only ERPNext consumer is assets/doctype/location (land area). The primitive exists and the delivery zone does not. Positive control: Territory resolves to a real doctype used by Pricing Rule and Loyalty Program. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/territory/territory.json · retrieved 2026-09-06 adversarially verified
Each delivery zone carries its own independently configurable delivery fee, order minimum, and quoted promise time, applied automatically from the validated customer address.
delivery-zone-pricing
Searched: 'Territory', 'Pricing Rule', 'delivery fee', 'delivery_charge', 'order minimum', 'promise time'. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'delivery fee', 'delivery_charge', 'order minimum', 'promise time' in either repository. Pricing Rule can indeed vary a charge by Territory (applicable_for includes Territory), so the fee half is half-buildable -- but the Territory record that would carry the fee, the minimum and the promise time holds none of the three, and nothing derives a Territory from an address. The POS screen compounds this: its Contact Details panel exposes exactly email_id, mobile_no, loyalty_program and loyalty_points, so a delivery address is never captured at the till to derive a zone from. Positive control: Pricing Rule's applicable_for enum is present and does list Territory. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/territory/territory.json · retrieved 2026-09-06 adversarially verified
Address entry is validated/geocoded against a mapping service at order time and rejects or flags out-of-zone addresses before the order is accepted.
delivery-address-validation
CORRECTION -- the uncited `no` is too strong. Searched: 'Address', geocode, autocomplete, 'Geolocation Settings'. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What is there: frappe v16.33.0 ships a Geolocation Settings single doctype with enable_address_autocompletion and a provider enum of Geoapify / Nomatim / HERE; providers/geoapify.py calls https://api.geoapify.com/v1/geocode/autocomplete and returns normalised address_line1/city/state/pincode/country into a 'New Address' dialog. So address entry CAN be geocoded against a mapping service. What is not there: it is off by default (enable_address_autocompletion default 0); it fires only from the desk Contact & Address sidebar (address_and_contact.js gated on frappe.boot.enable_address_autocompletion), never from the POS -- 'address' returns zero hits across all nine files of erpnext/selling/page/point_of_sale/ while 'customer' returns 121 in pos_item_cart.js alone, which is the positive control; the returned payload discards lat/lng; and with zero 'delivery zone' anywhere there is nothing out-of-zone to reject against. Half the claim is met, the operative gate is absent. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/integrations/doctype/geolocation_settings/geolocation_settings.json · retrieved 2026-09-06 adversarially verified
Tracks per-delivery driver compensation inputs — mileage or distance driven per run, per-delivery flat reimbursement, and driver-retained tips — and exports them to payroll as separate reimbursement vs. wage lines. differentiator
delivery-driver-comp
The Delivery Trip manual covers driver, vehicle, departure time, multiple customer stops, Google Maps estimated arrival and route optimisation. It documents no per-delivery pay, no mileage reimbursement and no driver tip allocation; driver compensation would be a Frappe HR payroll build. https://docs.frappe.io/erpnext/delivery-trip · retrieved 2026-08-02
Provides a driver cash bank / settle-up flow that reconciles cash collected, orders assigned, and tips owed at end of shift, producing a per-driver over/short figure.
delivery-cash-reconcile
Searched the vendor's words: 'POS Closing Entry', 'POS Opening Entry', 'Payment Reconciliation', driver bank, driver cash, driver pay, tip-out. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'driver bank', 'driver cash', 'driver pay' or 'tip.?out' in either repository. POS Closing Entry is the only settle-up document in the product and its accountable-party field is literally labelled Cashier and linked to User -- there is no Driver link anywhere on it, no cash-collected-per-driver line, and Delivery Trip carries no money field beyond a read-only grand_total copied onto each stop. Positive control: POS Closing Entry and its payment_reconciliation child table are present and found by the same search. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json · retrieved 2026-09-06 adversarially verified
Can hand a first-party order to an on-demand courier marketplace (DoorDash Drive, Uber Direct, Nash, Relay or equivalent) natively from the POS, with the courier quote and status returning into the order record.
delivery-daas-dispatch
Delivery Trip dispatches the operator’s own Driver and Vehicle records only. No DoorDash Drive, Uber Direct, Nash or other third-party courier hand-off appears anywhere in the documented flow. https://docs.frappe.io/erpnext/delivery-trip · retrieved 2026-08-02
Supports hybrid dispatch: rules that automatically overflow an order to a DaaS courier when no in-house driver is available, out of zone, or past a wait threshold. differentiator
delivery-daas-fallback
No third-party courier network is integrated at all — Delivery Trip is own-driver only — so there is no automatic fallback when in-house drivers are unavailable. https://docs.frappe.io/erpnext/delivery-trip · retrieved 2026-08-02
Offers direct, first-party certified API integrations with DoorDash, Uber Eats, and Grubhub marketplaces (vendor-owned, not solely resold through Otter/Deliverect/Chowly/ItsaCheckmate middleware). differentiator
delivery-3p-direct-integration
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The vendor's own integrations index does not name a food-delivery marketplace either: its 'Ready-Made Marketplace Options' list is Ecommerce Integrations, WooCommerce Connector, ERPNext Shipping and Frappe Paystack, and its advice for anything else is to build a custom connector against the REST API. Shipped integration surface, enumerated: frappe/integrations/doctype/ holds connected_app, geolocation_settings, google_calendar, google_contacts, google_settings, integration_request, ldap_*, oauth_*, push_notification_settings, slack_webhook_url, social_login_key, token_cache and webhook*; erpnext/erpnext_integrations/doctype/ holds plaid_settings alone. Core absence is not product absence -- the Frappe Cloud marketplace was not censused. https://docs.frappe.io/erpnext/e-commerce-integrations-for-erpnext · retrieved 2026-09-06 adversarially verified
Third-party marketplace orders inject automatically into the POS as normal tickets that fire to KDS/printers without tablet re-keying or manual accept.
delivery-3p-injection
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The record a marketplace ticket would land in is POS Invoice, and its field list carries no channel, no marketplace, no external order id and no accept/reject state; the vendor's integration guide confirms the intended route is the generic REST API plus a hand-added custom field, naming marketplace_order_id on Sales Order as an EXAMPLE of a field the operator must add themselves. So an integrator can build injection; nothing ships that does it. Positive control: the same docs census finds 'Loyalty Program' on 6 pages and 'Point of Sale' on 7. https://docs.frappe.io/erpnext/integrating-erpnext-with-other-applications · retrieved 2026-09-06 adversarially verified
Marking an item or modifier 86'd in the POS pushes item-level out-of-stock status to connected third-party channels in near real time, and restores it on availability (DoorDash requires item and item-option 86ing of new POS partners).
delivery-86-sync
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Controls over the 86-ing vocabulary in the vendor's own words: ERPNext expresses availability as Warehouse stock balance plus POS Profile's hide_unavailable_items flag -- there is no item-level or item-option-level out-of-stock state that can be pushed anywhere, and with zero marketplace names in either repository there is no channel to push it to. The vendor's own page frames inventory sync as connector work. Positive control: hide_unavailable_items is present in the POS Profile field list, so the availability concept itself is found by the search. https://docs.frappe.io/erpnext/e-commerce-integrations-for-erpnext · retrieved 2026-09-06 adversarially verified
Store can be paused/deactivated on each connected third-party marketplace from inside the POS with a timed auto-reactivation, rather than only from each marketplace's own tablet or portal.
delivery-store-pause
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The nearest shipped concept is POS Profile's disabled checkbox, which switches a till profile off outright -- no duration, no reason code, no auto-reactivation, and no channel to send it to. Zero hits for 'store pause', and zero for any marketplace name, in either repository. Positive control: the POS Profile field_order is found in full by the same search, so a pause field would have been seen if present. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-09-06 adversarially verified
Produces a third-party reconciliation report matching marketplace payout deposits to POS-recorded 3P sales, itemizing commission, marketing fees, refunds/adjustments, and identifying missing or unpaid orders. differentiator
delivery-3p-reconciliation
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Additional controls over the reconciliation vocabulary: zero hits for a commission or payout ledger tied to a channel; POS Invoice's own totals block carries taxes, discounts, loyalty and change amounts but no commission, marketing-fee or payout field, and no doctype anywhere represents an expected-versus-deposited marketplace settlement. A 3P payout would land as an ordinary Payment Entry or Journal Entry with no order-level match. Positive control: 'Payment Reconciliation' and 'Bank Reconciliation' both resolve to real ERPNext doctypes in the same search -- the reconciliation vocabulary is present, just never marketplace-aware; the quoted line is the one third-party-ish Link POS Invoice does carry, a coupon, which is the nearest thing to a channel field and is not one. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Vendor exposes integration health to the operator — failed/rejected order injections, connection status per channel, and alerts on failure — rather than failing silently. differentiator
delivery-injection-error-visibility
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The health-reporting primitives genuinely exist and the search finds them -- frappe ships Error Log, Integration Request, Webhook Request Log and Notification -- which is the positive control. What is absent is the subject: with zero marketplace names in either repository there is no per-channel connection status, no failed-injection queue and no channel alert, because there is no channel. This is a negative about the object of the reporting, not about the reporting machinery. The quoted field is POS Invoice's only status enum, which tracks accounting state (Draft/Return/Paid/Consolidated) and carries no injection or delivery-channel outcome. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Guests receive a branded order status / driver tracking page or SMS link on the restaurant's own domain for first-party delivery orders, driven by real order and driver state.
delivery-tracking-page
CORRECTION to an `unknown` that rested on 'an unverified notification feature' -- the notification feature is now verified, and it is not a tracking page. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. What exists, read line by line: delivery_trip.py's whitelisted notify_customers() loops the delivery_stops, looks up each stop's Contact, renders the Email Template named in Delivery Settings.dispatch_template against a context that really does include the Driver's cell_number and the stop's estimated_arrival, sends it with the Delivery Note print format attached, then stamps stop.email_sent_to and delivery_trip.email_notification_sent. So a guest dispatch email driven by real order and driver state does ship. What the claim asks for and is absent: it is email only -- there is no SMS path (SMS Settings is never referenced from the Delivery Trip module); it is a one-shot manual button, not a live page; there is no route, no web page and no portal template anywhere for order or driver status, on the restaurant's domain or any other. Positive control: the same search finds Delivery Settings' dispatch_template and send_with_attachment fields, so a tracking-page setting would have been found beside them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.py · retrieved 2026-09-06 adversarially verified
Quoted delivery promise times adjust dynamically from current kitchen load, driver availability, and zone drive time, rather than a fixed per-store constant. differentiator
delivery-promise-time
Searched the vendor's words: 'Delivery Trip', 'Calculate Estimated Arrival Times', 'Google Maps', 'promise time', kitchen load. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'promise time' in either repository, and word-anchored 'kitchen' resolves to exactly two files, both chart-of-accounts templates carrying a GL account named Kitchen (Singapore F&B and UAE) -- there is no kitchen-load concept to feed an ETA. Delivery Trip's ETA button is documented in the doctype itself as a Google Maps Direction API call, and delivery_trip.py's get_directions/process_route pass only the stop addresses and a departure_time; no driver-availability or queue-depth term enters the calculation. Positive control: 'Google Maps' 3 files, all in the Delivery Trip implementation -- the ETA feature that IS there is found. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.json · retrieved 2026-09-06 adversarially verified
Vendor documents explicit offline behavior for delivery: whether cash delivery orders, driver assignment, and driver settlement continue during an internet outage.
delivery-offline-behavior
The claim is about vendor DOCUMENTATION, so the docs census is the instrument. Bound: the full 1,863-page docs.frappe.io census (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) at the 2026-09-06 sitemap. Word-anchored 'offline' returns 14 pages across the whole census and not one is a POS or delivery offline-behaviour statement -- they are payment-request offline bank-transfer instructions, the GSTR-1 offline tool, Google OAuth access_type=offline, site_config, and a bench update-schedule note. The ERPNext Point of Sale page cited here is where such behaviour would be stated, and it describes real-time stock integration, deferred posting at session close, payment methods and loyalty, saying nothing about operating without connectivity. That silence matches the code: POS Settings at v16 holds four fields (invoice_fields, pos_search_fields, invoice_type, post_change_gl_entries) with no offline toggle, the v9 changelog's 'enable or disable Offline POS mode from POS Settings' describes a removed feature, and pos_controller.js round-trips to the server before rendering. With no offline mode there is no cash-delivery, driver-assignment or driver-settlement offline behaviour to document. Corpus: erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), tree API truncated:false. https://docs.frappe.io/erpnext/point-of-sale · retrieved 2026-09-06 adversarially verified
Digital ordering & guest-facing channels
Vendor ships a first-party, commission-free web ordering site on the restaurant's own branding/domain that writes orders directly into the POS with no per-order marketplace commission.
digital-first-party-web
Regrading a grade-F partial, not changing its value. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The census makes the shape exact. Real: frappe/webshop is a first-party GPLv3 storefront on the operator's own Frappe site and domain, taking no commission; its cart is a Quotation that becomes a Sales Order, and checkout is the quoted `enable_checkout` switch plus one payment_gateway_account raising a Payment Request. Not real, and why this stays partial: the 230-blob census contains ZERO paths matching pickup, curbside, delivery, schedul or slot; no modifier layer exists in either repo (\bmodifier\b = one accounting-role hit); place_order.html offers only Place Order or Request for Quote; and there is no prep timing. Two further facts the record should carry: (1) e-commerce is no longer in ERPNext core at all - erpnext/patches/v15_0/delete_ecommerce_doctypes.py removed it at v15, so any statement about 'ERPNext's webshop' is a statement about a separate app; (2) frappe/webshop carries ZERO git tags - it has never cut a release, and its only branches are develop plus version-15 backports (HEAD 1a5239d, 2026-06-05). Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Positive control: \bwebshop\b|website_item|e_commerce_settings = 7 files in erpnext. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/webshop_settings/webshop_settings.json · retrieved 2026-09-06 adversarially verified
Vendor offers a branded native iOS and Android ordering app (published under the restaurant's own brand in the App Store/Play Store), not only a mobile web page or a shared multi-restaurant marketplace app. differentiator
digital-native-app
Searched for a branded consumer app: android, ios, App Store, Play Store, Capacitor, Cordova, React Native, Flutter, PWA, service worker, manifest.json. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: progressive web app|\bPWA\b|manifest.json|service.?worker returns ZERO files across both repositories, and the native-framework pattern returns 11 files that are all noise (Font Awesome, fingerprintjs, Leaflet, jSignature, apple-mobile-web-app meta tags in frappe/www/desk.html). More decisively, core ships no consumer ordering surface at all to wrap: the quoted patch, erpnext/patches/v15_0/delete_ecommerce_doctypes.py, DELETES E Commerce Settings, Website Item, Recommended Items, Item Review, Wishlist and Website Offer from ERPNext at v15 and redirects operators to github.com/frappe/webshop. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. That census contains no mobile packaging of any kind (zero Capacitor/Cordova/native manifests); webshop is server-rendered Jinja under frappe/website. Positive control: \bPOS Profile\b = 53 files; the eight point_of_sale/*.js scripts are present, so shipped clients are visible to this search. Scope: core erpnext v16.34.1 + frappe v16.33.0 plus the frappe/webshop census; marketplace apps on Frappe Cloud are outside it. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/delete_ecommerce_doctypes.py · retrieved 2026-09-06 adversarially verified
Guests can create an account with saved addresses, saved (tokenized) payment methods, and one-tap reorder of a previous order across first-party channels.
digital-account-saved-payment
The only first-party guest ordering channel is frappe/webshop (e-commerce was removed from erpnext core at v15 by erpnext/patches/v15_0/delete_ecommerce_doctypes.py), so the negative has to be grounded there and not only in core. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Searched tokenis/tokeniz, card, vault, saved payment, reorder/re-order across all three. Invariance: `token` and `reorder` each match ZERO paths in the 230-blob webshop census; tokeni[sz] across erpnext+frappe returns eight files, all full-text-search tokenisers and PDF utilities. The artefact is Webshop Settings, whose ENTIRE checkout surface is quoted: enable_checkout, show_price_in_quotation, save_quotations_as_draft, payment_gateway_account, payment_success_url - a single Payment Gateway Account, consumed by webshop/webshop/shopping_cart/cart.py to raise a Payment Request redirect per order. A hosted redirect per order is the opposite of a stored token; there is no saved-card doctype, no customer payment profile and no one-tap reorder anywhere. Saved ADDRESSES do exist (webshop/templates/includes/cart/address_picker_card.html), which is why the cell is not simply empty. Positive control: \bRazorpay\b (7 files), \bStripe\b (5), \bPayPal\b (12) all fire in erpnext, so payment machinery is visible where it exists. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/webshop_settings/webshop_settings.json · retrieved 2026-09-06 adversarially verified
Digital checkout presents configurable or algorithmic upsell/cross-sell suggestions (rules-based add-ons or personalized recommendations from order history), with attach-rate reporting on those suggestions. differentiator
digital-upsell-engine
CORRECTION - the standing rationale asserts 'frappe/webshop renders the Item master and Price List with no recommendation or add-on prompt layer'. That sentence is false. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The census shows a `recommended_items` doctype (quoted field list), a `recommended_items` field on Website Item, and an `enable_recommendations` switch in Webshop Settings; erpnext/patches/v15_0/delete_ecommerce_doctypes.py names 'Recommended Items' among the doctypes it moved out of core at v15, which is why a core-only search misses it. So a configurable cross-sell layer DOES ship on the first-party web channel. What is still absent, and why this is partial and not yes: (a) placement - Recommended Items is a curated child table rendered on the Website Item page (templates/generators/item/*), not in the cart or at checkout; the cart templates (place_order.html, cart_items.html, cart_payment_summary.html) contain no suggestion block; (b) it is manually curated per item, with no order-history personalisation and no rules engine; (c) attach-rate reporting does not exist - the webshop census contains ZERO files under any `report` path. On the POS side Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. POS Profile's item-selector surface is fully enumerated as hide_unavailable_items / hide_images / auto_add_item_to_cart, with no suggestion engine. Positive control: \bwebshop\b|website_item|e_commerce_settings fires in erpnext (7 files), so the e-commerce trail is visible to this search. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/recommended_items/recommended_items.json · retrieved 2026-09-06 adversarially verified
Supports future/scheduled orders with per-daypart throttling — capacity limits on orders or items per time slot that automatically close slots when the kitchen is saturated.
digital-scheduled-pacing
Searched \bslot\b, time slot, throttle, pacing, capacity, daypart, and the vendor's real slot vocabulary - Appointment, Appointment Booking Settings, Appointment Booking Slots. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. This is the trap in this cell and it is worth naming: ERPNext DOES ship a guest-facing, capacity-limited slot booker. Appointment Booking Settings carries availability_of_slots (an Appointment Booking Slots child of day_of_week / from_time / to_time), number_of_agents, appointment_duration, advance_booking_days, holiday_list and enable_appointment_portal - genuine per-interval capacity on a public portal. It just does not carry an order: the quoted Appointment field_order is scheduled_time / status / customer_name / customer_phone_number / calendar_event / party, with NO items child table, no price and no link to Sales Order or POS Invoice. Conversely the object that does carry items, Sales Order, times it with `delivery_date` of fieldtype Date - no hour, no slot, no cap. Nothing joins the two, and no kitchen-load input exists (\bkitchen\b = two chart-of-accounts templates). frappe/webshop is likewise empty: `slot`, `schedul`, `pickup` and `delivery` match ZERO paths in its 230-blob census. Positive control: Appointment Booking Slots itself is the control - slot machinery IS visible to this search where it exists. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/crm/doctype/appointment/appointment.json · retrieved 2026-09-06 adversarially verified
Single digital ordering flow supports pickup, curbside (with arrival check-in), dine-in/QR table ordering, and delivery, with mode-specific fees and prep timing.
digital-fulfillment-modes
Searched the fulfilment vocabulary: \bcurbside\b, pickup, dine-in, QR table ordering, delivery mode, prep time, and the vendor's own Shipping Rule / Delivery Trip. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: \bcurbside\b returns ZERO files across erpnext+frappe, and `pickup`, `curbside`, `delivery` and `slot` each match ZERO paths in the webshop census. The artefact is webshop's entire order-placement control (quoted): the cart offers exactly two terminal actions - Place Order when checkout is enabled, or Request for Quote when it is not. There is no mode selector, and consequently no mode-specific fee or prep timing; the only address surface is a single shipping Address picker. Table/dine-in ordering was removed at v14 (erpnext/patches/v14_0/delete_hospitality_doctypes.py deletes Sales Invoice.restaurant_table). Delivery Trip and Shipping Rule exist but are back-office dispatch and freight-charge objects on a submitted Sales Order, not a guest-selectable channel. Positive control: \bDelivery Trip\b = 20 files / 35 lines, so fulfilment objects ARE visible to this search. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/templates/includes/cart/place_order.html · retrieved 2026-09-06 adversarially verified
Supports guest-facing QR scan-to-order and/or scan-to-pay at the table that opens or attaches to the existing POS check, including splitting and tipping.
digital-qr-table
Table-side ordering — restaurants, menus, tables, reservations, order entry — existed only in frappe/hospitality, archived read-only 2023-10-04. Nothing equivalent ships in core, and POS Invoice has no table state for a QR order to attach to. https://github.com/frappe/hospitality · retrieved 2026-08-02
Vendor ships a self-order kiosk running the same menu and modifier logic as the POS, with accessibility-compliant UI and unattended EMV payment. differentiator
digital-kiosk
Searched \bkiosk\b, self-order, unattended, EMV, and guest access to the POS. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \bkiosk\b returns ZERO files across both repositories, and ZERO paths in the 230-blob frappe/webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.). \bEMV\b anchored resolves to one line inside a base64 email fixture; \bcard reader\b|\bpin ?pad\b|semi.?integrat likewise returns a single base64 artefact - there is no unattended payment device support of any kind, consistent with Mode of Payment's type Select enumerating only Cash / Bank / General / Phone. The artefact quoted is the Point of Sale Page record: restrict_to_domain 'Retail' with a roles list of Accounts User / Accounts Manager / Sales User / Sales Manager, so the POS screen requires an authenticated Frappe User holding a staff role and cannot render for a guest. Positive control: frappe DOES ship guest-reachable surfaces (Web Form, Portal Settings, webshop's login_required_to_view_products switch), all visible to the same search - guest mode would have been found if the POS had one. Scope: core erpnext v16.34.1 + frappe v16.33.0 + the frappe/webshop census. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.json · retrieved 2026-09-06 adversarially verified
Supports group ordering: a shareable link where multiple participants add their own items to one order under a per-person or total spend cap, with split or single payment.
digital-group-ordering
Searched group order|shared cart, per-person cap, spend limit, participant, and the vendor's real cart vocabulary - Shopping Cart, Quotation, Party, Portal User. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: group order|shared cart returns ZERO files across erpnext+frappe. The artefact is webshop/webshop/shopping_cart/cart.py, whose party resolution (the quoted function sits directly after get_party/get_customer, which resolve the session User to exactly one Customer via Portal User) makes the model explicit: a webshop cart IS a draft Quotation owned by one resolved party, keyed to one logged-in session. There is no share token, no participant child table, no per-participant sub-cart and no per-person spend cap anywhere in the 230-blob census; the only multi-payer construct in the whole product is POS Invoice's `payments` child table, which is split tender on one till, not split payment across guests. Positive control: the same census surfaces webshop's coupon_code.html and address_picker_card.html, so cart-level features ARE visible to this search. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/shopping_cart/cart.py · retrieved 2026-09-06 adversarially verified
Offers a distinct catering ordering flow with separate catering menu/minimums, lead-time rules, quotes or proposals, deposits, and invoice/house-account or ACH payment terms. differentiator
digital-catering-portal
Searched \bcatering\b and the vendor's nearest back-office vocabulary: Quotation, Sales Order, Payment Entry advance, Payment Terms Template, minimum order, lead time. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: \bcatering\b returns ZERO files across erpnext+frappe and ZERO paths in the webshop census. The back-office half of the claim is real - Quotation, Sales Order, Payment Schedule / Payment Terms Template and advance Payment Entry all ship and can express a proposal, a deposit and net terms. The guest-facing half does not exist: the quoted block is the tail of Webshop Settings' entire commercial configuration, which reads section_break_18 / company / price_list / column_break_21 / default_customer_group / quotation_series - one company, ONE price_list, one default_customer_group, one quotation_series. There is no second catering catalogue, no order minimum field, no lead-time rule, no deposit capture at checkout and no approval routing anywhere in the storefront; webshop's only alternative flow is the Request for Quote button in templates/includes/cart/place_order.html, which merely saves the cart Quotation as a draft for a human to price. Positive control: \bSubscription Plan\b = 17 files and Payment Schedule is fully visible in the corpus, so billing-terms machinery IS findable. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/webshop_settings/webshop_settings.json · retrieved 2026-09-06 adversarially verified
Vendor offers AI voice phone ordering (native or a named certified partner) that answers inbound calls and injects the completed order into the POS without staff transcription. differentiator
digital-voice-ai-phone
CORRECTION to the standing rationale, which says 'Frappe's Telephony module integrates Twilio and Exotel to pop an incoming call against a Contact'. Neither provider ships at these tags. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. The quoted line is erpnext/patches/v15_0/remove_exotel_integration.py deleting the Exotel Settings doctype at v15 and directing operators to github.com/frappe/exotel_integration; Twilio left frappe at v13 (frappe/patches/v13_0/remove_twilio_settings.py deletes Twilio Settings and Twilio Number Group). Also: the Telephony module is in erpnext, not frappe. What remains is call_log / incoming_call_settings / incoming_call_handling_schedule / telephony_call_type / voice_call_settings - screen-pop plumbing with no shipped provider. Invariance: voice order|voice ai|conversational returns ZERO files across both repositories; nothing writes into a cart from a call, and no certified voice partner is named anywhere in the 1,863-page docs census (\brestaurant\b|\bhospitality\b = ZERO pages there). Positive control: \bExotel\b = 3 files, \bTwilio\b = 1 file - the search finds these strings exactly where they survive, which is in the removal patches. Verdict unchanged at no; the reasoning behind it was wrong. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/remove_exotel_integration.py · retrieved 2026-09-06 adversarially verified
Supports AI voice ordering at the drive-thru lane, integrated with the POS menu/modifiers and with escalation-to-human handoff.
digital-drivethru-ai
Searched drive.?thru|drive.?through and the surrounding vocabulary: lane, order point, timing, escalation/handoff, voice. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: drive.?thru|drive.?through returns ZERO files across both repositories - an absolute zero with no noise to read past; voice order|voice ai|conversational likewise returns ZERO. The artefact quoted is the Point of Sale Page's domain restriction: the POS is registered to the 'Retail' domain, and erpnext/domains/retail.py defines that domain as desktop icons for POS / Item / Customer / Sales Invoice / Purchase Order plus show_barcode_field - a counter-service retail till. There is no lane object, no order point, no timing measurement and no handoff model to escalate to, so there is no drive-thru surface for voice AI to attach to. Positive control: erpnext ships four domains (retail, distribution, manufacturing, services) and all four files are in the corpus - a hospitality or QSR domain would have been visible; instead the Restaurant module was deleted at v14 by erpnext/patches/v14_0/delete_hospitality_doctypes.py. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.json · retrieved 2026-09-06 adversarially verified
Supports conversational SMS or chat ordering/reordering (text-to-order or text-a-link) that lands in the POS.
digital-sms-ordering
Searched the vendor's messaging vocabulary: SMS Settings, sms_gateway_url, SMS Parameter, SMS Center, receive_sms, inbound webhook, plus conversational/chat ordering. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the artefact is frappe's SMS Settings, and its COMPLETE field list is sms_gateway_url (quoted), message_parameter, receiver_parameter, static_parameters_section, parameters, use_post, allowed_roles_section, allowed_roles. Every field is a component of one outbound HTTP GET/POST to a gateway URL; there is no inbound endpoint, no webhook receiver, no message-thread doctype and no reply handler - receive_sms|incoming.{0,15}sms|sms.{0,10}webhook returns nothing but the outbound plumbing above. Nothing lands in the POS: no code path in either repository creates a POS Invoice or Sales Order from a message. voice order|voice ai|conversational returns ZERO files. Positive control: \bSMS Settings\b = 13 files / 27 lines, and erpnext ships an SMS Center doctype for bulk outbound sends - so the messaging machinery IS fully visible to this search, and it is one-directional. Scope: core erpnext v16.34.1 + frappe v16.33.0. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/core/doctype/sms_settings/sms_settings.json · retrieved 2026-09-06 adversarially verified
Supports Order with Google — the restaurant's direct ordering link is provisioned to the Google Business Profile as an ordering option (ideally set as 'Preferred by Business'), rather than leaving marketplace links as the only choice. differentiator
digital-google-order
Searched 'order with google', google.{0,15}order, Google Business Profile, and then enumerated what Google integration the vendor actually ships. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: apple business|business connect|order with google|google.{0,15}order returns ZERO files across both repositories. The artefact is frappe's Google Settings, the single OAuth credential store for every Google feature in the platform; its whole field list is enable / client_id / client_secret / api_key / app_id / google_drive_picker_enabled (quoted), and the doctypes that consume it are Google Calendar, Google Contacts, Google Drive and Google Indexing. Ordering is not among them, and there is nothing to provision: core ships no consumer ordering endpoint at all after erpnext/patches/v15_0/delete_ecommerce_doctypes.py moved e-commerce to frappe/webshop at v15, and `google` matches ZERO paths in the 230-blob webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.). Positive control: \bgoogle\b = 66 files / 275 lines, led by google_calendar.py (53 hits) and google_contacts.py (26) - Google integrations ARE richly visible to this search where they exist. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/integrations/doctype/google_settings/google_settings.json · retrieved 2026-09-06 adversarially verified
Supports Apple Business Connect ordering placement — an 'Order Food' custom action on the Apple Maps place card pointing at the vendor's first-party ordering flow.
digital-apple-business-connect
Searched apple business|business connect and 'Order Food' / Maps place-card actions, then the precondition - whether any first-party ordering endpoint exists to register. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: apple business|business connect returns ZERO files across both repositories, and `apple` matches ZERO paths in the 230-blob frappe/webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.); the only Apple strings anywhere are four apple-mobile-web-app meta tags in frappe/www/desk.html. The artefact quoted is erpnext/patches/v15_0/delete_ecommerce_doctypes.py, which at v15 deletes E Commerce Settings, Website Item, Recommended Items, Item Review, Wishlist, Wishlist Item, Website Offer and Website Item Tabbed Section from core and tells the operator to install a separate app - so core erpnext v16.34.1 ships no consumer ordering surface, and webshop is a product-catalogue storefront with no restaurant ordering flow (pickup/curbside/slot/schedul all match zero paths). An operator can of course list their own business on Apple Maps and point a custom action at any URL; that is the operator acting as their own business, not a capability this product ships or documents - \brestaurant\b|\bhospitality\b returns ZERO pages across the 1,863-page docs census. Positive control: \bwebshop\b|website_item|e_commerce_settings = 7 files in erpnext, so the e-commerce trail is visible. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/delete_ecommerce_doctypes.py · retrieved 2026-09-06 adversarially verified
Loyalty accrual and redemption work inside the first-party digital ordering flow using the same guest identity as in-store, not as a separate post-purchase enrollment.
digital-loyalty-attach
CHANGES the cell from unknown to no, and grounds it. The standing rationale said 'whether webshop checkout accrues and redeems against the same Customer identity is not documented on any page retrieved' - a census of the app settles it without needing a doc page. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: `loyalty` matches ZERO paths in the 230-blob webshop census. Webshop Settings' entire optional-feature surface is the quoted add_ons_section - enable_wishlist and enable_reviews, and nothing else; there is no loyalty switch, no points display and no redemption control. webshop/webshop/shopping_cart/cart.py sets no loyalty field on the Quotation or Sales Order it builds. On the other side the machinery plainly exists and is POS-specific: Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. \bLoyalty Program\b returns 22 files / 56 lines, and POS Invoice ships a whole loyalty_points_redemption section (loyalty_points, loyalty_amount, redeem_loyalty_points, loyalty_program, loyalty_redemption_account, loyalty_redemption_cost_center) - Sales Order carries loyalty_points/loyalty_amount too, but webshop never populates them. So accrual and redemption are in-store only. Positive control: that same \bLoyalty Program\b search is the control - it fires 22 times in erpnext and zero times in webshop. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/webshop_settings/webshop_settings.json · retrieved 2026-09-06 adversarially verified
Supports guest subscription / membership programs (recurring billing for a delivery-fee waiver, a per-period item entitlement, or a paid loyalty tier) managed in the platform.
digital-subscriptions
Regrading a grade-F partial, not changing its value. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The artefact is the Subscription doctype, and the quoted run shows what it genuinely does model: subscription_period, trial_period_start/end, cancel_at_period_end, days_until_due, current_invoice_start/end, plus a `plans` child table of Subscription Plans and generate_invoice_at / submit_invoice. That is real recurring billing against a party, so a paid tier COULD be billed - which is why this is not `no`. Why it is not `yes`: there is no entitlement layer of any kind. Nothing links a Subscription to a fee waiver, a per-period item allowance, or a Pricing Rule; `party_type`/`party` is a Customer or Supplier link, not a guest identity; and the storefront cannot sell one - `subscription` matches ZERO paths in the 230-blob frappe/webshop census, and Webshop Settings has no subscription field. Loyalty Program exists but is a separate points construct with no tier billing. Positive control: \bSubscription Plan\b = 17 files / 34 lines, so the billing machinery IS fully visible to this search - the membership semantics are what is missing. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/subscription/subscription.json · retrieved 2026-09-06 adversarially verified
Discounts, coupon codes, and loyalty offers are defined once and honored identically across POS, kiosk, and first-party digital channels, with channel eligibility controls.
digital-promo-parity
Pricing Rule, Promotional Scheme and Coupon Code are a single engine evaluated on Sales Invoice, POS Invoice and webshop orders alike, so promos are defined once. No per-channel eligibility control because there is no channel dimension. https://docs.frappe.io/erpnext/promotional-scheme · retrieved 2026-08-01
Vendor documents that the operator owns and can export first-party guest records (email, phone, consented marketing status, order history) in bulk, without a fee or vendor approval. differentiator
digital-guest-data-ownership
Shortfall: the vendor documents the export but not the ownership. "‘Data Export’ helps you extract data from any DocTypes to a CSV or an Excel format", with filters and field selection, run by the operator with no ticket and no fee, and REST reads Customer and Contact programmatically — so bulk guest export is real and unencumbered. No published Frappe Cloud term states that the operator owns the data or limits Frappe’s use of it (commercial-data-ownership-clause is unknown for exactly this reason). Self-hosting makes ownership true in fact; the claim asks whether the vendor documents it. Downgraded from yes on verification. https://docs.frappe.io/erpnext/data-export · retrieved 2026-08-02 adversarially verified
Digital checkout uses vendor-hosted fields or a hosted payment page so card data never touches the restaurant's page, with the vendor publishing PCI DSS 4.0 compliance (including the client-side script-integrity requirements effective March 2025) and supporting 3DS.
digital-checkout-pci-sca
CHANGES the cell from unknown to partial and grounds both halves. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Half that is established: webshop checkout never touches card data on the operator's page. The quoted line is from webshop/webshop/shopping_cart/cart.py, which requires a single Webshop Settings.payment_gateway_account and hands the order to erpnext's Payment Request, whose Payment Gateway Account resolves to a hosted redirect (\bRazorpay\b 7 files, \bStripe\b 5, \bPayPal\b 12); `token` matches ZERO paths in the webshop census, i.e. no PAN or token is ever stored or posted by the storefront. Half that is established as ABSENT rather than unknown: 'PCI DSS' returns ZERO occurrences across erpnext v16.34.1 and frappe v16.33.0, \b3ds\b|three.?d.?secure returns ZERO files, and a bounded docs census (1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12).xml - the 26 misses are 404s in the publisher's own manifest) contains no PCI DSS 4.0 statement, no client-side script-integrity position and no 3DS documentation. Vendor legal/trust pages outside docs.frappe.io were not censused and are the one route that could still move this. Positive control: those three gateway names firing in erpnext is the control. https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/shopping_cart/cart.py · retrieved 2026-09-06 adversarially verified
Digital channels support the same service-fee / dual-pricing / card-surcharge configuration as the POS, with the required guest-facing disclosure and correct handling of jurisdictions and card brands where surcharging is prohibited. differentiator
digital-surcharge-transparency
There is no surcharge or service-fee engine whose disclosure could be governed: POS Profile enumerates taxes_and_charges, tax_category and apply_discount_on but no card surcharge, cash discount or service fee, and no card or BIN data enters the system. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Guest data, loyalty & marketing
Maintains a single guest profile that automatically merges transactions from in-store POS, first-party web/app ordering, and kiosk under one identity (phone or email match), with documented dedup/merge behavior.
guest-loyalty-unified-profile
One Customer master is shared by POS, webshop and back office, so transactions do land on a single identity. There is no automatic phone/email dedup or documented merge behavior — Customer creation at POS is manual. https://docs.frappe.io/erpnext/customer · retrieved 2026-08-01
Orders arriving from third-party marketplaces (DoorDash, Uber Eats, Grubhub) attach to a native guest profile with usable guest identity rather than landing as anonymous tickets. differentiator
guest-loyalty-thirdparty-identity-attach
Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 across erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files), tree API truncated:false. THE ARTEFACT: POS Invoice's 185-field field_order, the record a marketplace ticket would have to land in, carries no channel, no marketplace, no external order id and no external-customer field -- so there is no order source that could carry a marketplace guest identity. The guest profile itself is real and the search finds it (POS Invoice links Customer; pos_item_cart.js edits email_id and mobile_no straight onto the Customer record, 121 'customer' hits in that one file), which is the positive control: the negative is about the arriving order, not about the guest model. Bound to core at these tags; the Frappe Cloud marketplace was not censused. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Supports at least two of points-per-dollar, visit/punch-count, and spend-tier accrual as configuration, without custom development or a bolt-on loyalty vendor.
guest-loyalty-accrual-models
Verified: Collection Factor drives points-per-spend ('with a Collection Factor of $100, an eligible $1,000 invoice earns 10 points'), Conversion Factor sets redemption value, and 'Programs can use one tier or several tiers based on a Customer's cumulative eligible spend'. Caveat the dossier did not surface: the doc frames earning against submitted Sales Invoices and gives no POS- or webshop-specific accrual guidance, which strengthens the existing 'unknown' on digital-loyalty-attach. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-01 adversarially verified
Supports status tiers with automatic promotion and demotion driven by rolling-window spend or visit counts. differentiator
guest-loyalty-tiers
Multiple tiers with names and cumulative-spend thresholds, auto-promotion on threshold. Rolling-window evaluation and automatic demotion are not documented. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-01
Documents explicitly what loyalty lookup, accrual, and redemption do when the POS loses connectivity (queue-and-reconcile vs blocked). differentiator
guest-loyalty-offline-behavior
The claim is about explicit vendor documentation of loyalty behaviour under connectivity loss. Bound: the full 1,863-page docs.frappe.io census (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) at the 2026-09-06 sitemap, not the 1,544-page erpnext+framework subset. Word-anchored 'offline' returns 14 pages and none states POS behaviour; the ERPNext Point of Sale page cited here documents loyalty redemption at the till and says nothing about a disconnected mode. Code side, erpnext v16.34.1 + frappe v16.33.0 (tree API truncated:false): POS Settings holds four fields and no offline toggle, so the v9 changelog's offline switch is gone, and there is no queue-and-reconcile path for a loyalty lookup, accrual or redemption to be documented against. POSITIVE CONTROL: the loyalty machinery itself is fully present and found by the same searches -- Loyalty Program resolves in 22 files and pos_payment.js carries 31 loyalty references -- so a disconnected-mode branch would have shown up beside them. https://docs.frappe.io/erpnext/point-of-sale · retrieved 2026-09-06 adversarially verified
Offer/discount engine exposes explicit stacking and precedence rules (exclusive vs combinable, order of application) as configuration. differentiator
guest-loyalty-offer-stacking-rules
Verified: Pricing Rule documents Priority to resolve overlapping rules, 'Apply Multiple Pricing Rules' for stacking, and Mixed Conditions across selected items. Genuinely configurable precedence and combinability. https://docs.frappe.io/erpnext/pricing-rule · retrieved 2026-08-01 adversarially verified
Offers can be issued to a dynamically defined audience (rules over recency, frequency, spend, or items purchased) rather than only broadcast to the whole list. differentiator
guest-loyalty-targeted-offers
Searched the vendor's words: 'Pricing Rule', 'Promotional Scheme', 'Coupon Code', 'Customer Group', 'Territory', applicable_for, and the audience vocabulary recency / frequency / RFM / lapsed / win-back / segment. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'win-back'; word-anchored RFM and recency resolve only to list-view sort relevance in frappe/search/sqlite_search.py and list_view_settings -- a reader trap, not an audience engine. Pricing Rule's applicable_for enum is Customer / Customer Group / Territory / Sales Partner / Campaign / Supplier / Supplier Group: all static attributes. The one thing that looks dynamic is the Advanced Settings condition field (fieldtype Code, options PythonExpression) -- but utils.py evaluates it as frappe.safe_eval(pricing_rule.condition, None, doc.as_dict()), whose entire namespace is the current document's own fields, so no purchase history is reachable. The is_cumulative path does query history, and I checked it adversarially: get_qty_amount_data_for_cumulative filters on date window, warehouse and item only -- there is no customer clause at all, so it aggregates every customer's transactions, not this guest's. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pricing_rule/utils.py · retrieved 2026-09-06 adversarially verified
Automatically computes recency/frequency/monetary or equivalent lifecycle segments (new, regular, at-risk, lapsed, VIP) without the operator building the queries. differentiator
guest-loyalty-rfm-segmentation
The Loyalty Program manual enumerates the whole feature — Collection Factor (eligible spend per point), Conversion Factor, tiers by cumulative eligible spend, expiry in days, redemption accounting, and eligibility limited by Customer Group and Territory. No recency/frequency/monetary or behavioural segment builder is documented. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-02
Ships triggered lifecycle automations (birthday, first-visit thank-you, lapsed win-back) as configurable always-on campaigns rather than one-off manual sends.
guest-loyalty-lifecycle-automation
Searched the vendor's words: 'Campaign', 'Email Campaign', 'Campaign Email Schedule', 'Newsletter', 'Email Group', 'Notification', 'Auto Repeat', plus birthday / anniversary / lapsed / win-back / drip campaign. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What the uncited rationale missed: ERPNext DOES ship a drip engine -- Campaign holds a campaign_schedules child table of Campaign Email Schedule rows, each just send_after_days plus an Email Template, driven by Email Campaign. It fails the claim on both halves. (1) It is not triggered: Email Campaign is one record per recipient with a manually set start_date and a status of Scheduled/In Progress/Completed/Unsubscribed -- precisely the 'one-off manual send' the claim excludes -- and its email_campaign_for enum is Lead / Contact / Email Group, none of which is Customer. (2) A birthday trigger has no source field to fire from: word-anchored date_of_birth exists on Employee only, and the three 'birthday' hits in the corpus are two deprecation-dumpster docstrings and a Font Awesome CSS blob. Positive control: 'Email Campaign' 10 files, 'Auto Repeat' 46 files -- the automation vocabulary is found where it exists. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/crm/doctype/email_campaign/email_campaign.json · retrieved 2026-09-06 adversarially verified
Sends both email and SMS campaigns natively from the platform, not solely by handing the list to a third-party ESP. differentiator
guest-loyalty-native-email-sms
CORRECTION to the rationale, not to the value. The uncited partial rests on 'Newsletter/Email Group sends bulk email natively' -- but Newsletter has LEFT the framework at v16. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. The quoted v16 patch prints a deprecation warning naming Newsletter as moving to a separate app at github.com/frappe/newsletter, and the census confirms it: frappe/email/doctype/ at v16.33.0 contains email_group, email_group_member, email_queue, email_template, email_unsubscribe and notification, and no newsletter directory at all; the 14 remaining word-anchored 'Newsletter' files are documentation, changelogs, a v13 patch, an erpnext help link and a stray erpnext/public/js/newsletter.js. What still sends natively in core: ERPNext's Email Campaign drives a Campaign's campaign_schedules (Campaign Email Schedule = send_after_days + Email Template) at a Lead, Contact or Email Group, and frappe's SMS Settings posts to a BYO HTTP gateway. Both channels are therefore native, and both are framework primitives -- no campaign builder, no template library, no send analytics -- so partial holds. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/patches/v16_0/add_module_deprecation_warning.py · retrieved 2026-09-06 adversarially verified
Captures per-channel marketing consent with timestamp and source of consent, and honors revocation received by any reasonable means (not just the STOP keyword) across all channels.
guest-loyalty-consent-management
Searched the vendor's words: 'Email Group', 'Email Group Member', 'Email Unsubscribe', 'SMS Settings', consent, opt-in, source of consent. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial and sharpens both halves. Revocation is real and is honoured by more than a STOP keyword: Email Group Member carries an unsubscribed flag, and Email Unsubscribe records email + reference_doctype + reference_name + global_unsubscribe, so an opt-out can be recorded per document or globally and is applied by the email queue. Capture is what fails, and the quoted field list is the whole of it -- three fields: email_group, email, unsubscribed. There is no consent timestamp field, no source-of-consent field and no channel dimension, and SMS consent is not modelled at all (SMS Settings holds a gateway URL and parameter names only). Note also that the subscribe flow the old rationale leaned on has left core with Newsletter at v16. Positive control: Email Unsubscribe and Email Group Member are both found by the same search, so a consent_source field would have been. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/email_group_member/email_group_member.json · retrieved 2026-09-06 adversarially verified
Handles or explicitly documents A2P 10DLC brand and campaign registration required for the operator to send SMS through the platform.
guest-loyalty-10dlc-registration
Searched 10DLC, A2P, brand registration, campaign registration and sender ID over both repositories and the 1,863-page docs census. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for '10DLC' anywhere, in code or docs. Adversarial check on my own control: case-insensitive 'A2P' returns one file with seven lines -- frappe/tests/data/email_with_image.txt, where the letters occur inside base64 blobs; that is a reader artefact, not a finding. The artefact that would carry any of this is SMS Settings, whose entire field list is a gateway URL, a message parameter name, a receiver parameter name, a static-parameter table, a POST flag and an allowed-roles table: BYO HTTP gateway with no brand, campaign, sender-id or consent registration surface at all, so 10DLC registration is wholly the operator's problem and is nowhere documented. Positive control: SMS Settings and SMS Log both resolve to real frappe doctypes. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/core/doctype/sms_settings/sms_settings.json · retrieved 2026-09-06 adversarially verified
Reports redemption and incremental sales attributable to a specific campaign or offer, tying redeemed offers to actual check totals. differentiator
guest-loyalty-campaign-attribution
CORRECTION -- the uncited `no` understates the data model. Searched: 'Coupon Code', 'Campaign', 'UTM Campaign', utm_campaign, campaign_efficiency. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What is actually there: POS Invoice carries BOTH a coupon_code Link to Coupon Code AND a utm_campaign Link to UTM Campaign, and POS Profile carries utm_source/utm_medium/utm_campaign so every ticket rung on a till inherits a campaign tag; pos_payment.js binds a coupon_code change event on POS Invoice, so a redemption really is written onto the check that carries the grand_total. Redemption-to-check-total attribution is therefore reportable through Report Builder out of the box. What keeps this below yes: no shipped report does it -- the one campaign report, crm/report/campaign_efficiency, walks Lead to Opportunity to Quotation to Sales Order and never touches an invoice -- and nothing measures INCREMENTAL sales (no holdout, no control group, no baseline). Coupon Code's used counter is a global tally; the vendor's own coupon page states that Maximum Use caps overall use, with no per-customer limit. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Provides self-serve export of the full guest list and transaction history, including contact PII, via CSV or API, without a vendor fee or support ticket. differentiator
guest-loyalty-data-export-portability
"‘Data Export’ helps you extract data from any DocTypes to a CSV or an Excel format", with filters to "add filters to select only specific data" and per-field selection. Any DocType covers Customer, Contact, Address, Loyalty Point Entry and Sales Invoice, so the full guest list with contact PII and the transaction history are both exportable from the desk — no support ticket, no fee — with REST as the programmatic equivalent. Upgraded from partial on verification: the earlier downgrade rested on the Data Export tool being uncited, not absent. https://docs.frappe.io/erpnext/data-export · retrieved 2026-08-02 adversarially verified
Triggers post-transaction feedback requests and routes responses by score, sending low scores to private service recovery and high scores toward public review sites. differentiator
guest-loyalty-review-capture-routing
Searched 'review request', 'star rating', NPS, feedback, survey, and the framework's own Rating fieldtype over erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), tree API truncated:false. INVARIANCE: zero hits for 'review request', zero for word-anchored NPS, one hit each for 'star rating' and 'survey'; the 68 'feedback' files are the trap -- UI toast strings, validation messages and appraisal wording, not guest feedback. Nothing captures a post-transaction guest response, scores it, or routes by score, and no public-review-site link exists anywhere in either repository. THE CITED FILE IS THE POSITIVE CONTROL, not the artefact of absence: Delivery Trip's notify_customers() renders an Email Template to each stop's Contact and stamps email_sent_to, so the outbound half of a feedback request is already expressible with shipped machinery -- which is precisely why the missing return path is a real absence rather than a search failure. Bound to core at these tags; the Frappe Cloud marketplace was not censused. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.py · retrieved 2026-09-06 adversarially verified
Includes a native referral mechanic with per-guest codes or links, attribution of the referred guest's first order, and two-sided rewards.
guest-loyalty-referral-program
The Loyalty Program manual covers points accrual, tiers, expiry and redemption only. No referral code, referrer credit or referred-guest reward mechanism is documented. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-02
Issues an Apple Wallet or Google Wallet loyalty pass with push-updatable balance, as an alternative to requiring a branded app download. differentiator
guest-loyalty-wallet-pass
No Apple Wallet or Google Wallet pass issuance is documented. The loyalty balance lives on Loyalty Point Entry records visible in the Frappe desk and portal, with no pass generation and no push update. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-02
Provides admin tooling to fulfill guest data access and deletion requests (CCPA/CPRA-style) including deletion propagation to loyalty and marketing records.
guest-loyalty-privacy-rights-tooling
CORRECTION to both halves of the rationale, value unchanged. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. First: a DPA IS published -- Frappe Cloud terms 6.7 offers one for digital execution and docs.frappe.io/legal/data-protection/data-process-addendum-sample serves a downloadable sample copy, so 'no published DPA was located' was a retrieval gap. Second, and more important: deletion propagation is not merely undocumented, it is documented and it EXCLUDES the guest. Personal Data Deletion Request does not walk the database; it walks the user_data_fields hook, redacting only the doctypes each app registers. frappe/hooks.py registers Access Log, Activity Log, Comment, Contact, Contact Email and Address. ERPNext's entire registration is the quoted six lines: Lead and Opportunity. Customer, Sales Invoice, POS Invoice and Loyalty Point Entry appear nowhere in it, so an erasure request leaves the guest's Customer record and their whole loyalty ledger standing. In-app access and erasure workflows exist; they do not reach the loyalty and transaction records this claim is about. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/hooks.py · retrieved 2026-09-06 adversarially verified
Enforces loyalty fraud controls such as redemption velocity limits, manager approval on manual point adjustments, and flagging of employee self-redemption, with an audit log.
guest-loyalty-redemption-fraud-controls
Searched the vendor's words: 'Loyalty Point Entry', 'Role Permission Manager', 'Version', velocity, approval, self-redemption. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial. Present: every points movement is a Loyalty Point Entry row, and frappe's Version doctype attributes every change, so an audit log genuinely exists; Role Permissions can gate who creates or amends one. Absent, and the quoted field list is the evidence -- twelve fields, of which discretionary_reason is a free-text note with no approver, no approval state and no workflow: there is no manager-approval gate on a manual adjustment, no velocity or rate limit anywhere, and no employee self-redemption flag (Loyalty Point Entry links customer and invoice but never the User who rang it, so a self-redemption cannot be detected from the row). The vendor's own coupon page adds that the sibling redemption cap is global, not per guest: 'Maximum Use caps overall use.' Positive control: 'Loyalty Program' 23 files, and pos_payment.js carries 31 loyalty references, so a velocity or approval field would have been found. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.json · retrieved 2026-09-06 adversarially verified
Vendor documents AI/ML-generated recommendations for offer content, target audience, or send timing (claim-level; verify it is a shipped product feature, not a roadmap statement). differentiator
guest-loyalty-ai-offer-recommendation
No propensity, next-best-offer or recommendation model is documented against the Loyalty Program, and Pricing Rule targeting is static (Customer, Customer Group, Territory) rather than behavioural. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-02
Offers native stored-value/gift card balances tied to the same guest profile and redeemable across all locations of the brand.
guest-loyalty-stored-value-gift
Searched the vendor's words: 'Coupon Code', 'Gift Card', 'Loyalty Program', 'Loyalty Point Entry', stored value, store credit, gift_card. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The adversarial finding: ERPNext DOES have something called a Gift Card and it is not stored value. Coupon Code's coupon_type enum is literally Promotional / Gift Card, so a careless reader could score this yes. Its field list is coupon_name, coupon_type, customer, coupon_code, pricing_rule, valid_from, valid_upto, maximum_use, used, description -- a code that fires a Pricing Rule discount, with no balance, no amount, no currency and no ledger. Frappe's own documentation says so outright: at https://docs.frappe.io/erpnext/coupon-code the question 'Is a Gift Card Coupon Code a stored-value payment instrument?' is answered 'No. In this feature it is a generated code linked to a Pricing Rule, not a financial wallet.' Zero hits for 'store credit' or 'gift_card'. Positive control: Loyalty Point Entry, a real balance-bearing ledger with loyalty_points and expiry_date, is found by the same search -- so a stored-value ledger would have been too. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/coupon_code/coupon_code.json · retrieved 2026-09-06 adversarially verified
Labor & workforce
Employees clock in and out at the POS terminal using a PIN, badge, or card, with no separate time-clock hardware required.
labor-clock-in-at-pos
Frappe HR (separate free GPL-3.0 app) provides Employee Checkin with geolocation check-in/out and biometric-device import. It is not embedded in the POS screen and requires installing a second app. https://github.com/frappe/hrms · retrieved 2026-08-01
Captures a photo at punch (or performs facial verification) attached to the timecard entry, with a photo-only mode available that stores no biometric template. differentiator
labor-photo-punch-verification
SCOPE: the record already cites github.com/frappe/hrms as evidence for labor cells, so Frappe HR is in scope; ERPNext's HR module was split out of frappe/erpnext, and an absence in erpnext alone would prove only that the code moved. I therefore censused frappe/hrms@v16.17.1 (current stable v16 tag, released 2026-09-01) as a third corpus: the GitHub tree API answers truncated=false at 1,552 blobs, 1,418 of them text. Searched Frappe HR's own vocabulary -- Employee Checkin (the timecard record), log_type, device_id, fetch_geolocation -- and then the punch-photo vocabulary: zero word-boundary hits for selfie|facial|face recognition|photo capture, zero for camera|getUserMedia anywhere in hrms@v16.17.1 (including its Vue frontend/), and the single \bbiometric\b hit is a Shift Type label, not an image path. INVARIANCE: the Employee Checkin doctype's complete field_order carries a location section (latitude, longitude, fetch_geolocation, geolocation) and no image, photo or Attach Image field of any kind; the only 'Attach Image' fieldtype in the whole app is on Appraisal. POSITIVE CONTROL: 'Employee Checkin' itself resolves to 26 files / 68 lines including shift_type.py and attendance.py, so the search would have found a photo field on the same record had one existed. Bound: this is an absence in frappe/hrms@v16.17.1, frappe/erpnext@v16.34.1 and frappe/frappe@v16.33.0 -- not a statement about Frappe Cloud marketplace HR apps, which were not censused. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/employee_checkin/employee_checkin.json · retrieved 2026-09-06 adversarially verified
Records time punches while the POS is offline and reconciles them on reconnect without loss or duplicate entries, with the behavior documented. differentiator
labor-offline-time-punch
CHANGED FROM unknown, by censusing the app the prior note could not reach. Frappe HR is in scope (product.yaml cites github.com/frappe/hrms for labor cells); frappe/hrms@v16.17.1 answers truncated=false at 1,552 blobs. The prior note guessed that biometric devices buffer locally; that is true of the DEVICE, and Employee Checkin does carry a device_id for imported punches, but it is a third-party clock, not a first-party offline mode. INVARIANCE: hrms DOES ship a PWA -- frontend/src/main.js registers /assets/hrms/frontend/sw.js, InstallPrompt.vue offers installation, and package.json pulls workbox-core and workbox-precaching -- so if an offline punch queue existed anywhere in the Frappe stack it would be here. The whole service worker is quoted: it calls precacheAndRoute(self.__WB_MANIFEST) and cleanupOutdatedCaches(), i.e. it precaches the static app shell, then hands off to Firebase messaging for background push. There is no runtime route for API calls, no Background Sync registration, no IndexedDB or localforage write queue anywhere in the app, and \b(indexeddb|localforage|background.?sync|outbox|queue)\b returns no such hit. A check-in POST made with the server unreachable therefore fails outright; nothing reconciles on reconnect, and nothing documents such behaviour. The POS side is worse still: erpnext@v16.34.1 registers no service worker at all. POSITIVE CONTROL: 'serviceWorker' resolves in hrms/frontend/src/main.js and 'workbox' in frontend/package.json, so offline infrastructure IS present and searchable -- it caches assets, not punches. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/frontend/public/sw.js · retrieved 2026-09-06 adversarially verified
Permissions are grantable per discrete action (void, comp, discount, refund, drawer open, price change, report access) per role and per location, not limited to fixed cashier/manager/admin tiers.
labor-granular-rbac
Capability upheld but the citation is wrong and I had to source it myself. The REST API page documents CRUD, auth and pagination only — it says nothing about permissions, permlevels or User Permissions. The correct source is the users-and-permissions page, which does document read/write/create/submit/cancel/amend/delete per role, field-level Permission Levels, and User Permissions restricting by Link field value. Re-cite before publishing. https://docs.frappe.io/framework/user/en/basics/users-and-permissions · retrieved 2026-08-01 adversarially verified
Manager overrides and approvals are attributed to the individual approver and written to an immutable audit trail queryable after the fact.
labor-manager-override-audit
Shortfall: there is no approver to attribute. Frappe’s Version doctype carries track_changes: 1 and stores ref_doctype, docname and a serialised field-level diff with owner and creation timestamps, and submitted documents are immutable behind cancel-and-amend, so the immutable queryable audit trail half of the claim is met at primary-source level. But no override or approval event exists to log: there is no manager-PIN prompt at the terminal and no approver field anywhere in the POS (payments-refund-void-controls, order-capture-void-comp-controls). What is recorded is the actor, not a second party who authorised the action. Downgraded from yes on verification. https://raw.githubusercontent.com/frappe/frappe/develop/frappe/core/doctype/version/version.json · retrieved 2026-08-02 adversarially verified
Builds and publishes employee shift schedules inside the same platform that holds the timekeeping data, rather than requiring a third-party scheduling app. differentiator
labor-native-scheduling
Scored against frappe/hrms@v16.17.1 (tree API truncated=false, 1,552 blobs), which is in scope for this record. The prior rationale ('It is shift assignment, not a schedule builder') understates what v16 ships and I am correcting it upward while keeping the partial. INVARIANCE supporting the partial: hrms/hr/doctype now contains shift_type, shift_assignment, shift_request, shift_location, shift_assignment_tool, shift_schedule and shift_schedule_assignment. Shift Schedule -- quoted here -- pairs a shift_type with a frequency Select of Every Week / Every 2 Weeks / Every 3 Weeks / Every 4 Weeks and a repeat_on_days table, and Shift Schedule Assignment binds an employee to that schedule with create_shifts_after so future Shift Assignments are generated automatically. Shift Assignment Tool bulk-assigns across branch, department, designation, grade and employment_type filters. All of this sits in the same app that holds Employee Checkin and Attendance, which is exactly the claim's requirement, so no third-party scheduling app is needed. INVARIANCE supporting the shortfall: there is no role-coverage model (nothing counts how many of a designation a shift needs), no drag-and-drop weekly grid, no publish-to-staff action, and no labour-budget or forecast constraint -- \b(coverage|schedule builder|open shift)\b returns zero lines. POSITIVE CONTROL: 'Employee Checkin' resolves to 26 files in this same app, so timekeeping and scheduling demonstrably co-reside. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_schedule/shift_schedule.json · retrieved 2026-09-06 adversarially verified
Generates recommended staffing levels or labor hours by daypart from the operator's own POS sales history, not just a static template. differentiator
labor-demand-labor-forecast
Frappe HR enumerates its modules: employee lifecycle, leave, attendance with geolocation check-in, payroll and salary structures, expense claims and advances, performance management, shift management, onboarding and exit interviews. No sales-driven demand forecast or labour-model generator is among them. https://github.com/frappe/hrms · retrieved 2026-08-02
Displays labor cost as a percentage of sales in real time during service on a manager view or POS, not only in end-of-day or next-morning reports. differentiator
labor-realtime-labor-percent
Searched the vendor's report vocabulary across erpnext@v16.34.1, frappe@v16.33.0 and hrms@v16.17.1: zero word-boundary hits for 'labour cost'|'labor cost'|'labour percent'|labor_cost anywhere in the three repositories. Enumerated Frappe HR's complete shipped report set (hrms/hr/report + hrms/payroll/report, 29 directories): the only report that joins labour cost to revenue at all is Project Profitability. INVARIANCE: Project Profitability builds its figure by inner-joining Salary Slip Timesheet -> Timesheet -> Sales Invoice Timesheet -> Sales Invoice and filtering on both documents being submitted (docstatus == 1), i.e. it requires a completed payroll run and a Timesheet already billed onto an invoice. That is a period-close professional-services margin report, not a live labour-percent readout: it cannot fire during service, it reads Sales Invoice rather than POS Invoice, and no Dashboard Chart or Number Card ships against it. POSITIVE CONTROL: 'Employee Checkin' (68 lines) and 'Income Tax Slab' (62 lines) both resolve in hrms, and ERPNext's Sales Analytics report resolves in erpnext, so labour and sales reporting artefacts are both visible to this search. Bound to these three repositories at these tags; restaurant apps on the Frappe Cloud marketplace were not censused. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/report/project_profitability/project_profitability.py · retrieved 2026-09-06 adversarially verified
Warns or blocks at clock-in when an employee is approaching or would cross a configured overtime threshold, before the overtime is incurred. differentiator
labor-overtime-prevention
Frappe HR documents Shift Type, Shift Assignment and attendance capture, but no approaching-overtime alert, no clock-in block against scheduled hours and no weekly-hours projection. https://github.com/frappe/hrms · retrieved 2026-08-02
Configures meal and rest break rules per state or jurisdiction, prompts required break attestation, and flags missed breaks for premium pay. differentiator
labor-break-compliance-by-state
TRAP DISARMED FIRST: unanchored 'break' returns 162 files / 708 lines in hrms@v16.17.1 and every one is a Frappe layout fieldname -- column_break, section_break. Anchored, \b(meal break|rest break|meal period|break penalty|premium pay|attestation)\b returns zero lines, and (break_time|break_duration|unpaid_break|break_minutes) returns zero. INVARIANCE: the Shift Type doctype -- the record that defines when a shift starts and ends and how attendance is graded against it -- has a complete field_order of 27 fields covering auto-attendance, half-day/absent working-hour thresholds, late-entry and early-exit grace periods and overtime, and contains no break field at all: no break duration, no unpaid-break deduction, no missed-break flag, no attestation prompt. On the jurisdiction half, hrms/regional contains exactly two subtrees, india and united_arab_emirates; there is no US state or municipality rule library anywhere in the app. POSITIVE CONTROL: 'late_entry_grace_period' and 'early_exit_grace_period' both resolve on this same doctype, so per-shift time-rule fields ARE modelled here and would have been found had break rules been among them. Bound to frappe/hrms@v16.17.1 plus erpnext@v16.34.1 and frappe@v16.33.0. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_type/shift_type.json · retrieved 2026-09-06 adversarially verified
Enforces minor-labor restrictions (age-based maximum hours, prohibited time windows, school-day limits) at both scheduling and clock-in.
labor-minor-labor-rules
Frappe HR’s documented compliance content is India- and UAE-oriented (income tax slabs, statutory payroll components). No minor or youth labour rule library, no school-night hour caps and no age-based clock-in restrictions appear in its module list. https://github.com/frappe/hrms · retrieved 2026-08-02
Computes tip pooling and tip-outs automatically per shift from configurable rules (percentage of sales, hours worked, points, or role), rather than requiring a manual spreadsheet.
labor-tip-pooling-rules
Ran the brief's own trap discipline. \btips?\b over erpnext@v16.34.1 + frappe@v16.33.0 returns 21 lines in 12 files and every one is a reader artefact: UI hint strings ('Tip: Select report lines...'), leaflet popup-tip CSS, a '# TIP:' comment in three GitHub workflow files, and a test fixture titled 'Project Management Tips'. The one interesting hit is a general-ledger account literally named 'Accr-Tips' in the Singapore F&B chart-of-accounts template -- an accrual account a Singapore restaurant could post to by hand, exactly parallel to the 'Kitchen' GL account the brief flags, and not a tip engine. Over hrms@v16.17.1 the same anchored pattern returns ZERO lines. Second trap: \bgratuit returns 22 files / 163 lines in hrms, but Frappe HR's 'Gratuity' and 'Gratuity Rule' doctypes are end-of-service severance benefits set up by hrms/regional/united_arab_emirates and hrms/regional/india -- not restaurant gratuities; in erpnext the gratuity hits are French-language chart-of-accounts lines. INVARIANCE: no tip or gratuity amount is captured anywhere in the three repositories, so nothing exists to pool; the POS Invoice payments section quoted here runs cash_bank_account -> payments -> paid_amount -> change_amount with no tip, gratuity or service-charge field. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files and Mode of Payment ships its own doctype, so POS money-handling concepts are visible to this search. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Retains a per-shift, per-employee record of tips received, amounts contributed to the pool, and amounts distributed from the pool, exportable for audit.
labor-tip-distribution-audit-trail
POS Invoice enumerates no tip or gratuity field, so no tip is ever captured in the system and there is no distribution to audit. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-08-02
Payroll export separates cash from charged qualified tips and carries a Treasury tipped-occupation code, supporting the W-2 Box 12 code TP and Box 14b reporting required for tax year 2026. differentiator
labor-qualified-tips-w2-reporting
Searched the US payroll-tax vocabulary over hrms@v16.17.1 (1,552 blobs, tree API truncated=false): \bW-2\b|\bW2\b|\bIRS\b|form 941|\bFICA\b|box 12|tipped occupation returns exactly one line, and it is a Tailwind size class 'w-2 h-2' in frontend/src/components/BaseLayout.vue -- a pure reader artefact. 'United States'|'USA'|'US payroll' returns zero lines. INVARIANCE: Salary Slip's income-tax breakup section -- the region of the record that would carry statutory box mappings -- is built entirely around ctc, standard_tax_exemption_amount, tax_exemption_declaration, annual_taxable_amount and total_income_tax, i.e. the Indian Income Tax Slab model; there is no W-2, no Box 12, no Box 14, no Treasury tipped-occupation code, and hrms/regional contains only india and united_arab_emirates. Compounding it, \btips?\b returns zero lines in all of hrms, so no charged-versus-cash tip amount exists to report. POSITIVE CONTROL: 'Income Tax Slab' resolves to 26 files / 62 lines including a dedicated Income Tax Computation report, so statutory payroll-tax machinery IS present and searchable -- it is simply Indian. Bound to frappe/hrms@v16.17.1; Frappe Cloud marketplace payroll localisations were not censused. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/payroll/doctype/salary_slip/salary_slip.json · retrieved 2026-09-06 adversarially verified
Vendor processes payroll itself as a first-party product (tax filing and direct deposit), as opposed to exporting to a third-party payroll provider only. differentiator
labor-native-payroll
Frappe HR runs payroll natively — salary structures, income tax slabs, standard and off-cycle payroll runs, salary slips, bank payment entries. But it is a payroll calculation engine, not a US tax-filing and direct-deposit provider; filing is the operator's responsibility. https://github.com/frappe/hrms · retrieved 2026-08-01
Exports timecards, wages, and tips in documented formats or via direct integration for at least two major payroll providers (e.g. Gusto, ADP, Paychex, QuickBooks).
labor-payroll-export-formats
Scored against three corpora: frappe/hrms v16.17.1 (tree API truncated=false, 1,552 blobs, 1,418 text), erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files). I re-ran the provider control independently: \b(gusto|paychex|paylocity|ADP)\b returns files=0 lines=0 in hrms; in erpnext the wider alternation's 17 hits are all the word 'workday' inside Service Level Agreement / Service Day support code, and \bquickbooks\b is one line, a 'which system are you coming from' label in the setup wizard with no connector behind it. INVARIANCE: no payroll-export doctype exists in hrms, no provider credential store exists, and hrms/regional contains only india and united_arab_emirates. The Payroll workspace quoted here lists thirty links whose entire output side is Salary Register, Bank Remittance, Salary Payments Based On Payment Mode, Salary Payments via ECS (India's Electronic Clearing Service), Income Tax Computation, Provident Fund Deductions and Professional Tax Deductions -- every shipped export Indian statutory or generic banking. NOTE ON THE ARTEFACT'S WEIGHT: a Frappe Workspace is a curated shortcut dashboard, not a manifest, so its silence is suggestive rather than exhaustive; the exhaustive evidence is the zero over the provider names across all three repositories. What exists instead is generic -- any Query Report renders to CSV/XLSX and every doctype is readable over the REST API. Bound to these three tags; Frappe Cloud marketplace payroll apps were not censused. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/payroll/workspace/payroll/payroll.json · retrieved 2026-09-06 adversarially verified
Employees can request shift swaps or claim open shifts in a self-service app, subject to a manager approval workflow that enforces overtime and role eligibility. differentiator
labor-shift-swap-workflow
Scored against frappe/hrms v16.17.1 (tree API truncated=false, 1,552 blobs, 1,418 text), which is in scope for this record; ERPNext's HR module lives in that separate repository, so an erpnext-only absence would prove only that the code moved. INVARIANCE SUPPORTING THE PARTIAL: Shift Request's complete field_order is quoted here -- shift_type, employee, employee_name, department, status, company, approver, from_date, to_date, amended_from -- with status a Select of Draft / Approved / Rejected and approver a Link to User. That is a genuine employee-initiated, manager-approved shift change request, self-service in the same PWA that holds check-in, so the approval-workflow half of the claim is met. INVARIANCE SUPPORTING THE SHORTFALL, three distinct absences. (1) No open-shift marketplace. CORRECTED FIGURE: \b(open shift|shift swap|shift pickup|claim shift)\b is NOT zero across hrms -- it returns exactly one line, in shift_assignment_tool.js, and it is the empty-state string 'There are no open Shift Requests based on the given filters', i.e. 'open' as in awaiting approval, not an unclaimed shift posted for pickup. That is a reader artefact and the substantive absence stands: a Shift Request asks to be put on a shift type for a date range, nothing surfaces an unclaimed shift, and no employee can hand a shift to a named colleague. (2) No overtime eligibility check in the approval path: Shift Type carries allow_overtime and overtime_type but nothing in shift_request.py projects weekly hours or blocks an approval that would breach them. (3) No role eligibility check: the request carries department and designation only by inheritance from Employee, and nothing validates them. POSITIVE CONTROL: 'Shift Request' resolves across shift_assignment_tool.json and the approval code, so the request/approval machinery IS present and a swap-target field would have been found on it. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_request/shift_request.json · retrieved 2026-09-06 adversarially verified
Reports per-employee sales performance metrics (average check, items or category attachment rate, void and comp rate) by server or cashier. differentiator
labor-server-performance-metrics
Searched the vendor's vocabulary over erpnext@v16.34.1: Sales Person, Sales Team, Sales Person-wise Transaction Summary, Item-wise Sales Register, owner. INVARIANCE supporting the partial: every POS Invoice carries the framework's owner field (the cashier who created it) and, as quoted here, a Sales Team child table plus sales_partner, so a sale can be attributed to a named person; erpnext ships sales_person_wise_transaction_summary (filters sales_person, doc_type, date range, company, item_group, brand, customer, territory) and sales_person_commission_summary against that attribution. Average check and per-person item mix are therefore derivable from shipped reports without custom code. INVARIANCE supporting the shortfall: void and comp rate per server is not a shipped metric and cannot be assembled from a shipped report -- there is no comp concept at all, a void is a docstatus-2 cancellation with no reason code and no shipped exception report, and \b(attachment rate|void rate|comp rate)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0. Nor is there any per-server scorecard view; the operator assembles the metrics from separate reports. POSITIVE CONTROL: sales_team and sales_partner resolve as real fields on this doctype and Sales Person resolves as its own doctype with five shipped reports, so per-person sales attribution IS modelled and a void-rate metric would have been found beside it. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Inventory, purchasing & cost control
Supports multi-level recipe/BOM costing where a recipe can contain sub-recipes (prep items) and plate cost recalculates automatically when any component ingredient's cost changes.
inventory-recipe-bom-costing
The BOM manual states that "each item (sub-assembly) could have its own BOM hence forming a tree of Items with multiple levels", exposes that tree through the Materials Required (Exploded) view, and documents the "Update Cost button" to "fetch the latest price/costs", adding that "BOM cost can also be set to be updated automatically via Manufacturing Settings". Multi-level sub-recipes with automatic parent-cost recalculation on component price movement, in a core module rather than a contracted add-on. Re-cited on verification from the repository landing page to the manual. https://docs.frappe.io/erpnext/bill-of-materials · retrieved 2026-08-02 adversarially verified
Stores purchase unit, recipe unit, and count unit per item with explicit conversion factors, plus a yield/waste percentage applied to raw-to-usable conversion.
inventory-unit-conversion-yields
Shortfall: no raw-to-usable yield or waste percentage. The multi-unit half is documented verbatim in the Item manual — "set an additional UoM with an appropriate conversion factor. For example, 500 Nos of screws = 1 Kilogram" — so purchase, recipe and count units with explicit conversion factors are native. BOM scrap and process loss do not fill the gap: scrap is "the scrap Item that will be created when manufacturing", and process loss applies when a scrap item matches the finished product, where "its quantity is subtracted from the manufactured Item quantity". That is shrinkage on a produced item’s output, not usable yield on a purchased ingredient. Downgraded from yes on verification. https://docs.frappe.io/erpnext/bill-of-materials · retrieved 2026-08-02 adversarially verified
Produces a theoretical-vs-actual usage variance report per item for a defined count period, showing theoretical usage from POS sales times recipe, actual usage from counts plus receipts, and the variance in both units and currency. differentiator
inventory-theoretical-vs-actual
Searched the vendor's vocabulary over erpnext@v16.34.1: Stock Ledger, Stock Reconciliation, difference_amount, expense_account, BOM, Work Order, Stock Entry (Material Consumption for Manufacture). INVARIANCE supporting the partial: each of the claim's three inputs exists natively. Actual movement is the Stock Ledger Entry table. Counts and their variance are Stock Reconciliation, whose section quoted here carries expense_account and difference_amount -- so a count posts its variance to a named difference account in currency, per count period, automatically. Theoretical usage exists as BOM explosion through Work Order and Material Consumption for Manufacture, which is exactly recipe-times-output. INVARIANCE supporting the shortfall: nothing joins them. There is no shipped report that takes POS sales times recipe and sets it against counts plus receipts -- \b(theoretical|usage variance|variance report)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- and the manufacturing route requires a Work Order per production run, which no restaurant raises per plate sold. The operator gets the raw ledgers and builds the report. POSITIVE CONTROL: difference_amount and expense_account resolve as real fields on this doctype and 'BOM' resolves across bom.py and the MRP report, so both halves of the arithmetic ARE present and searchable -- what is missing is the report that performs it. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json · retrieved 2026-09-06 adversarially verified
Depletes ingredient on-hand quantities in near real time as orders are fired at the POS, including depletion driven by modifier selections, not only in an end-of-day batch. differentiator
inventory-realtime-depletion
POS Profile binds a Warehouse and POS Invoice with Update Stock depletes on submit in real time — but only the sold item, or the Product Bundle's components. No modifier-driven depletion, because modifiers do not exist. https://docs.frappe.io/erpnext/pos-profile · retrieved 2026-08-01
Automatically 86s (marks unavailable) menu items on the POS, online ordering, and connected third-party delivery menus when a component ingredient hits zero or a configured threshold. differentiator
inventory-86-auto-sync
CHANGED FROM no. The prior rationale said 'nothing auto-86s'; the POS item-selector query falsifies that. Searched the vendor's vocabulary -- POS Profile, Bin, actual_qty, hide_unavailable_items -- across erpnext@v16.34.1. FINDING: point_of_sale.py's get_items joins Bin and, when the POS Profile flag hide_unavailable_items is set, filters the grid to (is_stock_item == 0) OR (Bin.warehouse == warehouse AND Bin.actual_qty > 0). An item whose on-hand in the terminal's warehouse reaches zero therefore disappears from the POS automatically, per profile, with no human action -- a real automatic 86 on the POS surface; pos_item_selector.js additionally colours each tile red/orange/green off actual_qty. WHAT IS ABSENT, and why this is not a yes: (a) the trigger is the sold item's own Bin quantity, not a component ingredient -- there is no BOM explosion in the POS availability path, so a menu item does not 86 when a shared ingredient runs out; (b) the threshold is hard-coded > 0, not configurable; (c) there is no second channel to sync to -- erpnext/patches/v15_0/delete_ecommerce_doctypes.py deletes Website Item and E Commerce Settings from core and redirects operators to the separate frappe/webshop app, and \b(doordash|uber ?eats|grubhub|deliveroo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns zero lines across erpnext@v16.34.1 and frappe@v16.33.0, so no third-party delivery menu exists in core to push availability to. POSITIVE CONTROL: allow_negative_stock resolves to 40 files / 157 lines, so stock-availability enforcement is present and searchable. Bound to core; Frappe Cloud restaurant apps (URY, POSNext, GETPOS) were not censused. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.py · retrieved 2026-09-06 adversarially verified
Supports full physical inventory, ad-hoc spot counts of a subset, and scheduled recurring cycle counts, with each count's variance recorded as separate history rather than overwriting prior counts.
inventory-count-modes
Searched the vendor's counting vocabulary over erpnext@v16.34.1: Stock Reconciliation, purpose, set_warehouse, scan_barcode, scan_mode. INVARIANCE supporting the partial: Stock Reconciliation is a submittable document whose purpose Select is quoted here -- Opening Stock or Stock Reconciliation -- and whose items table is free-form, so an operator may count every item in a warehouse or any subset of them; each count is its own submitted, immutable document with its own difference_amount and expense_account posting, so histories accumulate rather than overwrite, which is the part of the claim that is met. It also carries scan_barcode and scan_mode, so counts can be scanned. INVARIANCE supporting the shortfall: \b(cycle count|recurring count|count schedule)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0. Frappe does ship a generic recurring-document engine, Auto Repeat, and 11 erpnext doctypes opt into it by setting allow_auto_repeat: 1 (Sales Order, Purchase Order, Quotation, Journal Entry, Payment Entry, POS Invoice, Delivery Note, Purchase Receipt, Supplier Quotation and the two Subcontracting orders) -- Stock Reconciliation is NOT among them, so no scheduled recurring cycle count can be configured even by reuse. POSITIVE CONTROL: allow_auto_repeat resolves to 21 files / 29 lines, so the opt-in flag was visible to the search wherever it is set. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json · retrieved 2026-09-06 adversarially verified
Provides a mobile/tablet counting app supporting barcode or QR scanning that continues to accept counts with no network connectivity and syncs on reconnect.
inventory-mobile-count-offline
The claim is conjunctive -- mobile counting + barcode/QR scanning + accepts counts offline + syncs on reconnect -- and it fails on the offline half only. CORRECTION TO THE PRIOR RATIONALE: scanning is not keyboard-wedge-only. frappe@v16.33.0 ships frappe.ui.Scanner (frappe/public/js/frappe/scanner/index.js) which instantiates Html5Qrcode with facingMode 'environment', i.e. a real rear-camera barcode/QR scanner, and erpnext@v16.34.1 wires scan_barcode into Stock Reconciliation, Stock Entry and Pick List; Stock Reconciliation Item itself carries 'barcode' and 'has_item_scanned' fields. On any tablet browser that is a working mobile count-with-camera flow. INVARIANCE (the offline half): \b(service.?worker|indexeddb|workbox|localforage)\b returns zero real hits across erpnext@v16.34.1 and frappe@v16.33.0 -- the files matching the unanchored alternation are 'offline' in changelog prose, a Google Calendar comment and a phone-control string. serviceWorker|caches.open returns zero lines. The framework's entire notion of connectivity is the function quoted here: a synchronous read of navigator.onLine with no queue, no cache and no replay path, so a count taken with the server unreachable is simply lost. POSITIVE CONTROL: 'scan_barcode' resolves to 40 files / 75 lines, so client-side stock-counting code IS present and would have carried an offline buffer had one existed. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/public/js/frappe/dom.js · retrieved 2026-09-06 adversarially verified
Ships pre-built electronic vendor catalog and order-transmission integrations with named broadline distributors (e.g. Sysco, US Foods, Performance Food Group) that send purchase orders and receive invoices electronically rather than by emailed PDF. differentiator
inventory-vendor-catalogs-edi
DISCLOSURE FIRST, because a bare 'no EDI' sentence would be false: erpnext@v16.34.1 DOES ship a module literally named EDI (erpnext/modules.txt lists it last, after Subcontracting). I read it rather than counting it. The whole module is two doctypes, Code List and Common Code, plus a genericode importer; Code List's complete field_order is title / canonical_uri / url / default_common_code / version / publisher / publisher_id / description, and Common Code's is code_list / canonical_uri / title / common_code / description / additional_data / applies_to. That is an OASIS genericode code-list registry for mapping standard code values (the kind e-invoicing needs), and it contains no trading partner, no connection, no document type, no transmission and no catalogue import. INVARIANCE: \b(EDIFACT|X12|ANSI X12|punchout|cXML|Sysco|US Foods|Performance Food)\b returns zero lines across erpnext@v16.34.1 and frappe@v16.33.0 -- every hit on the wider alternation is the string 'edi' inside erpnext.edi module paths. Purchase Order transmission in core is email/print only. POSITIVE CONTROL: the same search finds erpnext.edi.doctype.code_list.code_list_import.import_genericode, so the EDI module's real contents were visible to it; and docs.frappe.io/erpnext/erpnext_integration, ERPNext's own Integration Categories page (updated 2026-02-26), enumerates every shipped integration and names no broadline distributor. Bound to core; the Frappe Cloud marketplace was not censused. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/edi/doctype/code_list/code_list.json · retrieved 2026-09-06 adversarially verified
Ingests supplier invoices from photo, PDF, or email and extracts line-item detail (item, quantity, unit, price) into the inventory ledger without manual line entry. differentiator
inventory-invoice-ocr
Searched \b(OCR|tesseract|optical character|invoice scan|document scan|extract line item)\b and (document_ai|azure form|textract|invoice_extract|parse_invoice|scan_invoice) across erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both. The second pattern returns zero lines. The first returns exactly two: a GL account named 'Accr-OCR Employee Card' in the Singapore F&B chart-of-accounts template (reader artefact) and the quoted error string in Bank Statement Import, which refuses a scanned document because it has no OCR. SCOPE NOTE ON THAT QUOTE, because it matters: Bank Statement Import ingests BANK STATEMENTS, not supplier invoices, so its error string corroborates that no OCR engine exists in the tree -- it does not itself establish that supplier-invoice ingestion is absent. That absence is carried by the corpus-wide zero plus the shape of the purchase path: Purchase Invoice is keyed by hand, imported from structured CSV/XLSX via Data Import, or created from a Purchase Receipt; no photo, PDF or email drop anywhere yields item/qty/uom/price lines, and no document-extraction engine of any kind exists in either repository. POSITIVE CONTROL: 'Bank Statement Import' resolves to 13 files / 37 lines, so ERPNext's only document-ingestion surface IS present and searchable, and it is the code that states the limit. Bound to core at these tags; the Frappe Cloud marketplace was not censused. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/bank_statement_import_log/bank_statement_import_log.py · retrieved 2026-09-06 adversarially verified
Tracks per-item purchase price history across invoices and alerts when a received price exceeds the prior or contracted price by a configurable threshold. differentiator
inventory-price-change-alerts
Searched the vendor's vocabulary over erpnext@v16.34.1 and frappe@v16.33.0: Item Price, Item-wise Purchase History, Purchase Analytics, Notification. INVARIANCE supporting the partial: erpnext ships item_wise_purchase_history whose filter set -- company, from_date, to_date, item_group, item_code and the supplier filter quoted here -- gives a per-item purchase price trail across invoices and receipts, and Item Price keeps dated price records per price list, so the history the claim asks for is native. The alerting primitive is native too: frappe's Notification doctype fires on channel Email / Slack / System Notification / SMS with an event Select that includes Value Change and a free-form condition evaluated against any field, so an operator can configure 'alert when rate exceeds X'. INVARIANCE supporting the shortfall: nothing ships pre-built. There is no Notification fixture for purchase price, no contracted-price field to compare against (\b(contract price|contracted price|price variance)\b returns ZERO lines), and no threshold setting anywhere -- the operator must write the condition themselves, and comparing to the PRIOR received price specifically requires a custom Server Script because Notification conditions see only the current document. POSITIVE CONTROL: Notification resolves as a real frappe doctype with 44 fields and item_wise_purchase_history as a shipped report, so both the history and the alert engine ARE present -- the pre-built join is what is absent. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/buying/report/item_wise_purchase_history/item_wise_purchase_history.js · retrieved 2026-09-06 adversarially verified
Maintains par levels per item per location and generates suggested purchase order quantities from on-hand versus par, with at least one mode driven by a sales forecast rather than a static par. differentiator
inventory-par-auto-suggest
Searched the vendor's vocabulary over erpnext@v16.34.1: Item Reorder, reorder level, Material Request, Production Plan, Sales Forecast. INVARIANCE supporting the partial: Item Reorder is a child table on Item and its complete field list is quoted here -- warehouse, warehouse_group, warehouse_reorder_level, warehouse_reorder_qty, material_request_type. That is a par level per item per location (and per warehouse GROUP, which is the multi-site case), with a suggested order quantity, and reorder_item runs on the scheduler to raise Material Requests automatically when on-hand falls below the level. Native, shipped, exactly as the claim's first half asks. INVARIANCE supporting the shortfall, and it is narrower than the prior rationale allowed: erpnext@v16.34.1 DOES ship forecast-driven demand -- a Sales Forecast doctype feeding Master Production Schedule, plus an Exponential Smoothing Forecasting report over Sales Order history -- so a forecast mode is not simply missing. What is missing is the connection: Sales Forecast generates demand into Master Production Schedule and the MRP report, and nothing wires it to Item Reorder or to purchase suggestion; and its finest bucket is Weekly, useless for a restaurant's ordering rhythm. POSITIVE CONTROL: warehouse_reorder_level resolves across item.py, the reorder scheduler and stock_settings, so par machinery IS present and a forecast-driven par field would have been found on this doctype. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/item_reorder/item_reorder.json · retrieved 2026-09-06 adversarially verified
Provides a structured waste/spoilage logging workflow with reason codes that debits inventory and reports waste cost separately from usage variance.
inventory-waste-logging
Searched the vendor's vocabulary -- Stock Entry, Stock Entry Type, Material Issue, expense_account -- over erpnext@v16.34.1, then the restaurant vocabulary. INVARIANCE: Stock Entry Type is a three-field doctype (purpose, add_to_transit, is_standard) and its purpose Select carries exactly thirteen values: Material Issue, Material Receipt, Material Transfer, Material Transfer for Manufacture, Material Consumption for Manufacture, Manufacture, Repack, Send to Subcontractor, Disassemble, Receive from Customer, Return Raw Material to Customer, Subcontracting Delivery, Subcontracting Return. Not one of them is Waste, Spoilage, Damage, Breakage or Scrap. What makes this a partial rather than a no is that is_standard is a flag on this doctype: an operator can create a non-standard Stock Entry Type named 'Waste' over the Material Issue purpose, which depletes inventory and debits the configured expense account -- a real, native, one-field setup step. What is absent is anything shipped: no reason-code taxonomy, no required reason field on the Stock Entry line, and no report that separates waste cost from usage variance. POSITIVE CONTROL: 'Material Issue' resolves across stock_entry.py, the Stock Entry Type fixtures and the perpetual-inventory GL code, so the entry-type machinery is present and searchable; a waste type would have been found among the thirteen had one shipped. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json · retrieved 2026-09-06 adversarially verified
Tracks expiration or use-by dates on received and prepped items and surfaces an expiring-soon report or alert before spoilage.
inventory-shelf-life-expiry
Only expiry survives. The Batch documentation covers expiry date and expiry-vs-posting-date filtering, but the retrieved page documents neither 'Shelf Life in Days' on Item, nor Batch-Wise Balance History, nor FEFO auto-selection. Three of the four specifics in the note are unsourced inference on a cell scored yes with no URL. https://docs.frappe.io/erpnext/batch · retrieved 2026-08-01 adversarially verified
Supports partial-bottle liquid inventory by weight (scale integration) or by bottle fraction for bar and beverage counting.
inventory-bar-partial-bottle
Both disjuncts of the claim were searched separately over erpnext@v16.34.1 + frappe@v16.33.0. By weight: \b(pour spout|weigh|weighing|weight scale|scale integration|serial port|RS.?232|USB HID)\b returns ZERO lines -- there is no scale, pour-spout or peripheral-device integration of any kind, and the brief's own warning holds ('scale' unanchored is 133 files of CSS transforms and 'grayscale'). By bottle fraction: \bbottle\b returns 16 lines in 3 files and all are test fixtures ('Water Bottle' in test_putaway_rule.py, 'Bottle Item A' in test_item_wise_inventory_account.py) -- no bar, beverage or depletion workflow. INVARIANCE: Stock Reconciliation Item, the line on which a physical count is recorded, is quoted here from field_order through valuation_rate: barcode, item_code, warehouse, qty, stock_uom, valuation_rate. It carries no weight, gross_weight or tare field; weight_uom and net_weight exist in this codebase only on shipping and billing lines (Packing Slip Item, Sales/Purchase Invoice Item) for freight, never on a count. Generic Float qty against a non-whole-number UOM does let an operator type 0.4, but that is arithmetic, not partial-bottle inventory. POSITIVE CONTROL: must_be_whole_number resolves to 22 files / 274 lines including 239 shipped UOMs in uom_data.json, so fractional-UOM machinery is present and searchable; the bar-specific layer is what is missing. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json · retrieved 2026-09-06 adversarially verified
Exports period COGS and accounts-payable invoice detail in a named accounting system's import format (e.g. QuickBooks, Sage Intacct, NetSuite) with GL account mapping configurable per item category.
inventory-cogs-gl-export
Searched the vendor's vocabulary -- Item Default, perpetual inventory, expense_account, default_cogs_account, Item Group -- over erpnext@v16.34.1. INVARIANCE supporting the partial: Item Default is a child table hanging off Item (and mirrored on Item Group) keyed by company, and its field list quoted here carries default_warehouse, default_inventory_account, buying_cost_center, expense_account, purchase_expense_account, expenses_added_to_stock_account, selling_cost_center, income_account and default_cogs_account. GL account mapping per item and per item category, per company, is therefore native and configurable exactly as the claim asks, and under perpetual inventory the COGS posting is made automatically at delivery -- so the mapping half is fully met and the export half is mostly moot because ERPNext IS the ledger. INVARIANCE supporting the shortfall: \bquickbooks\b returns exactly ONE line in erpnext@v16.34.1 and it is a 'which system are you coming from' option in setup_wizard.js; there is no Intacct or NetSuite string anywhere; and docs.frappe.io's own QuickBooks Migrator page is now headed 'Deprecated', stating the built-in migrator was removed from ERPNext on 2025-01-17. So there is no ongoing mapped journal-entry sync to any named external GL, in either direction. POSITIVE CONTROL: 'Item Default' and default_cogs_account both resolve to real fields on this doctype, so per-item GL mapping was visible to the search. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/item_default/item_default.json · retrieved 2026-09-06 adversarially verified
Inventory and recipe costing are delivered natively by the POS vendor rather than requiring a separately-contracted third-party product (e.g. MarginEdge, MarketMan, Restaurant365) to function. differentiator
inventory-native-not-partner
Inventory, purchasing, BOM costing and manufacturing are core modules of the same free application. No MarginEdge/MarketMan/R365 equivalent contract needed. https://github.com/frappe/erpnext · retrieved 2026-08-01
Reporting, BI & data access
Provides a live sales dashboard reflecting transactions within minutes of the sale, accessible from both a browser and a mobile app off-premise.
reporting-realtime-dashboard
Searched the vendor's vocabulary -- Dashboard, Dashboard Chart, Number Card, Workspace -- over frappe@v16.33.0. INVARIANCE supporting the partial: frappe/desk/doctype ships dashboard, dashboard_chart, dashboard_chart_source, dashboard_chart_link, dashboard_settings, number_card and number_card_link, plus workspace_chart and workspace_number_card for placement. The Number Card field list quoted here binds a card to a document_type or report_name with an aggregate_function_based_on, a stats_time_interval and dynamic filters -- these are live queries against the live table, so a POS Invoice submitted now is in the figure on the next refresh, which is the 'within minutes' half of the claim. The Frappe desk is responsive and reachable over the public URL, so a browser on a phone off-premise works. INVARIANCE supporting the shortfall: there is no owner-facing mobile sales application. \b(service.?worker|indexeddb|workbox)\b returns zero real hits in erpnext@v16.34.1 or frappe@v16.33.0 -- notably, frappe/hrms@v16.17.1 DOES ship a PWA with frontend/public/sw.js and an InstallPrompt.vue, which shows Frappe builds installable mobile front ends when it wants to, and has built none for sales. POSITIVE CONTROL: 'Auto Email Report', Dashboard Chart and Number Card all resolve as shipped doctypes, so the reporting-surface search was working. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/desk/doctype/number_card/number_card.json · retrieved 2026-09-06 adversarially verified
Generates a daily close-out/EOD report reconciling gross sales, net sales, tax, tips, discounts, refunds, tender types, and expected cash deposit in one document.
reporting-eod-closeout
Shortfall: tips. POS Closing Entry is a single submitted document carrying period_start_date and period_end_date, the linked POS Opening Entry, pos_profile, the cashier, the POS Invoice and Sales Invoice transaction tables, a taxes table, total_quantity, net_total, total_taxes_and_charges, grand_total and a payment_reconciliation table of expected versus closing amount per Mode of Payment. Against a claim covering gross sales, net sales, tax, tips, discounts, refunds, tender types and expected cash deposit, everything is present except tips — POS Invoice enumerates no tip or gratuity field, so none is ever captured. Partial upheld on verification but re-evidenced at primary-source level: the earlier objection was that the mechanism was unverified, and it now is. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json · retrieved 2026-08-02 adversarially verified
Provides a product mix (PMIX) report at individual menu item AND modifier level with quantity, gross and net sales, filterable by daypart and revenue center.
reporting-pmix-modifier-level
Searched the vendor's report vocabulary over erpnext@v16.34.1: Item-wise Sales Register, Sales Analytics, Gross Profit. INVARIANCE supporting the partial: Item-wise Sales Register's complete filter set is from_date, to_date, customer, company, mode_of_payment, warehouse, brand, item_code, item_group, group_by and income_account -- per-item quantity, gross and net by period, which is the PMIX core. INVARIANCE supporting the shortfall, and it is two separate absences. (1) Modifier level: there is no modifier concept to report on -- Item Variant and Attribute are a purchasable-SKU matrix, not an order-time modifier, and no Sales Invoice Item or POS Invoice Item field carries a modifier or option line. (2) Daypart and revenue centre: \b(daypart|revenue center|revenue centre)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0, and the finest time bucket any shipped sales report offers is a week -- Sales Analytics' Range Select is Weekly / Monthly / Quarterly / Yearly. The filters quoted here are date-range only, with no time-of-day dimension. POSITIVE CONTROL: mode_of_payment and warehouse resolve as real filters on this same report, so dimension filters ARE modelled here and a daypart would have been found among them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js · retrieved 2026-09-06 adversarially verified
Produces an audit report of comps, voids, discounts, and price overrides attributed to the employee who applied them and the manager who approved them, with reason codes and timestamps.
reporting-comps-voids-audit
Searched the vendor's vocabulary over erpnext@v16.34.1 and frappe@v16.33.0: Version, track_changes, amended_from, docstatus, apply_discount_on. INVARIANCE supporting the partial: POS Invoice is submittable and declares "track_changes": 1, so every field-level edit lands in a frappe Version record (ref_doctype, docname, data) attributed to a user with a timestamp; a cancellation sets docstatus 2 and any correction becomes a new document carrying amended_from, so voids and amendments are permanent and attributed. The discount region quoted here -- coupon_code, apply_discount_on, base_discount_amount, additional_discount_percentage, discount_amount -- is likewise versioned, so a price override is recoverable. INVARIANCE supporting the shortfall: there is no reason field and no approver field anywhere in POS Invoice's 185-field field_order, no reason-code doctype exists (\b(reason code|void reason|comp reason)\b returns zero lines), and no shipped report aggregates comps, voids, discounts and overrides into an exception listing -- reconstructing one means querying Version blobs by hand. POSITIVE CONTROL: track_changes resolves as a real DocType property and Version ships as a core frappe doctype, so the audit machinery was visible to the search; what is missing is the reason taxonomy, the approver and the packaged report. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Reports cash over/short per drawer, per shift, and per employee, comparing counted cash to expected cash from tendered transactions and paid-outs.
reporting-cash-over-short
POS Closing Entry Detail carries exactly five fields — mode_of_payment, opening_amount, expected_amount, closing_amount and difference — giving counted-versus-expected per tender type. Its parent POS Closing Entry carries period_start_date, period_end_date, the linked POS Opening Entry, pos_profile and a user field labelled "Cashier", so the over/short figure resolves per drawer, per shift and per employee. Upgraded from partial on verification: the mechanic is real but had only ever been sought on the thin POS manual page, which documents none of it. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json · retrieved 2026-08-02 adversarially verified
Reports sales per labor hour and labor cost as a percentage of sales by hour, by department, and by employee, using actual clocked hours from the POS time clock.
reporting-labor-productivity
Two absences, searched separately. (1) The join: zero word-boundary hits for 'labour cost'|'labor cost'|labor_cost across erpnext@v16.34.1, frappe@v16.33.0 and hrms@v16.17.1, and enumeration of Frappe HR's 29 shipped report directories finds only Project Profitability joining labour cost to revenue -- via Sales Invoice Timesheet and a submitted Salary Slip, a professional-services construct with no path to POS Invoice or to Employee Checkin hours. Nothing computes sales per labour hour or labour cost as a percentage of sales, by any dimension. (2) The granularity: the claim asks for these figures BY HOUR, and the corpus cannot express an hour on the sales side at all. INVARIANCE: Sales Analytics -- ERPNext's principal sales-trend report -- offers the complete Range option set quoted here, Weekly / Monthly / Quarterly / Yearly, with no daily and no hourly bucket; \b(hourly|per hour|hour of day|by hour)\b across both repositories resolves only to scheduler cron types, Workstation hour_rate and Project costing_hours. POSITIVE CONTROL: 'Sales Person' and 'Item-wise Sales Register' both resolve as shipped reports and Sales Analytics groups by Customer/Item/Territory, so per-dimension sales reporting IS present -- the labour dimension and the hour bucket are what is absent. Bound to these three repositories at these tags. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/sales_analytics/sales_analytics.js · retrieved 2026-09-06 adversarially verified
Reports per-server metrics including average check, items per check, attachment rate for named categories, and tips as a percentage of sales. differentiator
reporting-server-scorecards
Searched the vendor's vocabulary over erpnext@v16.34.1: Sales Person, Sales Team, Item Group, Brand, Territory. INVARIANCE supporting the partial: sales_person_wise_transaction_summary is a shipped report whose filters -- quoted here from sales_person through the document-type selector -- run sales_person, doc_type, from_date, to_date, company, item_group, brand, customer, territory and show_return_entries, and POS Invoice carries a Sales Team child table plus the framework owner field. Average check and items per check per named person are therefore derivable from a shipped report, and sales_person_target_variance_based_on_item_group adds a target comparison. INVARIANCE supporting the shortfall, two absences that are qualitatively different. (1) Attachment rate for named categories: the report slices BY item_group, but nothing computes the ratio of checks containing a category to all checks -- \b(attachment rate|attach rate)\b returns ZERO lines. (2) Tips as a percentage of sales: impossible, because \btips?\b returns 21 lines across erpnext@v16.34.1 + frappe@v16.33.0 and every one is a reader artefact -- UI hint strings, leaflet popup-tip CSS, a workflow comment -- bar a Singapore F&B chart-of-accounts GL account named 'Accr-Tips'; no tip amount is captured on any document. There is also no scorecard view: the operator reads three reports. POSITIVE CONTROL: item_group and territory resolve as real filters here, so per-person dimensional slicing IS present. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js · retrieved 2026-09-06 adversarially verified
Reports revenue and margin by fulfillment channel — dine-in, direct online, first-party delivery, and each third-party marketplace separately — net of marketplace commission fees. differentiator
reporting-channel-profitability
Searched the restaurant channel vocabulary over erpnext@v16.34.1 + frappe@v16.33.0: \b(daypart|revenue center|revenue centre|fulfillment channel|order channel|sales channel)\b returns ZERO lines. DISCLOSURE of the near-misses I checked and rejected: POS Invoice does carry utm_source, sales_partner, commission_rate, amount_eligible_for_commission and total_commission -- but utm_source is marketing campaign attribution (renamed from Lead Source), not a fulfilment channel, and Sales Partner commission is a broker payout the operator configures, not marketplace commission data, because no marketplace exists to supply it: \b(doordash|uber ?eats|grubhub|deliveroo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns zero lines across both repositories and core's own e-commerce doctypes were deleted in erpnext/patches/v15_0/delete_ecommerce_doctypes.py. INVARIANCE: Gross Profit, the only shipped report that computes margin per sale, exposes the complete Group By option set quoted here -- Invoice, Item Code, Item Group, Brand, Warehouse, Customer, Customer Group, Territory, Sales Person, Project, Cost Center, Monthly, Payment Term -- and no channel, order-type or fulfilment dimension appears in it. An operator could repurpose Cost Center or an Accounting Dimension as a channel, but that is configuration, not a shipped report, and there would still be no commission figure to net out. POSITIVE CONTROL: this same file resolves group_by options for Sales Person and Cost Center, so dimension filters ARE modelled here and a channel would have been found among them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/gross_profit/gross_profit.js · retrieved 2026-09-06 adversarially verified
Supports scheduling any report for automatic recurring delivery by email or to a shared destination on a defined cadence and recipient list.
reporting-scheduled-delivery
CHANGED FROM unknown, and this is the cell whose prior note complained of a URL-less 'inferred' yes -- so it is now grounded on the doctype JSON itself. Searched the vendor's name for the feature, 'Auto Email Report', over frappe@v16.33.0 (3,634 files): 16 files / 41 lines, the doctype living at frappe/email/doctype/auto_email_report. INVARIANCE, read off its field list rather than off prose: report is a Link to Report (so ANY Query Report or Script Report qualifies, which is the claim's 'any report'); email_to is a required Small Text recipient list; frequency is a required Select whose complete option set is Daily / Weekdays / Weekly / Monthly, with day_of_week Monday..Sunday for the weekly case; format is a required Select of HTML / XLSX / CSV / PDF; enabled, send_if_data, no_of_rows, filters and dynamic_date_period round it out. Cadence, recipient list and delivery format are therefore all first-class configured fields, not an inference. POSITIVE CONTROL: the same doctype resolves in frappe/workspace_sidebar/automation.json (it is surfaced in the Automation workspace) and in three erpnext v13 patches that clean up Auto Email Reports pointing at deleted reports -- i.e. the feature is old enough that ERPNext ships migration code for it. Bound to frappe@v16.33.0; the delivery target is email, and a shared-destination drop is not offered. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/auto_email_report/auto_email_report.json · retrieved 2026-09-06 adversarially verified
Publishes a documented public REST or GraphQL API covering orders, payments, menu, and labor data, with self-service developer credentials obtainable without a signed partner agreement. differentiator
reporting-public-api
REST endpoints are auto-generated for every DocType, covering orders, invoices, payments, items, prices and customers, and API keys are self-generated by any user from User Settings > API Access with no partner agreement and no sales call. Caveat carried on verification: the labor half of the claim depends on installing Frappe HR, a separate — free, first-party — application, rather than being available out of the box. https://docs.frappe.io/framework/user/en/api/rest · retrieved 2026-08-02 adversarially verified
Emits outbound webhooks for order and payment lifecycle events to a customer-supplied endpoint, with documented retry behavior and payload signature verification. differentiator
reporting-webhooks
Shortfall: no documented retry or backoff behaviour, which the claim requires alongside signature verification. The signature half is documented — the Webhook doctype fires on document lifecycle events and, when a secret is set, adds an X-Frappe-Webhook-Signature header whose value is "a base64-encoded HMAC-SHA256 hash of the payload". The guide states only that "a webhook request log is created for every successful request"; failed deliveries are neither logged nor retried on any retrievable page. Downgraded from yes on verification, for consistency with extensibility-webhook-reliability, which scores the same evidence partial. https://docs.frappe.io/framework/user/en/guides/integration/webhooks · retrieved 2026-08-02 adversarially verified
API and raw-data access are included in the standard subscription rather than gated behind an additional per-location fee, revenue share, or enterprise-only contract. differentiator
reporting-api-not-upcharged
API reference: Frappe "generates REST API for all of your DocTypes out of the box" - GET /api/resource/:doctype for lists (filters, pagination, sorting), CRUD on /api/resource/:doctype/:name, /api/method/ for whitelisted methods, authenticated by per-user api_key:api_secret token, cookie session or OAuth bearer. No plan tier, entitlement flag or per-location gate appears anywhere in the API contract; the ERPNext manual's Data Export page separately documents extracting any DocType's records to CSV or Excel with field selection and filters. GPL-3.0 source, so self-hosted use carries no fee at all. https://docs.frappe.io/framework/user/en/api/rest · retrieved 2026-08-06 adversarially verified
Core reporting beyond basic sales summaries — labor vs sales, PMIX, comps/voids audit, multi-location comparison — is available on the entry-level paid plan rather than requiring a higher tier or an add-on analytics SKU. differentiator
reporting-tier-paywall
Shortfall: nothing is paywalled, but two of the four reports the claim names are not shipped in any tier. There are no software feature tiers — the whole reporting surface is in the free GPL-3.0 application and Frappe Cloud prices compute and isolation rather than features — so no report can sit behind an upgrade. PMIX (Item-wise Sales Register) and multi-location comparison (Consolidated Financial Statement, cross-company filters) exist; labor-versus-sales does not exist at all (reporting-labor-productivity) and comps/voids has no packaged exception report (reporting-comps-voids-audit). Regraded C on verification: a vendor pricing page is the only source for the no-tiers fact, and grade C cannot carry a differentiator yes. https://frappe.io/erpnext/pricing · retrieved 2026-08-02 adversarially verified
Documents a historical retention window of at least 24 months of transaction-level detail queryable in the reporting UI, with no silent truncation or archive retrieval fee. differentiator
reporting-history-retention
Searched Log Settings, Logs To Clear, clear_old_logs, retention, purge, archive over frappe v16.33.0 and erpnext v16.34.1 (tree API truncated:false for both). INVARIANCE SUPPORTING THE PARTIAL: truncation is not merely absent, it is structurally impossible for transactions. The only retention machinery frappe ships is Log Settings, whose child table Logs To Clear takes a ref_doctype and a 'Clear Logs After (days)' integer -- and as the quoted code shows, a doctype qualifies only if its controller satisfies the LogType Protocol by implementing a clear_old_logs static method. log_settings.py's remove_unsupported_doctypes() actively DELETES any entry whose doctype does not, with the message 'does not support automated log clearing'. POS Invoice, Sales Invoice, Stock Ledger Entry and GL Entry implement no such method, so they can never be scheduled for deletion; nothing archives them, and the operator owns the database, so no archive-retrieval fee can exist. CORRECTED INVARIANCE SUPPORTING THE SHORTFALL: it is not true that the vendor is silent on retention. Over the full 1,863-page docs.frappe.io census (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) the phrase resolves in eight documents, and the one that matters is the Frappe Cloud Service and Support Agreement, whose clause 6.9 is headed 'Data Retention & Deletion' and reads in full: 'The Customer Data shall be retained in accordance with the subscribed plan for Cloud Hosting, or otherwise deleted upon Customer request submitted via the support portal.' So the vendor addresses retention and declines to state a window, deferring to plan documentation; the Cloud space's own retention numbers are 14-day MariaDB binlogs, 48-hour server snapshots and a 7-daily/4-weekly offsite backup rotation, none of which is a transaction-detail retention commitment. The 24-month guarantee is therefore architectural, not contractual. POSITIVE CONTROL: Log Settings and clear_old_logs both resolve across frappe core, so the purge machinery IS present and searchable; it reaches logs only. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/core/doctype/log_settings/log_settings.py · retrieved 2026-09-06 adversarially verified
Sends proactive push or email alerts when an operator-configured metric breaches a threshold or deviates from its historical pattern (e.g. void spike, sales below forecast, discount rate anomaly). differentiator
reporting-anomaly-alerts
Searched the vendor's vocabulary over frappe@v16.33.0: Notification, condition, Value Change, channel, Server Script. INVARIANCE supporting the partial: the Notification doctype's 'Send Alert On' Select is quoted here in full -- New, Save, Submit, Cancel, Days After, Days Before, Minutes After, Minutes Before, Value Change, Method, Custom -- against any document_type, with a free-form condition expression, a recipients table, and a channel Select of Email / Slack / System Notification / SMS. So an operator-configured threshold alert (a discount above N, a cancellation, a value that changed) is genuinely configurable with no code, on four delivery channels including push-style System Notification. INVARIANCE supporting the shortfall: every trigger in that list is a document event or a fixed date/time offset. There is no aggregate trigger, no baseline and no statistical comparison -- \b(anomaly|deviation|standard deviation|z.score|seasonal|baseline)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- so 'deviates from its historical pattern' and 'sales below forecast' are unreachable without a custom Server Script, and there is no forecast at daily granularity to compare against anyway (Sales Forecast's finest frequency is Weekly). POSITIVE CONTROL: 'Value Change' and the condition field both resolve on this doctype, so the alert engine IS present and an anomaly mode would have been found in its event list. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/notification/notification.json · retrieved 2026-09-06 adversarially verified
Offers a natural-language query or AI assistant that answers ad-hoc questions against the operator's own sales and labor data and returns a figure or chart, not a generic help-article response.
reporting-nl-query
SCOPE, stated because it cuts against the verdict: frappe/insights is not cited anywhere in this record's claims, so it is a separate first-party app the record does not treat as in scope; it was checked anyway rather than leaving the cell open. INVARIANCE, CORE (this is the part that carries the verdict): \b(openai|anthropic|LLM|natural language|text-to-sql|copilot|ai assistant)\b returns ZERO lines across erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files), tree API truncated:false for both. INVARIANCE, INSIGHTS, and it is weaker: the GitHub tree API answers truncated=false for frappe/insights at v3.13.2 with 1,263 paths, and no path segment contains ai, llm, openai, anthropic, chat, copilot or nlq as a word -- the nearest hits are frontend/src/query/visual/useAssistedQuery.js and insights/doctype/insights_query/insights_assisted_query.py, which are the VISUAL query builder, not an assistant, and are the trap on this cell. That is a FILENAME census, so it bounds the app's structure and not its behaviour. The README's four Key Features -- Connect Multiple Sources, Query Builder ('create queries without any SQL knowledge... select tables, add joins, apply filters'), Visualizations and Dashboards, Database Support -- describe a click-driven builder, which removes SQL by clicking rather than by asking; 'natural language', 'chat', 'ask' and 'assistant' appear nowhere in it. A README is a summary document and its silence is not exhaustive. https://raw.githubusercontent.com/frappe/insights/v3.13.2/README.md · retrieved 2026-09-06 adversarially verified
Reports guest-level analytics including new versus returning guest counts, visit frequency, and lifetime spend cohorts tied to identifiable guest records from loyalty or online ordering. differentiator
reporting-guest-cohorts
Searched the vendor's vocabulary over erpnext@v16.34.1: Customer, Customer Group, Loyalty Program, Customer Acquisition and Loyalty, territory. INVARIANCE supporting the partial: the report quoted here ships with columns New Customers, Repeat Customers, Total, New Customer Revenue, Repeat Customer Revenue and Total Revenue, bucketed by Year and Month and sliceable by Territory -- so new-versus-returning counts and their revenue split against real identifiable Customer records are native, and POS Invoice links a Customer, with Loyalty Program giving a points ledger to identify the guest at the till. INVARIANCE supporting the shortfall: the report stops at new-versus-repeat. There is no visit-frequency distribution (no count-of-visits bucketing anywhere), no lifetime-spend cohort and no recency/frequency/monetary segmentation -- \b(cohort|RFM|lifetime value|\bLTV\b|visit frequency)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- and the month buckets are calendar periods, not signup cohorts followed forward, which is what the claim means by cohort. Nor is there an online-ordering channel in core to tie guests from: the e-commerce doctypes were deleted in erpnext/patches/v15_0/delete_ecommerce_doctypes.py. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files / 58 lines and this report resolves as a shipped Script Report, so guest-level analytics ARE present and a cohort view would have been found among them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py · retrieved 2026-09-06 adversarially verified
Produces a forward sales forecast at daypart or hourly granularity from the location's own history, exposed in the reporting UI and consumable by scheduling or ordering workflows. differentiator
reporting-sales-forecast
CHANGED FROM no. The prior rationale said 'no shipped forward sales forecast'; erpnext@v16.34.1 ships two. Searched \bforecast over the corpus: 17 files, and reading them finds (a) the Exponential Smoothing Forecasting report -- a standard Script Report, ref_doctype Sales Order, roles including Sales Manager and Sales User, which projects forward demand from the company's own order history; and (b) a Sales Forecast doctype with a Generate Demand action feeding Master Production Schedule and the Material Requirements Planning report, i.e. a forecast that IS consumable by an ordering workflow, which is the claim's second half. So 'exposed in the reporting UI' and 'consumable by ordering workflows' are both satisfied, and 'from the location's own history' is satisfied per Company and parent_warehouse. WHAT FAILS is granularity, and it fails hard. INVARIANCE: Sales Forecast's frequency selector -- quoted here in full -- offers exactly Weekly and Monthly; Exponential Smoothing Forecasting's periodicity offers Monthly / Quarterly / Half-Yearly / Yearly defaulting to Yearly; Sales Analytics' Range offers Weekly / Monthly / Quarterly / Yearly. The finest forward bucket anywhere in the product is a week, and \b(daypart|hourly|hour of day|by hour)\b returns no sales-side hit at all. A restaurant asking for a Friday-6pm forecast gets nothing. POSITIVE CONTROL: the same \bforecast search resolves Master Production Schedule and the MRP report, so forecasting machinery is present and searchable -- it is dimensioned for manufacturing, not for service. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/manufacturing/doctype/sales_forecast/sales_forecast.json · retrieved 2026-09-06 adversarially verified
Generates payroll- and tax-ready tip reporting: declared versus charged tips per employee, tip pool distribution detail, and a tax liability summary by jurisdiction.
reporting-tip-tax-compliance
This cell is downstream of the tip-capture absence, so I grounded that absence rather than the report. \btips?\b over erpnext@v16.34.1 + frappe@v16.33.0 returns 21 lines in 12 files, every one a reader artefact (UI hint strings 'Tip:', leaflet popup-tip CSS, '# TIP:' workflow comments, a test fixture) except one GL account named 'Accr-Tips' in the Singapore F&B chart-of-accounts template -- an account to post to, with nothing that computes a posting. Over hrms@v16.17.1 the same anchored pattern returns ZERO lines, and \bgratuit in hrms is the UAE/India end-of-service severance doctype, not a restaurant gratuity. INVARIANCE: the POS Invoice payments region quoted here -- outstanding_amount, payments_tab, payments_section, cash_bank_account, payments, base_paid_amount, paid_amount, base_change_amount, change_amount -- is the complete money-in area of the sale and carries no tip, gratuity, declared-tip or service-charge field. With no declared and no charged tip amount recorded on any document, there is no declared-versus-charged report, no pool-distribution detail and no tip tax liability summary to generate; and hrms/regional contains only india and united_arab_emirates, so there is no US jurisdiction model either. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files and Mode of Payment ships its own doctype with types Cash/Bank/General/Phone, so POS tender concepts ARE modelled and a tip tender would have been found among them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json · retrieved 2026-09-06 adversarially verified
Multi-location, franchise & enterprise governance
Supports a named organizational hierarchy of at least three levels (e.g. enterprise > region/group > location) as a first-class object that reporting and permissions can be scoped to, not just a flat list of locations.
multi-location-org-hierarchy
Documented verbatim at the current URL: "Open the Company tree view. Select New to create an independent Company, or select a group and use Add Child to create a subsidiary under it." Field behaviour: "Enable Is Group only for a parent used to organize child companies. A group does not post normal business transactions." and "Select a Parent Company when the entity belongs to a group structure." On structuring the group: "Use sibling Companies for entities at the same level. Use a parent and child structure for subsidiaries." and the Parent Company field "Places the entity under a group for consolidated navigation and reporting." Re-pointed 2026-08-09 from /erpnext/company, which 301s here. RE-TRANSCRIBED 2026-08-14: the page was rewritten between the 2026-08-13 and 2026-08-14 drift runs (visible text 47,236 -> 42,859 chars) and the five sentences previously quoted here no longer appear verbatim; every concept they carried is still documented on the same page, so the verdict is unchanged and only the wording was restated. https://docs.frappe.io/erpnext/company-setup · retrieved 2026-08-14 adversarially verified
Supports price tiers/zones so one menu item carries different prices per location group, per order channel, and per daypart without duplicating the item record.
multi-location-price-zones
Shortfall: no daypart dimension. One Item carries many Item Price rows selected per company, currency, customer group, territory and POS Profile, so per-location-group pricing works with no item duplication. Time-of-day pricing does not: Pricing Rule’s only temporal control is a Valid From / Valid Up To date range, with no time-of-day or day-of-week condition (menu-pricing-dayparting). Downgraded from yes on verification. https://docs.frappe.io/erpnext/pricing-rule · retrieved 2026-08-02 adversarially verified
Provides above-store reporting that aggregates sales, labor, discounts, voids, and item mix across any selected set of locations in one view, with store-vs-store ranking and variance flags.
multi-location-consolidated-reporting
Searched the vendor's vocabulary over erpnext@v16.34.1: Consolidated Financial Statement, Company tree with is_group, accumulated_in_group_company. INVARIANCE supporting the partial: erpnext ships consolidated_financial_statement and consolidated_trial_balance, whose filter set is company, filter_based_on, period start/end, fiscal years, finance_book, report, presentation_currency, and the accumulated_in_group_company checkbox quoted here -- so above-store rollup across a group-company tree, in one presentation currency, is genuinely native, and Sales Analytics / Item-wise Sales Register filter by company for the sales side. INVARIANCE supporting the shortfall: the consolidation is a GL consolidation. Labour never enters it (Frappe HR is a separate app; \b'labour cost'|'labor cost'\b returns zero lines in all three repositories), there is no discount or void rollup, and there is no store-versus-store ranking or variance flag -- \b(variance flag|store ranking|benchmark)\b returns zero lines, and every shipped comparison report ranks item groups, sales persons or territories, never locations. POSITIVE CONTROL: accumulated_in_group_company and presentation_currency resolve as real filters in this same file, so above-store options ARE modelled here and a store-ranking option would have been found among them. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js · retrieved 2026-09-06 adversarially verified
Gift cards issued at one location are redeemable at any other location in the brand, with a reported outstanding-liability balance and inter-store settlement/redemption reconciliation between owners.
multi-location-cross-location-giftcard
DISCLOSURE FIRST, because the prior rationale ('no gift card product') is wrong as written: erpnext@v16.34.1 ships a Coupon Code doctype whose coupon_type is DF.Literal['Promotional', 'Gift Card'], and coupon_code.py has a dedicated Gift Card branch that generates a 10-character hash code. I read it rather than stopping at the label. What that branch actually does is force maximum_use = 1 and require a Customer. INVARIANCE: the Coupon Code field_order quoted here is complete -- coupon_name, coupon_type, customer, coupon_code, from_external_ecomm_platform, pricing_rule, valid_from, valid_upto, maximum_use, used, description -- and there is no monetary value on the record at all: no face amount, no remaining balance, no partial redemption, no expiry-to-breakage posting and no liability account. ERPNext's 'Gift Card' is a single-use customer-bound discount voucher backed by a Pricing Rule, not a stored-value instrument. Consequently the claim's substance fails: there is no outstanding-liability balance to report (\b(stored value|breakage)\b returns zero lines across both repositories) and no inter-store settlement, and the cross-location half is degenerate rather than met -- one Frappe site holds one Coupon Code table shared by every Company, so a code is 'redeemable anywhere' only because nothing scopes or settles it. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files / 58 lines with a real points ledger and expiry, so ERPNext DOES model a customer-value instrument with a balance -- it just is not a gift card. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/coupon_code/coupon_code.json · retrieved 2026-09-06 adversarially verified
A single customer loyalty profile, balance, and stored order history is shared across all locations in the brand rather than being per-location.
multi-location-cross-location-loyalty
A single Customer's Loyalty Point Entry ledger spans every POS Profile and warehouse in the company, so cross-store loyalty works within a brand on one site. Loyalty Program is scoped per Company, so a multi-company franchise group does not share one balance. https://docs.frappe.io/erpnext/loyalty-program · retrieved 2026-08-01
A single location/terminal can operate two or more distinct brands or virtual brands with separate menus, receipts/branding, and separately reportable revenue, on the same hardware and drawer. differentiator
multi-location-multi-brand
Searched the vendor's vocabulary over erpnext@v16.34.1: POS Profile, Company, Letter Head, Print Format, Item Group, Warehouse. INVARIANCE supporting the partial: multiple Companies on one site is native and is the standard multi-brand arrangement -- each Company has its own Letter Head, its own Print Format selection on the POS Profile, its own account tree and its own separately reportable revenue, and the Consolidated Financial Statement rolls them up. Two brands on one site with separate branding and separate books is therefore real. INVARIANCE supporting the shortfall, read off the artefact quoted here: POS Profile's field_order opens with company, and company is declared reqd: 1, as is warehouse. A terminal's profile binds to exactly ONE Company and ONE Warehouse, and point_of_sale.py resolves items, prices and stock through that single profile for the whole session. To sell the second brand the cashier must close the session and open a different POS Profile, which also means a different POS Opening/Closing Entry and therefore a different drawer reconciliation -- so 'same hardware and drawer, simultaneously' fails at the doctype level, not merely in practice. \b(virtual brand|multi.?brand|concept)\b returns ZERO lines in erpnext@v16.34.1. POSITIVE CONTROL: company and warehouse both resolve as required Link fields on this doctype, so the binding IS modelled and a multi-company POS Profile would have shown as an optional or table field. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-09-06 adversarially verified
Tax configuration is per-location with support for multiple simultaneous tax rates, jurisdiction-specific rules (e.g. prepared-food vs grocery, inclusive vs exclusive tax), and per-location tax exemptions.
multi-location-multi-tax-jurisdiction
Shortfall: no per-location tax configuration, no documented inclusive-versus-exclusive setting and no per-location exemption. Tax Rule selects a Sales Taxes and Charges Template by Customer or Supplier, by billing and shipping addresses "fetched if saved in the Customer/Supplier master", and by Tax Category — "Setting a Tax Category allows applying multiple Tax Rules to a transaction based on different factors" — and setting an Item or Item Group on the rule covers the prepared-food-versus-grocery class distinction. Matching keys on the party’s address rather than the selling store, and the manual documents none of the other three elements. Downgraded from yes on verification. https://docs.frappe.io/erpnext/tax-rule · retrieved 2026-08-02 adversarially verified
Labor rules (overtime, break enforcement, predictive-scheduling compliance) are configurable per location or location group and enforced at the terminal, not just reported after the fact.
multi-location-central-labor-policy
SCOPE: Frappe HR is in scope for this record (product.yaml already cites github.com/frappe/hrms for labor cells), so I censused frappe/hrms@v16.17.1 -- tree API truncated=false at 1,552 blobs -- rather than inferring from erpnext alone. Searched the three things the claim names. Overtime: Shift Type carries allow_overtime and overtime_type, so an overtime CONCEPT exists. Break enforcement: \b(meal break|rest break|meal period|break penalty|premium pay|attestation)\b returns zero lines and (break_time|break_duration|unpaid_break) returns zero -- the 708 unanchored 'break' lines are all column_break/section_break. Predictive scheduling: zero hits for predictive scheduling, fair workweek or advance notice. INVARIANCE, and it is sharper than the prior rationale: Shift Type's complete 27-field field_order, quoted here through the auto-attendance block, has no company and no location field at all. Shift rules in Frappe HR are not per-location or per-location-group; they are global to the site, and only Shift Assignment (the per-employee record) carries a company. So the claim's premise fails one level earlier than 'not enforced at the terminal'. On enforcement, the POS is erpnext's Point of Sale page and hrms is a separate app: nothing in erpnext@v16.34.1 reads a Shift Type, and POS Profile has no labour field, so no rule can gate a terminal. POSITIVE CONTROL: 'Employee Checkin' resolves to 26 files / 68 lines and shift_type.py itself computes late-entry and early-exit marking, so shift-rule enforcement code IS present and searchable -- it grades attendance after the fact, which is exactly what the claim excludes. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_type/shift_type.json · retrieved 2026-09-06 adversarially verified
Hardware & physical footprint
The POS software runs on commodity off-the-shelf hardware (standard iPads, Android tablets, or PCs) that the operator can buy from a third party, rather than only on vendor-supplied proprietary terminals. differentiator
hardware-commodity-devices
The POS ships as a JavaScript Desk page in the product repository — point_of_sale.js, pos_controller.js, pos_item_cart.js, pos_item_selector.js, pos_item_details.js, pos_number_pad.js, pos_payment.js, pos_past_order_summary.js — with no native client and no device binding, so any iPad, Android tablet, PC, Mac or Chromebook with a browser runs it, and Frappe sells no terminals at all. Re-cited on verification: the POS manual page previously cited documents no device, browser or operating-system requirement of any kind. https://github.com/frappe/erpnext/tree/develop/erpnext/selling/page/point_of_sale · retrieved 2026-08-02 · not refetchable · site policy · graded A when read adversarially verified
Vendor documentation names the specific client operating systems supported (iOS/iPadOS, Android, Windows, Linux/web) and states minimum OS versions and device specs.
hardware-os-platforms
Bound: the full 1,863-page docs.frappe.io census at the 2026-09-06 sitemap -- erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12 -- not the 1,544-page erpnext+framework subset. CORRECTED INVARIANCE: /\bios\b|\bipad\b|\bandroid\b/i is NOT zero across the publisher's documentation. It returns two pages: docs.frappe.io/hr/mobile-app-installation, which names Android and iOS as install targets for Frappe HR's PWA, and docs.frappe.io/cloud/two-factor-authentication-2fa, which links a Play Store authenticator. Both lie outside the product that carries the POS, and neither states a minimum OS version or a device spec. Across the 708 erpnext pages and the 836 framework pages -- the documentation for the product that carries the POS -- the count is zero. THE ARTEFACT: the page cited here is the only 'System Requirements' section in the census and it is entirely server-side, naming macOS and Debian/Ubuntu as supported host distributions plus a dependency table (MariaDB 11.8, Python 3.14, NodeJS 24, Redis/valkey 6+, Yarn, pip) for Frappe v16. No client OS, no minimum client OS version, no device spec anywhere. The finding is therefore sharper than a bare zero: this publisher DOES write client-platform pages when a product has a mobile client -- Frappe HR has one -- and has written none for ERPNext or its POS. Code census for context: erpnext v16.34.1 + frappe v16.33.0, tree API truncated:false, with /progressive web app|\bPWA\b|manifest\.json|service.?worker/ returning ZERO files in either repository. https://docs.frappe.io/framework/user/en/installation · retrieved 2026-09-06 adversarially verified
Offers a purpose-built handheld ordering device with an integrated card reader (not a phone case add-on), with published drop rating and IP ingress rating.
hardware-handheld-purpose-built
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bhandheld\b/i, /\bdrop rating\b/i or /\bIP54\b|\bIP65\b|\bingress\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero hits for /\bhandheld\b/i across the 1,863-page docs census. POSITIVE CONTROL: the same SLA enumerates what Frappe DOES sell and support -- hosting plans, a product-warranty entitlement gated at the $50 Frappe Cloud plan and above, priority/phone support, L2 bug support -- so a handheld SKU would be named in that document. With no first-party device there is no published drop rating and no IP ingress rating to assess. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
The handheld supports hot-swappable or field-replaceable batteries, or the vendor publishes a rated battery life for a full shift. differentiator
hardware-handheld-battery-swap
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bhandheld\b/i, /\bhot.?swap\b/i and /\bshift life\b/i return ZERO files in both repositories and ZERO across the docs census. /\bbattery\b/i is NOT zero, and that is the trap: it survives in exactly 3 files and every hit is a manufacturing or stock TEST FIXTURE item name -- "Test Batch Battery Consumable", "Test Serial Battery Consumable", "_Disassemble Battery" -- a BOM component, never a device battery. No rated shift life, no hot-swap, no spare-battery programme. POSITIVE CONTROL: the SLA does name the device-adjacent obligations Frappe accepts (which Linux distributions Bench supports, upgrade support, scaling support), so a battery or spare-battery programme would be stated there. Operators run the browser POS on commodity tablets and phones; battery handling belongs to the device OEM, not to Frappe. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Handhelds support cellular/LTE connectivity as a documented fallback when store Wi-Fi drops, either built into the device or via a vendor-supplied failover.
hardware-handheld-lte
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bLTE\b/i, /\bcellular\b/i, /\b4G\b|\b5G\b/i, /\bSIM\b/i or /\bfailover\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero for LTE/cellular across the 1,863-page docs census. POSITIVE CONTROL: /\bnetwork printer\b/ = 5 files, so the corpus does contain the stack's device-connectivity configuration surface. A staff phone's own radio would carry the browser session, but that is the operator's device rather than a product capability -- and since the POS cannot boot without reaching the server (pos_controller.js calls check_opening_entry() in its constructor), there is no offline mode to cover a cellular gap either. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Terminals continue to take orders, print to kitchen, and record cash sales with the internet down, and the vendor documents explicitly which functions degrade (card auth, loyalty lookup, refunds).
hardware-offline-mode
Terminals require a live connection to the Frappe server. Offline operation is frappe/erpnext#29068, a feature request opened 2021-12-29, labelled inactive and closed without implementation, and no degradation matrix is published anywhere — the POS Profile field list contains no offline setting and the POS manual addresses offline mode nowhere. Corrected on verification: the issue is closed, not open. https://github.com/frappe/erpnext/issues/29068 · retrieved 2026-08-02 adversarially verified
Sells or supports a dedicated kitchen display system with bump-bar or touch input, station routing, and course/fire timing, as a first-party product rather than an integration-only dependency.
hardware-kds
No first-party KDS. Kitchen screens existed only in the hospitality app, archived Oct 4, 2023. https://github.com/frappe/hospitality · retrieved 2026-08-01
Offers a self-order kiosk running the same menu and modifier engine as the POS, in both countertop and freestanding form factors, with integrated payment and accessibility (ADA) compliance documented. differentiator
hardware-kiosk
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census for a kiosk APPLICATION as well as kiosk hardware, because those are different claims. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bkiosk\b/i returns ZERO files in erpnext v16.34.1, ZERO in frappe v16.33.0, and ZERO across the 1,863-page docs census -- there is no self-order application, no kiosk mode flag on POS Profile, and no ADA/accessibility statement for one. POSITIVE CONTROL: /\bPOS Profile\b/ = 53 files, and the POS Profile doctype JSON carries 70+ configuration fields (hide_unavailable_items, hide_images, auto_add_item_to_cart, print_receipt_on_order_complete, action_on_new_invoice...), so a kiosk mode would be visible in that field list if it existed. No enclosure, stand, printer or payment-reader bundle to assess. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Supports drive-thru-specific hardware: outdoor digital menu boards, order confirmation displays, and speaker/headset integration, with a documented timer/speed-of-service measurement.
hardware-drive-thru
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bdrive.thru\b|\bdrive.through\b/i returns ZERO files in both repositories and ZERO across the docs census; so do /\bmenu board\b/i, /\bheadset\b/i and /\bspeed of service\b/i. POSITIVE CONTROL, and it is the informative one: /\bkitchen\b/i anchored returns exactly 2 files and both are chart-of-accounts templates carrying a GL account literally named "Kitchen" (Singapore F&B and UAE charts). The search reaches food-service vocabulary in this corpus and finds only accounting. No order-confirmation board, vehicle detector or lane timer exists in the software, and Frappe supplies no hardware to run one on. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Works with standard ESC/POS thermal receipt and kitchen printers from more than one manufacturer (e.g. Epson and Star), including LAN/Ethernet printers, rather than only vendor-branded printers.
hardware-printer-compatibility
Shortfall: no manufacturer is ever named, no ESC/POS compatibility list is published, and raw thermal printing depends on third-party client software. Print Settings documents a CUPS print server — "You can enable print server by filling the print server IP and port. Then chose the default printer" — gated on installing the pycups library, covering generic LAN/IPP printers. Raw Printing documents driving a thermal printer in its native command language ("any string-based printer languages can be used in the Raw Commands field") but requires the operator to "download and install the QZ Tray application on the computer to which your thermal printer is connected". Regraded on verification from an unsourced inference to vendor documentation. https://docs.frappe.io/erpnext/raw-printing · retrieved 2026-08-02 adversarially verified
Supports the standard peripheral set — cash drawers (including multi-drawer per terminal), barcode scanners, scales for by-weight items, and customer-facing displays — with a published compatibility list.
hardware-peripherals
CORRECTION to the existing rationale, which says cash drawers have "no native support". They do have a documented path. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. Searched the vendor vocabulary: /\braw print/i, /\bQZ Tray\b/, /\bcups\b|\bpycups\b/, /\bdrawer\b/i, /scan_barcode|barcode_scanner/, /\bcustomer.display\b/i, /\bweighing\b|\bscale device\b/i. FINDINGS, per peripheral: (a) BARCODE SCANNERS -- fully supported, /scan_barcode|barcode_scanner/ = 37 files, POS Invoice carries a scan_barcode field, and the framework additionally documents a camera scanner API (framework/user/en/api/scanner, Html5-QRCode). (b) CASH DRAWERS -- supported via ESC/POS raw commands hand-written into a Print Format and pushed through QZ Tray, which the vendor documents in the sentence quoted here; /\bdrawer\b/i returns ZERO files in either repository, so there is no drawer object, no per-terminal multi-drawer model and no kick command in the product -- the operator writes the bytes. (c) SCALES -- absent: zero anchored hits for weighing, weigh-scale, scale device, serial port or RS-232 in either repo (the unanchored "scale" trap is 133 files of CSS transform and grayscale). (d) CUSTOMER-FACING DISPLAYS -- absent, and this is the trap on this cell: /customer.display/i returns 6 lines in pos_item_cart.js and point-of-sale.scss, but ".customer-display" there is a CSS class for the customer NAME chip inside the cashier's own cart panel, not a second screen. (e) No published compatibility list for any of them. POSITIVE CONTROL: /\bnetwork printer\b/ = 5 files and /\bcups\b|\bpycups\b/ = 3 files including frappe's pyproject dependency, so the peripheral surface is present and searchable. Partial stands, with a corrected reason: scanners yes, drawer via documented raw-printing DIY, scales and customer displays no, compatibility list none. https://docs.frappe.io/erpnext/raw-printing · retrieved 2026-09-06 adversarially verified
Card entry happens on a PCI-listed PTS device using validated point-to-point encryption, so the POS application and tablet stay out of PCI scope; the vendor states the merchant's SAQ type.
hardware-p2pe-terminal
The claim has two halves and both fail against first-party documents. (1) A PCI-listed PTS device using validated P2PE: Frappe's certifications page (quoted here) and the "Compliance & Certifications" section of docs.frappe.io/cloud/faq/architecture-and-security are closed enumerations of the vendor's compliance posture, and both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2 -- no PCI DSS, no P2PE listing, and nowhere a stated merchant SAQ type. (2) A device programme at all: the Frappe SLA states under Support Exclusions that "Frappe shall not provide any type of Infrastructure purchase to the Customer such as, but not limited to, server or any other type of hardware." Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for PCI, P2PE, PTS or SAQ in erpnext v16.34.1, frappe v16.33.0, or any of the 1,863 docs pages. POSITIVE CONTROL: the certifications page publishes attestations with dates and a certifying body (ISOQAR, Dec 2024 recertification, Dec 2025 surveillance audit), so it reports attestations when they exist. ERPNext keeps card data out of the application by architecture, but no PTS device programme and no SAQ statement is published. https://frappe.io/quality-and-information-security · retrieved 2026-09-06 adversarially verified
Supports contactless acceptance directly on a commodity phone or tablet (Tap to Pay on iPhone / Tap to Pay on Android) with no separate reader. differentiator
hardware-tap-to-phone
The POS Profile payments table maps Modes of Payment to GL accounts; there is no acquirer connection, no reader configuration and no SoftPOS or tap-to-phone SDK anywhere in the POS configuration. https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json · retrieved 2026-08-02
Hardware prices are published per SKU on the vendor's public site, rather than quote-only. differentiator
hardware-pricing-transparency
Not applicable in the operator's favor: Frappe publishes no hardware prices because it sells no hardware. The operator buys at open-market price. https://frappe.io/erpnext/pricing · retrieved 2026-08-01
Hardware can be purchased outright (owned) as an alternative to a mandatory lease or subscription-bundled rental, and the vendor states which. differentiator
hardware-ownership-vs-lease
The existing rationale says "Frappe does not state this anywhere", and that is the part that is wrong -- the vendor does state it, in its Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) under Support Exclusions section 2.3 item 6, quoted here. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: /\bRMA\b/i and /\bbuyout\b/i return ZERO files in both repositories. /\blease\b|\brental\b/i is NOT zero and had to be read: 9 lines across 8 files, every one of them a GL ACCOUNT NAME inside a chart-of-accounts template ("Lease Liabilities" and "Finance Lease - Current" in the Australian and New Zealand charts, "Rental-Equipment" and "Rental-Premises" in the Singapore default and F&B charts, "Lease-verplichtingen" in the Dutch grootboekschema) or a financial-report category description -- accounting vocabulary for the operator's own leases, not a Frappe hardware lease. In the docs census the pair survives on one page, about e-commerce integrations. So there is no lease, because there is no vendor hardware at all: every device an operator runs the browser POS on is bought on the open market and owned outright by construction. POSITIVE CONTROL: the same SLA and frappecloud.com/terms (effective 1 April 2026) DO state what is rented -- hosting subscriptions, plan tiers, product warranty gated at the $50 plan -- so the vendor states its commercial models where they exist. Held at partial rather than yes because what the vendor states is an exclusion of hardware supply, not an affirmative ownership term for hardware it sells; grade moves F to B on the cited exclusion. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Vendor documentation confirms whether hardware purchased from the vendor remains usable with other software after cancellation, i.e. it is not software-locked or remotely bricked. differentiator
hardware-usable-after-churn
The claim asks a single question: does VENDOR DOCUMENTATION CONFIRM that hardware purchased from the vendor stays usable with other software after cancellation. It does not, and cannot, because there is no vendor hardware for it to confirm anything about. The settling sentence is in the Support Exclusions of Frappe's published Service Level Agreement (section 2.3 item 6, last updated 18 June 2026, retrieved 2026-09-06 at 200 from the twelve-page docs.frappe.io/legal space): 'Frappe shall not provide any type of Infrastructure purchase to the Customer such as, but not limited to, server or any other type of hardware.' No post-cancellation hardware commitment is published anywhere in that space or in the 1,863-page docs census. SEPARATELY, and this is a structural observation rather than the claim's subject: nothing in the software could brick a device even if Frappe sold one -- /\bbrick(ed)?\b/, /\bremote wipe\b/, /\bdevice lock\b/, /\bactivation lock\b/ and /\bkill switch\b/ all return ZERO files across erpnext v16.34.1 and frappe v16.33.0, the two docs hits for 'brick' are 'bricks and mortar' in the PayPal and Razorpay write-ups, and every remote-control feature Frappe ships (Cloud site suspension, disable-account, cancel-subscription) acts on the SITE, never on a device. POSITIVE CONTROL: the same SLA states what Frappe does supply and support -- hosting plans, product warranty above the $50 Frappe Cloud plan, priority/phone support, L2 bug support -- so a hardware commitment would be named there. https://docs.frappe.io/legal/policies/service-level-agreement · retrieved 2026-09-06 adversarially verified
Publishes a hardware warranty term and a replacement/advance-exchange SLA with a stated turnaround (e.g. next-business-day depot swap). differentiator
hardware-rma-sla
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. This cell is answered by that sentence directly: with no vendor hardware there is no warranty term and no advance-exchange or depot-swap turnaround. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bRMA\b/i, /\badvance exchange\b/i and /\bnext.business.day\b/i return ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bdepot\b/i survives on exactly one line and it is a substring inside the escaped format_data blob of the Purchase Receipt serial-and-batch print format, not a service concept. POSITIVE CONTROL, and it is the sharp one: the SAME SLA document DOES publish turnaround commitments -- three tables of response and resolution times by issue priority (standard tier Critical: 1 hour response / 4 hour resolution; premium tier 30 min / 2 hours) and a "product warranty" entitlement threshold at the $50 Frappe Cloud plan. So this vendor publishes SLAs with stated turnarounds where it has an obligation. The warranty it names is a software-support warranty; the hardware clause it names is an exclusion. Device warranty is the OEM's. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Staff can run the ordering or payment app on their own personal phone (BYOD) with a documented permission and security model.
hardware-byod
Searched for a BYOD-specific posture: /\bBYOD\b/i, /\bMDM\b/i, /\bmobile device management\b/i, /\bpersonal device\b/i, /\bdevice policy\b/i over the code census and the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: ZERO hits for every one of those across both repositories AND across all 1,863 docs pages -- there is no BYOD guidance, no MDM integration and no personal-device policy anywhere. What DOES exist, and what keeps this at partial rather than no, is the generic access model the claim asks to be documented: any staff phone with a browser and a user account reaches the POS, and the Role / Role Profile / User Permission / Permission Level model is fully documented on the page cited here, with optional two-factor authentication (frappe/twofactor.py, 16 matching lines; docs.frappe.io/erpnext/setup-two-factor-authentication) layered on top. POSITIVE CONTROL: /\bpermission\b/ resolves across the whole framework and the docs census carries a dedicated permissions page plus perm-level troubleshooting pages, so a BYOD section would sit in that neighbourhood if it existed. Documented permission model: yes. BYOD-specific security model: absent. Grade moves F to B on the cited permissions documentation. https://docs.frappe.io/erpnext/permissions · retrieved 2026-09-06 adversarially verified
Provides a remote device-management console showing each terminal, printer, and KDS as online/offline, with remote reboot, software-version visibility, and staged rollout of updates. differentiator
hardware-remote-device-management
Searched the fleet-console vocabulary over the code census: /\bfleet\b/i, /\bMDM\b/i, /\bremote reboot\b/i, /\bstaged rollout\b/i, /\bfirmware\b/i, /\bterminal\b/i, /\bKDS\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bMDM\b/i, /\bremote reboot\b/i, /\bstaged rollout\b/i, /\bfirmware\b/i and /\bKDS\b/i return ZERO files in both repositories, and /\bterminal\b/i is 12 files of bench CLI shell vocabulary. /\bfleet\b/i is NOT zero and is the trap on this cell: it survives in exactly 2 files, vehicle.json and driver.json, where it is the "Fleet Manager" ROLE of ERPNext's vehicle module -- a fleet of trucks, not a fleet of terminals. ARTEFACT: Network Printer Settings is the ONLY hardware-device record type in frappe v16.33.0, and its complete field list is four entries -- server_ip (default localhost), port (default 631, i.e. CUPS), a column break, and printer_name. There is no status field, no last-seen timestamp, no online/offline state, no software version and no reboot action, so there is nothing for a device console to display. POSITIVE CONTROL: Frappe Cloud DOES ship a real fleet console -- docs.frappe.io/cloud documents per-site and per-server actions, analytics, process lists, notification configuration and staged bench update schedules -- which proves the vendor builds exactly this kind of console when the managed objects exist. It manages sites, benches and servers; it manages no terminals, printers or KDS stations. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/printing/doctype/network_printer_settings/network_printer_settings.json · retrieved 2026-09-06 adversarially verified
Integrates with specialty beverage hardware — self-pour tap walls, flow meters, or liquor pour spouts — such that pours post to a POS tab automatically.
hardware-selfpour-scales
Searched the beverage-hardware vocabulary anchored: /\bself.pour\b/, /\btap wall\b/, /\bflow.?meter\b/, /\bkeg\b/, /\bpour spout\b/, /\bweighing\b/, /\bweigh.scale\b/, /\bscale device\b/, /\bserial port\b/, /\bRS.?232\b/. Corpus: erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both. INVARIANCE: ZERO files for every one of those anchored patterns. Two traps defused to reach it: unanchored 'scale' is 133 files of CSS transform() and grayscale, and /\bpour\b/ alone is 48 files and 2,784 lines of FRENCH inside the Swiss, SYSCOHADA, Moroccan, Burkinabe and Beninese chart-of-accounts templates. THE FINDING IS THE CORPUS-WIDE ZERO, not the cited file: Network Printer Settings (server_ip / port / printer_name) is offered only as the shape of the stack's device surface -- it is one-way output to CUPS, and the only other device bridge is QZ Tray raw printing, also outbound -- so nothing in the product READS an instrument. POSITIVE CONTROL: device INPUT is present and findable where it exists -- /scan_barcode|barcode_scanner/ = 37 files including a scan_barcode field on POS Invoice itself -- so an instrumentation path would have surfaced. Item UOM conversion lets an operator type 0.4 by hand; that is data entry, not instrumentation. Bound to core at these tags. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/printing/doctype/network_printer_settings/network_printer_settings.json · retrieved 2026-09-06 adversarially verified
Supports inbound caller ID hardware or a telephony integration that pops the customer record and order history at the POS on an incoming call.
hardware-callerid-integration
Searched the telephony vocabulary over the code census and the docs census: /\btelephony\b/i, /\btwilio\b/i, /\bexotel\b/i, /\bcaller.?id\b/i, /\bincoming call\b/i, /\bscreen pop\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: the integration is real and first-party documented -- three docs pages (erpnext/exotel_integration, erpnext/notifications, erpnext/erpnext_integration) describe an inbound-call webhook (handle_incoming_call / handle_end_call / handle_missed_call) that pops the matching Lead or Customer record to the employee, quoted here. What is absent is the POS half of the claim: zero hits tie any call popup to the point_of_sale page -- the popup is a desk-wide dialog, the POS page (erpnext/selling/page/point_of_sale/*) contains no call listener, and nothing pre-populates an order from a call. POSITIVE CONTROL: the POS page DOES subscribe to realtime events where it needs to (pos_payment.js listens for process_phone_payment), so a call-pop subscription would be visible in that directory if it existed. Partial stands; grade moves F to B on the cited integration page. https://docs.frappe.io/erpnext/exotel_integration · retrieved 2026-09-06 adversarially verified
Integrations, API & extensibility
Public, self-serve API reference documentation is readable without a signed partner agreement, NDA, or sales call.
extensibility-public-api-docs
Re-verified independently this pass: the page loads for an anonymous reader with no account, NDA or sales contact and states "Frappe framework generates REST API for all of your DocTypes out of the box". It documents token auth (the token "is generated by concatenating api_key and api_secret with a colon"), password auth and OAuth 2.0 access tokens, plus CRUD over POST/GET/PUT/DELETE, filters, pagination, remote method calls and file upload. https://docs.frappe.io/framework/user/en/api/rest · retrieved 2026-08-02 adversarially verified
API access is included in the base subscription at no additional per-location fee, surcharge, or upgraded plan requirement. differentiator
extensibility-api-access-cost
Framework docs: API throttling is self-administered, not sold. "You can enable rate limiting on your site by adding configuration similar to the following in site_config.json" with "limit" (max request-seconds permitted) and "window" (window size in seconds); over-limit requests get HTTP 429. The site owner writes that file, so there is no vendor-metered API quota to buy up. The REST API reference confirms the API is generated for all DocTypes out of the box on every site, authenticated by per-user api_key:api_secret - no upgraded plan or per-location surcharge exists in the software, and self-hosting the GPL-3.0 stack costs nothing. https://docs.frappe.io/framework/user/en/rate-limiting · retrieved 2026-08-06 adversarially verified
A free sandbox or test environment with seeded data is available to developers without owning a paid production account. differentiator
extensibility-free-sandbox
Seeded test environment is in the product source. erpnext/setup/demo.py defines setup_demo_data(company_name) - it opens a "demo_data" savepoint, calls create_demo_company(), process_masters() and make_transactions(company) (items, item groups, customers, suppliers, sales and purchase invoices, payment entries) and rolls back on failure; clear_demo_data() removes it again. The framework installation guide documents standing the stack up locally with bench init, and the ERPNext README documents docker compose -f pwd.yml up -d on port 8080. GPL-3.0, so this requires no production account or payment. https://github.com/frappe/erpnext/blob/develop/erpnext/setup/demo.py · retrieved 2026-08-06 adversarially verified
Third-party apps authenticate via OAuth 2.0 with scoped, operator-granted, individually revocable permissions (not shared static API keys or credential sharing).
extensibility-oauth-partner-apps
OAuth 2.0 is a documented auth method — 'Use the generated access_token in request header' as Authorization: Bearer. Scoped OAuth Client / OAuth Bearer Token records are revocable per app, alongside per-user API key/secret pairs. https://docs.frappe.io/framework/user/en/api/rest · retrieved 2026-08-01
The platform pushes real-time webhooks for order lifecycle events (created, modified, paid, voided, refunded) rather than requiring polling.
extensibility-webhooks-push
Webhook doctype fires on document lifecycle events (on_update, on_submit, on_cancel, after_insert and similar) for any DocType including Sales Invoice and POS Invoice, with conditional filters. No polling required. https://docs.frappe.io/framework/user/en/guides/integration/webhooks · retrieved 2026-08-01
Webhooks are cryptographically signed (e.g. HMAC) AND documented to retry with backoff, with a replayable event log for missed deliveries. differentiator
extensibility-webhook-reliability
Verified against the webhooks guide: X-Frappe-Webhook-Signature carrying a base64-encoded HMAC-SHA256 of the payload, doc-event triggers, and 'a webhook request log is created for every successful request'. Retry/backoff is genuinely absent from the documentation — the partial is correctly conservative, and the log-only-on-success detail is accurate. https://docs.frappe.io/framework/user/en/guides/integration/webhooks · retrieved 2026-08-01 adversarially verified
A public write API accepts externally originated orders into the POS as first-class tickets that fire to KDS/printers and land in reporting.
extensibility-order-injection-api
Shortfall: injected orders cannot fire to a KDS or a kitchen printer, because no KDS exists and no ticket-routing engine ships. POST /api/resource/Sales Invoice, POS Invoice or Sales Order does create a first-class submittable document that hits the GL, depletes stock and appears in all reporting, so the land-in-reporting half of the claim holds fully. Downgraded from yes on verification — the researcher’s own note conceded the KDS shortfall. https://docs.frappe.io/framework/user/en/api/rest · retrieved 2026-08-02 adversarially verified
The vendor is a named DoorDash Preferred Integration Partner (DPIP) under the 2026 program requirements. differentiator
extensibility-doordash-preferred
DoorDash publishes its own complete provider registry at https://merchants.doordash.com/api/partner-integrations — 64 providers, each carrying a `qualityStatus` of PREFERRED (12), CERTIFIED (47) or AT_RISK_OF_SUSPENSION (5), plus a count of how many of the eight high-quality features the provider has built. It is served anonymously and merchants.doordash.com/robots.txt permits it (Allow: / with only /cdn-cgi/ and /monitoring barred). This is what the program page means when it says the roster is tracked in real time, and it is a CENSUS rather than a floor: every provider integrated with DoorDash appears in it with a tier, so a vendor that is absent altogether is not in the programme at any tier. This vendor appears nowhere in the 64 entries, under any provider id or friendly name — checked mechanically against both fields, with the only near-misses being substring coincidences (Speedline against Lightspeed, vroom_restaurant against Restaurant365) that were read and rejected. SUPERSEDES the 2026 announcement post most of this corpus cited: that post introduces its ten names with the word `include`, which makes it a floor and never a ceiling, and reading it as a ceiling is what produced this cell's prior grade. GRADE HARMONISED TO B, 2026-09-11: this URL was first written at grade A. The adversarial pass ruled E on the principle that the rubric grades by the publisher's relationship to the SCORED vendor, and DoorDash is not that vendor. B is the settlement, for two reasons that are not preference: 39 rows already graded a DoorDash-published document B on this claim before today, and one URL on one claim cannot carry two grades; and E is unworkable, because nine of the 47 rows are `yes` on a differentiator-weight claim, which the grade floor refuses below B. B reads as the product documentation of the programme's own publisher, which is what this registry is. The dissent is recorded in verification.jsonl. https://merchants.doordash.com/api/partner-integrations · retrieved 2026-09-11
Direct, first-party certified integrations exist with DoorDash, Uber Eats, and Grubhub without requiring a paid middleware layer (Otter/Chowly/Deliverect/Checkmate). differentiator
extensibility-first-party-delivery-integrations
Grounded on the publisher's own exhaustive enumeration rather than on a bare zero. docs.frappe.io/erpnext/erpnext_integration is ERPNext's 'Integration Categories' page (updated 2026-02-26), and it lists every shipped integration by category: Authentication (LDAP, Fairlogin); Backup (Dropbox, Google Drive, Amazon S3); Bank (Plaid); E-commerce (Shopify, WooCommerce, Amazon SP-API, Unicommerce, Zenoti); Shipping (ERPNext Shipping, itself only LetMeShip and SendCloud); Payment (RazorPay, GoCardless, Stripe, Braintree, Paytm, M-pesa); Telephony (Exotel); Google. No delivery marketplace of any kind appears, first-party or otherwise. CORPUS INVARIANCE: \b(doordash|uber ?eats|grubhub|postmates|deliveroo|olo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns ZERO lines across erpnext@v16.34.1 (5,170 files) and frappe@v16.33.0 (3,634 files) and zero pages across the 1,863-page docs.frappe.io census, and erpnext/erpnext_integrations -- the whole 'ERPNext Integrations' module named in erpnext/modules.txt -- contains exactly one doctype, plaid_settings. POSITIVE CONTROL: the same corpus search resolves Shopify, WooCommerce and Plaid to real integration code, so named third-party connectors ARE visible where they exist. BOUND: this is core ERPNext + Frappe. Restaurants on this stack buy URY, POSNext, GETPOS or KLiK PoS from the Frappe Cloud marketplace, which is out of this record's scope and was not censused; a marketplace app's DoorDash bridge would not make it a first-party Frappe integration either, which is what the claim asks. https://docs.frappe.io/erpnext/erpnext_integration · retrieved 2026-09-06 adversarially verified
The POS is a supported endpoint for at least two major aggregation middleware platforms (Deliverect, Chowly, Otter, Checkmate, ItsaCheckmate).
extensibility-middleware-compatibility
CLAIM: the POS is a supported endpoint for at least two major aggregation middleware platforms (Deliverect, Chowly, Otter, Checkmate/ItsaCheckmate). VERDICT: no/B. The prior pass left this unknown because 'two of the four companies' rosters are NOT a census'. NEW SURFACE 2026-09-18: CHOWLY IS NOW BOUNDED, which settles the claim arithmetically - with Deliverect and Otter already censused at zero, at most ONE of the five platforms (Checkmate, whose full roster is still behind a login-gated Google Sheet) could support ERPNext, and one is fewer than two, so the claim fails however Checkmate resolves. CHOWLY BOUND (three independent corpora, all on disk, all zero): (1) the 583-article Chowly Salesforce Knowledge census (chowly.help, taken via the Knowledge REST API in the 324th) - \berp ?next\b 0, \bfrappe\b 0, with positive controls proving the corpus reaches small POS vendors (toast 48 articles, square 95, linga 1, slice 2); (2) the KB's own POS roster article, an ENUMERATION: 'SDK: Provider Support Contacts' (articleNumber 000001325, https://chowly.help/s/article/SDK-Provider-Support-Contacts, HTTP 200 to curl today) states 'In this article, you will find contact information for different POS providers who've used an SDK to connect with Chowly ... All of the POS companies listed in this article have used SDKs to build to our POS API' and lists sixteen: Arrow POS, Brandibble, CBS Northstar, Dripos, GEMpos (ITWercs), Katalyst, Linga, Link, Milagro, Mr. Jims, Ordyx, PDQ, Redfin, Slice, Squirrel, Tabit - no ERPNext/Frappe; the companion article 'FAQ - Chowly's POS API Integration' (kA01K000000sgKISAY) points at exactly that list as 'a list of POS companies connected to our POS API'; (3) chowly.com/sitemap.xml re-fetched today, 167 <loc>, whose complete /pos/ set is six direct integrations (chowly-for-toast, -square, -spoton, -clover, -revel, -lightspeed) plus three /partnerships/ pages (toast, spoton, square) - erpnext 0, frappe 0. Chowly's own shipped RCC source (source maps, 325th) corroborates: types/POS.ts enum SupportedPOS = {SQUARE, UBEREATS} for self-onboarding and utils/posHelpers.ts IMAGE_EDITABLE_POS = epson, ncrsilver, ncrmenu, brink, revel, toast, square, spoton, clover, chowlysdk - no ERPNext. CHECKMATE re-probed today and still NOT a census: www.itsacheckmate.com/sitemap.xml (350 <loc>) contains only three /pos-integration/ paths (toast, your-pos, and a blog post), so the sitemap is not the roster and the 'full partner list' Google Sheet still needs a login - Checkmate is therefore left unbounded on purpose, and the verdict does not depend on it. CONTROL POISON: \bfrappe\b is a FALSE-POSITIVE TRAP - it matched only inside Otter's blog corpus as the BEVERAGE ('a Nutella latte or frappe can enhance the nutty theme', .cache/otter/s256/www-pages.txt); bare 'erp' remains poison (slerp, orderpay, enterprise). Denominators: Chowly 583 KB articles + 167 site URLs + 16-name SDK roster; Deliverect 10,173 <loc> incl. 3,289 integration URLs; Otter 77 integration <loc> + 286 help articles (all from the 317th/321st passes, re-used here). Retrieved 2026-09-18. https://chowly.help/s/article/SDK-Provider-Support-Contacts · retrieved 2026-09-18 adversarially verified
Native, vendor-maintained connectors exist for QuickBooks Online and at least one other GL/accounting system, with mapped journal entries rather than CSV-only export.
extensibility-accounting-connectors
CHANGED FROM partial -- a downgrade, because the partial's factual basis has been withdrawn by the vendor. The prior rationale rested on 'a QuickBooks Migrator app exists for one-time inbound migration'. It does not, not in this version. ERPNext's own documentation page for it is now titled 'QuickBooks Migrator (Deprecated)' and states in a callout that the built-in migrator was removed from the ERPNext develop branch on 2025-01-17 in PR #45240, directing operators instead to Data Import, the Chart of Accounts Importer, the Opening Invoice Creation Tool and opening Journal Entries -- i.e. to hand-mapped spreadsheets. CORPUS INVARIANCE confirming it independently: \bquickbooks\b returns exactly ONE line across erpnext@v16.34.1 (5,170 files) and frappe@v16.33.0 (3,634 files), and it is a 'which system are you coming from' option in setup_wizard.js alongside Tally, Zoho, Sage and SAP -- a migration-source label with no code behind it. There is no QuickBooks Migrator doctype left, and \b(intacct|netsuite|xero|sage intacct)\b returns zero lines. So there is no native vendor-maintained connector to QuickBooks Online and none to a second GL, in either direction, mapped or otherwise. The criterion does partly misfit -- ERPNext replaces the general ledger rather than syncing to one -- but the claim asks for connectors and there are now zero. POSITIVE CONTROL: 'Plaid' resolves to a real erpnext_integrations doctype and Shopify/WooCommerce to real integration docs, so first-party financial connectors ARE visible to this search where they exist. https://docs.frappe.io/erpnext/quickbooks-migrator · retrieved 2026-09-06 adversarially verified
Labor hours export natively to at least two named payroll providers (e.g. Gusto, ADP, Paychex, Paylocity) without manual re-keying.
extensibility-payroll-export
Scope verified rather than assumed: ERPNext's HR module lives in the separate frappe/hrms repository, so an erpnext-only absence would prove only that the code moved. Censused frappe/hrms v16.17.1 (tree API truncated=false, 1,552 blobs) alongside erpnext v16.34.1 and frappe v16.33.0. I re-ran the control: \b(gusto|paychex|paylocity|ADP)\b returns files=0 lines=0 in hrms; the erpnext hits on the wider alternation are all 'workday' inside Service Level Agreement code. INVARIANCE: there is no payroll-export doctype, no provider credential store, and hrms/regional contains only india and united_arab_emirates. The Payroll workspace's thirty links end at Salary Register, Bank Remittance, Salary Payments Based On Payment Mode, Salary Payments via ECS, Income Tax Computation, Provident Fund Deductions and Professional Tax Deductions -- Indian statutory or generic banking throughout. NOTE ON THE ARTEFACT'S WEIGHT: a Workspace is a curated shortcut dashboard, not an exhaustive manifest; it corroborates, and the provider-name zero across all three repositories is what establishes. What exists instead is architectural -- Frappe HR runs payroll itself, Query Reports render to CSV/XLSX, and Employee Checkin, Attendance and Salary Slip are all readable over the REST API, so an integrator can build an export, which is the unbuilt work the claim excludes. https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/payroll/workspace/payroll/payroll.json · retrieved 2026-09-06 adversarially verified
The vendor operates a public integrations marketplace listing named third-party apps that operators can browse and self-install.
extensibility-app-marketplace
Re-verified verbatim 2026-08-09 at the current URL (the old /marketplace 301s here): "Showing 344 apps", browsable by category (Analytics, Retail, E-commerce, Developer, ...) with a per-app detail page and self-install. Named third-party POS listings still present: URY - Restaurant POS & ERP, POSNext, GETPOS, KLiK PoS, POS Restaurant, POSpire. The vendor's cloud pricing page markets '150+ apps', an internal inconsistency, but the catalogue itself is the stronger source. https://cloud.frappe.io/marketplace/search · retrieved 2026-08-09 adversarially verified
The vendor supports a headless/embedded mode where a third-party UI (kiosk, web ordering, drive-thru) drives the POS transaction engine via API.
extensibility-headless-embedded
Searched the vendor's vocabulary over frappe@v16.33.0 and erpnext@v16.34.1: REST API, api/method, whitelist, OAuth Client, Webhook, headless. INVARIANCE supporting the partial: frappe/api ships both v1.py and v2.py route sets -- the module quoted here builds werkzeug Rules over document_list and the whitelisted-method dispatcher -- and every doctype including POS Invoice, POS Opening Entry and POS Closing Entry is a first-class REST resource behind them, with frappe/integrations/doctype/oauth_client and token_cache providing OAuth 2 and api-key auth. erpnext's own Point of Sale page is itself only a client of that layer: point_of_sale.py's get_items and the payment path are ordinary whitelisted methods. So a third-party kiosk, web-ordering or drive-thru UI genuinely can drive the transaction engine, and that is architecture, not aspiration. INVARIANCE supporting the shortfall: nothing is offered AS a headless mode. \b(headless|embedded pos|white.?label pos)\b returns ZERO lines across both repositories and zero pages in the 1,863-page docs.frappe.io census; there is no POS-specific API contract, no versioned order schema, no sandbox and no support commitment -- an integrator is calling internal desk methods whose signatures move between versions. POSITIVE CONTROL: 'oauth_client', 'webhook' and api/v2.py all resolve as shipped frappe modules, so the API surface IS present and a documented headless contract would have been found beside it. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/api/v1.py · retrieved 2026-09-06 adversarially verified
A complete historical data export (orders, customers, menu, payments metadata) is available to the operator on demand, in a documented machine-readable format, at contract end. differentiator
extensibility-data-portability-exit
The Data Export tool emits CSV or Excel for any DocType with filters and per-field selection, and REST reads every DocType, so orders, customers, items, prices and payment metadata all leave in a documented machine-readable format on demand. Self-hosted operators never surrender the database in the first place. Re-cited on verification, and the previously asserted downloadable full-site backup is trimmed: it appears on no page retrieved in this pass. https://docs.frappe.io/erpnext/data-export · retrieved 2026-08-02 adversarially verified
Reliability, offline & operations
Order entry, ticket routing, and check printing continue on-terminal when the internet connection is lost.
reliability-offline-order-entry
Order entry requires a reachable server. The browser-based offline POS was removed after v12 following chronic sync failures, and offline support is frappe/erpnext#29068, a feature request opened 2021-12-29 and closed as inactive without implementation. https://github.com/frappe/erpnext/issues/29068 · retrieved 2026-08-02
Card payments can be accepted while offline via store-and-forward, not just cash-only fallback. differentiator
reliability-offline-card-auth
The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell specifically: there is no card authorisation path online either -- Mode of Payment.type is Cash/Bank/General/Phone and Sales Invoice Payment carries no authorisation code -- so store-and-forward would have nothing to forward. Note that even cash-only fallback is unavailable, because the POS does not open without the server. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/pos_controller.js · retrieved 2026-09-06 adversarially verified
The vendor publicly documents who bears the loss when a store-and-forward transaction declines after connectivity returns, and states any per-transaction or cumulative offline cap. differentiator
reliability-offline-decline-liability
The claim asks what the vendor publicly documents about loss allocation on a store-and-forward decline and about any per-transaction or cumulative offline cap. Settled by the vendor's published agreements, retrieved 2026-09-06 at 200 from the twelve-page docs.frappe.io/legal space: the Service Level Agreement (updated 18 June 2026) and the Frappe Cloud Service and Support Agreement (effective 1 April 2026). Neither names offline transactions, a decline on reconnect, a liability allocation, or an offline cap of any kind. The antecedent is absent too, which is why no such position exists to publish: erpnext.PointOfSale.Controller calls check_opening_entry() before rendering, zero service-worker and zero store-and-forward hits across erpnext v16.34.1 and frappe v16.33.0 (tree API truncated:false), and the offline POS that existed at v7-v9 has been removed. POSITIVE CONTROL: the SLA enumerates its Support Exclusions explicitly and publishes response/resolution tables, so it is a document that states positions when Frappe holds one. https://docs.frappe.io/legal/policies/service-level-agreement · retrieved 2026-09-06 adversarially verified
Multiple terminals continue to share a single check/table state over the local network while the internet is down (LAN-only degraded operation, not per-terminal islands). differentiator
reliability-lan-degraded-multi-terminal
The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell the nuance matters: shared check state IS real while the server is reachable -- POS Invoice rows live in one MariaDB instance and every terminal is a browser talking to it, so LAN-only operation against an on-premise bench genuinely works with the internet down. What is absent is DEGRADED operation: no partition mode, no local replica on a terminal, no peer discovery. The check_opening_entry() round trip in the constructor is the proof -- a terminal that cannot reach the server does not island, it stops. Frappe Cloud's own security FAQ confirms the same shape one layer down: "No, there is no automated failover for databases on Frappe Cloud." https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/pos_controller.js · retrieved 2026-09-06 adversarially verified
The vendor documents a local/on-premise transaction engine or edge server (not purely cloud-hosted request/response) for the ordering path. differentiator
reliability-local-transaction-engine
Capability upheld, citation wrong. The pricing page says nothing about self-hosting; it sells the opposite. The supporting evidence is Frappe's production setup documentation (docker images as the recommended production path, plus 'bench setup production' with Supervisor/Nginx). Re-cite to the production-setup docs. https://docs.frappe.io/framework/user/en/production-setup · retrieved 2026-08-01 adversarially verified
Kitchen display and/or kitchen printer routing continues to function while offline.
reliability-offline-kds-printing
The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell there are two absences, not one. (a) KDS: /\bKDS\b|\bkitchen display\b/i returns ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bkitchen\b/i anchored is 2 files, both chart-of-accounts templates with a GL account named "Kitchen". (b) Kitchen printing: printing in this stack is a Print Format rendered by the SERVER and either handed to the browser or pushed to CUPS via frappe/printing (pycups, Network Printer Settings on port 631). Both paths require the server, and the QZ Tray raw-printing bridge is driven by the server-rendered client too, so neither survives a server outage. POSITIVE CONTROL: /\braw print/i = 7 files and /\bQZ Tray\b/ = 11 lines in frappe/public/js/frappe/form/print_utils.js, so the corpus does reach the thermal-printing surface. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/pos_controller.js · retrieved 2026-09-06 adversarially verified
The system automatically fails over to a backup printer or KDS station when a configured kitchen printer is unreachable, and alerts staff.
reliability-printer-fallback
Searched the failover vocabulary over the code census: /\bfailover\b|\bfail.over\b/i, /\bbackup printer\b/i, /\bfallback\b/i within the printing module, /\bunreachable\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bfailover\b|\bfail.over\b/i returns ZERO files in erpnext v16.34.1 and frappe v16.33.0. ARTEFACT: Network Printer Settings is the complete printer object in the framework and its entire field list is four entries -- server_ip, port, a column break, printer_name. There is no secondary/backup printer link, no priority, no health check, no alert recipient and no station-routing table, so there is nothing to fail over TO and nothing to raise an alert from. The alternative print path, QZ Tray raw printing, is a per-client browser bridge with a user connection prompt and has no server-side registry of stations at all. POSITIVE CONTROL: frappe DOES ship real alerting objects -- the Notification doctype, and Frappe Cloud threshold alerts documented at docs.frappe.io/cloud/reliability -- so an unreachable-printer alert would be expressible if the product modelled printer health. It does not. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/printing/doctype/network_printer_settings/network_printer_settings.json · retrieved 2026-09-06 adversarially verified
The vendor documents its conflict-resolution behavior for edits made on two devices during a network partition (e.g. last-write-wins, merge, or operator prompt).
reliability-sync-conflict-handling
Searched the concurrency vocabulary over the code census: /TimestampMismatchError/, /has been modified after you have opened it/, /\boptimistic\b/i, /\blast.write.wins\b/i, /\bmerge conflict\b/i, /\bCRDT\b/i, /\bvector clock\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: the mechanism is real and lives in the artefact cited here -- frappe/model/document.py compares the stored `modified` timestamp against the one the client opened and raises frappe.TimestampMismatchError, telling the second writer to refresh. That is optimistic concurrency with an operator prompt, it is exercised by tests in ten files including test_pos_invoice.py, and it is described in the public API docs (framework/user/en/api/document). What is absent is the thing the claim actually asks for: zero word-boundary hits for last-write-wins, merge, CRDT or vector clock as a documented partition policy, and no network-partition policy can exist because there is no offline sync at all (zero service-worker and zero store-and-forward hits in either repository; the POS controller does a frappe.call to check_opening_entry() before it renders). POSITIVE CONTROL: /\bdocstatus\b/ and the submit/cancel/amend state machine are fully present in the same file, proving the search reaches frappe's document-lifecycle layer. Partial stands -- single-server optimistic concurrency is documented, a partition policy is not; grade moves F to A on the primary source. https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/model/document.py · retrieved 2026-09-06 adversarially verified
The vendor publishes an explicit list of which features are unavailable offline (gift cards, loyalty lookup, refunds, manual card entry, text-to-pay).
reliability-offline-feature-matrix
The claim is about vendor PUBLICATION, so the docs census is the right instrument. Searched /\boffline\b/i across all 1,863 pages of the docs census -- 98.3% of docs.frappe.io's own sitemap manifest for the erpnext and framework spaces, the 26 misses being 404s inside the publisher's own manifest. INVARIANCE: 13 pages match and not one is a POS offline feature list -- they are payment-request "offline bank-transfer instructions", the GSTR-1 offline tool, Google OAuth access_type=offline in connected-app, and site_config. The ERPNext POS Introduction page, quoted here, is where an offline capability and its limits would be stated; it describes real-time stock integration, deferred posting at session close, multiple payment methods and loyalty, and says nothing about offline operation. That silence matches the code: Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. zero service-worker and zero store-and-forward hits, and the only /\boffline\b/i survivors touching POS are the v7/v9 changelogs for a mode that no longer exists. POSITIVE CONTROL: this publisher DOES write explicit negative feature matrices when it has one -- the Frappe Cloud security FAQ answers "Is there a WAF protecting applications?" with "No, but a server level firewall is available", "Is there automated failover for databases?" with "No", and states an RPO of up to 24 hours. There is no offline mode, hence no matrix to publish. https://docs.frappe.io/erpnext/point-of-sale · retrieved 2026-09-06 adversarially verified
A public, per-component status page exists showing current and historical incident state without a login.
reliability-public-status-page
The prior rationale recorded unknown because status.frappe.io failed TLS validation. Re-probed today and widened the search rather than accepting the refusal. Probed, all fetched 2026-09-06: status.frappe.io (DNS/TLS unreachable, status 0 -- a refusal, not an absence), status.frappecloud.com (unreachable), frappecloud.com/status (401), frappe.io/status (404), frappecloud.statuspage.io (200 but it is Atlassian's own Statuspage marketing site, i.e. no such tenant), and frappe.statuspage.io -- which IS Frappe's Statuspage tenant, titled "Frappe Status", and which answers with the sentence quoted here. That is not a wall in front of a page that exists publicly; it is the vendor's own status host stating the page is inactive and team-members-only. Cross-checked the documentation: docs.frappe.io/cloud/reliability describes continuous monitoring, incident tracking and 24x7 incident response, and docs.frappe.io/cloud/getting-started/uptime publishes per-provider uptime guarantees -- and NEITHER links a public status page; the uptime page instead says users are notified of downtime by email. POSITIVE CONTROL: the same Statuspage host returns a rendered, publicly readable page for tenants that are active, so a live Frappe status page would have rendered. No public, per-component, login-free status page exists. Moving unknown to no. https://frappe.statuspage.io/ · retrieved 2026-09-06 adversarially verified
24/7/365 live human support by phone is included in the base subscription, not sold as a premium support tier.
reliability-247-live-support
Upheld and now documented rather than inferred. frappe.io/support-sla: business hours are '10:00 to 18:00 Indian Standard Time (IST) (Monday-Friday)', weekend coverage is email-only for critical issues, and phone support is not in standard plans — 'Priority & Phone Support' must be purchased separately. For a US restaurant, 9pm Friday local is outside every published support window. The dossier's risk framing understates it: there is no support entitlement at all below the $50 plan. https://frappe.io/support-sla · retrieved 2026-08-01 adversarially verified
The vendor offers in-person on-site installation and go-live support (first-party or certified dealer network), not remote-only self-install. differentiator
reliability-onsite-install
Frappe itself is remote-only, but the pricing page markets a 'global network of 200+ partners' for implementation, which in practice includes local on-site work. Frappe does not warrant or price partner on-site delivery. https://frappe.io/erpnext/pricing · retrieved 2026-08-01
A hardware replacement/advance-exchange program with a stated turnaround time is included or purchasable.
reliability-hardware-replacement-sla
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. This cell asks whether a replacement/advance-exchange programme with a stated turnaround is included or purchasable; the SLA answers by excluding hardware supply from the agreement entirely. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bRMA\b/i and /\badvance exchange\b/i return ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bdepot\b/i survives on exactly one line, as a substring inside the escaped format_data blob of the Purchase Receipt serial-and-batch print format. POSITIVE CONTROL: the very same document publishes purchasable service tiers WITH stated turnarounds -- Standard, Premium and L2-bug tables of response/resolution time per issue priority, gated on the $50-and-above Frappe Cloud plan for product warranty -- so the vendor states turnarounds where it takes on obligations. For hardware it states an exclusion. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
The vendor publishes a current PCI DSS v4.0/4.0.1 Attestation of Compliance or equivalent (e.g. validated P2PE listing) covering the post-March-2025 future-dated requirements.
reliability-pci-dss-4-attestation
The prior rationale recorded unknown because no AoC was located. An absence is not evidence, so I went to the vendor pages that ENUMERATE its compliance posture and treated the enumeration as closed. Two of them, both fetched today: the certifications page quoted here, and the "Compliance & Certifications" section of docs.frappe.io/cloud/faq/architecture-and-security ("Yes, we are certified under ISO 9001:2015, ISO 27001:2022, and SOC-2 Type-2 standards."). Both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2, with dates, a certifying body (ISOQAR), a Statement of Applicability version and date, a Dec 2025 surveillance audit and an ISMS scope -- and neither names PCI DSS at any version, a validated P2PE listing, an AoC, or an SAQ type. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: zero word-boundary hits for /\bPCI\b/i, /\bP2PE\b/i, /\bAoC\b/i or /\bSAQ\b/i in erpnext v16.34.1, in frappe v16.33.0, or on any of the 1,863 docs pages. POSITIVE CONTROL: the same security FAQ answers compliance questions negatively when the answer is no ("Is there a WAF protecting applications?" -- "No, but a server level firewall is available"; "Is there automated failover for databases?" -- "No"), so this publisher does not omit inconvenient answers. Frappe's architecture keeps card data out of the application, but the vendor publishes no PCI DSS 4.0/4.0.1 attestation and no P2PE listing. Moving unknown to no. https://frappe.io/quality-and-information-security · retrieved 2026-09-06 adversarially verified
Multi-factor authentication is enforceable on back-office and POS administrative logins, with role-based permissions.
reliability-mfa-role-based-access
Both halves documented. 2FA is activated with "bench --site [sitename] set-config enable_two_factor_auth true" and configured in System Settings (validation method, QR expiry, issuer), offering "OTP App = TOTP using Soft or Hard Token" and "Email/SMS = HOTP using Email or SMS". On activation all users including the Administrator must complete a second factor, and enforcement is role-scoped — an administrator can disable 2FA for the All role and enable it on selected roles. RBAC is documented separately (per-role read/write/create/submit/cancel/amend/delete, field-level Permission Levels, User Permissions). Caveat: "2FA does not apply to login by Web Users and API login", so webshop guests and API tokens sit outside it. Upgraded from partial on verification: the earlier downgrade rested on the previously cited 2FA URL 404ing, not on the capability being absent. https://docs.frappe.io/erpnext/setup-two-factor-authentication · retrieved 2026-08-02 adversarially verified
A public, free training library (video/LMS) and a practice/training mode on the terminal exist for staff onboarding.
reliability-self-serve-training
Free public documentation at docs.frappe.io, an active public forum, and Frappe School courses cover self-serve learning. There is no POS training mode that lets staff practice without writing real transactions. https://docs.frappe.io/erpnext/point-of-sale · retrieved 2026-08-01
Any terminal can assume the master/server role automatically if the designated primary terminal or local server fails. differentiator
reliability-failover-terminal-role
Searched the master-election vocabulary over the code census: /\bfailover\b|\bfail.over\b/i, /\bprimary terminal\b/i, /\belection\b/i, /\bquorum\b/i, /\bpeer\b/i, and /\bmaster\b/i as a role. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bfailover\b|\bfail.over\b/i returns ZERO files in erpnext v16.34.1 and frappe v16.33.0. ARTEFACT: the POS is a browser page inside the Frappe desk; erpnext.PointOfSale.Controller does a frappe.call to check_opening_entry() before it can render, so a terminal is a pure client with no server role to assume, no local datastore and no peer awareness. The bench/MariaDB server is the single point of failure. POSITIVE CONTROL, and it cuts the right way: Frappe DOES document failover, but only at the infrastructure layer and only manually -- docs.frappe.io/cloud/faq/architecture-and-security says "No, there is no automated failover for databases on Frappe Cloud", and docs.frappe.io/cloud/servers/other-information/on-prem-failover-setup describes a beta, support-ticket-gated WireGuard replica to a customer-run server ("disabled by default for all servers"). Neither is a terminal assuming a server role. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/pos_controller.js · retrieved 2026-09-06 adversarially verified
Terminals support an automatic cellular/LTE failover for connectivity, first-party or documented.
reliability-cellular-backup
The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. A first-party LTE failover would be a device Frappe supplies, and it supplies none. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bLTE\b/i, /\bcellular\b/i, /\bfailover\b/i or /\bSIM\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero for LTE/cellular across the 1,863-page docs census -- so the second half of the claim, a DOCUMENTED failover, fails too. POSITIVE CONTROL: the vendor does document connectivity-layer operations when they exist -- docs.frappe.io/cloud covers obtaining a static IP, custom domains, moving a site across regions, and an on-prem WireGuard replica -- so cellular-failover guidance would sit in that space. A tablet's own radio would carry the browser session; that is the device, not the product, and with no offline mode the gap is not covered anyway. https://frappe.io/support-sla · retrieved 2026-09-06 adversarially verified
Commercial, compliance & data ownership
Vendor publicly offers a month-to-month subscription with no minimum multi-year term commitment for its core POS software tier. differentiator
commercial-month-to-month-contract
Frappe Cloud product documentation: "Frappe Cloud billing cycles are monthly" and "each site is microbilled on a daily basis - when you select a plan, the monthly amount is divided by the number of days in the current calendar month", so a site is charged only for the days it exists. The Disable Account / Cancel Subscription doc gives a self-service path (drop sites and servers, Settings > Team Actions > Disable) after which "your billing will be paused"; no notice period, minimum term or termination fee is stated anywhere in the billing docs. Self-hosting the GPL-3.0 stack involves no subscription at all. https://docs.frappe.io/cloud/billing/billing-cycle · retrieved 2026-08-06 adversarially verified
Vendor's published terms of service or MSA state no early termination fee / no liquidated damages for cancelling the software subscription before term end. differentiator
commercial-no-early-termination-fee
CORRECTION -- the affirmative contractual statement the rationale said was missing exists and is public. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the retrieved legal corpus for termination, early termination, liquidated damages, penalty, notice -- and both loaded phrases DO occur, so I read every hit rather than reporting a zero. 'liquidated damages' occurs twice (Frappe Cloud terms 12, Enterprise 10.3) and both run toward the customer: they are the remedy Frappe may owe if its liability cap is unenforceable. 'early termination' occurs once, Enterprise 7.3(b), and it is the label on a REFUND: 7.3(a) provides that if the customer prepaid and terminates before the prepaid term ends, other than for its own breach, 'Frappe shall refund to the Customer the unused portion of such prepaid fees on a pro-rata basis', and 13.4 repeats it. So the contracts pay money out on early termination rather than charging for it. The quoted Cloud clause covers the self-serve product and is the opposite of an ETF: terminate without cause, no prior written notice, by discontinuing payment, effective at the end of the then-current billing period. The one countervailing term is Cloud 8.4.2, unused prepaid credits non-refundable -- a forfeiture of money already paid, not a charge for leaving. Self-hosted GPL-3.0 use has no subscription to cancel. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
The auto-renewal term and the required cancellation notice window (e.g. 30/60/90 days) are stated in publicly accessible contract terms rather than only in a signed quote.
commercial-autorenew-terms-published
CORRECTION to an `unknown` -- the ToS/MSA was retrievable. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. The answer splits by product, which is why this is partial rather than yes or no. For self-serve Frappe Cloud the cancellation side IS publicly stated: Frappe Cloud terms 10.1.3 says the customer may terminate without cause with no prior written notice, effective at the end of the then-current billing period -- a stated notice window of zero on a billing-period cadence. For Enterprise, the quoted clause does exactly what the claim excludes: it relegates 'Renewal terms, price adjustments, or notice periods' to the Enterprise Order Form, the signed quote, and section 8.3 makes that Order Form prevail on commercial terms. Neither published agreement states an auto-renewal term length. Positive control: searching the same corpus for 'renew' returns hits only in this agreement, at 8.2, 9.3, 15.10, 15.14 and 15.19 -- the word is found where it exists. https://docs.frappe.io/legal/terms/enterprise-support-agreement · retrieved 2026-09-06 adversarially verified
The POS software can be purchased and operated with a third-party payment processor of the operator's choice (no mandatory in-house processing lock). differentiator
commercial-processing-not-bundled
ERPNext manual: "to enable Stripe payment service, you need to configure parameters like Publishable Key, Secret Key" - the merchant supplies credentials from their own processor account, and Frappe is never a party to the processing relationship. The first-party frappe/payments app documents five interchangeable gateways (Razorpay, Stripe, Braintree, PayPal, PayTM) implemented as separate Payment Gateway DocTypes and linked through a Payment Gateway Account, so the processor is a per-account configuration choice. No in-house processing product, attach requirement or revenue share is documented anywhere. Caveat noted elsewhere in the record: these are online/e-commerce gateways, so card-present integration must be built or bought. https://docs.frappe.io/erpnext/stripe-integration · retrieved 2026-08-06 adversarially verified
Vendor publishes an interchange-plus (cost-plus) processing rate option with the markup stated as a specific bps + per-transaction figure, rather than only blended/flat card-present rates. differentiator
commercial-interchange-plus-published
Not applicable — Frappe is not an acquirer or ISO and publishes no processing rates of any structure. https://frappe.io/erpnext/pricing · retrieved 2026-08-01
The processing agreement caps or prohibits unilateral vendor-initiated rate increases outside of pass-through interchange/network changes, or grants penalty-free exit on any increase. differentiator
commercial-rate-increase-clause
CORRECTION to an `unknown` -- the price-change terms were located. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the twelve-page legal corpus for price, pricing, rate, increase, interchange, pass-through. Invariance: zero occurrences of 'increase' in any of the twelve pages, and zero of 'interchange' -- there is no cap, no ceiling, no penalty-free exit tied to a price change, and no processing agreement at all, since Frappe is not the merchant's card processor (Mode of Payment's type enum in the product is Cash/Bank/General/Phone, with no acquirer relationship anywhere). What the published terms do say is the quoted clause: an unqualified unilateral right to modify pricing at sole discretion. The Enterprise Support Agreement 9.4 adds the only limit that exists -- price changes do not affect fees under an active Order Form during its current term, but 'Renewals and new Order Forms shall be subject to the revised pricing.' The mitigation is practical rather than contractual: under 10.1.3 a Cloud customer can leave at the end of any billing period, so an increase is escapable even though no clause grants that right on the increase. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
Per-location and per-additional-terminal software pricing is published as specific dollar figures on the vendor's public site (not 'contact sales' only).
commercial-pricing-published
Three problems the researcher missed: (a) every figure is an 'onwards' floor, which the dossier notes but then scores as a clean yes; (b) the two vendor pricing pages publish different server prices (see pricing.software); (c) a material commercial condition is undisclosed on the pricing page — frappe.io/support-sla states the standard SLA applies only to 'Frappe Cloud customers entitled for product warranty as per subscription plans of $50 and above', so the advertised $5 and $20 entry plans carry no support entitlement. That is a published-price-with-hidden-gating pattern, not full transpare https://frappe.io/support-sla · retrieved 2026-08-01 adversarially verified
Individual modules (online ordering, KDS, loyalty, inventory, payroll, marketing) can be purchased à la carte and cancelled independently without repricing the base POS subscription. differentiator
commercial-module-unbundling
Frappe Cloud documents per-app subscriptions separate from the site plan: "During app installation on a Frappe Cloud site, the user gets an option to select a plan. They can also change the plan from their site dashboard", and "Currently only monthly recurring plans are available. These are charged on pro-rata basis, i.e. if the customer uses your app's $30/mo plan for 10 days and let's say uninstalls the app, they will be charged $10 for that app at the end of the month." Apps are installed per site (Apps tab > Install App) and uninstalled individually (Apps tab > three dots > uninstall, /cloud/how-to-uninstall-an-app-from-the-site); the site plan is changed on a wholly separate screen. Base modules - ERPNext, Frappe HR, Webshop, Insights, CRM, Helpdesk - are separate free apps, so there is no bundled base POS subscription to reprice. Re-evidenced 2026-08-09; the prior citation (cloud.frappe.io/marketplace, a catalogue listing) went stale and did not support the a-la-carte/cancellation half of the claim. https://docs.frappe.io/cloud/app-plan · retrieved 2026-08-09 adversarially verified
All required terminals, KDS screens, and printers can be purchased outright at a published price, with no mandatory multi-year hardware lease or rental.
commercial-hardware-purchase-outright
All hardware is bought outright from third parties at market price. Frappe has no lease, no rental, and no hardware SKUs to bundle. https://frappe.io/erpnext/pricing · retrieved 2026-08-01
Vendor documents support for at least one non-proprietary/third-party hardware option (e.g. standard iPad, Epson/Star ESC/POS printers, generic cash drawer) rather than requiring vendor-only devices. differentiator
commercial-hardware-not-locked
Print Settings documents a generic CUPS print server addressed by IP and port with a selectable default printer, and Raw Printing documents driving any thermal printer in its native command language; neither is vendor-branded, and Frappe sells no hardware to lock to. The POS itself is a browser Desk page, so the terminal is whatever the operator buys. Against the claim’s wording: no specific manufacturer is named on any Frappe page, so Epson/Star support is generic rather than an explicit compatibility list. Re-cited on verification — the POS manual page previously cited says nothing about printers or devices. https://docs.frappe.io/erpnext/print-settings · retrieved 2026-08-02 adversarially verified
Operators can self-serve export their full transactional history (orders, line items, payments, labor) to CSV or a documented API without contacting support or paying a fee.
commercial-data-export-self-serve
"‘Data Export’ helps you extract data from any DocTypes to a CSV or an Excel format", with filters and field selection, run by the operator with no support ticket and no fee; REST reads the same DocTypes programmatically. Orders, line items and payments are ordinary DocTypes. Labor requires installing Frappe HR, which is free but is a second application. Re-cited on verification: the REST page previously cited documents no export tooling, backups or CSV/XLSX output. https://docs.frappe.io/erpnext/data-export · retrieved 2026-08-02 adversarially verified
Guest/customer records, loyalty balances or point ledgers, and gift-card liability balances are exportable in machine-readable form by the operator. differentiator
commercial-export-customer-and-loyalty
Customer, Contact, Address and Loyalty Point Entry are ordinary DocTypes, and the Data Export tool extracts "any DocTypes to a CSV or an Excel format" with filters and field selection. Gift-card liability is not exportable because gift cards do not exist in the product. Re-cited on verification: the Loyalty Program page previously cited documents accrual, tiers, expiry and redemption but nothing about export. https://docs.frappe.io/erpnext/data-export · retrieved 2026-08-02 adversarially verified
Contract or documentation specifies a post-termination data retrieval window (a defined number of days during which the operator can still export their data) rather than immediate cutoff. differentiator
commercial-post-termination-export-window
All twelve pages of the docs.frappe.io/legal space were fetched 2026-09-06 as raw markdown via the publisher's append-.md affordance, every one returning 200. The Enterprise Support Agreement's Effect of Termination clause, quoted here, states exactly what the claim asks for: a minimum 180-day window from termination during which the customer may download their data, after which Frappe may delete it without notice. WHY THIS IS PARTIAL AND NOT YES -- now closed rather than deferred: the self-serve Frappe Cloud Service and Support Agreement, the contract most operators are actually on, states no equivalent window. Its clause 6.9 ('Data Retention & Deletion') says only that data 'shall be retained in accordance with the subscribed plan for Cloud Hosting, or otherwise deleted upon Customer request submitted via the support portal', deferring to the Cloud plan documentation. I censused that space: the 160 Frappe Cloud pages define no post-termination window either, and docs.frappe.io/cloud/sites/drop-delete-your-site describes dropping a site as an immediate, confirmed, permanent delete ('You will lose all the data in your site as you proceed'), the only surviving artefacts being the backup rotation (7 daily / 4 weekly offsite, 48-hour server snapshots) rather than a stated retrieval window. So the window is contractually defined for Enterprise and undefined for self-serve, where the default is immediate deletion on the operator's own action. Moot for the self-hosted GPL-3.0 operator, who never hands the data over. POSITIVE CONTROL: the same legal search resolves the retention, termination and refund clauses where they exist. https://docs.frappe.io/legal/terms/enterprise-support-agreement · retrieved 2026-09-06 adversarially verified
Published terms explicitly state the merchant owns its transaction and customer data, and constrain the vendor's right to use or resell that data (beyond aggregated/de-identified use) for its own products or marketing. differentiator
commercial-data-ownership-clause
CORRECTION to an `unknown` -- the terms were retrievable and they answer both halves of the claim affirmatively. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the retrieved legal corpus for ownership, property, sell, share, disclose, aggregated, de-identified. The quoted clause states merchant ownership outright, and the very next clause supplies the use restriction the claim asks for: '6.4 Confidentiality -- Frappe shall not sell, share, or otherwise disclose Customer Data to third parties, except where required by law or legal process.' That is a stricter constraint than the claim's floor, since it carves out no aggregated or de-identified vendor use at all. Section 9.1.1 reinforces it: the invoice holder 'is deemed the owner of the account and all associated data.' Adversarial check: zero occurrences of 'aggregated' or 'de-identified' in the twelve pages, so no separate clause reopens the vendor-use door; the Privacy Policy governs Frappe's own website visitors, not Customer Data. Positive control: the same search finds the licensing and confidentiality sections in the same document. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
Vendor documents validated P2PE or hardware-encrypted card entry plus tokenization such that the merchant's PCI scope is reduced to SAQ A / SAQ P2PE-HW, and names the applicable SAQ.
commercial-pci-p2pe-tokenization
Searched PCI, PCI DSS, P2PE, SAQ, tokenization, cardholder, card number and EMV across three bounded corpora: (1) Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. (2) the 1,863-page docs census; (3) the twelve-page legal space at docs.frappe.io/legal, fetched today, all twelve returning 200. Invariance: zero occurrences of PCI, P2PE or SAQ in any of the three. Two of my own controls carried traps and I discarded them: case-insensitive 'tokeniz' returns 7 files that are entirely babel jslexer and SQLite FTS5 tokenizer configuration, and SAQ/VPAT/A2P in the repositories and PCI/P2PE in the docs are all substrings inside base64 image data-URIs. The artefact that would carry a PCI position is the Frappe Cloud Service and Support Agreement's own Security Standards clause, effective 1 April 2026, and it names ISO 27001 and nothing else; frappe.io/security returns 200 today but is a vulnerability-disclosure page with zero occurrences of PCI, P2PE, SAQ, SOC 2 or ISO 27001. Card acceptance is not modelled at all: Mode of Payment's type enum is Cash/Bank/General/Phone. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
Vendor documents PCI DSS v4.0.1 future-dated controls in effect since 31 Mar 2025 — notably MFA for all access to the cardholder data environment including POS and back-office logins, and (for hosted ordering pages) payment-page script integrity monitoring per Req 6.4.3/11.6.1.
commercial-pci-dss-4-controls
CORRECTION to an `unknown` -- the documents that would carry a PCI position were all retrieved and none does. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched PCI, PCI DSS, 4.0.1, cardholder data environment, CDE, script integrity, 6.4.3, 11.6.1, MFA, two-factor across the two repositories, the 1,863-page docs census and the twelve legal pages. Invariance: zero occurrences of 'PCI DSS' or 'CDE' in any of the three corpora, and zero non-base64 occurrences of 'PCI' in the docs (the six raw docs hits are all base64 image data-URIs, a reader artefact I discarded). The clause that would carry it is quoted here and names ISO 27001 alone; frappe.io/security returns 200 today and contains zero occurrences of PCI, P2PE, SAQ, SOC 2 or ISO 27001, and frappe.io/pci and frappe.io/compliance both 404. The technical half is genuinely available and undocumented: frappe ships built-in 2FA and System Settings can force it on all logins, so MFA is enforceable -- but no document defines a cardholder data environment or takes a Req 6.4.3 / 11.6.1 payment-page script-integrity position. Positive control: the same searches find the security, privacy and data-protection clauses that DO exist. https://docs.frappe.io/legal/terms/frappe-cloud-terms · retrieved 2026-09-06 adversarially verified
Product provides in-app tooling for CCPA/CPRA and GDPR data-subject requests — locating, exporting, and deleting an individual guest's records — plus a published DPA the operator can execute.
commercial-privacy-dsar-tooling
CORRECTION to both clauses of the rationale, value unchanged. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. First, the DPA is published, not absent: Frappe Cloud terms 6.7 offers one for digital execution and docs.frappe.io/legal/data-protection/data-process-addendum-sample serves a downloadable sample copy, alongside a named Grievance Officer page and a Frappe Cloud Data Processors list. Second, the in-app tooling is real but narrower than 'an individual guest's records': Personal Data Download Request and Personal Data Deletion Request are shipped doctypes with a verification and approval flow, but they act only on the doctypes registered in the user_data_fields hook. frappe/hooks.py registers Access Log, Activity Log, Comment, Contact, Contact Email and Address; ERPNext's whole registration is the quoted six lines, Lead and Opportunity. Customer, Sales Invoice, POS Invoice and Loyalty Point Entry are absent from it, so locating, exporting and deleting a guest's transaction and loyalty records is not covered by the shipped tooling. Positive control: the deletion machinery itself is found by the same search, including the anonymization_matrix and the Personal Data Deletion Step child table. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/hooks.py · retrieved 2026-09-06 adversarially verified
Vendor publishes an accessibility conformance report (VPAT/ACR) claiming WCAG 2.1 AA (or later) for its self-order kiosk and consumer web-ordering surfaces, including a documented tactile/audio non-visual access mode on kiosks. differentiator
commercial-wcag-kiosk-accessibility
Searched WCAG, VPAT, 'accessibility conformance', ACR and kiosk across four bounded corpora: (1) Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. -- word-anchored kiosk returns files=0 lines=0; (2) the 1,863-page docs census -- zero non-base64 lines for WCAG, VPAT or kiosk (the raw WCAG/VPAT hits are base64 image blobs on erpnext/sales-return and erpnext/deleting-all-transactions-for-the-company, a reader artefact I discarded); (3) the twelve-page docs.frappe.io/legal space fetched today, zero; (4) frappe.io/accessibility, which returns 404 today while frappe.io/security returns 200, so the absence is of the document, not of the site. The kiosk half is settled positively by the vendor's own product introduction, quoted here: ERPNext's POS is described as staffed retail transaction handling with inventory, payment methods, loyalty and reporting -- there is no self-order kiosk in the two repositories to certify. Positive control: the same docs census finds 'Point of Sale' on 7 pages and 'Loyalty Program' on 6. https://docs.frappe.io/erpnext/point-of-sale · retrieved 2026-09-06 adversarially verified
POS supports card-network-compliant dual pricing / cash discount or surcharging with automatic exclusion of debit and prepaid cards from any surcharge, and required receipt and menu-board disclosure of the fee. differentiator
commercial-dual-pricing-compliant
Searched the vendor's words: 'Mode of Payment', 'Sales Taxes and Charges', 'Pricing Rule', plus surcharge, cash discount, dual pricing, cardholder, card number, BIN, debit and prepaid. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'cash discount', 'dual pricing', 'cardholder', 'card number' and, in the repositories, 'surcharg'. Two controls of mine carried traps: word-anchored BIN returns 101 files, all /bin/ paths under case-insensitive matching; and 'surcharg' DOES return 3 docs pages, but every one is Indian tax-template vocabulary ('a surcharge, cess, or levy calculated only on another tax or charge amount' on erpnext/tax-on-another-tax-amount), not card surcharging. The dispositive artefact is Mode of Payment: its whole type enum is Cash/Bank/General/Phone, so the system holds no card brand, no debit/credit flag and no BIN, and cannot mechanically exclude debit and prepaid from a surcharge even if one were configured as a tax row. No receipt or menu-board fee-disclosure feature exists. Positive control: Sales Taxes and Charges Template and Pricing Rule are both found by the same search. https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json · retrieved 2026-09-06 adversarially verified
Adversarial verification
An independent pass was instructed to refute this record, defaulting to downgrade when uncertain. It challenged 199 values — 41 upheld, 147 downgraded, 11 upgraded. It separately resolved 14 previously unknown values. This is published in full because a reader who can see which values were contested, on what evidence, and which way they moved has something no affiliate-funded comparison offers.
Pricing and identity
| Field | Verdict | What the verifier found |
|---|---|---|
| pricing.implementation_fee | upheld | Verified on the pricing page: the 'global network of 200+ partners' language is present, Starter Packs are described as 'certified partners will help you get started quickly and economically' with no price attached, and no implementation figure of any kind is published. The dossier is right that this is the largest undisclosed cost line and it deserves the prominence given. source |
| pricing.processing_rate | upheld | Nothing on the pricing page or POS documentation sells card acceptance; the only card references are Frappe charging the customer for hosting. commercial-processing-not-bundled and payments-published-rates follow correctly from this. This is one of the few 'no' scores in the dossier that is genuinely structural rather than merely undocumented. source |
| pricing.software | downgrade-to-partial | The record repeats the marketing page's figures as settled fact and does not reconcile them, which reintroduces an error an earlier pass had already caught. I retrieved both vendor pages today. frappe.io/erpnext/pricing shows Sites '$5 onwards /mo' (₹410), Servers '$20 onwards /mo' (₹1,800) and Premium Servers '$125 onwards /mo' (₹5,400). Frappe's own Frappe Cloud pricing page shows Sites '$5 onwards /mo' (₹410) and Servers '$40 onwards /mo' (₹3,600), with no premium tier and no ₹1,800 figure anywhere on it. Only the $5 Sites floor survives cross-checking; server pricing must be reported as $20–$40 conflicting between two first-party pages, source-dated. The AGPL-versus-GPL contradiction the record flags is real and I confirmed it independently — license.txt in frappe/erpnext opens 'GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007' while the pricing page says 'AGPL-3.0 licensed'. source |
Capability claims
| Claim | As first scored | Verdict | What the verifier found |
|---|---|---|---|
| commercial-pricing-published | yes / documented | downgrade-to-partial | Three problems the researcher missed: (a) every figure is an 'onwards' floor, which the dossier notes but then scores as a clean yes; (b) the two vendor pricing pages publish different server prices (see pricing.software); (c) a material commercial condition is undisclosed on the pricing page — frappe.io/support-sla states the standard SLA applies only to 'Frappe Cloud customers entitled for product warranty as per subscription plans of $50 and above', so the advertised $5 and $20 entry plans carry no support entitlement. That is a published-price-with-hidden-gating pattern, not full transparency. source |
| reliability-247-live-support | no / inferred | upheld | Upheld and now documented rather than inferred. frappe.io/support-sla: business hours are '10:00 to 18:00 Indian Standard Time (IST) (Monday-Friday)', weekend coverage is email-only for critical issues, and phone support is not in standard plans — 'Priority & Phone Support' must be purchased separately. For a US restaurant, 9pm Friday local is outside every published support window. The dossier's risk framing understates it: there is no support entitlement at all below the $50 plan. source |
| labor-granular-rbac | yes / documented, source: docs.frappe.io/framework/user/en/api/rest | upheld | Capability upheld but the citation is wrong and I had to source it myself. The REST API page documents CRUD, auth and pagination only — it says nothing about permissions, permlevels or User Permissions. The correct source is the users-and-permissions page, which does document read/write/create/submit/cancel/amend/delete per role, field-level Permission Levels, and User Permissions restricting by Link field value. Re-cite before publishing. source |
| extensibility-webhook-reliability | partial / documented | upheld | Verified against the webhooks guide: X-Frappe-Webhook-Signature carrying a base64-encoded HMAC-SHA256 of the payload, doc-event triggers, and 'a webhook request log is created for every successful request'. Retry/backoff is genuinely absent from the documentation — the partial is correctly conservative, and the log-only-on-success detail is accurate. source |
| menu-pricing-dayparting | no / documented | upheld | Verified against the Pricing Rule doc: temporal control is 'Valid From and Valid Up To' date range only, with no time-of-day or day-of-week condition documented. This is a correct documented 'no', not an inference. It matters because dayparting is table stakes for a pizza operator. source |
| guest-loyalty-offer-stacking-rules | yes / documented | upheld | Verified: Pricing Rule documents Priority to resolve overlapping rules, 'Apply Multiple Pricing Rules' for stacking, and Mixed Conditions across selected items. Genuinely configurable precedence and combinability. source |
| guest-loyalty-accrual-models | yes / documented | upheld | Verified: Collection Factor drives points-per-spend ('with a Collection Factor of $100, an eligible $1,000 invoice earns 10 points'), Conversion Factor sets redemption value, and 'Programs can use one tier or several tiers based on a Customer's cumulative eligible spend'. Caveat the dossier did not surface: the doc frames earning against submitted Sales Invoices and gives no POS- or webshop-specific accrual guidance, which strengthens the existing 'unknown' on digital-loyalty-attach. source |
| payments-house-accounts | yes / documented | upheld | Verified in part and it holds: the Customer doc covers per-company credit-limit rows evaluated against submitted exposure, and points to the Accounts Receivable report. Minor correction — 'periodic Statement of Accounts' is not on the cited page, so trim that specific to avoid an unsupported detail inside an otherwise sound yes. source |
| inventory-shelf-life-expiry | yes / inferred — shelf life days, batch-wise balance history, FEFO | downgrade-to-partial | Only expiry survives. The Batch documentation covers expiry date and expiry-vs-posting-date filtering, but the retrieved page documents neither 'Shelf Life in Days' on Item, nor Batch-Wise Balance History, nor FEFO auto-selection. Three of the four specifics in the note are unsourced inference on a cell scored yes with no URL. source |
| delivery-tracking-page | partial / inferred — 'Delivery Trip can email/SMS customers an estimated arrival notification' | downgrade-to-unknown | The Delivery Trip documentation makes no mention of customer notification by email or SMS. It documents driver/vehicle selection, multiple stops, Google Maps best-route calculation and Google-sourced ETAs — nothing outbound to the guest. The partial rests entirely on an unverified notification feature. source |
| delivery-route-map | partial / inferred | upheld | Verified and can be upgraded from inferred to documented: 'Using Google Maps, the best route for the deliveries will be calculated' and Delivery Trip will 'calculate the estimated arrival time for the deliveries. This data is fetched from Google Maps.' One correction — the doc does not state that the operator must supply a Google Maps API key, so drop that as an asserted fact even though it is likely true. source |
| reliability-local-transaction-engine | yes / documented, source: frappe.io/erpnext/pricing | upheld | Capability upheld, citation wrong. The pricing page says nothing about self-hosting; it sells the opposite. The supporting evidence is Frappe's production setup documentation (docker images as the recommended production path, plus 'bench setup production' with Supervisor/Nginx). Re-cite to the production-setup docs. source |
| reporting-scheduled-delivery | yes / inferred — Auto Email Report doctype | downgrade-to-unknown | Scored yes with confidence 'inferred' and no source URL whatsoever. Auto Email Report is a specific named doctype with specific claimed behaviour (daily/weekly/monthly, CSV/XLSX/HTML, recipient list) and none of it is cited. source |
| extensibility-app-marketplace | yes / documented — '342+ apps' | upheld | Verified verbatim: the marketplace page reads 'Showing 342 apps', and URY - Restaurant POS & ERP, POSNext, GETPOS, KLiK PoS, POS Restaurant and POSpire are all present as third-party listings. Note the vendor's own cloud pricing page markets '150+ apps' — an internal inconsistency worth flagging but the marketplace listing itself is the stronger source. Developer revenue-share terms are indeed not published, so the 'unknown' on extensibility-partner-revshare is correct. source |
| reporting-webhooks | yes / grade B, docs.frappe.io/framework/user/en/guides/integration/webhooks | downgrade-to-partial | The taxonomy claim requires webhooks 'with documented retry behavior and payload signature verification'. I retrieved the webhooks guide myself: the signature half is documented — 'an additional header (X-Frappe-Webhook-Signature) will be added to the request before it's sent out, with its value being generated from the secret as a base64-encoded HMAC-SHA256 hash of the payload' — and the retry half is entirely absent, with the page stating only that 'a webhook request log is created for every successful request'. Half a required conjunction is a partial, not a yes. The record scores the identical evidence as partial at extensibility-webhook-reliability, so this cell was also internally inconsistent with its own neighbour. source |
| extensibility-menu-write-api | yes / grade B, docs.frappe.io/framework/user/en/api/rest | downgrade-to-partial | The claim is that 'menu items, modifiers, and prices can be written and updated via API'. I retrieved the REST page and it does support the items-and-prices half — 'Frappe framework generates REST API for all of your DocTypes out of the box', so Item, Item Price, Item Variant and Pricing Rule are writable over POST/PUT. But the modifier third of the claim cannot be satisfied at any price: the record's own menu-pricing-nested-modifiers scores no because ERPNext has no modifier construct. An API cannot write an object that does not exist, and this is a differentiator cell where the whole conjunction should be met before a yes. source |
| extensibility-order-injection-api | yes / grade B, docs.frappe.io/framework/user/en/api/rest | downgrade-to-partial | The claim requires externally originated orders to land 'as first-class tickets that fire to KDS/printers and land in reporting'. The REST page confirms POST to /api/resource/:doctype creates submittable documents for any DocType, so the land-in-reporting half holds. The fire-to-KDS half does not, and the researcher's own note concedes it verbatim: 'it cannot fire to KDS/printers because no KDS exists'. A yes whose note disclaims a required element of the claim is the exact pattern this pass exists to catch. source |
| menu-pricing-channel-price-books | yes / grade B, docs.frappe.io/erpnext/price-list | downgrade-to-partial | The claim asks for distinct price books per channel — dine-in, pickup, delivery, kiosk, each third-party marketplace — plus percentage-markup rules over a base price. The percentage-rule half is real (Pricing Rule applies a rate or discount percentage over the selected Price List). The per-channel half is not: Price Lists are selected by POS Profile, Customer, Customer Group or Territory, and the record itself scores digital-kiosk, delivery-3p-direct-integration and delivery-menu-push as no, so three of the five channels the claim enumerates do not exist in the product to be priced. The researcher's own note says it — 'Channels are modeled as price lists, not as named channels' — and then scored a yes anyway. source |
| multi-location-price-zones | yes / grade B, docs.frappe.io/erpnext/price-list | downgrade-to-partial | The claim requires one item to carry different prices per location group, per order channel AND per daypart without duplicating the item record. The per-location-group and per-item-record halves hold — many Item Price rows hang off one Item, selected per POS Profile, company, currency, customer group and territory. The daypart dimension does not exist: menu-pricing-dayparting is scored no in this same record and was independently verified against the Pricing Rule page, whose only temporal control is a Valid From / Valid Up To date range with no time-of-day or day-of-week condition. Two of three dimensions is a partial. source |
| multi-location-multi-tax-jurisdiction | yes / grade B, docs.frappe.io/erpnext/tax-rule | downgrade-to-partial | I retrieved the Tax Rule page the researcher cited. It documents matching on Customer/Supplier, on the billing and shipping addresses 'fetched if saved in the Customer/Supplier master', on Tax Category ('Setting a Tax Category allows applying multiple Tax Rules to a transaction based on different factors') and on Item or Item Group — that last one genuinely covers the prepared-food-versus-grocery class distinction the claim names. What the page does not document, and I could find nowhere else, is any of the other three elements of the claim: per-location tax configuration (Tax Rule keys on the party's address, not on the selling store), an inclusive-versus-exclusive tax setting, or per-location tax exemptions. Item-class rates plus party-address matching earn a partial, not the full jurisdiction claim. source |
| labor-manager-override-audit | yes / grade A, frappe Version doctype JSON | downgrade-to-partial | The Version doctype evidence is sound as far as it goes — track_changes with a field-level diff, owner and creation timestamp, and submitted documents immutable behind cancel-and-amend. But the claim is that 'manager overrides and approvals are attributed to the individual approver', and there is no override or approval event in this product to attribute. The record's own payments-refund-void-controls states there is 'no manager-PIN-at-terminal approval prompt and no approver field', and order-capture-void-comp-controls says the same. What Frappe logs is the actor who made the change, not a second party who authorised it. Audit trail yes; approver attribution no. source |
| inventory-unit-conversion-yields | yes / grade B, docs.frappe.io/erpnext/item | downgrade-to-partial | The UOM half is documented and the researcher's verbatim quote is accurate — alternate UoMs with conversion factors, '500 Nos of screws = 1 Kilogram'. The claim also requires 'a yield/waste percentage applied to raw-to-usable conversion', and the note reaches for BOM scrap and process loss to cover it. I read the BOM page: scrap is 'the scrap Item that will be created when manufacturing', and process loss is what happens 'when a scrap item matches the finished product being manufactured', where 'its quantity is subtracted from the manufactured Item quantity'. That is shrinkage on a produced item's output, not a usable-yield percentage on a purchased raw ingredient, which is the restaurant mechanic the claim describes. No such per-item yield field exists. source |
| digital-guest-data-ownership | yes / grade B, docs.frappe.io/framework/user/en/api/rest | downgrade-to-partial | The claim has two halves: the operator can export first-party guest records in bulk without fee or approval, and the vendor documents that the operator owns them. The export half survives and is now properly sourced — the Data Export manual states "'Data Export' helps you extract data from any DocTypes to a CSV or an Excel format", with filters and field selection, in-app and free. The ownership half is not documented anywhere: the record's own commercial-data-ownership-clause is unknown because the Frappe Cloud terms of service were never retrieved, and the cited REST page says nothing about ownership or export tooling at all. Self-hosting makes ownership true in practice, but the claim asks whether the vendor documents it, and it does not. source |
| reporting-tier-paywall | yes / grade B, frappe.io/erpnext/pricing | downgrade-to-partial | Two problems. First the evidence: a vendor pricing page is grade C by the project's own scale, not B, and a differentiator yes may not rest on one. Second the substance: the claim is that specific reports — labor versus sales, PMIX, comps/voids audit, multi-location comparison — are available on the entry-level paid plan rather than behind a higher tier. It is true that Frappe operates no feature tiers at all, which disposes of the paywall question. But two of the four named reports are not shipped in any tier: this record scores reporting-labor-productivity as no ('no shipped report joins them into sales-per-labor-hour or labor cost percentage by hour') and reporting-comps-voids-audit as partial with 'no packaged exception report'. Nothing is paywalled because half of it does not exist, which is a partial, not the clean yes the claim intends. source |
| reliability-mfa-role-based-access | partial / grade B — 'the framework 2FA guide URL returns 404; no retrievable source supports TOTP/SMS/email OTP or per-role enforcement' | upgrade-to-yes | The previous pass downgraded this because it could not find a live 2FA document. I found one. docs.frappe.io/erpnext/setup-two-factor-authentication is current and documents the whole mechanism: activation via 'bench --site [sitename] set-config enable_two_factor_auth true', configuration in System Settings with OTP validation method, QR expiry and issuer name, and three methods — 'OTP App = TOTP using Soft or Hard Token' and 'Email/SMS = HOTP using Email or SMS'. It also documents exactly the per-role enforcement the previous verifier said was unsupported: on activation 'all users including the Administrator have to perform a 2nd level authentication with a token', and an administrator may disable 2FA for the All role while enabling it in other roles. One real caveat to carry in the note rather than in the value: '2FA does not apply to login by Web Users and API login', so webshop guests and API tokens are outside it. With RBAC already documented on the users-and-permissions page, both halves of the claim are met. source |
| guest-loyalty-data-export-portability | partial / grade B — 'the cited page documents nothing about the Data Export tool or full-site backups, which is half the claim' | upgrade-to-yes | The previous pass was right that docs.frappe.io/framework/user/en/api/rest documents no export tooling — I re-read it and it covers auth, CRUD and pagination only, with no mention of Data Export, backups or CSV/XLSX. But the tool is real and documented elsewhere, and I located the page: "'Data Export' helps you extract data from any DocTypes to a CSV or an Excel format", with filters to 'add filters to select only specific data', field selection, and an option to omit header notes. Any DocType includes Customer, Contact, Address, Loyalty Point Entry and Sales Invoice. It is in-app, self-serve, no ticket and no fee, and REST covers the same ground programmatically. Both halves of the claim now hold; the downgrade was a citation failure, not a capability failure. source |
| reporting-cash-over-short | partial / grade B — 'expected-versus-counted per Mode of Payment per cashier per session is a specific mechanic and I could not confirm it on any retrieved page' | upgrade-to-yes | The previous pass could not confirm the mechanic because the thin POS manual page does not describe it — I re-fetched that page and it says nothing about closing entries, reconciliation or cash at all. So I went to the doctype definitions instead. POS Closing Entry Detail carries exactly five fields: mode_of_payment, opening_amount, expected_amount, closing_amount and difference. Its parent POS Closing Entry carries period_start_date, period_end_date, pos_opening_entry, pos_profile, a user field whose label is literally 'Cashier', a payment_reconciliation table, plus net_total, total_taxes_and_charges and grand_total. That is over/short per drawer, per shift and per employee, comparing counted against expected, which is the claim verbatim. Grade A primary evidence, upgraded. source |
| reporting-eod-closeout | partial / grade B — 'the claimed mechanism is unverified on the source given' | upheld | Partial stands, but for a different reason than the previous pass gave, and the evidence needs replacing. The mechanism is no longer unverified: POS Closing Entry is a real submitted document carrying period start and end, the linked POS Opening Entry, the cashier, the POS Invoice and Sales Invoice transaction tables, a taxes table, total_quantity, net_total, total_taxes_and_charges, grand_total and a payment_reconciliation table with expected versus closing amounts per Mode of Payment. Against the claim that reconciles 'gross sales, net sales, tax, tips, discounts, refunds, tender types, and expected cash deposit in one document', everything is present except tips — and tips are structurally absent, since POS Invoice enumerates no tip or gratuity field. Named shortfall is tips, not missing documentation. source |
| hardware-printer-compatibility | partial / grade F, no source — 'no native ESC/POS raw kitchen-ticket routing engine' | upheld | Partial is the right value but it was inference with no URL, and two first-party pages settle it. Print Settings documents a print server: 'You can enable print server by filling the print server IP and port. Then chose the default printer', gated on installing the pycups library via libcups2-dev or cups-libs — that is CUPS/IPP network printing to any queue the host can see. Raw Printing documents thermal printing: 'Sending a string of commands to a printer directly in its native language is called Raw Printing', with 'any string-based printer languages' usable in the Raw Commands field, but it requires installing QZ Tray, a third-party desktop application, on the machine the thermal printer is attached to. Named shortfall, now sourced: no manufacturer is named on either page, no Epson or Star compatibility list is published, and raw thermal printing depends on third-party client software rather than shipping in the product. source |
| hardware-commodity-devices | yes / grade B, docs.frappe.io/erpnext/point-of-sale | upheld | Capability upheld, citation worthless. I fetched the cited POS manual page and asked it directly about device, browser and operating-system requirements: it addresses none of them, being a short introduction to what POS is and why to use it. The supporting evidence is the source tree. erpnext/selling/page/point_of_sale contains point_of_sale.js, pos_controller.js, pos_item_cart.js, pos_item_selector.js, pos_item_details.js, pos_number_pad.js, pos_payment.js and pos_past_order_summary.js — the POS is a JavaScript Desk page rendered in the browser, with no native client and no device binding, and Frappe sells no terminals. Re-cite to the repository path. source |
| commercial-hardware-not-locked | yes / grade B, docs.frappe.io/erpnext/point-of-sale | upheld | Upheld with the citation replaced, because the cited POS page says nothing about printers or devices — I checked. The claim asks the vendor to document at least one non-proprietary hardware option. Print Settings documents a generic CUPS print server addressed by IP and port with a selectable default printer, and Raw Printing documents driving a thermal printer in its native command language via QZ Tray. Neither is vendor-branded, neither is gated to a Frappe SKU, and Frappe sells no hardware to lock to. Worth noting against the researcher's phrasing: no specific manufacturer is named on any Frappe page, so the 'Epson/Star' example in the claim is satisfied generically rather than by an explicit compatibility list. source |
| commercial-data-export-self-serve | yes / grade B, docs.frappe.io/framework/user/en/api/rest | upheld | Upheld, citation corrected. The REST page carries the API half — 'Frappe framework generates REST API for all of your DocTypes out of the box' — but I confirmed it contains no mention of a Data Export tool, backups, or CSV/XLSX output, which is what the claim's 'export to CSV' half needs. The Data Export manual supplies it: extract 'from any DocTypes to a CSV or an Excel format', with filters and field selection, run by the operator from the desk with no ticket and no fee. Orders, line items and payments are ordinary DocTypes; labor requires installing Frappe HR, which is free but is a second app. source |
| extensibility-data-portability-exit | yes / grade B, docs.frappe.io/framework/user/en/api/rest | upheld | Upheld, citation corrected — same mis-citation as commercial-data-export-self-serve. The claim wants a complete historical export in a documented machine-readable format on demand at contract end. The Data Export manual documents CSV and Excel output for any DocType with filters and field selection; REST supplies the same data programmatically for every DocType. The specific 'full site backup (database plus files) is downloadable' assertion in the researcher's note is not on either page I retrieved, so it should be trimmed rather than asserted, even though bench backup exists. source |
| commercial-export-customer-and-loyalty | yes / grade B, docs.frappe.io/erpnext/loyalty-program | upheld | Upheld, citation corrected. The Loyalty Program page documents accrual, tiers, expiry and redemption; it documents nothing about exporting anything, so it cannot support an export claim. The Data Export manual can and does: 'any DocTypes to a CSV or an Excel format', which covers Customer, Contact, Address and Loyalty Point Entry. The researcher's own caveat is correct and worth keeping — gift-card liability is not exportable because no gift-card object exists in the product. source |
| payments-processor-choice | partial / grade B, frappe.io/erpnext/pricing | upheld | Partial is right and the shortfall is correctly named, but a pricing page is grade C and cannot carry the 'documented list of supported processors/gateways' half of the claim. First-party integration documentation can. I retrieved two pages. Payment Request states that 'ERPNext can email the request with an online payment link when a Payment Gateway Account is configured' and instructs the user to 'select the payment gateway account when collecting online' — but it names no gateway. The named guide is Stripe: 'to enable Stripe payment service, you need to configure parameters like Publishable Key, Secret Key' under 'Explore > Integrations > Stripe Settings', which then creates a Payment Gateway Account linked to an account head in the chart of accounts. Card-present and terminal acceptance appear on neither page — both are online payment-link flows — which is exactly why this stays partial rather than becoming a yes. source |
| inventory-recipe-bom-costing | yes / grade B, github.com/frappe/erpnext | upheld | Upheld and now sourced to documentation rather than a repository landing page. The BOM manual states that 'each item (sub-assembly) could have its own BOM hence forming a tree of Items with multiple levels', exposes a Materials Required (Exploded) view of that tree, and documents the 'Update Cost button' to 'fetch the latest price/costs' with the note that 'BOM cost can also be set to be updated automatically via Manufacturing Settings'. Multi-level sub-recipes with automatic cost recalculation on component price movement is the claim exactly, and it is a core module rather than a paid add-on. source |
| extensibility-public-api-docs | yes / grade B | upheld | Re-verified independently this pass rather than taken from the earlier one. docs.frappe.io/framework/user/en/api/rest loads for an anonymous reader with no account, no NDA and no sales contact, and states 'Frappe framework generates REST API for all of your DocTypes out of the box'. It documents token-based auth where 'the token is generated by concatenating api_key and api_secret with a colon', password-based auth, and OAuth 2.0 access tokens, plus CRUD, filters and pagination. This is one of the strongest cells in the record. source |
| reporting-public-api | yes / grade B | upheld | Upheld, with a caveat the record should carry. The REST page confirms auto-generated endpoints for every DocType and self-generated api_key/api_secret credentials with no partner agreement, which covers orders, payments and the item master. The claim also names labor data, and labor lives in Frappe HR — a separate application that must be installed on the site. It is first-party and free, so the claim is met, but 'covering labor' is conditional on a second install rather than out of the box, and that belongs in the note. source |
| order-capture-offline-order-entry | no / grade A — 'an open, inactive feature request against the product repository (frappe/erpnext#29068, opened 2021-12-29)' | upheld | The value is right and the evidence is right, but the record states a fact about the source that is false, and it repeats it in five cells. I opened frappe/erpnext#29068: it is titled 'POS offline mode', opened 29 December 2021, labelled feature-request and inactive, and it is CLOSED, not open. It proposes Application Cache plus a WebSQL local store for master data and receipts pending sync — a proposal, never shipped. A closed-and-inactive request is if anything slightly firmer evidence of absence than an open one, so the no holds, but 'open' must be corrected here and in payments-offline-store-and-forward, kitchen-offline-operation, hardware-offline-mode and reliability-offline-order-entry, all of which carry the same wording. source |
| hardware-offline-mode | no / grade A — 'an open feature request labelled inactive (frappe/erpnext#29068)' | upheld | Same correction as order-capture-offline-order-entry: issue #29068 is closed, not open. The claim additionally asks whether the vendor documents which functions degrade offline; it publishes no such matrix, and I found no offline configuration of any kind in the POS Profile field list or the POS manual page, which addresses offline mode nowhere. The no is well founded — terminals require a reachable server — and only the characterisation of the issue needs fixing. source |
| payments-published-rates | no, grade B - Not applicable — Frappe is not a payment processor, so there | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| hardware-pricing-transparency | no, grade B - Not applicable in the operator's favor: Frappe publishes no | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| reliability-onsite-install | partial, grade B - Frappe itself is remote-only, but the pricing page markets a | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| reliability-menu-build-service | partial, grade B - 'Starter Packs' are described as certified-partner help to m | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| commercial-interchange-plus-published | no, grade B - Not applicable — Frappe is not an acquirer or ISO and publis | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| commercial-hardware-purchase-outright | yes, grade B - All hardware is bought outright from third parties at market | upheld | Grade only, value untouched. Corpus-wide mechanical pass (workflows/regrade-marketing-pages.mjs): the cited page is a first-party pricing/feature/product page, which atlas-evidence-rules grades C ("vendor pricing page or feature page - first-party, but written to sell"), not B ("vendor product documentation - the manual, the help centre, the admin guide"). No claim was re-researched in this pass and no evidence was re-read; only the grade was brought into line with the source type. source |
| reporting-api-not-upcharged | yes / B / "API and raw data access carry no fee on any plan and are free entirely when self-hosted. Frappe Cloud" | upheld | The cited evidence was frappe.io/erpnext/pricing, a grade-C sales page, which cannot support a yes on a differentiator. Located the primary API reference instead: the REST API is generated for every DocType on every site, authenticated per user, with no tier or metering construct; raw-data export to CSV/Excel is documented in the ERPNext manual. Value stands on grade-A documentation. source |
| extensibility-api-access-cost | yes / B / "No API fee, no per-location surcharge, no upgraded plan requirement. Free entirely when self-h" | upheld | Original citation was the grade-C pricing page. Replaced with primary framework documentation: the REST API ships for every DocType on every site, and rate limiting is configured by the site administrator in site_config.json rather than provisioned by Frappe, so there is no metered or tier-gated API to upcharge. Value stands at grade A. source |
| extensibility-free-sandbox | yes / B / "Strongest possible form: install the entire GPL-3.0 stack locally via bench or Docker for free" | upheld | Original citation was the grade-C pricing page (trial and signup credit), which does not establish a developer sandbox. Read the actual demo-data implementation in the ERPNext repository and the framework installation guide: local install is documented and the seeded demo dataset is a shipped, callable function. Value stands at grade A on first-party source for an open-source product. source |
| commercial-month-to-month-contract | yes / B / "Frappe Cloud is pay-as-you-use from $5/mo with no stated minimum term, and self-hosting has no" | upheld | The pricing page is grade C and cannot carry a differentiator yes. Frappe Cloud's own billing documentation independently establishes monthly cycles with daily proration and a documented self-service cancellation that pauses billing, with no minimum term or exit fee anywhere in the billing section. Value stands at grade B on vendor product documentation. source |
| commercial-processing-not-bundled | yes / B / "Absolute. Frappe sells no payment processing, so there is no in-house lock and no attach requir" | upheld | Replaced the grade-C pricing-page citation with the ERPNext integration manual and the frappe/payments source. Positive documentation: the operator enters their own Stripe publishable/secret keys, and five gateways ship as swappable DocTypes behind a Payment Gateway Account, which is direct evidence of processor choice rather than an inference from silence. Value stands at grade B. source |
| multi-location-org-hierarchy | yes / B - "Documented verbatim: 'A parent company is a larger organization which consists of one or more chi" | upheld | Citation-staleness check. The cited https://docs.frappe.io/erpnext/company 301s to https://docs.frappe.io/erpnext/company-setup; I fetched the destination (200, 2.7MB, Googlebot UA) and extracted its text. Every sentence the record quotes is present word for word, including the Is Group and Parent Company field definitions and the company tree view. The record's unsourced trailing claim about Cost Center, Warehouse and Territory trees is not on this page and has been withdrawn from the note. Value and grade stand. source |
| extensibility-app-marketplace | yes / B - "Verified verbatim: the marketplace page reads 'Showing 342 apps', and URY - Restaurant POS " | upheld | Citation-staleness check. https://cloud.frappe.io/marketplace 301s to https://cloud.frappe.io/marketplace/search; I fetched it (200, 366KB) and confirmed the body is the real catalogue, not an SPA shell - the app names and descriptions are in the served HTML. It reads "Showing 344 apps" rather than the recorded 342, and all six named third-party POS apps (URY, POSNext, GETPOS, KLiK PoS, POS Restaurant, POSpire) are still present, each with its own /marketplace/apps/<slug> page. Public browsing and self-install both hold; value and grade stand, URL and count refreshed. source |
| commercial-module-unbundling | yes / B - "Apps are installed and uninstalled individually on a site - ERPNext, Frappe HR, Webshop, In" | upheld | Citation-staleness check that turned into a re-evidencing. The cited cloud.frappe.io/marketplace 301s to /marketplace/search, and that catalogue page never carried the assertion anyway - it lists apps but says nothing about independent purchase or cancellation, which is thin for a differentiator-weight yes. I went to Frappe Cloud's documentation instead: https://docs.frappe.io/cloud/app-plan (200, Googlebot UA) states plans are selected per app at install time, are changeable from the site dashboard, are monthly, and are pro-rated so that uninstalling mid-month charges only the days used; https://docs.frappe.io/cloud/how-to-uninstall-an-app-from-the-site documents per-app uninstall from the Apps tab; https://docs.frappe.io/cloud/installing-an-app documents per-app install, and the site plan is a separate document (/cloud/how-to-change-a-site-plan), confirming app charges are not entangled with the base site subscription. Value and grade stand on much better evidence. source |
| multi-location-org-hierarchy | yes / B — five sentences quoted from docs.frappe.io/erpnext/company-setup | upheld | Found by the 62nd session's full drift re-run asking the regression question: matched fell 5 -> 0 on this page while visible text fell 47,236 -> 42,859 characters, the only unexplained movement in the run that was not a code effect. The page was REWRITTEN, not withdrawn. Every concept the cell rests on is still documented there: the company tree view with Add Child to create a subsidiary, Is Group marking an organizational parent that posts no transactions, Parent Company placing an entity under a group for consolidated reporting, and sibling companies for entities at the same level. Value and grade are unchanged; the five stale quotations were re-transcribed from the same document and each replacement was verified present against the live page before it was written. source |
| order-capture-coursing-hold-fire | no / F - No course or fire concept anywhere in ERPNext. No kitchen destination exists to fire to." | downgrade-to-no | Searched the vendor's own words - course/coursing/fire/hold/seat/modifier, plus 'Kitchen' as a send destination - anchored at word boundaries. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: zero real word-boundary hits for \bcourse\b|\bfire\b|\bcoursing\b in either repository (32 files match unanchored, every one of them noise: Leaflet's .fire() event dispatcher, jQuery, and 'of course' in a changelog); \bseat\b resolves to eight lines of a chair BOM in test_bom_creator.py; \bkitchen\b resolves to two chart-of-accounts templates (a GL account named Kitchen in the Singapore F&B and UAE charts). The POS line item that would have to carry a course number and a hold flag is POS Invoice Item, and its 98-field field_order (quoted) runs barcode -> item_code -> qty -> uom -> rate -> warehouse with no course, no hold, no fire, no send-destination field. The Restaurant module that once held these ideas was deleted from core by erpnext/patches/v14_0/delete_hospitality_doctypes.py, which drops Module Def 'Restaurant' and the Custom Fields Sales Invoice.restaurant_table and Price List.restaurant_menu - so this is 'removed at v14', not 'never existed'. Positive control: \bPOS Profile\b returns 53 files / 125 lines in the same corpus, so the search would have found a POS-side feature if one existed. Scope: core erpnext v16.34.1 + frappe v16.33.0 only; frappe/hospitality (archived read-only) and Frappe Cloud marketplace apps (URY, POSNext, GETPOS) are outside this census and are not claimed against. source |
| order-capture-split-merge | no / F - POS supports multiple payment modes on one invoice but no check splitting or merging by item, seat, | downgrade-to-no | Searched split/merge/transfer in the vendor's vocabulary - 'POS Invoice Merge Log', 'Merge Invoices Based On', 'consolidated_invoice' - plus split/seat/share over the POS page source. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. The trap here is that ERPNext DOES ship a doctype with 'merge' in its name, so an unanchored search reads as a hit. Reading it: POS Invoice Merge Log merges SUBMITTED POS Invoices into one consolidated Sales Invoice at shift close, and its only grouping key is the quoted Select - Customer or Customer Group. It is an accounting consolidation, the inverse of splitting a check. Invariance: zero occurrences of split/merge/transfer as an order operation across the eight POS page scripts (erpnext/selling/page/point_of_sale/*.js); the only 'split' hits there are JavaScript String.split() on serial numbers and shortcut keys. POS Invoice does carry a `payments` child table (multiple Mode of Payment rows on one invoice), i.e. split TENDER; it carries no second invoice reference, no seat field and no share/percentage allocator, i.e. no split CHECK. Positive control: \bPOS Profile\b = 53 files, \bLoyalty Program\b = 22 files in the same corpus. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| order-capture-bar-tab-preauth | no / F - No card pre-authorization capability; ERPNext performs no card processing." | downgrade-to-no | Searched the payment vocabulary: 'Mode of Payment', pre-auth/preauthoriz, card reader, pinpad, semi-integrated, EMV, tokenis/tokeniz. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: pre.?auth|preauthoriz returns two lines in the whole corpus, both OAuth (frappe/integrations/oauth2.py and a server_script.js comment) - zero payment pre-authorisation anywhere; \bcard reader\b|\bpin ?pad\b|semi.?integrat returns one line, inside a base64 email test fixture; tokeni[sz] returns eight files, all of them full-text search tokenisers and PDF utilities, none a card vault. The artefact that would have to carry a card tender type is Mode of Payment, and its `type` Select enumerates exactly Cash / Bank / General / Phone (quoted) - there is no Card type, no acquirer, no auth/capture split and no incremental-auth field, because ERPNext performs no card processing itself: a Mode of Payment is only a link to a GL Account. Positive control: \bRazorpay\b (7 files), \bStripe\b (5), \bPayPal\b (12) all fire - the gateways ERPNext does ship are online invoice-payment redirects via Payment Request, not card-present terminals. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| order-capture-transfer-audit | no / F - No open-check ownership model. Frappe's Version log would audit a document owner change but there is | downgrade-to-no | Searched the ownership vocabulary an open-check transfer needs: server/employee assignment, table, 'restaurant_table', transfer, handover, and Frappe's own audit primitive 'Version'. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the POS Invoice header field_order (185 fields; its opening run quoted) has no server, no employee, no table and no assigned-user field - the only actor recorded is the framework's `owner`. \bhandheld\b|\btableside\b returns zero files in either repository; there is no transfer action in any of the eight point_of_sale/*.js scripts. The table concept existed and was removed: erpnext/patches/v14_0/delete_hospitality_doctypes.py deletes the Custom Field Sales Invoice.restaurant_table at v14. Frappe's Version doctype would log a change of `owner` on a draft POS Invoice, but that is generic document versioning, not a transfer workflow naming both employees, and nothing in the POS UI invokes it. Positive control: \bPOS Profile\b = 53 files; POS Profile itself ships `applicable_for_users` (a POS Profile User child table), proving the corpus does surface POS-side user assignment where it exists - it exists for till access, not for check ownership. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| order-capture-native-handheld | no / F - POS is a responsive browser page. No first-party handheld app, and no tableside card payment path." | downgrade-to-no | Searched for a shipped mobile client in the vendor's terms and the platform's: Page/desk page, android, ios, App Store, Play Store, Capacitor, Cordova, React Native, Flutter, PWA, service worker, manifest.json, handheld, tableside. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: progressive web app|\bPWA\b|manifest.json|service.?worker returns ZERO files across both repositories; \bhandheld\b|\btableside\b returns ZERO files; the native-framework pattern returns 11 files, every one noise (Font Awesome CSS, fingerprintjs, Leaflet, jSignature, and four apple-mobile-web-app meta tags in frappe/www/desk.html, which only ask iOS Safari to hide its chrome). The artefact itself: the POS is registered as a Frappe `Page` (quoted) - a desk route rendered by point_of_sale.js in the same browser bundle as the rest of the desk. There is no separate mobile package, no offline service worker and, per Mode of Payment's Cash/Bank/General/Phone type list, no card-payment path to run tableside. Positive control: \bPOS Profile\b = 53 files and the eight point_of_sale/*.js scripts are all present in the corpus, so a shipped client would have been visible. Scope: core erpnext v16.34.1 + frappe v16.33.0; marketplace handheld apps on Frappe Cloud are outside this census. source |
| order-capture-kiosk-first-party | no / F - No first-party kiosk product." | downgrade-to-no | Searched \bkiosk\b, self-order, unattended, guest/anonymous access to the POS page, and ADA/WCAG/accessibility conformance. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \bkiosk\b returns ZERO files across both repositories - not a noisy zero, an absolute one. The artefact that would have to be opened to a guest is the Point of Sale Page record, and its access control (quoted) restricts it to the Retail domain and to four staff roles (Accounts User, Accounts Manager, Sales User, Sales Manager); a Frappe Page with a non-empty `roles` list is unreachable without an authenticated User holding one of them, so the POS cannot render as a guest-facing kiosk. No ADA/WCAG conformance statement exists for it anywhere in the 1,863-page docs census either. Positive control: \bPOS Profile\b = 53 files, and frappe DOES ship guest-facing surfaces (Web Form, Portal Settings) that the same search finds - so guest access would have been detectable. Scope: core erpnext v16.34.1 + frappe v16.33.0; kiosk apps sold on the Frappe Cloud marketplace are outside this census. source |
| order-capture-voice-ai | no / F - No first-party voice agent and no voice-AI partner program. A generic REST write API exists, which a | downgrade-to-no | Searched voice order|voice ai|conversational, plus the vendor's actual telephony vocabulary: Telephony module, Call Log, Telephony Call Type, Incoming Call Settings, Voice Call Settings, Twilio, Exotel. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: voice order|voice ai|conversational returns ZERO files across both repositories. What DOES exist is an erpnext Telephony module whose entire doctype list is call_log, incoming_call_handling_schedule, incoming_call_settings, telephony_call_type, voice_call_settings - screen-pop plumbing that links an inbound call to a Contact and writes nothing into a cart. Correction worth recording: the shipped telephony PROVIDERS have been removed from both repos - Twilio left frappe at v13 (frappe/patches/v13_0/remove_twilio_settings.py deletes Twilio Settings and Twilio Number Group) and Exotel left erpnext at v15 (the quoted patch deletes Exotel Settings and tells operators to install github.com/frappe/exotel_integration). So at v16 there is not even a first-party call provider, let alone a voice agent or a documented voice-AI partner programme. Positive control: \bExotel\b = 3 files and \bTwilio\b = 1 file, so the search finds telephony strings where they survive. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| order-capture-scheduled-orders | no / F - Sales Order carries a delivery date, but there is no make-queue or computed fire time — no kitchen q | downgrade-to-no | ATTACK 1 on an internal contradiction. The row's load-bearing sentence was 'the order cannot even express an hour, let alone a computed fire time' -- and its own positive control, two sentences later, stated that 'Sales Order DOES carry transaction_time (a Time field)'. A reader who checks the note falsifies the note. I read the field: transaction_time is real, is fieldtype Time, and is depends_on is_internal_customer, so it records placement time on intercompany transfers and is never a delivery promise. Grade A retained because delivery_date's Date fieldtype genuinely is the primary artefact for the absence, but the note had to stop asserting something the corpus contradicts. source |
| order-capture-order-ready-signal | no / F - No marketplace connections exist to signal." | downgrade-to-no | Searched for the marketplaces themselves in the vendor's namespace - doordash, ubereats, uber eats, grubhub, deliveroo, postmates - and for the module that would house such a connector. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the marketplace-name pattern returns ZERO files across both repositories. The artefact is erpnext's own module manifest (quoted excerpt): 21 modules, and the only one named for integrations is 'ERPNext Integrations', whose doctype directory at v16.34.1 contains exactly one entry - plaid_settings (bank-feed aggregation). There is no marketplace connector to push an order-ready event to, and no KDS state to derive one from (\bkitchen\b = two chart-of-accounts templates). Positive control: \bPlaid\b and \bDelivery Trip\b (20 files) both fire, so shipped integrations and dispatch objects are visible to this search. Scope: core erpnext v16.34.1 + frappe v16.33.0; marketplace connectors sold on the Frappe Cloud marketplace are outside this census and are not claimed against. source |
| menu-pricing-modifier-price-by-parent-size | no / F - No modifiers exist, so no modifier price matrix." | downgrade-to-no | Searched \bmodifier\b and the vendor's nearest real vocabulary - Item Variant, Item Attribute, Item Variant Attribute, Item Variant Settings, Product Bundle, Item Price. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \bmodifier\b returns exactly one file in both repositories, erpnext/patches/v16_0/migrate_account_freezing_settings_to_company.py, where it is an accounting role name - zero POS modifiers. The nearest shipped model is Item Variant (quoted field run: variant_of / variant_based_on / attributes). A variant is a distinct Item record with its own Item Price, so 'Large Coke' is a different SKU, not a priced modifier attached to a parent; there is no child table anywhere that attaches an option to a line and prices it, and therefore no matrix keyed on (parent item, size). Item Price is keyed on item_code / uom / price_list / customer, never on a parent line. Positive control: \bItem Attribute\b = 24 files / 69 lines and \bPricing Rule\b = 56 files, so the variant and pricing machinery is fully visible to this search - the modifier layer simply is not there. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| menu-pricing-86-propagation | no / F - No KDS, no first-party restaurant ordering, no kiosk, no marketplaces to propagate to." | downgrade-to-no | Searched \b86\b and eighty.six, then the vendor's real availability vocabulary: hide_unavailable_items, Item.disabled, allow_items_not_in_stock, Bin, actual_qty. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \b86\b is a pure reader artefact - 49 files, all of them account codes in chart-of-accounts templates and row numbers in bank-statement test fixtures; zero as a POS action. The artefact that would have to carry propagation is POS Profile, and the whole of its availability surface is the quoted `hide_unavailable_items` checkbox, which filters the POS item selector on that one till's warehouse stock. There is nothing for it to propagate TO: no KDS (\bkitchen\b = two chart-of-accounts templates), no marketplace (doordash|ubereats|grubhub|deliveroo = zero files), no kiosk (\bkiosk\b = zero files), and e-commerce was removed from core at v15 by erpnext/patches/v15_0/delete_ecommerce_doctypes.py. No propagation latency is documented anywhere in the 1,863-page docs census. Positive control: \bPOS Profile\b = 53 files / 125 lines. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| menu-pricing-countdown-auto-86 | no / F - Stock quantity is tracked and can go to zero, but there is no auto-86 with scheduled restore." | downgrade-to-no | Searched the vendor's stock-threshold vocabulary: Item Reorder / reorder_levels, warehouse_reorder_level, Bin, Stock Settings, Auto Material Request, plus countdown/par count and any auto-disable-at-zero. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the only per-item threshold ERPNext ships is the quoted `reorder_levels` (an Item Reorder child table of warehouse / warehouse_reorder_level / warehouse_reorder_qty / material_request_type), and erpnext/stock/reorder_item.py acts on it by raising a Material Request - a purchase/manufacture trigger, never a sale block and never an item disable. Nothing in either repository sets Item.disabled or POS Profile.hide_unavailable_items on a schedule; there is no scheduled restore job for item availability at all. hide_unavailable_items does hide zero-stock items from the POS selector, but it is a live stock filter with no par count, no countdown display and no timed restore. Positive control: reorder|re-?order = 53 files including erpnext/stock/reorder_item.py (48 hits), so the threshold machinery is fully visible - the auto-86 layer is absent, not hidden. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| menu-pricing-allergen-nutrition | no / F - No shipped allergen or nutrition fields. Frappe Custom Fields make adding them trivial, but nothing | downgrade-to-no | Searched \ballergen\b|\bnutrition\b and the vendor's nearest shipped vocabulary: Item Website Specification, Item Quality Inspection Parameter, BOM (recipe), Item Attribute. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \ballergen\b|\bnutrition\b returns ZERO files across both repositories - an absolute zero, no noise to read past. The artefact that would carry them is the Item doctype, whose opening field_order run is quoted (details -> naming_series -> item_code -> item_name -> item_group -> stock_uom -> image); across all 118 of its fields the only consumable-adjacent ones are shelf_life_in_days and end_of_life - shelf life and expiry, no allergen flag, no nutrition value. Item Website Specification is a free-text label/description pair on the website tab, not a typed allergen flag, and nothing publishes it to a third-party menu (doordash|ubereats|grubhub|deliveroo = zero files). BOM exists and could hold recipe components, but no code in either repository rolls any nutritional value up a BOM tree - there is no such field to roll up. Positive control: \bItem Attribute\b = 24 files and BOM's own field list is fully visible in the corpus. Scope: core erpnext v16.34.1 + frappe v16.33.0; Frappe Custom Fields would let an operator add such fields, which is configuration, not a shipped capability. source |
| menu-pricing-3p-menu-push | no / F - No marketplace integrations in core or on Frappe's own roadmap." | downgrade-to-no | Searched the marketplaces by name (doordash|ubereats|uber eats|grubhub|deliveroo|postmates), then the module that would house a connector, then the docs census for any partner programme. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the marketplace-name pattern returns ZERO files across both repositories, and \brestaurant\b|\bhospitality\b returns ZERO pages across the 1,863-page docs census (1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12); the 26 misses are 404s in the publisher's own manifest). The artefact is erpnext's module manifest (quoted excerpt): 21 modules, the only integration module being 'ERPNext Integrations', whose doctype directory at v16.34.1 holds exactly one entry, plaid_settings. There is no menu object to push (Price List.restaurant_menu was deleted at v14 by erpnext/patches/v14_0/delete_hospitality_doctypes.py) and no sync-status or rejection-error surface anywhere. Positive control: \bPlaid\b, \bRazorpay\b (7 files), \bStripe\b (5), \bPayPal\b (12) all fire, so shipped third-party integrations ARE visible to this search. Scope: core erpnext v16.34.1 + frappe v16.33.0; marketplace connectors on the Frappe Cloud marketplace are outside this census. source |
| menu-pricing-dynamic-pricing | no / F - Pricing Rule is condition-based (qty, customer, territory, date range), not demand- or time-of-day-d | upgrade-to-partial | CORRECTION - the standing rationale ('Pricing Rule is condition-based (qty, customer, territory, date range), not demand- or time-of-day-driven, and has no floor/ceiling guardrails') is falsified by the artefact. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Searched the vendor's vocabulary: Pricing Rule, Promotional Scheme, Dynamic Condition, for_price_list, Item.max_discount. Findings: (1) Pricing Rule ships a `condition` field of fieldtype Code / options PythonExpression, and erpnext/accounts/doctype/pricing_rule/utils.py evaluates it per transaction with the quoted safe_eval over the whole document dict - so a rule CAN key on POS Invoice.posting_time or Sales Order.transaction_time, i.e. time-of-day pricing is expressible, and it is documented as the 'Dynamic Condition' tab at https://docs.frappe.io/erpnext/pricing-rule. (2) Channel variance is native: Pricing Rule.for_price_list plus POS Profile.selling_price_list give a different automatic price per till/channel. (3) A guardrail exists on one side only - Item.max_discount, enforced by validate_max_discount() in erpnext/controllers/selling_controller.py, is an effective price FLOOR; there is no ceiling. (4) Demand-driven pricing is genuinely absent: no inventory-velocity or occupancy input feeds the rule engine. Two of three drivers plus one of two guardrails = partial, not no. Positive control: \bPricing Rule\b = 56 files / 272 lines, \bPromotional Scheme\b = 14 files. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| digital-native-app | no / F - No branded consumer iOS/Android ordering app." | downgrade-to-no | Searched for a branded consumer app: android, ios, App Store, Play Store, Capacitor, Cordova, React Native, Flutter, PWA, service worker, manifest.json. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: progressive web app|\bPWA\b|manifest.json|service.?worker returns ZERO files across both repositories, and the native-framework pattern returns 11 files that are all noise (Font Awesome, fingerprintjs, Leaflet, jSignature, apple-mobile-web-app meta tags in frappe/www/desk.html). More decisively, core ships no consumer ordering surface at all to wrap: the quoted patch, erpnext/patches/v15_0/delete_ecommerce_doctypes.py, DELETES E Commerce Settings, Website Item, Recommended Items, Item Review, Wishlist and Website Offer from ERPNext at v15 and redirects operators to github.com/frappe/webshop. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. That census contains no mobile packaging of any kind (zero Capacitor/Cordova/native manifests); webshop is server-rendered Jinja under frappe/website. Positive control: \bPOS Profile\b = 53 files; the eight point_of_sale/*.js scripts are present, so shipped clients are visible to this search. Scope: core erpnext v16.34.1 + frappe v16.33.0 plus the frappe/webshop census; marketplace apps on Frappe Cloud are outside it. source |
| digital-account-saved-payment | no / F - Webshop supports customer accounts and saved Addresses, but no tokenized saved payment method and no | downgrade-to-no | The only first-party guest ordering channel is frappe/webshop (e-commerce was removed from erpnext core at v15 by erpnext/patches/v15_0/delete_ecommerce_doctypes.py), so the negative has to be grounded there and not only in core. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Searched tokenis/tokeniz, card, vault, saved payment, reorder/re-order across all three. Invariance: `token` and `reorder` each match ZERO paths in the 230-blob webshop census; tokeni[sz] across erpnext+frappe returns eight files, all full-text-search tokenisers and PDF utilities. The artefact is Webshop Settings, whose ENTIRE checkout surface is quoted: enable_checkout, show_price_in_quotation, save_quotations_as_draft, payment_gateway_account, payment_success_url - a single Payment Gateway Account, consumed by webshop/webshop/shopping_cart/cart.py to raise a Payment Request redirect per order. A hosted redirect per order is the opposite of a stored token; there is no saved-card doctype, no customer payment profile and no one-tap reorder anywhere. Saved ADDRESSES do exist (webshop/templates/includes/cart/address_picker_card.html), which is why the cell is not simply empty. Positive control: \bRazorpay\b (7 files), \bStripe\b (5), \bPayPal\b (12) all fire in erpnext, so payment machinery is visible where it exists. source |
| digital-upsell-engine | no / F - Neither ordering surface has one. The POS item selector is fully enumerated in POS Profile (hide_una | upgrade-to-partial | CORRECTION - the standing rationale asserts 'frappe/webshop renders the Item master and Price List with no recommendation or add-on prompt layer'. That sentence is false. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The census shows a `recommended_items` doctype (quoted field list), a `recommended_items` field on Website Item, and an `enable_recommendations` switch in Webshop Settings; erpnext/patches/v15_0/delete_ecommerce_doctypes.py names 'Recommended Items' among the doctypes it moved out of core at v15, which is why a core-only search misses it. So a configurable cross-sell layer DOES ship on the first-party web channel. What is still absent, and why this is partial and not yes: (a) placement - Recommended Items is a curated child table rendered on the Website Item page (templates/generators/item/*), not in the cart or at checkout; the cart templates (place_order.html, cart_items.html, cart_payment_summary.html) contain no suggestion block; (b) it is manually curated per item, with no order-history personalisation and no rules engine; (c) attach-rate reporting does not exist - the webshop census contains ZERO files under any `report` path. On the POS side Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. POS Profile's item-selector surface is fully enumerated as hide_unavailable_items / hide_images / auto_add_item_to_cart, with no suggestion engine. Positive control: \bwebshop\b|website_item|e_commerce_settings fires in erpnext (7 files), so the e-commerce trail is visible to this search. source |
| digital-scheduled-pacing | no / F - There is no first-party restaurant ordering channel with capacity-limited time slots. Sales Order ca | downgrade-to-no | Searched \bslot\b, time slot, throttle, pacing, capacity, daypart, and the vendor's real slot vocabulary - Appointment, Appointment Booking Settings, Appointment Booking Slots. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. This is the trap in this cell and it is worth naming: ERPNext DOES ship a guest-facing, capacity-limited slot booker. Appointment Booking Settings carries availability_of_slots (an Appointment Booking Slots child of day_of_week / from_time / to_time), number_of_agents, appointment_duration, advance_booking_days, holiday_list and enable_appointment_portal - genuine per-interval capacity on a public portal. It just does not carry an order: the quoted Appointment field_order is scheduled_time / status / customer_name / customer_phone_number / calendar_event / party, with NO items child table, no price and no link to Sales Order or POS Invoice. Conversely the object that does carry items, Sales Order, times it with `delivery_date` of fieldtype Date - no hour, no slot, no cap. Nothing joins the two, and no kitchen-load input exists (\bkitchen\b = two chart-of-accounts templates). frappe/webshop is likewise empty: `slot`, `schedul`, `pickup` and `delivery` match ZERO paths in its 230-blob census. Positive control: Appointment Booking Slots itself is the control - slot machinery IS visible to this search where it exists. source |
| digital-fulfillment-modes | no / F - No pickup/curbside/dine-in/delivery mode selector with mode-specific fees and prep timing." | downgrade-to-no | Searched the fulfilment vocabulary: \bcurbside\b, pickup, dine-in, QR table ordering, delivery mode, prep time, and the vendor's own Shipping Rule / Delivery Trip. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: \bcurbside\b returns ZERO files across erpnext+frappe, and `pickup`, `curbside`, `delivery` and `slot` each match ZERO paths in the webshop census. The artefact is webshop's entire order-placement control (quoted): the cart offers exactly two terminal actions - Place Order when checkout is enabled, or Request for Quote when it is not. There is no mode selector, and consequently no mode-specific fee or prep timing; the only address surface is a single shipping Address picker. Table/dine-in ordering was removed at v14 (erpnext/patches/v14_0/delete_hospitality_doctypes.py deletes Sales Invoice.restaurant_table). Delivery Trip and Shipping Rule exist but are back-office dispatch and freight-charge objects on a submitted Sales Order, not a guest-selectable channel. Positive control: \bDelivery Trip\b = 20 files / 35 lines, so fulfilment objects ARE visible to this search. source |
| digital-kiosk | no / F - No first-party kiosk application ships in ERPNext core or in any frappe/* repository. The POS is a s | downgrade-to-no | Searched \bkiosk\b, self-order, unattended, EMV, and guest access to the POS. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: \bkiosk\b returns ZERO files across both repositories, and ZERO paths in the 230-blob frappe/webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.). \bEMV\b anchored resolves to one line inside a base64 email fixture; \bcard reader\b|\bpin ?pad\b|semi.?integrat likewise returns a single base64 artefact - there is no unattended payment device support of any kind, consistent with Mode of Payment's type Select enumerating only Cash / Bank / General / Phone. The artefact quoted is the Point of Sale Page record: restrict_to_domain 'Retail' with a roles list of Accounts User / Accounts Manager / Sales User / Sales Manager, so the POS screen requires an authenticated Frappe User holding a staff role and cannot render for a guest. Positive control: frappe DOES ship guest-reachable surfaces (Web Form, Portal Settings, webshop's login_required_to_view_products switch), all visible to the same search - guest mode would have been found if the POS had one. Scope: core erpnext v16.34.1 + frappe v16.33.0 + the frappe/webshop census. source |
| digital-group-ordering | no / F - No first-party guest ordering product exists, so there is no shared cart, no per-participant sub-car | downgrade-to-no | Searched group order|shared cart, per-person cap, spend limit, participant, and the vendor's real cart vocabulary - Shopping Cart, Quotation, Party, Portal User. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: group order|shared cart returns ZERO files across erpnext+frappe. The artefact is webshop/webshop/shopping_cart/cart.py, whose party resolution (the quoted function sits directly after get_party/get_customer, which resolve the session User to exactly one Customer via Portal User) makes the model explicit: a webshop cart IS a draft Quotation owned by one resolved party, keyed to one logged-in session. There is no share token, no participant child table, no per-participant sub-cart and no per-person spend cap anywhere in the 230-blob census; the only multi-payer construct in the whole product is POS Invoice's `payments` child table, which is split tender on one till, not split payment across guests. Positive control: the same census surfaces webshop's coupon_code.html and address_picker_card.html, so cart-level features ARE visible to this search. source |
| digital-catering-portal | no / F - Quotation, Sales Order and advance Payment Entry support catering-shaped flows in the back office, b | downgrade-to-no | Searched \bcatering\b and the vendor's nearest back-office vocabulary: Quotation, Sales Order, Payment Entry advance, Payment Terms Template, minimum order, lead time. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: \bcatering\b returns ZERO files across erpnext+frappe and ZERO paths in the webshop census. The back-office half of the claim is real - Quotation, Sales Order, Payment Schedule / Payment Terms Template and advance Payment Entry all ship and can express a proposal, a deposit and net terms. The guest-facing half does not exist: the quoted block is the tail of Webshop Settings' entire commercial configuration, which reads section_break_18 / company / price_list / column_break_21 / default_customer_group / quotation_series - one company, ONE price_list, one default_customer_group, one quotation_series. There is no second catering catalogue, no order minimum field, no lead-time rule, no deposit capture at checkout and no approval routing anywhere in the storefront; webshop's only alternative flow is the Request for Quote button in templates/includes/cart/place_order.html, which merely saves the cart Quotation as a draft for a human to price. Positive control: \bSubscription Plan\b = 17 files and Payment Schedule is fully visible in the corpus, so billing-terms machinery IS findable. source |
| digital-voice-ai-phone | no / F - No first-party voice ordering agent and no voice-AI partner programme. Frappe’s Telephony module int | downgrade-to-no | CORRECTION to the standing rationale, which says 'Frappe's Telephony module integrates Twilio and Exotel to pop an incoming call against a Contact'. Neither provider ships at these tags. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. The quoted line is erpnext/patches/v15_0/remove_exotel_integration.py deleting the Exotel Settings doctype at v15 and directing operators to github.com/frappe/exotel_integration; Twilio left frappe at v13 (frappe/patches/v13_0/remove_twilio_settings.py deletes Twilio Settings and Twilio Number Group). Also: the Telephony module is in erpnext, not frappe. What remains is call_log / incoming_call_settings / incoming_call_handling_schedule / telephony_call_type / voice_call_settings - screen-pop plumbing with no shipped provider. Invariance: voice order|voice ai|conversational returns ZERO files across both repositories; nothing writes into a cart from a call, and no certified voice partner is named anywhere in the 1,863-page docs census (\brestaurant\b|\bhospitality\b = ZERO pages there). Positive control: \bExotel\b = 3 files, \bTwilio\b = 1 file - the search finds these strings exactly where they survive, which is in the removal patches. Verdict unchanged at no; the reasoning behind it was wrong. source |
| digital-drivethru-ai | no / F - There is no drive-thru product of any kind in ERPNext — no order point, no lane, no timing — so ther | downgrade-to-no | Searched drive.?thru|drive.?through and the surrounding vocabulary: lane, order point, timing, escalation/handoff, voice. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: drive.?thru|drive.?through returns ZERO files across both repositories - an absolute zero with no noise to read past; voice order|voice ai|conversational likewise returns ZERO. The artefact quoted is the Point of Sale Page's domain restriction: the POS is registered to the 'Retail' domain, and erpnext/domains/retail.py defines that domain as desktop icons for POS / Item / Customer / Sales Invoice / Purchase Order plus show_barcode_field - a counter-service retail till. There is no lane object, no order point, no timing measurement and no handoff model to escalate to, so there is no drive-thru surface for voice AI to attach to. Positive control: erpnext ships four domains (retail, distribution, manufacturing, services) and all four files are in the corpus - a hospitality or QSR domain would have been visible; instead the Restaurant module was deleted at v14 by erpnext/patches/v14_0/delete_hospitality_doctypes.py. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| digital-sms-ordering | no / F - SMS Settings is a generic outbound HTTP SMS gateway used for notifications. There is no inbound mess | downgrade-to-no | Searched the vendor's messaging vocabulary: SMS Settings, sms_gateway_url, SMS Parameter, SMS Center, receive_sms, inbound webhook, plus conversational/chat ordering. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: the artefact is frappe's SMS Settings, and its COMPLETE field list is sms_gateway_url (quoted), message_parameter, receiver_parameter, static_parameters_section, parameters, use_post, allowed_roles_section, allowed_roles. Every field is a component of one outbound HTTP GET/POST to a gateway URL; there is no inbound endpoint, no webhook receiver, no message-thread doctype and no reply handler - receive_sms|incoming.{0,15}sms|sms.{0,10}webhook returns nothing but the outbound plumbing above. Nothing lands in the POS: no code path in either repository creates a POS Invoice or Sales Order from a message. voice order|voice ai|conversational returns ZERO files. Positive control: \bSMS Settings\b = 13 files / 27 lines, and erpnext ships an SMS Center doctype for bulk outbound sends - so the messaging machinery IS fully visible to this search, and it is one-directional. Scope: core erpnext v16.34.1 + frappe v16.33.0. source |
| digital-google-order | no / F - Order with Google requires a certified consumer ordering end-point to link to. ERPNext ships no rest | downgrade-to-no | Searched 'order with google', google.{0,15}order, Google Business Profile, and then enumerated what Google integration the vendor actually ships. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: apple business|business connect|order with google|google.{0,15}order returns ZERO files across both repositories. The artefact is frappe's Google Settings, the single OAuth credential store for every Google feature in the platform; its whole field list is enable / client_id / client_secret / api_key / app_id / google_drive_picker_enabled (quoted), and the doctypes that consume it are Google Calendar, Google Contacts, Google Drive and Google Indexing. Ordering is not among them, and there is nothing to provision: core ships no consumer ordering endpoint at all after erpnext/patches/v15_0/delete_ecommerce_doctypes.py moved e-commerce to frappe/webshop at v15, and `google` matches ZERO paths in the 230-blob webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.). Positive control: \bgoogle\b = 66 files / 275 lines, led by google_calendar.py (53 hits) and google_contacts.py (26) - Google integrations ARE richly visible to this search where they exist. source |
| digital-apple-business-connect | no / F - Apple Business Connect ordering actions require a consumer ordering end-point. ERPNext ships no rest | downgrade-to-no | Searched apple business|business connect and 'Order Food' / Maps place-card actions, then the precondition - whether any first-party ordering endpoint exists to register. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Invariance: apple business|business connect returns ZERO files across both repositories, and `apple` matches ZERO paths in the 230-blob frappe/webshop census (frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release.); the only Apple strings anywhere are four apple-mobile-web-app meta tags in frappe/www/desk.html. The artefact quoted is erpnext/patches/v15_0/delete_ecommerce_doctypes.py, which at v15 deletes E Commerce Settings, Website Item, Recommended Items, Item Review, Wishlist, Wishlist Item, Website Offer and Website Item Tabbed Section from core and tells the operator to install a separate app - so core erpnext v16.34.1 ships no consumer ordering surface, and webshop is a product-catalogue storefront with no restaurant ordering flow (pickup/curbside/slot/schedul all match zero paths). An operator can of course list their own business on Apple Maps and point a custom action at any URL; that is the operator acting as their own business, not a capability this product ships or documents - \brestaurant\b|\bhospitality\b returns ZERO pages across the 1,863-page docs census. Positive control: \bwebshop\b|website_item|e_commerce_settings = 7 files in erpnext, so the e-commerce trail is visible. source |
| digital-first-party-web | partial / F - frappe/webshop is a first-party GPL e-commerce storefront (split out of ERPNext core at v14) that wr | downgrade-to-partial | Regrading a grade-F partial, not changing its value. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The census makes the shape exact. Real: frappe/webshop is a first-party GPLv3 storefront on the operator's own Frappe site and domain, taking no commission; its cart is a Quotation that becomes a Sales Order, and checkout is the quoted `enable_checkout` switch plus one payment_gateway_account raising a Payment Request. Not real, and why this stays partial: the 230-blob census contains ZERO paths matching pickup, curbside, delivery, schedul or slot; no modifier layer exists in either repo (\bmodifier\b = one accounting-role hit); place_order.html offers only Place Order or Request for Quote; and there is no prep timing. Two further facts the record should carry: (1) e-commerce is no longer in ERPNext core at all - erpnext/patches/v15_0/delete_ecommerce_doctypes.py removed it at v15, so any statement about 'ERPNext's webshop' is a statement about a separate app; (2) frappe/webshop carries ZERO git tags - it has never cut a release, and its only branches are develop plus version-15 backports (HEAD 1a5239d, 2026-06-05). Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Positive control: \bwebshop\b|website_item|e_commerce_settings = 7 files in erpnext. source |
| digital-menu-single-source | partial / F - Webshop renders the same Item master and Price List as the POS, so one edit does propagate. There is | downgrade-to-partial | Regrading a grade-F partial, not changing its value. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. The artefact is webshop's Website Item, whose opening field_order run is quoted (naming_series / web_item_name / route / has_variants / variant_of / published): it is a thin published wrapper LINKING `item_code` on the ERPNext Item master, with item_name / variant_of / has_variants / stock_uom / brand all fetched through from that Item, and Webshop Settings carries a single `price_list`. So the storefront and the POS do read one Item master and one Price List - an item edit does propagate, and there is no second digital menu build. Why it is not `yes`: there is no menu record to be single-sourced FROM - Price List.restaurant_menu was deleted from core at v14 by erpnext/patches/v14_0/delete_hospitality_doctypes.py, \bmodifier\b matches one accounting-role hit in both repos, and Website Item is nonetheless a SEPARATE published record per item (published / route / website_image / web_long_description / recommended_items), so an operator does maintain a second object per sellable item even though its price and identity are inherited. Positive control: \bItem Attribute\b = 24 files, \bPricing Rule\b = 56 files - the shared master data IS visible to this search. source |
| digital-loyalty-attach | unknown / F - Loyalty Program is documented against Sales Invoice and POS. Whether webshop checkout accrues and re | resolve-to-no | CHANGES the cell from unknown to no, and grounds it. The standing rationale said 'whether webshop checkout accrues and redeems against the same Customer identity is not documented on any page retrieved' - a census of the app settles it without needing a doc page. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Invariance: `loyalty` matches ZERO paths in the 230-blob webshop census. Webshop Settings' entire optional-feature surface is the quoted add_ons_section - enable_wishlist and enable_reviews, and nothing else; there is no loyalty switch, no points display and no redemption control. webshop/webshop/shopping_cart/cart.py sets no loyalty field on the Quotation or Sales Order it builds. On the other side the machinery plainly exists and is POS-specific: Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. \bLoyalty Program\b returns 22 files / 56 lines, and POS Invoice ships a whole loyalty_points_redemption section (loyalty_points, loyalty_amount, redeem_loyalty_points, loyalty_program, loyalty_redemption_account, loyalty_redemption_cost_center) - Sales Order carries loyalty_points/loyalty_amount too, but webshop never populates them. So accrual and redemption are in-store only. Positive control: that same \bLoyalty Program\b search is the control - it fires 22 times in erpnext and zero times in webshop. source |
| digital-subscriptions | partial / F - ERPNext ships a Subscription doctype with recurring invoicing against a Subscription Plan. It is a B | downgrade-to-partial | Regrading a grade-F partial, not changing its value. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. The artefact is the Subscription doctype, and the quoted run shows what it genuinely does model: subscription_period, trial_period_start/end, cancel_at_period_end, days_until_due, current_invoice_start/end, plus a `plans` child table of Subscription Plans and generate_invoice_at / submit_invoice. That is real recurring billing against a party, so a paid tier COULD be billed - which is why this is not `no`. Why it is not `yes`: there is no entitlement layer of any kind. Nothing links a Subscription to a fee waiver, a per-period item allowance, or a Pricing Rule; `party_type`/`party` is a Customer or Supplier link, not a guest identity; and the storefront cannot sell one - `subscription` matches ZERO paths in the 230-blob frappe/webshop census, and Webshop Settings has no subscription field. Loyalty Program exists but is a separate points construct with no tier billing. Positive control: \bSubscription Plan\b = 17 files / 34 lines, so the billing machinery IS fully visible to this search - the membership semantics are what is missing. source |
| digital-checkout-pci-sca | unknown / F - Webshop hands off to hosted gateway flows (Razorpay/Stripe/PayPal), which would keep PAN off the pag | resolve-to-partial | CHANGES the cell from unknown to partial and grounds both halves. frappe/webshop was also censused via the GitHub tree API (truncated:false, 230 blobs, HEAD 1a5239d 2026-06-05); the repo carries ZERO git tags, i.e. it has never cut a release. Corpus: the two shallow clones at erpnext v16.34.1 (5,170 files) and frappe v16.33.0 (3,634 files); the GitHub tree API answered truncated:false for both, so this is a census of those two repositories at those two tags, nothing wider. Half that is established: webshop checkout never touches card data on the operator's page. The quoted line is from webshop/webshop/shopping_cart/cart.py, which requires a single Webshop Settings.payment_gateway_account and hands the order to erpnext's Payment Request, whose Payment Gateway Account resolves to a hosted redirect (\bRazorpay\b 7 files, \bStripe\b 5, \bPayPal\b 12); `token` matches ZERO paths in the webshop census, i.e. no PAN or token is ever stored or posted by the storefront. Half that is established as ABSENT rather than unknown: 'PCI DSS' returns ZERO occurrences across erpnext v16.34.1 and frappe v16.33.0, \b3ds\b|three.?d.?secure returns ZERO files, and a bounded docs census (1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12).xml - the 26 misses are 404s in the publisher's own manifest) contains no PCI DSS 4.0 statement, no client-side script-integrity position and no 3DS documentation. Vendor legal/trust pages outside docs.frappe.io were not censused and are the one route that could still move this. Positive control: those three gateway names firing in erpnext is the control. source |
| payments-surcharge-guardrails | no / F - No BIN-level card data reaches ERPNext; no surcharging engine." | downgrade-to-no | Searched the vendor vocabulary for card surcharging: /\bsurcharge/i, /\bBIN\b/i, /\binterchange\b/i, /\bcard.?type\b/i over the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero hits for /\bsurcharge/i anywhere in erpnext v16.34.1 or frappe v16.33.0. /\bBIN\b/i returns 101 files and every one is the Stock module "Bin" doctype (stock_projected_qty, test_bin, production_plan) -- an inventory bin, not a Bank Identification Number: that is the trap on this cell. In the docs census /\bsurcharg/i returns 3 pages and all three are Indian tax-template vocabulary ("a tax, levy, or surcharge", "surcharge, cess, or levy" in types-in-tax-template and tax-on-another-tax-amount), not card surcharging. POSITIVE CONTROL: /\bMode of Payment\b/ returns 62 files and the whole Pricing Rule engine is present, so the search does reach the accounting and pricing surfaces where a surcharge rule would live. ARTEFACT: the complete field list of Sales Invoice Payment -- the child table that IS the tender row on every POS Invoice -- has nine fields, none of which carries a card product code, a BIN, a network percentage cap or a per-location surcharge toggle. No BIN-level card data can reach ERPNext because no card data reaches it at all. source |
| payments-emv-nfc | no / F - No first-party payment terminals of any kind." | downgrade-to-no | Two searches. (1) Code census for the acceptance vocabulary: /\bEMV\b/i, /\bNFC\b/i, /\bcontactless\b/i, /\bapple pay\b/i, /\bgoogle pay\b/i, /\bterminal\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for NFC, contactless, Apple Pay or Google Pay in either repository; /\bEMV\b/i survives on exactly one line, inside frappe/tests/data/email_with_image.txt (a base64 blob) -- the EMV substring trap; /\bterminal\b/i is 12 files of bench CLI shell vocabulary plus a Colombian chart-of-accounts account name. Zero hits for EMV/NFC/contactless across the docs census as well. (2) The claim is about FIRST-PARTY payment terminals, which is a claim about what Frappe sells, and the vendor answers that in its own Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) under Support Exclusions. POSITIVE CONTROL: the same SLA does enumerate what Frappe supplies and charges for -- hosting plans, a product warranty entitlement above the $50 Frappe Cloud plan, priority/phone support, L2 bug support -- so a terminal programme would be named there if one existed. Frappe ships no payment terminal, so no first-party terminal accepts EMV or NFC. source |
| payments-qr-guest-pay | no / F - ERPNext can print a UPI QR on invoices in the India localization, but it does not close the check in | upgrade-to-partial | CORRECTION -- the existing rationale is wrong in both directions. (1) It says ERPNext prints a UPI QR "in the India localization"; the India localisation was DELETED from core in v14 by erpnext/patches/v14_0/remove_india_localisation.py ("India-specific regional features have been moved to a separate app") and /\bupi\b/i in the v16 census survives only in bank_statement_import test fixtures. (2) It says nothing closes the check automatically, but it does. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. Searched the vendor vocabulary: request_for_payment, process_phone_payment, Payment Request, Mode of Payment type. INVARIANCE: POS Invoice exposes a request_for_payment action that saves the invoice, calls create_payment_request, and pushes a gateway payment request to the customer's own contact_mobile; Mode of Payment.type is a Select whose complete option set is "Cash / Bank / General / Phone"; and pos_payment.js subscribes to the realtime event process_phone_payment and calls this.events.submit_invoice() once the received amount covers the grand total -- i.e. the guest pays from their own phone and the check closes in the POS automatically. What is absent is the QR half: nothing renders a payment QR onto a POS receipt or table tent. Frappe's only QR generator (PyQRCode, frappe/www/qrcode.html) serves two-factor-authentication enrolment. POSITIVE CONTROL: /qr.?code/i does return 17 files across both repos, so a receipt QR would have surfaced. Pay-from-own-phone with automatic check closure: present. Scan-a-QR-on-the-check: absent. Partial. source |
| payments-tip-adjust | no / F - No tip concept in POS Invoice and no auth/capture window because there is no card processing." | downgrade-to-no | Searched the gratuity and auth/capture vocabulary: /\btip\b/i, /\bgratuity\b/i, /\bpre.auth\b/i, /\bauth.?code\b/i, /\bcapture\b/i, /\bbatch\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\btip\b/i anchored at word boundaries survives in 10 files across both repositories and every one is noise -- leaflet.css, a hint string in financial_report_template.js, GitHub workflow YAML; unanchored "tip" is 574 files of "multiple"/"description". Zero word-boundary hits for pre-auth or store-and-forward in either repo. ARTEFACT: Sales Invoice Payment, the child table carrying every tender line on a POS Invoice, has exactly nine fields (default, mode_of_payment, amount, reference_no, column_break_3, account, type, base_amount, clearance_date). No tip field, no adjusted amount, no authorisation code, no batch/settlement window -- so there is nothing to adjust after the fact and no unadjusted-tip queue to surface on a manager screen. POSITIVE CONTROL: the sibling POS money concept IS modelled on the parent doctype -- POS Invoice carries loyalty_points, loyalty_amount, redeem_loyalty_points and loyalty_program -- which proves a POS-specific money field would appear in these field lists if it existed. source |
| payments-offline-decline-liability | no / F - No offline card capture exists, so no liability position is published." | downgrade-to-no | ATTACK 1. The verdict is a claim about what the vendor publicly documents; the cited artefact was a JavaScript constructor. Source code cannot carry a publication negative. Moved the citation to the legal document the note itself named as the place such a position would live, and dropped A to B accordingly. Value unchanged. source |
| payments-gift-cards | no / F - No gift card product. Could be modeled as a customer advance/credit, but that is a build, not a feat | downgrade-to-no | Searched /\bgift.card/i, /\bstored.value\b/i, /\bwallet\b/i over the code census and the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: "Gift Card" DOES exist in erpnext v16.34.1 -- but only as one of two literal values of Coupon Code.coupon_type (DF.Literal["Promotional", "Gift Card"]), where it generates a random 10-character hash, forces maximum_use = 1 in validate(), and links to a Pricing Rule. It is a single-use discount code, not a stored-value instrument: no balance field, no redemption ledger, and it is not a Mode of Payment (Mode of Payment.type is Cash/Bank/General/Phone). The vendor says so itself in the FAQ of its own Coupon Code documentation page, quoted here. POSITIVE CONTROL: the genuinely balance-tracking, cross-location money feature in this stack -- Loyalty Program with Loyalty Point Entry -- is present in 54 files and is wired into POS Invoice and pos_payment.js, which proves the corpus would show a gift-card balance object if one existed. No first-party gift-card product exists in core ERPNext. source |
| payments-chargeback-tooling | no / F - ERPNext is neither an acquirer nor a processor and captures no card transaction — POS Profile paymen | downgrade-to-no | Searched the dispute vocabulary: /\bchargeback\b/i, /\bdispute\b/i, /\brepresentment\b/i, /\bretrieval request\b/i over the code census, and /\bchargeback\b/i over the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for chargeback, representment or retrieval request in erpnext v16.34.1 or frappe v16.33.0; /\bdispute\b/i survives on exactly one line, in test_journal_entry.py, as an ordinary English word in a test comment. Zero chargeback hits across the docs census. ARTEFACT: Sales Invoice Payment is the complete tender record for a POS sale -- a Mode of Payment link, an amount, a GL account, a Read Only type fetched from Mode of Payment, a clearance date and a free-text reference_no. There is no acquirer reference, no card network, no processor transaction identifier a dispute could be raised against, and therefore no object a dispute dashboard could be built over. POSITIVE CONTROL: /\bPayment Gateway\b/ does return 14 files (Payment Gateway Account, Payment Request), so ERPNext's payment-adjacent surface IS in the corpus -- and that surface stops at handing off to a gateway. Disputes belong to whichever processor the operator contracts separately. source |
| payments-card-on-file | no / F - No tokenization vault. Online gateway integrations hand off to the gateway's own hosted flow." | downgrade-to-no | Searched for a vault in the vendor's and the industry's words: /\btokeniz/i, /\bcard.on.file\b/i, /\bPAN\b/i, /\bvault\b/i, /\bsaved card\b/i over the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero hits for card-on-file, vault or saved card; /\btokeniz/i survives in 7 files and every one is TEXT tokenisation -- frappe/search/sqlite_search.py (FTS tokenizer), the gettext javascript extractor, jquery.min.js -- not payment tokenisation. ARTEFACT: Sales Invoice Payment carries nine fields and the only free-text one is reference_no; there is no token, no card fingerprint, no expiry, and no customer payment-method child table on Customer or Contact anywhere in the tree. The gateway path that does exist (Payment Request -> Payment Gateway Account -> controller.request_for_payment) hands the payer to the gateway's own hosted flow and receives back a status, so any tokenisation lives inside the processor and is not reusable across ERPNext channels. POSITIVE CONTROL: /\bPayment Gateway\b/ = 14 files and /payment_gateway/ = 11 files, so the gateway surface is present and searchable; it contains no vault. source |
| payments-payout-timing | no / F - Not applicable — Frappe does not settle funds." | downgrade-to-no | ATTACK 1 and ATTACK 2. The row asserted a PUBLICATION absence ('vendor publishes its deposit schedule') and cited mode_of_payment.json at grade A. A doctype field list cannot establish what a vendor does or does not publish; it establishes only that ERPNext models no card tender. The note's actual evidence for the publication half was the SLA and the Cloud terms, which were not the cited artefact. Moved the URL to the document that carries the finding and dropped grade A to B, the honest grade for a vendor legal page. Also corrected the docs-census figure: 1,544 is the erpnext+framework subset, not the census. source |
| payments-p2pe-pci4 | no / F - Frappe publishes no PCI DSS AoC or P2PE listing. Card data never enters ERPNext in the intended arch | downgrade-to-no | Searched the attestation vocabulary: /\bPCI\b/i, /\bP2PE\b/i, /\bAoC\b/i, /\bSAQ\b/i, /\bPTS\b/i over the code census and over the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for PCI, P2PE, AoC, SAQ or PTS in erpnext v16.34.1, in frappe v16.33.0, or on any of the 1,863 docs pages. An absence is not an attestation, so I went to the place an attestation WOULD be published: Frappe's own certifications page (quoted here) and the "Compliance & Certifications" section of the Frappe Cloud security FAQ (docs.frappe.io/cloud/faq/architecture-and-security, fetched today: "Yes, we are certified under ISO 9001:2015, ISO 27001:2022, and SOC-2 Type-2 standards."). Both are CLOSED ENUMERATIONS of the vendor's compliance posture and both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2 -- no PCI DSS of any version and no validated P2PE listing. POSITIVE CONTROL: the same page publishes real, dated attestations with a certifying body (ISOQAR recertification Dec 2024, ISMS upgraded to ISO 27001:2022, surveillance audit Dec 2025, SOC-2 Type-2 achieved 2025), so it is a page that reports attestations when they exist. Frappe provides no P2PE and publishes no PCI DSS 4.x AoC. source |
| hardware-handheld-purpose-built | no / F - No first-party handheld of any kind, so no drop or IP rating." | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bhandheld\b/i, /\bdrop rating\b/i or /\bIP54\b|\bIP65\b|\bingress\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero hits for /\bhandheld\b/i across the 1,863-page docs census. POSITIVE CONTROL: the same SLA enumerates what Frappe DOES sell and support -- hosting plans, a product-warranty entitlement gated at the $50 Frappe Cloud plan and above, priority/phone support, L2 bug support -- so a handheld SKU would be named in that document. With no first-party device there is no published drop rating and no IP ingress rating to assess. source |
| hardware-handheld-battery-swap | no / F - Frappe sells no hardware of any kind and ships no first-party handheld, so there is no battery, hot- | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bhandheld\b/i, /\bhot.?swap\b/i and /\bshift life\b/i return ZERO files in both repositories and ZERO across the docs census. /\bbattery\b/i is NOT zero, and that is the trap: it survives in exactly 3 files and every hit is a manufacturing or stock TEST FIXTURE item name -- "Test Batch Battery Consumable", "Test Serial Battery Consumable", "_Disassemble Battery" -- a BOM component, never a device battery. No rated shift life, no hot-swap, no spare-battery programme. POSITIVE CONTROL: the SLA does name the device-adjacent obligations Frappe accepts (which Linux distributions Bench supports, upgrade support, scaling support), so a battery or spare-battery programme would be stated there. Operators run the browser POS on commodity tablets and phones; battery handling belongs to the device OEM, not to Frappe. source |
| hardware-handheld-lte | no / F - There is no first-party handheld device, so no cellular-equipped SKU exists. A staff phone’s own LTE | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bLTE\b/i, /\bcellular\b/i, /\b4G\b|\b5G\b/i, /\bSIM\b/i or /\bfailover\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero for LTE/cellular across the 1,863-page docs census. POSITIVE CONTROL: /\bnetwork printer\b/ = 5 files, so the corpus does contain the stack's device-connectivity configuration surface. A staff phone's own radio would carry the browser session, but that is the operator's device rather than a product capability -- and since the POS cannot boot without reaching the server (pos_controller.js calls check_opening_entry() in its constructor), there is no offline mode to cover a cellular gap either. source |
| hardware-kiosk | no / F - Frappe sells no hardware and ships no kiosk application, so there is no kiosk enclosure, stand, prin | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census for a kiosk APPLICATION as well as kiosk hardware, because those are different claims. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bkiosk\b/i returns ZERO files in erpnext v16.34.1, ZERO in frappe v16.33.0, and ZERO across the 1,863-page docs census -- there is no self-order application, no kiosk mode flag on POS Profile, and no ADA/accessibility statement for one. POSITIVE CONTROL: /\bPOS Profile\b/ = 53 files, and the POS Profile doctype JSON carries 70+ configuration fields (hide_unavailable_items, hide_images, auto_add_item_to_cart, print_receipt_on_order_complete, action_on_new_invoice...), so a kiosk mode would be visible in that field list if it existed. No enclosure, stand, printer or payment-reader bundle to assess. source |
| hardware-drive-thru | no / F - No drive-thru product exists in the software and Frappe sells no hardware, so there are no headsets, | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. Cross-checked against the code census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bdrive.thru\b|\bdrive.through\b/i returns ZERO files in both repositories and ZERO across the docs census; so do /\bmenu board\b/i, /\bheadset\b/i and /\bspeed of service\b/i. POSITIVE CONTROL, and it is the informative one: /\bkitchen\b/i anchored returns exactly 2 files and both are chart-of-accounts templates carrying a GL account literally named "Kitchen" (Singapore F&B and UAE charts). The search reaches food-service vocabulary in this corpus and finds only accounting. No order-confirmation board, vehicle detector or lane timer exists in the software, and Frappe supplies no hardware to run one on. source |
| hardware-p2pe-terminal | no / F - No PTS device program and no stated merchant SAQ type." | downgrade-to-no | The claim has two halves and both fail against first-party documents. (1) A PCI-listed PTS device using validated P2PE: Frappe's certifications page (quoted here) and the "Compliance & Certifications" section of docs.frappe.io/cloud/faq/architecture-and-security are closed enumerations of the vendor's compliance posture, and both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2 -- no PCI DSS, no P2PE listing, and nowhere a stated merchant SAQ type. (2) A device programme at all: the Frappe SLA states under Support Exclusions that "Frappe shall not provide any type of Infrastructure purchase to the Customer such as, but not limited to, server or any other type of hardware." Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for PCI, P2PE, PTS or SAQ in erpnext v16.34.1, frappe v16.33.0, or any of the 1,863 docs pages. POSITIVE CONTROL: the certifications page publishes attestations with dates and a certifying body (ISOQAR, Dec 2024 recertification, Dec 2025 surveillance audit), so it reports attestations when they exist. ERPNext keeps card data out of the application by architecture, but no PTS device programme and no SAQ statement is published. source |
| hardware-rma-sla | no / F - No vendor hardware, therefore no warranty or advance-exchange program. Device warranty is the OEM's. | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. This cell is answered by that sentence directly: with no vendor hardware there is no warranty term and no advance-exchange or depot-swap turnaround. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bRMA\b/i, /\badvance exchange\b/i and /\bnext.business.day\b/i return ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bdepot\b/i survives on exactly one line and it is a substring inside the escaped format_data blob of the Purchase Receipt serial-and-batch print format, not a service concept. POSITIVE CONTROL, and it is the sharp one: the SAME SLA document DOES publish turnaround commitments -- three tables of response and resolution times by issue priority (standard tier Critical: 1 hour response / 4 hour resolution; premium tier 30 min / 2 hours) and a "product warranty" entitlement threshold at the $50 Frappe Cloud plan. So this vendor publishes SLAs with stated turnarounds where it has an obligation. The warranty it names is a software-support warranty; the hardware clause it names is an exclusion. Device warranty is the OEM's. source |
| hardware-remote-device-management | no / F - No device fleet console. Frappe Cloud manages sites and servers, not terminals or printers." | downgrade-to-no | Searched the fleet-console vocabulary over the code census: /\bfleet\b/i, /\bMDM\b/i, /\bremote reboot\b/i, /\bstaged rollout\b/i, /\bfirmware\b/i, /\bterminal\b/i, /\bKDS\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bMDM\b/i, /\bremote reboot\b/i, /\bstaged rollout\b/i, /\bfirmware\b/i and /\bKDS\b/i return ZERO files in both repositories, and /\bterminal\b/i is 12 files of bench CLI shell vocabulary. /\bfleet\b/i is NOT zero and is the trap on this cell: it survives in exactly 2 files, vehicle.json and driver.json, where it is the "Fleet Manager" ROLE of ERPNext's vehicle module -- a fleet of trucks, not a fleet of terminals. ARTEFACT: Network Printer Settings is the ONLY hardware-device record type in frappe v16.33.0, and its complete field list is four entries -- server_ip (default localhost), port (default 631, i.e. CUPS), a column break, and printer_name. There is no status field, no last-seen timestamp, no online/offline state, no software version and no reboot action, so there is nothing for a device console to display. POSITIVE CONTROL: Frappe Cloud DOES ship a real fleet console -- docs.frappe.io/cloud documents per-site and per-server actions, analytics, process lists, notification configuration and staged bench update schedules -- which proves the vendor builds exactly this kind of console when the managed objects exist. It manages sites, benches and servers; it manages no terminals, printers or KDS stations. source |
| hardware-selfpour-scales | no / F - No self-pour, keg, flow-meter, pour-spout or scale integration exists. Item UOM conversion can recor | downgrade-to-no | ATTACK 2. Grade A requires the cited artefact to be the exhaustive place the feature would live. A network-printer settings doctype is not where a flow-meter, pour-spout or scale integration would live; the real evidence is a corpus-wide zero over ten anchored patterns, and the corpus is not the URL. Downgraded to B and rewrote the note so it stops presenting the printer doctype as the artefact that carries the absence. Value unchanged and well supported. source |
| reliability-offline-card-auth | no / F - No card processing at all, offline or online-card-present." | downgrade-to-no | The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell specifically: there is no card authorisation path online either -- Mode of Payment.type is Cash/Bank/General/Phone and Sales Invoice Payment carries no authorisation code -- so store-and-forward would have nothing to forward. Note that even cash-only fallback is unavailable, because the POS does not open without the server. source |
| reliability-offline-decline-liability | no / F - No store-and-forward exists, so no liability position is published." | downgrade-to-no | ATTACK 1, the same failure as payments-offline-decline-liability. A publication claim cited to pos_controller.js at grade A. The code establishes the antecedent, not the publication negative. Citation moved to the settling document, grade A to B. source |
| reliability-lan-degraded-multi-terminal | no / F - If the on-premise or cloud server is reachable over LAN, all terminals share state normally — but th | downgrade-to-no | The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell the nuance matters: shared check state IS real while the server is reachable -- POS Invoice rows live in one MariaDB instance and every terminal is a browser talking to it, so LAN-only operation against an on-premise bench genuinely works with the internet down. What is absent is DEGRADED operation: no partition mode, no local replica on a terminal, no peer discovery. The check_opening_entry() round trip in the constructor is the proof -- a terminal that cannot reach the server does not island, it stops. Frappe Cloud's own security FAQ confirms the same shape one layer down: "No, there is no automated failover for databases on Frappe Cloud." source |
| reliability-offline-kds-printing | no / F - No KDS, and printing is initiated by the server-rendered client." | downgrade-to-no | The offline family turns on one question: can the ERPNext POS run without the server? Searched the vendor vocabulary and the web-offline vocabulary over the code census: /\boffline\b/i, /\bservice.?worker\b/i, /\bindexeddb\b/i, /\bstore.and.forward\b/i, and localStorage inside the point_of_sale page. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for service worker or store-and-forward in either repository; indexeddb survives only in communication.js and fingerprintjs; /\boffline\b/i survives in 11 files across both repos and the ONLY POS-related survivors are historical changelogs -- erpnext/change_log/v7/v7_0_0.md ("New POS - Offline"), v7_2_0.md ("Provision to delete the offline records in POS") and v9/v9_0_0.md ("Now user has an option to enable or disable Offline POS mode from POS Settings"). An offline POS existed at v7-v9 and has been REMOVED; nothing implements it at v16. ARTEFACT: the POS application constructor. erpnext.PointOfSale.Controller calls this.check_opening_entry() before rendering, which is a frappe.call round trip to the server; if the server is unreachable the POS never renders a cart. POSITIVE CONTROL: /\bPOS Opening Entry\b/, /\bPOS Closing Entry\b/ and /\bPOS Invoice\b/ all resolve to real doctypes with real code, so the POS session vocabulary is present and this search reaches it. For this cell there are two absences, not one. (a) KDS: /\bKDS\b|\bkitchen display\b/i returns ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bkitchen\b/i anchored is 2 files, both chart-of-accounts templates with a GL account named "Kitchen". (b) Kitchen printing: printing in this stack is a Print Format rendered by the SERVER and either handed to the browser or pushed to CUPS via frappe/printing (pycups, Network Printer Settings on port 631). Both paths require the server, and the QZ Tray raw-printing bridge is driven by the server-rendered client too, so neither survives a server outage. POSITIVE CONTROL: /\braw print/i = 7 files and /\bQZ Tray\b/ = 11 lines in frappe/public/js/frappe/form/print_utils.js, so the corpus does reach the thermal-printing surface. source |
| reliability-printer-fallback | no / F - No automatic backup-printer failover or unreachable-printer alerting." | downgrade-to-no | Searched the failover vocabulary over the code census: /\bfailover\b|\bfail.over\b/i, /\bbackup printer\b/i, /\bfallback\b/i within the printing module, /\bunreachable\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bfailover\b|\bfail.over\b/i returns ZERO files in erpnext v16.34.1 and frappe v16.33.0. ARTEFACT: Network Printer Settings is the complete printer object in the framework and its entire field list is four entries -- server_ip, port, a column break, printer_name. There is no secondary/backup printer link, no priority, no health check, no alert recipient and no station-routing table, so there is nothing to fail over TO and nothing to raise an alert from. The alternative print path, QZ Tray raw printing, is a per-client browser bridge with a user connection prompt and has no server-side registry of stations at all. POSITIVE CONTROL: frappe DOES ship real alerting objects -- the Notification doctype, and Frappe Cloud threshold alerts documented at docs.frappe.io/cloud/reliability -- so an unreachable-printer alert would be expressible if the product modelled printer health. It does not. source |
| reliability-offline-feature-matrix | no / F - No published offline feature matrix — a direct consequence of there being no supported offline mode. | downgrade-to-no | The claim is about vendor PUBLICATION, so the docs census is the right instrument. Searched /\boffline\b/i across all 1,863 pages of the docs census -- 98.3% of docs.frappe.io's own sitemap manifest for the erpnext and framework spaces, the 26 misses being 404s inside the publisher's own manifest. INVARIANCE: 13 pages match and not one is a POS offline feature list -- they are payment-request "offline bank-transfer instructions", the GSTR-1 offline tool, Google OAuth access_type=offline in connected-app, and site_config. The ERPNext POS Introduction page, quoted here, is where an offline capability and its limits would be stated; it describes real-time stock integration, deferred posting at session close, multiple payment methods and loyalty, and says nothing about offline operation. That silence matches the code: Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. zero service-worker and zero store-and-forward hits, and the only /\boffline\b/i survivors touching POS are the v7/v9 changelogs for a mode that no longer exists. POSITIVE CONTROL: this publisher DOES write explicit negative feature matrices when it has one -- the Frappe Cloud security FAQ answers "Is there a WAF protecting applications?" with "No, but a server level firewall is available", "Is there automated failover for databases?" with "No", and states an RPO of up to 24 hours. There is no offline mode, hence no matrix to publish. source |
| reliability-hardware-replacement-sla | no / F - No vendor hardware program." | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. This cell asks whether a replacement/advance-exchange programme with a stated turnaround is included or purchasable; the SLA answers by excluding hardware supply from the agreement entirely. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bRMA\b/i and /\badvance exchange\b/i return ZERO files in both repositories and ZERO across the 1,863-page docs census; /\bdepot\b/i survives on exactly one line, as a substring inside the escaped format_data blob of the Purchase Receipt serial-and-batch print format. POSITIVE CONTROL: the very same document publishes purchasable service tiers WITH stated turnarounds -- Standard, Premium and L2-bug tables of response/resolution time per issue priority, gated on the $50-and-above Frappe Cloud plan for product warranty -- so the vendor states turnarounds where it takes on obligations. For hardware it states an exclusion. source |
| reliability-failover-terminal-role | no / F - Architecture is client-server; no terminal can assume a server role. The server is the single point | downgrade-to-no | Searched the master-election vocabulary over the code census: /\bfailover\b|\bfail.over\b/i, /\bprimary terminal\b/i, /\belection\b/i, /\bquorum\b/i, /\bpeer\b/i, and /\bmaster\b/i as a role. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: /\bfailover\b|\bfail.over\b/i returns ZERO files in erpnext v16.34.1 and frappe v16.33.0. ARTEFACT: the POS is a browser page inside the Frappe desk; erpnext.PointOfSale.Controller does a frappe.call to check_opening_entry() before it can render, so a terminal is a pure client with no server role to assume, no local datastore and no peer awareness. The bench/MariaDB server is the single point of failure. POSITIVE CONTROL, and it cuts the right way: Frappe DOES document failover, but only at the infrastructure layer and only manually -- docs.frappe.io/cloud/faq/architecture-and-security says "No, there is no automated failover for databases on Frappe Cloud", and docs.frappe.io/cloud/servers/other-information/on-prem-failover-setup describes a beta, support-ticket-gated WireGuard replica to a customer-run server ("disabled by default for all servers"). Neither is a terminal assuming a server role. source |
| reliability-cellular-backup | no / F - No first-party or documented LTE failover; a tablet's own cellular radio would work but that is the | downgrade-to-no | The claim is about FIRST-PARTY hardware, so the settling document is the vendor's commercial terms, not the code. Frappe's Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) states under Support Exclusions, section 2.3 item 6, that Frappe supplies no hardware at all. A first-party LTE failover would be a device Frappe supplies, and it supplies none. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files) -- the GitHub tree API answered truncated:false for both, so an absence here is a real absence in those two repositories at those two tags, not a claim about the wider Frappe app ecosystem (marketplace restaurant POS apps such as URY / POSNext / GETPOS are out of record scope). Docs census: 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. INVARIANCE: zero word-boundary hits for /\bLTE\b/i, /\bcellular\b/i, /\bfailover\b/i or /\bSIM\b/i in erpnext v16.34.1 or frappe v16.33.0, and zero for LTE/cellular across the 1,863-page docs census -- so the second half of the claim, a DOCUMENTED failover, fails too. POSITIVE CONTROL: the vendor does document connectivity-layer operations when they exist -- docs.frappe.io/cloud covers obtaining a static IP, custom domains, moving a site across regions, and an on-prem WireGuard replica -- so cellular-failover guidance would sit in that space. A tablet's own radio would carry the browser session; that is the device, not the product, and with no offline mode the gap is not covered anyway. source |
| hardware-os-platforms | unknown / F - No page retrieved names specific client operating systems with minimum versions or device specs. Fra | resolve-to-no | ATTACK 1 and a propagated premise. The note asserted that '/\bios\b|\bipad\b|\bandroid\b/i returns ZERO pages ... the publisher never names a client operating system anywhere in the documentation', then contradicted itself in its own positive control by conceding the hr and crm spaces carry mobile-app-installation pages. I re-ran it over the real 1,863-page census: two pages hit. The verdict survives -- no client-OS matrix or minimum version exists for the POS-bearing product -- but the stated zero was false, and the census figure was the previous brief's 1,544, which is the erpnext+framework subset and excludes the 147 hr, 160 cloud and 12 legal pages. Rewritten to state the true figure, the true hits, and the bound that actually carries the verdict. source |
| hardware-peripherals | partial / F - Barcode scanners work out of the box (Item Barcode field plus keyboard-wedge input in POS and Stock | downgrade-to-partial | CORRECTION to the existing rationale, which says cash drawers have "no native support". They do have a documented path. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. Searched the vendor vocabulary: /\braw print/i, /\bQZ Tray\b/, /\bcups\b|\bpycups\b/, /\bdrawer\b/i, /scan_barcode|barcode_scanner/, /\bcustomer.display\b/i, /\bweighing\b|\bscale device\b/i. FINDINGS, per peripheral: (a) BARCODE SCANNERS -- fully supported, /scan_barcode|barcode_scanner/ = 37 files, POS Invoice carries a scan_barcode field, and the framework additionally documents a camera scanner API (framework/user/en/api/scanner, Html5-QRCode). (b) CASH DRAWERS -- supported via ESC/POS raw commands hand-written into a Print Format and pushed through QZ Tray, which the vendor documents in the sentence quoted here; /\bdrawer\b/i returns ZERO files in either repository, so there is no drawer object, no per-terminal multi-drawer model and no kick command in the product -- the operator writes the bytes. (c) SCALES -- absent: zero anchored hits for weighing, weigh-scale, scale device, serial port or RS-232 in either repo (the unanchored "scale" trap is 133 files of CSS transform and grayscale). (d) CUSTOMER-FACING DISPLAYS -- absent, and this is the trap on this cell: /customer.display/i returns 6 lines in pos_item_cart.js and point-of-sale.scss, but ".customer-display" there is a CSS class for the customer NAME chip inside the cashier's own cart panel, not a second screen. (e) No published compatibility list for any of them. POSITIVE CONTROL: /\bnetwork printer\b/ = 5 files and /\bcups\b|\bpycups\b/ = 3 files including frappe's pyproject dependency, so the peripheral surface is present and searchable. Partial stands, with a corrected reason: scanners yes, drawer via documented raw-printing DIY, scales and customer displays no, compatibility list none. source |
| hardware-ownership-vs-lease | partial / F - There is no lease because there is no vendor hardware — everything is owned outright by definition. | downgrade-to-partial | The existing rationale says "Frappe does not state this anywhere", and that is the part that is wrong -- the vendor does state it, in its Service Level Agreement (frappe.io/support-sla, last updated 18 June 2026, fetched today) under Support Exclusions section 2.3 item 6, quoted here. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: /\bRMA\b/i and /\bbuyout\b/i return ZERO files in both repositories. /\blease\b|\brental\b/i is NOT zero and had to be read: 9 lines across 8 files, every one of them a GL ACCOUNT NAME inside a chart-of-accounts template ("Lease Liabilities" and "Finance Lease - Current" in the Australian and New Zealand charts, "Rental-Equipment" and "Rental-Premises" in the Singapore default and F&B charts, "Lease-verplichtingen" in the Dutch grootboekschema) or a financial-report category description -- accounting vocabulary for the operator's own leases, not a Frappe hardware lease. In the docs census the pair survives on one page, about e-commerce integrations. So there is no lease, because there is no vendor hardware at all: every device an operator runs the browser POS on is bought on the open market and owned outright by construction. POSITIVE CONTROL: the same SLA and frappecloud.com/terms (effective 1 April 2026) DO state what is rented -- hosting subscriptions, plan tiers, product warranty gated at the $50 plan -- so the vendor states its commercial models where they exist. Held at partial rather than yes because what the vendor states is an exclusion of hardware supply, not an affirmative ownership term for hardware it sells; grade moves F to B on the cited exclusion. source |
| hardware-usable-after-churn | partial / F - Structurally guaranteed — commodity devices running a browser cannot be software-locked or bricked b | downgrade-to-no | ATTACK 4 in the opposite direction: an over-generous partial. The row conceded 'the vendor publishes no post-cancellation hardware commitment because it has no hardware' and then scored partial anyway, crediting a structural inference (devices cannot be locked) that the claim does not ask for. The claim asks whether vendor documentation confirms a property of vendor-sold hardware; there is no vendor-sold hardware and no such confirmation, which is a `no`. Kept the structural observation in the note, clearly separated from the claim's subject, and moved the citation to the stable docs.frappe.io/legal URL for the SLA rather than the frappe.io marketing path. source |
| hardware-byod | partial / F - Any staff phone with a browser and a user account can reach the POS, and Frappe's role/user permissi | downgrade-to-partial | Searched for a BYOD-specific posture: /\bBYOD\b/i, /\bMDM\b/i, /\bmobile device management\b/i, /\bpersonal device\b/i, /\bdevice policy\b/i over the code census and the docs census. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: ZERO hits for every one of those across both repositories AND across all 1,863 docs pages -- there is no BYOD guidance, no MDM integration and no personal-device policy anywhere. What DOES exist, and what keeps this at partial rather than no, is the generic access model the claim asks to be documented: any staff phone with a browser and a user account reaches the POS, and the Role / Role Profile / User Permission / Permission Level model is fully documented on the page cited here, with optional two-factor authentication (frappe/twofactor.py, 16 matching lines; docs.frappe.io/erpnext/setup-two-factor-authentication) layered on top. POSITIVE CONTROL: /\bpermission\b/ resolves across the whole framework and the docs census carries a dedicated permissions page plus perm-level troubleshooting pages, so a BYOD section would sit in that neighbourhood if it existed. Documented permission model: yes. BYOD-specific security model: absent. Grade moves F to B on the cited permissions documentation. source |
| hardware-callerid-integration | partial / F - Frappe's Telephony module integrates Twilio and Exotel and pops an incoming-call notification linked | downgrade-to-partial | Searched the telephony vocabulary over the code census and the docs census: /\btelephony\b/i, /\btwilio\b/i, /\bexotel\b/i, /\bcaller.?id\b/i, /\bincoming call\b/i, /\bscreen pop\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: the integration is real and first-party documented -- three docs pages (erpnext/exotel_integration, erpnext/notifications, erpnext/erpnext_integration) describe an inbound-call webhook (handle_incoming_call / handle_end_call / handle_missed_call) that pops the matching Lead or Customer record to the employee, quoted here. What is absent is the POS half of the claim: zero hits tie any call popup to the point_of_sale page -- the popup is a desk-wide dialog, the POS page (erpnext/selling/page/point_of_sale/*) contains no call listener, and nothing pre-populates an order from a call. POSITIVE CONTROL: the POS page DOES subscribe to realtime events where it needs to (pos_payment.js listens for process_phone_payment), so a call-pop subscription would be visible in that directory if it existed. Partial stands; grade moves F to B on the cited integration page. source |
| reliability-sync-conflict-handling | partial / F - Frappe enforces optimistic concurrency on the document modified timestamp and prompts the second wri | downgrade-to-partial | Searched the concurrency vocabulary over the code census: /TimestampMismatchError/, /has been modified after you have opened it/, /\boptimistic\b/i, /\blast.write.wins\b/i, /\bmerge conflict\b/i, /\bCRDT\b/i, /\bvector clock\b/i. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: the mechanism is real and lives in the artefact cited here -- frappe/model/document.py compares the stored `modified` timestamp against the one the client opened and raises frappe.TimestampMismatchError, telling the second writer to refresh. That is optimistic concurrency with an operator prompt, it is exercised by tests in ten files including test_pos_invoice.py, and it is described in the public API docs (framework/user/en/api/document). What is absent is the thing the claim actually asks for: zero word-boundary hits for last-write-wins, merge, CRDT or vector clock as a documented partition policy, and no network-partition policy can exist because there is no offline sync at all (zero service-worker and zero store-and-forward hits in either repository; the POS controller does a frappe.call to check_opening_entry() before it renders). POSITIVE CONTROL: /\bdocstatus\b/ and the submit/cancel/amend state machine are fully present in the same file, proving the search reaches frappe's document-lifecycle layer. Partial stands -- single-server optimistic concurrency is documented, a partition policy is not; grade moves F to A on the primary source. source |
| reliability-public-status-page | unknown / F - status.frappe.io failed TLS validation (cert covers *.frappe.cloud only) and no alternate status hos | resolve-to-no | The prior rationale recorded unknown because status.frappe.io failed TLS validation. Re-probed today and widened the search rather than accepting the refusal. Probed, all fetched 2026-09-06: status.frappe.io (DNS/TLS unreachable, status 0 -- a refusal, not an absence), status.frappecloud.com (unreachable), frappecloud.com/status (401), frappe.io/status (404), frappecloud.statuspage.io (200 but it is Atlassian's own Statuspage marketing site, i.e. no such tenant), and frappe.statuspage.io -- which IS Frappe's Statuspage tenant, titled "Frappe Status", and which answers with the sentence quoted here. That is not a wall in front of a page that exists publicly; it is the vendor's own status host stating the page is inactive and team-members-only. Cross-checked the documentation: docs.frappe.io/cloud/reliability describes continuous monitoring, incident tracking and 24x7 incident response, and docs.frappe.io/cloud/getting-started/uptime publishes per-provider uptime guarantees -- and NEITHER links a public status page; the uptime page instead says users are notified of downtime by email. POSITIVE CONTROL: the same Statuspage host returns a rendered, publicly readable page for tenants that are active, so a live Frappe status page would have rendered. No public, per-component, login-free status page exists. Moving unknown to no. source |
| reliability-pci-dss-4-attestation | unknown / F - No PCI DSS 4.0/4.0.1 AoC or P2PE listing located. Frappe's architecture keeps card data out of the a | resolve-to-no | The prior rationale recorded unknown because no AoC was located. An absence is not evidence, so I went to the vendor pages that ENUMERATE its compliance posture and treated the enumeration as closed. Two of them, both fetched today: the certifications page quoted here, and the "Compliance & Certifications" section of docs.frappe.io/cloud/faq/architecture-and-security ("Yes, we are certified under ISO 9001:2015, ISO 27001:2022, and SOC-2 Type-2 standards."). Both list exactly ISO 9001:2015, ISO 27001:2022 and SOC-2 Type-2, with dates, a certifying body (ISOQAR), a Statement of Applicability version and date, a Dec 2025 surveillance audit and an ISMS scope -- and neither names PCI DSS at any version, a validated P2PE listing, an AoC, or an SAQ type. Corpus: code census of erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false for both; docs census of 1,863 pages of docs.frappe.io (erpnext 708 + framework 836 + cloud 160 + hr 147 + legal 12) for the erpnext and framework spaces. An absence is bounded to those two repositories at those tags and to those two documentation spaces -- marketplace apps (URY / POSNext / GETPOS) and the hr/crm/cloud doc spaces are outside it unless named. INVARIANCE: zero word-boundary hits for /\bPCI\b/i, /\bP2PE\b/i, /\bAoC\b/i or /\bSAQ\b/i in erpnext v16.34.1, in frappe v16.33.0, or on any of the 1,863 docs pages. POSITIVE CONTROL: the same security FAQ answers compliance questions negatively when the answer is no ("Is there a WAF protecting applications?" -- "No, but a server level firewall is available"; "Is there automated failover for databases?" -- "No"), so this publisher does not omit inconvenient answers. Frappe's architecture keeps card data out of the application, but the vendor publishes no PCI DSS 4.0/4.0.1 attestation and no P2PE listing. Moving unknown to no. source |
| delivery-dispatch-board | no / F - Delivery Trip is a form with a stop table, not a live dispatch board with driver availability and el | downgrade-to-no | Searched the vendor's words: 'Delivery Trip', 'Delivery Stop', 'Driver', dispatch board, expo screen, driver availability, elapsed time. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'dispatch board', 'expo screen', word-anchored 'expo', 'driver availability'. Delivery Trip IS a real document -- it batches 2+ stops onto one driver, so the multi-order run in the claim genuinely exists -- but its only progress signal is a five-value read-only Select, and Driver's own status enum is Active/Suspended/Left, so nothing in the model expresses undispatched-vs-assigned, driver availability, or an elapsed timer. Positive control: 'Delivery Trip' 21 files, 'optimize_route' 2 files -- the search finds the feature that is there. source |
| delivery-driver-tracking | no / F - No driver mobile app emitting live GPS back to dispatch." | downgrade-to-no | Searched: 'Driver', GPS, current_location, live location, watchPosition, navigator.geolocation, driver location. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: the Driver doctype's field list carries identity, licence and contact only -- no position, no last-seen, no heartbeat -- and Delivery Stop's lat/lng are hidden Google-Maps geocodes of the STOP address, not the driver. Word-anchored 'GPS' returns two hits, both the name of a sponsor company (Startrack GPS, Guatemala) in sponsors.md and a v6 changelog -- a name trap, not a feature. 'current_location' returns nine hits, all in asset_movement.py (fixed asset locations). navigator.geolocation appears twice: leaflet's bundled library and a one-shot getCurrentPosition that centres the generic Geolocation map field; watchPosition appears once, inside leaflet. Positive control: 'Delivery Trip' 21 files and Driver resolves to a real doctype. source |
| delivery-zones-polygon | no / F - Territory is a hierarchical label, not a geographic polygon or isochrone." | downgrade-to-no | Searched the vendor's words: 'Territory', 'delivery zone', polygon, isochrone, geofence. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'delivery zone', 'delivery_zone', isochrone, geofence in either repository and zero non-base64 lines for any of them across the 1,863-page docs census. Territory -- the only area concept ERPNext has -- is a nested-set label (lft/rgt/parent_territory) carrying no geometry at all. Adversarial check that survived: 'polygon' DOES hit 9 files, and frappe ships a Geolocation fieldtype backed by leaflet-draw that stores drawn GeoJSON polygons; but no delivery-facing doctype uses it, and the only ERPNext consumer is assets/doctype/location (land area). The primitive exists and the delivery zone does not. Positive control: Territory resolves to a real doctype used by Pricing Rule and Loyalty Program. source |
| delivery-zone-pricing | no / F - Pricing Rule can vary charges by Territory, but Territory is not derived from a validated address an | downgrade-to-no | Searched: 'Territory', 'Pricing Rule', 'delivery fee', 'delivery_charge', 'order minimum', 'promise time'. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'delivery fee', 'delivery_charge', 'order minimum', 'promise time' in either repository. Pricing Rule can indeed vary a charge by Territory (applicable_for includes Territory), so the fee half is half-buildable -- but the Territory record that would carry the fee, the minimum and the promise time holds none of the three, and nothing derives a Territory from an address. The POS screen compounds this: its Contact Details panel exposes exactly email_id, mobile_no, loyalty_program and loyalty_points, so a delivery address is never captured at the till to derive a zone from. Positive control: Pricing Rule's applicable_for enum is present and does list Territory. source |
| delivery-address-validation | no / F - Address is a free-text doctype; no geocoding gate at order time." | upgrade-to-partial | CORRECTION -- the uncited `no` is too strong. Searched: 'Address', geocode, autocomplete, 'Geolocation Settings'. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What is there: frappe v16.33.0 ships a Geolocation Settings single doctype with enable_address_autocompletion and a provider enum of Geoapify / Nomatim / HERE; providers/geoapify.py calls https://api.geoapify.com/v1/geocode/autocomplete and returns normalised address_line1/city/state/pincode/country into a 'New Address' dialog. So address entry CAN be geocoded against a mapping service. What is not there: it is off by default (enable_address_autocompletion default 0); it fires only from the desk Contact & Address sidebar (address_and_contact.js gated on frappe.boot.enable_address_autocompletion), never from the POS -- 'address' returns zero hits across all nine files of erpnext/selling/page/point_of_sale/ while 'customer' returns 121 in pos_item_cart.js alone, which is the positive control; the returned payload discards lat/lng; and with zero 'delivery zone' anywhere there is nothing out-of-zone to reject against. Half the claim is met, the operative gate is absent. source |
| delivery-cash-reconcile | no / F - POS Closing Entry reconciles a cashier drawer, not a driver bank." | downgrade-to-no | Searched the vendor's words: 'POS Closing Entry', 'POS Opening Entry', 'Payment Reconciliation', driver bank, driver cash, driver pay, tip-out. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'driver bank', 'driver cash', 'driver pay' or 'tip.?out' in either repository. POS Closing Entry is the only settle-up document in the product and its accountable-party field is literally labelled Cashier and linked to User -- there is no Driver link anywhere on it, no cash-collected-per-driver line, and Delivery Trip carries no money field beyond a read-only grand_total copied onto each stop. Positive control: POS Closing Entry and its payment_reconciliation child table are present and found by the same search. source |
| delivery-3p-direct-integration | no / F - No DoorDash, Uber Eats or Grubhub connector ships in ERPNext core or in any frappe/* repository, and | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The vendor's own integrations index does not name a food-delivery marketplace either: its 'Ready-Made Marketplace Options' list is Ecommerce Integrations, WooCommerce Connector, ERPNext Shipping and Frappe Paystack, and its advice for anything else is to build a custom connector against the REST API. Shipped integration surface, enumerated: frappe/integrations/doctype/ holds connected_app, geolocation_settings, google_calendar, google_contacts, google_settings, integration_request, ldap_*, oauth_*, push_notification_settings, slack_webhook_url, social_login_key, token_cache and webhook*; erpnext/erpnext_integrations/doctype/ holds plaid_settings alone. Core absence is not product absence -- the Frappe Cloud marketplace was not censused. source |
| delivery-3p-injection | no / F - No marketplace connectors. The REST write API would let an integrator build one, but nothing ships." | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The record a marketplace ticket would land in is POS Invoice, and its field list carries no channel, no marketplace, no external order id and no accept/reject state; the vendor's integration guide confirms the intended route is the generic REST API plus a hand-added custom field, naming marketplace_order_id on Sales Order as an EXAMPLE of a field the operator must add themselves. So an integrator can build injection; nothing ships that does it. Positive control: the same docs census finds 'Loyalty Program' on 6 pages and 'Point of Sale' on 7. source |
| delivery-menu-push | no / F - There are no marketplace integrations in core, so there is no channel to publish the Item master and | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Searched additionally for a publish/push direction: zero hits for the marketplace names means there is no channel to publish an Item master or Item Price row to, and the vendor's own e-commerce integration page describes catalog sync as something the OPERATOR builds -- it is listed under Common Integration Flows for a connector you write, not as a shipped feature. No channel-specific price markup concept exists either: Item Price is scoped by Price List and Pricing Rule by Territory/Customer Group, neither of which is a marketplace. source |
| delivery-86-sync | no / F - No marketplace connectors exist, so an out-of-stock item has nowhere to propagate to beyond the POS | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Controls over the 86-ing vocabulary in the vendor's own words: ERPNext expresses availability as Warehouse stock balance plus POS Profile's hide_unavailable_items flag -- there is no item-level or item-option-level out-of-stock state that can be pushed anywhere, and with zero marketplace names in either repository there is no channel to push it to. The vendor's own page frames inventory sync as connector work. Positive control: hide_unavailable_items is present in the POS Profile field list, so the availability concept itself is found by the search. source |
| delivery-store-pause | no / F - No marketplace connectors exist, so there is no store-level pause with a duration or reason to send | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The nearest shipped concept is POS Profile's disabled checkbox, which switches a till profile off outright -- no duration, no reason code, no auto-reactivation, and no channel to send it to. Zero hits for 'store pause', and zero for any marketplace name, in either repository. Positive control: the POS Profile field_order is found in full by the same search, so a pause field would have been seen if present. source |
| delivery-3p-reconciliation | no / F - No marketplace connectors and no commission or payout ledger exist. Third-party payouts would be han | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Additional controls over the reconciliation vocabulary: zero hits for a commission or payout ledger tied to a channel; POS Invoice's own totals block carries taxes, discounts, loyalty and change amounts but no commission, marketing-fee or payout field, and no doctype anywhere represents an expected-versus-deposited marketplace settlement. A 3P payout would land as an ordinary Payment Entry or Journal Entry with no order-level match. Positive control: 'Payment Reconciliation' and 'Bank Reconciliation' both resolve to real ERPNext doctypes in the same search -- the reconciliation vocabulary is present, just never marketplace-aware; the quoted line is the one third-party-ish Link POS Invoice does carry, a coupon, which is the nearest thing to a channel field and is not one. source |
| delivery-injection-error-visibility | no / F - Frappe does expose an Error Log and Webhook Request Log, but there are no channels whose health to r | downgrade-to-no | Absence control over the marketplaces' own names, word-anchored, case-insensitive: DoorDash, Uber Eats, UberEats, Grubhub, Deliveroo, Deliverect, Chowly, ItsaCheckmate, Postmates, Zomato, Swiggy, Talabat, Just Eat, Menulog, Glovo, Wolt -- every one returns files=0 lines=0 in both repositories, and every one returns zero non-base64 lines across the 1,863-page docs census. Positive controls in the same run: 'Delivery Trip' 21 files, 'Google Maps' 3 files, 'POS Profile' 41 files, 'Loyalty Program' 23 files -- the same search finds the vendor's real vocabulary. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The health-reporting primitives genuinely exist and the search finds them -- frappe ships Error Log, Integration Request, Webhook Request Log and Notification -- which is the positive control. What is absent is the subject: with zero marketplace names in either repository there is no per-channel connection status, no failed-injection queue and no channel alert, because there is no channel. This is a negative about the object of the reporting, not about the reporting machinery. The quoted field is POS Invoice's only status enum, which tracks accounting state (Draft/Return/Paid/Consolidated) and carries no injection or delivery-channel outcome. source |
| delivery-promise-time | no / F - Delivery Trip ETAs come from Google Maps drive time only — no kitchen load or driver-availability in | downgrade-to-no | Searched the vendor's words: 'Delivery Trip', 'Calculate Estimated Arrival Times', 'Google Maps', 'promise time', kitchen load. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'promise time' in either repository, and word-anchored 'kitchen' resolves to exactly two files, both chart-of-accounts templates carrying a GL account named Kitchen (Singapore F&B and UAE) -- there is no kitchen-load concept to feed an ETA. Delivery Trip's ETA button is documented in the doctype itself as a Google Maps Direction API call, and delivery_trip.py's get_directions/process_route pass only the stop addresses and a departure_time; no driver-availability or queue-depth term enters the calculation. Positive control: 'Google Maps' 3 files, all in the Delivery Trip implementation -- the ETA feature that IS there is found. source |
| delivery-offline-behavior | no / F - No offline mode exists anywhere in the product, so no delivery offline behavior is documented." | downgrade-to-no | ATTACK 1 plus the docs-bound defect. A 'vendor documents X' claim was cited to pos_settings.json at grade A; a doctype JSON cannot establish what the vendor's documentation says. Re-ran the offline census over the full 1,863-page corpus rather than the 1,544-page erpnext+framework subset the row named (one additional page, still no POS matrix), moved the citation to the vendor page that would carry the statement, and dropped A to B. source |
| guest-loyalty-thirdparty-identity-attach | no / F - No marketplace integrations." | downgrade-to-no | ATTACK 2. The row cited pos_item_cart.js -- the file it names as its own positive control for a PRESENCE -- as grade-A evidence for an absence. Repointed the citation at POS Invoice's field list, where the missing channel/external-identity field would actually have to live, and dropped A to B because the operative evidence remains a corpus-wide zero over sixteen marketplace names rather than anything a single file contains. source |
| guest-loyalty-offline-behavior | no / F - There is no offline mode in the product, so no queue-and-reconcile behavior is defined or documented | downgrade-to-no | ATTACK 1. Publication claim cited to pos_settings.json at grade A. Moved to the vendor documentation page and re-bounded to the real 1,863-page docs census; grade A to B. source |
| guest-loyalty-targeted-offers | no / F - Pricing Rules target Customer, Customer Group and Territory — static attributes, not recency/frequen | downgrade-to-no | Searched the vendor's words: 'Pricing Rule', 'Promotional Scheme', 'Coupon Code', 'Customer Group', 'Territory', applicable_for, and the audience vocabulary recency / frequency / RFM / lapsed / win-back / segment. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'win-back'; word-anchored RFM and recency resolve only to list-view sort relevance in frappe/search/sqlite_search.py and list_view_settings -- a reader trap, not an audience engine. Pricing Rule's applicable_for enum is Customer / Customer Group / Territory / Sales Partner / Campaign / Supplier / Supplier Group: all static attributes. The one thing that looks dynamic is the Advanced Settings condition field (fieldtype Code, options PythonExpression) -- but utils.py evaluates it as frappe.safe_eval(pricing_rule.condition, None, doc.as_dict()), whose entire namespace is the current document's own fields, so no purchase history is reachable. The is_cumulative path does query history, and I checked it adversarially: get_qty_amount_data_for_cumulative filters on date window, warehouse and item only -- there is no customer clause at all, so it aggregates every customer's transactions, not this guest's. source |
| guest-loyalty-lifecycle-automation | no / F - Frappe's Notification doctype can send scheduled or event-triggered email/SMS on any doctype, so a b | downgrade-to-no | Searched the vendor's words: 'Campaign', 'Email Campaign', 'Campaign Email Schedule', 'Newsletter', 'Email Group', 'Notification', 'Auto Repeat', plus birthday / anniversary / lapsed / win-back / drip campaign. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What the uncited rationale missed: ERPNext DOES ship a drip engine -- Campaign holds a campaign_schedules child table of Campaign Email Schedule rows, each just send_after_days plus an Email Template, driven by Email Campaign. It fails the claim on both halves. (1) It is not triggered: Email Campaign is one record per recipient with a manually set start_date and a status of Scheduled/In Progress/Completed/Unsubscribed -- precisely the 'one-off manual send' the claim excludes -- and its email_campaign_for enum is Lead / Contact / Email Group, none of which is Customer. (2) A birthday trigger has no source field to fire from: word-anchored date_of_birth exists on Employee only, and the three 'birthday' hits in the corpus are two deprecation-dumpster docstrings and a Font Awesome CSS blob. Positive control: 'Email Campaign' 10 files, 'Auto Repeat' 46 files -- the automation vocabulary is found where it exists. source |
| guest-loyalty-10dlc-registration | no / F - No A2P 10DLC handling or documentation; SMS is BYO-gateway, so registration is entirely the operator | downgrade-to-no | Searched 10DLC, A2P, brand registration, campaign registration and sender ID over both repositories and the 1,863-page docs census. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for '10DLC' anywhere, in code or docs. Adversarial check on my own control: case-insensitive 'A2P' returns one file with seven lines -- frappe/tests/data/email_with_image.txt, where the letters occur inside base64 blobs; that is a reader artefact, not a finding. The artefact that would carry any of this is SMS Settings, whose entire field list is a gateway URL, a message parameter name, a receiver parameter name, a static-parameter table, a POST flag and an allowed-roles table: BYO HTTP gateway with no brand, campaign, sender-id or consent registration surface at all, so 10DLC registration is wholly the operator's problem and is nowhere documented. Positive control: SMS Settings and SMS Log both resolve to real frappe doctypes. source |
| guest-loyalty-campaign-attribution | no / F - Coupon Code tracks a used-count, and a Campaign doctype links to Lead/Opportunity in CRM, but there | upgrade-to-partial | CORRECTION -- the uncited `no` understates the data model. Searched: 'Coupon Code', 'Campaign', 'UTM Campaign', utm_campaign, campaign_efficiency. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. What is actually there: POS Invoice carries BOTH a coupon_code Link to Coupon Code AND a utm_campaign Link to UTM Campaign, and POS Profile carries utm_source/utm_medium/utm_campaign so every ticket rung on a till inherits a campaign tag; pos_payment.js binds a coupon_code change event on POS Invoice, so a redemption really is written onto the check that carries the grand_total. Redemption-to-check-total attribution is therefore reportable through Report Builder out of the box. What keeps this below yes: no shipped report does it -- the one campaign report, crm/report/campaign_efficiency, walks Lead to Opportunity to Quotation to Sales Order and never touches an invoice -- and nothing measures INCREMENTAL sales (no holdout, no control group, no baseline). Coupon Code's used counter is a global tally; the vendor's own coupon page states that Maximum Use caps overall use, with no per-customer limit. source |
| guest-loyalty-review-capture-routing | no / F - No review request, star-rating capture or routing feature exists in ERPNext or Frappe HR. The Notifi | downgrade-to-no | ATTACK 2. The cited URL is the file the note itself nominates as its positive control -- evidence that adjacent machinery is PRESENT. A file demonstrating a presence cannot be grade-A primary evidence for an absence somewhere else. Kept the citation, since it is the honest thing to point at, but relabelled it as the control and dropped A to B. source |
| guest-loyalty-stored-value-gift | no / F - No stored-value or gift card product." | downgrade-to-no | Searched the vendor's words: 'Coupon Code', 'Gift Card', 'Loyalty Program', 'Loyalty Point Entry', stored value, store credit, gift_card. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. The adversarial finding: ERPNext DOES have something called a Gift Card and it is not stored value. Coupon Code's coupon_type enum is literally Promotional / Gift Card, so a careless reader could score this yes. Its field list is coupon_name, coupon_type, customer, coupon_code, pricing_rule, valid_from, valid_upto, maximum_use, used, description -- a code that fires a Pricing Rule discount, with no balance, no amount, no currency and no ledger. Frappe's own documentation says so outright: at https://docs.frappe.io/erpnext/coupon-code the question 'Is a Gift Card Coupon Code a stored-value payment instrument?' is answered 'No. In this feature it is a generated code linked to a Pricing Rule, not a financial wallet.' Zero hits for 'store credit' or 'gift_card'. Positive control: Loyalty Point Entry, a real balance-bearing ledger with loyalty_points and expiry_date, is found by the same search -- so a stored-value ledger would have been too. source |
| commercial-pci-p2pe-tokenization | no / F - No P2PE, no tokenization vault, and no stated merchant SAQ type. Card acceptance is entirely the ope | downgrade-to-no | Searched PCI, PCI DSS, P2PE, SAQ, tokenization, cardholder, card number and EMV across three bounded corpora: (1) Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. (2) the 1,863-page docs census; (3) the twelve-page legal space at docs.frappe.io/legal, fetched today, all twelve returning 200. Invariance: zero occurrences of PCI, P2PE or SAQ in any of the three. Two of my own controls carried traps and I discarded them: case-insensitive 'tokeniz' returns 7 files that are entirely babel jslexer and SQLite FTS5 tokenizer configuration, and SAQ/VPAT/A2P in the repositories and PCI/P2PE in the docs are all substrings inside base64 image data-URIs. The artefact that would carry a PCI position is the Frappe Cloud Service and Support Agreement's own Security Standards clause, effective 1 April 2026, and it names ISO 27001 and nothing else; frappe.io/security returns 200 today but is a vulnerability-disclosure page with zero occurrences of PCI, P2PE, SAQ, SOC 2 or ISO 27001. Card acceptance is not modelled at all: Mode of Payment's type enum is Cash/Bank/General/Phone. source |
| commercial-wcag-kiosk-accessibility | no / F - No VPAT/ACR published, and no kiosk product to certify." | downgrade-to-no | Searched WCAG, VPAT, 'accessibility conformance', ACR and kiosk across four bounded corpora: (1) Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. -- word-anchored kiosk returns files=0 lines=0; (2) the 1,863-page docs census -- zero non-base64 lines for WCAG, VPAT or kiosk (the raw WCAG/VPAT hits are base64 image blobs on erpnext/sales-return and erpnext/deleting-all-transactions-for-the-company, a reader artefact I discarded); (3) the twelve-page docs.frappe.io/legal space fetched today, zero; (4) frappe.io/accessibility, which returns 404 today while frappe.io/security returns 200, so the absence is of the document, not of the site. The kiosk half is settled positively by the vendor's own product introduction, quoted here: ERPNext's POS is described as staffed retail transaction handling with inventory, payment methods, loyalty and reporting -- there is no self-order kiosk in the two repositories to certify. Positive control: the same docs census finds 'Point of Sale' on 7 pages and 'Loyalty Program' on 6. source |
| commercial-dual-pricing-compliant | no / F - No dual pricing, cash discount, or surcharging engine, and no card-brand or BIN data in the system t | downgrade-to-no | Searched the vendor's words: 'Mode of Payment', 'Sales Taxes and Charges', 'Pricing Rule', plus surcharge, cash discount, dual pricing, cardholder, card number, BIN, debit and prepaid. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false. The finding is an absence of these strings in those two repositories at those two tags, not a claim about the wider Frappe ecosystem or the Frappe Cloud marketplace, which was not censused. Invariance: zero hits for 'cash discount', 'dual pricing', 'cardholder', 'card number' and, in the repositories, 'surcharg'. Two controls of mine carried traps: word-anchored BIN returns 101 files, all /bin/ paths under case-insensitive matching; and 'surcharg' DOES return 3 docs pages, but every one is Indian tax-template vocabulary ('a surcharge, cess, or levy calculated only on another tax or charge amount' on erpnext/tax-on-another-tax-amount), not card surcharging. The dispositive artefact is Mode of Payment: its whole type enum is Cash/Bank/General/Phone, so the system holds no card brand, no debit/credit flag and no BIN, and cannot mechanically exclude debit and prepaid from a surcharge even if one were configured as a tax row. No receipt or menu-board fee-disclosure feature exists. Positive control: Sales Taxes and Charges Template and Pricing Rule are both found by the same search. source |
| delivery-driver-roster | partial / F - ERPNext core has Driver and Vehicle doctypes and a Delivery Trip document with per-trip status, so d | downgrade-to-partial | Searched the vendor's words: 'Driver', 'Vehicle', 'Delivery Trip', clock-in, dispatch state. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial, and pins the exact shortfall. First-class entities: Driver is its own doctype (naming series HR-DRI-, linked to Employee, Vehicle and Address) and Delivery Trip is a submittable document with a driver link and a status, so per-driver run history is reportable straight out of the Delivery Trip list. The claimed dispatch state machine is absent and the quoted field is why: Driver's only status enum is Active / Suspended / Left -- an employment state, not in-store / on-run / returning. Clock-in is absent from the POS specifically: 'address' and 'clock' both return zero hits across all nine files of erpnext/selling/page/point_of_sale/, and I checked my own control -- 'shift' does return three hits and every one is a keyboard modifier (Shift+Ctrl+C, shift+ctrl+backspace, oEvent.shiftKey), a reader trap, not a work shift. Positive control: 'customer' returns 121 hits in pos_item_cart.js alone. Attendance lives in Frappe HR, a separate app outside this census. source |
| delivery-tracking-page | unknown / F - The Delivery Trip documentation makes no mention of customer notification by email or SMS. It docume | resolve-to-no | CORRECTION to an `unknown` that rested on 'an unverified notification feature' -- the notification feature is now verified, and it is not a tracking page. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. What exists, read line by line: delivery_trip.py's whitelisted notify_customers() loops the delivery_stops, looks up each stop's Contact, renders the Email Template named in Delivery Settings.dispatch_template against a context that really does include the Driver's cell_number and the stop's estimated_arrival, sends it with the Delivery Note print format attached, then stamps stop.email_sent_to and delivery_trip.email_notification_sent. So a guest dispatch email driven by real order and driver state does ship. What the claim asks for and is absent: it is email only -- there is no SMS path (SMS Settings is never referenced from the Delivery Trip module); it is a one-shot manual button, not a live page; there is no route, no web page and no portal template anywhere for order or driver status, on the restaurant's domain or any other. Positive control: the same search finds Delivery Settings' dispatch_template and send_with_attachment fields, so a tracking-page setting would have been found beside them. source |
| guest-loyalty-native-email-sms | partial / F - Newsletter/Email Group sends bulk email natively, and SMS Settings supports a generic HTTP SMS gatew | downgrade-to-partial | CORRECTION to the rationale, not to the value. The uncited partial rests on 'Newsletter/Email Group sends bulk email natively' -- but Newsletter has LEFT the framework at v16. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. The quoted v16 patch prints a deprecation warning naming Newsletter as moving to a separate app at github.com/frappe/newsletter, and the census confirms it: frappe/email/doctype/ at v16.33.0 contains email_group, email_group_member, email_queue, email_template, email_unsubscribe and notification, and no newsletter directory at all; the 14 remaining word-anchored 'Newsletter' files are documentation, changelogs, a v13 patch, an erpnext help link and a stray erpnext/public/js/newsletter.js. What still sends natively in core: ERPNext's Email Campaign drives a Campaign's campaign_schedules (Campaign Email Schedule = send_after_days + Email Template) at a Lead, Contact or Email Group, and frappe's SMS Settings posts to a BYO HTTP gateway. Both channels are therefore native, and both are framework primitives -- no campaign builder, no template library, no send analytics -- so partial holds. source |
| guest-loyalty-consent-management | partial / F - Newsletter subscription carries an unsubscribe flag and Email Unsubscribe records the event. No per- | downgrade-to-partial | Searched the vendor's words: 'Email Group', 'Email Group Member', 'Email Unsubscribe', 'SMS Settings', consent, opt-in, source of consent. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial and sharpens both halves. Revocation is real and is honoured by more than a STOP keyword: Email Group Member carries an unsubscribed flag, and Email Unsubscribe records email + reference_doctype + reference_name + global_unsubscribe, so an opt-out can be recorded per document or globally and is applied by the email queue. Capture is what fails, and the quoted field list is the whole of it -- three fields: email_group, email, unsubscribed. There is no consent timestamp field, no source-of-consent field and no channel dimension, and SMS consent is not modelled at all (SMS Settings holds a gateway URL and parameter names only). Note also that the subscribe flow the old rationale leaned on has left core with Newsletter at v16. Positive control: Email Unsubscribe and Email Group Member are both found by the same search, so a consent_source field would have been. source |
| guest-loyalty-privacy-rights-tooling | partial / F - Frappe Framework ships Personal Data Download Request and Personal Data Deletion Request doctypes fo | downgrade-to-partial | CORRECTION to both halves of the rationale, value unchanged. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. First: a DPA IS published -- Frappe Cloud terms 6.7 offers one for digital execution and docs.frappe.io/legal/data-protection/data-process-addendum-sample serves a downloadable sample copy, so 'no published DPA was located' was a retrieval gap. Second, and more important: deletion propagation is not merely undocumented, it is documented and it EXCLUDES the guest. Personal Data Deletion Request does not walk the database; it walks the user_data_fields hook, redacting only the doctypes each app registers. frappe/hooks.py registers Access Log, Activity Log, Comment, Contact, Contact Email and Address. ERPNext's entire registration is the quoted six lines: Lead and Opportunity. Customer, Sales Invoice, POS Invoice and Loyalty Point Entry appear nowhere in it, so an erasure request leaves the guest's Customer record and their whole loyalty ledger standing. In-app access and erasure workflows exist; they do not reach the loyalty and transaction records this claim is about. source |
| guest-loyalty-redemption-fraud-controls | partial / F - Role Permission Manager can restrict who may create or amend Loyalty Point Entry, and the Version lo | downgrade-to-partial | Searched the vendor's words: 'Loyalty Point Entry', 'Role Permission Manager', 'Version', velocity, approval, self-redemption. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Confirms partial. Present: every points movement is a Loyalty Point Entry row, and frappe's Version doctype attributes every change, so an audit log genuinely exists; Role Permissions can gate who creates or amends one. Absent, and the quoted field list is the evidence -- twelve fields, of which discretionary_reason is a free-text note with no approver, no approval state and no workflow: there is no manager-approval gate on a manual adjustment, no velocity or rate limit anywhere, and no employee self-redemption flag (Loyalty Point Entry links customer and invoice but never the User who rang it, so a self-redemption cannot be detected from the row). The vendor's own coupon page adds that the sibling redemption cap is global, not per guest: 'Maximum Use caps overall use.' Positive control: 'Loyalty Program' 23 files, and pos_payment.js carries 31 loyalty references, so a velocity or approval field would have been found. source |
| commercial-no-early-termination-fee | partial / F - No ETF can apply to a month-to-month hosting subscription or to self-hosted GPL software, so the pra | upgrade-to-yes | CORRECTION -- the affirmative contractual statement the rationale said was missing exists and is public. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the retrieved legal corpus for termination, early termination, liquidated damages, penalty, notice -- and both loaded phrases DO occur, so I read every hit rather than reporting a zero. 'liquidated damages' occurs twice (Frappe Cloud terms 12, Enterprise 10.3) and both run toward the customer: they are the remedy Frappe may owe if its liability cap is unenforceable. 'early termination' occurs once, Enterprise 7.3(b), and it is the label on a REFUND: 7.3(a) provides that if the customer prepaid and terminates before the prepaid term ends, other than for its own breach, 'Frappe shall refund to the Customer the unused portion of such prepaid fees on a pro-rata basis', and 13.4 repeats it. So the contracts pay money out on early termination rather than charging for it. The quoted Cloud clause covers the self-serve product and is the opposite of an ETF: terminate without cause, no prior written notice, by discontinuing payment, effective at the end of the then-current billing period. The one countervailing term is Cloud 8.4.2, unused prepaid credits non-refundable -- a forfeiture of money already paid, not a charge for leaving. Self-hosted GPL-3.0 use has no subscription to cancel. source |
| commercial-autorenew-terms-published | unknown / F - Auto-renewal and cancellation-notice terms were not located; the Frappe Cloud ToS/MSA was not retrie | resolve-to-partial | CORRECTION to an `unknown` -- the ToS/MSA was retrievable. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. The answer splits by product, which is why this is partial rather than yes or no. For self-serve Frappe Cloud the cancellation side IS publicly stated: Frappe Cloud terms 10.1.3 says the customer may terminate without cause with no prior written notice, effective at the end of the then-current billing period -- a stated notice window of zero on a billing-period cadence. For Enterprise, the quoted clause does exactly what the claim excludes: it relegates 'Renewal terms, price adjustments, or notice periods' to the Enterprise Order Form, the signed quote, and section 8.3 makes that Order Form prevail on commercial terms. Neither published agreement states an auto-renewal term length. Positive control: searching the same corpus for 'renew' returns hits only in this agreement, at 8.2, 9.3, 15.10, 15.14 and 15.19 -- the word is found where it exists. source |
| commercial-rate-increase-clause | unknown / F - No processing agreement exists. Frappe Cloud hosting price-change terms were not located in the publ | resolve-to-no | CORRECTION to an `unknown` -- the price-change terms were located. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the twelve-page legal corpus for price, pricing, rate, increase, interchange, pass-through. Invariance: zero occurrences of 'increase' in any of the twelve pages, and zero of 'interchange' -- there is no cap, no ceiling, no penalty-free exit tied to a price change, and no processing agreement at all, since Frappe is not the merchant's card processor (Mode of Payment's type enum in the product is Cash/Bank/General/Phone, with no acquirer relationship anywhere). What the published terms do say is the quoted clause: an unqualified unilateral right to modify pricing at sole discretion. The Enterprise Support Agreement 9.4 adds the only limit that exists -- price changes do not affect fees under an active Order Form during its current term, but 'Renewals and new Order Forms shall be subject to the revised pricing.' The mitigation is practical rather than contractual: under 10.1.3 a Cloud customer can leave at the end of any billing period, so an increase is escapable even though no clause grants that right on the increase. source |
| commercial-post-termination-export-window | unknown / F - Frappe Cloud's post-termination data retention window is not stated on any page retrieved. Moot for | resolve-to-partial | The row explicitly deferred its self-serve half to 'plan documentation in the Cloud doc space, which is outside the census I ran' -- an admitted hole left standing inside a live claim note. That space is 160 pages of the docs.frappe.io sitemap and was reachable; I censused it. The value does not change, but an unresolved deferral has been replaced with the actual finding, and the note now names clause 6.9 and the drop-site behaviour instead of gesturing at an uncensused space. source |
| commercial-data-ownership-clause | unknown / F - Frappe Cloud's terms of service were not retrieved, so no data-ownership or data-use restriction cla | resolve-to-yes | CORRECTION to an `unknown` -- the terms were retrievable and they answer both halves of the claim affirmatively. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched the retrieved legal corpus for ownership, property, sell, share, disclose, aggregated, de-identified. The quoted clause states merchant ownership outright, and the very next clause supplies the use restriction the claim asks for: '6.4 Confidentiality -- Frappe shall not sell, share, or otherwise disclose Customer Data to third parties, except where required by law or legal process.' That is a stricter constraint than the claim's floor, since it carves out no aggregated or de-identified vendor use at all. Section 9.1.1 reinforces it: the invoice holder 'is deemed the owner of the account and all associated data.' Adversarial check: zero occurrences of 'aggregated' or 'de-identified' in the twelve pages, so no separate clause reopens the vendor-use door; the Privacy Policy governs Frappe's own website visitors, not Customer Data. Positive control: the same search finds the licensing and confidentiality sections in the same document. source |
| commercial-pci-dss-4-controls | unknown / F - MFA is technically enforceable on all logins via Frappe's built-in 2FA, but Frappe publishes no PCI | resolve-to-no | CORRECTION to an `unknown` -- the documents that would carry a PCI position were all retrieved and none does. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. Searched PCI, PCI DSS, 4.0.1, cardholder data environment, CDE, script integrity, 6.4.3, 11.6.1, MFA, two-factor across the two repositories, the 1,863-page docs census and the twelve legal pages. Invariance: zero occurrences of 'PCI DSS' or 'CDE' in any of the three corpora, and zero non-base64 occurrences of 'PCI' in the docs (the six raw docs hits are all base64 image data-URIs, a reader artefact I discarded). The clause that would carry it is quoted here and names ISO 27001 alone; frappe.io/security returns 200 today and contains zero occurrences of PCI, P2PE, SAQ, SOC 2 or ISO 27001, and frappe.io/pci and frappe.io/compliance both 404. The technical half is genuinely available and undocumented: frappe ships built-in 2FA and System Settings can force it on all logins, so MFA is enforceable -- but no document defines a cardholder data environment or takes a Req 6.4.3 / 11.6.1 payment-page script-integrity position. Positive control: the same searches find the security, privacy and data-protection clauses that DO exist. source |
| commercial-privacy-dsar-tooling | partial / F - Frappe Framework ships Personal Data Download Request and Personal Data Deletion Request doctypes pr | downgrade-to-partial | CORRECTION to both clauses of the rationale, value unchanged. Corpus: the two-repository census erpnext v16.34.1 (5,170 files) + frappe v16.33.0 (3,634 files), GitHub tree API truncated:false; where the docs are cited, the 1,863-page bounded census of docs.frappe.io's own sitemap, plus the twelve-page docs.frappe.io/legal space fetched today, all twelve returning 200. Retrieval note that changes several of these cells: the Frappe legal space was NOT walled. All twelve pages listed in docs.frappe.io's sitemap under /legal/ were fetched today as raw markdown via the publisher's documented append-.md affordance and every one returned 200, including the Frappe Cloud Service and Support Agreement (36,045 bytes, effective 1 April 2026), the Enterprise Support Agreement (32,328 bytes, effective 1 January 2026) and a downloadable sample Data Processing Addendum. The earlier 'not retrieved' rationale was a retrieval gap, not an absence. First, the DPA is published, not absent: Frappe Cloud terms 6.7 offers one for digital execution and docs.frappe.io/legal/data-protection/data-process-addendum-sample serves a downloadable sample copy, alongside a named Grievance Officer page and a Frappe Cloud Data Processors list. Second, the in-app tooling is real but narrower than 'an individual guest's records': Personal Data Download Request and Personal Data Deletion Request are shipped doctypes with a verification and approval flow, but they act only on the doctypes registered in the user_data_fields hook. frappe/hooks.py registers Access Log, Activity Log, Comment, Contact, Contact Email and Address; ERPNext's whole registration is the quoted six lines, Lead and Opportunity. Customer, Sales Invoice, POS Invoice and Loyalty Point Entry are absent from it, so locating, exporting and deleting a guest's transaction and loyalty records is not covered by the shipped tooling. Positive control: the deletion machinery itself is found by the same search, including the anonymization_matrix and the Personal Data Deletion Step child table. source |
| labor-photo-punch-verification | no / F - Frappe HR documents geolocation check-in but no photo capture or facial verification at punch." | downgrade-to-no | SCOPE: the record already cites github.com/frappe/hrms as evidence for labor cells, so Frappe HR is in scope; ERPNext's HR module was split out of frappe/erpnext, and an absence in erpnext alone would prove only that the code moved. I therefore censused frappe/hrms@v16.17.1 (current stable v16 tag, released 2026-09-01) as a third corpus: the GitHub tree API answers truncated=false at 1,552 blobs, 1,418 of them text. Searched Frappe HR's own vocabulary -- Employee Checkin (the timecard record), log_type, device_id, fetch_geolocation -- and then the punch-photo vocabulary: zero word-boundary hits for selfie|facial|face recognition|photo capture, zero for camera|getUserMedia anywhere in hrms@v16.17.1 (including its Vue frontend/), and the single \bbiometric\b hit is a Shift Type label, not an image path. INVARIANCE: the Employee Checkin doctype's complete field_order carries a location section (latitude, longitude, fetch_geolocation, geolocation) and no image, photo or Attach Image field of any kind; the only 'Attach Image' fieldtype in the whole app is on Appraisal. POSITIVE CONTROL: 'Employee Checkin' itself resolves to 26 files / 68 lines including shift_type.py and attendance.py, so the search would have found a photo field on the same record had one existed. Bound: this is an absence in frappe/hrms@v16.17.1, frappe/erpnext@v16.34.1 and frappe/frappe@v16.33.0 -- not a statement about Frappe Cloud marketplace HR apps, which were not censused. source |
| labor-realtime-labor-percent | no / F - No shipped report joining live clocked hours to live sales." | downgrade-to-no | Searched the vendor's report vocabulary across erpnext@v16.34.1, frappe@v16.33.0 and hrms@v16.17.1: zero word-boundary hits for 'labour cost'|'labor cost'|'labour percent'|labor_cost anywhere in the three repositories. Enumerated Frappe HR's complete shipped report set (hrms/hr/report + hrms/payroll/report, 29 directories): the only report that joins labour cost to revenue at all is Project Profitability. INVARIANCE: Project Profitability builds its figure by inner-joining Salary Slip Timesheet -> Timesheet -> Sales Invoice Timesheet -> Sales Invoice and filtering on both documents being submitted (docstatus == 1), i.e. it requires a completed payroll run and a Timesheet already billed onto an invoice. That is a period-close professional-services margin report, not a live labour-percent readout: it cannot fire during service, it reads Sales Invoice rather than POS Invoice, and no Dashboard Chart or Number Card ships against it. POSITIVE CONTROL: 'Employee Checkin' (68 lines) and 'Income Tax Slab' (62 lines) both resolve in hrms, and ERPNext's Sales Analytics report resolves in erpnext, so labour and sales reporting artefacts are both visible to this search. Bound to these three repositories at these tags; restaurant apps on the Frappe Cloud marketplace were not censused. source |
| labor-break-compliance-by-state | no / F - Frappe HR's compliance localizations are India- and UAE-centric; no US state break rule library." | downgrade-to-no | TRAP DISARMED FIRST: unanchored 'break' returns 162 files / 708 lines in hrms@v16.17.1 and every one is a Frappe layout fieldname -- column_break, section_break. Anchored, \b(meal break|rest break|meal period|break penalty|premium pay|attestation)\b returns zero lines, and (break_time|break_duration|unpaid_break|break_minutes) returns zero. INVARIANCE: the Shift Type doctype -- the record that defines when a shift starts and ends and how attendance is graded against it -- has a complete field_order of 27 fields covering auto-attendance, half-day/absent working-hour thresholds, late-entry and early-exit grace periods and overtime, and contains no break field at all: no break duration, no unpaid-break deduction, no missed-break flag, no attestation prompt. On the jurisdiction half, hrms/regional contains exactly two subtrees, india and united_arab_emirates; there is no US state or municipality rule library anywhere in the app. POSITIVE CONTROL: 'late_entry_grace_period' and 'early_exit_grace_period' both resolve on this same doctype, so per-shift time-rule fields ARE modelled here and would have been found had break rules been among them. Bound to frappe/hrms@v16.17.1 plus erpnext@v16.34.1 and frappe@v16.33.0. source |
| labor-tip-pooling-rules | no / F - No tip concept anywhere in POS or HR." | downgrade-to-no | Ran the brief's own trap discipline. \btips?\b over erpnext@v16.34.1 + frappe@v16.33.0 returns 21 lines in 12 files and every one is a reader artefact: UI hint strings ('Tip: Select report lines...'), leaflet popup-tip CSS, a '# TIP:' comment in three GitHub workflow files, and a test fixture titled 'Project Management Tips'. The one interesting hit is a general-ledger account literally named 'Accr-Tips' in the Singapore F&B chart-of-accounts template -- an accrual account a Singapore restaurant could post to by hand, exactly parallel to the 'Kitchen' GL account the brief flags, and not a tip engine. Over hrms@v16.17.1 the same anchored pattern returns ZERO lines. Second trap: \bgratuit returns 22 files / 163 lines in hrms, but Frappe HR's 'Gratuity' and 'Gratuity Rule' doctypes are end-of-service severance benefits set up by hrms/regional/united_arab_emirates and hrms/regional/india -- not restaurant gratuities; in erpnext the gratuity hits are French-language chart-of-accounts lines. INVARIANCE: no tip or gratuity amount is captured anywhere in the three repositories, so nothing exists to pool; the POS Invoice payments section quoted here runs cash_bank_account -> payments -> paid_amount -> change_amount with no tip, gratuity or service-charge field. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files and Mode of Payment ships its own doctype, so POS money-handling concepts are visible to this search. source |
| labor-qualified-tips-w2-reporting | no / F - No US W-2 payroll output at all, let alone Box 12 code TP or Treasury tipped-occupation codes." | downgrade-to-no | Searched the US payroll-tax vocabulary over hrms@v16.17.1 (1,552 blobs, tree API truncated=false): \bW-2\b|\bW2\b|\bIRS\b|form 941|\bFICA\b|box 12|tipped occupation returns exactly one line, and it is a Tailwind size class 'w-2 h-2' in frontend/src/components/BaseLayout.vue -- a pure reader artefact. 'United States'|'USA'|'US payroll' returns zero lines. INVARIANCE: Salary Slip's income-tax breakup section -- the region of the record that would carry statutory box mappings -- is built entirely around ctc, standard_tax_exemption_amount, tax_exemption_declaration, annual_taxable_amount and total_income_tax, i.e. the Indian Income Tax Slab model; there is no W-2, no Box 12, no Box 14, no Treasury tipped-occupation code, and hrms/regional contains only india and united_arab_emirates. Compounding it, \btips?\b returns zero lines in all of hrms, so no charged-versus-cash tip amount exists to report. POSITIVE CONTROL: 'Income Tax Slab' resolves to 26 files / 62 lines including a dedicated Income Tax Computation report, so statutory payroll-tax machinery IS present and searchable -- it is simply Indian. Bound to frappe/hrms@v16.17.1; Frappe Cloud marketplace payroll localisations were not censused. source |
| labor-payroll-export-formats | no / F - No named Gusto/ADP/Paychex/QuickBooks payroll connectors. Generic CSV export and REST are available. | downgrade-to-no | ATTACK 2. Grade A rested on a Workspace JSON described as 'the artefact that would advertise a payroll export'. Advertising is not exhaustiveness -- a workspace is a curated UI shortcut list and omitting a feature from it proves nothing about the app. The load-bearing evidence is the provider-name zero across three repositories, which I re-derived myself over HRMS.txt. Downgraded to B and said so in the note. source |
| inventory-86-auto-sync | no / F - Stock can hit zero and stop-sale can be enforced, but nothing auto-86s across POS, online, and third | upgrade-to-partial | CHANGED FROM no. The prior rationale said 'nothing auto-86s'; the POS item-selector query falsifies that. Searched the vendor's vocabulary -- POS Profile, Bin, actual_qty, hide_unavailable_items -- across erpnext@v16.34.1. FINDING: point_of_sale.py's get_items joins Bin and, when the POS Profile flag hide_unavailable_items is set, filters the grid to (is_stock_item == 0) OR (Bin.warehouse == warehouse AND Bin.actual_qty > 0). An item whose on-hand in the terminal's warehouse reaches zero therefore disappears from the POS automatically, per profile, with no human action -- a real automatic 86 on the POS surface; pos_item_selector.js additionally colours each tile red/orange/green off actual_qty. WHAT IS ABSENT, and why this is not a yes: (a) the trigger is the sold item's own Bin quantity, not a component ingredient -- there is no BOM explosion in the POS availability path, so a menu item does not 86 when a shared ingredient runs out; (b) the threshold is hard-coded > 0, not configurable; (c) there is no second channel to sync to -- erpnext/patches/v15_0/delete_ecommerce_doctypes.py deletes Website Item and E Commerce Settings from core and redirects operators to the separate frappe/webshop app, and \b(doordash|uber ?eats|grubhub|deliveroo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns zero lines across erpnext@v16.34.1 and frappe@v16.33.0, so no third-party delivery menu exists in core to push availability to. POSITIVE CONTROL: allow_negative_stock resolves to 40 files / 157 lines, so stock-availability enforcement is present and searchable. Bound to core; Frappe Cloud restaurant apps (URY, POSNext, GETPOS) were not censused. source |
| inventory-mobile-count-offline | no / F - Item barcode scanning works in Stock Entry via keyboard-wedge scanners on any browser, but there is | downgrade-to-no | The claim is conjunctive -- mobile counting + barcode/QR scanning + accepts counts offline + syncs on reconnect -- and it fails on the offline half only. CORRECTION TO THE PRIOR RATIONALE: scanning is not keyboard-wedge-only. frappe@v16.33.0 ships frappe.ui.Scanner (frappe/public/js/frappe/scanner/index.js) which instantiates Html5Qrcode with facingMode 'environment', i.e. a real rear-camera barcode/QR scanner, and erpnext@v16.34.1 wires scan_barcode into Stock Reconciliation, Stock Entry and Pick List; Stock Reconciliation Item itself carries 'barcode' and 'has_item_scanned' fields. On any tablet browser that is a working mobile count-with-camera flow. INVARIANCE (the offline half): \b(service.?worker|indexeddb|workbox|localforage)\b returns zero real hits across erpnext@v16.34.1 and frappe@v16.33.0 -- the files matching the unanchored alternation are 'offline' in changelog prose, a Google Calendar comment and a phone-control string. serviceWorker|caches.open returns zero lines. The framework's entire notion of connectivity is the function quoted here: a synchronous read of navigator.onLine with no queue, no cache and no replay path, so a count taken with the server unreachable is simply lost. POSITIVE CONTROL: 'scan_barcode' resolves to 40 files / 75 lines, so client-side stock-counting code IS present and would have carried an offline buffer had one existed. source |
| inventory-vendor-catalogs-edi | no / F - No Sysco / US Foods / PFG catalog or EDI connectors. Purchase Orders can be emailed as PDF." | downgrade-to-no | DISCLOSURE FIRST, because a bare 'no EDI' sentence would be false: erpnext@v16.34.1 DOES ship a module literally named EDI (erpnext/modules.txt lists it last, after Subcontracting). I read it rather than counting it. The whole module is two doctypes, Code List and Common Code, plus a genericode importer; Code List's complete field_order is title / canonical_uri / url / default_common_code / version / publisher / publisher_id / description, and Common Code's is code_list / canonical_uri / title / common_code / description / additional_data / applies_to. That is an OASIS genericode code-list registry for mapping standard code values (the kind e-invoicing needs), and it contains no trading partner, no connection, no document type, no transmission and no catalogue import. INVARIANCE: \b(EDIFACT|X12|ANSI X12|punchout|cXML|Sysco|US Foods|Performance Food)\b returns zero lines across erpnext@v16.34.1 and frappe@v16.33.0 -- every hit on the wider alternation is the string 'edi' inside erpnext.edi module paths. Purchase Order transmission in core is email/print only. POSITIVE CONTROL: the same search finds erpnext.edi.doctype.code_list.code_list_import.import_genericode, so the EDI module's real contents were visible to it; and docs.frappe.io/erpnext/erpnext_integration, ERPNext's own Integration Categories page (updated 2026-02-26), enumerates every shipped integration and names no broadline distributor. Bound to core; the Frappe Cloud marketplace was not censused. source |
| inventory-invoice-ocr | no / F - No supplier-invoice OCR in core ERPNext." | downgrade-to-no | ATTACK 1. The row was graded A on a first-party error string, which is genuinely primary evidence -- but for a different document class. 'Bank Statement Import cannot OCR a scanned bank statement' does not establish 'no supplier-invoice OCR ingestion exists'; the corpus-wide zero does, and the corpus is not the cited file. A product's own error message is good evidence for exactly the proposition it states and no wider one. Kept the citation, dropped A to B, and made the note say which half the quote carries. source |
| inventory-bar-partial-bottle | no / F - Fractional UOMs would let you record 0.4 bottles, but there is no scale integration, pour-spout inte | downgrade-to-no | Both disjuncts of the claim were searched separately over erpnext@v16.34.1 + frappe@v16.33.0. By weight: \b(pour spout|weigh|weighing|weight scale|scale integration|serial port|RS.?232|USB HID)\b returns ZERO lines -- there is no scale, pour-spout or peripheral-device integration of any kind, and the brief's own warning holds ('scale' unanchored is 133 files of CSS transforms and 'grayscale'). By bottle fraction: \bbottle\b returns 16 lines in 3 files and all are test fixtures ('Water Bottle' in test_putaway_rule.py, 'Bottle Item A' in test_item_wise_inventory_account.py) -- no bar, beverage or depletion workflow. INVARIANCE: Stock Reconciliation Item, the line on which a physical count is recorded, is quoted here from field_order through valuation_rate: barcode, item_code, warehouse, qty, stock_uom, valuation_rate. It carries no weight, gross_weight or tare field; weight_uom and net_weight exist in this codebase only on shipping and billing lines (Packing Slip Item, Sales/Purchase Invoice Item) for freight, never on a count. Generic Float qty against a non-whole-number UOM does let an operator type 0.4, but that is arithmetic, not partial-bottle inventory. POSITIVE CONTROL: must_be_whole_number resolves to 22 files / 274 lines including 239 shipped UOMs in uom_data.json, so fractional-UOM machinery is present and searchable; the bar-specific layer is what is missing. source |
| reporting-labor-productivity | no / F - Frappe HR holds clocked hours and ERPNext holds sales, but no shipped report joins them into sales-p | downgrade-to-no | Two absences, searched separately. (1) The join: zero word-boundary hits for 'labour cost'|'labor cost'|labor_cost across erpnext@v16.34.1, frappe@v16.33.0 and hrms@v16.17.1, and enumeration of Frappe HR's 29 shipped report directories finds only Project Profitability joining labour cost to revenue -- via Sales Invoice Timesheet and a submitted Salary Slip, a professional-services construct with no path to POS Invoice or to Employee Checkin hours. Nothing computes sales per labour hour or labour cost as a percentage of sales, by any dimension. (2) The granularity: the claim asks for these figures BY HOUR, and the corpus cannot express an hour on the sales side at all. INVARIANCE: Sales Analytics -- ERPNext's principal sales-trend report -- offers the complete Range option set quoted here, Weekly / Monthly / Quarterly / Yearly, with no daily and no hourly bucket; \b(hourly|per hour|hour of day|by hour)\b across both repositories resolves only to scheduler cron types, Workstation hour_rate and Project costing_hours. POSITIVE CONTROL: 'Sales Person' and 'Item-wise Sales Register' both resolve as shipped reports and Sales Analytics groups by Customer/Item/Territory, so per-dimension sales reporting IS present -- the labour dimension and the hour bucket are what is absent. Bound to these three repositories at these tags. source |
| reporting-channel-profitability | no / F - No channel dimension and no marketplace commission data to net out." | downgrade-to-no | Searched the restaurant channel vocabulary over erpnext@v16.34.1 + frappe@v16.33.0: \b(daypart|revenue center|revenue centre|fulfillment channel|order channel|sales channel)\b returns ZERO lines. DISCLOSURE of the near-misses I checked and rejected: POS Invoice does carry utm_source, sales_partner, commission_rate, amount_eligible_for_commission and total_commission -- but utm_source is marketing campaign attribution (renamed from Lead Source), not a fulfilment channel, and Sales Partner commission is a broker payout the operator configures, not marketplace commission data, because no marketplace exists to supply it: \b(doordash|uber ?eats|grubhub|deliveroo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns zero lines across both repositories and core's own e-commerce doctypes were deleted in erpnext/patches/v15_0/delete_ecommerce_doctypes.py. INVARIANCE: Gross Profit, the only shipped report that computes margin per sale, exposes the complete Group By option set quoted here -- Invoice, Item Code, Item Group, Brand, Warehouse, Customer, Customer Group, Territory, Sales Person, Project, Cost Center, Monthly, Payment Term -- and no channel, order-type or fulfilment dimension appears in it. An operator could repurpose Cost Center or an Accounting Dimension as a channel, but that is configuration, not a shipped report, and there would still be no commission figure to net out. POSITIVE CONTROL: this same file resolves group_by options for Sales Person and Cost Center, so dimension filters ARE modelled here and a channel would have been found among them. source |
| reporting-sales-forecast | no / F - No shipped forward sales forecast at daypart or hourly granularity." | upgrade-to-partial | CHANGED FROM no. The prior rationale said 'no shipped forward sales forecast'; erpnext@v16.34.1 ships two. Searched \bforecast over the corpus: 17 files, and reading them finds (a) the Exponential Smoothing Forecasting report -- a standard Script Report, ref_doctype Sales Order, roles including Sales Manager and Sales User, which projects forward demand from the company's own order history; and (b) a Sales Forecast doctype with a Generate Demand action feeding Master Production Schedule and the Material Requirements Planning report, i.e. a forecast that IS consumable by an ordering workflow, which is the claim's second half. So 'exposed in the reporting UI' and 'consumable by ordering workflows' are both satisfied, and 'from the location's own history' is satisfied per Company and parent_warehouse. WHAT FAILS is granularity, and it fails hard. INVARIANCE: Sales Forecast's frequency selector -- quoted here in full -- offers exactly Weekly and Monthly; Exponential Smoothing Forecasting's periodicity offers Monthly / Quarterly / Half-Yearly / Yearly defaulting to Yearly; Sales Analytics' Range offers Weekly / Monthly / Quarterly / Yearly. The finest forward bucket anywhere in the product is a week, and \b(daypart|hourly|hour of day|by hour)\b returns no sales-side hit at all. A restaurant asking for a Friday-6pm forecast gets nothing. POSITIVE CONTROL: the same \bforecast search resolves Master Production Schedule and the MRP report, so forecasting machinery is present and searchable -- it is dimensioned for manufacturing, not for service. source |
| reporting-tip-tax-compliance | no / F - No tips are captured, so no declared-versus-charged reporting exists." | downgrade-to-no | This cell is downstream of the tip-capture absence, so I grounded that absence rather than the report. \btips?\b over erpnext@v16.34.1 + frappe@v16.33.0 returns 21 lines in 12 files, every one a reader artefact (UI hint strings 'Tip:', leaflet popup-tip CSS, '# TIP:' workflow comments, a test fixture) except one GL account named 'Accr-Tips' in the Singapore F&B chart-of-accounts template -- an account to post to, with nothing that computes a posting. Over hrms@v16.17.1 the same anchored pattern returns ZERO lines, and \bgratuit in hrms is the UAE/India end-of-service severance doctype, not a restaurant gratuity. INVARIANCE: the POS Invoice payments region quoted here -- outstanding_amount, payments_tab, payments_section, cash_bank_account, payments, base_paid_amount, paid_amount, base_change_amount, change_amount -- is the complete money-in area of the sale and carries no tip, gratuity, declared-tip or service-charge field. With no declared and no charged tip amount recorded on any document, there is no declared-versus-charged report, no pool-distribution detail and no tip tax liability summary to generate; and hrms/regional contains only india and united_arab_emirates, so there is no US jurisdiction model either. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files and Mode of Payment ships its own doctype with types Cash/Bank/General/Phone, so POS tender concepts ARE modelled and a tip tender would have been found among them. source |
| multi-location-cross-location-giftcard | no / F - No gift card product and therefore no outstanding-liability or inter-store settlement reporting." | downgrade-to-no | DISCLOSURE FIRST, because the prior rationale ('no gift card product') is wrong as written: erpnext@v16.34.1 ships a Coupon Code doctype whose coupon_type is DF.Literal['Promotional', 'Gift Card'], and coupon_code.py has a dedicated Gift Card branch that generates a 10-character hash code. I read it rather than stopping at the label. What that branch actually does is force maximum_use = 1 and require a Customer. INVARIANCE: the Coupon Code field_order quoted here is complete -- coupon_name, coupon_type, customer, coupon_code, from_external_ecomm_platform, pricing_rule, valid_from, valid_upto, maximum_use, used, description -- and there is no monetary value on the record at all: no face amount, no remaining balance, no partial redemption, no expiry-to-breakage posting and no liability account. ERPNext's 'Gift Card' is a single-use customer-bound discount voucher backed by a Pricing Rule, not a stored-value instrument. Consequently the claim's substance fails: there is no outstanding-liability balance to report (\b(stored value|breakage)\b returns zero lines across both repositories) and no inter-store settlement, and the cross-location half is degenerate rather than met -- one Frappe site holds one Coupon Code table shared by every Company, so a code is 'redeemable anywhere' only because nothing scopes or settles it. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files / 58 lines with a real points ledger and expiry, so ERPNext DOES model a customer-value instrument with a balance -- it just is not a gift card. source |
| multi-location-central-labor-policy | no / F - Frappe HR policies are configurable per company, but nothing is enforced at a POS terminal and there | downgrade-to-no | SCOPE: Frappe HR is in scope for this record (product.yaml already cites github.com/frappe/hrms for labor cells), so I censused frappe/hrms@v16.17.1 -- tree API truncated=false at 1,552 blobs -- rather than inferring from erpnext alone. Searched the three things the claim names. Overtime: Shift Type carries allow_overtime and overtime_type, so an overtime CONCEPT exists. Break enforcement: \b(meal break|rest break|meal period|break penalty|premium pay|attestation)\b returns zero lines and (break_time|break_duration|unpaid_break) returns zero -- the 708 unanchored 'break' lines are all column_break/section_break. Predictive scheduling: zero hits for predictive scheduling, fair workweek or advance notice. INVARIANCE, and it is sharper than the prior rationale: Shift Type's complete 27-field field_order, quoted here through the auto-attendance block, has no company and no location field at all. Shift rules in Frappe HR are not per-location or per-location-group; they are global to the site, and only Shift Assignment (the per-employee record) carries a company. So the claim's premise fails one level earlier than 'not enforced at the terminal'. On enforcement, the POS is erpnext's Point of Sale page and hrms is a separate app: nothing in erpnext@v16.34.1 reads a Shift Type, and POS Profile has no labour field, so no rule can gate a terminal. POSITIVE CONTROL: 'Employee Checkin' resolves to 26 files / 68 lines and shift_type.py itself computes late-entry and early-exit marking, so shift-rule enforcement code IS present and searchable -- it grades attendance after the fact, which is exactly what the claim excludes. source |
| extensibility-doordash-preferred | no / F - Not among the 2026 DoorDash Preferred Integration Partners (Checkmate, Chowly, Deliverect, Otter, PA | downgrade-to-no | This claim is about membership of a third-party programme, so no code census can settle it; it is settled by the programme owner's own exhaustive roster. Re-probed DoorDash's newsroom announcement today (2026-09-06): HTTP 200, 406,541 bytes, live -- worth recording because another atlas row notes this URL once 404'd, and a 404 is not a deletion. The page names the 2026 cohort exhaustively as Checkmate, Chowly, Deliverect, Otter, PAR, Qu, Square, Stream, Toast and UrbanPiper -- ten names, each an outbound link -- and neither ERPNext, Frappe, Frappe Technologies nor any Frappe-ecosystem app appears on the page. INVARIANCE from the corpus side, which corroborates rather than establishes: \b(doordash|uber ?eats|grubhub|deliveroo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns ZERO lines across erpnext@v16.34.1, frappe@v16.33.0 and hrms@v16.17.1, and zero pages in the 1,863-page docs.frappe.io census -- there is no DoorDash integration at all, so the DPIP gates (250+ live DoorDash stores, sub-1% failure and merchant-avoidable cancel rate, SSIO, menu pull with 86 items, Order Ready Signal) cannot be met. POSITIVE CONTROL: the same anchored search resolves 'Shopify', 'WooCommerce' and 'Amazon' in the corpus and docs, so named third-party platform integrations ARE visible where they exist. NOTE the verbatim text carries an asterisk: 'the 2026* cohort'. source |
| extensibility-first-party-delivery-integrations | no / F - No DoorDash, Uber Eats or Grubhub integrations, first-party or otherwise." | downgrade-to-no | Grounded on the publisher's own exhaustive enumeration rather than on a bare zero. docs.frappe.io/erpnext/erpnext_integration is ERPNext's 'Integration Categories' page (updated 2026-02-26), and it lists every shipped integration by category: Authentication (LDAP, Fairlogin); Backup (Dropbox, Google Drive, Amazon S3); Bank (Plaid); E-commerce (Shopify, WooCommerce, Amazon SP-API, Unicommerce, Zenoti); Shipping (ERPNext Shipping, itself only LetMeShip and SendCloud); Payment (RazorPay, GoCardless, Stripe, Braintree, Paytm, M-pesa); Telephony (Exotel); Google. No delivery marketplace of any kind appears, first-party or otherwise. CORPUS INVARIANCE: \b(doordash|uber ?eats|grubhub|postmates|deliveroo|olo|otter|chowly|deliverect|checkmate|urbanpiper)\b returns ZERO lines across erpnext@v16.34.1 (5,170 files) and frappe@v16.33.0 (3,634 files) and zero pages across the 1,863-page docs.frappe.io census, and erpnext/erpnext_integrations -- the whole 'ERPNext Integrations' module named in erpnext/modules.txt -- contains exactly one doctype, plaid_settings. POSITIVE CONTROL: the same corpus search resolves Shopify, WooCommerce and Plaid to real integration code, so named third-party connectors ARE visible where they exist. BOUND: this is core ERPNext + Frappe. Restaurants on this stack buy URY, POSNext, GETPOS or KLiK PoS from the Frappe Cloud marketplace, which is out of this record's scope and was not censused; a marketplace app's DoorDash bridge would not make it a first-party Frappe integration either, which is what the claim asks. source |
| extensibility-payroll-export | no / F - No native connectors to Gusto, ADP, Paychex or Paylocity. Frappe HR runs payroll itself; export to t | downgrade-to-no | ATTACK 2, the same defect as labor-payroll-export-formats: grade A on a Frappe Workspace JSON. Downgraded to B. I did verify the ATTACK-3 half independently and it holds -- this row genuinely censused hrms and the provider zeros re-derive over hrms at v16.17.1. source |
| reporting-scheduled-delivery | unknown / F - Scored yes with confidence 'inferred' and no source URL whatsoever. Auto Email Report is a specific | resolve-to-yes | CHANGED FROM unknown, and this is the cell whose prior note complained of a URL-less 'inferred' yes -- so it is now grounded on the doctype JSON itself. Searched the vendor's name for the feature, 'Auto Email Report', over frappe@v16.33.0 (3,634 files): 16 files / 41 lines, the doctype living at frappe/email/doctype/auto_email_report. INVARIANCE, read off its field list rather than off prose: report is a Link to Report (so ANY Query Report or Script Report qualifies, which is the claim's 'any report'); email_to is a required Small Text recipient list; frequency is a required Select whose complete option set is Daily / Weekdays / Weekly / Monthly, with day_of_week Monday..Sunday for the weekly case; format is a required Select of HTML / XLSX / CSV / PDF; enabled, send_if_data, no_of_rows, filters and dynamic_date_period round it out. Cadence, recipient list and delivery format are therefore all first-class configured fields, not an inference. POSITIVE CONTROL: the same doctype resolves in frappe/workspace_sidebar/automation.json (it is surfaced in the Automation workspace) and in three erpnext v13 patches that clean up Auto Email Reports pointing at deleted reports -- i.e. the feature is old enough that ERPNext ships migration code for it. Bound to frappe@v16.33.0; the delivery target is email, and a shared-destination drop is not offered. source |
| inventory-count-modes | partial / F - Stock Reconciliation supports both full and partial/subset counts, and each is a separate submitted | downgrade-to-partial | Searched the vendor's counting vocabulary over erpnext@v16.34.1: Stock Reconciliation, purpose, set_warehouse, scan_barcode, scan_mode. INVARIANCE supporting the partial: Stock Reconciliation is a submittable document whose purpose Select is quoted here -- Opening Stock or Stock Reconciliation -- and whose items table is free-form, so an operator may count every item in a warehouse or any subset of them; each count is its own submitted, immutable document with its own difference_amount and expense_account posting, so histories accumulate rather than overwrite, which is the part of the claim that is met. It also carries scan_barcode and scan_mode, so counts can be scanned. INVARIANCE supporting the shortfall: \b(cycle count|recurring count|count schedule)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0. Frappe does ship a generic recurring-document engine, Auto Repeat, and 11 erpnext doctypes opt into it by setting allow_auto_repeat: 1 (Sales Order, Purchase Order, Quotation, Journal Entry, Payment Entry, POS Invoice, Delivery Note, Purchase Receipt, Supplier Quotation and the two Subcontracting orders) -- Stock Reconciliation is NOT among them, so no scheduled recurring cycle count can be configured even by reuse. POSITIVE CONTROL: allow_auto_repeat resolves to 21 files / 29 lines, so the opt-in flag was visible to the search wherever it is set. source |
| inventory-waste-logging | partial / F - Stock Entry (Material Issue) debits an expense/scrap account and depletes inventory, and Stock Entry | downgrade-to-partial | Searched the vendor's vocabulary -- Stock Entry, Stock Entry Type, Material Issue, expense_account -- over erpnext@v16.34.1, then the restaurant vocabulary. INVARIANCE: Stock Entry Type is a three-field doctype (purpose, add_to_transit, is_standard) and its purpose Select carries exactly thirteen values: Material Issue, Material Receipt, Material Transfer, Material Transfer for Manufacture, Material Consumption for Manufacture, Manufacture, Repack, Send to Subcontractor, Disassemble, Receive from Customer, Return Raw Material to Customer, Subcontracting Delivery, Subcontracting Return. Not one of them is Waste, Spoilage, Damage, Breakage or Scrap. What makes this a partial rather than a no is that is_standard is a flag on this doctype: an operator can create a non-standard Stock Entry Type named 'Waste' over the Material Issue purpose, which depletes inventory and debits the configured expense account -- a real, native, one-field setup step. What is absent is anything shipped: no reason-code taxonomy, no required reason field on the Stock Entry line, and no report that separates waste cost from usage variance. POSITIVE CONTROL: 'Material Issue' resolves across stock_entry.py, the Stock Entry Type fixtures and the perpetual-inventory GL code, so the entry-type machinery is present and searchable; a waste type would have been found among the thirteen had one shipped. source |
| inventory-cogs-gl-export | partial / F - ERPNext is itself the accounting system — perpetual inventory posts COGS to the GL automatically wit | downgrade-to-partial | Searched the vendor's vocabulary -- Item Default, perpetual inventory, expense_account, default_cogs_account, Item Group -- over erpnext@v16.34.1. INVARIANCE supporting the partial: Item Default is a child table hanging off Item (and mirrored on Item Group) keyed by company, and its field list quoted here carries default_warehouse, default_inventory_account, buying_cost_center, expense_account, purchase_expense_account, expenses_added_to_stock_account, selling_cost_center, income_account and default_cogs_account. GL account mapping per item and per item category, per company, is therefore native and configurable exactly as the claim asks, and under perpetual inventory the COGS posting is made automatically at delivery -- so the mapping half is fully met and the export half is mostly moot because ERPNext IS the ledger. INVARIANCE supporting the shortfall: \bquickbooks\b returns exactly ONE line in erpnext@v16.34.1 and it is a 'which system are you coming from' option in setup_wizard.js; there is no Intacct or NetSuite string anywhere; and docs.frappe.io's own QuickBooks Migrator page is now headed 'Deprecated', stating the built-in migrator was removed from ERPNext on 2025-01-17. So there is no ongoing mapped journal-entry sync to any named external GL, in either direction. POSITIVE CONTROL: 'Item Default' and default_cogs_account both resolve to real fields on this doctype, so per-item GL mapping was visible to the search. source |
| reporting-realtime-dashboard | partial / F - Dashboard, Dashboard Chart and Number Card render live query results and the Frappe UI is responsive | downgrade-to-partial | Searched the vendor's vocabulary -- Dashboard, Dashboard Chart, Number Card, Workspace -- over frappe@v16.33.0. INVARIANCE supporting the partial: frappe/desk/doctype ships dashboard, dashboard_chart, dashboard_chart_source, dashboard_chart_link, dashboard_settings, number_card and number_card_link, plus workspace_chart and workspace_number_card for placement. The Number Card field list quoted here binds a card to a document_type or report_name with an aggregate_function_based_on, a stats_time_interval and dynamic filters -- these are live queries against the live table, so a POS Invoice submitted now is in the figure on the next refresh, which is the 'within minutes' half of the claim. The Frappe desk is responsive and reachable over the public URL, so a browser on a phone off-premise works. INVARIANCE supporting the shortfall: there is no owner-facing mobile sales application. \b(service.?worker|indexeddb|workbox)\b returns zero real hits in erpnext@v16.34.1 or frappe@v16.33.0 -- notably, frappe/hrms@v16.17.1 DOES ship a PWA with frontend/public/sw.js and an InstallPrompt.vue, which shows Frappe builds installable mobile front ends when it wants to, and has built none for sales. POSITIVE CONTROL: 'Auto Email Report', Dashboard Chart and Number Card all resolve as shipped doctypes, so the reporting-surface search was working. source |
| reporting-pmix-modifier-level | partial / F - Item-wise Sales Register and Sales Analytics give per-item quantity, gross and net, filterable by da | downgrade-to-partial | Searched the vendor's report vocabulary over erpnext@v16.34.1: Item-wise Sales Register, Sales Analytics, Gross Profit. INVARIANCE supporting the partial: Item-wise Sales Register's complete filter set is from_date, to_date, customer, company, mode_of_payment, warehouse, brand, item_code, item_group, group_by and income_account -- per-item quantity, gross and net by period, which is the PMIX core. INVARIANCE supporting the shortfall, and it is two separate absences. (1) Modifier level: there is no modifier concept to report on -- Item Variant and Attribute are a purchasable-SKU matrix, not an order-time modifier, and no Sales Invoice Item or POS Invoice Item field carries a modifier or option line. (2) Daypart and revenue centre: \b(daypart|revenue center|revenue centre)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0, and the finest time bucket any shipped sales report offers is a week -- Sales Analytics' Range Select is Weekly / Monthly / Quarterly / Yearly. The filters quoted here are date-range only, with no time-of-day dimension. POSITIVE CONTROL: mode_of_payment and warehouse resolve as real filters on this same report, so dimension filters ARE modelled here and a daypart would have been found among them. source |
| reporting-comps-voids-audit | partial / F - Cancelled and amended invoices are permanent records attributed to a user, and the Version log captu | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1 and frappe@v16.33.0: Version, track_changes, amended_from, docstatus, apply_discount_on. INVARIANCE supporting the partial: POS Invoice is submittable and declares "track_changes": 1, so every field-level edit lands in a frappe Version record (ref_doctype, docname, data) attributed to a user with a timestamp; a cancellation sets docstatus 2 and any correction becomes a new document carrying amended_from, so voids and amendments are permanent and attributed. The discount region quoted here -- coupon_code, apply_discount_on, base_discount_amount, additional_discount_percentage, discount_amount -- is likewise versioned, so a price override is recoverable. INVARIANCE supporting the shortfall: there is no reason field and no approver field anywhere in POS Invoice's 185-field field_order, no reason-code doctype exists (\b(reason code|void reason|comp reason)\b returns zero lines), and no shipped report aggregates comps, voids, discounts and overrides into an exception listing -- reconstructing one means querying Version blobs by hand. POSITIVE CONTROL: track_changes resolves as a real DocType property and Version ships as a core frappe doctype, so the audit machinery was visible to the search; what is missing is the reason taxonomy, the approver and the packaged report. source |
| multi-location-central-menu-publish | partial / F - One Item master on one site is automatically shared by all companies and warehouses, so central auth | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Item, Item Default, Item Group, Company, Price List. INVARIANCE supporting the partial: the Item doctype has NO company field. Company-specific behaviour lives entirely in the Item Default child table quoted here, which is keyed by company and carries default_warehouse, default_price_list and the account defaults. So one Item master on one site is inherently shared by every Company and Warehouse, and editing it changes the menu everywhere at once -- central authoring is not a feature here, it is the only possible arrangement, which is why this is not a plain no. INVARIANCE supporting the shortfall: because there is nothing to publish, there is no publish action, no target-set selector, no staged/effective-dated menu version and no push history. \b(publish|rollout|deploy)\b against the Item tree returns only website-publishing leftovers, and core's website-item doctypes were themselves deleted in erpnext/patches/v15_0/delete_ecommerce_doctypes.py. The only change record is the generic frappe Version log, which tells you a field changed, not which locations received it and when. POSITIVE CONTROL: Item Default and its company Link both resolve on this doctype, so per-company item scoping IS modelled and a publish/target mechanism would have been found beside it. source |
| multi-location-consolidated-reporting | partial / F - Consolidated Financial Statement across a group-company tree is native, and sales/item reports filte | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Consolidated Financial Statement, Company tree with is_group, accumulated_in_group_company. INVARIANCE supporting the partial: erpnext ships consolidated_financial_statement and consolidated_trial_balance, whose filter set is company, filter_based_on, period start/end, fiscal years, finance_book, report, presentation_currency, and the accumulated_in_group_company checkbox quoted here -- so above-store rollup across a group-company tree, in one presentation currency, is genuinely native, and Sales Analytics / Item-wise Sales Register filter by company for the sales side. INVARIANCE supporting the shortfall: the consolidation is a GL consolidation. Labour never enters it (Frappe HR is a separate app; \b'labour cost'|'labor cost'\b returns zero lines in all three repositories), there is no discount or void rollup, and there is no store-versus-store ranking or variance flag -- \b(variance flag|store ranking|benchmark)\b returns zero lines, and every shipped comparison report ranks item groups, sales persons or territories, never locations. POSITIVE CONTROL: accumulated_in_group_company and presentation_currency resolve as real filters in this same file, so above-store options ARE modelled here and a store-ranking option would have been found among them. source |
| extensibility-middleware-compatibility | unknown / F - No evidence located that Deliverect, Chowly, Otter or Checkmate list ERPNext as a supported POS endp | upheld | ATTACK 4. The row's own note concedes 'That leaves one published exhaustive POS roster, not two' and then scores `no` anyway on a vendor-side corpus zero. But the vendor-side zero is not probative here, and this analyst says so elsewhere: extensibility-headless-embedded (partial/A, same batch) establishes that every doctype including POS Invoice is a first-class REST resource and that 'a third-party kiosk, web-ordering or drive-thru UI genuinely can drive the transaction engine'. Middleware integrates against generic REST APIs without the vendor shipping a line of code, so zero occurrences of 'deliverect' in erpnext is consistent with Deliverect listing ERPNext. Two rows in the same output contradict each other on exactly this point. Grade C was honest about the retrieval; the verdict was not. Returned to unknown with the documents that would settle it named. |
| extensibility-accounting-connectors | partial / F - ERPNext replaces the GL rather than syncing to one, so the criterion partly misfits. A QuickBooks Mi | downgrade-to-no | CHANGED FROM partial -- a downgrade, because the partial's factual basis has been withdrawn by the vendor. The prior rationale rested on 'a QuickBooks Migrator app exists for one-time inbound migration'. It does not, not in this version. ERPNext's own documentation page for it is now titled 'QuickBooks Migrator (Deprecated)' and states in a callout that the built-in migrator was removed from the ERPNext develop branch on 2025-01-17 in PR #45240, directing operators instead to Data Import, the Chart of Accounts Importer, the Opening Invoice Creation Tool and opening Journal Entries -- i.e. to hand-mapped spreadsheets. CORPUS INVARIANCE confirming it independently: \bquickbooks\b returns exactly ONE line across erpnext@v16.34.1 (5,170 files) and frappe@v16.33.0 (3,634 files), and it is a 'which system are you coming from' option in setup_wizard.js alongside Tally, Zoho, Sage and SAP -- a migration-source label with no code behind it. There is no QuickBooks Migrator doctype left, and \b(intacct|netsuite|xero|sage intacct)\b returns zero lines. So there is no native vendor-maintained connector to QuickBooks Online and none to a second GL, in either direction, mapped or otherwise. The criterion does partly misfit -- ERPNext replaces the general ledger rather than syncing to one -- but the claim asks for connectors and there are now zero. POSITIVE CONTROL: 'Plaid' resolves to a real erpnext_integrations doctype and Shopify/WooCommerce to real integration docs, so first-party financial connectors ARE visible to this search where they exist. source |
| labor-offline-time-punch | unknown / F - Undetermined rather than absent. Frappe HR imports punches from biometric attendance devices, which | resolve-to-no | CHANGED FROM unknown, by censusing the app the prior note could not reach. Frappe HR is in scope (product.yaml cites github.com/frappe/hrms for labor cells); frappe/hrms@v16.17.1 answers truncated=false at 1,552 blobs. The prior note guessed that biometric devices buffer locally; that is true of the DEVICE, and Employee Checkin does carry a device_id for imported punches, but it is a third-party clock, not a first-party offline mode. INVARIANCE: hrms DOES ship a PWA -- frontend/src/main.js registers /assets/hrms/frontend/sw.js, InstallPrompt.vue offers installation, and package.json pulls workbox-core and workbox-precaching -- so if an offline punch queue existed anywhere in the Frappe stack it would be here. The whole service worker is quoted: it calls precacheAndRoute(self.__WB_MANIFEST) and cleanupOutdatedCaches(), i.e. it precaches the static app shell, then hands off to Firebase messaging for background push. There is no runtime route for API calls, no Background Sync registration, no IndexedDB or localforage write queue anywhere in the app, and \b(indexeddb|localforage|background.?sync|outbox|queue)\b returns no such hit. A check-in POST made with the server unreachable therefore fails outright; nothing reconciles on reconnect, and nothing documents such behaviour. The POS side is worse still: erpnext@v16.34.1 registers no service worker at all. POSITIVE CONTROL: 'serviceWorker' resolves in hrms/frontend/src/main.js and 'workbox' in frontend/package.json, so offline infrastructure IS present and searchable -- it caches assets, not punches. source |
| labor-native-scheduling | partial / F - Frappe HR provides Shift Type, Shift Assignment and Shift Request in the same app that holds attenda | downgrade-to-partial | Scored against frappe/hrms@v16.17.1 (tree API truncated=false, 1,552 blobs), which is in scope for this record. The prior rationale ('It is shift assignment, not a schedule builder') understates what v16 ships and I am correcting it upward while keeping the partial. INVARIANCE supporting the partial: hrms/hr/doctype now contains shift_type, shift_assignment, shift_request, shift_location, shift_assignment_tool, shift_schedule and shift_schedule_assignment. Shift Schedule -- quoted here -- pairs a shift_type with a frequency Select of Every Week / Every 2 Weeks / Every 3 Weeks / Every 4 Weeks and a repeat_on_days table, and Shift Schedule Assignment binds an employee to that schedule with create_shifts_after so future Shift Assignments are generated automatically. Shift Assignment Tool bulk-assigns across branch, department, designation, grade and employment_type filters. All of this sits in the same app that holds Employee Checkin and Attendance, which is exactly the claim's requirement, so no third-party scheduling app is needed. INVARIANCE supporting the shortfall: there is no role-coverage model (nothing counts how many of a designation a shift needs), no drag-and-drop weekly grid, no publish-to-staff action, and no labour-budget or forecast constraint -- \b(coverage|schedule builder|open shift)\b returns zero lines. POSITIVE CONTROL: 'Employee Checkin' resolves to 26 files in this same app, so timekeeping and scheduling demonstrably co-reside. source |
| labor-shift-swap-workflow | partial / F - Frappe HR Shift Request goes through an approval workflow. No open-shift claiming marketplace and no | downgrade-to-partial | Re-derived the row's stated invariance rather than inheriting it, and it was wrong: the note claimed '\b(open shift|shift swap|shift pickup|claim shift)\b returns ZERO lines across hrms@v16.17.1' and the anchored pattern returns one line. The hit is a reader artefact and the conclusion survives, but a published zero that is not a zero is exactly the defect this program treats as disqualifying, and the trap ('open Shift Requests' meaning pending approval) is worth recording so the next reader does not rediscover it as a finding. Value and grade unchanged; figure corrected. source |
| labor-server-performance-metrics | partial / F - Every POS Invoice carries an owner and optional Sales Person, and Sales Person / Item-wise Sales rep | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Sales Person, Sales Team, Sales Person-wise Transaction Summary, Item-wise Sales Register, owner. INVARIANCE supporting the partial: every POS Invoice carries the framework's owner field (the cashier who created it) and, as quoted here, a Sales Team child table plus sales_partner, so a sale can be attributed to a named person; erpnext ships sales_person_wise_transaction_summary (filters sales_person, doc_type, date range, company, item_group, brand, customer, territory) and sales_person_commission_summary against that attribution. Average check and per-person item mix are therefore derivable from shipped reports without custom code. INVARIANCE supporting the shortfall: void and comp rate per server is not a shipped metric and cannot be assembled from a shipped report -- there is no comp concept at all, a void is a docstatus-2 cancellation with no reason code and no shipped exception report, and \b(attachment rate|void rate|comp rate)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0. Nor is there any per-server scorecard view; the operator assembles the metrics from separate reports. POSITIVE CONTROL: sales_team and sales_partner resolve as real fields on this doctype and Sales Person resolves as its own doctype with five shipped reports, so per-person sales attribution IS modelled and a void-rate metric would have been found beside it. source |
| inventory-theoretical-vs-actual | partial / F - Stock Ledger gives actual movement, Stock Reconciliation records counts and posts the variance to a | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Stock Ledger, Stock Reconciliation, difference_amount, expense_account, BOM, Work Order, Stock Entry (Material Consumption for Manufacture). INVARIANCE supporting the partial: each of the claim's three inputs exists natively. Actual movement is the Stock Ledger Entry table. Counts and their variance are Stock Reconciliation, whose section quoted here carries expense_account and difference_amount -- so a count posts its variance to a named difference account in currency, per count period, automatically. Theoretical usage exists as BOM explosion through Work Order and Material Consumption for Manufacture, which is exactly recipe-times-output. INVARIANCE supporting the shortfall: nothing joins them. There is no shipped report that takes POS sales times recipe and sets it against counts plus receipts -- \b(theoretical|usage variance|variance report)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- and the manufacturing route requires a Work Order per production run, which no restaurant raises per plate sold. The operator gets the raw ledgers and builds the report. POSITIVE CONTROL: difference_amount and expense_account resolve as real fields on this doctype and 'BOM' resolves across bom.py and the MRP report, so both halves of the arithmetic ARE present and searchable -- what is missing is the report that performs it. source |
| inventory-price-change-alerts | partial / F - Item Price history and Item-wise Purchase History give full per-item purchase price trails, and the | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1 and frappe@v16.33.0: Item Price, Item-wise Purchase History, Purchase Analytics, Notification. INVARIANCE supporting the partial: erpnext ships item_wise_purchase_history whose filter set -- company, from_date, to_date, item_group, item_code and the supplier filter quoted here -- gives a per-item purchase price trail across invoices and receipts, and Item Price keeps dated price records per price list, so the history the claim asks for is native. The alerting primitive is native too: frappe's Notification doctype fires on channel Email / Slack / System Notification / SMS with an event Select that includes Value Change and a free-form condition evaluated against any field, so an operator can configure 'alert when rate exceeds X'. INVARIANCE supporting the shortfall: nothing ships pre-built. There is no Notification fixture for purchase price, no contracted-price field to compare against (\b(contract price|contracted price|price variance)\b returns ZERO lines), and no threshold setting anywhere -- the operator must write the condition themselves, and comparing to the PRIOR received price specifically requires a custom Server Script because Notification conditions see only the current document. POSITIVE CONTROL: Notification resolves as a real frappe doctype with 44 fields and item_wise_purchase_history as a shipped report, so both the history and the alert engine ARE present -- the pre-built join is what is absent. source |
| inventory-par-auto-suggest | partial / F - Reorder Level and Reorder Qty per item-per-warehouse automatically generate Material Requests when o | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Item Reorder, reorder level, Material Request, Production Plan, Sales Forecast. INVARIANCE supporting the partial: Item Reorder is a child table on Item and its complete field list is quoted here -- warehouse, warehouse_group, warehouse_reorder_level, warehouse_reorder_qty, material_request_type. That is a par level per item per location (and per warehouse GROUP, which is the multi-site case), with a suggested order quantity, and reorder_item runs on the scheduler to raise Material Requests automatically when on-hand falls below the level. Native, shipped, exactly as the claim's first half asks. INVARIANCE supporting the shortfall, and it is narrower than the prior rationale allowed: erpnext@v16.34.1 DOES ship forecast-driven demand -- a Sales Forecast doctype feeding Master Production Schedule, plus an Exponential Smoothing Forecasting report over Sales Order history -- so a forecast mode is not simply missing. What is missing is the connection: Sales Forecast generates demand into Master Production Schedule and the MRP report, and nothing wires it to Item Reorder or to purchase suggestion; and its finest bucket is Weekly, useless for a restaurant's ordering rhythm. POSITIVE CONTROL: warehouse_reorder_level resolves across item.py, the reorder scheduler and stock_settings, so par machinery IS present and a forecast-driven par field would have been found on this doctype. source |
| inventory-menu-margin-linkage | partial / F - The Gross Profit report joins selling price to valuation rate per item/invoice/sales-person and yiel | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Gross Profit, valuation_rate, BOM, Item Group, Notification. INVARIANCE supporting the partial: the Gross Profit report emits gross_profit and gross_profit_percent per row and its Group By Select -- quoted here in full -- includes Item Code, Item Group and Brand, so contribution margin per menu item against actual sales mix is a shipped report, not a construction. Where the item is manufactured through a BOM the valuation rate carries the recipe cost, so ingredient cost changes do flow into the margin figure on the next valuation. INVARIANCE supporting the shortfall: there is no threshold and no flag. \b(margin threshold|margin alert|below margin)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0; Gross Profit has no filter for 'margin under N percent' among its eleven filters; and while frappe's Notification doctype could in principle watch a field, it fires on document events and cannot watch a report's computed column, so even the configurable route does not reach this claim. POSITIVE CONTROL: gross_profit_percent resolves four times in gross_profit.py's column sets and Item Group resolves as a Group By option, so the margin-per-item machinery IS present and a threshold filter would have been found beside it. source |
| reporting-server-scorecards | partial / F - Sales Person-wise reports and invoice owner give average check and item mix per cashier. Attachment | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Sales Person, Sales Team, Item Group, Brand, Territory. INVARIANCE supporting the partial: sales_person_wise_transaction_summary is a shipped report whose filters -- quoted here from sales_person through the document-type selector -- run sales_person, doc_type, from_date, to_date, company, item_group, brand, customer, territory and show_return_entries, and POS Invoice carries a Sales Team child table plus the framework owner field. Average check and items per check per named person are therefore derivable from a shipped report, and sales_person_target_variance_based_on_item_group adds a target comparison. INVARIANCE supporting the shortfall, two absences that are qualitatively different. (1) Attachment rate for named categories: the report slices BY item_group, but nothing computes the ratio of checks containing a category to all checks -- \b(attachment rate|attach rate)\b returns ZERO lines. (2) Tips as a percentage of sales: impossible, because \btips?\b returns 21 lines across erpnext@v16.34.1 + frappe@v16.33.0 and every one is a reader artefact -- UI hint strings, leaflet popup-tip CSS, a workflow comment -- bar a Singapore F&B chart-of-accounts GL account named 'Accr-Tips'; no tip amount is captured on any document. There is also no scorecard view: the operator reads three reports. POSITIVE CONTROL: item_group and territory resolve as real filters here, so per-person dimensional slicing IS present. source |
| reporting-history-retention | partial / F - Retention is unlimited in practice because the operator owns the database and nothing is truncated o | downgrade-to-partial | Propagated premise, ATTACK 1. The row asserted that '\b(retention (policy|period|window)|data retention)\b returns zero lines in the 1,544-page docs.frappe.io census'. That census is the erpnext+framework subset, and over the real 1,863-page corpus the pattern returns thirteen lines in eight documents -- including a Frappe Cloud clause literally headed 'Data Retention & Deletion'. Value and grade stand, because log_settings.py genuinely carries the structural half, but a live claim note asserting a zero that is not a zero had to be corrected, and the actual clause is better evidence for the shortfall than the false absence was. source |
| reporting-anomaly-alerts | partial / F - The Notification doctype fires email/SMS/system alerts on document events or scheduled conditions ag | downgrade-to-partial | Searched the vendor's vocabulary over frappe@v16.33.0: Notification, condition, Value Change, channel, Server Script. INVARIANCE supporting the partial: the Notification doctype's 'Send Alert On' Select is quoted here in full -- New, Save, Submit, Cancel, Days After, Days Before, Minutes After, Minutes Before, Value Change, Method, Custom -- against any document_type, with a free-form condition expression, a recipients table, and a channel Select of Email / Slack / System Notification / SMS. So an operator-configured threshold alert (a discount above N, a cancellation, a value that changed) is genuinely configurable with no code, on four delivery channels including push-style System Notification. INVARIANCE supporting the shortfall: every trigger in that list is a document event or a fixed date/time offset. There is no aggregate trigger, no baseline and no statistical comparison -- \b(anomaly|deviation|standard deviation|z.score|seasonal|baseline)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- so 'deviates from its historical pattern' and 'sales below forecast' are unreachable without a custom Server Script, and there is no forecast at daily granularity to compare against anyway (Sales Forecast's finest frequency is Weekly). POSITIVE CONTROL: 'Value Change' and the condition field both resolve on this doctype, so the alert engine IS present and an anomaly mode would have been found in its event list. source |
| reporting-nl-query | unknown / F - Frappe Insights is a separate first-party BI app and has shipped AI-assisted query features in recen | resolve-to-no | ATTACK 2. Grade B was over-graded. The Insights half rests on (a) a README, a summary/marketing document that is grade C at best, and (b) a filename census, which cannot establish content absence -- the row's own wording was 'not one filename contains'. I re-pulled the frappe/insights tree at v3.13.2 myself (1,263 paths, truncated:false) and independently confirmed no ai/llm path and that 'assisted query' is the visual builder, so the verdict survives; the grade does not. Held at `no` rather than `unknown` because the core corpora carry a clean zero and Insights is outside this record's scope by the row's own admission. source |
| multi-location-multi-brand | partial / F - Multiple Companies on one site give separate revenue reporting, letterheads and print formats. A POS | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: POS Profile, Company, Letter Head, Print Format, Item Group, Warehouse. INVARIANCE supporting the partial: multiple Companies on one site is native and is the standard multi-brand arrangement -- each Company has its own Letter Head, its own Print Format selection on the POS Profile, its own account tree and its own separately reportable revenue, and the Consolidated Financial Statement rolls them up. Two brands on one site with separate branding and separate books is therefore real. INVARIANCE supporting the shortfall, read off the artefact quoted here: POS Profile's field_order opens with company, and company is declared reqd: 1, as is warehouse. A terminal's profile binds to exactly ONE Company and ONE Warehouse, and point_of_sale.py resolves items, prices and stock through that single profile for the whole session. To sell the second brand the cashier must close the session and open a different POS Profile, which also means a different POS Opening/Closing Entry and therefore a different drawer reconciliation -- so 'same hardware and drawer, simultaneously' fails at the doctype level, not merely in practice. \b(virtual brand|multi.?brand|concept)\b returns ZERO lines in erpnext@v16.34.1. POSITIVE CONTROL: company and warehouse both resolve as required Link fields on this doctype, so the binding IS modelled and a multi-company POS Profile would have shown as an optional or table field. source |
| extensibility-headless-embedded | partial / F - Architecturally native — the POS UI is itself just a client of the same REST layer, so a third-party | downgrade-to-partial | Searched the vendor's vocabulary over frappe@v16.33.0 and erpnext@v16.34.1: REST API, api/method, whitelist, OAuth Client, Webhook, headless. INVARIANCE supporting the partial: frappe/api ships both v1.py and v2.py route sets -- the module quoted here builds werkzeug Rules over document_list and the whitelisted-method dispatcher -- and every doctype including POS Invoice, POS Opening Entry and POS Closing Entry is a first-class REST resource behind them, with frappe/integrations/doctype/oauth_client and token_cache providing OAuth 2 and api-key auth. erpnext's own Point of Sale page is itself only a client of that layer: point_of_sale.py's get_items and the payment path are ordinary whitelisted methods. So a third-party kiosk, web-ordering or drive-thru UI genuinely can drive the transaction engine, and that is architecture, not aspiration. INVARIANCE supporting the shortfall: nothing is offered AS a headless mode. \b(headless|embedded pos|white.?label pos)\b returns ZERO lines across both repositories and zero pages in the 1,863-page docs.frappe.io census; there is no POS-specific API contract, no versioned order schema, no sandbox and no support commitment -- an integrator is calling internal desk methods whose signatures move between versions. POSITIVE CONTROL: 'oauth_client', 'webhook' and api/v2.py all resolve as shipped frappe modules, so the API surface IS present and a documented headless contract would have been found beside it. source |
| reporting-guest-cohorts | partial / F - ERPNext ships a Customer Acquisition and Loyalty report (new versus repeat customers by period) and | downgrade-to-partial | Searched the vendor's vocabulary over erpnext@v16.34.1: Customer, Customer Group, Loyalty Program, Customer Acquisition and Loyalty, territory. INVARIANCE supporting the partial: the report quoted here ships with columns New Customers, Repeat Customers, Total, New Customer Revenue, Repeat Customer Revenue and Total Revenue, bucketed by Year and Month and sliceable by Territory -- so new-versus-returning counts and their revenue split against real identifiable Customer records are native, and POS Invoice links a Customer, with Loyalty Program giving a points ledger to identify the guest at the till. INVARIANCE supporting the shortfall: the report stops at new-versus-repeat. There is no visit-frequency distribution (no count-of-visits bucketing anywhere), no lifetime-spend cohort and no recency/frequency/monetary segmentation -- \b(cohort|RFM|lifetime value|\bLTV\b|visit frequency)\b returns ZERO lines across erpnext@v16.34.1 and frappe@v16.33.0 -- and the month buckets are calendar periods, not signup cohorts followed forward, which is what the claim means by cohort. Nor is there an online-ordering channel in core to tie guests from: the e-commerce doctypes were deleted in erpnext/patches/v15_0/delete_ecommerce_doctypes.py. POSITIVE CONTROL: 'Loyalty Program' resolves to 22 files / 58 lines and this report resolves as a shipped Script Report, so guest-level analytics ARE present and a cohort view would have been found among them. source |
Sources
Every URL this record cites. 140 in total.
- https://frappe.io/erpnext/pricing
- https://github.com/frappe/erpnext/blob/develop/license.txt
- https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_profile/pos_profile.json
- https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
- https://raw.githubusercontent.com/frappe/frappe/develop/frappe/core/doctype/version/version.json
- https://github.com/frappe/erpnext/issues/29068
- https://github.com/frappe/hospitality
- https://github.com/frappe/hrms
- https://docs.frappe.io/erpnext/point-of-sale
- https://docs.frappe.io/erpnext/pos-profile
- https://docs.frappe.io/erpnext/item
- https://docs.frappe.io/erpnext/loyalty-program
- https://docs.frappe.io/erpnext/delivery-trip
- https://docs.frappe.io/erpnext/company
- https://docs.frappe.io/erpnext/tax-rule
- https://docs.frappe.io/framework/user/en/desk/version
- https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
- https://raw.githubusercontent.com/frappe/erpnext/develop/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.json
- https://docs.frappe.io/erpnext/data-export
- https://docs.frappe.io/erpnext/setup-two-factor-authentication
- https://docs.frappe.io/erpnext/bill-of-materials
- https://docs.frappe.io/erpnext/raw-printing
- https://docs.frappe.io/erpnext/print-settings
- https://docs.frappe.io/erpnext/stripe-integration
- https://docs.frappe.io/erpnext/payment-request
- https://docs.frappe.io/erpnext/pos-workflows
- not refetchable
- https://frappe.io/cloud/pricing
- https://docs.frappe.io/erpnext/opening-and-closing
- not refetchable
- https://docs.frappe.io/erpnext/quotation
- https://docs.frappe.io/erpnext/pricing-rule
- https://docs.frappe.io/erpnext/price-list
- https://docs.frappe.io/erpnext/customer
- https://docs.frappe.io/erpnext/promotional-scheme
- https://docs.frappe.io/erpnext/batch
- https://docs.frappe.io/framework/user/en/api/rest
- https://docs.frappe.io/framework/user/en/guides/integration/webhooks
- https://docs.frappe.io/framework/user/en/basics/users-and-permissions
- https://docs.frappe.io/framework/user/en/production-setup
- https://cloud.frappe.io/marketplace
- https://frappe.io/support-sla
- https://frappe.io/cloud/pricing
- https://docs.frappe.io/erpnext
- https://github.com/frappe/erpnext
- https://docs.frappe.io/erpnext/v13/user/manual/en/setting-up/data/data-export
- https://docs.frappe.io/framework/user/en/rate-limiting
- https://github.com/frappe/erpnext/blob/develop/erpnext/setup/demo.py
- https://docs.frappe.io/framework/user/en/installation
- https://docs.frappe.io/cloud/billing/billing-cycle
- https://docs.frappe.io/cloud/billing/disable-account
- https://docs.frappe.io/erpnext/stripe-integration
- https://github.com/frappe/payments
- https://docs.frappe.io/erpnext/company-setup
- https://cloud.frappe.io/marketplace/search
- https://docs.frappe.io/cloud/app-plan
- https://docs.frappe.io/cloud/how-to-uninstall-an-app-from-the-site
- https://docs.frappe.io/cloud/installing-an-app
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/remove_exotel_integration.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/doctype/sales_order/sales_order.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/modules.txt
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/item/item.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_profile/pos_profile.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pricing_rule/utils.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/patches/v15_0/delete_ecommerce_doctypes.py
- https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/webshop_settings/webshop_settings.json
- https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/recommended_items/recommended_items.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/crm/doctype/appointment/appointment.json
- https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/templates/includes/cart/place_order.html
- https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/shopping_cart/cart.py
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/core/doctype/sms_settings/sms_settings.json
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/integrations/doctype/google_settings/google_settings.json
- https://raw.githubusercontent.com/frappe/webshop/1a5239d4482800b8fe1cb7d88c4ea0d9e837a03e/webshop/webshop/doctype/website_item/website_item.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/subscription/subscription.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
- https://docs.frappe.io/legal/policies/service-level-agreement
- https://docs.frappe.io/erpnext/coupon-code
- https://docs.frappe.io/legal/terms/frappe-cloud-terms
- https://frappe.io/quality-and-information-security
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/printing/doctype/network_printer_settings/network_printer_settings.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/pos_controller.js
- https://docs.frappe.io/erpnext/permissions
- https://docs.frappe.io/erpnext/exotel_integration
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/model/document.py
- https://frappe.statuspage.io/
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/driver/driver.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/setup/doctype/territory/territory.json
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/integrations/doctype/geolocation_settings/geolocation_settings.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
- https://docs.frappe.io/erpnext/e-commerce-integrations-for-erpnext
- https://docs.frappe.io/erpnext/integrating-erpnext-with-other-applications
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/crm/doctype/email_campaign/email_campaign.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/delivery_trip/delivery_trip.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/coupon_code/coupon_code.json
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/patches/v16_0/add_module_deprecation_warning.py
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/email_group_member/email_group_member.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/hooks.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.json
- https://docs.frappe.io/legal/terms/enterprise-support-agreement
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/employee_checkin/employee_checkin.json
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/report/project_profitability/project_profitability.py
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_type/shift_type.json
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/payroll/doctype/salary_slip/salary_slip.json
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/payroll/workspace/payroll/payroll.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/page/point_of_sale/point_of_sale.py
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/public/js/frappe/dom.js
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/edi/doctype/code_list/code_list.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/doctype/bank_statement_import_log/bank_statement_import_log.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_reconciliation_item/stock_reconciliation_item.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/sales_analytics/sales_analytics.js
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/gross_profit/gross_profit.js
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/manufacturing/doctype/sales_forecast/sales_forecast.json
- https://about.doordash.com/en-us/news/doordash-preferred-integrations-program-2026
- https://docs.frappe.io/erpnext/erpnext_integration
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/auto_email_report/auto_email_report.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/stock_entry_type/stock_entry_type.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/item_default/item_default.json
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/desk/doctype/number_card/number_card.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js
- https://docs.frappe.io/erpnext/quickbooks-migrator
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/frontend/public/sw.js
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_schedule/shift_schedule.json
- https://raw.githubusercontent.com/frappe/hrms/v16.17.1/hrms/hr/doctype/shift_request/shift_request.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/buying/report/item_wise_purchase_history/item_wise_purchase_history.js
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/stock/doctype/item_reorder/item_reorder.json
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/core/doctype/log_settings/log_settings.py
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/email/doctype/notification/notification.json
- https://raw.githubusercontent.com/frappe/insights/v3.13.2/README.md
- https://raw.githubusercontent.com/frappe/frappe/v16.33.0/frappe/api/v1.py
- https://raw.githubusercontent.com/frappe/erpnext/v16.34.1/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py