fix: add unified ledger amount and enforce manual decimal precision
Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
This commit is contained in:
co-authored by
genichin
parent
ccde81b7a0
commit
a71c91f6ef
@@ -341,6 +341,7 @@
|
||||
- BUFFER_IN: cash_balance -> profit_buffer.
|
||||
- BUY: cash_balance -> asset_quantity.
|
||||
- SELL: asset_quantity -> cash_balance.
|
||||
- DIVIDEND: external net cash dividend -> profit_buffer only; `tax_amount` is reference metadata and does not affect snapshot math.
|
||||
- REVERSAL: append-only inverse effect of `target_ledger_entry_id`.
|
||||
|
||||
### Return Aggregate Semantics
|
||||
@@ -356,6 +357,8 @@
|
||||
|
||||
- Manual writes lock the portfolio row while calculating/appending/updating snapshots to avoid lost updates.
|
||||
- Manual writes reject insufficient cash/quantity/buffer with HTTP 409 rather than creating a new negative state.
|
||||
- DIVIDEND duplicate candidate (`portfolio_id`, `executed_at` UTC date, decimal `amount`, `note`) returns HTTP 409 `POTENTIAL_DUPLICATE_DIVIDEND` unless request confirms with `confirm_duplicate=true`.
|
||||
- DIVIDEND uses date-only input stored as `executed_at` UTC midnight (`00:00:00Z`).
|
||||
- `total_value_after` for manual entries is the portfolio snapshot value after the mutation and includes cash, asset valuation, and profit buffer.
|
||||
|
||||
## Shared Consistency Rules
|
||||
|
||||
@@ -280,11 +280,12 @@
|
||||
3. Disabled portfolio receives HTTP 409 `PORTFOLIO_DISABLED`.
|
||||
4. If `managed_by_daemon_id IS NOT NULL` and request lacks `confirm_daemon_managed_manual_write=true`, the API returns HTTP 409 `MANUAL_WRITE_REQUIRES_CONFIRMATION` with daemon id and required confirmation marker.
|
||||
5. Valid actions dispatch to a single repository transaction that locks the portfolio row (`FOR UPDATE OF p`), calculates the action effect, appends a `portfolio_ledger` row with `source='manual'`, and updates the portfolio snapshot.
|
||||
6. BUY/SELL require sufficient cash/quantity. BUFFER_OUT/BUFFER_IN/WITHDRAW/PROFIT require sufficient buffer/cash as appropriate. Insufficient state returns HTTP 409 with structured code.
|
||||
6. BUY/SELL require sufficient cash/quantity. BUFFER_OUT/BUFFER_IN/WITHDRAW/PROFIT require sufficient buffer/cash as appropriate. DIVIDEND requires `amount` and date-only `executed_at`, stores `executed_at` at UTC midnight, and increases only `profit_buffer` (`tax` metadata only). Insufficient state returns HTTP 409 with structured code.
|
||||
7. REVERSAL requires `target_ledger_entry_id`, rejects duplicate reversal targets, and appends a reversing row instead of mutating/deleting the target.
|
||||
8. Response includes after-snapshot: `cash_balance_after`, `asset_quantity_after`, `profit_buffer_after`, `total_value_after`.
|
||||
9. `GET /v1/portfolios/{portfolio_id}/ledger/manual` returns newest manual entries only (`source='manual'`).
|
||||
10. `GET /v1/portfolios/{portfolio_id}/returns/summary` returns `net_contributed_capital=sum(INVEST)-sum(WITHDRAW)` and `cumulative_profit_withdrawn=sum(PROFIT)` separately.
|
||||
8. Duplicate DIVIDEND candidate (same portfolio/date/amount/note and original not reversed) returns HTTP 409 `POTENTIAL_DUPLICATE_DIVIDEND` with matched entry id; `confirm_duplicate=true` re-submit records it.
|
||||
9. Response includes after-snapshot: `cash_balance_after`, `asset_quantity_after`, `profit_buffer_after`, `total_value_after`.
|
||||
10. `GET /v1/portfolios/{portfolio_id}/ledger/manual` returns newest manual entries only (`source='manual'`).
|
||||
11. `GET /v1/portfolios/{portfolio_id}/returns/summary` returns `net_contributed_capital=sum(INVEST)-sum(WITHDRAW)` and `cumulative_profit_withdrawn=sum(PROFIT)` separately.
|
||||
|
||||
## Flow: `v1 API — POST /auth/service-tokens`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user