Step-by-Step Guide — Follow each step exactly as written. All values are provided — do not improvise.
TC-BIL-007: Discounts, Adjustments & Void (Detailed)
Module: Billing & Invoicing — Discounts / Void
Primary Test User: treasurer@demo.membervu.com / Treasurer123! (Finance Manager)
Priority: P1
URLs for this test:
Frontend:
Admin invoices:
API base:
Frontend:
https://stg-rcme.membervu.com/loginAdmin invoices:
https://stg-rcme.membervu.com/admin/invoicesAPI base:
https://stg-api.membervu.com/api/billing
Payment gateway is INERT on staging (Paynamics). All payment/allocation states in this TC are created via manual payment recording or direct API calls that create Invoice/Payment records only — never a live charge.
Step 1: Log in and open an OUTSTANDING invoice
| Step | Action (EXACT clicks/typing) | Expected Result (EXACT text/behavior) | Test Value |
|---|---|---|---|
| 1 | Go to https://stg-rcme.membervu.com/login; sign in. | Dashboard loads. | treasurer@demo.membervu.com / Treasurer123! |
| 2 | Sidebar → Finance → Invoices. | Split-view invoice list loads. | — |
| 3 | Filter Status = Outstanding. Click a DUES-source invoice (e.g. an RCME-DUES-00xx row) that has no existing payments. | Detail panel opens on the right showing amountCents, status, source. | Note the exact amountCents shown, e.g. ₱15,000.00 |
Step 2: Apply a PERCENTAGE discount (BIL7-01)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Click the invoice's actions menu → Apply Discount (ApplyDiscountModal). | Modal opens with a discount-type toggle (FIXED / PERCENTAGE), a value field, a reason field, and a live preview of the resulting net amount. | — |
| 2 | Select PERCENTAGE, enter a value, enter a reason. | Live preview shows resulting net = amountCents − (amountCents × 10%) exactly. | Value 10 (%) · Reason QA BIL-007 percentage discount |
| 3 | Submit. | POST /api/billing/admin/invoices/:invoiceId/discount returns 200. Invoice detail refreshes. | — |
Data assertion: the invoice's balance/amount due must equal the ORIGINAL amount minus EXACTLY 10% (e.g. ₱15,000.00 → ₱13,500.00, not ₱13,499.xx or a rounded-off figure). A visible discount line or badge shows the discount reason and either the original amount or the discount amount — record which of the two the UI actually shows.
originalAmountCents must be preserved (recoverable from the invoice detail / audit trail) even after the discount is applied.
Step 3: Apply a FIXED discount on a second invoice (BIL7-02)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Open a second OUTSTANDING invoice with no existing payments. Apply Discount → select FIXED. | Field now expects a peso amount (major units), not a percent. | Value 500 (₱500.00) |
| 2 | Enter reason, submit. | 200; balance drops by EXACTLY ₱500.00 (50000 cents) — not approximated. | Reason QA BIL-007 fixed discount |
Step 4: Fully-discount an invoice to ₱0 — still listed (BIL7-03)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Open a third small-amount OUTSTANDING invoice (or use one of the above after further discounting). Apply a discount that brings the balance to exactly ₱0.00 — FIXED equal to the full amountCents, or PERCENTAGE = 100. | Submit succeeds; invoice net amount = 0. | FIXED = full invoice amount, or PERCENTAGE 100 |
| 2 | Navigate back to the invoice list (all filters cleared, or filtered to the invoice's known source/period). | The ₱0 invoice still appears in the list — it is NOT hidden or filtered out just because its balance is zero. | — |
| 3 | Call the list API directly (or inspect network tab). | GET /api/billing/invoices/tenant response items[] includes this invoice's id. | — |
Data assertion: count the invoices in the list before and after — the total count must be unchanged (the ₱0 invoice is present both times), and the ₱0 invoice's status is NOT silently flipped to something that would exclude it from "Outstanding" filters if its net is genuinely zero — verify its actual computed status (likely
PAID if discount-to-zero is treated as settled) rather than assuming.
Step 5: Discount cap ignores a PENDING allocation (BIL7-04)
This is a money-correctness assertion — do not skip. The point: a payment that hasn't settled (still PENDING/UNDER_REVIEW admin review) must not count as "already paid" for discount-cap purposes.
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Pick a fresh OUTSTANDING invoice, e.g. ₱10,000.00. As a member (or admin recording on the member's behalf), submit a manual bank-transfer payment with proof for ₱6,000.00, but do not approve it yet. | Payment record created with status PENDING/UNDER_REVIEW (awaiting approval). Invoice balance is UNCHANGED (still shows ₱10,000.00 outstanding) because the allocation isn't settled. | Amount ₱6,000.00 |
| 2 | As Finance Manager, attempt to apply a discount that would bring the invoice's net BELOW ₱6,000.00 (e.g. a FIXED discount of ₱5,000.00, leaving ₱5,000.00 net). | Request succeeds (200) — because the pending ₱6,000.00 is NOT counted as "already paid", there's no ₱6,000.00 floor to violate. | Discount ₱5,000.00 → net ₱5,000.00 |
| 3 | Reset: pick another fresh invoice, ₱10,000.00. Record and this time approve a manual payment of ₱6,000.00 (status becomes settled/SUCCEEDED). | Invoice balance now correctly shows ₱4,000.00 outstanding. | — |
| 4 | Attempt the same discount (net below ₱6,000.00, e.g. down to ₱5,000.00). | Request is rejected — 409 CONFLICT — because the resulting net (₱5,000.00) would fall below the SETTLED amount already paid (₱6,000.00). This is R-FIN-001. | — |
Step 6: Void an invoice from each source (BIL7-05 / 06 / 07)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Open a DUES-source invoice with no payments at all. Actions menu → Void Statement. Enter a reason. | Button is visible (source no longer restricts it). POST /api/billing/admin/invoices/:invoiceId/void → 200. Status becomes VOID. | Reason QA BIL-007 void dues |
| 2 | Repeat on an EVENT-source invoice (created from an event registration) with no payments. | Same endpoint succeeds — 200, status VOID. No source-based rejection. | Reason QA BIL-007 void event |
| 3 | Repeat on a manually-created (OTHER/manual) invoice with no payments. | Same endpoint succeeds — 200, status VOID. | Reason QA BIL-007 void manual |
Step 7: Void is blocked on a SUCCEEDED payment, regardless of source (BIL7-08)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Open the invoice from Step 5.3 (has an approved/SUCCEEDED ₱6,000.00 manual payment). | Look for the Void action. | — |
| 2 | Observe whether the Void button is present at all in the UI. | Known UI/backend drift: the frontend action list hides "Void Statement" whenever the invoice has any payment record (hasPayments, even a rejected/pending one) — stricter than the backend, which only blocks on a SUCCEEDED allocation. Record whether the button is hidden here. | — |
| 3 | If the UI exposes it (or via direct API call), attempt POST .../void on this invoice. | Backend rejects with 400 — "Cannot void invoice with existing payments. Please process refunds first." The invoice status remains unchanged (NOT VOID). | — |
CLEANUP
- The invoices voided in Step 6 remain
VOIDpermanently by design — no action needed, but note their invoice numbers in your test log so they aren't mistaken for genuinely cancelled member obligations. - Reject or leave-pending the throwaway ₱6,000.00 manual payment from Step 5.1 if it was never meant to be a real settlement (or approve/reject per your test data conventions).
- Discounted invoices from Steps 2–4 are permanent adjustments on seed data — flag to the test lead if the seed needs a reset before the next full regression pass.