Skip to content

Feat/order cod - #656

Merged
mnindrazaka merged 16 commits into
mainfrom
feat/order-cod
Sep 26, 2026
Merged

mnindrazaka merged 16 commits into
mainfrom
feat/order-cod

Conversation

@mnindrazaka

Copy link
Copy Markdown
Collaborator

No description provided.

mnindrazaka and others added 15 commits September 26, 2026 17:20
* docs: add PRD for order-app cash on delivery payment

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWw1wxmq74Dq98w5Ghu1vL

* docs: resolve open questions in COD payment PRD

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWw1wxmq74Dq98w5Ghu1vL

---------

Co-authored-by: Claude <noreply@anthropic.com>
Phase 1 of docs/prd-order-cod-payment.md: extends the OpenAPI contract
and Go domain with the cash-on-delivery vocabulary — method=cod,
verificationPhoto, verificationStatus/paymentVerificationStatus,
cancelReason=rejected — and declares the three staff verification
endpoints. ParsePaymentMethod accepts cod, but the checkout handler
rejects it with "payment method is not available yet" until the
checkout branch lands in a later phase.


Claude-Session: https://claude.ai/code/session_01EzQkGZyQsdzUu2G1DKVMVP

Co-authored-by: Claude <noreply@anthropic.com>
#643)

Implements phase 9 of docs/prd-order-cod-payment.md (FR-7): a
platform-split base component that requests the rear camera via
getUserMedia, lets the guest review and retake the shot, and hands the
confirmed frame back as a size-capped JPEG base64 string. The native
stub keeps apps/pos-mobile bundling since COD never reaches that app.


Claude-Session: https://claude.ai/code/session_01KTMhEfmyiUXXKqnMSe19gV

Co-authored-by: Claude <noreply@anthropic.com>
Migration 000044 adds payments.verification_status/verified_at and the
payment_verification_photos table; PaymentVerificationRepository stores
and sweeps the COD presence photo per the D5 invariant (a row exists iff
its payment is cod + pending + awaiting). transaction_repo.go joins
payment_verification_status alongside the existing payment_method read.

Nothing writes to the new table yet — phase 4 wires the checkout branch.


Claude-Session: https://claude.ai/code/session_01Vqw1HnFL225uRphhhDpU9R

Co-authored-by: Claude <noreply@anthropic.com>
Phase 3 of the order COD payment PRD (docs/prd-order-cod-payment.md):
KdsNotificationKindCodVerification with its own title/body, and
order_paid gains a "collect at pickup" line for a still-unpaid COD
transaction. Both bypass the station and business-day staleness rules
the same way cash_pending/cash_cancelled already do, since that bypass
is keyed on kind != order_paid in the MySQL repository. No new enqueue
site yet — that lands with the COD checkout branch (phase 4).


Claude-Session: https://claude.ai/code/session_01SVXvjLdwjZTSrhfHRoNgA8

Co-authored-by: Claude <noreply@anthropic.com>
…#644)

Implements phase 7 of docs/prd-order-cod-payment.md (FR-10): an unpaid
COD transaction's ready message now labels the payment method
"COD — bayar di kasir" and adds a line reminding the guest to bring
cash for pickup. A paid COD order, and every other method, are
unchanged.


Claude-Session: https://claude.ai/code/session_01AUYhhBca6k9Y287S2eNtBo

Co-authored-by: Claude <noreply@anthropic.com>
Extends PaymentMethod/PaymentCancelReason with cod/rejected and adds
verificationStatus to Payment/PaymentSummary per the regenerated TS
client. CheckoutUsecase gains a verificationPhoto context field plus
CAPTURE_PHOTO/RETAKE_PHOTO actions, ignoring SUBMIT_DETAILS for a cod
checkout with no photo and clearing the photo on a method change.
OrderStatusUsecase gains an awaitingVerification state that polls every
3s and resolves to preparing/ready once a cod payment is approved,
independent of its (still pending) money status.

OrderStatusHandler maps awaitingVerification onto the existing cash
variant for now (no screen changes yet), and a handful of exhaustive
PaymentMethod matches elsewhere in libs/ui pick up a cod case so the
type addition doesn't break compilation ahead of their own phases.


