feat: products table in bill of payment
This commit is contained in:
		
							
								
								
									
										13
									
								
								external/billing/schemas.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								external/billing/schemas.py
									
									
									
									
										vendored
									
									
								
							@@ -87,3 +87,16 @@ class BillStatusUpdateRequest(BaseSchema):
 | 
			
		||||
    listener_transaction_id: int
 | 
			
		||||
    channel: NotificationChannel
 | 
			
		||||
    info: BillPaymentInfo | BillPaymentStatus
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServiceBillingDocumentPdf(BaseSchema):
 | 
			
		||||
    name: str = ""
 | 
			
		||||
    price: int
 | 
			
		||||
    quantity: int
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProductBillingDocumentPdf(BaseSchema):
 | 
			
		||||
    article: str = ""
 | 
			
		||||
    size: str = ""
 | 
			
		||||
    price: int
 | 
			
		||||
    quantity: int
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@ import backend.config
 | 
			
		||||
import constants
 | 
			
		||||
from constants import MONTHS, ENV
 | 
			
		||||
from external.billing import BillingClient, CreateBillingRequestValue, CreateBillRequestSchema, CreateBillRequestItems, \
 | 
			
		||||
    BillStatusUpdateRequest, NotificationChannel, NotifyReceivedBillRequestSchema, DeleteBillRequestSchema
 | 
			
		||||
    BillStatusUpdateRequest, NotificationChannel, NotifyReceivedBillRequestSchema, DeleteBillRequestSchema, \
 | 
			
		||||
    ProductBillingDocumentPdf, ServiceBillingDocumentPdf
 | 
			
		||||
from models import DealBillRequest, Deal, DealProduct, DealService as DealServiceModel
 | 
			
		||||
from schemas.billing import *
 | 
			
		||||
from services.base import BaseService
 | 
			
		||||
@@ -138,28 +139,41 @@ class BillingService(BaseService):
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return CancelDealBillResponse(ok=False, message=str(e))
 | 
			
		||||
 | 
			
		||||
    async def _get_services_for_deal(self, deal: Deal) -> List[CreateBillingRequestValue]:
 | 
			
		||||
        services: List[CreateBillingRequestValue] = []
 | 
			
		||||
    async def _get_products_for_deal(self, deal: Deal) -> tuple[list, list, bool]:
 | 
			
		||||
        services: list[ServiceBillingDocumentPdf] = []
 | 
			
		||||
        products: list[ProductBillingDocumentPdf] = []
 | 
			
		||||
        is_size_needed: bool = False
 | 
			
		||||
 | 
			
		||||
        for product in deal.products:
 | 
			
		||||
            product_price = 0
 | 
			
		||||
            for service in product.services:
 | 
			
		||||
                services.append(
 | 
			
		||||
                    CreateBillingRequestValue(
 | 
			
		||||
                    ServiceBillingDocumentPdf(
 | 
			
		||||
                        name=f'[{product.product.name}] - {service.service.name}',
 | 
			
		||||
                        price=service.price,
 | 
			
		||||
                        amount=product.quantity
 | 
			
		||||
                        quantity=product.quantity
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
                product_price += service.price
 | 
			
		||||
            is_size_needed = is_size_needed | bool(product.product.size)
 | 
			
		||||
            products.append(
 | 
			
		||||
                ProductBillingDocumentPdf(
 | 
			
		||||
                    article=product.product.article,
 | 
			
		||||
                    size=product.product.size if product.product.size else "",
 | 
			
		||||
                    price=product_price,
 | 
			
		||||
                    quantity=product.quantity,
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        for service in deal.services:
 | 
			
		||||
            services.append(
 | 
			
		||||
                CreateBillingRequestValue(
 | 
			
		||||
                ServiceBillingDocumentPdf(
 | 
			
		||||
                    name=f'{service.service.name}',
 | 
			
		||||
                    price=service.price,
 | 
			
		||||
                    amount=service.quantity
 | 
			
		||||
                    quantity=service.quantity
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        return services
 | 
			
		||||
        return services, products, is_size_needed
 | 
			
		||||
 | 
			
		||||
    async def _create_billing_document_html(self, deal_id: int):
 | 
			
		||||
        deal: Deal | None = await self.session.scalar(
 | 
			
		||||
@@ -176,9 +190,9 @@ class BillingService(BaseService):
 | 
			
		||||
        if not deal:
 | 
			
		||||
            return ""
 | 
			
		||||
 | 
			
		||||
        services = await self._get_services_for_deal(deal)
 | 
			
		||||
        (services, products, is_size_needed) = await self._get_products_for_deal(deal)
 | 
			
		||||
 | 
			
		||||
        deal_price = sum((service.price * service.amount for service in services))
 | 
			
		||||
        deal_price = sum((service.price * service.quantity for service in services))
 | 
			
		||||
        deal_price_words = get_string_by_number(deal_price)[0:-10]
 | 
			
		||||
        deal_price = to_locale_number(deal_price)
 | 
			
		||||
        template = ENV.get_template("bill-of-payment.html")
 | 
			
		||||
@@ -186,7 +200,9 @@ class BillingService(BaseService):
 | 
			
		||||
        now = datetime.datetime.now()
 | 
			
		||||
        curr_date = f"{now.day} {MONTHS[now.month - 1]} {now.year} г."
 | 
			
		||||
        return template.render({
 | 
			
		||||
            "products": products,
 | 
			
		||||
            "services": services,
 | 
			
		||||
            "is_size_needed": is_size_needed,
 | 
			
		||||
            "deal_price": deal_price,
 | 
			
		||||
            "deal_price_words": deal_price_words,
 | 
			
		||||
            "deal": deal,
 | 
			
		||||
 
 | 
			
		||||
@@ -39,10 +39,38 @@
 | 
			
		||||
            </h2>
 | 
			
		||||
            <hr/>
 | 
			
		||||
            <table>
 | 
			
		||||
                <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th>Артикул</th>
 | 
			
		||||
                    {% if is_size_needed %}
 | 
			
		||||
                        <th>Размер</th>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    <th style="white-space: nowrap">Кол-во</th>
 | 
			
		||||
                    <th>Цена</th>
 | 
			
		||||
                    <th>Сумма</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tfoot>
 | 
			
		||||
                </tfoot>
 | 
			
		||||
                </thead>
 | 
			
		||||
                <tbody>
 | 
			
		||||
                {% for product in products %}
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>{{ product.article }}</td>
 | 
			
		||||
                        {% if is_size_needed %}
 | 
			
		||||
                            <td>{{ product.size }}</td>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        <td>{{ '{:,}'.format(product.quantity) }} шт.</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(product.price).replace(',', ' ') }} ₽</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(product.price * product.quantity).replace(',', ' ') }} ₽</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
                </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
            <table style="margin-top: 10px;">
 | 
			
		||||
                <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th>Наименование товара (работы, услуги)</th>
 | 
			
		||||
                    <th>Количество</th>
 | 
			
		||||
                    <th style="white-space: nowrap">Кол-во</th>
 | 
			
		||||
                    <th>Цена</th>
 | 
			
		||||
                    <th>Сумма</th>
 | 
			
		||||
                </tr>
 | 
			
		||||
@@ -53,9 +81,9 @@
 | 
			
		||||
                {% for service in services %}
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>{{ service.name }}</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(service.amount) }} шт.</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(service.quantity) }} шт.</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(service.price).replace(',', ' ') }} ₽</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(service.price * service.amount).replace(',', ' ') }} ₽</td>
 | 
			
		||||
                        <td>{{ '{:,}'.format(service.price * service.quantity).replace(',', ' ') }} ₽</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
                </tbody>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user