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,230 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+
8
+
9
+ class PrintChannel(str, Enum):
10
+ KIOSKO = "kiosko"
11
+ BARRA = "barra"
12
+ LOCAL = "local"
13
+ DOMICILE = "domicilio"
14
+ PICKUP = "recoger"
15
+
16
+
17
+ class CompanyHeaderData(BaseModel):
18
+ company_name: str | None = None
19
+ company_reason: str | None = None
20
+ company_dni: str | None = None
21
+ company_phone: str | None = None
22
+ company_address: str | None = None
23
+
24
+
25
+ class WorkerData(BaseModel):
26
+ first_name: str | None = None
27
+
28
+
29
+ class DiscountData(BaseModel):
30
+ model_config = ConfigDict(extra="allow")
31
+
32
+ value: str | None = None
33
+ type: str | None = None
34
+ total: str | None = None
35
+
36
+
37
+ class HeaderData(BaseModel):
38
+ model_config = ConfigDict(extra="allow")
39
+
40
+ company_name: str | None = None
41
+ company_reason: str | None = None
42
+ company_dni: str | None = None
43
+ company_phone: str | None = None
44
+ company_address: str | None = None
45
+ worker_name: str | None = None
46
+ client_name: str | None = None
47
+ client_phone: str | None = None
48
+ client_address: str | None = None
49
+
50
+
51
+ class PrintSettingsData(BaseModel):
52
+ model_config = ConfigDict(extra="allow")
53
+
54
+ show_header: bool | None = None
55
+ show_total_price: bool | None = None
56
+ show_price_per_unit: bool | None = None
57
+ show_local_header: bool | None = None
58
+ details_font: dict[str, Any] | str | None = None
59
+
60
+
61
+ class IvaData(BaseModel):
62
+ Base: str
63
+ impo: str
64
+ iva: str
65
+
66
+
67
+ class FiskalyData(BaseModel):
68
+ model_config = ConfigDict(extra="allow")
69
+
70
+
71
+ class PrinterData(BaseModel):
72
+ name: str
73
+ printer_width: str
74
+ tpv: str | None = None
75
+
76
+
77
+ class PrintProductData(BaseModel):
78
+ model_config = ConfigDict(extra="allow")
79
+
80
+ product_name: str
81
+ qty: int
82
+ option: Any = None
83
+ total_price: Any
84
+ product_price: Any
85
+ discount_type: str | None = None
86
+ discount: DiscountData | None = None
87
+ importe: Any | None = None
88
+ details: str | None = None
89
+ order: str | None = None
90
+ order_readable: str | None = None
91
+ printer: list[PrinterData] = Field(default_factory=list)
92
+ category: int | None = None
93
+
94
+
95
+ class ClientTicketProduct(BaseModel):
96
+ name: str
97
+ qty: int
98
+ option: Any | None = None
99
+ price: str | None = None
100
+ unitary_price: str | None = None
101
+
102
+
103
+ class KitchenProductLine(BaseModel):
104
+ name: str
105
+ qty: int
106
+ option: Any | None = None
107
+ printer_r: str
108
+ printer_w: str
109
+ details: str | None = None
110
+ order: str | None = None
111
+ tpv: str | None = None
112
+ order_readable: str | None = None
113
+ price: Any | None = None
114
+ unitary_price: Any | None = None
115
+
116
+
117
+ class ProductsGroup(BaseModel):
118
+ group: str
119
+ products: list[KitchenProductLine]
120
+
121
+
122
+ class PrinterProductGroup(BaseModel):
123
+ printer_name: str
124
+ tpv_key: str
125
+ printer_width: str
126
+ products: list[KitchenProductLine]
127
+
128
+
129
+ class KitchenTicketData(BaseModel):
130
+ id: int | None = None
131
+ table_name: str | None = None
132
+ credit_card: bool
133
+ serial: str
134
+ details: str | None = None
135
+ type: str
136
+ discount: DiscountData | None = None
137
+ created_at: str | None = None
138
+ total: str | None = None
139
+ request_price: Any | None = None
140
+ command_guests: int | None = None
141
+ headerData: HeaderData | None = None
142
+ products: list[KitchenProductLine] | None = None
143
+ products_groups: list[ProductsGroup] | None = None
144
+
145
+
146
+ class PrintRequestData(BaseModel):
147
+ model_config = ConfigDict(extra="allow")
148
+
149
+ id: int
150
+ type: str
151
+ serial: str
152
+ credit_card: bool
153
+ request_price: Any
154
+ details: str | None = None
155
+ from_client: str | None = None
156
+ client: int | None = None
157
+ address: int | None = None
158
+ shift_time: str | None = None
159
+ delivery_date: str | None = None
160
+ created_at: str | None = None
161
+ print_by: str | None = None
162
+ order_by: str | None = None
163
+ group_by_orders: bool | None = None
164
+ all_discounted: bool | None = None
165
+ discount: DiscountData | None = None
166
+ command_guests: int | None = None
167
+ table_name: str | None = None
168
+ qr: str | None = None
169
+ currency: str | None = None
170
+ total: str | None = None
171
+ ivaData: IvaData | None = None
172
+ PrintSettings: PrintSettingsData | None = None
173
+ headerData: HeaderData | None = None
174
+ is_invoice: bool | None = None
175
+ ticket_text: str | None = None
176
+ payed_with: str | None = None
177
+ fiskalyData: FiskalyData | None = None
178
+ price_domicile_service: Any | None = None
179
+
180
+
181
+ class ClientTicketData(PrintRequestData):
182
+ products: list[ClientTicketProduct] | None = None
183
+
184
+
185
+ class PrintJob(BaseModel):
186
+ request: PrintRequestData
187
+ products: list[PrintProductData]
188
+ tpv_key: str
189
+
190
+
191
+ class ClientTicketPayload(BaseModel):
192
+ data: ClientTicketData
193
+ currency: str
194
+ model: int
195
+ company_key: str | None
196
+ printer: str
197
+ printer_qty: int
198
+ printer_width: Any
199
+
200
+
201
+ class KitchenTicketPayload(BaseModel):
202
+ data: KitchenTicketData
203
+ currency: str
204
+ model: int
205
+ company_key: str | None = None
206
+ printer: str
207
+ printer_qty: int
208
+ printer_width: Any
209
+ PrintSettings: PrintSettingsData | None = None
210
+
211
+
212
+ class MarchCommandData(BaseModel):
213
+ table_name: str | None = None
214
+ credit_card: bool | None = None
215
+ serial: str | None = None
216
+ type: str | None = None
217
+
218
+
219
+ class FamilyData(BaseModel):
220
+ model_config = ConfigDict(extra="allow")
221
+
222
+ id: int
223
+ name: str | None = None
224
+
225
+
226
+ class PrintResult(BaseModel):
227
+ model_config = ConfigDict(extra="forbid")
228
+
229
+ multi_printer: list[KitchenTicketPayload] | bool | None = None
230
+ ticket_client: list[ClientTicketPayload] | None = None
@@ -0,0 +1 @@
1
+ from .discount_formatter import DiscountFormatter
@@ -0,0 +1,17 @@
1
+ from decimal import Decimal
2
+ from typing import Callable
3
+
4
+ from printer_core.entities import PrintProductData
5
+
6
+ class DiscountFormatter:
7
+ def __init__(self, currency_symbol_resolver: Callable[[str], str] | None = None):
8
+ self._currency_symbol_resolver = currency_symbol_resolver or (lambda _: "")
9
+
10
+ def format(self, product: PrintProductData, currency_code: str) -> str:
11
+ currency_symbol = self._currency_symbol_resolver(currency_code)
12
+ if product.discount_type == "number":
13
+ return f" (Dto {product.total_price}{currency_symbol})"
14
+ if product.discount_type == "percent" and product.discount:
15
+ total = Decimal(str(product.importe)) - Decimal(str(product.total_price))
16
+ return f" (Dto {product.discount.value}% {total}{currency_symbol})"
17
+ return ""
printer_core/ports.py ADDED
@@ -0,0 +1,45 @@
1
+ from typing import Any, Protocol
2
+
3
+ from printer_core.entities import FamilyData, HeaderData, PrintRequestData, PrintSettingsData
4
+
5
+
6
+ class PrinterGateway(Protocol):
7
+ def send_data(self, tpv_key: str, data: Any) -> None:
8
+ ...
9
+
10
+
11
+ class Clock(Protocol):
12
+ def now_iso(self) -> str:
13
+ ...
14
+
15
+
16
+ class HeaderProvider(Protocol):
17
+ def build_header(self, request: PrintRequestData, worker: Any | None = None) -> HeaderData:
18
+ ...
19
+
20
+
21
+ class HeaderDataProvider(Protocol):
22
+ def get_company_header(self) -> dict[str, str]:
23
+ ...
24
+
25
+ def get_worker_header(self, user: Any) -> dict[str, str]:
26
+ ...
27
+
28
+ def get_pickup_client_header(self, client_id: int | None, from_client: str | None) -> dict[str, str]:
29
+ ...
30
+
31
+ def get_domicile_client_header(self, address_id: int | None, from_client: str | None) -> dict[str, str]:
32
+ ...
33
+
34
+
35
+ class PrintSettingsBuilder(Protocol):
36
+ def build(self, kitchen_ticket_settings: Any) -> PrintSettingsData:
37
+ ...
38
+
39
+
40
+ class FamilyCategoryProvider(Protocol):
41
+ def get_families(self) -> list[FamilyData]:
42
+ ...
43
+
44
+ def get_family_by_category_ids(self, category_ids: list[int]) -> dict[int, FamilyData]:
45
+ ...
@@ -0,0 +1 @@
1
+ from .family_product_selector import FamilyProductSelector
@@ -0,0 +1,33 @@
1
+ from collections import defaultdict
2
+
3
+ from printer_core.entities import FamilyData, PrintProductData
4
+ from printer_core.ports import FamilyCategoryProvider
5
+
6
+
7
+ class FamilyProductSelector:
8
+ def __init__(self, provider: FamilyCategoryProvider):
9
+ self._provider = provider
10
+
11
+ def group_products(self, products: list[PrintProductData]) -> tuple[
12
+ list[FamilyData], dict[int, list[PrintProductData]], list[PrintProductData]
13
+ ]:
14
+ category_ids = [product.category for product in products if product.category]
15
+ category_ids = [category_id for category_id in category_ids if category_id]
16
+ families = self._provider.get_families()
17
+ family_by_category = self._provider.get_family_by_category_ids(category_ids)
18
+
19
+ products_by_family: dict[int, list[PrintProductData]] = defaultdict(list)
20
+ products_without_family: list[PrintProductData] = []
21
+
22
+ for product in products:
23
+ category_id = product.category
24
+ if not category_id or category_id not in family_by_category:
25
+ products_without_family.append(product)
26
+ continue
27
+ family = family_by_category.get(category_id)
28
+ if not family:
29
+ products_without_family.append(product)
30
+ continue
31
+ products_by_family[family.id].append(product)
32
+
33
+ return families, products_by_family, products_without_family
@@ -0,0 +1,12 @@
1
+ from printer_core.dispatchers.kitchen_ticket_dispatcher import KitchenTicketDispatcher
2
+ from printer_core.context.ticket_context_builder import TicketContextBuilder
3
+ from printer_core.selectors.family_product_selector import FamilyProductSelector
4
+ from printer_core.builders.client_ticket_builder import ClientTicketBuilder
5
+ from printer_core.dispatchers.payload_dispatcher import PayloadDispatcher
6
+ from printer_core.services.flows import ClientPrintFlow, KitchenPrintFlow, PrintFlow
7
+ from printer_core.services.print_policy import FlowTarget, PrintPlan, PrintPolicy
8
+ from .march_printer_service import MarchPrinterService
9
+ from .multi_printer_service import MultiPrinterService
10
+ from .multi_printer_family_service import MultiPrinterFamilyService
11
+ from .order_print_service import OrderPrintService
12
+ from .unique_ticket_service import UniqueTicketService
@@ -0,0 +1,5 @@
1
+ from printer_core.services.flows.base import PrintFlow
2
+ from printer_core.services.flows.client import ClientPrintFlow
3
+ from printer_core.services.flows.kitchen import KitchenPrintFlow
4
+
5
+ __all__ = ["PrintFlow", "ClientPrintFlow", "KitchenPrintFlow"]
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Protocol
4
+
5
+ from printer_core.entities import (
6
+ ClientTicketPayload,
7
+ KitchenTicketPayload,
8
+ PrintChannel,
9
+ PrintProductData,
10
+ PrintRequestData,
11
+ )
12
+ from printer_core.services.print_policy import FlowTarget
13
+
14
+
15
+ class PrintFlow(Protocol):
16
+ target: FlowTarget
17
+
18
+ def execute(
19
+ self,
20
+ base_request: PrintRequestData,
21
+ products: list[PrintProductData],
22
+ context: Any,
23
+ channel: PrintChannel,
24
+ tpv_key: str | None = None,
25
+ ) -> list[KitchenTicketPayload] | list[ClientTicketPayload]:
26
+ ...
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable
4
+
5
+ from printer_core.builders.client_ticket_builder import ClientTicketBuilder
6
+ from printer_core.context.ticket_context_builder import TicketContextBuilder
7
+ from printer_core.entities import (
8
+ ClientTicketPayload,
9
+ PrintChannel,
10
+ PrintProductData,
11
+ PrintRequestData,
12
+ PrinterData,
13
+ )
14
+ from printer_core.ports import HeaderProvider, PrinterGateway, PrintSettingsBuilder
15
+ from printer_core.services.print_policy import FlowTarget
16
+
17
+
18
+ class ClientPrintFlow:
19
+ target = FlowTarget.CLIENT
20
+
21
+ def __init__(
22
+ self,
23
+ gateway: PrinterGateway,
24
+ header_provider: HeaderProvider,
25
+ print_settings_builder: PrintSettingsBuilder,
26
+ currency_symbol_resolver: Callable[[str], str],
27
+ domicile_service_label: str,
28
+ ):
29
+ self._gateway = gateway
30
+ self._currency_symbol_resolver = currency_symbol_resolver
31
+ self._domicile_service_label = domicile_service_label
32
+ self._context_builder = TicketContextBuilder(
33
+ header_provider=header_provider,
34
+ print_settings_builder=print_settings_builder,
35
+ )
36
+
37
+ def execute(
38
+ self,
39
+ base_request: PrintRequestData,
40
+ products: list[PrintProductData],
41
+ context: Any,
42
+ channel: PrintChannel,
43
+ tpv_key: str,
44
+ ) -> list[ClientTicketPayload]:
45
+ if not tpv_key:
46
+ raise ValueError("tpv_key is required for client printing")
47
+ client_request = self._context_builder.apply_client_context(
48
+ base_request,
49
+ context.kitchen_settings,
50
+ include_header=True,
51
+ details_font_none=True,
52
+ worker=context.worker,
53
+ )
54
+ client_request = self._apply_client_request_overrides(client_request, channel)
55
+ client_request = client_request.model_copy(update={"is_invoice": False})
56
+ data = self._build_client_ticket(
57
+ client_request,
58
+ products,
59
+ context.ticket_settings,
60
+ context.main_printer,
61
+ tpv_key,
62
+ )
63
+ payload = [item.model_dump(mode="json", exclude_none=True) for item in data]
64
+ self._gateway.send_data(tpv_key, payload)
65
+ return data
66
+
67
+ def _build_client_ticket(
68
+ self,
69
+ request: PrintRequestData,
70
+ products: list[PrintProductData],
71
+ ticket_settings: Any,
72
+ main_printer: PrinterData,
73
+ tpv_key: str,
74
+ ) -> list[ClientTicketPayload]:
75
+ ticket_builder = ClientTicketBuilder(
76
+ currency_symbol_resolver=self._currency_symbol_resolver,
77
+ domicile_service_label=self._domicile_service_label,
78
+ )
79
+ return ticket_builder.build(
80
+ request=request,
81
+ products=products,
82
+ printer=main_printer,
83
+ ticket_settings=ticket_settings,
84
+ tpv_key=tpv_key,
85
+ )
86
+
87
+ def _apply_client_request_overrides(
88
+ self,
89
+ request: PrintRequestData,
90
+ channel: PrintChannel,
91
+ ) -> PrintRequestData:
92
+ if channel != PrintChannel.LOCAL:
93
+ return request
94
+ print_settings = request.PrintSettings
95
+ if not print_settings:
96
+ return request
97
+ return request.model_copy(update={"PrintSettings": print_settings.model_copy(update={"show_header": False})})
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable
4
+
5
+ from printer_core.context.ticket_context_builder import TicketContextBuilder
6
+ from printer_core.entities import (
7
+ KitchenProductLine,
8
+ KitchenTicketPayload,
9
+ PrintChannel,
10
+ PrintProductData,
11
+ PrintRequestData,
12
+ PrinterData,
13
+ ProductsGroup,
14
+ )
15
+ from printer_core.ports import FamilyCategoryProvider, HeaderProvider, PrinterGateway, PrintSettingsBuilder
16
+ from printer_core.services.multi_printer_family_service import MultiPrinterFamilyService
17
+ from printer_core.services.multi_printer_service import MultiPrinterService
18
+ from printer_core.services.print_policy import FlowTarget
19
+
20
+
21
+ class KitchenPrintFlow:
22
+ target = FlowTarget.KITCHEN
23
+
24
+ def __init__(
25
+ self,
26
+ gateway: PrinterGateway,
27
+ header_provider: HeaderProvider,
28
+ print_settings_builder: PrintSettingsBuilder,
29
+ family_provider: FamilyCategoryProvider,
30
+ currency_symbol_resolver: Callable[[str], str],
31
+ ):
32
+ self._gateway = gateway
33
+ self._family_provider = family_provider
34
+ self._currency_symbol_resolver = currency_symbol_resolver
35
+ self._context_builder = TicketContextBuilder(
36
+ header_provider=header_provider,
37
+ print_settings_builder=print_settings_builder,
38
+ )
39
+
40
+ def execute(
41
+ self,
42
+ base_request: PrintRequestData,
43
+ products: list[PrintProductData],
44
+ context: Any,
45
+ channel: PrintChannel,
46
+ tpv_key: str | None = None,
47
+ ) -> list[KitchenTicketPayload]:
48
+ kitchen_request = self._context_builder.apply_kitchen_context(
49
+ base_request,
50
+ context.ticket_settings,
51
+ context.kitchen_settings,
52
+ header_mode=self._header_mode(channel),
53
+ include_print_by=self._include_print_by(channel),
54
+ worker=context.worker,
55
+ )
56
+ return self._dispatch_kitchen(
57
+ request=kitchen_request,
58
+ products=products,
59
+ ticket_settings=context.ticket_settings,
60
+ kitchen_settings=context.kitchen_settings,
61
+ main_printer=context.main_printer,
62
+ )
63
+
64
+ def _dispatch_kitchen(
65
+ self,
66
+ request: PrintRequestData,
67
+ products: list[PrintProductData],
68
+ ticket_settings: Any,
69
+ kitchen_settings: Any,
70
+ main_printer: PrinterData,
71
+ ) -> list[KitchenTicketPayload]:
72
+ if getattr(kitchen_settings, "print_by", "categories") == "categories":
73
+ service = MultiPrinterService(
74
+ gateway=self._gateway,
75
+ currency_symbol_resolver=self._currency_symbol_resolver,
76
+ order_by_func=self._noop_order_by,
77
+ group_products_func=self._noop_group_products,
78
+ )
79
+ return service.build_and_dispatch(
80
+ request=request,
81
+ products=products,
82
+ main_printer=main_printer,
83
+ ticket_settings=ticket_settings,
84
+ kitchen_ticket_settings=kitchen_settings,
85
+ )
86
+ service = MultiPrinterFamilyService(
87
+ gateway=self._gateway,
88
+ family_provider=self._family_provider,
89
+ currency_symbol_resolver=self._currency_symbol_resolver,
90
+ order_by_func=self._noop_order_by,
91
+ group_products_func=self._noop_group_products,
92
+ )
93
+ return service.build_and_dispatch(
94
+ request=request,
95
+ products=products,
96
+ main_printer=main_printer,
97
+ ticket_settings=ticket_settings,
98
+ kitchen_ticket_settings=kitchen_settings,
99
+ )
100
+
101
+ def _header_mode(self, channel: PrintChannel) -> str:
102
+ if channel in (PrintChannel.DOMICILE, PrintChannel.PICKUP):
103
+ return "domicile"
104
+ return "local"
105
+
106
+ def _include_print_by(self, channel: PrintChannel) -> bool:
107
+ return channel not in (PrintChannel.BARRA, PrintChannel.KIOSKO)
108
+
109
+ def _noop_order_by(self, products: list[KitchenProductLine]) -> list[KitchenProductLine]:
110
+ return products
111
+
112
+ def _noop_group_products(self, products: list[KitchenProductLine]) -> list[ProductsGroup]:
113
+ return [ProductsGroup(group="Sin orden", products=products)]
@@ -0,0 +1,61 @@
1
+ from printer_core.clock import SystemClock
2
+ from printer_core.entities import KitchenProductLine, KitchenTicketData, KitchenTicketPayload, MarchCommandData, PrinterData, PrintSettingsData
3
+ from printer_core.ports import Clock, PrinterGateway
4
+
5
+
6
+ class MarchPrinterService:
7
+ def __init__(self, gateway: PrinterGateway, clock: Clock | None = None):
8
+ self._gateway = gateway
9
+ self._clock = clock or SystemClock()
10
+
11
+ def build_and_send(self,
12
+ printers: list[PrinterData],
13
+ command_data: MarchCommandData,
14
+ order_type_text: str,
15
+ tpv_key: str,
16
+ currency: str,
17
+ print_settings: PrintSettingsData,
18
+ printer_qty: int = 1,
19
+ ) -> list[KitchenTicketPayload]:
20
+ final_request: list[KitchenTicketPayload] = []
21
+ for printer in printers:
22
+ products = [KitchenProductLine(
23
+ name=str(order_type_text),
24
+ qty=0,
25
+ option=[],
26
+ price=0,
27
+ printer_r=str(printer.name),
28
+ printer_w=printer.printer_width,
29
+ details="",
30
+ order=None,
31
+ tpv=str(tpv_key),
32
+ order_readable=None,
33
+ )]
34
+ data = KitchenTicketData(
35
+ table_name=str(command_data.table_name or ""),
36
+ credit_card=bool(command_data.credit_card),
37
+ serial=str(command_data.serial or ""),
38
+ created_at=self._clock.now_iso(),
39
+ request_price="0",
40
+ type=str(command_data.type or ""),
41
+ total="0",
42
+ discount=None,
43
+ products=products,
44
+ )
45
+ payload = KitchenTicketPayload(
46
+ data=data,
47
+ model=1,
48
+ printer_qty=printer_qty,
49
+ printer=str(printer.name),
50
+ printer_width=printer.printer_width,
51
+ currency=currency,
52
+ PrintSettings=print_settings.model_copy(update={
53
+ "show_header": True,
54
+ "show_total_price": False,
55
+ "show_price_per_unit": False,
56
+ }),
57
+ )
58
+
59
+ final_request.append(payload)
60
+ self._gateway.send_data(tpv_key, [payload.model_dump(mode="json", exclude_none=True)])
61
+ return final_request