Adds settle receivable functionality
Implements a "Settle Receivable" feature for super users to record manual payments from users who owe money. Introduces a dialog for inputting payment details (amount, method, description, reference), triggers an API call to record the transaction, and updates user balances and transaction history. This is for non-lightning payments like cash, bank transfers, or checks.
This commit is contained in:
parent
d06f46a63c
commit
1412359172
4 changed files with 278 additions and 1 deletions
111
views_api.py
111
views_api.py
|
|
@ -59,6 +59,7 @@ from .models import (
|
|||
ReceivableEntry,
|
||||
RecordPayment,
|
||||
RevenueEntry,
|
||||
SettleReceivable,
|
||||
UserBalance,
|
||||
UserWalletSettings,
|
||||
)
|
||||
|
|
@ -727,6 +728,116 @@ async def api_pay_user(
|
|||
}
|
||||
|
||||
|
||||
@castle_api_router.post("/api/v1/receivables/settle")
|
||||
async def api_settle_receivable(
|
||||
data: SettleReceivable,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> dict:
|
||||
"""
|
||||
Manually settle a receivable (record when user pays castle in person).
|
||||
|
||||
This endpoint is for non-lightning payments like:
|
||||
- Cash payments
|
||||
- Bank transfers
|
||||
- Other manual settlements
|
||||
|
||||
Admin only.
|
||||
"""
|
||||
from lnbits.settings import settings as lnbits_settings
|
||||
|
||||
if wallet.wallet.user != lnbits_settings.super_user:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="Only super user can settle receivables",
|
||||
)
|
||||
|
||||
# Validate payment method
|
||||
valid_methods = ["cash", "bank_transfer", "check", "other"]
|
||||
if data.payment_method.lower() not in valid_methods:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"Invalid payment method. Must be one of: {', '.join(valid_methods)}",
|
||||
)
|
||||
|
||||
# Get user's receivable account (what user owes)
|
||||
user_receivable = await get_or_create_user_account(
|
||||
data.user_id, AccountType.ASSET, "Accounts Receivable"
|
||||
)
|
||||
|
||||
# Get the appropriate asset account based on payment method
|
||||
payment_account_map = {
|
||||
"cash": "Cash",
|
||||
"bank_transfer": "Bank Account",
|
||||
"check": "Bank Account",
|
||||
"other": "Cash"
|
||||
}
|
||||
|
||||
account_name = payment_account_map.get(data.payment_method.lower(), "Cash")
|
||||
payment_account = await get_account_by_name(account_name)
|
||||
|
||||
# If account doesn't exist, try to find or create a generic one
|
||||
if not payment_account:
|
||||
# Try to find any asset account that's not receivable
|
||||
all_accounts = await get_all_accounts()
|
||||
for acc in all_accounts:
|
||||
if acc.account_type == AccountType.ASSET and "receivable" not in acc.name.lower():
|
||||
payment_account = acc
|
||||
break
|
||||
|
||||
if not payment_account:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail=f"Payment account '{account_name}' not found. Please create it first.",
|
||||
)
|
||||
|
||||
# Create journal entry
|
||||
# DR Cash/Bank (asset increased), CR Accounts Receivable (asset decreased)
|
||||
# This records that user paid their debt
|
||||
|
||||
# Add meta information for audit trail
|
||||
entry_meta = {
|
||||
"source": "manual_settlement",
|
||||
"payment_method": data.payment_method,
|
||||
"settled_by": wallet.wallet.user,
|
||||
"payer_user_id": data.user_id,
|
||||
}
|
||||
|
||||
entry_data = CreateJournalEntry(
|
||||
description=data.description,
|
||||
reference=data.reference or f"MANUAL-{data.user_id[:8]}",
|
||||
flag=JournalEntryFlag.CLEARED, # Manual payments are immediately cleared
|
||||
meta=entry_meta,
|
||||
lines=[
|
||||
CreateEntryLine(
|
||||
account_id=payment_account.id,
|
||||
debit=data.amount,
|
||||
credit=0,
|
||||
description=f"Payment received via {data.payment_method}",
|
||||
),
|
||||
CreateEntryLine(
|
||||
account_id=user_receivable.id,
|
||||
debit=0,
|
||||
credit=data.amount,
|
||||
description="Receivable settled",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
entry = await create_journal_entry(entry_data, wallet.wallet.id)
|
||||
|
||||
# Get updated balance
|
||||
balance = await get_user_balance(data.user_id)
|
||||
|
||||
return {
|
||||
"journal_entry_id": entry.id,
|
||||
"user_id": data.user_id,
|
||||
"amount_settled": data.amount,
|
||||
"payment_method": data.payment_method,
|
||||
"new_balance": balance.balance,
|
||||
"message": f"Receivable settled successfully via {data.payment_method}",
|
||||
}
|
||||
|
||||
|
||||
# ===== SETTINGS ENDPOINTS =====
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue