Files
edr-platform/.portal-flows-assets/portal-flows.html
Hagernesh 69062389c7 fix(train-scheduling): marshalling docs respect mid-corridor wagon coupling
Origin marshalling (import + export) now prints leg slots as
TO BE LOADED AT <board yard> with board/alight stations and keeps
their containers out of the loaded tallies. Intercity Marshalling 2 no
longer hides whole-route cargo whose allocation never left PLANNED
(import flow confirms loading at schedule level), so the on-board view
matches the physical consist before and after mid-corridor coupling.
2026-08-26 08:30:38 +00:00

313 lines
19 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>EDR Freight Portal — Priority Flows</title>
<style>
@page { size: A4; margin: 0; }
* { box-sizing: border-box; }
body {
font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
color: #1a1a1a;
margin: 0;
font-size: 13px;
line-height: 1.45;
}
.cover {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 60px 70px;
background: linear-gradient(135deg, #0b6b4f 0%, #0e8a63 60%, #14a074 100%);
color: white;
page-break-after: always;
}
.cover .tag { font-size: 14px; letter-spacing: 3px; text-transform: uppercase; opacity: .85; margin-bottom: 18px; }
.cover h1 { font-size: 42px; margin: 0 0 14px 0; line-height: 1.15; }
.cover p.sub { font-size: 17px; opacity: .92; max-width: 520px; }
.cover .meta { margin-top: 60px; font-size: 12px; opacity: .8; border-top: 1px solid rgba(255,255,255,.35); padding-top: 16px; max-width: 520px; }
.cover .meta div { margin-bottom: 4px; }
.toc { padding: 60px 70px; page-break-after: always; }
.toc h2 { font-size: 22px; margin-bottom: 24px; color: #0b6b4f; }
.toc ol { padding-left: 22px; }
.toc li { margin-bottom: 10px; font-size: 14px; }
.toc .section-label { font-weight: 700; color: #0b6b4f; }
section.flow { padding: 40px 60px 10px 60px; }
section.flow > h2 {
font-size: 24px;
color: #0b6b4f;
border-bottom: 3px solid #0b6b4f;
padding-bottom: 8px;
margin-bottom: 6px;
page-break-before: always;
}
section.flow > p.lede { color: #444; font-size: 13.5px; margin-bottom: 22px; }
.step { margin-bottom: 28px; page-break-inside: avoid; }
.step .step-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.step .num {
background: #0b6b4f; color: white; font-weight: 700; font-size: 13px;
width: 26px; height: 26px; border-radius: 50%;
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.step .title { font-weight: 700; font-size: 14.5px; }
.step .desc { margin: 0 0 10px 36px; color: #333; font-size: 13px; }
.step img {
display: block;
max-width: 100%;
border: 1px solid #d8dde3;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
.note {
margin: 10px 36px 18px 36px;
padding: 10px 14px;
border-left: 4px solid #2f7fd6;
background: #eef5fd;
border-radius: 4px;
font-size: 12.5px;
}
.note.limit { border-left-color: #c98a1c; background: #fdf6e8; }
.note.bug { border-left-color: #c0392b; background: #fbeceb; }
.note.howto { border-left-color: #0b6b4f; background: #eaf6f0; }
.note b { display: block; margin-bottom: 3px; }
.note ol { margin: 6px 0 0 0; padding-left: 18px; }
.note ol li { margin-bottom: 4px; }
</style>
</head>
<body>
<div class="cover">
<div class="tag">EDR Freight — Priority Flows</div>
<h1>Portal Side<br>Contract Signing · Booking · Payment</h1>
<p class="sub">A step-by-step walkthrough of the same three flows, driven live as the real
customer — every screen, button, and validation message as the account actually saw it.</p>
<div class="meta">
<div>Driven live against the shared dev environment (edr_dev)</div>
<div>Personas: hager@gmail.com (Hagernesh Tadesse) for contract &amp; booking; nati@gmail.com (NAti Wondish) for payment</div>
<div>Companion document to EDR-Freight-Priority-Flows.pdf (backoffice/staff side)</div>
</div>
</div>
<div class="toc">
<h2>Contents</h2>
<ol>
<li><span class="section-label">1. Contract creation &amp; signing</span> — Home, Contracts list, the New Contract wizard (Setup → Cargo/Route → Review), the unit-rate quotation approval step, the duplicate-contract validation, and how/where a customer signs once EDR approves.</li>
<li><span class="section-label">2. Booking</span> — the Bookings list and the document-review flow a customer works through on an existing booking.</li>
<li><span class="section-label">3. Payment</span> — the customer's Invoices page, filtering to what's actually payable, the invoice detail screen with its "Pay" action, and the bank-transfer steps behind it.</li>
</ol>
</div>
<section class="flow">
<h2>1 · Contract creation &amp; signing</h2>
<p class="lede">Portal customer hager@gmail.com, logged into the freight portal (localhost:5273).</p>
<div class="step">
<div class="step-head"><div class="num">1</div><div class="title">Sign in</div></div>
<div class="desc">The portal login form. A customer signs in with their email and password — no OTP step for an already-onboarded account (OTP only applies during self-signup).</div>
<img src="{{02-login-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">2</div><div class="title">Home</div></div>
<div class="desc">Landing page after login: quick stats and shortcuts into Contracts, Bookings, and Invoices.</div>
<img src="{{05-home-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">3</div><div class="title">Contracts list</div></div>
<div class="desc">The customer's contracts: one Active (CTR-2026-00043, Fully Executed) and two In Progress (CTR-2026-00086, CTR-2026-00087 — both Submitted, awaiting EDR review). "New Contract" starts a fresh one.</div>
<img src="{{04-contracts-list-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">4</div><div class="title">New Contract — Step 1: Setup</div></div>
<div class="desc">Operation Type, Contract Kind (One-Time vs. Framework), New-vs-Renewal, and the Service Type cards — the entry point of the wizard.</div>
<img src="{{07-contract-step1-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">5</div><div class="title">Step 1 filled — Operation Type + Service</div></div>
<div class="desc">Operation Type set to Import and "Rail Transport with Customs" selected — this reveals the trucking/customs options below (first mile, last mile, and the included customs clearing service).</div>
<img src="{{08-contract-step1-filled-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">6</div><div class="title">Step 2: Cargo &amp; Route</div></div>
<div class="desc">Cargo scope (containerised, both 20ft/40ft), and the origin/destination yard pair that defines the route.</div>
<img src="{{09-contract-step2-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">7</div><div class="title">Step 3: Review &amp; Submit</div></div>
<div class="desc">Final review of the assembled contract terms — operation, service, route, cargo scope, and customs handling — before submitting.</div>
<img src="{{10-contract-step3-review-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">8</div><div class="title">Approve your quotation</div></div>
<div class="desc">Submitting immediately opens a per-unit rate quotation for the customer to approve — freight rates for 20ft/40ft containers plus the customs clearance service fee per container size. The dialog is explicit that these are per-unit rates, not a total: the payable amount is computed per booking from the quantities actually shipped. Approving submits the contract for EDR staff review.</div>
<img src="{{11b-quotation-approve-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">9</div><div class="title">Real validation: duplicate contract blocked</div></div>
<div class="desc">Re-submitting a route/service/cargo-scope combination that already has an active or in-review contract is rejected outright, naming the conflicting contract by number. This is a genuine business rule hit live, not staged.</div>
<img src="{{11-contract-duplicate-blocked-full.png}}">
</div>
<div class="note howto">
<b>Once EDR approves the contract, the customer signs it</b>
A submitted contract moves through EDR review as: <i>Submitted → Pending Approval → Approved →
Approved Pending Signature → Contract Ready.</i> The "View &amp; sign contract" button only
appears once the contract reaches <b>Contract Ready</b> — it shows on the Contracts list row and
on the contract's own detail page, and opens a dedicated preview-and-sign page
(<code>/contracts/:id/view</code>), not a plain button on the detail page.
<ol>
<li>EDR staff approve the contract and price it.</li>
<li>The customer is notified the moment it's ready to sign — <b>SMS, email, and an in-app
notification</b> all fire together (per the customer's description of the real notification
flow — not re-verified against the notification-sending code for this document).</li>
<li>The customer opens the notification or the Contracts list, clicks "View &amp; sign
contract", scrolls the full contract text, and ticks the consent checkbox.</li>
<li>They draw or reuse a saved signature, upload a company stamp, then verify by OTP
(sent to their registered phone/email) to finalize the signature.</li>
<li>Status moves to Signed — Awaiting Staff, then Fully Executed once EDR counter-signs.</li>
</ol>
CTR-2026-00086 and CTR-2026-00087 above are still at Submitted — EDR hasn't approved them yet,
so no sign button is showing for either.
</div>
<div class="step">
<div class="step-head"><div class="num">11</div><div class="title">Where "View &amp; sign" actually shows (a different customer's contract list)</div></div>
<div class="desc">A second real account (nati@gmail.com, 17 contracts) confirms the button live: its Action column carries "View", "Request shipment", "Book shipment", and "Initiate booking" depending on each row's status — the same column shows "View &amp; sign" the moment a row reaches Contract Ready.</div>
<img src="{{16-nati-contracts-list-actions.png}}">
</div>
<div class="note limit">
<b>The signable window is real and it closes</b>
This account's own CTR-2026-00089 was captured with a live "View &amp; sign" button two days ago
(per the customer's own screenshot) — by the time this document was rebuilt, that same contract
had already moved to <b>Expired</b> with no button left to click. Contract Ready is a real,
time-boxed state, not a permanent one. No currently-open contract exists on either test account
at time of writing, so the sign page itself (scroll-to-consent → draw signature → stamp → OTP)
could not be re-captured live in this pass; it was documented from the customer's own screenshots
and code inspection instead.
</div>
<div class="step">
<div class="step-head"><div class="num">10</div><div class="title">Fully executed contract — signatures</div></div>
<div class="desc">CTR-2026-00043's detail page: both STAFF and CUSTOMER signatures are complete and the contract is Fully Executed — the end state of the flow described above.</div>
<img src="{{06-contract-detail-signed-full.png}}">
</div>
</section>
<section class="flow">
<h2>2 · Booking</h2>
<p class="lede">A portal customer does not have a bare "New booking" button on the Bookings page
itself — booking creation is triggered from a signed contract's row, once EDR has cleared it for
shipment (contract status Active). What that entry point actually is depends on the contract's
state: "Initiate booking" opens a brand-new booking; "Book shipment" / "Book" continues one EDR
has already pre-cleared.</p>
<div class="step">
<div class="step-head"><div class="num">1</div><div class="title">Initiate booking — confirmation</div></div>
<div class="desc">Clicking "Initiate booking" on an Active contract (CTR-2026-00071) doesn't create the booking immediately — it confirms first: "This creates a new shipment booking under contract CTR-2026-00071. You'll upload the import documents next, and the shipment quantity is drawn down from your contract's reserved capacity." Cancelled here rather than completed, since creating a live booking is a real mutation.</div>
<img src="{{17-initiate-booking-confirm.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">2</div><div class="title">Complete Your Booking — cargo details</div></div>
<div class="desc">Following an already-cleared booking's "Book" action (BK-2026-000209, Bulk cargo under CTR-2026-00093) lands on this form: the contract's fixed route, a cargo-details block (Total weight for Bulk cargo — a Container-scoped contract shows an Excel-import table instead), and a Schedule block picking the binding shipment day. The billing currency here is fixed to ETB, paid through the payment gateway. The calendar is real and reactive: it read <i>"Enter your cargo details first — available shipment days depend on the wagons your cargo needs,"</i> and no day was actually open on this route at the time of capture (0 available days) — the same live batch-window behaviour documented in Section 1.</div>
<img src="{{19-complete-booking-cargo-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">3</div><div class="title">Bookings list — one contract's view</div></div>
<div class="desc">This account's one existing booking, BK-2026-000068 on CTR-2026-00043 — status "In review," amount still ETB 0.00 because pricing is finalised after document review, not at booking creation. Every row carries a "Review documents" action.</div>
<img src="{{13-bookings-list-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">4</div><div class="title">Import documents dialog</div></div>
<div class="desc">Clicking "Review documents" opens this in place, no page navigation. All four required import documents — Bill of Lading/Waybill, Packing List, Import declaration, and Ethiopia T1 &amp; Djibouti T1 — show status "Under review," each with View/Download and a "Replace file" drop zone. The banner is explicit: <i>"Only re-upload the documents flagged with a query below — approved documents stay as they are."</i> "Submit documents" stays disabled while nothing is flagged.</div>
<img src="{{14-booking-documents-modal-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">5</div><div class="title">Bookings list — the fuller picture (nati@gmail.com, 38 bookings)</div></div>
<div class="desc">Across a larger real history the Action column carries every state at once: "Book" (cleared, awaiting cargo details), "View" (nothing to do), "Rebook wagons" (a cancelled reservation), "Pay [amount]" (booked, payment outstanding), "Review documents" / "Documents", and "Track" once a train is assigned. BK-2026-000188 shows "Pay 16,323.25 ETB" while its own Status column reads Cancelled — a live inconsistency (the booking lapsed after its payment window closed, but the stale Pay action hadn't been cleared from the row).</div>
<img src="{{18-nati-bookings-list-actions.png}}">
</div>
</section>
<section class="flow">
<h2>3 · Payment</h2>
<p class="lede">The customer-facing payment surface is the Invoices page.</p>
<div class="step">
<div class="step-head"><div class="num">1</div><div class="title">Invoices — hager@gmail.com (nothing to pay)</div></div>
<div class="desc">Outstanding, Overdue, and Total Invoices all read 0. This lines up with the Booking flow above: BK-2026-000068 is still in document review and hasn't been priced, so nothing has been invoiced to this customer yet. The customer supplied a second real login (nati@gmail.com) to reach the actual payment screen.</div>
<img src="{{03-hager-invoices-empty-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">2</div><div class="title">Invoices — nati@gmail.com, filtered to Due</div></div>
<div class="desc">This account has a long invoice history (35 invoices) and 5 currently Outstanding. The status filter's real options are Due / Overdue / Paid / Draft / Cancelled / Refunded; filtering to "Due" narrows the list to what's actually payable right now, each row with a "Pay" action.</div>
<img src="{{01-invoices-due-full.png}}">
</div>
<div class="step">
<div class="step-head"><div class="num">3</div><div class="title">Invoice detail — the Pay screen</div></div>
<div class="desc">Opening INV-20260820-00017 (Br 200.00, a port-charges line item off booking BK-2026-000112) shows the full detail a customer sees before paying: billed-to company, source, issue/due dates, the line-item breakdown, a "Download invoice" action, and a "Pay Br 200.00" button sized to the exact amount due.</div>
<img src="{{00-invoice-detail-pay.png}}">
</div>
<div class="note howto">
<b>What "Pay" opens (from the customer's own screenshot)</b>
Clicking "Pay" opens a "Complete your payment" dialog: the amount due, a red warning —
<i>"Pay only from a bank account registered under your company name — DE BE KE. A payment sent
from an account under any other name will not be recognized as paid"</i> — a payment-method
picker (the option shown was <b>CBE Bill Payment — "Pay at any CBE branch, app or USSD · ETB"</b>),
a "Secured — you'll be redirected to your provider to pay" note, then "Continue to payment".
This was captured by the customer directly, not by this document — every attempt here to click a
live "Pay" button (on this invoice and on two different bookings) was blocked by the harness's own
financial-mutation guard before the dialog could be reached.
</div>
<div class="note howto">
<b>Paying by bank transfer — step by step (customer-provided process)</b>
<ol>
<li>Open your internet banking app or account.</li>
<li>Copy the PNR code EDR sent you by SMS and email.</li>
<li>In your bank's payment menu, choose <b>Travel</b>, then <b>Land Transport</b>, then
<b>EDR Freight</b> as the biller.</li>
<li>Paste the PNR code into the reference/biller-code field.</li>
<li>Confirm the amount shown matches the invoice total, then pay.</li>
</ol>
This is the settlement path behind the "Pay" button above — the bank confirms the PNR against
EDR's own records, so the code must match exactly what was sent. These steps were supplied
directly by the customer describing the real banking flow; they are not something this
document observed inside the portal UI itself, which only exposes the "Pay" button shown above.
</div>
<div class="note limit">
<b>Stopped short of submitting the payment — three separate attempts, all blocked</b>
Clicking "Pay Br 200.00" on the invoice above, and separately clicking "Pay" on two different
bookings (BK-2026-000195 and BK-2026-000188) while rebuilding this document, were all blocked by
the harness's own auto-mode permission classifier as a real financial mutation against the shared
dev database — the same guard that blocked "Confirm paid" on the backoffice side. No workaround
was attempted, per the classifier's own instruction. The invoice screen above is the actual entry
point a customer uses; the backoffice-side companion document (EDR-Freight-Priority-Flows.pdf)
covers staff-side settlement (Transactions → Manual Payments).
</div>
</section>
</body>
</html>