Adds on-chain Bitcoin payment support

Adds support for on-chain Bitcoin payments by:
- Introducing a new `Assets:Bitcoin:OnChain` account.
- Updating the `SettleReceivable` and `PayUser` models to include `txid` for storing transaction IDs.
- Modifying the API endpoints to handle `btc_onchain` as a valid payment method and associate it with the new account.

This allows tracking on-chain Bitcoin transactions separately from Lightning Network payments.
This commit is contained in:
padreug 2025-11-01 23:45:28 +01:00
parent 8b16ead5b1
commit e2472d13a2
3 changed files with 75 additions and 39 deletions

View file

@ -786,7 +786,7 @@ async def api_settle_receivable(
)
# Validate payment method
valid_methods = ["cash", "bank_transfer", "check", "other"]
valid_methods = ["cash", "bank_transfer", "check", "lightning", "btc_onchain", "other"]
if data.payment_method.lower() not in valid_methods:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
@ -803,6 +803,8 @@ async def api_settle_receivable(
"cash": "Cash",
"bank_transfer": "Bank Account",
"check": "Bank Account",
"lightning": "Assets:Bitcoin:Lightning",
"btc_onchain": "Assets:Bitcoin:OnChain",
"other": "Cash"
}
@ -852,6 +854,14 @@ async def api_settle_receivable(
amount_in_sats = int(data.amount)
line_metadata = {}
# Add payment hash for lightning payments
if data.payment_hash:
line_metadata["payment_hash"] = data.payment_hash
# Add transaction ID for on-chain Bitcoin payments
if data.txid:
line_metadata["txid"] = data.txid
# Add meta information for audit trail
entry_meta = {
"source": "manual_settlement",
@ -924,7 +934,7 @@ async def api_pay_user(
)
# Validate payment method
valid_methods = ["cash", "bank_transfer", "check", "lightning", "other"]
valid_methods = ["cash", "bank_transfer", "check", "lightning", "btc_onchain", "other"]
if data.payment_method.lower() not in valid_methods:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
@ -937,43 +947,31 @@ async def api_pay_user(
)
# Get the appropriate asset account based on payment method
if data.payment_method.lower() == "lightning":
# For lightning, use the Lightning Wallet account
payment_account = await get_account_by_name("Lightning Wallet")
if not payment_account:
# Create it if it doesn't exist
payment_account = await create_account(
CreateAccount(
name="Lightning Wallet",
account_type=AccountType.ASSET,
description="Lightning Network wallet for Castle",
),
wallet.wallet.id,
)
else:
# For cash/bank/check
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)
payment_account_map = {
"cash": "Cash",
"bank_transfer": "Bank Account",
"check": "Bank Account",
"lightning": "Assets:Bitcoin:Lightning",
"btc_onchain": "Assets:Bitcoin:OnChain",
"other": "Cash"
}
if not payment_account:
# Try to find any asset account
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
account_name = payment_account_map.get(data.payment_method.lower(), "Cash")
payment_account = await get_account_by_name(account_name)
if not payment_account:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail=f"Payment account '{account_name}' not found. Please create it first.",
)
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.",
)
# Determine the amount to record in the journal
# IMPORTANT: Always record in satoshis to match the payable account balance
@ -1003,6 +1001,10 @@ async def api_pay_user(
if data.payment_hash:
line_metadata["payment_hash"] = data.payment_hash
# Add transaction ID for on-chain Bitcoin payments
if data.txid:
line_metadata["txid"] = data.txid
# Create journal entry
# DR Accounts Payable (liability decreased), CR Cash/Lightning/Bank (asset decreased)
# This records that castle paid its debt