Skip to content

E2E SCENARIOS — QUOTE & PRICING

VietGara — Release 1.2 · Version 1.0 — September 30, 2026

Covers FR-QUO-01..04 and the daily transaction limit (FR-LIC-02) as it applies to quotes and repair orders. FR-QUO-05 (PDF export) is Release 1.4. Records are in 00_Test_Data.md §3.3; a quote’s line items and approval-mode choice have no dedicated fixtures — each scenario below creates its own.

IDTitlePriorityAutomation
E2E-QUO-001Create a draft quote with labor and part linesP1Automated (API, partial)
E2E-QUO-002Quote field validationP2Automated (API, partial)
E2E-QUO-003Edit and delete a draft; a non-draft quote cannot be edited or deletedP2Automated (API, partial)
E2E-QUO-004Send for approval (LINK mode): e-mailed automatically when the customer has an e-mail on fileP1Automated (API, partial)
E2E-QUO-005Send for approval (LINK mode): no e-mail on file, the advisor copies the linkP2Automated (API, partial)
E2E-QUO-006The customer decides each line from the public linkP1Automated (API, partial)
E2E-QUO-007The public link stops working once decided, expired or unknownP2Automated (API, partial)
E2E-QUO-008MANUAL mode: the advisor records the customer’s decision directlyP1Automated (API, partial)
E2E-QUO-009The garage’s default approval mode pre-fills a new quote; overriding it per quoteP2Automated (API, partial)
E2E-QUO-010Convert an approved quote into a repair order, preserving only approved linesP1Automated (API, partial)
E2E-QUO-011Quote number is rendered from the garage’s template and unique per garageP3Automated (API, partial)
E2E-QUO-012The daily transaction limit blocks quote creation and conversionP1Automated (API, partial)
E2E-QUO-013List and filter quotes by statusP2Automated (API, partial)
E2E-QUO-014Permissions: no access, and full accessP1Automated
E2E-QUO-015Pick a job on a quote: the labor line and the part lines appear, editableP1Automated
E2E-QUO-016A hidden consumable is not billed, not shown to the customer and not decidedP1Automated
E2E-QUO-017A hidden consumable follows its job when the quote convertsP1Automated (API)

E2E-QUO-001 · Create a draft quote with labor and part lines

Priority: P1 · Covers: FR-QUO-01 · Automation: Automated (API, partial)

Preconditions: baseline. Signed in as ADVISOR_A1, active garage A1.

Test data: customer QA Customer An Nguyen, vehicle 51A-111.11. Lines: (1) Labor “Oil change service”, qty 1, unit price 250000; (2) Part “Engine oil 5W-30”, qty 4, unit price 180000.

Steps

  1. Quotes → New quote. Pick the customer, then the vehicle (only An Nguyen’s own vehicles are offered).
  2. Add line item twice and fill in the test data.
  3. Save.

Expected results

  • The quote is created as a draft, numbered BG-<YYYY><MM>-0001 (or the next free sequence for the garage this month), status Draft.
  • The line total of each row is quantity × unit price; the quote total is their sum (970,000 VND).
  • Opening the quote from the list shows the same customer, vehicle, lines and total.
  • The quote does not appear when A2 is the active garage.

E2E-QUO-002 · Quote field validation

Priority: P2 · Covers: FR-QUO-01 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. Customer An Nguyen, vehicle 51A-111.11.

Test data:

CaseDescriptionQuantityUnit priceExpected
a(empty)1100000Description required
bBrake pad0100000Quantity must be a positive number
cBrake pad1.9999100000At most 3 decimal places
dBrake pad1-1Unit price must not be negative
eBrake pad1.5100000Saved

Steps

  1. New quote with the customer and vehicle; for each case, set the single line to the row’s data and save.

Expected results

  • a–d are refused; the form shows “Please check the highlighted information.” and marks the field.
  • e is saved. Clean-up: delete it.
  • A quote needs at least one line: removing the only line disables Save.

E2E-QUO-003 · Edit and delete a draft; a non-draft quote cannot be edited or deleted

Priority: P2 · Covers: FR-QUO-01 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. A draft quote for An Nguyen (E2E-QUO-001’s quote, or a fresh one).

Steps

  1. Edit the draft: change the labor line’s unit price to 280000; add a third line. Save.
  2. Send for approval (any mode).
  3. Try to open the line-item editor again; try Delete.
  4. Delete a second, still-draft quote.

