Skip to content

feat(whatsapp): add shopper help and post-purchase actions - #664

Merged
onerandomdevv merged 2 commits into
devfrom
codex/feat-whatsapp-shopper-post-purchase-actions
Jul 26, 2026
Merged

feat(whatsapp): add shopper help and post-purchase actions#664
onerandomdevv merged 2 commits into
devfrom
codex/feat-whatsapp-shopper-post-purchase-actions

Conversation

@onerandomdevv

@onerandomdevv onerandomdevv commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds the final WIZZA shopper help and post-purchase actions for linked accounts. WIZZA can now prepare eligible disputes with an explicit one-time confirmation, read the shopper's current dispute status, and report real buyer-refund settlement status through canonical order/dispute services. Ineligible or expired dispute requests are directed to Twizrr support without changing store-management behavior.

Type of change

  • New feature
  • Bug fix
  • Refactor / cleanup
  • Database migration included
  • Chore / maintenance
  • Documentation

Area affected

  • Backend
  • Web
  • WhatsApp
  • Shared package
  • Database / Prisma
  • GitHub / CI / infrastructure

How to test this

  1. Link a shopper account to WhatsApp and ask WIZZA to open a dispute for an eligible delivered order, including a factual reason and description.
  2. Confirm the request and verify that the canonical dispute service opens it only once; repeat the confirmation and verify that it reports an expired request.
  3. Ask for the dispute status and refund status for a shopper-owned order, then try an unknown or ineligible order.

Expected result: eligible dispute requests require explicit confirmation, duplicate confirmations cannot create duplicate disputes, status responses use real domain data, and unsupported/ineligible cases return safe guidance without exposing provider, store, or fulfillment internals.

Pre-commit checklist

  • Backend lint/type/build pass when backend is affected
  • Web lint/type/build pass when web is affected (N/A: no web files changed)
  • Shared package build passes when shared is affected (N/A: shared package unchanged)
  • No console.log left in production code
  • No secrets or .env files committed
  • No new any types added
  • No non-MVP legacy features reintroduced
  • All money values are BigInt kobo, never float
  • Paystack webhook changes verify HMAC before processing (N/A: webhook unchanged)
  • Database migrations are Prisma migrations, not db push (N/A: no migration)
  • Database migrations are backward-compatible or risk is documented (N/A: no migration)

Screenshots

N/A. Backend and WhatsApp behavior only.

Notes for reviewer

Runtime behavior

  • Added typed start_dispute, get_dispute_status, and get_refund_status shopper-agent tools.
  • Dispute creation requires an active linked account, canonical order ownership and eligibility checks, and explicit Confirm/Cancel input.
  • Pending dispute requests use short-lived Redis state and are consumed with getDel before the write, preventing confirmation reuse.
  • Dispute and refund reads use canonical domain methods scoped directly to the linked buyer.
  • Latest-order fallback includes only DIRECT and DROPSHIP_CUSTOMER orders, excluding private linked fulfillment orders.
  • Refund output contains only the shopper-facing order code, normalized buyer-refund status, and formatted amount. Provider references, supplier/store internals, and counterparty payout amounts remain private.
  • Orders outside the dispute policy or window receive a support handoff. Store administration remains unsupported in WhatsApp.

Validation

  • Focused Jest: 6 suites, 233 tests passed.
  • Touched-file backend ESLint: passed.
  • Backend typecheck: passed.
  • Backend build: passed.
  • Prisma validate: passed.
  • git diff --check: passed.
  • git diff --cached --check: passed.
  • Staged secret, environment-file, migration/schema, private-prompt, and shopper-output scans: passed.
  • Normal pre-commit hook completed successfully.

No schema/migrations, checkout/cart/payment behavior, payout math, delivery/Shipbubble behavior, product search/ranking, image search, public product URLs, web routes, store management, .env.local, secrets, or private prompt values were changed.

Summary by CodeRabbit

  • New Features

    • Added WhatsApp support for opening disputes after shopper confirmation.
    • Added dispute status and refund status lookups, including order references and formatted refund amounts.
    • Added eligibility checks, ownership validation, duplicate-dispute protection, and pending confirmation handling.
    • Improved intent recognition for dispute and refund requests.
  • Bug Fixes

    • Restricted shopper-visible responses to safe, relevant information and excluded internal or provider details.
  • Tests

    • Added comprehensive coverage for dispute, refund, routing, confirmation, authorization, and output safety flows.

@codesandbox

