summaryrefslogtreecommitdiff
path: root/src/FundLab.Api/App.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 10:43:09 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 10:43:09 +0800
commit3d9398234a54774544eb48a1caed6a1b2d5132eb (patch)
treebf6773bfce7872da1d7aa40f5d1b8af8cdaacf76 /src/FundLab.Api/App.fs
parenta5ac465ab59197a55a222d30ebd2cf26ffe80f86 (diff)
downloadfund-lab-3d9398234a54774544eb48a1caed6a1b2d5132eb.tar.gz
Add confirmation status and holdings UI (3d-2c)
Wire the subscription confirmation and positions endpoints into the frontend: order rows show per-order trade date and confirmed outcome (NAV, units, NAV date, invested cash, residual) or pending_nav reason, each confirmable order gets a confirm action posting to the existing confirm endpoint with an idempotency key and request-sequence guard, and a new holdings panel renders available/reserved cash plus per-code positions (units, cost, latest valuation NAV with date, or an explicit '估值待更新' when no valuation exists). Orders list/create responses now return the full detail shape so pending reasons and confirmation results survive refresh. The optional text decoder accepts the current plain-value/null wire format alongside the legacy case/fields envelope, restoring fund type and daily return display. Browser QA gains a J-series covering the real confirm flow, holdings rendering and cash accounting; Web tests cover decoders, confirm guard, stale-response protection and token invalidation.
Diffstat (limited to 'src/FundLab.Api/App.fs')
-rw-r--r--src/FundLab.Api/App.fs30
1 files changed, 2 insertions, 28 deletions
diff --git a/src/FundLab.Api/App.fs b/src/FundLab.Api/App.fs
index 839a641..97787aa 100644
--- a/src/FundLab.Api/App.fs
+++ b/src/FundLab.Api/App.fs
@@ -57,19 +57,6 @@ type FundApiResponse =
status: string
}
-type SubscriptionOrderApiResponse =
- {
- id: Guid
- fundId: Guid
- fundCode: string
- amount: string
- feeAmount: string
- reservedTotal: string
- status: string
- submittedAt: string
- isSynthetic: bool
- }
-
type ConfirmedQuoteEvidenceResponse =
{
navDate: string
@@ -198,20 +185,7 @@ module App =
status = fund.Status
}
- let private orderResponse (order: SubscriptionOrderRecord) : SubscriptionOrderApiResponse =
- {
- id = order.Id
- fundId = order.FundId
- fundCode = order.FundCode
- amount = cashText order.Amount
- feeAmount = cashText order.FeeAmount
- reservedTotal = cashText order.ReservedTotal
- status = order.Status
- submittedAt = timestampText order.SubmittedAt
- isSynthetic = order.IsSynthetic
- }
-
- let private confirmationResponse (order: SubscriptionOrderRecord) : SubscriptionOrderDetailResponse =
+ let private orderResponse (order: SubscriptionOrderRecord) : SubscriptionOrderDetailResponse =
let quoteEvidence =
order.ConfirmedQuote
|> Option.map (fun quote ->
@@ -461,7 +435,7 @@ module App =
match repository.ConfirmSubscriptionOrder(idempotencyKey, fundId, orderId) with
| OrderConfirmed order
| ConfirmReplayed order
- | ConfirmPendingNav order -> json (confirmationResponse order) next ctx
+ | ConfirmPendingNav order -> json (orderResponse order) next ctx
| ConfirmIdempotencyConflict ->
errorResponse 409 "IDEMPOTENCY_CONFLICT" "idempotency key was used with a different request" next ctx
| ConfirmAlreadyConfirmed ->