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,102 @@
1
+ from typing import Any, Callable
2
+
3
+ from printer_core.algorithms.products_modifiers_multiprinter_family import (
4
+ ProductsModifiersMultiprinterFamily,
5
+ )
6
+ from printer_core.builders.printer_products_grouper import PrinterProductsGrouper
7
+ from printer_core.dispatchers.kitchen_ticket_dispatcher import KitchenTicketDispatcher
8
+ from printer_core.entities import (
9
+ KitchenProductLine,
10
+ KitchenTicketPayload,
11
+ PrintProductData,
12
+ PrintRequestData,
13
+ PrinterData,
14
+ ProductsGroup,
15
+ )
16
+ from printer_core.formatters.discount_formatter import DiscountFormatter
17
+ from printer_core.ports import FamilyCategoryProvider, PrinterGateway
18
+ from printer_core.selectors.family_product_selector import FamilyProductSelector
19
+ from printer_core.utils.printer_helpers import group_products_by_orders, order_products_by_name
20
+
21
+
22
+ class MultiPrinterFamilyService:
23
+ def __init__(
24
+ self,
25
+ gateway: PrinterGateway,
26
+ family_provider: FamilyCategoryProvider,
27
+ currency_symbol_resolver: Callable[[str], str],
28
+ order_by_func: Callable[[list[KitchenProductLine]], list[KitchenProductLine]] | None = None,
29
+ group_products_func: Callable[[list[KitchenProductLine]], list[ProductsGroup]] | None = None,
30
+ ):
31
+ self._gateway = gateway
32
+ self._family_provider = family_provider
33
+ self._currency_symbol_resolver = currency_symbol_resolver
34
+ self._order_by_func = order_by_func or order_products_by_name
35
+ self._group_products_func = group_products_func or group_products_by_orders
36
+
37
+ def build_and_dispatch(
38
+ self,
39
+ request: PrintRequestData,
40
+ products: list[PrintProductData],
41
+ main_printer: PrinterData,
42
+ ticket_settings: Any,
43
+ kitchen_ticket_settings: Any,
44
+ ) -> list[KitchenTicketPayload]:
45
+ selector = FamilyProductSelector(provider=self._family_provider)
46
+ families, products_by_family, products_without_family = selector.group_products(products)
47
+
48
+ formatter = DiscountFormatter(currency_symbol_resolver=self._currency_symbol_resolver)
49
+ family_builder = ProductsModifiersMultiprinterFamily(formatter)
50
+ list_products_own_printer: list[KitchenProductLine] = []
51
+ dispatched: list[KitchenTicketPayload] = []
52
+
53
+ for family in families:
54
+ list_products_own_printer.clear()
55
+ family_products = products_by_family.get(family.id, [])
56
+ for product in family_products:
57
+ if product.printer:
58
+ product_with_printer = product
59
+ else:
60
+ product_with_printer = product.model_copy(update={"printer": [main_printer]})
61
+ family_builder.append_product(
62
+ list_products_own_printer, product_with_printer, request, kitchen_ticket_settings
63
+ )
64
+ dispatched.extend(self._dispatch_products(
65
+ list_products_own_printer, request, ticket_settings, kitchen_ticket_settings
66
+ ))
67
+
68
+ list_products_own_printer.clear()
69
+ for product in products_without_family:
70
+ if product.printer:
71
+ product_with_printer = product
72
+ else:
73
+ product_with_printer = product.model_copy(update={"printer": [main_printer]})
74
+ family_builder.append_product(
75
+ list_products_own_printer, product_with_printer, request, kitchen_ticket_settings
76
+ )
77
+
78
+ dispatched.extend(self._dispatch_products(
79
+ list_products_own_printer, request, ticket_settings, kitchen_ticket_settings
80
+ ))
81
+ return dispatched
82
+
83
+ def _dispatch_products(
84
+ self,
85
+ list_products_own_printer: list[KitchenProductLine],
86
+ request: PrintRequestData,
87
+ ticket_settings: Any,
88
+ kitchen_ticket_settings: Any,
89
+ ) -> list[KitchenTicketPayload]:
90
+ if not list_products_own_printer:
91
+ return []
92
+ if (request.order_by or "standard") == "name":
93
+ list_products_own_printer = self._order_by_func(list_products_own_printer)
94
+ grouped_products = PrinterProductsGrouper.group_by_printer_key(list_products_own_printer)
95
+ dispatcher = KitchenTicketDispatcher(gateway=self._gateway)
96
+ return dispatcher.dispatch(
97
+ request=request,
98
+ grouped_products=grouped_products,
99
+ ticket_settings=ticket_settings,
100
+ kitchen_ticket_settings=kitchen_ticket_settings,
101
+ group_products_func=self._group_products_func,
102
+ )
@@ -0,0 +1,49 @@
1
+ from typing import Any, Callable
2
+
3
+ from printer_core.algorithms.products_modifiers_multiprinter import ProductsModifiersMultiPrinter
4
+ from printer_core.builders.printer_products_grouper import PrinterProductsGrouper
5
+ from printer_core.dispatchers.kitchen_ticket_dispatcher import KitchenTicketDispatcher
6
+ from printer_core.entities import KitchenProductLine, KitchenTicketPayload, PrintProductData, PrintRequestData, PrinterData, ProductsGroup
7
+ from printer_core.formatters.discount_formatter import DiscountFormatter
8
+ from printer_core.ports import PrinterGateway
9
+ from printer_core.utils.printer_helpers import group_products_by_orders, order_products_by_name
10
+
11
+
12
+ class MultiPrinterService:
13
+ def __init__(
14
+ self,
15
+ gateway: PrinterGateway,
16
+ currency_symbol_resolver: Callable[[str], str],
17
+ order_by_func: Callable[[list[KitchenProductLine]], list[KitchenProductLine]] | None = None,
18
+ group_products_func: Callable[[list[KitchenProductLine]], list[ProductsGroup]] | None = None,
19
+ ):
20
+ self._gateway = gateway
21
+ self._currency_symbol_resolver = currency_symbol_resolver
22
+ self._order_by_func = order_by_func or order_products_by_name
23
+ self._group_products_func = group_products_func or group_products_by_orders
24
+
25
+ def build_and_dispatch(
26
+ self,
27
+ request: PrintRequestData,
28
+ products: list[PrintProductData],
29
+ main_printer: PrinterData,
30
+ ticket_settings: Any,
31
+ kitchen_ticket_settings: Any,
32
+ ) -> list[KitchenTicketPayload]:
33
+ formatter = DiscountFormatter(currency_symbol_resolver=self._currency_symbol_resolver)
34
+ list_products_own_printer = ProductsModifiersMultiPrinter(formatter).build(
35
+ request, products, kitchen_ticket_settings, main_printer
36
+ )
37
+
38
+ if (request.order_by or "standard") == "name":
39
+ list_products_own_printer = self._order_by_func(list_products_own_printer)
40
+
41
+ grouped_products = PrinterProductsGrouper.group_by_printer_key(list_products_own_printer)
42
+ dispatcher = KitchenTicketDispatcher(gateway=self._gateway)
43
+ return dispatcher.dispatch(
44
+ request=request,
45
+ grouped_products=grouped_products,
46
+ ticket_settings=ticket_settings,
47
+ kitchen_ticket_settings=kitchen_ticket_settings,
48
+ group_products_func=self._group_products_func,
49
+ )
@@ -0,0 +1,98 @@
1
+ from __future__ import annotations
2
+
3
+ from decimal import Decimal
4
+ from typing import Any, Callable
5
+
6
+ from printer_core.clock import SystemClock
7
+ from printer_core.entities import (
8
+ PrintChannel,
9
+ PrintJob,
10
+ PrintRequestData,
11
+ PrintResult,
12
+ )
13
+ from printer_core.services.flows import PrintFlow
14
+ from printer_core.services.print_policy import FlowTarget, PrintPolicy
15
+ from printer_core.utils.printer_helpers import build_iva_data
16
+ from printer_core.ports import FamilyCategoryProvider, HeaderProvider, PrinterGateway, PrintSettingsBuilder
17
+
18
+
19
+ class OrderPrintService:
20
+ def __init__(
21
+ self,
22
+ gateway: PrinterGateway,
23
+ header_provider: HeaderProvider,
24
+ print_settings_builder: PrintSettingsBuilder,
25
+ family_provider: FamilyCategoryProvider,
26
+ currency_symbol_resolver: Callable[[str], str],
27
+ flows: list[PrintFlow],
28
+ domicile_service_label: str = "Domicile Service",
29
+ ):
30
+ self._gateway = gateway
31
+ self._family_provider = family_provider
32
+ self._currency_symbol_resolver = currency_symbol_resolver
33
+ self._header_provider = header_provider
34
+ self._print_settings_builder = print_settings_builder
35
+ self._domicile_service_label = domicile_service_label
36
+ self._clock = SystemClock()
37
+ self._flows = flows
38
+
39
+ def print_job(self, job: PrintJob, context: Any, channel: PrintChannel) -> PrintResult:
40
+ base_request = self._build_request(job.request, context, channel)
41
+ products = job.products
42
+
43
+ result = PrintResult()
44
+ policy = PrintPolicy(channel, context.ticket_settings, context.global_settings)
45
+ plan = policy.plan(base_request)
46
+
47
+ for flow in self._flows:
48
+ if flow.target not in plan.enabled_flows:
49
+ continue
50
+ data = flow.execute(
51
+ base_request=base_request,
52
+ products=products,
53
+ context=context,
54
+ channel=channel,
55
+ tpv_key=job.tpv_key,
56
+ )
57
+ if flow.target == FlowTarget.KITCHEN:
58
+ result = result.model_copy(update={"multi_printer": data})
59
+ elif flow.target == FlowTarget.CLIENT:
60
+ result = result.model_copy(update={"ticket_client": data})
61
+
62
+ return result
63
+
64
+ def _build_request(
65
+ self,
66
+ request: PrintRequestData,
67
+ context: Any,
68
+ channel: PrintChannel,
69
+ ) -> PrintRequestData:
70
+ enriched = self._normalize_discount(channel, request)
71
+ if not enriched.print_by and getattr(context.kitchen_settings, "print_by", None):
72
+ enriched = enriched.model_copy(update={"print_by": context.kitchen_settings.print_by})
73
+ if channel in (PrintChannel.KIOSKO, PrintChannel.BARRA):
74
+ enriched = enriched.model_copy(update={"created_at": self._clock.now_iso()})
75
+ if not enriched.currency and getattr(context.global_settings, "currency", None):
76
+ enriched = enriched.model_copy(update={"currency": context.global_settings.currency})
77
+
78
+ total, enriched = self._compute_total(channel, enriched)
79
+ iva_data = build_iva_data(total, Decimal(str(context.global_settings.iva)))
80
+ enriched = enriched.model_copy(update={"total": str(total), "ivaData": iva_data})
81
+ return enriched
82
+
83
+ def _compute_total(self, channel: PrintChannel, request: PrintRequestData) -> tuple[Decimal, PrintRequestData]:
84
+ request_price = Decimal(str(request.request_price)).quantize(Decimal(".01"))
85
+ if channel != PrintChannel.DOMICILE:
86
+ if request.price_domicile_service is not None:
87
+ request = request.model_copy(update={"price_domicile_service": None})
88
+ return request_price, request
89
+ domicile_price = Decimal(str(request.price_domicile_service or "0")).quantize(Decimal(".01"))
90
+ request = request.model_copy(update={"price_domicile_service": str(domicile_price)})
91
+ return request_price + domicile_price, request
92
+
93
+ def _normalize_discount(self, channel: PrintChannel, request: PrintRequestData) -> PrintRequestData:
94
+ if channel == PrintChannel.LOCAL:
95
+ return request.model_copy(update={"discount": None})
96
+ if channel in (PrintChannel.KIOSKO, PrintChannel.BARRA) and not request.all_discounted:
97
+ return request.model_copy(update={"discount": None})
98
+ return request
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from enum import Enum
5
+ from typing import Any
6
+
7
+ from printer_core.entities import PrintChannel, PrintRequestData
8
+
9
+
10
+ class FlowTarget(str, Enum):
11
+ KITCHEN = "kitchen"
12
+ CLIENT = "client"
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class PrintPlan:
17
+ enabled_flows: set[FlowTarget] = field(default_factory=set)
18
+ reasons: list[str] = field(default_factory=list)
19
+
20
+ @property
21
+ def print_kitchen(self) -> bool:
22
+ return FlowTarget.KITCHEN in self.enabled_flows
23
+
24
+ @property
25
+ def print_client(self) -> bool:
26
+ return FlowTarget.CLIENT in self.enabled_flows
27
+
28
+
29
+ class PrintPolicy:
30
+ def __init__(self, channel: PrintChannel, ticket_settings: Any, global_settings: Any):
31
+ self._channel = channel
32
+ self._ticket_settings = ticket_settings
33
+ self._global_settings = global_settings
34
+
35
+ def plan(self, request: PrintRequestData) -> PrintPlan:
36
+ print_kitchen = self._should_print_kitchen()
37
+ print_client = self._should_print_client(request)
38
+ enabled_flows: set[FlowTarget] = set()
39
+ if print_kitchen:
40
+ enabled_flows.add(FlowTarget.KITCHEN)
41
+ if print_client:
42
+ enabled_flows.add(FlowTarget.CLIENT)
43
+ return PrintPlan(enabled_flows=enabled_flows)
44
+
45
+ def _should_print_kitchen(self) -> bool:
46
+ if self._channel in (PrintChannel.KIOSKO, PrintChannel.BARRA):
47
+ return bool(getattr(self._ticket_settings, "ticket_kitchen_barra", False))
48
+ if self._channel == PrintChannel.LOCAL:
49
+ return bool(getattr(self._ticket_settings, "ticket_kitchen_local", False))
50
+ return bool(getattr(self._ticket_settings, "ticket_kitchen_domicile_or_pickup", False))
51
+
52
+ def _should_print_client(self, request: PrintRequestData) -> bool:
53
+ if self._channel in (PrintChannel.KIOSKO, PrintChannel.BARRA):
54
+ enabled = bool(getattr(self._ticket_settings, "ticket_client_barra", False))
55
+ if not enabled:
56
+ return False
57
+ if self._channel == PrintChannel.BARRA and self._barra_payment_suppresses(request):
58
+ return False
59
+ return True
60
+ if self._channel == PrintChannel.LOCAL:
61
+ return bool(getattr(self._ticket_settings, "ticket_client_local", False))
62
+ return bool(getattr(self._ticket_settings, "ticket_client_domicile_or_pickup", False))
63
+
64
+ def _barra_payment_suppresses(self, request: PrintRequestData) -> bool:
65
+ credit_card = bool(request.credit_card)
66
+ if getattr(self._global_settings, "use_payment_terminal", False) and credit_card:
67
+ return True
68
+ if getattr(self._global_settings, "use_cashmatic", False) and not credit_card:
69
+ return True
70
+ if getattr(self._global_settings, "use_cashlogy", False) and not credit_card:
71
+ return True
72
+ return False
@@ -0,0 +1,52 @@
1
+ from typing import Any, Callable
2
+
3
+ from printer_core.algorithms.products_modifiers_unique_ticket import ProductsModifiersUniqueTicket
4
+ from printer_core.entities import ClientTicketData, ClientTicketPayload, PrintProductData, PrintRequestData, PrinterData
5
+ from printer_core.formatters.discount_formatter import DiscountFormatter
6
+
7
+
8
+ class UniqueTicketService:
9
+ def __init__(
10
+ self,
11
+ currency_symbol_resolver: Callable[[str], str],
12
+ domicile_service_label: str,
13
+ ):
14
+ self._currency_symbol_resolver = currency_symbol_resolver
15
+ self._domicile_service_label = domicile_service_label
16
+
17
+ def build_payload(
18
+ self,
19
+ request: PrintRequestData,
20
+ products: list[PrintProductData],
21
+ ticket_settings: Any,
22
+ printer: PrinterData,
23
+ tpv_key: str,
24
+ ) -> list[ClientTicketPayload]:
25
+ formatter = DiscountFormatter(currency_symbol_resolver=self._currency_symbol_resolver)
26
+ list_products_in_same_printers = ProductsModifiersUniqueTicket(
27
+ formatter, domicile_service_label=self._domicile_service_label
28
+ ).build(request, products)
29
+
30
+ ticket_text = getattr(ticket_settings, "ticket_text", "")
31
+ qty_client_ticket = getattr(ticket_settings, "qty_client_ticket", 1)
32
+
33
+ client_request = ClientTicketData(
34
+ **request.model_dump(exclude={"products", "ticket_text"}),
35
+ ticket_text=ticket_text,
36
+ products=list_products_in_same_printers,
37
+ )
38
+ if client_request.type in ["domicilio", "recoger"]:
39
+ client_request = client_request.model_copy(update={"details": client_request.details or ""})
40
+ elif client_request.details:
41
+ client_request = client_request.model_copy(update={"details": None})
42
+
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.printer_width,
51
+ )
52
+ return [payload]
File without changes
File without changes
@@ -0,0 +1,188 @@
1
+ from __future__ import annotations
2
+
3
+ from types import SimpleNamespace
4
+
5
+ from printer_core.entities import (
6
+ DiscountData,
7
+ FamilyData,
8
+ HeaderData,
9
+ PrintProductData,
10
+ PrintRequestData,
11
+ PrintSettingsData,
12
+ PrinterData,
13
+ )
14
+
15
+
16
+ class FakeGateway:
17
+ def __init__(self):
18
+ self.calls: list[tuple[str, object]] = []
19
+
20
+ def send_data(self, tpv_key: str, data: object) -> None:
21
+ self.calls.append((tpv_key, data))
22
+
23
+
24
+ class FakeClock:
25
+ def __init__(self, now_value: str = "2024-01-01 10:00"):
26
+ self._now_value = now_value
27
+
28
+ def now_iso(self) -> str:
29
+ return self._now_value
30
+
31
+
32
+ class FakeHeaderProvider:
33
+ def build_header(self, request: PrintRequestData, worker: object | None = None) -> HeaderData:
34
+ worker_name = getattr(worker, "first_name", None) if worker else None
35
+ return HeaderData(
36
+ company_name="Company",
37
+ worker_name=worker_name,
38
+ client_name=f"{request.type}:{request.from_client}",
39
+ )
40
+
41
+
42
+ class FakePrintSettingsBuilder:
43
+ def __init__(self, settings: PrintSettingsData | None = None):
44
+ self._settings = settings or PrintSettingsData(
45
+ show_header=True,
46
+ show_total_price=True,
47
+ show_price_per_unit=False,
48
+ show_local_header=None,
49
+ details_font={"size": 10},
50
+ )
51
+
52
+ def build(self, kitchen_ticket_settings: object) -> PrintSettingsData:
53
+ return self._settings
54
+
55
+
56
+ class FakeFamilyProvider:
57
+ def __init__(self, families: list[FamilyData], family_by_category: dict[int, FamilyData]):
58
+ self._families = families
59
+ self._family_by_category = family_by_category
60
+
61
+ def get_families(self) -> list[FamilyData]:
62
+ return self._families
63
+
64
+ def get_family_by_category_ids(self, category_ids: list[int]) -> dict[int, FamilyData]:
65
+ return {cid: self._family_by_category[cid] for cid in category_ids if cid in self._family_by_category}
66
+
67
+
68
+ def make_discount(value: str = "10", discount_type: str = "percent", total: str = "0") -> DiscountData:
69
+ return DiscountData(value=value, type=discount_type, total=total)
70
+
71
+
72
+ def make_request(
73
+ request_type: str = "local",
74
+ from_client: str = "web",
75
+ credit_card: bool = False,
76
+ request_price: str = "10.00",
77
+ currency: str | None = "EUR",
78
+ all_discounted: bool = False,
79
+ discount: DiscountData | None = None,
80
+ price_domicile_service: str | None = None,
81
+ **overrides: object,
82
+ ) -> PrintRequestData:
83
+ payload = {
84
+ "id": 1,
85
+ "type": request_type,
86
+ "serial": "S1",
87
+ "credit_card": credit_card,
88
+ "request_price": request_price,
89
+ "from_client": from_client,
90
+ "currency": currency,
91
+ "all_discounted": all_discounted,
92
+ "discount": discount,
93
+ "price_domicile_service": price_domicile_service,
94
+ "command_guests": 2,
95
+ "table_name": "T1",
96
+ }
97
+ payload.update(overrides)
98
+ return PrintRequestData(**payload)
99
+
100
+
101
+ def make_product(
102
+ name: str = "Burger",
103
+ qty: int = 1,
104
+ total_price: str = "5.00",
105
+ product_price: str = "5.00",
106
+ **overrides: object,
107
+ ) -> PrintProductData:
108
+ payload = {
109
+ "product_name": name,
110
+ "qty": qty,
111
+ "total_price": total_price,
112
+ "product_price": product_price,
113
+ }
114
+ payload.update(overrides)
115
+ return PrintProductData(**payload)
116
+
117
+
118
+ def make_printer(name: str = "P1", printer_width: str = "80", tpv: str | None = "TPV1") -> PrinterData:
119
+ return PrinterData(name=name, printer_width=printer_width, tpv=tpv)
120
+
121
+
122
+ def make_print_settings(
123
+ show_header: bool | None = True,
124
+ show_total_price: bool | None = True,
125
+ show_price_per_unit: bool | None = False,
126
+ show_local_header: bool | None = None,
127
+ details_font: dict[str, object] | str | None = None,
128
+ ) -> PrintSettingsData:
129
+ return PrintSettingsData(
130
+ show_header=show_header,
131
+ show_total_price=show_total_price,
132
+ show_price_per_unit=show_price_per_unit,
133
+ show_local_header=show_local_header,
134
+ details_font=details_font,
135
+ )
136
+
137
+
138
+ def make_ticket_settings(
139
+ order_by: str | None = None,
140
+ qty_kitchen_ticket: int = 1,
141
+ qty_client_ticket: int = 1,
142
+ ticket_text: str = "",
143
+ **overrides: object,
144
+ ) -> SimpleNamespace:
145
+ payload = {
146
+ "order_by": order_by,
147
+ "qty_kitchen_ticket": qty_kitchen_ticket,
148
+ "qty_client_ticket": qty_client_ticket,
149
+ "ticket_text": ticket_text,
150
+ }
151
+ payload.update(overrides)
152
+ return SimpleNamespace(**payload)
153
+
154
+
155
+ def make_kitchen_settings(
156
+ group_by_orders: bool = False,
157
+ print_by: str = "categories",
158
+ show_total_price: bool = False,
159
+ show_command_guests: bool = False,
160
+ show_price_per_unit: bool = False,
161
+ show_local_header: bool = True,
162
+ show_domicile_header: bool = True,
163
+ ) -> SimpleNamespace:
164
+ return SimpleNamespace(
165
+ group_by_orders=group_by_orders,
166
+ print_by=print_by,
167
+ show_total_price=show_total_price,
168
+ show_command_guests=show_command_guests,
169
+ show_price_per_unit=show_price_per_unit,
170
+ show_local_header=show_local_header,
171
+ show_domicile_header=show_domicile_header,
172
+ )
173
+
174
+
175
+ def make_global_settings(
176
+ currency: str | None = "EUR",
177
+ iva: int = 21,
178
+ use_payment_terminal: bool = False,
179
+ use_cashmatic: bool = False,
180
+ use_cashlogy: bool = False,
181
+ ) -> SimpleNamespace:
182
+ return SimpleNamespace(
183
+ currency=currency,
184
+ iva=iva,
185
+ use_payment_terminal=use_payment_terminal,
186
+ use_cashmatic=use_cashmatic,
187
+ use_cashlogy=use_cashlogy,
188
+ )