refactor: payment.check_status() into check_payment_status(payment) (#3747)

Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
This commit is contained in:
dni ⚡
2026-02-25 07:53:57 +01:00
co-authored by Vlad Stan
parent c65ab2af87
commit 1d9808b269
8 changed files with 101 additions and 67 deletions
+10 -53
View File
@@ -6,23 +6,16 @@ from typing import Literal
from fastapi import Query from fastapi import Query
from lnurl import LnurlWithdrawResponse from lnurl import LnurlWithdrawResponse
from loguru import logger
from pydantic import BaseModel, Field, validator from pydantic import BaseModel, Field, validator
from lnbits.db import FilterModel from lnbits.db import FilterModel
from lnbits.fiat import get_fiat_provider
from lnbits.fiat.base import ( from lnbits.fiat.base import (
FiatPaymentFailedStatus,
FiatPaymentPendingStatus,
FiatPaymentStatus, FiatPaymentStatus,
FiatPaymentSuccessStatus,
) )
from lnbits.utils.exchange_rates import allowed_currencies from lnbits.utils.exchange_rates import allowed_currencies
from lnbits.wallets import get_funding_source
from lnbits.wallets.base import ( from lnbits.wallets.base import (
PaymentFailedStatus,
PaymentPendingStatus,
PaymentStatus, PaymentStatus,
PaymentSuccessStatus,
) )
@@ -130,59 +123,23 @@ class Payment(BaseModel):
"fiat_" "fiat_"
) )
# DEPRECATED: in v1.5.0, use service check_payment_status instead
async def check_status( async def check_status(
self, skip_internal_payment_notifications: bool | None = False self, skip_internal_payment_notifications: bool | None = False
) -> PaymentStatus: ) -> PaymentStatus:
if self.is_internal: logger.warning("payment.check_status() is deprecated.")
if self.success: from lnbits.core.services.payments import check_payment_status
return PaymentSuccessStatus()
if self.failed:
return PaymentFailedStatus()
if self.is_in and self.fiat_provider:
fiat_status = await self.check_fiat_status(
skip_internal_payment_notifications
)
return PaymentStatus(paid=fiat_status.paid)
return PaymentPendingStatus()
funding_source = get_funding_source()
if self.is_out:
status = await funding_source.get_payment_status(self.checking_id)
else:
status = await funding_source.get_invoice_status(self.checking_id)
return status
return await check_payment_status(self, skip_internal_payment_notifications)
# DEPRECATED: in v1.5.0, use service check_payment_status instead
async def check_fiat_status( async def check_fiat_status(
self, skip_internal_payment_notifications: bool | None = False self, skip_internal_payment_notifications: bool | None = False
) -> FiatPaymentStatus: ) -> FiatPaymentStatus:
if not self.is_internal: logger.warning("payment.check_fiat_status() is deprecated.")
return FiatPaymentPendingStatus() from lnbits.core.services.fiat_providers import check_fiat_status
if self.success:
return FiatPaymentSuccessStatus()
if self.failed:
return FiatPaymentFailedStatus()
if not self.fiat_provider: return await check_fiat_status(self, skip_internal_payment_notifications)
return FiatPaymentPendingStatus()
checking_id = self.extra.get("fiat_checking_id")
if not checking_id:
return FiatPaymentPendingStatus()
fiat_provider = await get_fiat_provider(self.fiat_provider)
if not fiat_provider:
return FiatPaymentPendingStatus()
fiat_status = await fiat_provider.get_invoice_status(checking_id)
if skip_internal_payment_notifications:
return fiat_status
if fiat_status.success:
# notify receivers asynchronously
from lnbits.tasks import internal_invoice_queue
await internal_invoice_queue.put(self.checking_id)
return fiat_status
class PaymentFilters(FilterModel): class PaymentFilters(FilterModel):
+4
View File
@@ -1,3 +1,4 @@
from .fiat_providers import check_fiat_status
from .funding_source import ( from .funding_source import (
get_balance_delta, get_balance_delta,
switch_to_voidwallet, switch_to_voidwallet,
@@ -7,6 +8,7 @@ from .notifications import enqueue_admin_notification, send_payment_notification
from .payments import ( from .payments import (
calculate_fiat_amounts, calculate_fiat_amounts,
cancel_hold_invoice, cancel_hold_invoice,
check_payment_status,
check_transaction_status, check_transaction_status,
check_wallet_limits, check_wallet_limits,
create_fiat_invoice, create_fiat_invoice,
@@ -40,6 +42,8 @@ __all__ = [
"calculate_fiat_amounts", "calculate_fiat_amounts",
"cancel_hold_invoice", "cancel_hold_invoice",
"check_admin_settings", "check_admin_settings",
"check_fiat_status",
"check_payment_status",
"check_transaction_status", "check_transaction_status",
"check_wallet_limits", "check_wallet_limits",
"check_webpush_settings", "check_webpush_settings",
+40
View File
@@ -12,6 +12,12 @@ from lnbits.core.models import CreatePayment, Payment, PaymentState
from lnbits.core.models.misc import SimpleStatus from lnbits.core.models.misc import SimpleStatus
from lnbits.db import Connection from lnbits.db import Connection
from lnbits.fiat import get_fiat_provider from lnbits.fiat import get_fiat_provider
from lnbits.fiat.base import (
FiatPaymentFailedStatus,
FiatPaymentPendingStatus,
FiatPaymentStatus,
FiatPaymentSuccessStatus,
)
from lnbits.settings import settings from lnbits.settings import settings
@@ -29,6 +35,40 @@ async def handle_fiat_payment_confirmation(
logger.warning(e) logger.warning(e)
async def check_fiat_status(
payment: Payment, skip_internal_payment_notifications: bool | None = False
) -> FiatPaymentStatus:
if not payment.is_internal:
return FiatPaymentPendingStatus()
if payment.success:
return FiatPaymentSuccessStatus()
if payment.failed:
return FiatPaymentFailedStatus()
if not payment.fiat_provider:
return FiatPaymentPendingStatus()
checking_id = payment.extra.get("fiat_checking_id")
if not checking_id:
return FiatPaymentPendingStatus()
fiat_provider = await get_fiat_provider(payment.fiat_provider)
if not fiat_provider:
return FiatPaymentPendingStatus()
fiat_status = await fiat_provider.get_invoice_status(checking_id)
if skip_internal_payment_notifications:
return fiat_status
if fiat_status.success:
# notify receivers asynchronously
from lnbits.tasks import internal_invoice_queue
await internal_invoice_queue.put(payment.checking_id)
return fiat_status
def check_stripe_signature( def check_stripe_signature(
payload: bytes, payload: bytes,
sig_header: str | None, sig_header: str | None,
+27 -3
View File
@@ -25,6 +25,7 @@ from lnbits.utils.exchange_rates import fiat_amount_as_satoshis, satoshis_amount
from lnbits.wallets import fake_wallet, get_funding_source from lnbits.wallets import fake_wallet, get_funding_source
from lnbits.wallets.base import ( from lnbits.wallets.base import (
InvoiceResponse, InvoiceResponse,
PaymentFailedStatus,
PaymentPendingStatus, PaymentPendingStatus,
PaymentResponse, PaymentResponse,
PaymentStatus, PaymentStatus,
@@ -47,6 +48,7 @@ from ..models import (
PaymentState, PaymentState,
Wallet, Wallet,
) )
from .fiat_providers import check_fiat_status
from .notifications import send_payment_notification_in_background from .notifications import send_payment_notification_in_background
payment_lock = asyncio.Lock() payment_lock = asyncio.Lock()
@@ -364,7 +366,7 @@ async def update_pending_payments(wallet_id: str):
async def update_pending_payment( async def update_pending_payment(
payment: Payment, conn: Connection | None = None payment: Payment, conn: Connection | None = None
) -> Payment: ) -> Payment:
status = await payment.check_status() status = await check_payment_status(payment)
if status.failed: if status.failed:
payment.status = PaymentState.FAILED payment.status = PaymentState.FAILED
await update_payment(payment, conn=conn) await update_payment(payment, conn=conn)
@@ -618,7 +620,29 @@ async def check_transaction_status(
if payment.status == PaymentState.SUCCESS.value: if payment.status == PaymentState.SUCCESS.value:
return PaymentSuccessStatus(fee_msat=payment.fee) return PaymentSuccessStatus(fee_msat=payment.fee)
return await payment.check_status() return await check_payment_status(payment)
async def check_payment_status(
payment: Payment, skip_internal_payment_notifications: bool | None = False
) -> PaymentStatus:
if payment.is_internal:
if payment.success:
return PaymentSuccessStatus()
if payment.failed:
return PaymentFailedStatus()
if payment.is_in and payment.fiat_provider:
fiat_status = await check_fiat_status(
payment, skip_internal_payment_notifications
)
return PaymentStatus(paid=fiat_status.paid)
return PaymentPendingStatus()
funding_source = get_funding_source()
if payment.is_out:
status = await funding_source.get_payment_status(payment.checking_id)
else:
status = await funding_source.get_invoice_status(payment.checking_id)
return status
async def get_payments_daily_stats( async def get_payments_daily_stats(
@@ -869,7 +893,7 @@ async def _verify_external_payment(
raise PaymentError("Payment already paid.", status="success") raise PaymentError("Payment already paid.", status="success")
# payment failed # payment failed
status = await payment.check_status() status = await check_payment_status(payment)
if status.failed: if status.failed:
raise PaymentError( raise PaymentError(
"Payment is failed node, retrying is not possible.", status="failed" "Payment is failed node, retrying is not possible.", status="failed"
+6 -5
View File
@@ -9,6 +9,7 @@ from lnbits.core.crud.payments import (
from lnbits.core.models.misc import SimpleStatus from lnbits.core.models.misc import SimpleStatus
from lnbits.core.models.payments import CreateInvoice from lnbits.core.models.payments import CreateInvoice
from lnbits.core.services.fiat_providers import ( from lnbits.core.services.fiat_providers import (
check_fiat_status,
check_stripe_signature, check_stripe_signature,
verify_paypal_webhook, verify_paypal_webhook,
) )
@@ -87,7 +88,7 @@ async def _handle_stripe_intent_session_completed(event: dict):
if not payment: if not payment:
logger.warning(f"No payment found for hash: '{payment_hash}'.") logger.warning(f"No payment found for hash: '{payment_hash}'.")
return return
await payment.check_fiat_status() await check_fiat_status(payment)
async def _handle_stripe_checkout_session_completed(event: dict): async def _handle_stripe_checkout_session_completed(event: dict):
@@ -110,7 +111,7 @@ async def _handle_stripe_checkout_session_completed(event: dict):
payment = await get_standalone_payment(payment_hash) payment = await get_standalone_payment(payment_hash)
if not payment: if not payment:
raise ValueError(f"No payment found for hash: '{payment_hash}'.") raise ValueError(f"No payment found for hash: '{payment_hash}'.")
await payment.check_fiat_status() await check_fiat_status(payment)
async def _handle_stripe_subscription_invoice_paid(event: dict): async def _handle_stripe_subscription_invoice_paid(event: dict):
@@ -155,7 +156,7 @@ async def _handle_stripe_subscription_invoice_paid(event: dict):
), ),
) )
await payment.check_fiat_status() await check_fiat_status(payment)
async def _get_stripe_subscription_payment_options( async def _get_stripe_subscription_payment_options(
@@ -192,7 +193,7 @@ async def handle_paypal_event(event: dict):
if not payment: if not payment:
logger.warning(f"No payment found for hash: '{payment_hash}'.") logger.warning(f"No payment found for hash: '{payment_hash}'.")
return return
await payment.check_fiat_status() await check_fiat_status(payment)
return return
if event_type in ( if event_type in (
@@ -247,7 +248,7 @@ async def _handle_paypal_subscription_payment(resource: dict):
), ),
) )
await payment.check_fiat_status() await check_fiat_status(payment)
def _paypal_extract_payment_hash(resource: dict) -> str | None: def _paypal_extract_payment_hash(resource: dict) -> str | None:
+5 -1
View File
@@ -178,7 +178,11 @@ async def invoice_callback_dispatcher(checking_id: str, is_internal: bool = Fals
logger.warning(f"Payment '{checking_id}' is not incoming, skipping.") logger.warning(f"Payment '{checking_id}' is not incoming, skipping.")
return return
status = await payment.check_status(skip_internal_payment_notifications=True) from lnbits.core.services.payments import check_payment_status
status = await check_payment_status(
payment, skip_internal_payment_notifications=True
)
payment.fee = status.fee_msat or payment.fee payment.fee = status.fee_msat or payment.fee
# only overwrite preimage if status.preimage provides it # only overwrite preimage if status.preimage provides it
payment.preimage = status.preimage or payment.preimage payment.preimage = status.preimage or payment.preimage
+6 -2
View File
@@ -7,7 +7,11 @@ from lnbits import bolt11
from lnbits.core.crud import get_standalone_payment, update_payment from lnbits.core.crud import get_standalone_payment, update_payment
from lnbits.core.crud.wallets import create_wallet, get_wallet from lnbits.core.crud.wallets import create_wallet, get_wallet
from lnbits.core.models import CreateInvoice, Payment, PaymentState from lnbits.core.models import CreateInvoice, Payment, PaymentState
from lnbits.core.services import fee_reserve_total, get_balance_delta from lnbits.core.services import (
check_payment_status,
fee_reserve_total,
get_balance_delta,
)
from lnbits.core.services.payments import pay_invoice, update_wallet_balance from lnbits.core.services.payments import pay_invoice, update_wallet_balance
from lnbits.core.services.users import create_user_account from lnbits.core.services.users import create_user_account
from lnbits.exceptions import PaymentError from lnbits.exceptions import PaymentError
@@ -355,7 +359,7 @@ async def test_pay_hold_invoice_check_pending_and_fail_cancel_payment_task_in_me
assert payment_db_after_settlement is not None assert payment_db_after_settlement is not None
# payment is failed # payment is failed
status = await payment_db_after_settlement.check_status() status = await check_payment_status(payment_db_after_settlement)
assert not status.paid assert not status.paid
assert status.failed assert status.failed
+3 -3
View File
@@ -12,7 +12,7 @@ from lnbits.core.crud.wallets import create_wallet
from lnbits.core.models.payments import CreateInvoice, PaymentState from lnbits.core.models.payments import CreateInvoice, PaymentState
from lnbits.core.models.users import User from lnbits.core.models.users import User
from lnbits.core.models.wallets import Wallet from lnbits.core.models.wallets import Wallet
from lnbits.core.services import payments from lnbits.core.services import check_payment_status, payments
from lnbits.core.services.fiat_providers import ( from lnbits.core.services.fiat_providers import (
check_stripe_signature, check_stripe_signature,
handle_fiat_payment_confirmation, handle_fiat_payment_confirmation,
@@ -221,7 +221,7 @@ async def test_create_wallet_fiat_invoice_success(
assert payment.checking_id.startswith("fiat_stripe_") assert payment.checking_id.startswith("fiat_stripe_")
assert payment.fee <= 0 assert payment.fee <= 0
status = await payment.check_status() status = await check_payment_status(payment)
assert status.success is False assert status.success is False
assert status.pending is True assert status.pending is True
@@ -230,7 +230,7 @@ async def test_create_wallet_fiat_invoice_success(
"lnbits.fiat.StripeWallet.get_invoice_status", "lnbits.fiat.StripeWallet.get_invoice_status",
AsyncMock(return_value=fiat_mock_status), AsyncMock(return_value=fiat_mock_status),
) )
status = await payment.check_status() status = await check_payment_status(payment)
assert status.paid is True assert status.paid is True
assert status.success is True assert status.success is True