Expected results

  • Step 1 saves; the total reflects the new price and the added line.
  • Step 2 moves the quote out of Draft; the edit and delete controls are gone (or refused with “This cannot be done right now.” if attempted directly).
  • Step 4 asks “Delete quote <number>?” and removes it from the list.

Priority: P1 · Covers: FR-QUO-02 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. A draft quote for An Nguyen ([email protected], has an e-mail), approval mode Send a link.

Steps

  1. Open the quote → Send for approval.
  2. Open Mailpit, search to:[email protected].

Expected results

  • The quote’s status becomes Sent; a banner reads “The approval link was e-mailed to the customer.” with the link shown and a Copy link button.
  • Mailpit shows an e-mail to An Nguyen with the quote number and a link starting with the owner web’s address (/public/quotes/<token>).
  • The link in the banner and the link in the e-mail are the same.

Priority: P2 · Covers: FR-QUO-02 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. A draft quote for a customer created in the scenario with no e-mail (QA Customer QUO005), approval mode Send a link; the baseline customers all keep their e-mail.

Steps

  1. Open the quote → Send for approval.
  2. Click Copy link and paste it somewhere visible.

Expected results

  • The banner reads “The approval link was created — the customer has no e-mail on file, so share the link another way.” (no auto-e-mail).
  • The copied link matches the one shown, and opens the public quote page (E2E-QUO-006).
  • Mailpit has no new message to any address for this quote.

Priority: P1 · Covers: FR-QUO-02, FR-QUO-03 · Automation: Automated (API, partial)

Preconditions: a Sent, LINK-mode quote with 2 lines and its public link (E2E-QUO-004 or 005).

Steps

  1. Open the public link in a private/incognito window (no sign-in).
  2. Approve line 1, reject line 2. Submit the decision.
  3. As ADVISOR_A1, open the quote.
  4. Repeat with a fresh Sent quote where every line is rejected.

Expected results

  • The public page shows the garage name, quote number, customer/vehicle names and the lines — no internal ids, no Authorization header sent.
  • After submitting: “You approved this quote. Thank you!” is not shown when only some lines are rejected — instead the page reflects the mixed decision; the page becomes read-only.
  • In the owner web, the quote’s status is Approved (at least one line approved) with line 1 marked approved and line 2 rejected.
  • Step 4’s quote becomes Rejected (every line rejected).
  • Reopening the same public link now shows the decision already made, with no way to decide again.

Priority: P2 · Covers: FR-QUO-02 · Automation: Automated (API, partial)

Preconditions: the decided link from E2E-QUO-006. A second, freshly sent LINK-mode quote.

Steps

  1. Open the already-decided link again.
  2. Open /public/quotes/not-a-real-token.
  3. Advisor rejects the second quote’s public token from the owner web by re-sending it (a fresh Send for approval issues a new token, invalidating the old one) — open the old (copied earlier) link.

Expected results

  • Steps 1–3 each show “This link is invalid or has expired.” (422 QUOTE_LINK_INVALID), never a stack trace or a blank page.

E2E-QUO-008 · MANUAL mode: the advisor records the customer’s decision directly

Priority: P1 · Covers: FR-QUO-02, FR-QUO-03 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. A draft quote for Chi Le (A2 — use OWNER_A instead if a cross-garage user is inconvenient; simplest: a draft quote for An Nguyen), approval mode Record manually.

Steps

  1. Open the quote → Send for approval.
  2. Record the customer’s decision → approve every line → Save decision.

Expected results

  • Step 1: the quote becomes Sent; no e-mail is sent and no public link banner is shown (MANUAL mode has no customer-facing touchpoint).
  • Step 2: the quote becomes Approved; the decision panel is replaced by the Convert to repair order action.
  • The same panel, reached instead on a LINK-mode Sent quote, lets the advisor override a phone decision (documented behaviour; not re-tested here since E2E-QUO-006 already covers the public path).

E2E-QUO-009 · The garage’s default approval mode pre-fills a new quote; overriding it per quote

Priority: P2 · Covers: FR-QUO-02, FR-TEN-05 · Automation: Automated (API, partial)

Preconditions: baseline. OWNER_A. A1’s default approval mode is Send a link (factory default).

