feat: end-point for pdf of all deal's barcodes, client and marketplace info in bill of payment

This commit is contained in:
2024-09-28 19:38:06 +04:00
parent d9c43624c0
commit 489f65a087
8 changed files with 169 additions and 57 deletions

View File

@@ -1,13 +1,11 @@
from abc import abstractmethod
from typing import List, Dict
from models import ProductBarcode, Product, BarcodeTemplate
from models import BarcodeTemplate, Product
class BaseBarcodeGenerator:
@abstractmethod
def generate(self,
barcode: ProductBarcode,
product: Product,
template: BarcodeTemplate):
def generate(self, data: List[Dict[str, str | Product | BarcodeTemplate | int]]):
pass

View File

@@ -1,26 +1,40 @@
from typing import List, Dict
from barcodes.attributes import AttributeWriterFactory
from barcodes.generator.base import BaseBarcodeGenerator
from barcodes.pdf import PDFGenerator
from models import ProductBarcode, Product, BarcodeTemplate
from models import Product, BarcodeTemplate
from schemas.barcode import PdfBarcodeGenData
class DefaultBarcodeGenerator(BaseBarcodeGenerator):
def generate(self,
barcode: str,
product: Product,
template: BarcodeTemplate,
quantity: int = 1):
def generate(self, barcodes_data: List[Dict[str, str | Product | BarcodeTemplate | int]]):
pdf_generator = PDFGenerator()
attributes = {}
for attribute in template.attributes:
attribute_getter = AttributeWriterFactory.get_writer(attribute.key)
if not attribute_getter:
continue
value = attribute_getter.get_value(product)
if not value or not value.strip():
continue
attributes[attribute.name] = value
for additional_attribute in template.additional_attributes:
attributes[additional_attribute.name] = additional_attribute.value
barcode_text = '<br/>'.join([f'{key}: {value}' for key, value in attributes.items()])
return pdf_generator.generate(barcode, barcode_text, num_duplicates=quantity)
pdf_barcodes_gen_data: List[PdfBarcodeGenData] = []
for barcode_data in barcodes_data:
attributes = {}
for attribute in barcode_data["template"].attributes:
attribute_getter = AttributeWriterFactory.get_writer(attribute.key)
if not attribute_getter:
continue
value = attribute_getter.get_value(barcode_data["product"])
if not value or not value.strip():
continue
attributes[attribute.name] = value
for additional_attribute in barcode_data["template"].additional_attributes:
attributes[additional_attribute.name] = additional_attribute.value
barcode_text = '<br/>'.join([f'{key}: {value}' for key, value in attributes.items()])
pdf_barcodes_gen_data.append(
PdfBarcodeGenData(
barcode_value=barcode_data["barcode"],
text=barcode_text,
num_duplicates=barcode_data["quantity"]
)
)
print(f"value = {barcode_data['barcode']}, text = {barcode_text}, num = {barcode_data['quantity']}")
return pdf_generator.generate(pdf_barcodes_gen_data)

View File

@@ -1,5 +1,7 @@
import os
from io import BytesIO
from typing import List
from reportlab.graphics.barcode import code128
from reportlab.lib.pagesizes import mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
@@ -8,6 +10,7 @@ from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from constants import APP_PATH
from schemas.barcode import PdfBarcodeGenData
class PDFGenerator:
@@ -82,7 +85,7 @@ class PDFGenerator:
buffer.seek(0)
return buffer
def generate(self, barcode_value, text, num_duplicates=1):
def generate(self, barcodes_data: List[PdfBarcodeGenData]):
buffer = BytesIO()
# Создаем документ с указанным размером страницы
@@ -93,43 +96,58 @@ class PDFGenerator:
topMargin=1 * mm,
bottomMargin=1 * mm)
# Создаем абзац с новым стилем
paragraph = Paragraph(text, self.small_style)
# Список элементов для добавления в документ
elements = []
product_barcode_canvases = []
product_counter = 0
product_barcodes_counter = 0
# Получаем ширину и высоту абзаца
paragraph_width, paragraph_height = paragraph.wrap(self.page_width - 2 * mm, self.page_height)
for barcode_data in barcodes_data:
# Создаем абзац с новым стилем
paragraph = Paragraph(barcode_data.text, self.small_style)
# Рассчитываем доступное пространство для штрихкода
human_readable_height = 6 * mm # Высота human-readable текста
space_between_text_and_barcode = 4 * mm # Отступ между текстом и штрихкодом
barcode_height = self.page_height - paragraph_height - human_readable_height - space_between_text_and_barcode - 4 * mm # Учитываем поля и отступы
# Получаем ширину и высоту абзаца
paragraph_width, paragraph_height = paragraph.wrap(self.page_width - 2 * mm, self.page_height)
# Создаем штрихкод
available_width = self.page_width - 2 * mm # Учитываем поля
# Рассчитываем доступное пространство для штрихкода
human_readable_height = 6 * mm # Высота human-readable текста
space_between_text_and_barcode = 4 * mm # Отступ между текстом и штрихкодом
barcode_height = self.page_height - paragraph_height - human_readable_height - space_between_text_and_barcode - 4 * mm # Учитываем поля и отступы
# Приблизительное количество элементов в штрихкоде Code 128 для средней длины
num_elements = 11 * len(barcode_value) # Примерная оценка: 11 элементов на символ
# Создаем штрихкод
available_width = self.page_width - 2 * mm # Учитываем поля
# Рассчитываем ширину штриха
bar_width = available_width / num_elements
barcode = code128.Code128(barcode_value,
barWidth=bar_width,
barHeight=barcode_height,
humanReadable=True)
# Приблизительное количество элементов в штрихкоде Code 128 для средней длины
num_elements = 11 * len(barcode_data.barcode_value) # Примерная оценка: 11 элементов на символ
# Рассчитываем ширину штриха
bar_width = available_width / num_elements
barcode = code128.Code128(barcode_data.barcode_value,
barWidth=bar_width,
barHeight=barcode_height,
humanReadable=True)
product_barcode_canvases.append(barcode)
# Добавление штрихкодов в список элементов документа
for _ in range(barcode_data.num_duplicates):
elements.append(paragraph)
elements.append(Spacer(1, space_between_text_and_barcode)) # Отступ между текстом и штрихкодом
elements.append(PageBreak())
# Функция для отрисовки штрихкода на canvas
def add_barcode(canvas, doc):
barcode_width = barcode.width
nonlocal product_barcodes_counter, product_counter
barcode_canvas = product_barcode_canvases[product_counter]
barcode_width = barcode_canvas.width
barcode_x = (self.page_width - barcode_width) / 2 # Центрируем штрихкод
barcode_y = human_readable_height + 2 * mm # Размещаем штрихкод снизу с учетом отступа
barcode.drawOn(canvas, barcode_x, barcode_y)
barcode_canvas.drawOn(canvas, barcode_x, barcode_y)
# Создаем список элементов для добавления в документ
elements = []
for _ in range(num_duplicates):
elements.append(paragraph)
elements.append(Spacer(1, space_between_text_and_barcode)) # Отступ между текстом и штрихкодом
elements.append(PageBreak())
product_barcodes_counter += 1
if product_barcodes_counter >= barcodes_data[product_counter].num_duplicates:
product_barcodes_counter = 0
product_counter += 1
# Создаем документ
doc.build(elements[:-1], onFirstPage=add_barcode, onLaterPages=add_barcode) # Убираем последний PageBreak