diff --git a/click_up/classes/merchant.py b/click_up/classes/merchant.py index cccc7dd..f751f42 100644 --- a/click_up/classes/merchant.py +++ b/click_up/classes/merchant.py @@ -12,44 +12,32 @@ class MerchantApi: def __init__(self, service_id, merchant_user_id, secret_key): """ Initialize the MerchantApi instance. - - Args: - url (str): Base URL of the CLICK Merchant API. - merchant_user_id (str): Merchant User ID provided by CLICK. - secret_key (str): Secret key for authentication. + :param service_id: Service ID provided by CLICK. + :param merchant_user_id: Merchant User ID provided by CLICK. + :param secret_key: Secret key for authentication. """ self.http = Http() self.secret_key = secret_key - self.service_id = service_id + self.service_id = int(service_id) self.merchant_user_id = merchant_user_id self.url = "https://api.click.uz/v2/merchant" def create_invoice( self, - amount, - phone_number, - merchant_trans_id - ): + amount: float, + phone_number: str, + merchant_trans_id: str + ) -> dict: """ Create an invoice using the CLICK API. - - Args: - service_id (int): Service ID. - amount (float): Requested amount. - phone_number (str): Invoice receiver. - merchant_trans_id (str): - Order ID (for online shopping) / personal account / login - in the billing of the supplier. - Returns: - dict: A dictionary containing the response from the API. + :param amount: Requested amount. + :param phone_number: Invoice receiver. + :param merchant_trans_id: + Order ID (for online shopping) / personal account / login + in the billing of the supplier. + :returns dict: A dictionary containing the response from the API. """ - timestamp = int(time.time()) - digest_input = f"{timestamp}{self.secret_key}" - digest = hashlib.sha1(digest_input.encode()).hexdigest() - headers = { - "Auth": f"{self.merchant_user_id}:{digest}:{timestamp}", - } - body = { + data = { "service_id": self.service_id, "amount": amount, "phone_number": phone_number, @@ -57,4 +45,34 @@ def create_invoice( } url = f"{self.url}/invoice/create" - return self.http.post(url, body, headers, 10) + return self._send_post_request(url, data) + + + def submit_fiscal_check( + self, + payment_id: int, + fiscal_check_url: str + ) -> dict: + """ + Sends already generated fiscal check data to CLICK for linking it to the invoice + :param payment_id: payment ID from the CLICK side. + :param fiscal_check_url: URL of the fiscal check from the ofd.uz. + """ + + data = { + "service_id": self.service_id, + "payment_id": payment_id, + "qrcode": fiscal_check_url, + } + + url = f"{self.url}/payment/ofd_data/submit_qrcode" + return self._send_post_request(url, data) + + def _send_post_request(self, url: str, data: dict) -> dict: + timestamp = int(time.time()) + digest_input = f"{timestamp}{self.secret_key}" + digest = hashlib.sha1(digest_input.encode()).hexdigest() + headers = { + "Auth": f"{self.merchant_user_id}:{digest}:{timestamp}", + } + return self.http.post(url, data, headers, 10) diff --git a/click_up/migrations/0002_clicktransaction_click_payment_id.py b/click_up/migrations/0002_clicktransaction_click_payment_id.py new file mode 100644 index 0000000..bfaf513 --- /dev/null +++ b/click_up/migrations/0002_clicktransaction_click_payment_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.4 on 2025-05-21 12:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('click_up', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='clicktransaction', + name='click_payment_id', + field=models.CharField(max_length=255, blank=True, null=True, help_text='click_paydoc_id'), + ), + ] diff --git a/click_up/models.py b/click_up/models.py index 160561c..2842f03 100644 --- a/click_up/models.py +++ b/click_up/models.py @@ -23,7 +23,8 @@ class ClickTransaction(models.Model): (SUCCESSFULLY, "Successfully"), ] state = models.IntegerField(choices=STATE, default=CREATED) - transaction_id = models.CharField(max_length=255) + transaction_id = models.CharField(max_length=255, help_text="click_trans_id") + click_payment_id = models.CharField(max_length=255, blank=True, null=True, help_text="click_paydoc_id") account_id = models.BigIntegerField(null=False) amount = models.DecimalField(max_digits=10, decimal_places=2) created_at = models.DateTimeField(auto_now_add=True) @@ -44,6 +45,7 @@ def get_or_create( account_id, transaction_id, amount, + click_payment_id, state=None ) -> "ClickTransaction": """ @@ -54,6 +56,7 @@ def get_or_create( account_id=account_id, amount=amount, transaction_id=transaction_id, + click_payment_id=click_payment_id, defaults={"state": cls.INITIATING}, ) if state is not None: @@ -68,6 +71,7 @@ def update_or_create( account_id, transaction_id, amount, + click_payment_id, state=None ) -> "ClickTransaction": """ @@ -78,6 +82,7 @@ def update_or_create( account_id=account_id, amount=amount, transaction_id=transaction_id, + click_payment_id=click_payment_id, defaults={"state": cls.INITIATING}, ) if state is not None: diff --git a/click_up/views.py b/click_up/views.py index 35c1cca..5444ae2 100644 --- a/click_up/views.py +++ b/click_up/views.py @@ -168,7 +168,8 @@ def create_transaction(self, account: AccountModel, params: ClickShopApiRequest) transaction = ClickTransaction.get_or_create( account_id=account.id, amount=params.amount, - transaction_id=params.click_trans_id + transaction_id=params.click_trans_id, + click_payment_id=params.click_paydoc_id ) # callback event @@ -196,6 +197,7 @@ def perform_transaction(self, account: AccountModel, params: ClickShopApiRequest account_id=account.id, amount=params.amount, transaction_id=params.click_trans_id, + click_payment_id=params.click_paydoc_id, state=state )