# Sale

How closing a sale (M-Fechar-Venda) ends a car's ownership period without deleting anything, pays off its Loan, and shows the deal result and the economic result apart.

## What it does [#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" [#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 [#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) [#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 [#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 [#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.

## Key files [#key-files]

- [`packages/api/src/features/disposal/disposal.contract.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/disposal/disposal.contract.ts)
- [`packages/api/src/features/disposal/disposal.service.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/disposal/disposal.service.ts)
- [`apps/mobile/src/features/disposal/disposal.screen.tsx`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/mobile/src/features/disposal/disposal.screen.tsx)

