Weekly Order Intake

DailyGrubs Console · implementation plan

The attached file cannot be the weekly input. It is a report of orders that already happened.

Every column in Orders_Detail_2026-09-02 is an outcome: orderstatus=delivered, deliverytime, rider, assigntime, kms. Feeding it back would re-create twelve deliveries that were already made, already ridden and already charged.

It also fails the console’s existing upload contract outright. Of the six columns the bulk uploader marks required, two are absent from the report entirely and one is blank on all twelve rows. This is fixable — the underlying customer data is all there — but it needs a purpose-built intake template, and that is decision one below.

Analysis · the gap

Report export vs. the upload contract

The console already accepts CSV/XLSX bulk uploads via orders/multipleOrders.js, which maps incoming headers through a fixed headerMap and rejects the file if a required column is missing. Here is that contract against what the report actually provides.

Upload columnReport fieldFilledStatus
sendernamereqlocationname12/12Mappable
senderphonereqlocationcontactno12/12Mappable
senderaddressreqPickupaddress0/12Present but empty
receivernamereqdeliverycustomer12/12Mappable
receiveralternatephonereq——Absent
itemdescriptionreq—1/12Absent
receiverphonedeliverycontactno12/12Mappable
receiverfulladdressdeliveryaddress12/12Mappable
receiverlatitudedeliverylat12/12Mappable
receiverlongitudedeliverylong12/12Mappable
pickupdatedeliverydate12/12Timezone-suspect
Quantity——Absent
Analysis · the harder constraint

Orders attach to customer records, not to addresses

This is the part that decides the architecture. createorders posts an array in which every element carries customerid and deliveryid. A row of free text is not enough — each line of the weekly file has to resolve to a customer that exists, or one has to be created first. That is exactly why the current UI says “Press Continue to add as drop customers” between upload and creation.

Three more values are never in any sheet and must come from elsewhere at commit time:

Consequence: the weekly file supplies who and what. The pickup point, the slot and the money are supplied by the run, not the sheet. Any automation has to bind them explicitly rather than inherit them by accident.
Design

Where an agent earns its place — and where it does not

Most of this pipeline is not an AI problem. Parsing, validating, pricing and posting are deterministic and must stay that way, because they are the steps where a confident wrong answer costs money. The agent belongs at the three genuinely ambiguous joints.

Deterministic — no model
  • Parse XLSX/CSV, drop TOTAL rows
  • Validate required columns, reject early
  • Compute charge from tenant pricing
  • Duplicate detection by run key
  • Build and POST the createorders payload
  • Reuse scanDataQuality as a pre-commit gate
Agent — proposes, never commits
  • Customer resolution: match name + phone + address to an existing record, or propose a new one
  • Address normalisation: split free text into locality/landmark/pincode, including Tamil-script entries
  • Anomaly triage: explain why a row looks wrong, in operator language
The rule: the agent returns a proposal with a confidence score and its reasoning. Deterministic code applies a threshold. Anything below it goes to the operator queue rather than into the batch. A model never writes an order.
Build

Phases

Ordered by dependency — each phase is useful on its own, and nothing writes an order until phase 4.

00

Define the intake template

A real order-intake sheet: sender, receiver, phone, address, item, quantity, requested date, collect-cash. Published as a downloadable template from the console so the weekly file is generated against a known contract instead of being whatever someone exported.

GateNothing else starts until the column list is agreed and a sample week exists.
01

Parser and validator, dry-run only

  • Pure module beside opsAnalysis.js, same testing approach
  • Per-row result: ok / needs-review / rejected, each with a reason
  • Reuses the existing scanDataQuality findings
GateRun a real week through it and read the report. Zero writes.
02

Customer resolution

  • Deterministic first: exact phone match against gettenantcustomers
  • Agent second, only for what did not match exactly
  • Every proposal carries confidence + rationale; below threshold goes to the queue
GateMeasure match accuracy on a known week before it influences anything.
03

Review and commit screen

  • Proposed batch shown as a table: resolved customer, address, charge, flags
  • Operator picks pickup location and slot — the values the sheet cannot supply
  • One commit button, posting to orders/createorders
GateThis is the first phase that creates real orders. Ship it behind a role check.
04

Scheduling and idempotency

  • Weekly trigger: watched folder, mailbox, or an upload endpoint — see decision 3
  • Run key per row = hash(tenant, week, receiver phone, address, item). Persisted.
  • A replayed file is a no-op. The endpoint has no dedupe of its own, so this layer must.
GateDeliberately re-run last week’s file and confirm zero new orders.
05

Supervised autonomy

  • Auto-commit only rows that are fully resolved, unflagged and above threshold
  • Anything else waits in the queue; the operator gets a digest, not a surprise
  • Kill switch, and an audit row per created order naming the run that made it
GateEnable only after several consecutive clean weeks at phase 4.
Risk

What will go wrong, and the guardrail for each

RiskWhy it is real hereGuardrail
Duplicate ordersThe same file re-sent, or a retry after a timeout. createorders does not dedupe.Persisted run key per row; replay is a no-op.
Wrong customerFuzzy matching on names like HAMEEZ RAMEEZ with trailing spaces, and two scripts for one locality.Exact phone match first; agent proposals below threshold never auto-commit.
Bad geocodeAddresses carry plus-codes and free text; the store itself resolves to two precisions.Reject rows whose coordinates fall outside the tenant’s service radius.
Wrong slot / dateThe deliverydate timezone defect is unresolved and reads 5½ hours early.Operator sets the slot per batch; never inherit a date from the sheet until the backend is fixed.
Silent field driftAlready observed: the API sends ridername/deliverycharges, the export writes rider/deliverycharge. Both fail as blanks and zeros, not errors.Validate the parsed shape and fail loudly on an unknown or missing column.
Blocked on you

Decisions needed before phase 0

  1. What is actually in the weekly file? Recurring standing orders for the same customers, or a fresh list each week? The first makes customer resolution nearly free; the second makes it the hard part.
  2. One pickup location, or several? This tenant has two — Bawa Medical (King Nagar) and Bawaa Medicals 2 (Weavers Colony). If a single file mixes both, it needs a sender column per row rather than one choice per batch.
  3. How does the file arrive? Operator upload in the console is simplest and needs no new infrastructure. A watched folder or mailbox is more automatic and more to build and secure.
  4. Where does the agent run? Still open from before: inside backend_jupiter, or a separate DailyGrubs service it calls. Nothing in phases 0–1 depends on the answer, so building can start regardless.
  5. Who may commit a batch? Auth in this console is localStorage and the route guards are currently commented out. A screen that creates real orders needs that settled first.