213 lines
5.2 KiB
Python
213 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from collections.abc import AsyncGenerator, Coroutine
|
|
from typing import TYPE_CHECKING, Any, NamedTuple
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
if TYPE_CHECKING:
|
|
pass
|
|
|
|
|
|
class FiatStatusResponse(NamedTuple):
|
|
error_message: str | None = None
|
|
balance: float = 0
|
|
|
|
|
|
class FiatInvoiceResponse(NamedTuple):
|
|
ok: bool
|
|
checking_id: str | None = None # payment_hash, rpc_id
|
|
payment_request: str | None = None
|
|
error_message: str | None = None
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return self.ok is True
|
|
|
|
@property
|
|
def pending(self) -> bool:
|
|
return self.ok is None
|
|
|
|
@property
|
|
def failed(self) -> bool:
|
|
return self.ok is False
|
|
|
|
|
|
class FiatPaymentResponse(NamedTuple):
|
|
# when ok is None it means we don't know if this succeeded
|
|
ok: bool | None = None
|
|
checking_id: str | None = None # payment_hash, rcp_id
|
|
fee: float | None = None
|
|
error_message: str | None = None
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return self.ok is True
|
|
|
|
@property
|
|
def pending(self) -> bool:
|
|
return self.ok is None
|
|
|
|
@property
|
|
def failed(self) -> bool:
|
|
return self.ok is False
|
|
|
|
|
|
class FiatPaymentStatus(NamedTuple):
|
|
paid: bool | None = None
|
|
fee: float | None = None # todo: what fee is this?
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return self.paid is True
|
|
|
|
@property
|
|
def pending(self) -> bool:
|
|
return self.paid is not True
|
|
|
|
@property
|
|
def failed(self) -> bool:
|
|
return self.paid is False
|
|
|
|
def __str__(self) -> str:
|
|
if self.success:
|
|
return "success"
|
|
if self.failed:
|
|
return "failed"
|
|
return "pending"
|
|
|
|
|
|
class FiatSubscriptionPaymentOptions(BaseModel):
|
|
|
|
memo: str | None = Field(
|
|
default=None,
|
|
description="Payments created by the recurring subscription"
|
|
" will have this memo.",
|
|
)
|
|
wallet_id: str | None = Field(
|
|
default=None,
|
|
description="Payments created by the recurring subscription"
|
|
" will be made to this wallet.",
|
|
)
|
|
subscription_request_id: str | None = Field(
|
|
default=None,
|
|
description="Unique ID that can be used to identify the subscription request."
|
|
"If not provided, one will be generated.",
|
|
)
|
|
tag: str | None = Field(
|
|
default=None,
|
|
description="Payments created by the recurring subscription"
|
|
" will have this tag. Admin only.",
|
|
)
|
|
extra: dict[str, Any] | None = Field(
|
|
default=None,
|
|
description="Payments created by the recurring subscription"
|
|
" will merge this extra data to the payment extra. Admin only.",
|
|
)
|
|
|
|
success_url: str | None = Field(
|
|
default="https://my.lnbits.com",
|
|
description="The URL to redirect the user to after the"
|
|
" subscription is successfully created.",
|
|
)
|
|
|
|
|
|
class CreateFiatSubscription(BaseModel):
|
|
subscription_id: str
|
|
quantity: int
|
|
payment_options: FiatSubscriptionPaymentOptions
|
|
|
|
|
|
class FiatSubscriptionResponse(BaseModel):
|
|
ok: bool = True
|
|
subscription_request_id: str | None = None
|
|
checkout_session_url: str | None = None
|
|
error_message: str | None = None
|
|
|
|
|
|
class FiatPaymentSuccessStatus(FiatPaymentStatus):
|
|
paid = True
|
|
|
|
|
|
class FiatPaymentFailedStatus(FiatPaymentStatus):
|
|
paid = False
|
|
|
|
|
|
class FiatPaymentPendingStatus(FiatPaymentStatus):
|
|
paid = None
|
|
|
|
|
|
class FiatProvider(ABC):
|
|
@abstractmethod
|
|
async def cleanup(self):
|
|
pass
|
|
|
|
@abstractmethod
|
|
def status(
|
|
self, only_check_settings: bool | None = False
|
|
) -> Coroutine[None, None, FiatStatusResponse]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def create_invoice(
|
|
self,
|
|
amount: float,
|
|
payment_hash: str,
|
|
currency: str,
|
|
memo: str | None = None,
|
|
extra: dict[str, Any] | None = None,
|
|
**kwargs,
|
|
) -> Coroutine[None, None, FiatInvoiceResponse]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def create_subscription(
|
|
self,
|
|
subscription_id: str,
|
|
quantity: int,
|
|
payment_options: FiatSubscriptionPaymentOptions,
|
|
**kwargs,
|
|
) -> Coroutine[None, None, FiatSubscriptionResponse]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def cancel_subscription(
|
|
self,
|
|
subscription_id: str,
|
|
correlation_id: str,
|
|
**kwargs,
|
|
) -> Coroutine[None, None, FiatSubscriptionResponse]:
|
|
"""
|
|
Cancel a subscription.
|
|
Args:
|
|
subscription_id: The ID of the subscription to cancel.
|
|
correlation_id: An identifier used to verify that the subscription belongs
|
|
to the user that made the request. Usually the wallet ID.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def pay_invoice(
|
|
self,
|
|
payment_request: str,
|
|
) -> Coroutine[None, None, FiatPaymentResponse]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_invoice_status(
|
|
self, checking_id: str
|
|
) -> Coroutine[None, None, FiatPaymentStatus]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_payment_status(
|
|
self, checking_id: str
|
|
) -> Coroutine[None, None, FiatPaymentStatus]:
|
|
pass
|
|
|
|
async def paid_invoices_stream(
|
|
self,
|
|
) -> AsyncGenerator[str, None]:
|
|
yield ""
|