Nandini · Operations Flow Diagrams

Animated walkthrough — Order · Wallet · COD · Delivery completion. ✅ implemented · ⚠️ partial · ❌ missing

Order placement → assignment

Customer browses → checkout → backend assigns to nearest distributor
🛒
Add to cart
CartContext on RN
CartSheet on web
CLIENT
💳
Checkout
Slot · Address · Coupon · Pay mode
CLIENT
📡
POST /api/orders
orderController.createOrder
API
📝
Order created
status: PENDING
orderType: B2C
DB
⚠️
🎯
Route to distributor
order.distributor = nearest depot
ASSIGN
⚠️
🔔
Notify distributor
push / socket event
polling only today
NOTIFY
POLLING

Current step

Click ▶ Play or Step ▸ to walk the flow.

Code reference

Files in play

The data lifecycle is anchored in three files:

nandani-be/src/controllers/orderController.js
nandani-be/src/models/Order.js
nandani-be/src/controllers/distributorController.js
Active stage (animating) Completed step Pending step ✅ implemented · ⚠️ partial · ❌ missing

Wallet — top-up, spend, settle, refund

Embedded ledger in User.distributorProfile.walletTransactions[]
💼
Open wallet
Distributor sees balance + ledger
SCREEN
Top-up via Razorpay
recordCreditPayment()
razorpay_payment_id stored
PAYMENT
💰
walletBalance += amount
+ txn type: TOPUP
LEDGER
📦
B2B order placed
createB2BOrder()
SPEND
📉
Deduct wallet first
walletBalance -= n
creditUsed += spillover
LEDGER
🏦
Credit on B2C DELIVERED
No earnings settled today
GAP
MISSING
⚠️
↩️
Refund on cancel
Razorpay refund API
+ REFUND txn
REVERSAL

Live ledger preview

Razorpay top-up · rzp_pmnt_8X4.. TOPUP +₹10,000 bal ₹10,000
B2B order #ORDER37 · 120 × Milk 500ml ORDER −₹6,840 bal ₹3,160
B2C delivery commission (proposed) SETTLE +₹38 bal ₹3,198
Cancellation refund · #ORDER41 REFUND +₹420 bal ₹3,618

Current step

Click ▶ Play to animate top-up → spend → settle → refund.

Schema reference

Where this lives

The ledger is embedded on the distributor's user document:

User.distributorProfile.walletBalance: Number
User.distributorProfile.creditUsed: Number
User.distributorProfile.walletTransactions: [{amount,type,balanceAfter,...}]

COD cash reconciliation

Distributor collects cash on delivery → marks collected → settled to platform on payout day
📝
Order created · COD
paymentMethod: COD
paymentMode: CASH
DB
🚚
Out for delivery
Distributor en route
or rider en route
STATUS
⚠️
💵
Collect cash at door
Customer pays in person
PHYSICAL
Mark "Cash received"
PATCH /payment-collected
order.paymentCollected = true
NEW
PROPOSED
🎯
Mark delivered
status: DELIVERED
timeline.deliveredAt
STATUS
Post-delivery
🧾
Auto-invoice
Invoice.create on DELIVERED
NEW
💰
Cash held in wallet
walletBalance -= cashHeld
(distributor owes platform)
NEW
🏦
Daily settlement
Cron: cashHeld → 0
Settlement record
CRON
📊
Admin reconciles
/dashboard/settlements
UI

Current step

Watch the cash journey — from customer's pocket → distributor's wallet → platform settlement.

What's missing today

Add to Order schema

The COD reconciliation hinges on three new fields plus a settlement job:

order.paymentCollected: Boolean
order.paymentCollectedAt: Date
Settlement model: cashHeld, settledAt, distributor, period

Delivery completion — self vs rider

Order PENDING → CONFIRMED → PREPARING → OUT_FOR_DELIVERY → DELIVERED with OTP, notifications & payout
📥
PENDING
Order lands on distributor screen
STATUS
CONFIRMED
"Accept order" tapped
STATUS
📦
PREPARING
"Start packing"
STATUS
⚠️
👤
Pick delivery
"Me (self)" or roster rider
not enforced today
CHOICE
🔢
OTP generated
6-digit · sent to customer
order.deliveryOtp
NEW
PROPOSED
🚚
OUT_FOR_DELIVERY
"Mark ready for pickup"
STATUS
Self-delivery branch
📍
Live location ping
Every 30s while en route
NEW
🔓
Verify customer OTP
Customer reads code
POST /verify-delivery-otp
NEW
💵
Cash collected? (COD)
paymentCollected = true
NEW
⚠️
🎯
DELIVERED
timeline.deliveredAt set
currently nothing else fires
STATUS
SUCCESS
🧾
Invoice + wallet + notify
Auto-invoice
+₹commission to wallet
customer push
NEW
Rider branch
📲
Rider sees order
DeliveryList screen
STATUS
⚠️
📍
Rider location
Geolocation service
not yet pushed to backend
PARTIAL
🔓
Rider OTP
DeliveryOtp screen exists
SCREEN
⚠️
🎯
DELIVERED (rider)
Status update only
STATUS
Failure paths
⚠️
Customer not reachable
DELIVERY_FAILED status
+ attempt log
NEW
🔁
Reschedule
Pick new slot · max 3 tries
NEW
↩️
RETURNED
Refund + notify
STATUS

Current step

Hit Play to watch a full happy-path delivery, then see where the rider branch and failure path diverge.

Implementation map

17 stages, ~6 ✅, ~3 ⚠️, ~8 ❌

Today the status pipeline works end-to-end but nothing fires around it. The 8 ❌ stages need:

order.deliveryOtp + verify endpoint
order.paymentCollected + PATCH endpoint
order.liveLocation { lat,lng,at } + ping endpoint
DELIVERY_FAILED + attempts[] in status enum
Auto-invoice + walletTransaction on DELIVERED
createNotification() inside updateAssignedOrderStatus
Active stage Done Pending Branches play sequentially: main → self → rider → failure