Steps

  1. A1 → Garage settings → Configuration → set the default approval mode to Record manually. Save.
  2. New quote for An Nguyen: look at the approval-mode choice before touching it.
  3. Change it to Send a link for this one quote only. Save.
  4. New quote again: look at the default.

Expected results

  • Step 2 shows Record manually pre-selected, with the hint text explaining what it does.
  • Step 3 saves with LINK mode on this quote; the garage’s own default is unchanged.
  • Step 4 again shows Record manually. Clean-up: set A1’s default back to Send a link; delete the quotes created.

E2E-QUO-010 · Convert an approved quote into a repair order, preserving only approved lines

Priority: P1 · Covers: FR-QUO-04 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active. An Approved quote for An Nguyen with one approved and one rejected line (E2E-QUO-006’s first quote, or a fresh equivalent).

Steps

  1. Open the quote → Convert to repair order.
  2. Follow the link to the new repair order (E2E-REP-003 covers its detail in full).

Expected results

  • A banner reads “A repair order was created from this quote.” with a View repair order link; the quote’s status becomes Converted and its actions are gone.
  • The repair order has exactly the one approved line (same description, quantity, unit price), status Open, the same customer name and vehicle plate as the quote, and its own number (LSC-<YYYY><MM>-####).
  • Converting the same quote again is refused (already converted).
  • The vehicle’s repair history (An Nguyen’s vehicle) now lists both the quote (Converted) and the repair order.

E2E-QUO-011 · Quote number is rendered from the garage’s template and unique per garage

Priority: P3 · Covers: FR-TEN-05 · Automation: Automated (API, partial)

Preconditions: baseline. OWNER_A.

Steps

  1. A1 active → create 2 draft quotes; note their numbers.
  2. A2 active → create 1 draft quote; note its number.

Expected results

  • A1’s quotes are numbered BG-<YYYY><MM>-#### with consecutive sequences (e.g. -0002, -0003 continuing from whatever A1 already has).
  • A2’s quote starts its own sequence (e.g. -0001) — each garage counts independently, even for the same owner.
  • Clean-up: delete the 3 quotes.

E2E-QUO-012 · The daily transaction limit blocks quote creation and conversion

Priority: P1 · Covers: FR-LIC-02 · Automation: Automated (API, partial)

Preconditions: ADMIN creates plan QA Transaction Limit, code qa-txn-limit (100,000 VND/month, 1 garage, 5 staff, 2 transactions/day, on sale). Sign up and verify signup.quo012.<unique>@vietgara.test (QA Owner QUO012, 0900000501); switch to QA Transaction Limit; create 1 garage QA Gara QUO012; create a customer with a vehicle in it.

Steps

  1. Create a draft quote (transaction 1 of 2 today).
  2. Send it for approval (LINK) and approve every line from the public link, then Convert to repair order (transaction 2 of 2).
  3. Create a second draft quote (would be transaction 3).
  4. Close the repair order from step 2’s conversion once ready (see E2E-REP-008). Closing is not a creation, so it is not counted and the limit does not refuse it.

Expected results

  • Steps 1–2 succeed; Transactions today 2 / 2 on the Subscription page.
  • Step 3 is refused: “Your plan limit is reached. Upgrade to add more.”
  • Step 4 (closing) is a separate action from creation and is not itself counted against maxTransactionsPerDay (only quote/repair-order/settlement creation is, per Low-Level Design §Entitlement); confirm closing still succeeds once every line is completed.
  • Clean-up: none required (single-use user); note the user and plan for later removal if the environment is reused.

E2E-QUO-013 · List and filter quotes by status

Priority: P2 · Covers: FR-QUO-01 · Automation: Automated (API, partial)

Preconditions: baseline. ADVISOR_A1, A1 active, with at least one quote in each of Draft, Sent, Approved/Rejected and Converted (reuse quotes from earlier scenarios, or create fresh ones).

Steps

  1. Quotes with no filter.
  2. Filter by each status in turn.

Expected results

  • No filter lists every quote of A1, newest first, each with number, customer/vehicle, status badge, total and created date.
  • Each filter shows only quotes of that status.

E2E-QUO-014 · Permissions: no access, and full access

Priority: P1 · Covers: FR-IAM-03, FR-QUO-01 · Automation: Automated

Preconditions: baseline. A1 active.

Test data: TECH_A1A2 (no quote access, per the Technician role), ADVISOR_A1 (quote read/write), MANAGER_A1 (everything).

Steps

  1. TECH_A1A2: look at the sidebar; type /quotes directly.
  2. ADVISOR_A1: create, send and delete a draft quote.
  3. MANAGER_A1: same as step 2.

Expected results

  • TECH_A1A2 has no Quotes entry in the sidebar; /quotes shows no data or “You are not allowed to do this.”
  • ADVISOR_A1 and MANAGER_A1 can fully manage quotes.

E2E-QUO-015 · Pick a job on a quote: the labor line and the part lines appear, editable

Priority: P1 · Covers: FR-CAT-05, FR-CAT-06, FR-QUO-01 · Automation: Automated

Blackbox: TestAddJobToQuote (one labor line at the job’s price, a line per active suggested part at the part’s price, a packaging unit typed and priced per unit; the quote total follows; the quote is edited afterwards; an inactive or unknown job, a non-draft quote and a quote that would pass 100 lines are refused).

Preconditions: baseline. ADVISOR_A1, A1 active. The job Oil change (labor 200,000; OIL-5W30 × 4 litres at 90,000; FLT-OIL-01 × 1 hidden). A draft quote for An Nguyen with one free-form line of 100,000.

Steps

  1. Open the draft quote → Add a job. Search oil and pick Oil change.
  2. Change the oil line’s quantity from 4 to 5. Save the quote.
  3. Add the same job again.
  4. Send the quote, then try Add a job on it.

Expected results

  • Step 1: the quote gains the labor line Oil change at 200,000, the oil line 4 L at 90,000 (360,000) and a hidden line for the filter marked “Hidden from the customer”; the total is 100,000 + 200,000 + 360,000 = 660,000.
  • Step 2: the oil line is 450,000, the total 750,000; the labor line is unchanged.
  • Step 3: the lines are added again (a job may be used twice).
  • Step 4: the sent quote has no Add a job; through the API it is refused as not editable.

E2E-QUO-016 · A hidden consumable is not billed, not shown to the customer and not decided

Priority: P1 · Covers: FR-CAT-08, FR-QUO-02, FR-QUO-03, FR-QUO-05 · Automation: Automated

Blackbox: TestHiddenConsumableOnTheQuote (price 0 and left out of the total; the public quote and the PDF omit it; the decision covers the billable lines only and a decision naming the hidden line is refused; a hidden line must be a catalogue part line, and a quote needs a billable line; a bad job id is refused).

Preconditions: baseline. ADVISOR_A1, A1 active. A draft quote with the job Oil change added (E2E-QUO-015), which includes a hidden FLT-OIL-01 line.

Steps

  1. Open the quote: look at the hidden line and the total.
  2. Try to mark a free-form line, or a labor line, as hidden; try to save a quote whose only line is hidden.
  3. Send the quote (LINK mode) and open the public link as the customer.
  4. Download the quote’s PDF.
  5. As the customer decide on the lines.

Expected results

  • Step 1: the hidden line shows “Hidden from the customer”, price 0, and is not in the total.
  • Step 2: refused (“Only a catalogue part line can be hidden, and a quote needs a billable line.”).
  • Step 3: the public page lists the labor and the oil line only, with the same total.
  • Step 4: the PDF lists the same lines and the same total.
  • Step 5: the customer decides on the lines shown; the hidden line is not among them.

E2E-QUO-017 · A hidden consumable follows its job when the quote converts

Priority: P1 · Covers: FR-CAT-08, FR-QUO-03, FR-QUO-04 · Automation: Automated (API)

Blackbox: TestHiddenConsumableFollowsItsJob (approve a billable line of the job and the consumable converts; reject every billable line of the job and it is dropped; a free-standing consumable follows the quote; the order’s total leaves it out).

Preconditions: baseline. ADVISOR_A1, A1 active. Two sent quotes, each with the job Oil change (labor, oil and a hidden filter) and one free-form line.

Steps

  1. On the first quote approve the job’s labor line, reject its oil line and the free-form line. Convert.
  2. On the second quote reject all the job’s lines and approve the free-form line. Convert.

Expected results

  • Step 1: the repair order has the labor line and the hidden filter line (not billed); its total is the labor price.
  • Step 2: the repair order has the free-form line only; the filter is not on it.