Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 46 additions & 28 deletions click_up/classes/merchant.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,49 +12,67 @@ 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,
"merchant_trans_id": merchant_trans_id
}

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)
18 changes: 18 additions & 0 deletions click_up/migrations/0002_clicktransaction_click_payment_id.py
Original file line number Diff line number Diff line change
@@ -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'),
),
]
7 changes: 6 additions & 1 deletion click_up/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -44,6 +45,7 @@ def get_or_create(
account_id,
transaction_id,
amount,
click_payment_id,
state=None
) -> "ClickTransaction":
"""
Expand All @@ -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:
Expand All @@ -68,6 +71,7 @@ def update_or_create(
account_id,
transaction_id,
amount,
click_payment_id,
state=None
) -> "ClickTransaction":
"""
Expand All @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion click_up/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)

Expand Down