Compare commits

..

4 commits

Author SHA1 Message Date
72547b9785 ignore Python bytecode caches
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 15:09:55 +03:30
7dcb730507 FEATURE(wallets): rename WALLET_RIAL and add WALLET_INCOME_FROM_IPG
WALLET_RIAL -> WALLET_RIAL_DEPOSIT to match the naming used for the same
wallet-service UUID in the advertising/settlement/promotions repos. Also
adds WALLET_INCOME_FROM_IPG and wires it in: after a successful wallet
charge, the commission portion is deposited separately into it (attributed
to the requesting OAuth2 application) instead of never entering the wallet
ledger. The income deposit is best-effort and logs on failure rather than
failing an already-successful charge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 15:09:49 +03:30
6f2d5e0bd7 run by docker via base:debian13 2026-05-02 13:32:07 +03:30
a52ba09460 FEATURE(pg): add DateTimeRangeFilter to panel admin
add DateTimeRangeFilter to panel admin
2026-04-27 14:44:39 +03:30
7 changed files with 69 additions and 14 deletions

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
.idea .idea
.env .env
media media
__pycache__/
*.pyc
/clients/ /clients/
/delme.py /delme.py
/log/accounts.log /log/accounts.log

View file

@ -1,10 +1,12 @@
FROM debian:12 FROM base:debian13
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
WORKDIR /app WORKDIR /app
#RUN date #RUN date
RUN apt update #RUN apt update
RUN apt install gnupg2 netcat-traditional libssl-dev libcrypto++-dev lsb-release python3-pip -y #RUN apt install gnupg2 netcat-traditional libssl-dev libcrypto++-dev lsb-release python3-pip -y
RUN apt install binutils libproj-dev gdal-bin -y #RUN apt install binutils libproj-dev gdal-bin -y
COPY requirements.txt /app/requirements.txt #COPY requirements.txt /app/requirements.txt
RUN pip3 install --break-system-packages -r requirements.txt #RUN pip3 install --break-system-packages -r requirements.txt
#RUN pip3 install --break-system-packages django-admin-rangefilter==0.13.5
#RUN pip3 install --break-system-packages setuptools
#ENTRYPOINT ["./run.sh"] #ENTRYPOINT ["./run.sh"]

View file

@ -14,6 +14,7 @@ from django.urls import path
from .constans import StateChoices from .constans import StateChoices
from .forms import ApplicationGatewayPolicyForm from .forms import ApplicationGatewayPolicyForm
from .models import PaymentRequest, PNA, Fake, ApplicationGatewayPolicy, SEP from .models import PaymentRequest, PNA, Fake, ApplicationGatewayPolicy, SEP
from rangefilter.filters import DateTimeRangeFilter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -74,7 +75,7 @@ class PaymentRequestAdmin(admin.ModelAdmin):
list_display = ['state', 'check_success_again', 'uuid', 'splited_amount', 'user_id', 'jajali_datetime', list_display = ['state', 'check_success_again', 'uuid', 'splited_amount', 'user_id', 'jajali_datetime',
'is_registered', 'created_at', 'application', 'gateway'] 'is_registered', 'created_at', 'application', 'gateway']
search_fields = ['application__uuid', 'application__client_id', 'amount', 'user__uuid'] search_fields = ['application__uuid', 'application__client_id', 'amount', 'user__uuid']
list_filter = ['application', 'state', 'gateway'] list_filter = ['application', 'state', 'gateway', ('created_at', DateTimeRangeFilter), ('updated_at', DateTimeRangeFilter)]
actions = [export_exel, mark_as_registered] actions = [export_exel, mark_as_registered]
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):

View file

