printer-core 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. printer_core/__init__.py +1 -0
  2. printer_core/algorithms/__init__.py +3 -0
  3. printer_core/algorithms/products_modifiers_multiprinter.py +59 -0
  4. printer_core/algorithms/products_modifiers_multiprinter_family.py +53 -0
  5. printer_core/algorithms/products_modifiers_unique_ticket.py +30 -0
  6. printer_core/builders/__init__.py +4 -0
  7. printer_core/builders/client_ticket_builder.py +97 -0
  8. printer_core/builders/header_builder.py +26 -0
  9. printer_core/builders/kitchen_ticket_payload_builder.py +99 -0
  10. printer_core/builders/printer_products_grouper.py +19 -0
  11. printer_core/clock.py +6 -0
  12. printer_core/context/__init__.py +1 -0
  13. printer_core/context/ticket_context_builder.py +55 -0
  14. printer_core/dispatchers/__init__.py +2 -0
  15. printer_core/dispatchers/kitchen_ticket_dispatcher.py +34 -0
  16. printer_core/dispatchers/payload_dispatcher.py +18 -0
  17. printer_core/entities/__init__.py +53 -0
  18. printer_core/entities/print_context.py +15 -0
  19. printer_core/entities/print_models.py +230 -0
  20. printer_core/formatters/__init__.py +1 -0
  21. printer_core/formatters/discount_formatter.py +17 -0
  22. printer_core/ports.py +45 -0
  23. printer_core/selectors/__init__.py +1 -0
  24. printer_core/selectors/family_product_selector.py +33 -0
  25. printer_core/services/__init__.py +12 -0
  26. printer_core/services/flows/__init__.py +5 -0
  27. printer_core/services/flows/base.py +26 -0
  28. printer_core/services/flows/client.py +97 -0
  29. printer_core/services/flows/kitchen.py +113 -0
  30. printer_core/services/march_printer_service.py +61 -0
  31. printer_core/services/multi_printer_family_service.py +102 -0
  32. printer_core/services/multi_printer_service.py +49 -0
  33. printer_core/services/order_print_service.py +98 -0
  34. printer_core/services/print_policy.py +72 -0
  35. printer_core/services/unique_ticket_service.py +52 -0
  36. printer_core/tests/__init__.py +0 -0
  37. printer_core/tests/unitaries/__init__.py +0 -0
  38. printer_core/tests/unitaries/helpers.py +188 -0
  39. printer_core/tests/unitaries/test_cases_output.py +189 -0
  40. printer_core/tests/unitaries/test_client_ticket_builder.py +78 -0
  41. printer_core/tests/unitaries/test_discount_formatter.py +37 -0
  42. printer_core/tests/unitaries/test_family_product_selector.py +28 -0
  43. printer_core/tests/unitaries/test_flows.py +141 -0
  44. printer_core/tests/unitaries/test_header_builder_foodeo_printers.py +87 -0
  45. printer_core/tests/unitaries/test_kitchen_ticket_dispatcher.py +61 -0
  46. printer_core/tests/unitaries/test_kitchen_ticket_payload_builder.py +113 -0
  47. printer_core/tests/unitaries/test_march_printer_service.py +31 -0
  48. printer_core/tests/unitaries/test_multi_printer_family_service.py +53 -0
  49. printer_core/tests/unitaries/test_multi_printer_service.py +51 -0
  50. printer_core/tests/unitaries/test_order_print_service.py +144 -0
  51. printer_core/tests/unitaries/test_payload_dispatcher.py +61 -0
  52. printer_core/tests/unitaries/test_print_policy.py +45 -0
  53. printer_core/tests/unitaries/test_printer_helpers.py +71 -0
  54. printer_core/tests/unitaries/test_printer_products_grouper.py +20 -0
  55. printer_core/tests/unitaries/test_products_modifiers.py +102 -0
  56. printer_core/tests/unitaries/test_ticket_context_builder.py +71 -0
  57. printer_core/tests/unitaries/test_unique_ticket_service.py +24 -0
  58. printer_core/utils/__init__.py +1 -0
  59. printer_core/utils/printer_helpers.py +42 -0
  60. printer_core-0.0.1.dist-info/METADATA +24 -0
  61. printer_core-0.0.1.dist-info/RECORD +62 -0
  62. printer_core-0.0.1.dist-info/WHEEL +4 -0