Claude-Session: https://claude.ai/code/session_01QRePh1AnvvXDpLGxh9U58Z

Co-authored-by: Claude <noreply@anthropic.com>
Adds the transaction-side building blocks a barista's COD verification
needs: paymentVerificationStatus on the Transaction entity, the three
verification repository methods (api + mock), and the
TransactionVerificationUsecase state machine
(hidden → loading → shown → approving/confirmingReject → rejecting →
success/error/gone). No UI yet — that's phase 13.


Claude-Session: https://claude.ai/code/session_01TGc1ksCgR2UNNKirp1cpKd

Co-authored-by: Claude <noreply@anthropic.com>
Implements FR-2 of docs/prd-order-cod-payment.md: ORDER_COD_PAYMENT_ENABLED
and COD_VERIFICATION_EXPIRY_SECONDS gate and size the cod branch in
PaymentUsecase.Checkout, which creates a pending/awaiting payment, its
verification photo row and a cod_verification KDS notification without ever
calling the DOKU gateway. Phase 1's "not available yet" checkout rejection
is replaced by the flag check, and the checkout route gains a 2 MiB
MaxBytesReader ahead of the photo's own 1 MiB decoded cap.


Claude-Session: https://claude.ai/code/session_014ZYvwZLH7AwmEHyGCLrtXv

Co-authored-by: Claude <noreply@anthropic.com>
Implements PaymentVerificationUsecase.GetVerification/Approve/Reject
(FR-4) with the payment_verification_{handler,route,transformer} under
CheckAuth, and wires it into main.go. Approve converts the cart,
deletes the photo and enqueues order_paid; Reject reuses
finalizeUncollectedPayment and deletes the photo. Both guard on a
locked payment row so they serialise against a guest cancel or the
sweeper.


Claude-Session: https://claude.ai/code/session_01SkoPPLRHFNQGMFMgo6vPsr

Co-authored-by: Claude <noreply@anthropic.com>
Implements FR-5 and FR-6 from docs/prd-order-cod-payment.md: an approved
COD payment is pending but must behave as committed, and every terminal
path deletes the verification photo.

- Payment.IsExpirable() is the single predicate the sweeper and a guest's
  own status poll ask; Payment.IsAwaitingCodVerification() is PayTransaction
  and CompleteTransaction's guard.
- GetExpirablePayments excludes an approved COD payment; expireOne's
  under-lock re-check does too, for the race where approval lands between
  the sweeper's batch read and the per-payment lock.
- CanBeCancelledBy refuses an approved COD payment, and CancelPayment now
  enforces it (D10) rather than only reporting it for the transformer.
- PayTransaction and CompleteTransaction refuse an awaiting COD payment
  with 400, writing nothing.
- finalizeUncollectedPayment deletes the COD verification photo
  unconditionally, covering reject, guest cancel, sweeper expiry,
  guest-poll expiry and supersede through their one shared function.
- DeleteOrphanedVerificationPhotos runs on the existing maintenance
  sweeper tick as the D5 backstop, warning on a non-zero count.


Claude-Session: https://claude.ai/code/session_01DVfwfmVpAqu3oGEx7Vedbc

Co-authored-by: Claude <noreply@anthropic.com>
)

Implements Phase 11 of docs/prd-order-cod-payment.md (FR-13), building on
Phase 8's awaitingVerification state machine.

- New CodVerificationView: "Menunggu konfirmasi barista..." with the
  transaction number, items, and a live countdown-derived minute count
  ("Jika tidak dikonfirmasi dalam N menit...") computed from the
  payment's expiredAt.
