feat(v2): deposit CRUD + confirmation endpoints (P3b)
Adds 6 operator-scoped deposit endpoints:
POST /api/v1/dca/deposits — record fiat from an LP
(creator_user_id = the
operator who recorded)
GET /api/v1/dca/deposits — operator's deposits (all)
GET /api/v1/dca/deposits?client_id=X — scoped to one LP
GET /api/v1/dca/deposits/{id} — single
PUT /api/v1/dca/deposits/{id} — edit (pending only)
PUT /api/v1/dca/deposits/{id}/status — confirm/reject
DELETE /api/v1/dca/deposits/{id} — delete (pending only)
Cross-checks (client_id, machine_id) at create to prevent operators
binding deposits across machines incorrectly. Edits + deletes are
restricted to pending status so confirmed deposits become immutable
audit records (consistent with v1's existing behaviour from commit
28241e7).
Refs: aiolabs/satmachineadmin#9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7226b8289d
commit
b7f6f0a696
1 changed files with 116 additions and 0 deletions
116
views_api.py
116
views_api.py
|
|
@ -13,13 +13,18 @@ from lnbits.decorators import check_super_user, check_user_exists
|
|||
|
||||
from .crud import (
|
||||
create_dca_client,
|
||||
create_deposit,
|
||||
create_machine,
|
||||
delete_dca_client,
|
||||
delete_deposit,
|
||||
delete_machine,
|
||||
get_client_balance_summary,
|
||||
get_dca_client,
|
||||
get_dca_clients_for_machine,
|
||||
get_dca_clients_for_operator,
|
||||
get_deposit,
|
||||
get_deposits_for_client,
|
||||
get_deposits_for_operator,
|
||||
get_machine,
|
||||
get_machines_for_operator,
|
||||
get_payments_for_operator,
|
||||
|
|
@ -28,19 +33,25 @@ from .crud import (
|
|||
get_settlements_for_operator,
|
||||
get_super_config,
|
||||
update_dca_client,
|
||||
update_deposit,
|
||||
update_deposit_status,
|
||||
update_machine,
|
||||
update_super_config,
|
||||
)
|
||||
from .models import (
|
||||
ClientBalanceSummary,
|
||||
CreateDcaClientData,
|
||||
CreateDepositData,
|
||||
CreateMachineData,
|
||||
DcaClient,
|
||||
DcaDeposit,
|
||||
DcaPayment,
|
||||
DcaSettlement,
|
||||
Machine,
|
||||
SuperConfig,
|
||||
UpdateDcaClientData,
|
||||
UpdateDepositData,
|
||||
UpdateDepositStatusData,
|
||||
UpdateMachineData,
|
||||
UpdateSuperConfigData,
|
||||
)
|
||||
|
|
@ -211,6 +222,111 @@ async def api_get_client_balance(
|
|||
return summary
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Deposits — operator records fiat handed in by an LP at a machine.
|
||||
# =============================================================================
|
||||
|
||||
|
||||
async def _deposit_owned_by(deposit_id: str, user_id: str) -> DcaDeposit:
|
||||
deposit = await get_deposit(deposit_id)
|
||||
if deposit is None:
|
||||
raise HTTPException(HTTPStatus.NOT_FOUND, "Deposit not found")
|
||||
machine = await get_machine(deposit.machine_id)
|
||||
if machine is None or machine.operator_user_id != user_id:
|
||||
raise HTTPException(HTTPStatus.NOT_FOUND, "Deposit not found")
|
||||
return deposit
|
||||
|
||||
|
||||
@satmachineadmin_api_router.post(
|
||||
"/api/v1/dca/deposits", response_model=DcaDeposit
|
||||
)
|
||||
async def api_create_deposit(
|
||||
data: CreateDepositData, user: User = Depends(check_user_exists)
|
||||
) -> DcaDeposit:
|
||||
# Verify the (client_id, machine_id) pair belongs to the operator.
|
||||
client = await _client_owned_by(data.client_id, user.id)
|
||||
if client.machine_id != data.machine_id:
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"client_id and machine_id refer to different machines",
|
||||
)
|
||||
return await create_deposit(user.id, data)
|
||||
|
||||
|
||||
@satmachineadmin_api_router.get(
|
||||
"/api/v1/dca/deposits", response_model=list[DcaDeposit]
|
||||
)
|
||||
async def api_list_deposits(
|
||||
client_id: str | None = None,
|
||||
user: User = Depends(check_user_exists),
|
||||
) -> list[DcaDeposit]:
|
||||
"""Operator's deposits across all their machines; ?client_id scopes to
|
||||
a single LP (with ownership check)."""
|
||||
if client_id is not None:
|
||||
await _client_owned_by(client_id, user.id)
|
||||
return await get_deposits_for_client(client_id)
|
||||
return await get_deposits_for_operator(user.id)
|
||||
|
||||
|
||||
@satmachineadmin_api_router.get(
|
||||
"/api/v1/dca/deposits/{deposit_id}", response_model=DcaDeposit
|
||||
)
|
||||
async def api_get_deposit(
|
||||
deposit_id: str, user: User = Depends(check_user_exists)
|
||||
) -> DcaDeposit:
|
||||
return await _deposit_owned_by(deposit_id, user.id)
|
||||
|
||||
|
||||
@satmachineadmin_api_router.put(
|
||||
"/api/v1/dca/deposits/{deposit_id}", response_model=DcaDeposit
|
||||
)
|
||||
async def api_update_deposit(
|
||||
deposit_id: str,
|
||||
data: UpdateDepositData,
|
||||
user: User = Depends(check_user_exists),
|
||||
) -> DcaDeposit:
|
||||
existing = await _deposit_owned_by(deposit_id, user.id)
|
||||
if existing.status != "pending":
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Only pending deposits can be edited",
|
||||
)
|
||||
updated = await update_deposit(deposit_id, data)
|
||||
if updated is None:
|
||||
raise HTTPException(HTTPStatus.NOT_FOUND, "Deposit not found")
|
||||
return updated
|
||||
|
||||
|
||||
@satmachineadmin_api_router.put(
|
||||
"/api/v1/dca/deposits/{deposit_id}/status", response_model=DcaDeposit
|
||||
)
|
||||
async def api_update_deposit_status(
|
||||
deposit_id: str,
|
||||
data: UpdateDepositStatusData,
|
||||
user: User = Depends(check_user_exists),
|
||||
) -> DcaDeposit:
|
||||
await _deposit_owned_by(deposit_id, user.id)
|
||||
updated = await update_deposit_status(deposit_id, data)
|
||||
if updated is None:
|
||||
raise HTTPException(HTTPStatus.NOT_FOUND, "Deposit not found")
|
||||
return updated
|
||||
|
||||
|
||||
@satmachineadmin_api_router.delete(
|
||||
"/api/v1/dca/deposits/{deposit_id}", status_code=HTTPStatus.NO_CONTENT
|
||||
)
|
||||
async def api_delete_deposit(
|
||||
deposit_id: str, user: User = Depends(check_user_exists)
|
||||
) -> None:
|
||||
existing = await _deposit_owned_by(deposit_id, user.id)
|
||||
if existing.status != "pending":
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Only pending deposits can be deleted",
|
||||
)
|
||||
await delete_deposit(deposit_id)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Settlements (read-only at this phase; landing happens in tasks.py)
|
||||
# =============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue