diff --git a/backend/order/invoice_generator.py b/backend/order/invoice_generator.py index 34e8fb7..d71cce9 100644 --- a/backend/order/invoice_generator.py +++ b/backend/order/invoice_generator.py @@ -9,7 +9,7 @@ from django.template.loader import render_to_string from weasyprint import HTML from django.conf import settings import jdatetime - +from django.conf import settings def generate_order_invoice(order_id): """ @@ -30,33 +30,26 @@ def generate_order_invoice(order_id): except OrderModel.DoesNotExist: raise ValueError(f"Order with ID {order_id} does not exist") - # Prepare items with calculated discount amounts + # Prepare items with calculated discount amounts using stored values items = order.items.all() items_with_discount = [] + total_items_discount = 0 + for item in items: - # Calculate the discount amount from the discount_percent - # price is after discount, so we need to calculate original price - # original_price = price / (1 - discount_percent/100) - # discount_amount = original_price - price - if item.discount_percent > 0: - discount_multiplier = (100 - item.discount_percent) / 100 - price_after_discount = item.price - price_before_discount = int(price_after_discount / discount_multiplier) if discount_multiplier > 0 else price_after_discount - item_discount_amount = (price_before_discount - price_after_discount) - else: - item_discount_amount = 0 - price_before_discount = item.price + total_items_discount += item.total_product_discount_amount() or 0 items_with_discount.append({ 'item': item, - 'discount_amount': item_discount_amount, - 'price_before_discount': price_before_discount + 'discount_amount': item.total_product_discount_amount() or 0, + 'price_before_discount': item.total_price_before_discount(), + 'unit_price': item.unit_price(), + 'final_price': item.price_after_special_discount(), }) - # Prepare context for the template + # Use stored model fields for accuracy and consistency context = { 'order': order, - 'order_number': order.pk + 1000, + 'order_number': order.pk, 'items': items, 'items_with_discount': items_with_discount, 'user': order.user, @@ -64,11 +57,13 @@ def generate_order_invoice(order_id): 'discount_code': order.discount_code, 'created_at_jalali': jdatetime.datetime.fromgregorian(datetime=order.created_at) if order.created_at else None, 'total_items': sum(item.quantity for item in items), - 'subtotal': order.cart_total, - 'discount_amount': order.discount_amount or 0, - 'special_discount_total': order.special_discount_total or 0, - 'tax': order.tax or 0, - 'final_price': order.final_price, + 'subtotal': order.cart_total or 0, # Stored field: total before any discounts + 'items_discount_amount': total_items_discount, + 'discount_amount': order.discount_amount or 0, # Stored field: discount code amount + 'special_discount_total': order.special_discount_total or 0, # Stored field: special discount total + 'tax_rate': settings.DEFAULT_TAX_RATE, + 'tax': order.tax or 0, # Stored field: tax amount + 'final_price': order.final_price or 0, # Stored field: final price after all calculations 'is_paid': order.is_paid, 'status': order.get_status_display(), } @@ -104,7 +99,32 @@ def generate_shop_order_invoice(shop_order_id): except ShopOrderModel.DoesNotExist: raise ValueError(f"ShopOrder with ID {shop_order_id} does not exist") + # Calculate total before any discount from shop order items + # shop_order.subtotal stores price AFTER product discount, so we need to recalculate + items = shop_order.items.select_related('order_item').all() + total_before_any_discount = 0 + total_product_discount = 0 + + for shop_item in items: + order_item = shop_item.order_item + # order_item.price is unit price AFTER product discount + if order_item.discount_percent > 0: + discount_multiplier = (100 - order_item.discount_percent) / 100 + if discount_multiplier > 0: + price_before_discount_unit = int(order_item.price / discount_multiplier) + else: + price_before_discount_unit = order_item.price + + item_discount = (price_before_discount_unit - order_item.price) * shop_item.quantity + total_product_discount += item_discount + else: + price_before_discount_unit = order_item.price + + total_before_any_discount += price_before_discount_unit * shop_item.quantity + # Prepare context for the template + subtotal_after_discount = total_before_any_discount - (total_product_discount + shop_order.special_discount_amount) + shop_order.tax_amount + context = { 'shop_order': shop_order, 'order_number': shop_order.order.pk + 1000, @@ -119,12 +139,13 @@ def generate_shop_order_invoice(shop_order_id): 'address_city': shop_order.address_city, 'address_province': shop_order.address_province, 'address_recipient_name': shop_order.address_recipient_name, - 'items': shop_order.items.all(), + 'items': items, 'created_at_jalali': jdatetime.datetime.fromgregorian(datetime=shop_order.order_created_at) if shop_order.order_created_at else None, 'total_items': shop_order.items_count, - 'subtotal': shop_order.subtotal, - 'discount_amount': shop_order.discount_amount, + 'subtotal': total_before_any_discount, # Total BEFORE any discount + 'discount_amount': total_product_discount, # Product discount amount 'special_discount_amount': shop_order.special_discount_amount, + 'subtotal_after_discount': subtotal_after_discount, 'tax_amount': shop_order.tax_amount, 'commission_percent': shop_order.commission_percent, 'commission_amount': shop_order.commission_amount, diff --git a/backend/order/models.py b/backend/order/models.py index 0e32a98..bfc1257 100644 --- a/backend/order/models.py +++ b/backend/order/models.py @@ -250,7 +250,25 @@ class OrderItemModel(models.Model): def __str__(self): return f'({self.product}) - ({self.order.user})' - + + # @property + def total_price_before_discount(self): + return self.price * self.quantity + + # @property + def total_product_discount_amount(self): + if self.discount_percent > 0: + return int((self.price * self.quantity) * (self.discount_percent / 100)) + return 0 + + # @property + def price_after_special_discount(self): + all_discounts = (self.special_discount_amount or 0) + self.total_product_discount_amount() + print(all_discounts) + return self.total_price_before_discount() - all_discounts + + def unit_price(self): + return self.price class ShopOrderModel(models.Model): """Represents the portion of a customer Order that belongs to a single Shop. diff --git a/backend/templates/order/invoice_order.html b/backend/templates/order/invoice_order.html index 824a69a..00fd6f1 100644 --- a/backend/templates/order/invoice_order.html +++ b/backend/templates/order/invoice_order.html @@ -264,7 +264,8 @@ نام محصول تنوع تعداد - قیمت اصلی + قیمت واحد + جمع تخفیف محصول تخفیف ویژه قیمت نهایی @@ -277,6 +278,7 @@ {{ item_data.item.product.product.name }} {{ item_data.item.product.title }} {{ item_data.item.quantity }} + {{ item_data.unit_price|price_format }} تومان {{ item_data.price_before_discount|price_format }} تومان {% if item_data.item.discount_percent > 0 %} @@ -292,7 +294,7 @@ --- {% endif %} - {{ item_data.item.price|price_format }} تومان + {{ item_data.final_price|price_format }} تومان {% endfor %} @@ -304,28 +306,52 @@ تعداد کل اقلام: {{ total_items }} -
- جمع کل: + + +
+ ۱. جمع سبد خرید (بعد از تخفیف محصولات): {{ subtotal|price_format }} تومان
+ + +
+ ۲. تخفیف محصولات: + + {% if items_discount_amount > 0 %} + -{{ items_discount_amount|price_format }} تومان + {% else %} + 0 تومان + {% endif %} + +
+ + +
+ ۳. تخفیف ویژه محصولات: + + {% if special_discount_total > 0 %} + -{{ special_discount_total|price_format }} تومان + {% else %} + 0 تومان + {% endif %} + +
+ {% if discount_amount > 0 %}
- تخفیف کد: - {{ discount_amount|price_format }} تومان + تخفیف کد تخفیف: + -{{ discount_amount|price_format }} تومان
{% endif %} - {% if special_discount_total > 0 %} +
- تخفیف ویژه: - {{ special_discount_total|price_format }} تومان -
- {% endif %} -
- مالیات: + مالیات ({{ tax_rate }}%): {{ tax|price_format }} تومان
+ +
- مبلغ قابل پرداخت: + ۴. قیمت نهایی (قابل پرداخت): {{ final_price|price_format }} تومان