Skip to content

Commit

Permalink
feat: ICPS (#12), verbose_name, typo, type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
hoosnick committed Oct 1, 2023
1 parent 108446f commit d5df016
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 145 deletions.
17 changes: 6 additions & 11 deletions lib/payme/admin.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
from django.contrib import admin

from payme.models import (
Item, MerchatTransactionsModel,
OrderDetail, ShippingDetail
FiscalData, Item, ShippingDetail,
MerchantTransactionsModel
)
# pylint: disable=fixme
# TODO: order Payme models in admin panel
# 1. OrderDetail
# 2. Item
# 3. ShippingDetail
# 4. MerchatTransactionsModel

admin.site.register(
[
OrderDetail, Item,
ShippingDetail,
MerchatTransactionsModel,
MerchantTransactionsModel,
FiscalData,
Item,
ShippingDetail
]
)
122 changes: 73 additions & 49 deletions lib/payme/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,92 @@ class Migration(migrations.Migration):

operations = [
migrations.CreateModel(
name='Item',
name="FiscalData",
fields=[
('id', models.BigAutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID'
)),
('discount', models.BigIntegerField(blank=True, null=True)),
('title', models.CharField(max_length=255)),
('price', models.BigIntegerField(default=0)),
('count', models.IntegerField(default=1)),
('code', models.CharField(max_length=17)),
('units', models.IntegerField(blank=True, null=True)),
('package_code', models.CharField(max_length=255)),
('vat_percent', models.IntegerField(blank=True, default=0, null=True)),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("code", models.CharField(max_length=17)),
("units", models.IntegerField(blank=True, null=True)),
("package_code", models.CharField(max_length=255)),
("vat_percent", models.IntegerField(blank=True, default=0, null=True)),
],
),
migrations.CreateModel(
name='MerchatTransactionsModel',
name="MerchantTransactionsModel",
fields=[
('id', models.BigAutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID'
)),
('_id', models.CharField(max_length=255, null=True)),
('transaction_id', models.CharField(max_length=255, null=True)),
('order_id', models.BigIntegerField(blank=True, null=True)),
('amount', models.BigIntegerField(blank=True, null=True)),
('time', models.BigIntegerField(blank=True, null=True)),
('perform_time', models.BigIntegerField(default=0, null=True)),
('cancel_time', models.BigIntegerField(default=0, null=True)),
('state', models.IntegerField(default=1, null=True)),
('reason', models.CharField(blank=True, max_length=255, null=True)),
('created_at_ms', models.CharField(blank=True, max_length=255, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("_id", models.CharField(max_length=255, null=True)),
("transaction_id", models.CharField(max_length=255, null=True)),
("order_id", models.BigIntegerField(blank=True, null=True)),
("amount", models.BigIntegerField(blank=True, null=True)),
("time", models.BigIntegerField(blank=True, null=True)),
("perform_time", models.BigIntegerField(default=0, null=True)),
("cancel_time", models.BigIntegerField(default=0, null=True)),
("state", models.IntegerField(default=1, null=True)),
("reason", models.CharField(blank=True, max_length=255, null=True)),
(
"created_at_ms",
models.CharField(blank=True, max_length=255, null=True),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='ShippingDetail',
name="ShippingDetail",
fields=[
('id', models.BigAutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID'
)),
('title', models.CharField(max_length=255)),
('price', models.BigIntegerField(default=0)),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=255)),
("price", models.BigIntegerField(default=0)),
],
),
migrations.CreateModel(
name='OrderDetail',
name="Item",
fields=[
('id', models.BigAutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID'
)),
('receipt_type', models.IntegerField(default=0)),
('items', models.ManyToManyField(to='payme.item')),
('shipping', models.ForeignKey(
blank=True, null=True,
on_delete=django.db.models.deletion.CASCADE,
to='payme.shippingdetail'
)),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("discount", models.BigIntegerField(blank=True, null=True)),
("title", models.CharField(max_length=255)),
("price", models.BigIntegerField(default=0)),
("count", models.IntegerField(default=1)),
(
"fiscal_data",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="payme.fiscaldata",
),
),
],
),
]
132 changes: 59 additions & 73 deletions lib/payme/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from django.db import models
from django.db.models import Case, F, Sum, When


class MerchatTransactionsModel(models.Model):
class MerchantTransactionsModel(models.Model):
"""
MerchatTransactionsModel class \
MerchantTransactionsModel class \
That's used for managing transactions in database.
"""
_id = models.CharField(max_length=255, null=True, blank=False)
Expand All @@ -22,6 +23,11 @@ class MerchatTransactionsModel(models.Model):
def __str__(self):
return str(self._id)

class Meta:
# pylint: disable=missing-class-docstring
verbose_name = "Merchant Transaction"
verbose_name_plural = "Merchant Transactions"


