Packages

A package is one physical parcel — the unit that actually gets sealed, handed to a carrier, and tracked to delivery. This page tracks every package's journey and lets you record what happens to it after it leaves the warehouse.

Where packages come from

Packages are created as part of picking-wave preparation (packing a wave's stock moves into physical parcels) — there is no create button here. Most packages reach Despatched in bulk, the moment their wave is despatched — see the cascade explained on the Picking Waves page. This page is where you track each package individually from that point on, and seal it beforehand.

Where to find it & who can see it

Open Despatch › Packages in the left navigation. The list is visible to anyone holding package.view (or a super administrator). It is index/view-only — no create or edit form. Each row has a View action showing the package's Contents and its GPS tracking trail (both described below), plus its other row actions.

The package lifecycle

A package can be in one of nine states. Only four transitions are driven from this screen; getting to Despatched normally happens automatically when its wave is despatched.

Columns

ColumnShows
package_numberThe package's identifying number, shown as a badge. Searchable and sortable.
Customercustomer.profile.full_name — who the package is addressed to.
Carriercarrier.name — the delivery carrier handling this package.
tracking_numberThe carrier's tracking reference. Searchable.
StateA coloured badge — see the diagram above for the colour key.
is_codA tick/cross icon — whether this is a Cash on Delivery (COD) package (see below).
cod_receivedA tick/cross icon — whether the COD cash-on-delivery amount for this package has been confirmed received.

The list defaults to newest first (created_at desc).

Filters

FilterWhat it narrows
StateAll nine PackageState values: Draft, Packing, Sealed, Labeled, Despatched, Delivered, Returned, Lost, Cancelled. Filtering on Sealed is how you find packages that are closed up but whose label has not been recorded yet.
is_codA three-way yes / no / all toggle to isolate Cash on Delivery packages from ordinary ones.
Screenshot placeholderThe Packages list showing Package Number, Customer, Carrier, Tracking Number, State, and the two COD icon columns, with the State and is_cod filter panel open.

Actions

Permissions

All four actions below need package.track, in addition to package.view to see the list.

  1. Seal — Draft or PackingSealed Confirmation required

    Use this once a package is physically packed and ready to be closed up. Confirming calculates and stores the package's postage_cost automatically (via the postage calculator, based on weight/carrier/destination) — you do not enter a postage figure yourself.

  2. Mark labelled — SealedLabeled Confirmation required

    Records that the package's address label has been printed and applied. Only appears on a package currently Sealed. It changes nothing else — no postage is recalculated and no stock is touched.

    This step is optional. Despatching a wave sweeps up every one of its packages that has not already been delivered, returned, lost or cancelled — whether or not it was marked labelled. Use it when you want the labelling step on the record, and use the State filter on Sealed to see which packages are still waiting on a label.

  3. Record delivery — DespatchedDelivered, Returned or Lost

    Only appears once a package is Despatched. Unlike most actions in this console, it opens a form directly rather than a plain confirmation dialog:

    FieldTypeRequiredNotes
    delivery_stateSelect — Delivered / Returned / LostYesThe outcome you are recording; the package's state moves to whichever you choose. Choosing Delivered also closes the package's stock moves: any move whose every part has now been delivered moves to Done. A move split across several packages waits until the last of them is delivered. Returned and Lost still leave the stock moves untouched — stock is not automatically put back for a return, and no write-off is raised for a loss; both still need handling by hand. Recording Delivered can also complete the whole sale order — see below.
    return_reasonTextareaNoFree text — typically filled in when recording a Returned outcome, but the form does not enforce this.
    delivery_notesTextareaNoAny additional context about the delivery attempt.
  4. Mark COD received Confirmation required

    Only shown when the package is COD and has not yet been marked received. It does not change the package's state — it simply sets cod_received to true, recording that the cash the carrier collected on delivery has come back to AIR (usually because it was reconciled through a payment lot — see below).

Recording the last delivery completes the sale order for you

When you mark a package Delivered, the portal checks the parent sale order: if that was the last outstanding delivery on it — every delivery move for the order is now either Done or Cancelled — the order moves itself from In Despatch to Completed. Nobody has to close it by hand, and the change is written to the order's own state log with your name against it, exactly as a manual completion would be.

Anything still outstanding holds the order open — a move that is still Reserved, Shipped or Suspended all count as outstanding. So an order with a held part stays In Despatch until that part is either despatched and delivered or cancelled. If an order you expected to close is still sitting in In Despatch, look for its unfinished moves on Stock Moves.

What is inside a package Built

Open a package row's View action and the first tab is Contents — the list of stock moves packed into that parcel. It needs only package.view, the same permission as the list itself. It is read-only: contents are written when the wave's packages are generated (see Picking Waves), never edited here.

ColumnWhat it means
MoveThe stock move's reference (MOV-…). Searchable.
ProductThe product being shipped. Searchable.
In this packageHow much of that move is in this parcel.
Move totalHow much the move authorises altogether. When it is larger than In this package, the row is annotated Partially packed — the difference has not been packed yet, and is either in another package or still waiting to be packed.
Move stateThe stock move's own state badge — see Stock Moves.
A package can hold part of a move — and a move can be split across packages

A stock move used to live in exactly one package. It no longer does: a move can be split, so that part of it ships now and the rest ships later, in a different parcel with its own tracking number. That is why In this package and Move total are two separate columns.

In practice, package generation still packs whole moves today, so the two figures will normally match — nothing yet decides to pack a part-quantity automatically. The machinery for a split shipment is in place; what is not in place is anything that chooses to make one on its own.

When a move is split, each parcel decrements only the stock it actually carries at despatch, and the move is only marked Shipped once all of it has gone. The unshipped remainder stays reserved.

Understanding COD

Cash on Delivery (COD) means the customer pays for the goods in cash at the point of delivery — to the postman on an India Post despatch, or to the courier rider — rather than in advance. AIR uses it for certain despatches. A COD package therefore carries a cash liability until that money is actually banked and confirmed — which is why is_cod and cod_received are separate flags, and why Mark COD received exists independently of the delivery outcome itself. The cash from many COD packages is banked together and reconciled in batches — see COD Payment Lots for how that reconciliation works, and note that Mark COD received here can also happen automatically as part of a lot's Reconcile step.

Bulk actions

There are none — packages are actioned one row at a time.

Delivery tracking (GPS) & hand-delivery proof Built

Every despatched package can accumulate a trail of GPS-stamped tracking events — captured by the SE (or hand-delivery carrier) in the field via the Flutter app, not typed in here. The HO console shows this trail read-only: open a package row's View action to see the GPS tracking trail relation manager. It requires delivery_tracking.view — a package.view-only user sees the package but not this tab.

API — recording and reading the trail

Method & pathPermissionPurpose
POST /api/v1/delivery-tracking-logs delivery_tracking.create Record one GPS event. Body: package_id, event_type (pickup / in_transit / attempted / delivered / returned), latitude (-90..90), longitude (-180..180), optional accuracy_meters, device_info, notes. captured_by and captured_at are set server-side from the authenticated actor and the current time — they cannot be supplied by the client. Returns 201 with the created log. Rejected with 422 if the package is Draft or Cancelled — events can only be logged for a despatchable package.
GET /api/v1/packages/{package}/tracking-logs delivery_tracking.view Lists a package's tracking logs oldest-first (captured_at ascending), each with the capturing user eager-loaded. This is the same data the HO relation manager renders (sorted the same way).

The hand-delivery completion rule

Both pieces of evidence are required — not either/or

When Record delivery is used to mark a package Delivered and its carrier's type is hand_delivery, the transition is blocked with 422 unless both are already on file: a tracking log with event_type = delivered for that package, and a package attachment with category = delivery_challan. Courier / India Post / transport packages are unaffected — this rule only applies to the hand-delivery carrier type.

delivered_at (whether defaulted to "now" or supplied explicitly on the Record delivery form) can no longer be a future timestamp — the request is rejected with 422 if it is after the current time.

Proof is preserved once a package reaches a terminal state (US-INV-67)

A package attachment can no longer be deleted once its package is Delivered, Returned, or LostDELETE /api/v1/packages/{package}/attachments/{attachment} returns 422 for a package in any of these three states. This locks the delivery-challan (and any other) evidence in place permanently once the delivery outcome is settled; attachments can still be freely added or removed while the package is in an earlier state.

Related pages

See Picking Waves for how packages reach Despatched in bulk, COD Payment Lots for how COD cash collected on delivery is banked and reconciled, and Attachments for the delivery-challan / proof-of-delivery upload API referenced above.