producteca 1.0.13__py3-none-any.whl → 2.0.14__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.
@@ -1,10 +1,15 @@
1
1
  from pydantic import BaseModel, Field
2
2
  from typing import List, Optional
3
3
  import requests
4
- from ..config.config import ConfigProducteca
4
+ from producteca.abstract.abstract_dataclass import BaseService
5
+ from producteca.sales_orders.search_sale_orders import SearchSalesOrderParams, SearchSalesOrder
6
+ from producteca.payments.payments import Payment
7
+ from producteca.shipments.shipment import Shipment
8
+ from dataclasses import dataclass
5
9
  import logging
6
10
  _logger = logging.getLogger(__name__)
7
11
 
12
+
8
13
  class SaleOrderLocation(BaseModel):
9
14
  streetName: Optional[str] = None
10
15
  streetNumber: Optional[str] = None
@@ -14,6 +19,7 @@ class SaleOrderLocation(BaseModel):
14
19
  neighborhood: Optional[str] = None
15
20
  zipCode: Optional[str] = None
16
21
 
22
+
17
23
  class SaleOrderBillingInfo(BaseModel):
18
24
  docType: Optional[str] = None
19
25
  docNumber: Optional[str] = None
@@ -29,11 +35,13 @@ class SaleOrderBillingInfo(BaseModel):
29
35
  lastName: Optional[str] = None
30
36
  businessName: Optional[str] = None
31
37
 
38
+
32
39
  class SaleOrderProfile(BaseModel):
33
40
  app: int
34
41
  integrationId: str
35
42
  nickname: Optional[str] = None
36
43
 
44
+
37
45
  class SaleOrderContact(BaseModel):
38
46
  id: int
39
47
  name: str
@@ -49,15 +57,18 @@ class SaleOrderContact(BaseModel):
49
57
  profile: Optional[SaleOrderProfile] = None
50
58
  billingInfo: Optional[SaleOrderBillingInfo] = None
51
59
 
60
+
52
61
  class SaleOrderIntegrationId(BaseModel):
53
62
  alternateId: Optional[str] = None
54
63
  integrationId: str
55
64
  app: int
56
65
 
66
+
57
67
  class SaleOrderVariationPicture(BaseModel):
58
68
  url: str
59
69
  id: Optional[int] = None
60
70
 
71
+
61
72
  class SaleOrderVariationStock(BaseModel):
62
73
  warehouseId: Optional[int] = None
63
74
  warehouse: str
@@ -66,10 +77,12 @@ class SaleOrderVariationStock(BaseModel):
66
77
  lastModified: Optional[str] = None
67
78
  available: int
68
79
 
80
+
69
81
  class SaleOrderVariationAttribute(BaseModel):
70
82
  key: str
71
83
  value: str
72
84
 
85
+
73
86
  class SaleOrderVariation(BaseModel):
74
87
  supplierCode: Optional[str] = None
75
88
  pictures: Optional[List[SaleOrderVariationPicture]] = None
@@ -86,15 +99,18 @@ class SaleOrderVariation(BaseModel):
86
99
  sku: str
87
100
  barcode: Optional[str] = None
88
101
 
102
+
89
103
  class SaleOrderProduct(BaseModel):
90
104
  name: str
91
105
  code: str
92
106
  brand: Optional[str] = None
93
107
  id: int
94
108
 
109
+
95
110
  class SaleOrderConversation(BaseModel):
96
111
  questions: Optional[List[str]] = None
97
112
 
113
+
98
114
  class SaleOrderLine(BaseModel):
99
115
  price: float
100
116
  originalPrice: Optional[float] = None
@@ -107,6 +123,7 @@ class SaleOrderLine(BaseModel):
107
123
  reserved: Optional[int] = None
108
124
  id: int
109
125
 
126
+
110
127
  class SaleOrderCard(BaseModel):
111
128
  paymentNetwork: Optional[str] = None
112
129
  firstSixDigits: Optional[int] = None