class ShippingDetail(models.Model):
"""
Expand All @@ -35,93 +41,59 @@ def __str__(self) -> str:
shipping_price = self.price / 100 # shipping price in soum
return f"[{self.pk}] {self.title} - {shipping_price:,}"

class Meta:
# pylint: disable=missing-class-docstring
verbose_name = "Shipping Detail"
verbose_name_plural = "Shipping Details"

class Item(models.Model):

class FiscalData(models.Model):
"""
Item class \
That's used for managing order items
FiscalData class \
That's used for managing fiscalization items
"""
discount = models.BigIntegerField(null=True, blank=True)
title = models.CharField(max_length=255)
price = models.BigIntegerField(default=0)
count = models.IntegerField(default=1)
code = models.CharField(max_length=17)
units = models.IntegerField(null=True, blank=True)
package_code = models.CharField(max_length=255)
vat_percent = models.IntegerField(default=0, null=True, blank=True)

def __str__(self) -> str:
item_price = self.price / 100 # item price in soum
return f"[{self.id}] {self.title} ({self.count} pc.) x {item_price:,} UZS"
return f"[{self.pk}] {self.code} - {self.package_code}"

class Meta:
# pylint: disable=missing-class-docstring
verbose_name = "Fiscal Data"
verbose_name_plural = "Fiscal Data"


class OrderDetail(models.Model):
class Item(models.Model):
"""
OrderDetail class \
That's used for managing order details
Item class \
That's used for managing order items
"""
receipt_type = models.IntegerField(default=0)
shipping = models.ForeignKey(
to=ShippingDetail,
null=True, blank=True,
on_delete=models.CASCADE
discount = models.BigIntegerField(null=True, blank=True)
title = models.CharField(max_length=255)
price = models.BigIntegerField(default=0)
count = models.IntegerField(default=1)
fiscal_data = models.ForeignKey(
FiscalData, null=True,
on_delete=models.SET_NULL
)
items = models.ManyToManyField(Item)

@property
def get_items_display(self):
# pylint: disable=missing-function-docstring
item_display = [f'[{self.pk}]']

for fld in self._meta.get_fields():
if not isinstance(fld, models.ManyToOneRel):
continue

if not issubclass(fld.related_model, BaseOrder):
continue

related_order = fld.get_accessor_name()
orders = getattr(self, related_order).values()
order_id = orders[0].get('id') if orders else 'None'

item_display.append(f'FOR ORDER - {order_id}')

if self.shipping:
item_display.append(f'ADDRESS: {self.shipping.title}')

item_display.append(f'AMOUNT: {self.get_total_items_price:,} UZS')

return ' '.join(item_display)

@property
def get_total_items_price(self) -> int:
# pylint: disable=missing-function-docstring
items = self.items.all().aggregate(
total_price=models.Sum(
models.Case(
models.When(
discount__isnull=True,
then=models.F('price') * models.F('count')
),
default=(
(models.F('price') * models.F('count')) -
models.F('discount')
),
output_field=models.BigIntegerField()
)
)
)
shipping_price = self.shipping.price if self.shipping else 0
return int(shipping_price + items['total_price']) / 100

def __str__(self) -> str:
return self.get_items_display
item_price = self.price / 100 # item price in soum
return f"[{self.pk}] {self.title} ({self.count} pc.) x {item_price:,} UZS"

class Meta:
# pylint: disable=missing-class-docstring
verbose_name = "Order Item"
verbose_name_plural = "Order Items"


class DisallowOverrideMetaclass(models.base.ModelBase):
# pylint: disable=missing-class-docstring
def __new__(mcs, name, bases, attrs: dict, **kwargs):
disallowed_fields = ['amount', 'detail']
disallowed_fields = ['amount', 'receipt_type', 'shipping']

if name != 'BaseOrder':
for field_name in disallowed_fields:
Expand All @@ -140,20 +112,34 @@ class BaseOrder(models.Model, metaclass=DisallowOverrideMetaclass):
Order class \
That's used for managing order process
"""
detail = models.ForeignKey(
OrderDetail,
receipt_type = models.IntegerField(default=0)
items = models.ManyToManyField(Item)
shipping = models.ForeignKey(
to=ShippingDetail,
null=True, blank=True,
on_delete=models.CASCADE
)

@property
def amount(self):
def amount(self) -> int:
# pylint: disable=missing-function-docstring
return self.detail.get_total_items_price if self.detail else 0
items = self.items.all().aggregate(
total_price=Sum(
Case(
When(discount__isnull=True, then=F('price') * F('count')),
default=(F('price') * F('count')) - F('discount'),
output_field=models.BigIntegerField()
)
)
)
shipping_price = self.shipping.price if self.shipping else 0
return int(shipping_price + items['total_price']) / 100

def __str__(self):
return f"ORDER ID: {self.id} - AMOUNT: {self.amount:,} UZS"
return f"ORDER ID: {self.pk} - AMOUNT: {self.amount:,} UZS"

class Meta:
# pylint: disable=missing-class-docstring
abstract = True
verbose_name = "Order"
verbose_name_plural = "Orders"
Loading

0 comments on commit d5df016

Please sign in to comment.