What it does
Closing a sale (RF19, US23) ends the car's open Ownership Period. One transaction writes the ★ disposal header (date, the Loan it paid off, author), the ★ ledger_entry rows sale_proceeds and sale_cost, sets the period's end date and moves the car to sold. Nothing is deleted or merged (RN01): every expense, service and document stays with the car.
recordSale in disposal.service.ts is the one write path: M-Compra's trade-in (US08) sells through it too, and sale.tradedInFor then names the car it was traded in for.
When the car's newest Loan still has a balance, the sale pays it off: the balance becomes a loan_principal entry on the sale date (never an expense, RN05) and a final zero ★ loan_snapshot closes the Loan.
Two results, never "profit"
The figures come from the period's ledger as it stands after corrections, through @autofolio/domain (RF20, RN04, RN06):
- Deal result = price received − purchase base (price and acquisition costs) − capitalized upgrades − selling costs.
- Economic result of ownership = deal result − running costs while owned (operating costs, interest and fees; never principal).
Before a sale a rise in value is "estimated appreciation"; after it, "deal result" (appreciationLabelKey).
Procedures
| Procedure | Who | Failures |
|---|---|---|
disposal.get { vehicleId } | Members of the Organization | NOT_FOUND (car) |
disposal.close { id, vehicleId, disposedOn, priceMinor, costsMinor? } | Members of the Organization | INPUT_VALIDATION, NOT_FOUND (car), BAD_REQUEST (not in the garage, date before the purchase or in the future), CONFLICT (id) |
Both answer open (the open period's purchase base, upgrades, running costs and the balance to pay off) for a car that can be sold, and sale (every figure of the latest sale, both results and the payoff) once it is sold.
Offline and idempotency (RNF04)
The client generates the Disposal's id. Sending it again answers the sale as it stands and writes nothing more; an id that names another car's sale is CONFLICT.
Data and isolation
disposal and ledger_entry are append-only for every role and isolated by Active Organization. No audit_log event is written: the ★ rows are the trail, and amounts never go to logs (RNF07).
App
M-Fechar-Venda (screen-M-Fechar-Venda, route /close-sale/[vehicleId]) opens from the vehicle profile's More menu. It shows the date, the loan payoff, price received and selling costs as fields, the purchase base and upgrades, the deal result (positive or negative), running costs and the economic result, recomputed as you type, and "Confirm sale" (confirmar-venda). Confirming shows the "Sold" sheet with "My collection", which returns to the garage. A sold car's profile shows both results again and opens the sale as recorded; a traded-in car's sale shows "Traded in for" (trocado-por), which opens the new car.
autofolio://dev/M-Fechar-Venda opens the seeded Corolla Cross with the sale example typed in. Flow F7 sells it, so it runs once per demo account.