@@ -115,10 +132,12 @@ class SaleOrderCard(BaseModel):
115
132
  cardholderIdentificationType: Optional[str] = None
116
133
  cardholderName: Optional[str] = None
117
134
 
135
+
118
136
  class SaleOrderPaymentIntegration(BaseModel):
119
137
  integrationId: str
120
138
  app: int
121
139
 
140
+
122
141
  class SaleOrderPayment(BaseModel):
123
142
  date: Optional[str] = None
124
143
  amount: float
@@ -134,6 +153,7 @@ class SaleOrderPayment(BaseModel):
134
153
  hasCancelableStatus: Optional[bool] = None
135
154
  id: Optional[int] = None
136
155
 
156
+
137
157
  class SaleOrderShipmentMethod(BaseModel):
138
158
  trackingNumber: Optional[str] = None
139
159
  trackingUrl: Optional[str] = None
@@ -144,17 +164,20 @@ class SaleOrderShipmentMethod(BaseModel):
144
164
  eta: Optional[int] = None
145
165
  status: Optional[str] = None
146
166
 
167
+
147
168
  class SaleOrderShipmentProduct(BaseModel):
148
169
  product: int
149
170
  variation: int
150
171
  quantity: int
151
172
 
173
+
152
174
  class SaleOrderShipmentIntegration(BaseModel):
153
175
  app: int
154
176
  integrationId: str
155
177
  status: str
156
178
  id: int
157
179
 
180
+
158
181
  class SaleOrderShipment(BaseModel):
159
182
  date: str
160
183
  products: List[SaleOrderShipmentProduct]
@@ -163,6 +186,7 @@ class SaleOrderShipment(BaseModel):
163
186
  receiver: Optional[dict] = None
164
187
  id: int
165
188
 
189
+
166
190
  class SaleOrderInvoiceIntegration(BaseModel):
167
191
  id: Optional[int] = None
168
192
  integrationId: Optional[str] = None
@@ -172,6 +196,7 @@ class SaleOrderInvoiceIntegration(BaseModel):
172
196
  xmlUrl: Optional[str] = None
173
197
  decreaseStock: Optional[bool] = None
174
198
 
199
+
175
200
  class SaleOrder(BaseModel):
176
201
  tags: Optional[List[str]] = None
177
202
  integrations: Optional[List[SaleOrderIntegrationId]] = None
@@ -210,46 +235,114 @@ class SaleOrder(BaseModel):
210
235
  notes: Optional[str] = None
211
236
  id: int
212
237
 
213
- @classmethod
214
- def get(cls, config: ConfigProducteca, sale_order_id: int) -> "SaleOrder":
215
- endpoint = f'salesorders/{sale_order_id}'
216
- url = config.get_endpoint(endpoint)
217
- response = requests.get(url, headers=config.headers)
218
- return cls(**response.json())
219
-
220
- @classmethod
221
- def get_shipping_labels(cls, config: ConfigProducteca, sale_order_id: int):
222
- endpoint = f'salesorders/{sale_order_id}/labels'
223
- url = config.get_endpoint(endpoint)
224
- response = requests.get(url, headers=config.headers)
238
+
239
+ @dataclass
240
+ class SaleOrderService(BaseService[SaleOrder]):
241
+ endpoint: str = Field(default='salesorders', exclude=True)
242
+
243
+ def __call__(self, **payload):
244
+ self._record = SaleOrder(**payload)
245
+ return self
246
+
247
+ def get(self, sale_order_id: int) -> "SaleOrder":
248
+ endpoint = f'{self.endpoint}/{sale_order_id}'
249
+ url = self.config.get_endpoint(endpoint)
250
+ response = requests.get(url, headers=self.config.headers)
251
+ if not response.ok:
252
+ raise Exception("Order could not be fetched")
253
+ return SaleOrder(**response.json())
254
+
255
+ def get_shipping_labels(self):
256
+ if not self._record:
257
+ raise Exception("You need to add a record id")
258
+ endpoint = f'{self.endpoint}/{self._record.id}/labels'
259
+ url = self.config.get_endpoint(endpoint)
260
+ response = requests.get(url, headers=self.config.headers)
261
+ if not response.ok:
262
+ raise Exception("labels could not be gotten")
225
263
  return response.json()