codesandbox Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
twizrr-web Ready Ready Preview, Comment Jul 26, 2026 9:20pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
twizrr-admin Skipped Skipped Jul 26, 2026 9:20pm
twizrr-app Skipped Skipped Jul 26, 2026 9:20pm

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@onerandomdevv, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 138ee6fe-3961-49d1-8b1e-c75dd97b5e3d

📥 Commits

Reviewing files that changed from the base of the PR and between 08ef9af and dd63709.

📒 Files selected for processing (2)
  • apps/backend/src/domains/orders/order/order.service.spec.ts
  • apps/backend/src/domains/orders/order/order.service.ts
📝 Walkthrough

Walkthrough

Adds WhatsApp shopper-agent support for starting disputes, checking dispute status, and checking refund status, including buyer authorization, Redis-backed confirmation handling, safe output validation, deterministic routing, service wiring, and tests.

Changes

WhatsApp post-purchase dispute and refund flows

Layer / File(s) Summary
Tool contracts and deterministic routing
apps/backend/src/channels/whatsapp/agent/*, apps/backend/src/channels/whatsapp/whatsapp-intent.service.*
Adds tool types, definitions, input normalization, safe output validation, and keyword fallback routing for dispute and refund operations.
Buyer-scoped dispute and order access
apps/backend/src/domains/orders/dispute/dispute.service.ts, apps/backend/src/domains/orders/order/order.service.*
Adds buyer-specific dispute opening and visibility methods, explicit buyer authorization, buyer-based event attribution, and latest-order lookup.
Post-purchase preparation and status service
apps/backend/src/channels/whatsapp/whatsapp-post-purchase.service.*, apps/backend/src/channels/whatsapp/whatsapp.constants.ts, apps/backend/src/channels/whatsapp/whatsapp.module.ts
Implements dispute preparation, Redis-backed confirmation state, pending reply consumption, dispute status, refund status formatting, error handling, and module wiring.
WhatsApp message and tool orchestration
apps/backend/src/channels/whatsapp/whatsapp.service.*
Routes post-purchase tools, processes pending confirmations before normal intents, sends confirmation controls, and returns shopper-safe dispute/refund responses.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Shopper
  participant WhatsAppService
  participant WhatsAppIntentService
  participant WhatsAppPostPurchaseService
  participant RedisService
  participant DisputeService

  Shopper->>WhatsAppService: Send dispute request
  WhatsAppService->>WhatsAppIntentService: Parse shopper intent
  WhatsAppIntentService-->>WhatsAppService: Return start_dispute
  WhatsAppService->>WhatsAppPostPurchaseService: prepareDispute
  WhatsAppPostPurchaseService->>RedisService: Store pending dispute
  WhatsAppPostPurchaseService-->>WhatsAppService: confirmation_required
  WhatsAppService-->>Shopper: Send confirm/cancel controls
  Shopper->>WhatsAppService: Confirm dispute
  WhatsAppService->>WhatsAppPostPurchaseService: handlePendingReply
  WhatsAppPostPurchaseService->>RedisService: Consume pending dispute
  WhatsAppPostPurchaseService->>DisputeService: openBuyerDispute
  WhatsAppService-->>Shopper: Send dispute result
Loading

Possibly related PRs

  • coded-devs/twizrr#408: Tightens WhatsApp tool routing and protected-topic handling for dispute/refund requests.
  • coded-devs/twizrr#656: Introduces the shopper-agent tool registry and orchestration foundation extended by these tools.
  • coded-devs/twizrr#660: Extends the WhatsApp linked-shopper read execution path used here for dispute and refund status.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main WhatsApp shopper help and post-purchase feature work.
Description check ✅ Passed The description matches the template sections and includes a clear summary, testing steps, checklist, screenshots, and reviewer notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/feat-whatsapp-shopper-post-purchase-actions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/backend/src/domains/orders/dispute/dispute.service.ts (1)

185-259: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate order-fetch + eligibility orchestration between openBuyerDispute and assertBuyerCanOpenDispute.

Both methods independently: fetch the order via prisma.order.findUnique with the same include, call assertBuyerOwnsOrder/assertOrderCanBeDisputed, and re-run the "existing active dispute" findFirst. The underlying business rules stay centralized (both call the same shared assertion helpers), so there's no correctness-drift risk today, but this is two DB round-trips per shopper action (once during WhatsApp confirmation staging, once again at confirm-time) and ~35 lines of duplicated orchestration that will need to be kept in sync if the eligibility flow gains steps later (e.g., an additional guard).

Consider extracting a shared private helper (e.g., loadDisputableOrder(orderId, buyerId): Promise<OrderForDispute>) that both openBuyerDispute and assertBuyerCanOpenDispute call.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/domains/orders/dispute/dispute.service.ts` around lines 185
- 259, Extract the duplicated order-loading and dispute-eligibility
orchestration from openBuyerDispute and assertBuyerCanOpenDispute into a shared
private helper such as loadDisputableOrder(orderId, buyerId). Have the helper
fetch the order, apply assertBuyerOwnsOrder and assertOrderCanBeDisputed, and
reject active disputes; then have both public methods reuse it while preserving
each method’s existing transaction and return behavior.
apps/backend/src/channels/whatsapp/whatsapp.service.spec.ts (1)

1679-1793: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for get_dispute_status and the ineligible/cancel dispute paths.

Current new tests cover get_refund_status (read), start_dispute happy-path confirmation, and pending-confirmation success, but not get_dispute_status, nor the branch where prepareDispute returns confirmationButtons: false (ineligible/expired → plain-text/support redirect), nor a "cancel" pending-reply outcome.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/channels/whatsapp/whatsapp.service.spec.ts` around lines
1679 - 1793, Extend the WhatsApp service tests around the existing refund and
dispute cases to cover get_dispute_status with shopper-safe output and message
delivery, prepareDispute returning confirmationButtons: false with the expected
plain-text/support redirect, and handlePendingReply returning the cancel outcome
with the corresponding response. Reuse the existing setup and assertions for
user, phone, intent, and service calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/src/domains/orders/order/order.service.ts`:
- Around line 1879-1897: Update getLatestByBuyer to filter out PENDING_PAYMENT,
CANCELLED, and other non-actionable or terminal order statuses, selecting the
most recent order that can still support dispute or refund-status flows.
Preserve the existing buyer, order-type, ordering, and selected fields.

---

Nitpick comments:
In `@apps/backend/src/channels/whatsapp/whatsapp.service.spec.ts`:
- Around line 1679-1793: Extend the WhatsApp service tests around the existing
refund and dispute cases to cover get_dispute_status with shopper-safe output
and message delivery, prepareDispute returning confirmationButtons: false with
the expected plain-text/support redirect, and handlePendingReply returning the
cancel outcome with the corresponding response. Reuse the existing setup and
assertions for user, phone, intent, and service calls.

In `@apps/backend/src/domains/orders/dispute/dispute.service.ts`:
- Around line 185-259: Extract the duplicated order-loading and
dispute-eligibility orchestration from openBuyerDispute and
assertBuyerCanOpenDispute into a shared private helper such as
loadDisputableOrder(orderId, buyerId). Have the helper fetch the order, apply
assertBuyerOwnsOrder and assertOrderCanBeDisputed, and reject active disputes;
then have both public methods reuse it while preserving each method’s existing
transaction and return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 33a2dc07-867b-4aae-923b-2857af561af2

📥 Commits

Reviewing files that changed from the base of the PR and between b6c1903 and 08ef9af.

📒 Files selected for processing (14)
  • apps/backend/src/channels/whatsapp/agent/shopper-agent-tool.registry.spec.ts
  • apps/backend/src/channels/whatsapp/agent/shopper-agent-tool.registry.ts
  • apps/backend/src/channels/whatsapp/agent/shopper-agent.types.ts
  • apps/backend/src/channels/whatsapp/whatsapp-intent.service.spec.ts
  • apps/backend/src/channels/whatsapp/whatsapp-intent.service.ts
  • apps/backend/src/channels/whatsapp/whatsapp-post-purchase.service.spec.ts
  • apps/backend/src/channels/whatsapp/whatsapp-post-purchase.service.ts
  • apps/backend/src/channels/whatsapp/whatsapp.constants.ts
  • apps/backend/src/channels/whatsapp/whatsapp.module.ts
  • apps/backend/src/channels/whatsapp/whatsapp.service.spec.ts
  • apps/backend/src/channels/whatsapp/whatsapp.service.ts
  • apps/backend/src/domains/orders/dispute/dispute.service.ts
  • apps/backend/src/domains/orders/order/order.service.spec.ts
  • apps/backend/src/domains/orders/order/order.service.ts

Comment thread apps/backend/src/domains/orders/order/order.service.ts
@vercel
vercel Bot temporarily deployed to Preview – twizrr-admin July 26, 2026 21:19 Inactive
@vercel
vercel Bot temporarily deployed to Preview – twizrr-app July 26, 2026 21:19 Inactive
@onerandomdevv
onerandomdevv merged commit 6e8f722 into dev Jul 26, 2026
14 checks passed
@onerandomdevv
onerandomdevv deleted the codex/feat-whatsapp-shopper-post-purchase-actions branch July 26, 2026 21:23
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