Skip to content

Commit de21809

Browse files
committed
Refactor receipt handling and improve test coverage for receipt operations
1 parent f62874d commit de21809

File tree

4 files changed

+162
-121
lines changed

4 files changed

+162
-121
lines changed

src/integrify/clopos/handlers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,8 @@ def __init__(
242242
class _UpdateReceiptHandler(AuthedAPIPayloadHandler):
243243
def handle_payload(self, *args, **kwds):
244244
if self.req_model:
245-
self.__req_model = self.req_model.from_args(*args, **kwds)
246-
return self.__req_model.model_dump(
245+
self._APIPayloadHandler__req_model = self.req_model.from_args(*args, **kwds) # pylint: disable=invalid-name,attribute-defined-outside-init
246+
return self._APIPayloadHandler__req_model.model_dump(
247247
by_alias=True,
248248
mode='json',
249249
)

src/integrify/clopos/schemas/products/request.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from itertools import zip_longest
2-
from typing import Literal, NotRequired, TypedDict, Union
2+
from typing import Literal, TypedDict, Union
33

44
from pydantic import Field, field_serializer, model_serializer
5+
from typing_extensions import NotRequired
56

67
from integrify.api import PayloadBaseModel
78
from integrify.clopos.helpers import BoolInt

tests/conftest.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import uuid
12
from functools import partial
23

34
import pytest
45

6+
from integrify.clopos.schemas.common.response import ObjectResponse
7+
from integrify.clopos.schemas.receipts.object import Receipt
8+
from integrify.schemas import APIResponse
59
from integrify.test import pytest_addoption # noqa: F401
610
from integrify.test import requires_env as _requires_env
11+
from tests.client import CloposTestClientClass
712
from tests.mocks import * # noqa: F403
813

914
requires_env = partial(
@@ -29,3 +34,114 @@ def authed_client(client):
2934
client = CloposTestClientClass()
3035
client._token = client.auth().body.token
3136
yield client
37+
38+
39+
@pytest.fixture(scope='package')
40+
def new_receipt_resp(authed_client: 'CloposTestClientClass'):
41+
cid = uuid.uuid4().hex
42+
43+
data = {
44+
'address': '',
45+
'by_card': 0,
46+
'by_cash': 30000,
47+
'cid': cid,
48+
'closed_at': 1755524813947,
49+
'created_at': 1755524813947,
50+
'customer_discount_type': 0,
51+
'delivery_fee': 0,
52+
'discount_rate': 0,
53+
'discount_type': 0,
54+
'discount_value': 0,
55+
'gift_total': 0,
56+
'guests': 1,
57+
'meta': {
58+
'preprint_count': 0,
59+
'sale_type': {'name': 'Satis usulu 1'},
60+
'user': {'name': 'Clopos'},
61+
'terminal_updated_at': 1755524813947,
62+
'availiableDeposit': 30000,
63+
},
64+
'original_subtotal': 30000,
65+
'payment_methods': [{'id': 1, 'name': 'Cash', 'amount': 30000}],
66+
'printed': False,
67+
'receipt_products': [
68+
{
69+
'cid': 'f5b17d93-5586-411b-9e9d-934d3aa2e2ff',
70+
'product_id': 31042,
71+
'portion_size': 1,
72+
'is_gift': 0,
73+
'meta': {
74+
'product': {
75+
'name': 'Апельсинли реване',
76+
'giftable': False,
77+
'price': 22000,
78+
'modifier_name': 'not found',
79+
'discountable': True,
80+
'sold_by_weight': False,
81+
'priceWithoutTaxes': 22000,
82+
'barcode': '',
83+
'taxes': [],
84+
'station': {'id': 57, 'name': 'Отдел Кондитер'},
85+
},
86+
'originalPrice': 22000,
87+
'total_gift': 0,
88+
'discountedPrice': 0,
89+
'terminal_updated_at': 1755524813946,
90+
},
91+
'price': 22000,
92+
'count': 1,
93+
'subtotal': 22000,
94+
'total': 22000,
95+
},
96+
{
97+
'cid': 'c5202cc3-1f03-47b1-9dbc-5f049dabf997',
98+
'product_id': 31046,
99+
'portion_size': 1,
100+
'is_gift': 0,
101+
'meta': {
102+
'product': {
103+
'name': 'Ачма узум жевиз',
104+
'giftable': False,
105+
'price': 8000,
106+
'modifier_name': 'not found',
107+
'discountable': True,
108+
'sold_by_weight': False,
109+
'priceWithoutTaxes': 8000,
110+
'barcode': '',
111+
'taxes': [],
112+
'station': {'id': 57, 'name': 'Отдел Кондитер'},
113+
},
114+
'originalPrice': 8000,
115+
'total_gift': 0,
116+
'discountedPrice': 0,
117+
'terminal_updated_at': 1755524813947,
118+
},
119+
'price': 8000,
120+
'count': 1,
121+
'subtotal': 8000,
122+
'total': 8000,
123+
},
124+
],
125+
'remaining': 0,
126+
'rps_discount': 0,
127+
'sale_type_id': 1000,
128+
'service_charge': 0,
129+
'service_charge_value': 0,
130+
'status': 2,
131+
'subtotal': 30000,
132+
'terminal_id': 1,
133+
'total': 30000,
134+
'total_tax': 0,
135+
'user_id': 1,
136+
}
137+
138+
resp = authed_client.create_receipt(**data) # type: ignore
139+
assert resp.ok
140+
assert resp.body.data.cid == cid
141+
142+
yield resp
143+
144+
145+
@pytest.fixture(scope='package')
146+
def new_receipt_object(new_receipt_resp: APIResponse[ObjectResponse[Receipt]]):
147+
yield new_receipt_resp.body.data

tests/test_main.py

Lines changed: 42 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
# Main aspects of Clopos: Product, Sales, Order and Receipt
22
import random
3-
import uuid
43
from typing import TYPE_CHECKING
54

6-
import pytest
75
from pytest_mock import MockerFixture
86

9-
from integrify.clopos.schemas.common.response import BaseResponse, ErrorResponse
7+
from integrify.clopos.schemas.common.response import BaseResponse, ErrorResponse, ObjectResponse
108
from integrify.clopos.schemas.enums import OrderStatus, ProductType
119
from integrify.clopos.schemas.orders.object import Order
12-
from integrify.clopos.schemas.products.object import Product
10+
from integrify.clopos.schemas.products.object import Product, StopList
1311
from integrify.clopos.schemas.receipts.object import Receipt
12+
from integrify.schemas import APIResponse
13+
from tests.client import CloposTestClientClass
1414
from tests.conftest import requires_env
1515

1616
if TYPE_CHECKING:
1717
from tests.client import CloposTestClientClass
1818

19-
# used to create, get, delete a receipt
20-
RECEIPT_ID = None
21-
2219

2320
@requires_env()
2421
def test_get_products(authed_client: 'CloposTestClientClass'):
@@ -169,6 +166,16 @@ def test_get_product_by_id_wrong_id(authed_client: 'CloposTestClientClass'):
169166
assert resp.body.error == 'No query results for model [App\\Models\\Client\\Product] 1000'
170167

171168

169+
@requires_env()
170+
def test_get_stop_list(authed_client: 'CloposTestClientClass'):
171+
resp = authed_client.get_stop_list()
172+
173+
assert resp.ok
174+
assert resp.body.success
175+
assert isinstance(resp.body.data, list)
176+
assert isinstance(resp.body.data[0], StopList)
177+
178+
172179
@requires_env()
173180
def test_get_orders(authed_client: 'CloposTestClientClass'):
174181
resp = authed_client.get_orders()
@@ -318,135 +325,52 @@ def test_get_receipt_by_id_wrong_id(authed_client: 'CloposTestClientClass'):
318325

319326

320327
@requires_env()
321-
def test_create_receipt(authed_client: 'CloposTestClientClass'):
322-
global RECEIPT_ID
323-
324-
cid = uuid.uuid4().hex
325-
326-
data = {
327-
'address': '',
328-
'by_card': 0,
329-
'by_cash': 30000,
330-
'cid': cid,
331-
'closed_at': 1755524813947,
332-
'created_at': 1755524813947,
333-
'customer_discount_type': 0,
334-
'delivery_fee': 0,
335-
'discount_rate': 0,
336-
'discount_type': 0,
337-
'discount_value': 0,
338-
'gift_total': 0,
339-
'guests': 1,
340-
'meta': {
341-
'preprint_count': 0,
342-
'sale_type': {'name': 'Satis usulu 1'},
343-
'user': {'name': 'Clopos'},
344-
'terminal_updated_at': 1755524813947,
345-
'availiableDeposit': 30000,
346-
},
347-
'original_subtotal': 30000,
348-
'payment_methods': [{'id': 1, 'name': 'Cash', 'amount': 30000}],
349-
'printed': False,
350-
'receipt_products': [
351-
{
352-
'cid': 'f5b17d93-5586-411b-9e9d-934d3aa2e2ff',
353-
'product_id': 31042,
354-
'portion_size': 1,
355-
'is_gift': 0,
356-
'meta': {
357-
'product': {
358-
'name': 'Апельсинли реване',
359-
'giftable': False,
360-
'price': 22000,
361-
'modifier_name': 'not found',
362-
'discountable': True,
363-
'sold_by_weight': False,
364-
'priceWithoutTaxes': 22000,
365-
'barcode': '',
366-
'taxes': [],
367-
'station': {'id': 57, 'name': 'Отдел Кондитер'},
368-
},
369-
'originalPrice': 22000,
370-
'total_gift': 0,
371-
'discountedPrice': 0,
372-
'terminal_updated_at': 1755524813946,
373-
},
374-
'price': 22000,
375-
'count': 1,
376-
'subtotal': 22000,
377-
'total': 22000,
378-
},
379-
{
380-
'cid': 'c5202cc3-1f03-47b1-9dbc-5f049dabf997',
381-
'product_id': 31046,
382-
'portion_size': 1,
383-
'is_gift': 0,
384-
'meta': {
385-
'product': {
386-
'name': 'Ачма узум жевиз',
387-
'giftable': False,
388-
'price': 8000,
389-
'modifier_name': 'not found',
390-
'discountable': True,
391-
'sold_by_weight': False,
392-
'priceWithoutTaxes': 8000,
393-
'barcode': '',
394-
'taxes': [],
395-
'station': {'id': 57, 'name': 'Отдел Кондитер'},
396-
},
397-
'originalPrice': 8000,
398-
'total_gift': 0,
399-
'discountedPrice': 0,
400-
'terminal_updated_at': 1755524813947,
401-
},
402-
'price': 8000,
403-
'count': 1,
404-
'subtotal': 8000,
405-
'total': 8000,
406-
},
407-
],
408-
'remaining': 0,
409-
'rps_discount': 0,
410-
'sale_type_id': 1000,
411-
'service_charge': 0,
412-
'service_charge_value': 0,
413-
'status': 2,
414-
'subtotal': 30000,
415-
'terminal_id': 1,
416-
'total': 30000,
417-
'total_tax': 0,
418-
'user_id': 1,
419-
}
420-
421-
resp = authed_client.create_receipt(**data) # type: ignore
328+
def test_create_receipt(
329+
authed_client: 'CloposTestClientClass',
330+
new_receipt_resp: APIResponse[ObjectResponse[Receipt]],
331+
):
332+
assert new_receipt_resp.ok
333+
assert isinstance(new_receipt_resp.body.data, Receipt)
334+
335+
resp = authed_client.get_receipt_by_id(new_receipt_resp.body.data.id)
422336

423337
assert resp.ok
424338
assert isinstance(resp.body.data, Receipt)
425339

426-
resp = authed_client.get_receipt_by_id(resp.body.data.id)
427340

428-
RECEIPT_ID = resp.body.data.id
341+
@requires_env()
342+
def test_get_receipt_by_id(authed_client: 'CloposTestClientClass', new_receipt_object: Receipt):
343+
resp = authed_client.get_receipt_by_id(new_receipt_object.id)
344+
429345
assert resp.ok
346+
assert resp.body.success
430347
assert isinstance(resp.body.data, Receipt)
431-
assert resp.body.data.cid == cid
348+
349+
assert resp.body.data.id == new_receipt_object.id
432350

433351

434352
@requires_env()
435-
@pytest.mark.skipif(not RECEIPT_ID, reason='test_create_receipt must be run successfully first')
436-
def test_get_receipt_by_id(authed_client: 'CloposTestClientClass'):
437-
resp = authed_client.get_receipt_by_id(RECEIPT_ID) # type: ignore[arg-type]
353+
def test_update_closed_receipt(authed_client: 'CloposTestClientClass', new_receipt_object: Receipt):
354+
resp = authed_client.get_receipt_by_id(new_receipt_object.id)
438355

439356
assert resp.ok
440357
assert resp.body.success
441358
assert isinstance(resp.body.data, Receipt)
359+
assert resp.body.data.status != OrderStatus.NEW
360+
361+
resp = authed_client.update_closed_receipt(
362+
id=new_receipt_object.id,
363+
order_status=OrderStatus.NEW,
364+
)
442365

443-
assert resp.body.data.id == RECEIPT_ID
366+
assert resp.ok
367+
assert isinstance(resp.body.data, Receipt)
368+
assert resp.body.data.order_status == OrderStatus.NEW
444369

445370

446371
@requires_env()
447-
@pytest.mark.skipif(not RECEIPT_ID, reason='test_create_receipt must be run successfully first')
448-
def test_delete_receipt(authed_client: 'CloposTestClientClass'):
449-
resp = authed_client.delete_receipt(RECEIPT_ID) # type: ignore[arg-type]
372+
def test_delete_receipt(authed_client: 'CloposTestClientClass', new_receipt_object: Receipt):
373+
resp = authed_client.delete_receipt(new_receipt_object.id)
450374

451375
assert resp.ok
452376
assert isinstance(resp.body, BaseResponse)

0 commit comments

Comments
 (0)