@@ -0,0 +1 @@
1
+ # printer_core package
@@ -0,0 +1,3 @@
1
+ from .products_modifiers_multiprinter import ProductsModifiersMultiPrinter
2
+ from .products_modifiers_multiprinter_family import ProductsModifiersMultiprinterFamily
3
+ from .products_modifiers_unique_ticket import ProductsModifiersUniqueTicket
@@ -0,0 +1,59 @@
1
+ from typing import Any
2
+
3
+ from printer_core.entities import KitchenProductLine, PrintProductData, PrintRequestData, PrinterData
4
+ from printer_core.formatters.discount_formatter import DiscountFormatter
5
+
6
+
7
+ class ProductsModifiersMultiPrinter:
8
+ def __init__(self, formatter: DiscountFormatter):
9
+ self._formatter = formatter
10
+
11
+ def build(
12
+ self,
13
+ request: PrintRequestData,
14
+ products: list[PrintProductData],
15
+ kitchen_ticket_settings: Any,
16
+ main_printer: PrinterData | dict[str, Any],
17
+ ) -> list[KitchenProductLine]:
18
+ list_products_own_printer: list[KitchenProductLine] = []
19
+ fallback_printer = self._resolve_printer(main_printer)
20
+ for product in products:
21
+ printers = list(product.printer or [])
22
+ if not printers:
23
+ printers = [fallback_printer]
24
+ for actual_printer in printers:
25
+ printer_payload = self._resolve_printer(actual_printer)
26
+ name = product.product_name
27
+ if kitchen_ticket_settings.show_price_per_unit and not request.all_discounted:
28
+ name += self._formatter.format(product, request.currency or "")
29
+ line = KitchenProductLine(
30
+ name=name,
31
+ qty=int(product.qty),
32
+ option=product.option,
33
+ printer_r=printer_payload.name,
34
+ printer_w=printer_payload.printer_width,
35
+ details=product.details or "",
36
+ order=product.order or "",
37
+ tpv=printer_payload.tpv,
38
+ order_readable=product.order_readable or "",
39
+ )
40
+ if kitchen_ticket_settings.show_price_per_unit:
41
+ line = line.model_copy(update={
42
+ "price": product.total_price,
43
+ "unitary_price": product.product_price,
44
+ })
45
+ list_products_own_printer.append(line)
46
+ return list_products_own_printer
47
+
48
+ def _resolve_printer(self, printer: PrinterData | dict[str, Any]) -> PrinterData:
49
+ if isinstance(printer, PrinterData):
50
+ return printer
51
+ if isinstance(printer, dict):
52
+ return PrinterData(**printer)
53
+ if hasattr(printer, "model_dump"):
54
+ return PrinterData(**printer.model_dump(mode="json", exclude_none=True))
55
+ return PrinterData(
56
+ name=printer.name,
57
+ printer_width=printer.printer_width,
58
+ tpv=getattr(printer, "tpv", None),
59
+ )
@@ -0,0 +1,53 @@
1
+ from typing import Any
2
+
3
+ from printer_core.entities import KitchenProductLine, PrintProductData, PrintRequestData, PrinterData
4
+ from printer_core.formatters.discount_formatter import DiscountFormatter
5
+
6
+
7
+ class ProductsModifiersMultiprinterFamily:
8
+ def __init__(self, formatter: DiscountFormatter):
9
+ self._formatter = formatter
10
+
11
+ def append_product(self,
12
+ list_products_own_printer: list[KitchenProductLine],
13
+ product: PrintProductData,
14
+ request: PrintRequestData,
15
+ kitchen_ticket_settings: Any,
16
+ ) -> None:
17
+ for actual_printer in product.printer:
18
+ printer_payload = self._resolve_printer(actual_printer)
19
+ name_with_discount: str = product.product_name
20
+ if not request.all_discounted:
21
+ name_with_discount += self._formatter.format(product, request.currency or "")
22
+ line = KitchenProductLine(
23
+ name=name_with_discount,
24
+ qty=int(product.qty),
25
+ option=product.option,
26
+ printer_r=printer_payload.name,
27
+ printer_w=printer_payload.printer_width,
28
+ details=product.details or "",
29
+ order=product.order or "",
30
+ tpv=printer_payload.tpv,
31
+ order_readable=product.order_readable or "",
32
+ )
33
+
34
+ if kitchen_ticket_settings.show_price_per_unit:
35
+ line = line.model_copy(update={
36
+ "price": product.total_price,
37
+ "unitary_price": product.product_price,
38
+ })
39
+
40
+ list_products_own_printer.append(line)
41
+
42
+ def _resolve_printer(self, printer: PrinterData | dict[str, Any]) -> PrinterData:
43
+ if isinstance(printer, PrinterData):
44
+ return printer
45
+ if isinstance(printer, dict):
46
+ return PrinterData(**printer)
47
+ if hasattr(printer, "model_dump"):
48
+ return PrinterData(**printer.model_dump(mode="json", exclude_none=True))
49
+ return PrinterData(
50
+ name=printer.name,
51
+ printer_width=printer.printer_width,
52
+ tpv=getattr(printer, "tpv", None),
53
+ )
@@ -0,0 +1,30 @@
1
+ from printer_core.entities import ClientTicketProduct, PrintProductData, PrintRequestData
2
+ from printer_core.formatters.discount_formatter import DiscountFormatter
3
+
4
+
5
+ class ProductsModifiersUniqueTicket:
6
+ def __init__(self, formatter: DiscountFormatter, domicile_service_label: str = "Domicile Service"):
7
+ self._formatter = formatter
8
+ self._domicile_service_label = domicile_service_label
9
+
10
+ def build(self, request: PrintRequestData, products: list[PrintProductData]) -> list[ClientTicketProduct]:
11
+ list_products_in_same_printers: list[ClientTicketProduct] = []
12
+ for product in products:
13
+ with_discount = ""
14
+ if not request.all_discounted:
15
+ with_discount = self._formatter.format(product, request.currency or "")
16
+ product_name = product.product_name + with_discount
17
+ list_products_in_same_printers.append(ClientTicketProduct(
18
+ name=product_name,
19
+ qty=int(product.qty),
20
+ option=product.option,
21
+ price=str(product.total_price),
22
+ unitary_price=str(product.product_price),
23
+ ))
24
+ if request.price_domicile_service:
25
+ list_products_in_same_printers.append(ClientTicketProduct(
26
+ name=self._domicile_service_label,
27
+ qty=1,
28
+ price=str(request.price_domicile_service),
29
+ ))
30
+ return list_products_in_same_printers
@@ -0,0 +1,4 @@
1
+ from .kitchen_ticket_payload_builder import KitchenTicketPayloadBuilder
2
+ from .printer_products_grouper import PrinterProductsGrouper
3
+ from .client_ticket_builder import ClientTicketBuilder
4
+ from .header_builder import HeaderBuilder
@@ -0,0 +1,97 @@
1
+ from decimal import Decimal
2
+ from typing import Any, Callable
3
+
4
+ from printer_core.entities import (
5
+ ClientTicketData,
6
+ ClientTicketPayload,
7
+ ClientTicketProduct,
8
+ PrintProductData,
9
+ PrintRequestData,
10
+ PrinterData,
11
+ )
12
+
13
+
14
+ class ClientTicketBuilder:
15
+ def __init__(self,
16
+ currency_symbol_resolver: Callable[[str], str] | None = None,
17
+ domicile_service_label: str = "Domicile Service",
18
+ ):
19
+ self._currency_symbol_resolver = currency_symbol_resolver or (lambda _: "")
20
+ self._domicile_service_label = domicile_service_label
21
+
22
+ def build(self,
23
+ request: PrintRequestData,
24
+ products: list[PrintProductData],
25
+ printer: PrinterData | dict[str, Any],
26
+ ticket_settings: Any,
27
+ tpv_key: str,
28
+ ) -> list[ClientTicketPayload]:
29
+ ticket_text = self._get_attr(ticket_settings, "ticket_text", "")
30
+ qty_client_ticket = self._get_attr(ticket_settings, "qty_client_ticket", 1)
31
+ client_request = ClientTicketData(
32
+ **request.model_dump(exclude={"products", "ticket_text"}),
33
+ ticket_text=ticket_text,
34
+ products=self._build_products(request, products),
35
+ )
36
+
37
+ if client_request.type in ["domicilio", "recoger"]:
38
+ client_request = client_request.model_copy(update={"details": client_request.details or ""})
39
+ elif client_request.details:
40
+ client_request = client_request.model_copy(update={"details": None})
41
+
42
+ printer_name, printer_width = self._resolve_printer(printer)
43
+ payload = ClientTicketPayload(
44
+ data=client_request,
45
+ currency=client_request.currency or "",
46
+ model=2,
47
+ company_key=tpv_key,
48
+ printer=printer_name,
49
+ printer_qty=qty_client_ticket,
50
+ printer_width=printer_width,
51
+ )
52
+ return [payload]
53
+
54
+ def _build_products(
55
+ self,
56
+ request: PrintRequestData,
57
+ products: list[PrintProductData],
58
+ ) -> list[ClientTicketProduct]:
59
+ list_products: list[ClientTicketProduct] = []
60
+ currency_symbol = self._currency_symbol_resolver(request.currency or "")
61
+ for product in products:
62
+ with_discount = ""
63
+ if not request.all_discounted:
64
+ with_discount = self._format_discount(product, currency_symbol)
65
+ product_name = product.product_name + with_discount
66
+ list_products.append(ClientTicketProduct(
67
+ name=product_name,
68
+ qty=int(product.qty),
69
+ option=product.option,
70
+ price=str(product.total_price),
71
+ unitary_price=str(product.product_price),
72
+ ))
73
+ if request.price_domicile_service:
74
+ list_products.append(ClientTicketProduct(
75
+ name=self._domicile_service_label,
76
+ qty=1,
77
+ price=str(request.price_domicile_service),
78
+ ))
79
+ return list_products
80
+
81
+ def _format_discount(self, product: PrintProductData, currency_symbol: str) -> str:
82
+ if product.discount_type == "number":
83
+ return f" (Dto {product.total_price}{currency_symbol})"
84
+ if product.discount_type == "percent" and product.discount:
85
+ total = Decimal(str(product.importe)) - Decimal(str(product.total_price))
86
+ return f" (Dto {product.discount.value}% {total}{currency_symbol})"
87
+ return ""
88
+
89
+ def _get_attr(self, obj: Any, attr: str, default: Any) -> Any:
90
+ if isinstance(obj, dict):
91
+ return obj.get(attr, default)
92
+ return getattr(obj, attr, default)
93
+
94
+ def _resolve_printer(self, printer: PrinterData | dict[str, Any]) -> tuple[str, Any]:
95
+ if isinstance(printer, dict):
96
+ return printer["name"], printer["printer_width"]
97
+ return printer.name, printer.printer_width
@@ -0,0 +1,26 @@
1
+ from typing import Any
2
+
3
+ from printer_core.entities import HeaderData, PrintRequestData
4
+ from printer_core.ports import HeaderDataProvider
5
+
6
+
7
+ class HeaderBuilder:
8
+ def __init__(self, provider: HeaderDataProvider, show_person_name: bool):
9
+ self._provider = provider
10
+ self._show_person_name = show_person_name
11
+
12
+ def build_header(self, request: PrintRequestData, worker: Any | None = None) -> HeaderData:
13
+ header_data: dict[str, str] = self._provider.get_company_header()
14
+ if self._show_person_name and worker:
15
+ header_data.update(self._provider.get_worker_header(worker))
16
+ header_data.update(self._client_header(request))
17
+ return HeaderData(**header_data)
18
+
19
+ def _client_header(self, request: PrintRequestData) -> dict[str, str]:
20
+ request_type = request.type
21
+ from_client = request.from_client
22
+ if request_type == "recoger":
23
+ return self._provider.get_pickup_client_header(request.client, from_client)
24
+ if request_type == "domicilio":
25
+ return self._provider.get_domicile_client_header(request.address, from_client)
26
+ return {}
@@ -0,0 +1,99 @@
1
+ from datetime import datetime
2
+ from typing import Any, Callable
3
+
4
+ from printer_core.clock import SystemClock
5
+ from printer_core.entities import (
6
+ KitchenProductLine,
7
+ KitchenTicketData,
8
+ KitchenTicketPayload,
9
+ PrintRequestData,
10
+ PrintSettingsData,
11
+ ProductsGroup,
12
+ )
13
+ from printer_core.ports import Clock
14
+
15
+
16
+ class KitchenTicketPayloadBuilder:
17
+ def __init__(self, clock: Clock | None = None):
18
+ self._clock = clock or SystemClock()
19
+
20
+ def build(self,
21
+ request: PrintRequestData,
22
+ printer_name: str,
23
+ tpv_key: str,
24
+ printer_width: str,
25
+ products: list[KitchenProductLine],
26
+ ticket_settings: Any,
27
+ kitchen_ticket_settings: Any,
28
+ group_products_func: Callable[[list[KitchenProductLine]], list[ProductsGroup]],
29
+ ) -> KitchenTicketPayload:
30
+ data = KitchenTicketData(
31
+ id=request.id,
32
+ table_name=request.table_name,
33
+ credit_card=request.credit_card,
34
+ serial=request.serial,
35
+ details=request.details or "",
36
+ type=request.type,
37
+ discount=request.discount,
38
+ )
39
+
40
+ data = data.model_copy(update={"created_at": self._resolve_created_at(request)})
41
+
42
+ if kitchen_ticket_settings.show_total_price:
43
+ data = data.model_copy(update={
44
+ "total": str(request.total),
45
+ "request_price": request.request_price,
46
+ })
47
+
48
+ if request.type == "local" and kitchen_ticket_settings.show_command_guests:
49
+ data = data.model_copy(update={"command_guests": request.command_guests})
50
+
51
+ if request.headerData:
52
+ data = data.model_copy(update={"headerData": request.headerData})
53
+
54
+ model = 1
55
+ if request.type != "local":
56
+ model = 2
57
+
58
+ data = self._set_products(data, request, products, group_products_func)
59
+ print_settings = self._set_print_settings(request)
60
+
61
+ return KitchenTicketPayload(
62
+ data=data,
63
+ model=model,
64
+ printer_qty=ticket_settings.qty_kitchen_ticket,
65
+ printer=printer_name,
66
+ company_key=tpv_key,
67
+ printer_width=printer_width,
68
+ currency=request.currency or "",
69
+ PrintSettings=print_settings,
70
+ )
71
+
72
+ def _resolve_created_at(self, request: PrintRequestData) -> str:
73
+ if request.type in ["domicilio", "recoger"] and request.shift_time and request.delivery_date:
74
+ shift_time = datetime.strptime(request.shift_time, "%H:%M").time()
75
+ delivery_date = datetime.strptime(request.delivery_date, "%Y-%m-%d").date()
76
+ return datetime.combine(delivery_date, shift_time).strftime("%Y-%m-%d %H:%M")
77
+ return self._clock.now_iso()
78
+
79
+ def _set_products(self,
80
+ data: KitchenTicketData,
81
+ request: PrintRequestData,
82
+ products: list[KitchenProductLine],
83
+ group_products_func: Callable[[list[KitchenProductLine]], list[ProductsGroup]],
84
+ ) -> KitchenTicketData:
85
+ group_by_orders = request.group_by_orders
86
+ if group_by_orders and request.type == "local":
87
+ grouped = group_products_func(products)
88
+ if grouped and not isinstance(grouped[0], ProductsGroup):
89
+ grouped = [ProductsGroup(group="Sin orden", products=grouped)]
90
+ return data.model_copy(update={"products_groups": grouped})
91
+ return data.model_copy(update={"products": products})
92
+
93
+ def _set_print_settings(self, request: PrintRequestData) -> PrintSettingsData | None:
94
+ print_settings = request.PrintSettings
95
+ if not print_settings:
96
+ return None
97
+ if request.type == "local" and print_settings.show_local_header is not None:
98
+ return print_settings.model_copy(update={"show_header": print_settings.show_local_header})
99
+ return print_settings
@@ -0,0 +1,19 @@
1
+ from printer_core.entities import KitchenProductLine, PrinterProductGroup
2
+
3
+
4
+ class PrinterProductsGrouper:
5
+ @staticmethod
6
+ def group_by_printer_key(products: list[KitchenProductLine]) -> list[PrinterProductGroup]:
7
+ grouped: dict[str, PrinterProductGroup] = {}
8
+ for item in products:
9
+ key = f"{item.printer_r}%%{item.tpv or ''}%%{item.printer_w}"
10
+ if key not in grouped:
11
+ grouped[key] = PrinterProductGroup(
12
+ printer_name=item.printer_r,
13
+ tpv_key=item.tpv or "",
14
+ printer_width=item.printer_w,
15
+ products=[item],
16
+ )
17
+ else:
18
+ grouped[key].products.append(item)
19
+ return list(grouped.values())
printer_core/clock.py ADDED
@@ -0,0 +1,6 @@
1
+ from datetime import datetime, timezone
2
+
3
+
4
+ class SystemClock:
5
+ def now_iso(self) -> str:
6
+ return datetime.now(timezone.utc).isoformat()
@@ -0,0 +1 @@
1
+ from .ticket_context_builder import TicketContextBuilder
@@ -0,0 +1,55 @@
1
+ from typing import Any
2
+
3
+ from printer_core.entities import PrintRequestData, PrintSettingsData
4
+ from printer_core.ports import HeaderProvider, PrintSettingsBuilder
5
+
6
+
7
+ class TicketContextBuilder:
8
+ def __init__(self, header_provider: HeaderProvider, print_settings_builder: PrintSettingsBuilder):
9
+ self._header_provider = header_provider
10
+ self._print_settings_builder = print_settings_builder
11
+
12
+ def apply_kitchen_context(self,
13
+ request: PrintRequestData,
14
+ ticket_settings: Any,
15
+ kitchen_ticket_settings: Any,
16
+ header_mode: str,
17
+ include_print_by: bool = True,
18
+ worker: Any | None = None,
19
+ ) -> PrintRequestData:
20
+ updates: dict[str, Any] = {
21
+ "order_by": ticket_settings.order_by if ticket_settings.order_by else "name",
22
+ "group_by_orders": kitchen_ticket_settings.group_by_orders,
23
+ "PrintSettings": self._print_settings_builder.build(kitchen_ticket_settings),
24
+ }
25
+ if include_print_by:
26
+ updates["print_by"] = kitchen_ticket_settings.print_by
27
+ if self._should_add_header(kitchen_ticket_settings, header_mode):
28
+ header_data = self._header_provider.build_header(request, worker=worker)
29
+ updates["headerData"] = header_data
30
+ return request.model_copy(update=updates)
31
+
32
+ def apply_client_context(self,
33
+ request: PrintRequestData,
34
+ kitchen_ticket_settings: Any,
35
+ include_header: bool = True,
36
+ details_font_none: bool = True,
37
+ worker: Any | None = None,
38
+ ) -> PrintRequestData:
39
+ print_settings: PrintSettingsData = self._print_settings_builder.build(kitchen_ticket_settings)
40
+ if details_font_none:
41
+ print_settings = print_settings.model_copy(update={"details_font": None})
42
+ updates: dict[str, Any] = {"PrintSettings": print_settings}
43
+ if include_header:
44
+ header_data = self._header_provider.build_header(request, worker=worker)
45
+ updates["headerData"] = header_data
46
+ return request.model_copy(update=updates)
47
+
48
+ def _should_add_header(self, kitchen_ticket_settings: Any, header_mode: str) -> bool:
49
+ match header_mode:
50
+ case "local":
51
+ return kitchen_ticket_settings.show_local_header
52
+ case "domicile":
53
+ return kitchen_ticket_settings.show_domicile_header
54
+ case _:
55
+ return False
@@ -0,0 +1,2 @@
1
+ from .kitchen_ticket_dispatcher import KitchenTicketDispatcher
2
+ from .payload_dispatcher import PayloadDispatcher
@@ -0,0 +1,34 @@
1
+ from typing import Any, Callable
2
+
3
+ from printer_core.builders.kitchen_ticket_payload_builder import KitchenTicketPayloadBuilder
4
+ from printer_core.entities import KitchenProductLine, KitchenTicketPayload, PrintRequestData, PrinterProductGroup, ProductsGroup
5
+ from printer_core.ports import PrinterGateway
6
+
7
+
8
+ class KitchenTicketDispatcher:
9
+ def __init__(self, gateway: PrinterGateway, builder: KitchenTicketPayloadBuilder | None = None):
10
+ self._builder = builder or KitchenTicketPayloadBuilder()
11
+ self._gateway = gateway
12
+
13
+ def dispatch(self,
14
+ request: PrintRequestData,
15
+ grouped_products: list[PrinterProductGroup],
16
+ ticket_settings: Any,
17
+ kitchen_ticket_settings: Any,
18
+ group_products_func: Callable[[list[KitchenProductLine]], list[ProductsGroup]],
19
+ ) -> list[KitchenTicketPayload]:
20
+ final_request: list[KitchenTicketPayload] = []
21
+ for group in grouped_products:
22
+ payload = self._builder.build(
23
+ request=request,
24
+ printer_name=group.printer_name,
25
+ tpv_key=group.tpv_key,
26
+ printer_width=group.printer_width,
27
+ products=group.products,
28
+ ticket_settings=ticket_settings,
29
+ kitchen_ticket_settings=kitchen_ticket_settings,
30
+ group_products_func=group_products_func,
31
+ )
32
+ final_request.append(payload)
33
+ self._gateway.send_data(group.tpv_key, [payload.model_dump(mode="json", exclude_none=True)])
34
+ return final_request
@@ -0,0 +1,18 @@
1
+ from typing import Any
2
+
3
+ from printer_core.ports import PrinterGateway
4
+
5
+
6
+ class PayloadDispatcher:
7
+ def __init__(self, gateway: PrinterGateway):
8
+ self._gateway = gateway
9
+
10
+ def send(self, tpv_key: str, payload: Any) -> None:
11
+ if hasattr(payload, "model_dump"):
12
+ payload = payload.model_dump(mode="json", exclude_none=True)
13
+ if isinstance(payload, list):
14
+ payload = [
15
+ item.model_dump(mode="json", exclude_none=True) if hasattr(item, "model_dump") else item
16
+ for item in payload
17
+ ]
18
+ self._gateway.send_data(tpv_key, payload)
@@ -0,0 +1,53 @@
1
+ from .print_context import PrintContext
2
+ from .print_models import (
3
+ ClientTicketData,
4
+ ClientTicketPayload,
5
+ ClientTicketProduct,
6
+ CompanyHeaderData,
7
+ DiscountData,
8
+ FamilyData,
9
+ FiskalyData,
10
+ HeaderData,
11
+ IvaData,
12
+ KitchenProductLine,
13
+ KitchenTicketData,
14
+ KitchenTicketPayload,
15
+ MarchCommandData,
16
+ PrintSettingsData,
17
+ PrintChannel,
18
+ PrintJob,
19
+ PrintResult,
20
+ PrintProductData,
21
+ PrintRequestData,
22
+ PrinterData,
23
+ PrinterProductGroup,
24
+ ProductsGroup,
25
+ WorkerData,
26
+ )
27
+
28
+ __all__ = [
29
+ "ClientTicketPayload",
30
+ "ClientTicketProduct",
31
+ "ClientTicketData",
32
+ "CompanyHeaderData",
33
+ "DiscountData",
34
+ "FamilyData",
35
+ "FiskalyData",
36
+ "HeaderData",
37
+ "IvaData",
38
+ "KitchenProductLine",
39
+ "KitchenTicketData",
40
+ "KitchenTicketPayload",
41
+ "MarchCommandData",
42
+ "PrintContext",
43
+ "PrintSettingsData",
44
+ "PrintChannel",
45
+ "PrintJob",
46
+ "PrintResult",
47
+ "PrintProductData",
48
+ "PrintRequestData",
49
+ "PrinterData",
50
+ "PrinterProductGroup",
51
+ "ProductsGroup",
52
+ "WorkerData",
53
+ ]
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from printer_core.entities.print_models import PrinterData, WorkerData
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class PrintContext:
11
+ ticket_settings: Any
12
+ kitchen_settings: Any
13
+ global_settings: Any
14
+ main_printer: PrinterData
15
+ worker: WorkerData | None = None