Adds balance payment feature
Implements a feature that allows users to pay their outstanding balance via Lightning. The changes include: - Adds the UI elements for invoice generation and display, including QR code. - Integrates backend endpoints to generate and record payments. - Adds polling mechanism to track payments and update balance. - Creates new database models to support manual payment requests.
This commit is contained in:
parent
eb9a3c1600
commit
ef3e2d9e0d
4 changed files with 232 additions and 49 deletions
74
views_api.py
74
views_api.py
|
|
@ -444,20 +444,66 @@ async def api_get_all_balances(
|
|||
# ===== PAYMENT ENDPOINTS =====
|
||||
|
||||
|
||||
@castle_api_router.post("/api/v1/pay-balance")
|
||||
async def api_pay_balance(
|
||||
@castle_api_router.post("/api/v1/generate-payment-invoice")
|
||||
async def api_generate_payment_invoice(
|
||||
amount: int,
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
) -> dict:
|
||||
"""
|
||||
Record a payment from user to castle (reduces what user owes or what castle owes user).
|
||||
This should be called after an invoice is paid.
|
||||
Generate an invoice on the Castle wallet for user to pay their balance.
|
||||
User can then pay this invoice to settle their debt.
|
||||
"""
|
||||
wallet_id = wallet.wallet.id
|
||||
from lnbits.core.models import CreateInvoice
|
||||
from lnbits.core.services import create_payment_request
|
||||
|
||||
# Get castle wallet ID
|
||||
castle_wallet_id = await check_castle_wallet_configured()
|
||||
|
||||
# Create invoice on castle wallet
|
||||
invoice_data = CreateInvoice(
|
||||
out=False,
|
||||
amount=amount,
|
||||
memo=f"Payment from user {wallet.wallet.user[:8]} to Castle",
|
||||
unit="sat",
|
||||
extra={"user_id": wallet.wallet.user, "type": "castle_payment"},
|
||||
)
|
||||
|
||||
payment = await create_payment_request(castle_wallet_id, invoice_data)
|
||||
|
||||
return {
|
||||
"payment_hash": payment.payment_hash,
|
||||
"payment_request": payment.bolt11,
|
||||
"amount": amount,
|
||||
"memo": invoice_data.memo,
|
||||
}
|
||||
|
||||
|
||||
@castle_api_router.post("/api/v1/record-payment")
|
||||
async def api_record_payment(
|
||||
payment_hash: str,
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
) -> dict:
|
||||
"""
|
||||
Record a lightning payment in accounting after invoice is paid.
|
||||
This reduces what the user owes to the castle.
|
||||
"""
|
||||
from lnbits.core.crud.payments import get_standalone_payment
|
||||
|
||||
# Get the payment details
|
||||
payment = await get_standalone_payment(payment_hash)
|
||||
if not payment:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Payment not found"
|
||||
)
|
||||
|
||||
if not payment.paid:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="Payment not yet paid"
|
||||
)
|
||||
|
||||
# Get user's receivable account (what user owes)
|
||||
user_receivable = await get_or_create_user_account(
|
||||
wallet_id, AccountType.ASSET, "Accounts Receivable"
|
||||
wallet.wallet.user, AccountType.ASSET, "Accounts Receivable"
|
||||
)
|
||||
|
||||
# Get lightning account
|
||||
|
|
@ -467,33 +513,35 @@ async def api_pay_balance(
|
|||
status_code=HTTPStatus.NOT_FOUND, detail="Lightning account not found"
|
||||
)
|
||||
|
||||
# Create journal entry
|
||||
# Create journal entry to record payment
|
||||
# DR Lightning Balance, CR Accounts Receivable (User)
|
||||
# This reduces what the user owes
|
||||
entry_data = CreateJournalEntry(
|
||||
description=f"Payment received from user {wallet_id[:8]}",
|
||||
description=f"Lightning payment from user {wallet.wallet.user[:8]}",
|
||||
reference=payment_hash,
|
||||
lines=[
|
||||
CreateEntryLine(
|
||||
account_id=lightning_account.id,
|
||||
debit=amount,
|
||||
debit=payment.amount,
|
||||
credit=0,
|
||||
description="Lightning payment received",
|
||||
),
|
||||
CreateEntryLine(
|
||||
account_id=user_receivable.id,
|
||||
debit=0,
|
||||
credit=amount,
|
||||
credit=payment.amount,
|
||||
description="Payment applied to balance",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
entry = await create_journal_entry(entry_data, wallet_id)
|
||||
entry = await create_journal_entry(entry_data, wallet.wallet.user)
|
||||
|
||||
# Get updated balance
|
||||
balance = await get_user_balance(wallet_id)
|
||||
balance = await get_user_balance(wallet.wallet.user)
|
||||
|
||||
return {
|
||||
"journal_entry": entry.dict(),
|
||||
"journal_entry_id": entry.id,
|
||||
"new_balance": balance.balance,
|
||||
"message": "Payment recorded successfully",
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue