Enables admin to generate invoices for users
Allows administrators to generate payment invoices on behalf of specific users. This is useful for handling settlement invoices in certain scenarios. The changes include: - Adding a `user_id` field to the generate payment invoice request model - Updating the API endpoint to accept the `user_id` parameter - Implementing checks to ensure only superusers can generate invoices for other users - Updating the memo and extra data to reflect the target user
This commit is contained in:
parent
a2a58d323b
commit
af424109f1
3 changed files with 36 additions and 8 deletions
|
|
@ -173,6 +173,7 @@ class GeneratePaymentInvoice(BaseModel):
|
|||
"""Generate payment invoice request"""
|
||||
|
||||
amount: int
|
||||
user_id: Optional[str] = None # For admin-generated settlement invoices
|
||||
|
||||
|
||||
class RecordPayment(BaseModel):
|
||||
|
|
|
|||
|
|
@ -915,7 +915,8 @@ window.app = Vue.createApp({
|
|||
'/castle/api/v1/generate-payment-invoice',
|
||||
this.g.user.wallets[0].adminkey,
|
||||
{
|
||||
amount: this.settleReceivableDialog.amount
|
||||
amount: this.settleReceivableDialog.amount,
|
||||
user_id: this.settleReceivableDialog.user_id // Specify which user this invoice is for
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
40
views_api.py
40
views_api.py
|
|
@ -559,10 +559,26 @@ async def api_generate_payment_invoice(
|
|||
"""
|
||||
Generate an invoice on the Castle wallet for user to pay their balance.
|
||||
User can then pay this invoice to settle their debt.
|
||||
|
||||
If user_id is provided (admin only), the invoice is generated for that specific user.
|
||||
"""
|
||||
from lnbits.core.crud.wallets import get_wallet
|
||||
from lnbits.core.models import CreateInvoice
|
||||
from lnbits.core.services import create_payment_request
|
||||
from lnbits.settings import settings as lnbits_settings
|
||||
|
||||
# Determine which user this invoice is for
|
||||
if data.user_id:
|
||||
# Admin generating invoice for a specific user
|
||||
if wallet.wallet.user != lnbits_settings.super_user:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="Only super user can generate invoices for other users",
|
||||
)
|
||||
target_user_id = data.user_id
|
||||
else:
|
||||
# User generating invoice for themselves
|
||||
target_user_id = wallet.wallet.user
|
||||
|
||||
# Get castle wallet ID
|
||||
castle_wallet_id = await check_castle_wallet_configured()
|
||||
|
|
@ -571,9 +587,9 @@ async def api_generate_payment_invoice(
|
|||
invoice_data = CreateInvoice(
|
||||
out=False,
|
||||
amount=data.amount,
|
||||
memo=f"Payment from user {wallet.wallet.user[:8]} to Castle",
|
||||
memo=f"Payment from user {target_user_id[:8]} to Castle",
|
||||
unit="sat",
|
||||
extra={"user_id": wallet.wallet.user, "type": "castle_payment"},
|
||||
extra={"user_id": target_user_id, "type": "castle_payment"},
|
||||
)
|
||||
|
||||
payment = await create_payment_request(castle_wallet_id, invoice_data)
|
||||
|
|
@ -602,6 +618,8 @@ async def api_record_payment(
|
|||
"""
|
||||
Record a lightning payment in accounting after invoice is paid.
|
||||
This reduces what the user owes to the castle.
|
||||
|
||||
The user_id is extracted from the payment metadata (set during invoice generation).
|
||||
"""
|
||||
from lnbits.core.crud.payments import get_standalone_payment
|
||||
|
||||
|
|
@ -617,9 +635,17 @@ async def api_record_payment(
|
|||
status_code=HTTPStatus.BAD_REQUEST, detail="Payment not yet paid"
|
||||
)
|
||||
|
||||
# Get user_id from payment metadata (set during invoice generation)
|
||||
# This allows admins to record payments on behalf of users
|
||||
target_user_id = wallet.wallet.user # Default to wallet user
|
||||
if payment.extra and isinstance(payment.extra, dict):
|
||||
metadata_user_id = payment.extra.get("user_id")
|
||||
if metadata_user_id:
|
||||
target_user_id = metadata_user_id
|
||||
|
||||
# Get user's receivable account (what user owes)
|
||||
user_receivable = await get_or_create_user_account(
|
||||
wallet.wallet.user, AccountType.ASSET, "Accounts Receivable"
|
||||
target_user_id, AccountType.ASSET, "Accounts Receivable"
|
||||
)
|
||||
|
||||
# Get lightning account
|
||||
|
|
@ -638,11 +664,11 @@ async def api_record_payment(
|
|||
"source": "lightning_payment",
|
||||
"created_via": "record_payment",
|
||||
"payment_hash": data.payment_hash,
|
||||
"payer_user_id": wallet.wallet.user,
|
||||
"payer_user_id": target_user_id,
|
||||
}
|
||||
|
||||
entry_data = CreateJournalEntry(
|
||||
description=f"Lightning payment from user {wallet.wallet.user[:8]}",
|
||||
description=f"Lightning payment from user {target_user_id[:8]}",
|
||||
reference=data.payment_hash,
|
||||
flag=JournalEntryFlag.CLEARED, # Payment is immediately cleared
|
||||
meta=entry_meta,
|
||||
|
|
@ -662,10 +688,10 @@ async def api_record_payment(
|
|||
],
|
||||
)
|
||||
|
||||
entry = await create_journal_entry(entry_data, wallet.wallet.user)
|
||||
entry = await create_journal_entry(entry_data, target_user_id)
|
||||
|
||||
# Get updated balance
|
||||
balance = await get_user_balance(wallet.wallet.user)
|
||||
balance = await get_user_balance(target_user_id)
|
||||
|
||||
return {
|
||||
"journal_entry_id": entry.id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue