printer-core 0.0.11__tar.gz → 0.0.12__tar.gz
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-0.0.11 → printer_core-0.0.12}/PKG-INFO +1 -1
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/algorithms/products_modifiers_multiprinter.py +8 -5
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/algorithms/products_modifiers_multiprinter_family.py +1 -1
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/client_ticket_builder.py +11 -11
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/entities/print_context.py +4 -3
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/entities/print_models.py +4 -3
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/flows/client.py +10 -7
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/flows/kitchen.py +20 -20
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/multi_printer_family_service.py +20 -9
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/multi_printer_service.py +3 -2
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_client_ticket_builder.py +40 -40
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_multi_printer_family_service.py +21 -3
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_order_print_service.py +104 -104
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_products_modifiers.py +14 -1
- {printer_core-0.0.11 → printer_core-0.0.12}/pyproject.toml +1 -1
- {printer_core-0.0.11 → printer_core-0.0.12}/.gitignore +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/README.md +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/algorithms/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/algorithms/products_modifiers_unique_ticket.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/header_builder.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/kitchen_ticket_payload_builder.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/printer_products_grouper.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/clock.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/context/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/context/ticket_context_builder.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/dispatchers/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/dispatchers/kitchen_ticket_dispatcher.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/dispatchers/payload_dispatcher.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/entities/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/formatters/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/formatters/discount_formatter.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/ports.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/selectors/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/selectors/family_product_selector.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/flows/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/flows/base.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/march_printer_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/order_print_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/print_policy.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/unique_ticket_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/helpers.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_cases_output.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_discount_formatter.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_family_product_selector.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_flows.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_header_builder_foodeo_printers.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_kitchen_ticket_dispatcher.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_kitchen_ticket_payload_builder.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_march_printer_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_multi_printer_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_payload_dispatcher.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_print_policy.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_printer_helpers.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_printer_products_grouper.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_ticket_context_builder.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_unique_ticket_service.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/utils/__init__.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/printer_core/utils/printer_helpers.py +0 -0
- {printer_core-0.0.11 → printer_core-0.0.12}/scripts/link_backend_env.sh +0 -0
|
@@ -13,14 +13,17 @@ class ProductsModifiersMultiPrinter:
|
|
|
13
13
|
request: PrintRequestData,
|
|
14
14
|
products: list[PrintProductData],
|
|
15
15
|
kitchen_ticket_settings: Any,
|
|
16
|
-
|
|
16
|
+
main_printer: PrinterData | dict[str, Any] | None,
|
|
17
17
|
) -> list[KitchenProductLine]:
|
|
18
18
|
list_products_own_printer: list[KitchenProductLine] = []
|
|
19
|
-
fallback_printer = self._resolve_printer(main_printer)
|
|
20
19
|
for product in products:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
if product.printer == []:
|
|
21
|
+
continue
|
|
22
|
+
printers = product.printer
|
|
23
|
+
if printers is None:
|
|
24
|
+
if main_printer is None:
|
|
25
|
+
raise ValueError("main_printer is required for unresolved kitchen products")
|
|
26
|
+
printers = [self._resolve_printer(main_printer)]
|
|
24
27
|
for actual_printer in printers:
|
|
25
28
|
printer_payload = self._resolve_printer(actual_printer)
|
|
26
29
|
name = product.product_name
|
|
@@ -14,7 +14,7 @@ class ProductsModifiersMultiprinterFamily:
|
|
|
14
14
|
request: PrintRequestData,
|
|
15
15
|
kitchen_ticket_settings: Any,
|
|
16
16
|
) -> None:
|
|
17
|
-
for actual_printer in product.printer:
|
|
17
|
+
for actual_printer in product.printer or []:
|
|
18
18
|
printer_payload = self._resolve_printer(actual_printer)
|
|
19
19
|
name_with_discount: str = product.product_name
|
|
20
20
|
if not request.all_discounted:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
from decimal import Decimal
|
|
2
3
|
from typing import Any, Callable
|
|
3
|
-
from datetime import datetime
|
|
4
4
|
|
|
5
5
|
from printer_core.clock import SystemClock
|
|
6
|
-
from printer_core.entities import (
|
|
7
|
-
ClientTicketData,
|
|
8
|
-
ClientTicketPayload,
|
|
9
|
-
ClientTicketProfile,
|
|
6
|
+
from printer_core.entities import (
|
|
7
|
+
ClientTicketData,
|
|
8
|
+
ClientTicketPayload,
|
|
9
|
+
ClientTicketProfile,
|
|
10
10
|
ClientTicketProduct,
|
|
11
11
|
PrintProductData,
|
|
12
12
|
PrintRequestData,
|
|
@@ -50,10 +50,10 @@ class ClientTicketBuilder:
|
|
|
50
50
|
client_request = client_request.model_copy(update={"created_at": self._resolve_created_at(request)})
|
|
51
51
|
|
|
52
52
|
printer_name, printer_width = self._resolve_printer(printer)
|
|
53
|
-
payload = ClientTicketPayload(
|
|
53
|
+
payload = ClientTicketPayload(
|
|
54
54
|
data=client_request,
|
|
55
55
|
currency=client_request.currency or "",
|
|
56
|
-
model=3 if request.client_profile == ClientTicketProfile.COMMAND else 2,
|
|
56
|
+
model=3 if request.client_profile == ClientTicketProfile.COMMAND else 2,
|
|
57
57
|
company_key=tpv_key,
|
|
58
58
|
printer=printer_name,
|
|
59
59
|
printer_qty=qty_client_ticket,
|
|
@@ -112,10 +112,10 @@ class ClientTicketBuilder:
|
|
|
112
112
|
return printer["name"], printer["printer_width"]
|
|
113
113
|
return printer.name, printer.printer_width
|
|
114
114
|
|
|
115
|
-
def _resolve_created_at(self, request: PrintRequestData) -> str:
|
|
116
|
-
if request.client_profile == ClientTicketProfile.COMMAND:
|
|
117
|
-
return request.created_at or self._clock.now_iso()
|
|
118
|
-
if request.type in ["domicilio", "recoger"] and request.shift_time and request.delivery_date:
|
|
115
|
+
def _resolve_created_at(self, request: PrintRequestData) -> str:
|
|
116
|
+
if request.client_profile == ClientTicketProfile.COMMAND:
|
|
117
|
+
return request.created_at or self._clock.now_iso()
|
|
118
|
+
if request.type in ["domicilio", "recoger"] and request.shift_time and request.delivery_date:
|
|
119
119
|
shift_time = datetime.strptime(request.shift_time, "%H:%M").time()
|
|
120
120
|
delivery_date = datetime.strptime(request.delivery_date, "%Y-%m-%d").date()
|
|
121
121
|
return datetime.combine(delivery_date, shift_time).strftime("%Y-%m-%d %H:%M")
|
|
@@ -7,9 +7,10 @@ from printer_core.entities.print_models import PrinterData, WorkerData
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@dataclass(frozen=True)
|
|
10
|
-
class PrintContext:
|
|
10
|
+
class PrintContext:
|
|
11
11
|
ticket_settings: Any
|
|
12
12
|
kitchen_settings: Any
|
|
13
13
|
global_settings: Any
|
|
14
|
-
main_printer: PrinterData
|
|
15
|
-
worker: WorkerData | None = None
|
|
14
|
+
main_printer: PrinterData | None
|
|
15
|
+
worker: WorkerData | None = None
|
|
16
|
+
client_printer: PrinterData | None = None
|
|
@@ -81,7 +81,7 @@ class PrinterData(BaseModel):
|
|
|
81
81
|
tpv: str | None = None
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
class PrintProductData(BaseModel):
|
|
84
|
+
class PrintProductData(BaseModel):
|
|
85
85
|
model_config = ConfigDict(extra="allow")
|
|
86
86
|
|
|
87
87
|
product_name: str
|
|
@@ -95,8 +95,9 @@ class PrintProductData(BaseModel):
|
|
|
95
95
|
details: str | None = None
|
|
96
96
|
order: str | None = None
|
|
97
97
|
order_readable: str | None = None
|
|
98
|
-
printer: list[PrinterData] =
|
|
99
|
-
category: int | None = None
|
|
98
|
+
printer: list[PrinterData] | None = None
|
|
99
|
+
category: int | None = None
|
|
100
|
+
request_item_id: int | None = Field(default=None, exclude=True)
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
class ClientTicketProduct(BaseModel):
|
|
@@ -63,13 +63,16 @@ class ClientPrintFlow:
|
|
|
63
63
|
"headerData": header_data,
|
|
64
64
|
})
|
|
65
65
|
client_request = self._apply_client_request_overrides(client_request, channel)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
client_printer = getattr(context, "client_printer", None) or context.main_printer
|
|
67
|
+
if client_printer is None:
|
|
68
|
+
raise ValueError("client_printer is required for client printing")
|
|
69
|
+
data = self._build_client_ticket(
|
|
70
|
+
client_request,
|
|
71
|
+
products,
|
|
72
|
+
context.ticket_settings,
|
|
73
|
+
client_printer,
|
|
74
|
+
tpv_key,
|
|
75
|
+
)
|
|
73
76
|
payload = [self._serialize_client_payload(item) for item in data]
|
|
74
77
|
self._gateway.send_data(tpv_key, payload)
|
|
75
78
|
return data
|
|
@@ -3,14 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any, Callable
|
|
4
4
|
|
|
5
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
|
-
)
|
|
6
|
+
from printer_core.entities import (
|
|
7
|
+
KitchenProductLine,
|
|
8
|
+
KitchenTicketPayload,
|
|
9
|
+
PrintChannel,
|
|
10
|
+
PrintProductData,
|
|
11
|
+
PrintRequestData,
|
|
12
|
+
PrinterData,
|
|
13
|
+
)
|
|
14
14
|
from printer_core.ports import FamilyCategoryProvider, HeaderProvider, PrinterGateway, PrintSettingsBuilder
|
|
15
15
|
from printer_core.services.multi_printer_family_service import MultiPrinterFamilyService
|
|
16
16
|
from printer_core.services.multi_printer_service import MultiPrinterService
|
|
@@ -66,14 +66,14 @@ class KitchenPrintFlow:
|
|
|
66
66
|
products: list[PrintProductData],
|
|
67
67
|
ticket_settings: Any,
|
|
68
68
|
kitchen_settings: Any,
|
|
69
|
-
|
|
69
|
+
main_printer: PrinterData | None,
|
|
70
70
|
) -> list[KitchenTicketPayload]:
|
|
71
71
|
if getattr(kitchen_settings, "print_by", "categories") == "categories":
|
|
72
|
-
service = MultiPrinterService(
|
|
73
|
-
gateway=self._gateway,
|
|
74
|
-
currency_symbol_resolver=self._currency_symbol_resolver,
|
|
75
|
-
order_by_func=self._noop_order_by,
|
|
76
|
-
)
|
|
72
|
+
service = MultiPrinterService(
|
|
73
|
+
gateway=self._gateway,
|
|
74
|
+
currency_symbol_resolver=self._currency_symbol_resolver,
|
|
75
|
+
order_by_func=self._noop_order_by,
|
|
76
|
+
)
|
|
77
77
|
return service.build_and_dispatch(
|
|
78
78
|
request=request,
|
|
79
79
|
products=products,
|
|
@@ -83,10 +83,10 @@ class KitchenPrintFlow:
|
|
|
83
83
|
)
|
|
84
84
|
service = MultiPrinterFamilyService(
|
|
85
85
|
gateway=self._gateway,
|
|
86
|
-
family_provider=self._family_provider,
|
|
87
|
-
currency_symbol_resolver=self._currency_symbol_resolver,
|
|
88
|
-
order_by_func=self._noop_order_by,
|
|
89
|
-
)
|
|
86
|
+
family_provider=self._family_provider,
|
|
87
|
+
currency_symbol_resolver=self._currency_symbol_resolver,
|
|
88
|
+
order_by_func=self._noop_order_by,
|
|
89
|
+
)
|
|
90
90
|
return service.build_and_dispatch(
|
|
91
91
|
request=request,
|
|
92
92
|
products=products,
|
|
@@ -103,5 +103,5 @@ class KitchenPrintFlow:
|
|
|
103
103
|
def _include_print_by(self, channel: PrintChannel) -> bool:
|
|
104
104
|
return channel not in (PrintChannel.BARRA, PrintChannel.KIOSKO)
|
|
105
105
|
|
|
106
|
-
def _noop_order_by(self, products: list[KitchenProductLine]) -> list[KitchenProductLine]:
|
|
107
|
-
return products
|
|
106
|
+
def _noop_order_by(self, products: list[KitchenProductLine]) -> list[KitchenProductLine]:
|
|
107
|
+
return products
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/services/multi_printer_family_service.py
RENAMED
|
@@ -38,7 +38,7 @@ class MultiPrinterFamilyService:
|
|
|
38
38
|
self,
|
|
39
39
|
request: PrintRequestData,
|
|
40
40
|
products: list[PrintProductData],
|
|
41
|
-
|
|
41
|
+
main_printer: PrinterData | None,
|
|
42
42
|
ticket_settings: Any,
|
|
43
43
|
kitchen_ticket_settings: Any,
|
|
44
44
|
) -> list[KitchenTicketPayload]:
|
|
@@ -54,10 +54,9 @@ class MultiPrinterFamilyService:
|
|
|
54
54
|
list_products_own_printer.clear()
|
|
55
55
|
family_products = products_by_family.get(family.id, [])
|
|
56
56
|
for product in family_products:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
product_with_printer = product.model_copy(update={"printer": [main_printer]})
|
|
57
|
+
product_with_printer = self._resolve_product_route(product, main_printer)
|
|
58
|
+
if product_with_printer is None:
|
|
59
|
+
continue
|
|
61
60
|
family_builder.append_product(
|
|
62
61
|
list_products_own_printer, product_with_printer, request, kitchen_ticket_settings
|
|
63
62
|
)
|
|
@@ -67,10 +66,9 @@ class MultiPrinterFamilyService:
|
|
|
67
66
|
|
|
68
67
|
list_products_own_printer.clear()
|
|
69
68
|
for product in products_without_family:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
product_with_printer = product.model_copy(update={"printer": [main_printer]})
|
|
69
|
+
product_with_printer = self._resolve_product_route(product, main_printer)
|
|
70
|
+
if product_with_printer is None:
|
|
71
|
+
continue
|
|
74
72
|
family_builder.append_product(
|
|
75
73
|
list_products_own_printer, product_with_printer, request, kitchen_ticket_settings
|
|
76
74
|
)
|
|
@@ -80,6 +78,19 @@ class MultiPrinterFamilyService:
|
|
|
80
78
|
))
|
|
81
79
|
return dispatched
|
|
82
80
|
|
|
81
|
+
def _resolve_product_route(
|
|
82
|
+
self,
|
|
83
|
+
product: PrintProductData,
|
|
84
|
+
main_printer: PrinterData | None,
|
|
85
|
+
) -> PrintProductData | None:
|
|
86
|
+
if product.printer == []:
|
|
87
|
+
return None
|
|
88
|
+
if product.printer is not None:
|
|
89
|
+
return product
|
|
90
|
+
if main_printer is None:
|
|
91
|
+
raise ValueError("main_printer is required for unresolved kitchen products")
|
|
92
|
+
return product.model_copy(update={"printer": [main_printer]})
|
|
93
|
+
|
|
83
94
|
def _dispatch_products(
|
|
84
95
|
self,
|
|
85
96
|
list_products_own_printer: list[KitchenProductLine],
|
|
@@ -3,7 +3,8 @@ from typing import Any, Callable
|
|
|
3
3
|
from printer_core.algorithms.products_modifiers_multiprinter import ProductsModifiersMultiPrinter
|
|
4
4
|
from printer_core.builders.printer_products_grouper import PrinterProductsGrouper
|
|
5
5
|
from printer_core.dispatchers.kitchen_ticket_dispatcher import KitchenTicketDispatcher
|
|
6
|
-
from printer_core.entities import KitchenProductLine, KitchenTicketPayload, PrintProductData, PrintRequestData,
|
|
6
|
+
from printer_core.entities import KitchenProductLine, KitchenTicketPayload, PrintProductData, PrintRequestData, \
|
|
7
|
+
PrinterData, ProductsGroup
|
|
7
8
|
from printer_core.formatters.discount_formatter import DiscountFormatter
|
|
8
9
|
from printer_core.ports import PrinterGateway
|
|
9
10
|
from printer_core.utils.printer_helpers import group_products_by_orders, order_products_by_name
|
|
@@ -26,7 +27,7 @@ class MultiPrinterService:
|
|
|
26
27
|
self,
|
|
27
28
|
request: PrintRequestData,
|
|
28
29
|
products: list[PrintProductData],
|
|
29
|
-
|
|
30
|
+
main_printer: PrinterData | None,
|
|
30
31
|
ticket_settings: Any,
|
|
31
32
|
kitchen_ticket_settings: Any,
|
|
32
33
|
) -> list[KitchenTicketPayload]:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
|
-
from printer_core.builders.client_ticket_builder import ClientTicketBuilder
|
|
3
|
-
from printer_core.entities import ClientTicketProfile, DiscountData
|
|
4
2
|
|
|
3
|
+
from printer_core.builders.client_ticket_builder import ClientTicketBuilder
|
|
4
|
+
from printer_core.entities import ClientTicketProfile, DiscountData
|
|
5
5
|
from printer_core.tests.unitaries.helpers import make_printer, make_product, make_request, make_ticket_settings
|
|
6
6
|
|
|
7
7
|
|
|
@@ -109,7 +109,7 @@ class ClientTicketBuilderTest(unittest.TestCase):
|
|
|
109
109
|
|
|
110
110
|
self.assertEqual(len(payloads[0].data.products), 1)
|
|
111
111
|
|
|
112
|
-
def test_build_does_not_serialize_rectified_flag_when_request_is_rectified(self):
|
|
112
|
+
def test_build_does_not_serialize_rectified_flag_when_request_is_rectified(self):
|
|
113
113
|
builder = ClientTicketBuilder()
|
|
114
114
|
request = make_request(is_rectified=True)
|
|
115
115
|
products = [make_product()]
|
|
@@ -122,40 +122,40 @@ class ClientTicketBuilderTest(unittest.TestCase):
|
|
|
122
122
|
tpv_key="TPV1",
|
|
123
123
|
)
|
|
124
124
|
|
|
125
|
-
self.assertTrue(request.is_rectified)
|
|
126
|
-
self.assertNotIn("is_rectified", payloads[0].data.model_dump())
|
|
127
|
-
|
|
128
|
-
def test_command_profile_uses_model_three_and_preserves_created_at_and_discount(self):
|
|
129
|
-
builder = ClientTicketBuilder()
|
|
130
|
-
request = make_request(
|
|
131
|
-
request_type="local",
|
|
132
|
-
created_at="2026-07-30T14:25:00+00:00",
|
|
133
|
-
discount=DiscountData(value="10", type="%", total="2.00"),
|
|
134
|
-
client_profile=ClientTicketProfile.COMMAND,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
payload = builder.build(
|
|
138
|
-
request=request,
|
|
139
|
-
products=[make_product()],
|
|
140
|
-
printer=make_printer(),
|
|
141
|
-
ticket_settings=make_ticket_settings(),
|
|
142
|
-
tpv_key="TPV1",
|
|
143
|
-
)[0]
|
|
144
|
-
|
|
145
|
-
self.assertEqual(payload.model, 3)
|
|
146
|
-
self.assertEqual(payload.data.created_at, "2026-07-30T14:25:00+00:00")
|
|
147
|
-
self.assertEqual(payload.data.discount.total, "2.00")
|
|
148
|
-
|
|
149
|
-
def test_client_profile_is_not_serialized_in_request_or_payload(self):
|
|
150
|
-
request = make_request(client_profile=ClientTicketProfile.COMMAND)
|
|
151
|
-
|
|
152
|
-
self.assertNotIn("client_profile", request.model_dump())
|
|
153
|
-
|
|
154
|
-
payload = ClientTicketBuilder().build(
|
|
155
|
-
request=request,
|
|
156
|
-
products=[make_product()],
|
|
157
|
-
printer=make_printer(),
|
|
158
|
-
ticket_settings=make_ticket_settings(),
|
|
159
|
-
tpv_key="TPV1",
|
|
160
|
-
)[0]
|
|
161
|
-
self.assertNotIn("client_profile", payload.model_dump()["data"])
|
|
125
|
+
self.assertTrue(request.is_rectified)
|
|
126
|
+
self.assertNotIn("is_rectified", payloads[0].data.model_dump())
|
|
127
|
+
|
|
128
|
+
def test_command_profile_uses_model_three_and_preserves_created_at_and_discount(self):
|
|
129
|
+
builder = ClientTicketBuilder()
|
|
130
|
+
request = make_request(
|
|
131
|
+
request_type="local",
|
|
132
|
+
created_at="2026-07-30T14:25:00+00:00",
|
|
133
|
+
discount=DiscountData(value="10", type="%", total="2.00"),
|
|
134
|
+
client_profile=ClientTicketProfile.COMMAND,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
payload = builder.build(
|
|
138
|
+
request=request,
|
|
139
|
+
products=[make_product()],
|
|
140
|
+
printer=make_printer(),
|
|
141
|
+
ticket_settings=make_ticket_settings(),
|
|
142
|
+
tpv_key="TPV1",
|
|
143
|
+
)[0]
|
|
144
|
+
|
|
145
|
+
self.assertEqual(payload.model, 3)
|
|
146
|
+
self.assertEqual(payload.data.created_at, "2026-07-30T14:25:00+00:00")
|
|
147
|
+
self.assertEqual(payload.data.discount.total, "2.00")
|
|
148
|
+
|
|
149
|
+
def test_client_profile_is_not_serialized_in_request_or_payload(self):
|
|
150
|
+
request = make_request(client_profile=ClientTicketProfile.COMMAND)
|
|
151
|
+
|
|
152
|
+
self.assertNotIn("client_profile", request.model_dump())
|
|
153
|
+
|
|
154
|
+
payload = ClientTicketBuilder().build(
|
|
155
|
+
request=request,
|
|
156
|
+
products=[make_product()],
|
|
157
|
+
printer=make_printer(),
|
|
158
|
+
ticket_settings=make_ticket_settings(),
|
|
159
|
+
tpv_key="TPV1",
|
|
160
|
+
)[0]
|
|
161
|
+
self.assertNotIn("client_profile", payload.model_dump()["data"])
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import unittest
|
|
1
2
|
from unittest.mock import patch
|
|
2
3
|
|
|
3
|
-
import unittest
|
|
4
4
|
from printer_core.entities import FamilyData
|
|
5
5
|
from printer_core.services.multi_printer_family_service import MultiPrinterFamilyService
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
from printer_core.tests.unitaries.helpers import FakeFamilyProvider, make_kitchen_settings, make_printer, make_product, \
|
|
7
|
+
make_request, make_ticket_settings
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class MultiPrinterFamilyServiceTest(unittest.TestCase):
|
|
@@ -51,3 +51,21 @@ class MultiPrinterFamilyServiceTest(unittest.TestCase):
|
|
|
51
51
|
|
|
52
52
|
self.assertEqual(len(dispatch_calls), 3)
|
|
53
53
|
self.assertTrue(all(count >= 1 for count in dispatch_calls))
|
|
54
|
+
|
|
55
|
+
def test_explicit_empty_route_is_not_replaced_by_fallback(self):
|
|
56
|
+
provider = FakeFamilyProvider(families=[], family_by_category={})
|
|
57
|
+
service = MultiPrinterFamilyService(
|
|
58
|
+
gateway=object(),
|
|
59
|
+
family_provider=provider,
|
|
60
|
+
currency_symbol_resolver=lambda _: "",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
result = service.build_and_dispatch(
|
|
64
|
+
request=make_request(),
|
|
65
|
+
products=[make_product(printer=[])],
|
|
66
|
+
main_printer=make_printer(name="Main"),
|
|
67
|
+
ticket_settings=make_ticket_settings(),
|
|
68
|
+
kitchen_ticket_settings=make_kitchen_settings(show_price_per_unit=False),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
self.assertEqual(result, [])
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_order_print_service.py
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from printer_core.entities import ClientTicketProfile, PrintChannel, PrintJob
|
|
3
|
-
from printer_core.services.order_print_service import OrderPrintService
|
|
4
|
-
from printer_core.services.print_policy import FlowTarget, PrintPlan
|
|
1
|
+
import unittest
|
|
5
2
|
|
|
3
|
+
from printer_core.entities import ClientTicketProfile, PrintChannel, PrintJob
|
|
4
|
+
from printer_core.services.order_print_service import OrderPrintService
|
|
5
|
+
from printer_core.services.print_policy import FlowTarget, PrintPlan
|
|
6
6
|
from printer_core.tests.unitaries.helpers import (
|
|
7
7
|
FakeClock,
|
|
8
8
|
make_discount,
|
|
@@ -104,7 +104,7 @@ class OrderPrintServiceTest(unittest.TestCase):
|
|
|
104
104
|
enriched = kitchen_flow.calls[0]["base_request"]
|
|
105
105
|
self.assertEqual(enriched.created_at, "2024-05-01 08:00")
|
|
106
106
|
|
|
107
|
-
def test_print_job_skips_flows_when_disabled(self):
|
|
107
|
+
def test_print_job_skips_flows_when_disabled(self):
|
|
108
108
|
kitchen_flow = FakeFlow(FlowTarget.KITCHEN, return_value=[])
|
|
109
109
|
service = OrderPrintService(
|
|
110
110
|
flows=[kitchen_flow],
|
|
@@ -119,102 +119,102 @@ class OrderPrintServiceTest(unittest.TestCase):
|
|
|
119
119
|
|
|
120
120
|
result = service.print_job(job, context, PrintChannel.LOCAL)
|
|
121
121
|
|
|
122
|
-
self.assertEqual(kitchen_flow.calls, [])
|
|
123
|
-
self.assertIsNone(result.multi_printer)
|
|
124
|
-
self.assertIsNone(result.ticket_client)
|
|
125
|
-
|
|
126
|
-
def test_explicit_plan_runs_client_when_automatic_setting_is_disabled(self):
|
|
127
|
-
client_flow = FakeFlow(FlowTarget.CLIENT, return_value=[{"client": True}])
|
|
128
|
-
service = OrderPrintService(flows=[client_flow])
|
|
129
|
-
job = PrintJob(
|
|
130
|
-
request=make_request(request_type="local"),
|
|
131
|
-
products=[make_product()],
|
|
132
|
-
tpv_key="TPV1",
|
|
133
|
-
)
|
|
134
|
-
context = type("Ctx", (), {
|
|
135
|
-
"ticket_settings": make_ticket_settings(ticket_kitchen_local=False, ticket_client_local=False),
|
|
136
|
-
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
137
|
-
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
138
|
-
})()
|
|
139
|
-
|
|
140
|
-
result = service.print_job(
|
|
141
|
-
job,
|
|
142
|
-
context,
|
|
143
|
-
PrintChannel.LOCAL,
|
|
144
|
-
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
self.assertEqual(result.ticket_client, [{"client": True}])
|
|
148
|
-
self.assertEqual(len(client_flow.calls), 1)
|
|
149
|
-
|
|
150
|
-
def test_explicit_plan_rejects_target_without_configured_flow(self):
|
|
151
|
-
service = OrderPrintService(flows=[])
|
|
152
|
-
job = PrintJob(
|
|
153
|
-
request=make_request(request_type="local"),
|
|
154
|
-
products=[make_product()],
|
|
155
|
-
tpv_key="TPV1",
|
|
156
|
-
)
|
|
157
|
-
context = type("Ctx", (), {
|
|
158
|
-
"ticket_settings": make_ticket_settings(ticket_kitchen_local=False, ticket_client_local=False),
|
|
159
|
-
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
160
|
-
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
161
|
-
})()
|
|
162
|
-
|
|
163
|
-
with self.assertRaisesRegex(ValueError, "client"):
|
|
164
|
-
service.print_job(
|
|
165
|
-
job,
|
|
166
|
-
context,
|
|
167
|
-
PrintChannel.LOCAL,
|
|
168
|
-
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
def test_automatic_plan_ignores_enabled_flow_not_exposed_by_caller(self):
|
|
172
|
-
kitchen_flow = FakeFlow(FlowTarget.KITCHEN, return_value=[{"kitchen": True}])
|
|
173
|
-
service = OrderPrintService(flows=[kitchen_flow])
|
|
174
|
-
job = PrintJob(
|
|
175
|
-
request=make_request(request_type="barra"),
|
|
176
|
-
products=[make_product()],
|
|
177
|
-
tpv_key="TPV1",
|
|
178
|
-
)
|
|
179
|
-
context = type("Ctx", (), {
|
|
180
|
-
"ticket_settings": make_ticket_settings(
|
|
181
|
-
ticket_kitchen_barra=True,
|
|
182
|
-
ticket_client_barra=True,
|
|
183
|
-
),
|
|
184
|
-
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
185
|
-
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
186
|
-
})()
|
|
187
|
-
|
|
188
|
-
result = service.print_job(job, context, PrintChannel.BARRA)
|
|
189
|
-
|
|
190
|
-
self.assertEqual(result.multi_printer, [{"kitchen": True}])
|
|
191
|
-
self.assertIsNone(result.ticket_client)
|
|
192
|
-
self.assertEqual(len(kitchen_flow.calls), 1)
|
|
193
|
-
|
|
194
|
-
def test_command_profile_preserves_local_header_discount(self):
|
|
195
|
-
client_flow = FakeFlow(FlowTarget.CLIENT, return_value=[])
|
|
196
|
-
service = OrderPrintService(flows=[client_flow])
|
|
197
|
-
discount = make_discount(total="2.00")
|
|
198
|
-
job = PrintJob(
|
|
199
|
-
request=make_request(
|
|
200
|
-
request_type="local",
|
|
201
|
-
discount=discount,
|
|
202
|
-
client_profile=ClientTicketProfile.COMMAND,
|
|
203
|
-
),
|
|
204
|
-
products=[make_product()],
|
|
205
|
-
tpv_key="TPV1",
|
|
206
|
-
)
|
|
207
|
-
context = type("Ctx", (), {
|
|
208
|
-
"ticket_settings": make_ticket_settings(ticket_client_local=False),
|
|
209
|
-
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
210
|
-
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
211
|
-
})()
|
|
212
|
-
|
|
213
|
-
service.print_job(
|
|
214
|
-
job,
|
|
215
|
-
context,
|
|
216
|
-
PrintChannel.LOCAL,
|
|
217
|
-
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
self.assertEqual(client_flow.calls[0]["base_request"].discount, discount)
|
|
122
|
+
self.assertEqual(kitchen_flow.calls, [])
|
|
123
|
+
self.assertIsNone(result.multi_printer)
|
|
124
|
+
self.assertIsNone(result.ticket_client)
|
|
125
|
+
|
|
126
|
+
def test_explicit_plan_runs_client_when_automatic_setting_is_disabled(self):
|
|
127
|
+
client_flow = FakeFlow(FlowTarget.CLIENT, return_value=[{"client": True}])
|
|
128
|
+
service = OrderPrintService(flows=[client_flow])
|
|
129
|
+
job = PrintJob(
|
|
130
|
+
request=make_request(request_type="local"),
|
|
131
|
+
products=[make_product()],
|
|
132
|
+
tpv_key="TPV1",
|
|
133
|
+
)
|
|
134
|
+
context = type("Ctx", (), {
|
|
135
|
+
"ticket_settings": make_ticket_settings(ticket_kitchen_local=False, ticket_client_local=False),
|
|
136
|
+
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
137
|
+
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
138
|
+
})()
|
|
139
|
+
|
|
140
|
+
result = service.print_job(
|
|
141
|
+
job,
|
|
142
|
+
context,
|
|
143
|
+
PrintChannel.LOCAL,
|
|
144
|
+
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
self.assertEqual(result.ticket_client, [{"client": True}])
|
|
148
|
+
self.assertEqual(len(client_flow.calls), 1)
|
|
149
|
+
|
|
150
|
+
def test_explicit_plan_rejects_target_without_configured_flow(self):
|
|
151
|
+
service = OrderPrintService(flows=[])
|
|
152
|
+
job = PrintJob(
|
|
153
|
+
request=make_request(request_type="local"),
|
|
154
|
+
products=[make_product()],
|
|
155
|
+
tpv_key="TPV1",
|
|
156
|
+
)
|
|
157
|
+
context = type("Ctx", (), {
|
|
158
|
+
"ticket_settings": make_ticket_settings(ticket_kitchen_local=False, ticket_client_local=False),
|
|
159
|
+
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
160
|
+
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
161
|
+
})()
|
|
162
|
+
|
|
163
|
+
with self.assertRaisesRegex(ValueError, "client"):
|
|
164
|
+
service.print_job(
|
|
165
|
+
job,
|
|
166
|
+
context,
|
|
167
|
+
PrintChannel.LOCAL,
|
|
168
|
+
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def test_automatic_plan_ignores_enabled_flow_not_exposed_by_caller(self):
|
|
172
|
+
kitchen_flow = FakeFlow(FlowTarget.KITCHEN, return_value=[{"kitchen": True}])
|
|
173
|
+
service = OrderPrintService(flows=[kitchen_flow])
|
|
174
|
+
job = PrintJob(
|
|
175
|
+
request=make_request(request_type="barra"),
|
|
176
|
+
products=[make_product()],
|
|
177
|
+
tpv_key="TPV1",
|
|
178
|
+
)
|
|
179
|
+
context = type("Ctx", (), {
|
|
180
|
+
"ticket_settings": make_ticket_settings(
|
|
181
|
+
ticket_kitchen_barra=True,
|
|
182
|
+
ticket_client_barra=True,
|
|
183
|
+
),
|
|
184
|
+
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
185
|
+
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
186
|
+
})()
|
|
187
|
+
|
|
188
|
+
result = service.print_job(job, context, PrintChannel.BARRA)
|
|
189
|
+
|
|
190
|
+
self.assertEqual(result.multi_printer, [{"kitchen": True}])
|
|
191
|
+
self.assertIsNone(result.ticket_client)
|
|
192
|
+
self.assertEqual(len(kitchen_flow.calls), 1)
|
|
193
|
+
|
|
194
|
+
def test_command_profile_preserves_local_header_discount(self):
|
|
195
|
+
client_flow = FakeFlow(FlowTarget.CLIENT, return_value=[])
|
|
196
|
+
service = OrderPrintService(flows=[client_flow])
|
|
197
|
+
discount = make_discount(total="2.00")
|
|
198
|
+
job = PrintJob(
|
|
199
|
+
request=make_request(
|
|
200
|
+
request_type="local",
|
|
201
|
+
discount=discount,
|
|
202
|
+
client_profile=ClientTicketProfile.COMMAND,
|
|
203
|
+
),
|
|
204
|
+
products=[make_product()],
|
|
205
|
+
tpv_key="TPV1",
|
|
206
|
+
)
|
|
207
|
+
context = type("Ctx", (), {
|
|
208
|
+
"ticket_settings": make_ticket_settings(ticket_client_local=False),
|
|
209
|
+
"kitchen_settings": make_kitchen_settings(print_by="categories"),
|
|
210
|
+
"global_settings": make_global_settings(currency="EUR", iva=21),
|
|
211
|
+
})()
|
|
212
|
+
|
|
213
|
+
service.print_job(
|
|
214
|
+
job,
|
|
215
|
+
context,
|
|
216
|
+
PrintChannel.LOCAL,
|
|
217
|
+
plan=PrintPlan(enabled_flows={FlowTarget.CLIENT}),
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
self.assertEqual(client_flow.calls[0]["base_request"].discount, discount)
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_products_modifiers.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import unittest
|
|
2
|
+
|
|
2
3
|
from printer_core.algorithms.products_modifiers_multiprinter import ProductsModifiersMultiPrinter
|
|
3
4
|
from printer_core.algorithms.products_modifiers_multiprinter_family import ProductsModifiersMultiprinterFamily
|
|
4
5
|
from printer_core.algorithms.products_modifiers_unique_ticket import ProductsModifiersUniqueTicket
|
|
5
6
|
from printer_core.formatters.discount_formatter import DiscountFormatter
|
|
6
|
-
|
|
7
7
|
from printer_core.tests.unitaries.helpers import make_kitchen_settings, make_printer, make_product, make_request
|
|
8
8
|
|
|
9
9
|
|
|
@@ -34,6 +34,19 @@ class ProductsModifiersMultiPrinterTest(unittest.TestCase):
|
|
|
34
34
|
self.assertEqual(len(lines), 2)
|
|
35
35
|
self.assertEqual({line.printer_r for line in lines}, {"P1", "P2"})
|
|
36
36
|
|
|
37
|
+
def test_build_skips_product_with_explicit_empty_route(self):
|
|
38
|
+
service = ProductsModifiersMultiPrinter(DiscountFormatter())
|
|
39
|
+
product = make_product(printer=[])
|
|
40
|
+
|
|
41
|
+
lines = service.build(
|
|
42
|
+
make_request(),
|
|
43
|
+
[product],
|
|
44
|
+
make_kitchen_settings(show_price_per_unit=False),
|
|
45
|
+
None,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self.assertEqual(lines, [])
|
|
49
|
+
|
|
37
50
|
def test_build_sets_prices_when_enabled(self):
|
|
38
51
|
formatter = DiscountFormatter()
|
|
39
52
|
service = ProductsModifiersMultiPrinter(formatter)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/kitchen_ticket_payload_builder.py
RENAMED
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/builders/printer_products_grouper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/dispatchers/kitchen_ticket_dispatcher.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/selectors/family_product_selector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_cases_output.py
RENAMED
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_discount_formatter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_payload_dispatcher.py
RENAMED
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_print_policy.py
RENAMED
|
File without changes
|
{printer_core-0.0.11 → printer_core-0.0.12}/printer_core/tests/unitaries/test_printer_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|