226
264
 
227
- @classmethod
228
- def close(cls, config: ConfigProducteca, sale_order_id: int):
229
- endpoint = f'salesorders/{sale_order_id}/close'
230
- url = config.get_endpoint(endpoint)
231
- response = requests.post(url, headers=config.headers)
232
- return response.status_code, response.json()
233
-
234
- @classmethod
235
- def cancel(cls, config: ConfigProducteca, sale_order_id: int):
236
- endpoint = f'salesorders/{sale_order_id}/cancel'
237
- url = config.get_endpoint(endpoint)
238
- response = requests.post(url, headers=config.headers)
239
- return response.status_code, response.json()
240
-
241
- @classmethod
242
- def synchronize(cls, config: ConfigProducteca, payload: "SaleOrder") -> tuple[int, "SaleOrder"]:
243
- endpoint = 'salesorders/synchronize'
244
- url = config.get_endpoint(endpoint)
245
- response = requests.post(url, data=payload.model_dump_json(exclude_none=True), headers=config.headers)
246
- return response.status_code, cls(**response.json())
247
-
248
- @classmethod
249
- def invoice_integration(cls, config: ConfigProducteca, sale_order_id: int, payload: "SaleOrder"):
250
- endpoint = f'salesorders/{sale_order_id}/invoiceIntegration'
251
- url = config.get_endpoint(endpoint)
252
- response = requests.put(url, headers=config.headers, data=payload.model_dump_json(exclude_none=True))
253
- if response.status_code == 200:
254
- return response.status_code, {}
255
- return response.status_code, response.json()
265
+ def close(self):
266
+ if not self._record:
267
+ raise Exception("You need to add a record id")
268
+ endpoint = f'{self.endpoint}/{self._record.id}/close'
269
+ url = self.config.get_endpoint(endpoint)
270
+ response = requests.post(url, headers=self.config.headers)
271
+ if not response.ok:
272
+ raise Exception("Order could not be closed")
273
+
274
+ def cancel(self):
275
+ if not self._record:
276
+ raise Exception("You need to add a record id")
277
+ endpoint = f'{self.endpoint}/{self._record.id}/cancel'
278
+ url = self.config.get_endpoint(endpoint)
279
+ response = requests.post(url, headers=self.config.headers)
280
+ if not response.ok:
281
+ raise Exception("Order could not be closed")
282
+
283
+ def synchronize(self, payload: "SaleOrder") -> "SaleOrder":
284
+ endpoint = f'{self.endpoint}/synchronize'
285
+ url = self.config.get_endpoint(endpoint)
286
+ response = requests.post(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
287
+ if not response.ok:
288
+ raise Exception(f"Synchronize error {response.text}")
289
+ return SaleOrder(**response.json())
290
+
291
+ def invoice_integration(self):
292
+ if not self._record:
293
+ raise Exception("You need to add a record id")
294
+ endpoint = f'{self.endpoint}/{self._record.id}/invoiceIntegration'
295
+ url = self.config.get_endpoint(endpoint)
296
+ response = requests.put(url, headers=self.config.headers, data=self._record.model_dump_json(exclude_none=True))
297
+ if not response.ok:
298
+ raise Exception(f"Error on resposne {response.text}")
299
+ return SaleOrder(**response.json())
300
+
301
+ def search(self, params: SearchSalesOrderParams):
302
+ endpoint: str = f"search/{self.endpoint}"
303
+ headers = self.config.headers
304
+ url = self.config.get_endpoint(endpoint)
305
+ new_url = f"{url}?$filter={params.filter}&top={params.top}&skip={params.skip}"
306
+ response = requests.get(
307
+ new_url,
308
+ headers=headers,
309
+ )
310
+ if not response.ok:
311
+ raise Exception(f"Error on resposne {response.text}")
312
+ return SearchSalesOrder(**response.json())
313
+
314
+ def add_payment(self, payload: "Payment") -> "Payment":
315
+ if not self._record:
316
+ raise Exception("You need to add a record id")
317
+ url = self.config.get_endpoint(f"{self.endpoint}/{self._record.id}/payments")
318
+ res = requests.post(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
319
+ if not res.ok:
320
+ raise Exception(f"Error on resposne {res.text}")
321
+ return Payment(**res.json())
322
+
323
+ def update_payment(self, payment_id: int, payload: "Payment") -> "Payment":
324
+ if not self._record:
325
+ raise Exception("You need to add a record id")
326
+ url = self.config.get_endpoint(f"{self.endpoint}/{self._record.id}/payments/{payment_id}")
327
+ res = requests.put(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
328
+ if not res.ok:
329
+ raise Exception(f"Error on payment update {res.text}")
330
+ return Payment(**res.json())
331
+
332
+ def add_shipment(self, payload: "Shipment") -> "Shipment":
333
+ if not self._record:
334
+ raise Exception("You need to add a record id")
335
+ url = self.config.get_endpoint(f"{self.endpoint}/{self._record.id}/shipments")
336
+ res = requests.post(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
337
+ if not res.ok:
338
+ raise Exception(f"Error on shipment add {res.text}")
339
+ return Shipment(**res.json())
340
+
341
+ def update_shipment(self, shipment_id: str, payload: "Shipment") -> "Shipment":
342
+ if not self._record:
343
+ raise Exception("You need to add a record id")
344
+ url = self.config.get_endpoint(f"{self.endpoint}/{self._record.id}/shipments/{shipment_id}")
345
+ res = requests.put(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
346
+ if not res.ok:
347
+ raise Exception(f"Error on shipment update {res.text}")
348
+ return Shipment(**res.json())
@@ -0,0 +1,152 @@
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel, Field
3
+ import logging
4
+
5
+ _logger = logging.getLogger(__name__)
6
+
7
+
8
+ class SalesOrderProduct(BaseModel):
9
+ id: int
10
+ name: str
11
+ code: str
12
+ brand: str
13
+
14
+
15
+ class SalesOrderVariationAttribute(BaseModel):
16
+ key: str
17
+ value: str
18
+
19
+
20
+ class SalesOrderVariation(BaseModel):
21
+ id: int
22
+ attributes: List[SalesOrderVariationAttribute]
23
+ sku: str
24
+ thumbnail: str
25
+
26
+
27
+ class SalesOrderLine(BaseModel):
28
+ product: SalesOrderProduct
29
+ variation: SalesOrderVariation
30
+ quantity: int
31
+ price: float
32
+
33
+
34
+ class SalesOrderCard(BaseModel):
35
+ payment_network: str = Field(alias="paymentNetwork")
36
+ first_six_digits: int = Field(alias="firstSixDigits")
37
+ last_four_digits: int = Field(alias="lastFourDigits")
38
+ cardholder_identification_number: str = Field(alias="cardholderIdentificationNumber")
39
+ cardholder_identification_type: str = Field(alias="cardholderIdentificationType")
40
+ cardholder_name: str = Field(alias="cardholderName")
41
+
42
+
43
+ class SalesOrderPaymentIntegration(BaseModel):
44
+ integration_id: str = Field(alias="integrationId")
45
+ app: int
46
+
47
+
48
+ class SalesOrderPayment(BaseModel):
49
+ date: str
50
+ amount: float
51
+ coupon_amount: float = Field(alias="couponAmount")
52
+ status: str
53
+ method: str
54
+ integration: SalesOrderPaymentIntegration
55
+ transaction_fee: float = Field(alias="transactionFee")
56
+ installments: int
57
+ card: SalesOrderCard
58
+ notes: str
59
+ has_cancelable_status: bool = Field(alias="hasCancelableStatus")
60
+ id: int
61
+
62
+
63
+ class SalesOrderIntegration(BaseModel):
64
+ alternate_id: str = Field(alias="alternateId")
65
+ integration_id: int = Field(alias="integrationId")
66
+ app: int
67
+
68
+
69
+ class SalesOrderShipmentProduct(BaseModel):
70
+ product: int
71
+ variation: int
72
+ quantity: int
73
+
74
+
75
+ class SalesOrderShipmentMethod(BaseModel):
76
+ tracking_number: str = Field(alias="trackingNumber")
77
+ tracking_url: str = Field(alias="trackingUrl")
78
+ courier: str
79
+ mode: str
80
+ cost: float
81
+ type: str
82
+ eta: str
83
+ status: str
84
+
85
+
86
+ class SalesOrderShipmentIntegration(BaseModel):
87
+ id: int
88
+ integration_id: str = Field(alias="integrationId")
89
+ app: int
90
+ status: str
91
+
92
+
93
+ class SalesOrderShipment(BaseModel):
94
+ date: str
95
+ products: List[SalesOrderShipmentProduct]
96
+ method: SalesOrderShipmentMethod
97
+ integration: SalesOrderShipmentIntegration
98
+
99
+
100
+ class SalesOrderResultItem(BaseModel):
101
+ codes: List[str]
102
+ contact_id: int = Field(alias="contactId")
103
+ currency: str
104
+ date: str
105
+ delivery_method: str = Field(alias="deliveryMethod")
106
+ delivery_status: str = Field(alias="deliveryStatus")
107
+ id: str
108
+ integration_ids: List[str] = Field(alias="integrationIds")
109
+ integrations: List[SalesOrderIntegration]
110
+ invoice_integration_app: int = Field(alias="invoiceIntegrationApp")
111
+ invoice_integration_id: str = Field(alias="invoiceIntegrationId")
112
+ lines: List[SalesOrderLine]
113
+ payments: List[SalesOrderPayment]
114
+ payment_status: str = Field(alias="paymentStatus")
115
+ payment_term: str = Field(alias="paymentTerm")
116
+ product_names: List[str] = Field(alias="productNames")
117
+ reserving_product_ids: str = Field(alias="reservingProductIds")
118
+ sales_channel: int = Field(alias="salesChannel")
119
+ shipments: List[SalesOrderShipment]
120
+ tracking_number: str = Field(alias="trackingNumber")
121
+ skus: List[str]
122
+ status: str
123
+ tags: List[str]
124
+ warehouse: str
125
+ company_id: int = Field(alias="companyId")
126
+ shipping_cost: float = Field(alias="shippingCost")
127
+ contact_phone: str = Field(alias="contactPhone")
128
+ brands: List[str]
129
+ courier: str
130
+ order_id: int = Field(alias="orderId")
131
+ updated_at: str = Field(alias="updatedAt")
132
+ invoice_integration_created_at: str = Field(alias="invoiceIntegrationCreatedAt")
133
+ invoice_integration_document_url: str = Field(alias="invoiceIntegrationDocumentUrl")
134
+ has_document_url: bool = Field(alias="hasDocumentUrl")
135
+ integration_alternate_ids: str = Field(alias="integrationAlternateIds")
136
+ cart_id: str = Field(alias="cartId")
137
+ amount: float
138
+ has_any_shipments: bool = Field(alias="hasAnyShipments")
139
+
140
+
141
+ class SearchSalesOrder(BaseModel):
142
+ count: int
143
+ results: List[SalesOrderResultItem]
144
+
145
+
146
+ class SearchSalesOrderParams(BaseModel):
147
+ top: Optional[int]
148
+ skip: Optional[int]
149
+ filter: Optional[str] = Field(default=None, alias="$filter")
150
+
151
+ class Config:
152
+ validate_by_name = True
@@ -0,0 +1,137 @@
1
+ {
2
+ "count": 0,
3
+ "results": [
4
+ {
5
+ "codes": [
6
+ "string"
7
+ ],
8
+ "contactId": 0,
9
+ "currency": "Local",
10
+ "date": "string",
11
+ "deliveryMethod": "ToBeConfirmed",
12
+ "deliveryStatus": "ToBeConfirmed",
13
+ "id": "string",
14
+ "integrationIds": [
15
+ "string"
16
+ ],
17
+ "integrations": [
18
+ {
19
+ "alternateId": "string",
20
+ "integrationId": 0,
21
+ "app": 0
22
+ }
23
+ ],
24
+ "invoiceIntegrationApp": 0,
25
+ "invoiceIntegrationId": "string",
26
+ "lines": [
27
+ {
28
+ "product": {
29
+ "id": 0,
30
+ "name": "string",
31
+ "code": "string",
32
+ "brand": "string"
33
+ },
34
+ "variation": {
35
+ "id": 0,
36
+ "attributes": [
37
+ {
38
+ "key": "string",
39
+ "value": "string"
40
+ }
41
+ ],
42
+ "sku": "string",
43
+ "thumbnail": "string"
44
+ },
45
+ "quantity": 0,
46
+ "price": 0
47
+ }
48
+ ],
49
+ "payments": [
50
+ {
51
+ "date": "string",
52
+ "amount": 0,
53
+ "couponAmount": 0,
54
+ "status": "Pending",
55
+ "method": "Cash",
56
+ "integration": {
57
+ "integrationId": "string",
58
+ "app": 249
59
+ },
60
+ "transactionFee": 0,
61
+ "installments": 0,
62
+ "card": {
63
+ "paymentNetwork": "string",
64
+ "firstSixDigits": 0,
65
+ "lastFourDigits": 0,
66
+ "cardholderIdentificationNumber": "string",
67
+ "cardholderIdentificationType": "string",
68
+ "cardholderName": "string"
69
+ },
70
+ "notes": "string",
71
+ "hasCancelableStatus": true,
72
+ "id": 0
73
+ }
74
+ ],
75
+ "paymentStatus": "Pending",
76
+ "paymentTerm": "Advance",
77
+ "productNames": [
78
+ "string"
79
+ ],
80
+ "reservingProductIds": "string",
81
+ "salesChannel": 0,
82
+ "shipments": [
83
+ {
84
+ "date": "string",
85
+ "products": [
86
+ {
87
+ "product": 0,
88
+ "variation": 0,
89
+ "quantity": 0
90
+ }
91
+ ],
92
+ "method": {
93
+ "trackingNumber": "string",
94
+ "trackingUrl": "string",
95
+ "courier": "string",
96
+ "mode": "string",
97
+ "cost": 0,
98
+ "type": "Ship",
99
+ "eta": "string",
100
+ "status": "PickingPending"
101
+ },
102
+ "integration": {
103
+ "id": 0,
104
+ "integrationId": "string",
105
+ "app": 0,
106
+ "status": "NotAvailable"
107
+ }
108
+ }
109
+ ],
110
+ "trackingNumber": "string",
111
+ "skus": [
112
+ "string"
113
+ ],
114
+ "status": "Pending",
115
+ "tags": [
116
+ "string"
117
+ ],
118
+ "warehouse": "string",
119
+ "companyId": 0,
120
+ "shippingCost": 0,
121
+ "contactPhone": "string",
122
+ "brands": [
123
+ "string"
124
+ ],
125
+ "courier": "string",
126
+ "orderId": 0,
127
+ "updatedAt": "string",
128
+ "invoiceIntegrationCreatedAt": "string",
129
+ "invoiceIntegrationDocumentUrl": "string",
130
+ "hasDocumentUrl": true,
131
+ "integrationAlternateIds": "string",
132
+ "cartId": "string",
133
+ "amount": 0,
134
+ "hasAnyShipments": true
135
+ }
136
+ ]
137
+ }
@@ -1,12 +1,13 @@
1
1
  import unittest
2
2
  from unittest.mock import patch, Mock
3
- from producteca.config.config import ConfigProducteca
4
3
  from producteca.sales_orders.sales_orders import SaleOrder, SaleOrderInvoiceIntegration
4
+ from producteca.client import ProductecaClient
5
5
 
6
6
 
7
7
  class TestSaleOrder(unittest.TestCase):
8
+
8
9
  def setUp(self):
9
- self.config = ConfigProducteca(token="test_client", api_key="test_secret")
10
+ self.client = ProductecaClient(token="test_client", api_key="test_secret")
10
11
  self.sale_order_id = 123
11
12
  self.mock_response = {
12
13
  "id": self.sale_order_id,
@@ -21,7 +22,7 @@ class TestSaleOrder(unittest.TestCase):
21
22
  json=lambda: self.mock_response
22
23
  )
23
24
 
24
- sale_order = SaleOrder.get(self.config, self.sale_order_id)
25
+ sale_order = self.client.SalesOrder.get(self.sale_order_id)
25
26
  self.assertEqual(sale_order.id, self.sale_order_id)
26
27
  mock_get.assert_called_once()
27
28
 
@@ -33,20 +34,17 @@ class TestSaleOrder(unittest.TestCase):
33
34
  json=lambda: mock_labels
34
35
  )
35
36
 
36
- labels = SaleOrder.get_shipping_labels(self.config, self.sale_order_id)
37
+ labels = self.client.SalesOrder(id=1234).get_shipping_labels()
37
38
  self.assertEqual(labels, mock_labels)
38
39
  mock_get.assert_called_once()
39
40
 
40
41
  @patch('requests.post')
41
42
  def test_close_sale_order(self, mock_post):
42
43
  mock_post.return_value = Mock(
43
- status_code=200,
44
- json=lambda: {"status": "closed"}
44
+ status_code=200
45
45
  )
46
46
 
47
- status_code, response = SaleOrder.close(self.config, self.sale_order_id)
48
- self.assertEqual(status_code, 200)
49
- self.assertEqual(response, {"status": "closed"})
47
+ self.client.SalesOrder(id=1234).close()
50
48
  mock_post.assert_called_once()
51
49
 
52
50
  @patch('requests.post')
@@ -56,9 +54,7 @@ class TestSaleOrder(unittest.TestCase):
56
54
  json=lambda: {"status": "cancelled"}
57
55
  )
58
56
 
59
- status_code, response = SaleOrder.cancel(self.config, self.sale_order_id)
60
- self.assertEqual(status_code, 200)
61
- self.assertEqual(response, {"status": "cancelled"})
57
+ self.client.SalesOrder(id=1234).cancel()
62
58
  mock_post.assert_called_once()
63
59
 
64
60
  @patch('requests.post')
@@ -69,8 +65,7 @@ class TestSaleOrder(unittest.TestCase):
69
65
  json=lambda: self.mock_response
70
66
  )
71
67
 
72
- status_code, response = SaleOrder.synchronize(self.config, sale_order)
73
- self.assertEqual(status_code, 200)
68
+ response = self.client.SalesOrder.synchronize(sale_order)
74
69
  self.assertEqual(response.id, self.sale_order_id)
75
70
  mock_post.assert_called_once()
76
71
 
@@ -86,13 +81,17 @@ class TestSaleOrder(unittest.TestCase):
86
81
 
87
82
  mock_put.return_value = Mock(
88
83
  status_code=200,
89
- json=lambda: {}
84
+ json=lambda: {
85
+ "id": 1,
86
+ "integrationId": "test123",
87
+ "app": 1
88
+ }
90
89
  )
91
90
 
92
- status_code, response = SaleOrder.invoice_integration(self.config, self.sale_order_id, sale_order)
93
- self.assertEqual(status_code, 200)
94
- self.assertEqual(response, {})
91
+ response = self.client.SalesOrder(**sale_order.model_dump()).invoice_integration()
92
+ self.assertIsInstance(response, SaleOrder)
95
93
  mock_put.assert_called_once()
96
94
 
95
+
97
96
  if __name__ == '__main__':
98
97
  unittest.main()