@ -11,7 +11,7 @@ from django.urls import reverse
from oauth2_provider.settings import oauth2_settings from oauth2_provider.settings import oauth2_settings
from apps.core.models import BaseModel, BasePGModel from apps.core.models import BaseModel, BasePGModel
from apps.pg.constans import StateChoices from apps.pg.constans import StateChoices, TypeChoices
import uuid import uuid
from utils.clients.wallet_client import deposit_to_user_wallet_submit, deposit_to_user_wallet_verify from utils.clients.wallet_client import deposit_to_user_wallet_submit, deposit_to_user_wallet_verify
@ -83,6 +83,10 @@ class PaymentRequest(models.Model):
return to_jalali(self.created_at) return to_jalali(self.created_at)
@property
def income_uuid(self):
return uuid.uuid5(self.uuid, 'income')
def save_commission(self): def save_commission(self):
self.commission = calculate_pna_commission(self.amount) self.commission = calculate_pna_commission(self.amount)
self.save(update_fields=['commission']) self.save(update_fields=['commission'])
@ -145,7 +149,7 @@ class PaymentRequest(models.Model):
"uuid": str(self.uuid), "uuid": str(self.uuid),
"payee": str(self.user.uuid), "payee": str(self.user.uuid),
"payee_type": 1, "payee_type": 1,
"payee_wallet": settings.WALLET_RIAL, "payee_wallet": settings.WALLET_RIAL_DEPOSIT,
"amount": self.amount, "amount": self.amount,
"details": { "details": {
'description': str(_("charge via ipg")), 'description': str(_("charge via ipg")),
@ -153,7 +157,7 @@ class PaymentRequest(models.Model):
'application_details_url': '' 'application_details_url': ''
}, },
} }
submit_response = deposit_to_user_wallet_submit(settings.WALLET_RIAL, data) submit_response = deposit_to_user_wallet_submit(settings.WALLET_RIAL_DEPOSIT, data)
if not submit_response or not submit_response.uuid: if not submit_response or not submit_response.uuid:
logger.error(f"[Deposit Submit] Wallet submission failed | payment_id={self.pk}") logger.error(f"[Deposit Submit] Wallet submission failed | payment_id={self.pk}")
@ -171,7 +175,7 @@ class PaymentRequest(models.Model):
return to_success return to_success
def deposit_verify(self): def deposit_verify(self):
verify_response = deposit_to_user_wallet_verify(settings.WALLET_RIAL, self.uuid) verify_response = deposit_to_user_wallet_verify(settings.WALLET_RIAL_DEPOSIT, self.uuid)
if not verify_response: if not verify_response:
logger.error(f"[Deposit Verify] Failed to get response from wallet service | payment_id={self.pk}") logger.error(f"[Deposit Verify] Failed to get response from wallet service | payment_id={self.pk}")
@ -205,6 +209,47 @@ class PaymentRequest(models.Model):
return to_pay_success return to_pay_success
def deposit_income_submit(self):
data = {
"uuid": str(self.income_uuid),
"payee": str(self.application_id),
"payee_type": TypeChoices.APPLICATION.value,
"payee_wallet": settings.WALLET_INCOME_FROM_IPG,
"amount": self.commission,
"details": {
'description': str(_("ipg commission income")),
'reference_id': str(self.uuid),
'application_details_url': ''
},
}
submit_response = deposit_to_user_wallet_submit(settings.WALLET_INCOME_FROM_IPG, data)
if not submit_response or not submit_response.uuid:
raise Exception('Failed to submit income in wallet')
return submit_response
def deposit_income_verify(self):
verify_response = deposit_to_user_wallet_verify(settings.WALLET_INCOME_FROM_IPG, self.income_uuid)
if not verify_response or not verify_response.uuid:
raise Exception('Failed to verify income in wallet')
if verify_response.state != 5:
raise Exception('Failed to verify income in wallet')
return True
def charge_wallet_income(self):
if not self.application_id or not self.commission:
return
try:
self.deposit_income_submit()
self.deposit_income_verify()
logger.info(f"[Charge Wallet] Income charged successfully | payment_id={self.pk}")
except Exception:
logger.exception(f"[Charge Wallet] Failed to charge income | payment_id={self.pk}")
def charge_wallet_balance(self): def charge_wallet_balance(self):
logger.info(f"[Charge Wallet] Starting wallet charge process | payment_id={self.pk}") logger.info(f"[Charge Wallet] Starting wallet charge process | payment_id={self.pk}")
if self.state in [StateChoices.IPG_SUCCESS]: if self.state in [StateChoices.IPG_SUCCESS]:
@ -221,6 +266,7 @@ class PaymentRequest(models.Model):
to_pay_success = self.deposit_verify() to_pay_success = self.deposit_verify()
if to_pay_success: if to_pay_success:
logger.info(f"[Charge Wallet] Wallet charged successfully | payment_id={self.pk}") logger.info(f"[Charge Wallet] Wallet charged successfully | payment_id={self.pk}")
self.charge_wallet_income()
else: else:
logger.warning(f"[Charge Wallet] Wallet charge verification failed | payment_id={self.pk}") logger.warning(f"[Charge Wallet] Wallet charge verification failed | payment_id={self.pk}")
return bool(to_pay_success) return bool(to_pay_success)

View file

@ -49,6 +49,7 @@ INSTALLED_APPS = [
'django_filters', 'django_filters',
'jalali_date', 'jalali_date',
'django_admin_logs', 'django_admin_logs',
'rangefilter',
# local apps # local apps
'apps.core', 'apps.core',
@ -63,7 +64,7 @@ MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', 'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'utils.i18n.ForceAdminLanguageMiddleware', # 'utils.i18n.ForceAdminLanguageMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'oauth2_provider.middleware.OAuth2TokenMiddleware', 'oauth2_provider.middleware.OAuth2TokenMiddleware',
@ -262,7 +263,8 @@ LOGGING = get_logging_setting()
PNA_CORPORATION_PIN = config('PNA_CORPORATION_PIN') PNA_CORPORATION_PIN = config('PNA_CORPORATION_PIN')
WALLET_BASE_PUBLIC_URL = config('WALLET_BASE_PUBLIC_URL') WALLET_BASE_PUBLIC_URL = config('WALLET_BASE_PUBLIC_URL')
WALLET_RIAL = config('WALLET_RIAL') WALLET_RIAL_DEPOSIT = config('WALLET_RIAL_DEPOSIT')
WALLET_INCOME_FROM_IPG = config('WALLET_INCOME_FROM_IPG')
IPG_BASE_PUBLIC_URL = config('IPG_BASE_PUBLIC_URL') IPG_BASE_PUBLIC_URL = config('IPG_BASE_PUBLIC_URL')
COMMISSION_LEVEL1 = config('COMMISSION_LEVEL1', cast=int) COMMISSION_LEVEL1 = config('COMMISSION_LEVEL1', cast=int)

View file

@ -19,4 +19,5 @@ httpx
django-redis django-redis
xlsxwriter xlsxwriter
xlrd xlrd
django_admin_logs django_admin_logs
django-admin-rangefilter

View file

@ -182,6 +182,7 @@ zope-event==5.0
# via gevent # via gevent
zope-interface==7.2 zope-interface==7.2
# via gevent # via gevent
django-admin-rangefilter==0.13.5
# The following packages are considered to be unsafe in a requirements file: # The following packages are considered to be unsafe in a requirements file:
# setuptools # setuptools