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,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
|
+
)
|