diff --git a/bfxapi/rest/endpoints/rest_merchant_endpoints.py b/bfxapi/rest/endpoints/rest_merchant_endpoints.py index 0c80110..2e445ce 100644 --- a/bfxapi/rest/endpoints/rest_merchant_endpoints.py +++ b/bfxapi/rest/endpoints/rest_merchant_endpoints.py @@ -1,9 +1,11 @@ -from typing import TypedDict, List, Union, Literal, Optional +from typing import TypedDict, List, Union, Literal, Optional, Any from decimal import Decimal from .. types import * +from .. enums import MerchantSettingsKey from .. middleware import Middleware + from ...utils.camel_and_snake_case_helpers import to_snake_case_keys, to_camel_case_keys _CustomerInfo = TypedDict("_CustomerInfo", { @@ -31,6 +33,19 @@ class RestMerchantEndpoints(Middleware): "id": id, "start": start, "end": end, "limit": limit })) ] + + def get_invoices_paginated(self, page: int = 1, page_size: int = 10, sort: Literal["asc", "desc"] = "asc", + sort_field: Literal["t", "amount", "status"] = "t", status: Optional[List[Literal["CREATED", "PENDING", "COMPLETED", "EXPIRED"]]] = None, fiat: Optional[List[str]] = None, + crypto: Optional[List[str]] = None, id: Optional[str] = None, order_id: Optional[str] = None) -> InvoicePage: + body = to_camel_case_keys({ + "page": page, "page_size": page_size, "sort": sort, + "sort_field": sort_field, "status": status, "fiat": fiat, + "crypto": crypto, "id": id, "order_id": order_id + }) + + data = to_snake_case_keys(self._POST("auth/r/ext/pay/invoices/paginated", body=body)) + + return InvoicePage.parse(data) def get_invoice_count_stats(self, status: Literal["CREATED", "PENDING", "COMPLETED", "EXPIRED"], format: str) -> List[InvoiceStats]: return [ InvoiceStats(**sub_data) for sub_data in self._POST("auth/r/ext/pay/invoice/stats/count", body={ "status": status, "format": format }) ] @@ -66,4 +81,23 @@ class RestMerchantEndpoints(Middleware): return bool(self._POST("auth/w/ext/pay/settings/convert/remove", body={ "baseCcy": base_currency, "convertCcy": convert_currency - })) \ No newline at end of file + })) + + def set_merchant_settings(self, key: MerchantSettingsKey, val: Any) -> bool: + return bool(self._POST("auth/w/ext/pay/settings/set", body={ "key": key, "val": val })) + + def get_merchant_settings(self, key: MerchantSettingsKey) -> Any: + return self._POST("auth/r/ext/pay/settings/get", body={ "key": key }) + + def list_merchant_settings(self, keys: List[MerchantSettingsKey] = list()) -> Dict[MerchantSettingsKey, Any]: + return self._POST("auth/r/ext/pay/settings/list", body={ "keys": keys }) + + def get_deposits(self, start: int, end: int, ccy: Optional[str] = None, unlinked: Optional[bool] = None) -> List[MerchantDeposit]: + return [ MerchantDeposit(**sub_data) for sub_data in to_snake_case_keys(self._POST("auth/r/ext/pay/deposits", body={ + "from": start, "to": end, "ccy": ccy, "unlinked": unlinked + })) ] + + def get_unlinked_deposits(self, ccy: str, start: Optional[int] = None, end: Optional[int] = None) -> List[MerchantUnlinkedDeposit]: + return [ MerchantUnlinkedDeposit(**sub_data) for sub_data in to_snake_case_keys(self._POST("/auth/r/ext/pay/deposits/unlinked", body={ + "ccy": ccy, "start": start, "end": end + })) ] \ No newline at end of file diff --git a/bfxapi/rest/enums.py b/bfxapi/rest/enums.py index 65c1e1a..c256a34 100644 --- a/bfxapi/rest/enums.py +++ b/bfxapi/rest/enums.py @@ -21,7 +21,7 @@ class Config(str, Enum): INFO_PAIR_FUTURES = "pub:info:pair:futures" INFO_TX_STATUS = "pub:info:tx:status" - SPEC_MARGIN = "pub:spec:margin", + SPEC_MARGIN = "pub:spec:margin" FEES = "pub:fees" class Precision(str, Enum): @@ -33,4 +33,14 @@ class Precision(str, Enum): class Sort(int, Enum): ASCENDING = +1 - DESCENDING = -1 \ No newline at end of file + DESCENDING = -1 + +class MerchantSettingsKey(str, Enum): + PREFERRED_FIAT = "bfx_pay_preferred_fiat" + RECOMMEND_STORE = "bfx_pay_recommend_store" + NOTIFY_PAYMENT_COMPLETED = "bfx_pay_notify_payment_completed" + NOTIFY_PAYMENT_COMPLETED_EMAIL = "bfx_pay_notify_payment_completed_email" + NOTIFY_AUTOCONVERT_EXECUTED = "bfx_pay_notify_autoconvert_executed" + DUST_BALANCE_UI = "bfx_pay_dust_balance_ui" + MERCHANT_CUSTOMER_SUPPORT_URL = "bfx_pay_merchant_customer_support_url" + MERCHANT_UNDERPAID_THRESHOLD = "bfx_pay_merchant_underpaid_threshold" \ No newline at end of file diff --git a/bfxapi/rest/types.py b/bfxapi/rest/types.py index 032416d..9e3e752 100644 --- a/bfxapi/rest/types.py +++ b/bfxapi/rest/types.py @@ -638,6 +638,23 @@ class InvoiceSubmission(_Type): force_completed: bool amount_diff: str +@dataclass +class InvoicePage(_Type): + page: int + page_size: int + sort: Literal["asc", "desc"] + sort_field: Literal["t", "amount", "status"] + total_pages: int + total_items: int + items: List[InvoiceSubmission] + + @classmethod + def parse(cls, data: Dict[str, Any]) -> "InvoicePage": + for index, item in enumerate(data["items"]): + data["items"][index] = InvoiceSubmission.parse(item) + + return InvoicePage(**data) + @dataclass class InvoiceStats(_Type): time: str @@ -649,4 +666,32 @@ class CurrencyConversion(_Type): convert_currency: str created: int +@dataclass +class MerchantDeposit(_Type): + id: int + invoice_id: Optional[str] + order_id: Optional[str] + type: Literal["ledger", "deposit"] + amount: float + t: int + txid: str + currency: str + method: str + pay_method: str + +@dataclass +class MerchantUnlinkedDeposit(_Type): + id: int + method: str + currency: str + created_at: int + updated_at: int + amount: float + fee: float + txid: str + address: str + payment_id: Optional[int] + status: str + note: Optional[str] + #endregion \ No newline at end of file diff --git a/examples/rest/merchant/settings.py b/examples/rest/merchant/settings.py new file mode 100644 index 0000000..4afe06b --- /dev/null +++ b/examples/rest/merchant/settings.py @@ -0,0 +1,28 @@ +# python -c "import examples.rest.merchant.settings" + +import os + +from bfxapi import Client, REST_HOST + +from bfxapi.rest.enums import MerchantSettingsKey + +bfx = Client( + REST_HOST=REST_HOST, + API_KEY=os.getenv("BFX_API_KEY"), + API_SECRET=os.getenv("BFX_API_SECRET") +) + +if not bfx.rest.merchant.set_merchant_settings(MerchantSettingsKey.RECOMMEND_STORE, 1): + print(f"Cannot set <{MerchantSettingsKey.RECOMMEND_STORE}> to <1>.") + +print(f"The current <{MerchantSettingsKey.PREFERRED_FIAT}> value is:", + bfx.rest.merchant.get_merchant_settings(MerchantSettingsKey.PREFERRED_FIAT)) + +settings = bfx.rest.merchant.list_merchant_settings([ + MerchantSettingsKey.DUST_BALANCE_UI, + MerchantSettingsKey.MERCHANT_CUSTOMER_SUPPORT_URL, + MerchantSettingsKey.MERCHANT_UNDERPAID_THRESHOLD +]) + +for key, value in settings.items(): + print(f"<{key}>:", value) \ No newline at end of file diff --git a/examples/rest/merchant/submit_invoice.py b/examples/rest/merchant/submit_invoice.py index cb71dce..bec606e 100644 --- a/examples/rest/merchant/submit_invoice.py +++ b/examples/rest/merchant/submit_invoice.py @@ -40,4 +40,6 @@ print(bfx.rest.merchant.complete_invoice( deposit_id=1 )) -print(bfx.rest.merchant.get_invoices(limit=25)) \ No newline at end of file +print(bfx.rest.merchant.get_invoices(limit=25)) + +print(bfx.rest.merchant.get_invoices_paginated(page=1, page_size=60, sort="asc", sort_field="t")) \ No newline at end of file