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.
- printer_core/__init__.py +1 -0
- printer_core/algorithms/__init__.py +3 -0
- printer_core/algorithms/products_modifiers_multiprinter.py +59 -0
- printer_core/algorithms/products_modifiers_multiprinter_family.py +53 -0
- printer_core/algorithms/products_modifiers_unique_ticket.py +30 -0
- printer_core/builders/__init__.py +4 -0
- printer_core/builders/client_ticket_builder.py +97 -0
- printer_core/builders/header_builder.py +26 -0
- printer_core/builders/kitchen_ticket_payload_builder.py +99 -0
- printer_core/builders/printer_products_grouper.py +19 -0
- printer_core/clock.py +6 -0
- printer_core/context/__init__.py +1 -0
- printer_core/context/ticket_context_builder.py +55 -0
- printer_core/dispatchers/__init__.py +2 -0
- printer_core/dispatchers/kitchen_ticket_dispatcher.py +34 -0
- printer_core/dispatchers/payload_dispatcher.py +18 -0
- printer_core/entities/__init__.py +53 -0
- printer_core/entities/print_context.py +15 -0
- printer_core/entities/print_models.py +230 -0
- printer_core/formatters/__init__.py +1 -0
- printer_core/formatters/discount_formatter.py +17 -0
- printer_core/ports.py +45 -0
- printer_core/selectors/__init__.py +1 -0
- printer_core/selectors/family_product_selector.py +33 -0
- printer_core/services/__init__.py +12 -0
- printer_core/services/flows/__init__.py +5 -0
- printer_core/services/flows/base.py +26 -0
- printer_core/services/flows/client.py +97 -0
- printer_core/services/flows/kitchen.py +113 -0
- printer_core/services/march_printer_service.py +61 -0
- printer_core/services/multi_printer_family_service.py +102 -0
- printer_core/services/multi_printer_service.py +49 -0
- printer_core/services/order_print_service.py +98 -0
- printer_core/services/print_policy.py +72 -0
- printer_core/services/unique_ticket_service.py +52 -0
- printer_core/tests/__init__.py +0 -0
- printer_core/tests/unitaries/__init__.py +0 -0
- printer_core/tests/unitaries/helpers.py +188 -0
- printer_core/tests/unitaries/test_cases_output.py +189 -0
- printer_core/tests/unitaries/test_client_ticket_builder.py +78 -0
- printer_core/tests/unitaries/test_discount_formatter.py +37 -0
- printer_core/tests/unitaries/test_family_product_selector.py +28 -0
- printer_core/tests/unitaries/test_flows.py +141 -0
- printer_core/tests/unitaries/test_header_builder_foodeo_printers.py +87 -0
- printer_core/tests/unitaries/test_kitchen_ticket_dispatcher.py +61 -0
- printer_core/tests/unitaries/test_kitchen_ticket_payload_builder.py +113 -0
- printer_core/tests/unitaries/test_march_printer_service.py +31 -0
- printer_core/tests/unitaries/test_multi_printer_family_service.py +53 -0
- printer_core/tests/unitaries/test_multi_printer_service.py +51 -0
- printer_core/tests/unitaries/test_order_print_service.py +144 -0
- printer_core/tests/unitaries/test_payload_dispatcher.py +61 -0
- printer_core/tests/unitaries/test_print_policy.py +45 -0
- printer_core/tests/unitaries/test_printer_helpers.py +71 -0
- printer_core/tests/unitaries/test_printer_products_grouper.py +20 -0
- printer_core/tests/unitaries/test_products_modifiers.py +102 -0
- printer_core/tests/unitaries/test_ticket_context_builder.py +71 -0
- printer_core/tests/unitaries/test_unique_ticket_service.py +24 -0
- printer_core/utils/__init__.py +1 -0
- printer_core/utils/printer_helpers.py +42 -0
- printer_core-0.0.1.dist-info/METADATA +24 -0
- printer_core-0.0.1.dist-info/RECORD +62 -0
- 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,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
|