feat: add daily report functionality and settlement status to shop orders

This commit is contained in:
Parsa Nazer
2026-02-09 11:08:39 +03:30
parent 0771a286b2
commit bd7c7252c7
6 changed files with 78 additions and 11 deletions
+37 -6
View File
@@ -1,6 +1,7 @@
from django.contrib import admin, messages from django.contrib import admin, messages
from .models import * from .models import *
from unfold.admin import TabularInline, StackedInline from unfold.admin import TabularInline, StackedInline
from unfold.contrib.inlines.admin import NonrelatedTabularInline
from django.db.models import Q from django.db.models import Q
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
@@ -60,19 +61,50 @@ class CartAdmin(ModelAdmin):
inlines = [CartItemInline] inlines = [CartItemInline]
class ShopOrderInline(StackedInline):
model = ShopOrderModel
extra = 0
max_num = 0
tab = True
class ShopOrderItemInline(NonrelatedTabularInline): # NonrelatedStackedInline is available as well
model = ShopOrderItem
tab = True
extra = 0
show_change_link = True
def get_form_queryset(self, obj):
"""
Gets all nonrelated objects needed for inlines. Method must be implemented.
"""
shop_orders = obj.shop_orders.all()
return ShopOrderItem.objects.filter(shop_order__in=shop_orders)
def save_new_instance(self, parent, instance):
"""
Extra save method which can for example update inline instances based on current
main model object. Method must be implemented.
"""
pass
from .models import ShopDailyReport, ShopOrderModel from .models import ShopDailyReport, ShopOrderModel
@admin.register(ShopDailyReport) @admin.register(ShopDailyReport)
class ShopDailyReportAdmin(ModelAdmin): class ShopDailyReportAdmin(ModelAdmin):
pass list_display = ['shop', 'date', 'is_settled',]
inlines = [ShopOrderInline, ShopOrderItemInline]
def get_queryset(self, request): def get_queryset(self, request):
if request.user.is_superuser: if request.user.is_superuser:
return ShopOrderModel.objects.all() return self.model.objects.all()
if not hasattr(request.user, 'shop'): if not hasattr(request.user, 'shop'):
return ShopOrderModel.objects.none() return self.model.objects.none()
queryset = ShopOrderModel.objects.filter(shop=request.user.shop) queryset = self.model.objects.filter(shop=request.user.shop)
return queryset return queryset
def has_view_permission(self, request, obj=None): def has_view_permission(self, request, obj=None):
@@ -95,11 +127,10 @@ class ShopOrderItemInline(StackedInline):
@admin.register(ShopOrderModel) @admin.register(ShopOrderModel)
class ShopOrderModelAdmin(ShopOrderAdminPermission, ModelAdmin): class ShopOrderModelAdmin(ShopOrderAdminPermission, ModelAdmin):
inlines = [ShopOrderItemInline] inlines = [ShopOrderItemInline]
list_display = ['id', 'shop', 'order', 'customer_name', 'status', 'is_paid', 'is_settled', 'download_invoice_button'] list_display = ['id', 'shop', 'order', 'customer_name', 'status', 'is_paid', 'is_settled', 'created_at', 'download_invoice_button']
readonly_fields = ['download_invoice_link'] readonly_fields = ['download_invoice_link']
def download_invoice_button(self, obj): def download_invoice_button(self, obj):
@@ -0,0 +1,24 @@
# Generated by Django 5.1.2 on 2026-02-08 15:40
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0042_ordermodel_special_discount_code_and_more'),
]
operations = [
migrations.AddField(
model_name='shopdailyreport',
name='is_settled',
field=models.BooleanField(default=False, verbose_name='تسویه شده'),
),
migrations.AddField(
model_name='shopordermodel',
name='daily_report',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='shop_orders', to='order.shopdailyreport', verbose_name='گزارش روزانه'),
),
]
+2
View File
@@ -279,6 +279,7 @@ class ShopOrderModel(models.Model):
""" """
order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='shop_orders') order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='shop_orders')
shop = models.ForeignKey('account.ShopModel', on_delete=models.CASCADE, related_name='shop_orders') shop = models.ForeignKey('account.ShopModel', on_delete=models.CASCADE, related_name='shop_orders')
daily_report = models.ForeignKey('ShopDailyReport', on_delete=models.SET_NULL, null=True, blank=True, related_name='shop_orders', verbose_name='گزارش روزانه')
# Customer Information # Customer Information
customer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='مشتری') customer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='مشتری')
@@ -355,6 +356,7 @@ class ShopDailyReport(models.Model):
total_sales = models.BigIntegerField(default=0) total_sales = models.BigIntegerField(default=0)
total_commission = models.BigIntegerField(default=0) total_commission = models.BigIntegerField(default=0)
total_payable = models.BigIntegerField(default=0) total_payable = models.BigIntegerField(default=0)
is_settled = models.BooleanField(default=False, verbose_name='تسویه شده')
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
class Meta: class Meta:
+9 -2
View File
@@ -1,4 +1,4 @@
from .models import ShopOrderModel, ShopOrderItem from .models import ShopOrderModel, ShopOrderItem, ShopDailyReport
from django.db import transaction from django.db import transaction
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.db.models.signals import pre_save from django.db.models.signals import pre_save
@@ -248,4 +248,11 @@ def send_invoice_to_shop_telegram(sender, instance: ShopOrderModel, created, **k
shop_order_id=instance.pk, shop_order_id=instance.pk,
chat_id=instance.shop.telegram_chat_id, chat_id=instance.shop.telegram_chat_id,
bot_token=bot_token bot_token=bot_token
) )
@receiver(post_save, sender=ShopDailyReport)
def update_shop_orders_settlement_status(sender, instance: ShopDailyReport, **kwargs):
"""When a ShopDailyReport's is_settled status changes, update all related ShopOrderModel instances."""
# Update all shop orders linked to this daily report
instance.shop_orders.update(is_settled=instance.is_settled)
+5 -2
View File
@@ -75,9 +75,9 @@ def generate_daily_shop_reports():
from datetime import timedelta from datetime import timedelta
from django.db.models import Sum from django.db.models import Sum
from .models import ShopOrderModel, ShopDailyReport from .models import ShopOrderModel, ShopDailyReport
target_date = (timezone.now() - timedelta(days=1)).date() target_date = (timezone.now() - timedelta(days=1)).date()
logging.info(f'Generating shop reports for {target_date}') print(f'Generating shop reports for {target_date}')
shop_orders = ShopOrderModel.objects.filter(created_at__date=target_date) shop_orders = ShopOrderModel.objects.filter(created_at__date=target_date)
if not shop_orders.exists(): if not shop_orders.exists():
@@ -110,6 +110,9 @@ def generate_daily_shop_reports():
} }
) )
# Link all shop orders for this shop and date to the daily report
shop_orders.filter(shop_id=shop_id).update(daily_report=report)
if created: if created:
reports_created += 1 reports_created += 1
else: else:
+1 -1
View File
@@ -42,7 +42,7 @@ django-iranian-cities==1.0.2
django-jalali==7.3.0 django-jalali==7.3.0
django-storages==1.14.5 django-storages==1.14.5
django-timezone-field==7.1 django-timezone-field==7.1
django-unfold==0.48.0 django-unfold==0.78.1
djangorestframework==3.15.2 djangorestframework==3.15.2
djangorestframework-simplejwt==5.3.1 djangorestframework-simplejwt==5.3.1
djoser==2.3.1 djoser==2.3.1