- OrderStatusScreen gains its own awaitingVerification variant (previously
  reused awaitingCashPayment's screen), rendering CodVerificationView with
  the existing cancel-button/confirmation plumbing.
- New PayAtPickupBanner, shown on OrderPreparingView/OrderReadyView for an
  approved-but-unpaid COD order and absent once paid.
- The cancelled variant gains the rejected copy ("Pesanan ditolak" /
  barista-could-not-confirm message) alongside the existing guest/superseded
  copy.
- OrderStatusHandler maps all COD-carrying states exhaustively and derives
  payAtPickupAmount from the payment (cod + still pending).


Claude-Session: https://claude.ai/code/session_01E9hTrybVAkM135sVq4vQQ5

Co-authored-by: Claude <noreply@anthropic.com>
… 13) (#653)

Wires the transaction-side building blocks from phase 12 into the POS
transaction list: a "Needs confirmation" badge and Verify menu item while
a COD order awaits verification, a "COD · unpaid" badge once approved,
and Pay/Mark as Ready/Delete/Print Order Slip hidden until verified.

Adds TransactionVerificationSheet (loading/shown/approving/
confirmingReject/rejecting/gone/error) driven by TransactionVerificationUsecase,
wired through TransactionListHandler and the app/pos/TransactionList
composition root so both POS web and pos-mobile pick it up.


Claude-Session: https://claude.ai/code/session_017KWqfDUh6eRgQoKhLPpPTj

Co-authored-by: Claude <noreply@anthropic.com>
* feat(ui): details sheet offers COD (phase 10)

Implements FR-8 from docs/prd-order-cod-payment.md: CustomerDetailsSheet
replaces isCashPaymentEnabled with an enabledMethods list so the picker
covers any subset of qris/cash/cod, adds the COD option and its in-sheet
CameraCapture step (disabling submit as "Ambil foto dulu" until a photo
is captured, with a retake affordance once one is), and wires the photo
through CartHandler into CheckoutUsecase's CAPTURE_PHOTO/RETAKE_PHOTO
actions. app/order/Cart.tsx now derives enabledMethods from both the
cash and COD env flags.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5S8Puhg2Pmw8Bg2jzh69p

* fix(ui): simplify COD method label per review feedback

Reuse the Wallet icon and relabel the COD option as "Cash" / "Bayar
tunai di kasir saat mengambil pesanan" instead of the jargon-heavy
"COD — Bayar saat ambil" copy, per PR review feedback on #652.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B5S8Puhg2Pmw8Bg2jzh69p

---------

Co-authored-by: Claude <noreply@anthropic.com>
* test(e2e): add COD checkout and verification specs, document phase 14

Adds order-web-e2e's cod.spec.ts (cart → COD → camera capture → awaiting
screen → API-side approve → preparing → ready) and pos-web-e2e's
transactions.codVerification.spec.ts (verify → approve → mark ready → pay →
paid, and verify → reject → row gone), driven against a fake camera device
in Chromium. Turns ORDER_COD_PAYMENT_ENABLED on for the e2e-main CI job and
NEXT_PUBLIC_ORDER_COD_PAYMENT_ENABLED on for order-web-e2e's build.

Updates docs-site (order-checkout, transactions, kds) and README with the
COD trial's guest/barista flows, env vars and production rollout steps, per
docs/prd-order-cod-payment.md phase 14.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SvLoLmweVuyKnYGoY8BkSR

* chore: revert e2e-main.yml change pending manual apply

Push access here lacks the workflow OAuth scope needed to update
.github/workflows/e2e-main.yml, so the ORDER_COD_PAYMENT_ENABLED=true
addition (needed for the new COD e2e specs to run post-merge) is reverted
from this branch. The diff is provided separately for manual application.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SvLoLmweVuyKnYGoY8BkSR

* Enable COD payment in e2e workflow

---------

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 26, 2026

Copy link
Copy Markdown

Deployment failed for project gatherloop-pos with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/m-nindra-zakas-projects-ae6b8849?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Sep 26, 2026

Copy link
Copy Markdown

Deployment failed for project gatherloop-ui-storybook with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/m-nindra-zakas-projects-ae6b8849?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Sep 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
gatherloop-order Ignored Ignored Sep 26, 2026 9:33pm UTC

@mnindrazaka
mnindrazaka merged commit be50350 into main Sep 26, 2026
5 of 7 checks passed
@mnindrazaka
mnindrazaka deleted the feat/order-cod branch September 26, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant