producteca 2.0.15__py3-none-any.whl → 2.0.16__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.
@@ -13,6 +13,33 @@ class TestProduct(unittest.TestCase):
13
13
  code="TEST001",
14
14
  category="Test"
15
15
  )
16
+ self.product_to_create_payload = {
17
+ "sku": "9817234",
18
+ "code": "871234",
19
+ "name": "Hola test",
20
+ "buyingPrice": 0,
21
+ "deals": [
22
+ {
23
+ "campaign": "string",
24
+ "regularPrice": 0,
25
+ "dealPrice": 0
26
+ }
27
+ ],
28
+ "prices": [
29
+ {
30
+ "amount": 10,
31
+ "currency": "Local",
32
+ "priceList": "Default"
33
+ }
34
+ ],
35
+ "stocks": [
36
+ {
37
+ "quantity": 2,
38
+ "availableQuantity": 2,
39
+ "warehouse": "Default"
40
+ }
41
+ ],
42
+ }
16
43
 
17
44
  @patch('requests.post')
18
45
  def test_create_product_success(self, mock_post):
@@ -22,7 +49,7 @@ class TestProduct(unittest.TestCase):
22
49
  mock_response.json.return_value = self.test_product.model_dump()
23
50
  mock_post.return_value = mock_response
24
51
 
25
- response = self.client.Product(**self.test_product.model_dump()).create()
52
+ response = self.client.Product(**self.test_product.model_dump()).synchronize(self.product_to_create_payload)
26
53
 
27
54
  self.assertEqual(response.sku, "TEST001")
28
55
 
@@ -34,17 +61,17 @@ class TestProduct(unittest.TestCase):
34
61
  mock_post.return_value = mock_response
35
62
 
36
63
  with self.assertRaises(Exception):
37
- self.client.Product.create()
64
+ self.client.Product.synchronize(self.product_to_create_payload)
38
65
 
39
66
  @patch('requests.post')
40
67
  def test_update_product_success(self, mock_post):
41
- # Mock successful update
68
+ payload = self.product_to_create_payload
42
69
  mock_response = Mock()
43
70
  mock_response.status_code = 200
44
71
  mock_response.json.return_value = self.test_product.model_dump()
45
72
  mock_post.return_value = mock_response
46
73
 
47
- response = self.client.Product(**self.test_product.model_dump()).update()
74
+ response = self.client.Product(**self.test_product.model_dump()).synchronize(payload)
48
75
 
49
76
  self.assertEqual(response.name, "Test Product")
50
77
 
@@ -65,28 +92,86 @@ class TestProduct(unittest.TestCase):
65
92
  # Mock get bundle response
66
93
  mock_response = Mock()
67
94
  mock_response.status_code = 200
68
- test_prod = self.test_product.model_dump()
69
- test_prod.update({"sku": "TEST001", "bundles": []})
95
+ test_prod = {
96
+ "results": [
97
+ {
98
+ "companyId": 0,
99
+ "productId": 0,
100
+ "variations": [
101
+ {
102
+ "variationId": 0,
103
+ "components": [
104
+ {
105
+ "quantity": 0,
106
+ "variationId": 0,
107
+ "productId": 0
108
+ }
109
+ ]
110
+ }
111
+ ],
112
+ "id": "string"
113
+ }
114
+ ],
115
+ "count": 0
116
+ }
70
117
  mock_response.json.return_value = test_prod
71
118
  mock_get.return_value = mock_response
72
119
 
73
120
  product = self.client.Product.get_bundle(1)
74
121
 
75
- self.assertEqual(product.sku, "TEST001")
122
+ self.assertEqual(product.count, 0)
76
123
 
77
124
  @patch('requests.get')
78
125
  def test_get_ml_integration(self, mock_get):
79
126
  # Mock ML integration response
80
127
  mock_response = Mock()
81
128
  mock_response.status_code = 200
82
- test_prod = self.test_product.model_dump()
83
- test_prod.update({"sku": "TEST001", "integrations": []})
84
- mock_response.json.return_value = test_prod
129
+ meli_product = {
130
+ "hasCustomShippingCosts": True,
131
+ "productId": 0,
132
+ "shipping": {
133
+ "localPickup": True,
134
+ "mode": "string",
135
+ "freeShipping": True,
136
+ "freeShippingCost": 0,
137
+ "mandatoryFreeShipping": True,
138
+ "freeShippingMethod": "string"
139
+ },
140
+ "mShopsShipping": {
141
+ "enabled": True
142
+ },
143
+ "addFreeShippingCostToPrice": True,
144
+ "category": {
145
+ "meliId": "string",
146
+ "acceptsMercadoenvios": True,
147
+ "suggest": True,
148
+ "fixed": True
149
+ },
150
+ "attributeCompletion": {
151
+ "productIdentifierStatus": "Complete",
152
+ "dataSheetStatus": "Complete",
153
+ "status": "Complete",
154
+ "count": 0,
155
+ "total": 0
156
+ },
157
+ "catalogProducts": [
158
+ "string"
159
+ ],
160
+ "warranty": "string",
161
+ "domain": "string",
162
+ "listingTypeId": "GoldSpecial",
163
+ "catalogProductsStatus": "Unlinked",
164
+ "tags": [
165
+ "string"
166
+ ]
167
+ }
168
+
169
+ mock_response.json.return_value = meli_product
85
170
  mock_get.return_value = mock_response
86
171
 
87
172
  product = self.client.Product.get_ml_integration(1)
88
173
 
89
- self.assertEqual(product.sku, "TEST001")
174
+ self.assertEqual(product.listing_type_id, "GoldSpecial")
90
175
 
91
176
 
92
177
  if __name__ == '__main__':
@@ -34,8 +34,8 @@ class TestSearchProduct(unittest.TestCase):
34
34
  "results": [{
35
35
  "@search.score": 1.0,
36
36
  "id": 123,
37
- "product_id": 456,
38
- "company_id": 789,
37
+ "productId": 456,
38
+ "companyId": 789,
39
39
  "name": "Test Product",
40
40
  "code": "TEST-001",
41
41
  "skus": ["SKU001"],
@@ -47,18 +47,18 @@ class TestSearchProduct(unittest.TestCase):
47
47
  "quantity": 10,
48
48
  "reserved": 0
49
49
  }],
50
- "warehouses_with_stock": ["Main"],
51
- "total_stock": 10,
52
- "has_pictures": True,
53
- "buying_price": 100.0,
50
+ "warehousesWithStock": ["Main"],
51
+ "totalStock": 10,
52
+ "hasPictures": True,
53
+ "buyingPrice": 100.0,
54
54
  "prices": [{
55
- "price_list_id": 1,
56
- "price_list": "Default",
55
+ "priceListId": 1,
56
+ "priceList": "Default",
57
57
  "amount": 200.0,
58
58
  "currency": "USD"
59
59
  }],
60
- "integration_ids": ["INT001"],
61
- "integration_apps": ["APP1"],
60
+ "integrationIds": ["INT001"],
61
+ "integrationApps": ["APP1"],
62
62
  "integrations": [],
63
63
  "campaigns": [],
64
64
  "app": None,
@@ -11,56 +11,56 @@ _logger = logging.getLogger(__name__)
11
11
 
12
12
 
13
13
  class SaleOrderLocation(BaseModel):
14
- streetName: Optional[str] = None
15
- streetNumber: Optional[str] = None
16
- addressNotes: Optional[str] = None
14
+ street_name: Optional[str] = Field(None, alias="streetName")
15
+ street_number: Optional[str] = Field(None, alias="streetNumber")
16
+ address_notes: Optional[str] = Field(None, alias="addressNotes")
17
17
  state: Optional[str] = None
18
18
  city: Optional[str] = None
19
19
  neighborhood: Optional[str] = None
20
- zipCode: Optional[str] = None
20
+ zip_code: Optional[str] = Field(None, alias="zipCode")
21
21
 
22
22
 
23
23
  class SaleOrderBillingInfo(BaseModel):
24
- docType: Optional[str] = None
25
- docNumber: Optional[str] = None
26
- streetName: Optional[str] = None
27
- streetNumber: Optional[str] = None
24
+ doc_type: Optional[str] = Field(None, alias="docType")
25
+ doc_number: Optional[str] = Field(None, alias="docNumber")
26
+ street_name: Optional[str] = Field(None, alias="streetName")
27
+ street_number: Optional[str] = Field(None, alias="streetNumber")
28
28
  comment: Optional[str] = None
29
- zipCode: Optional[str] = None
29
+ zip_code: Optional[str] = Field(None, alias="zipCode")
30
30
  city: Optional[str] = None
31
31
  state: Optional[str] = None
32
- stateRegistration: Optional[str] = None
33
- taxPayerType: Optional[str] = None
34
- firstName: Optional[str] = None
35
- lastName: Optional[str] = None
36
- businessName: Optional[str] = None
32
+ state_registration: Optional[str] = Field(None, alias="stateRegistration")
33
+ tax_payer_type: Optional[str] = Field(None, alias="taxPayerType")
34
+ first_name: Optional[str] = Field(None, alias="firstName")
35
+ last_name: Optional[str] = Field(None, alias="lastName")
36
+ business_name: Optional[str] = Field(None, alias="businessName")
37
37
 
38
38
 
39
39
  class SaleOrderProfile(BaseModel):
40
40
  app: int
41
- integrationId: str
41
+ integration_id: str = Field(alias="integrationId")
42
42
  nickname: Optional[str] = None
43
43
 
44
44
 
45
45
  class SaleOrderContact(BaseModel):
46
46
  id: int
47
47
  name: str
48
- contactPerson: Optional[str] = None
48
+ contact_person: Optional[str] = Field(None, alias="contactPerson")
49
49
  mail: Optional[str] = None
50
- phoneNumber: Optional[str] = None
51
- taxId: Optional[str] = None
50
+ phone_number: Optional[str] = Field(None, alias="phoneNumber")
51
+ tax_id: Optional[str] = Field(None, alias="taxId")
52
52
  location: Optional[SaleOrderLocation] = None
53
53
  notes: Optional[str] = None
54
54
  type: Optional[str] = None
55
- priceList: Optional[str] = None
56
- priceListId: Optional[str] = None
55
+ price_list: Optional[str] = Field(None, alias="priceList")
56
+ price_list_id: Optional[str] = Field(None, alias="priceListId")
57
57
  profile: Optional[SaleOrderProfile] = None
58
- billingInfo: Optional[SaleOrderBillingInfo] = None
58
+ billing_info: Optional[SaleOrderBillingInfo] = Field(None, alias="billingInfo")
59
59
 
60
60
 
61
61
  class SaleOrderIntegrationId(BaseModel):
62
- alternateId: Optional[str] = None
63
- integrationId: str
62
+ alternate_id: Optional[str] = Field(None, alias="alternateId")
63
+ integration_id: str = Field(alias="integrationId")
64
64
  app: int
65
65
 
66
66
 
@@ -70,11 +70,11 @@ class SaleOrderVariationPicture(BaseModel):
70
70
 
71
71
 
72
72
  class SaleOrderVariationStock(BaseModel):
73
- warehouseId: Optional[int] = None
73
+ warehouse_id: Optional[int] = Field(None, alias="warehouseId")
74
74
  warehouse: str
75
75
  quantity: int
76
76
  reserved: int
77
- lastModified: Optional[str] = None
77
+ last_modified: Optional[str] = Field(None, alias="lastModified")
78
78
  available: int
79
79
 
80
80
 
@@ -84,13 +84,13 @@ class SaleOrderVariationAttribute(BaseModel):
84
84
 
85
85
 
86
86
  class SaleOrderVariation(BaseModel):
87
- supplierCode: Optional[str] = None
87
+ supplier_code: Optional[str] = Field(None, alias="supplierCode")
88
88
  pictures: Optional[List[SaleOrderVariationPicture]] = None
89
89
  stocks: Optional[List[SaleOrderVariationStock]] = None
90
- integrationId: Optional[int] = None
91
- attributesHash: Optional[str] = None
92
- primaryColor: Optional[str] = None
93
- secondaryColor: Optional[str] = None
90
+ integration_id: Optional[int] = Field(None, alias="integrationId")
91
+ attributes_hash: Optional[str] = Field(None, alias="attributesHash")
92
+ primary_color: Optional[str] = Field(None, alias="primaryColor")
93
+ secondary_color: Optional[str] = Field(None, alias="secondaryColor")
94
94
  size: Optional[str] = None
95
95
  thumbnail: Optional[str] = None
96
96
  attributes: Optional[List[SaleOrderVariationAttribute]] = None
@@ -113,11 +113,11 @@ class SaleOrderConversation(BaseModel):
113
113
 
114
114
  class SaleOrderLine(BaseModel):
115
115
  price: float
116
- originalPrice: Optional[float] = None
117
- transactionFee: Optional[float] = None
116
+ original_price: Optional[float] = Field(None, alias="originalPrice")
117
+ transaction_fee: Optional[float] = Field(None, alias="transactionFee")
118
118
  product: SaleOrderProduct
119
119
  variation: SaleOrderVariation
120
- orderVariationIntegrationId: Optional[str] = None
120
+ order_variation_integration_id: Optional[str] = Field(None, alias="orderVariationIntegrationId")
121
121
  quantity: int
122
122
  conversation: Optional[SaleOrderConversation] = None
123
123
  reserved: Optional[int] = None
@@ -125,38 +125,38 @@ class SaleOrderLine(BaseModel):
125
125
 
126
126
 
127
127
  class SaleOrderCard(BaseModel):
128
- paymentNetwork: Optional[str] = None
129
- firstSixDigits: Optional[int] = None
130
- lastFourDigits: Optional[int] = None
131
- cardholderIdentificationNumber: Optional[str] = None
132
- cardholderIdentificationType: Optional[str] = None
133
- cardholderName: Optional[str] = None
128
+ payment_network: Optional[str] = Field(None, alias="paymentNetwork")
129
+ first_six_digits: Optional[int] = Field(None, alias="firstSixDigits")
130
+ last_four_digits: Optional[int] = Field(None, alias="lastFourDigits")
131
+ cardholder_identification_number: Optional[str] = Field(None, alias="cardholderIdentificationNumber")
132
+ cardholder_identification_type: Optional[str] = Field(None, alias="cardholderIdentificationType")
133
+ cardholder_name: Optional[str] = Field(None, alias="cardholderName")
134
134
 
135
135
 
136
136
  class SaleOrderPaymentIntegration(BaseModel):
137
- integrationId: str
137
+ integration_id: str = Field(alias="integrationId")
138
138
  app: int
139
139
 
140
140
 
141
141
  class SaleOrderPayment(BaseModel):
142
142
  date: Optional[str] = None
143
143
  amount: float
144
- couponAmount: Optional[float] = None
144
+ coupon_amount: Optional[float] = Field(None, alias="couponAmount")
145
145
  status: Optional[str] = None
146
146
  method: Optional[str] = None
147
147
  integration: Optional[SaleOrderPaymentIntegration] = None
148
- transactionFee: Optional[float] = None
148
+ transaction_fee: Optional[float] = Field(None, alias="transactionFee")
149
149
  installments: Optional[int] = None
150
150
  card: Optional[SaleOrderCard] = None
151
151
  notes: Optional[str] = None
152
- authorizationCode: Optional[str] = None
153
- hasCancelableStatus: Optional[bool] = None
152
+ authorization_code: Optional[str] = Field(None, alias="authorizationCode")
153
+ has_cancelable_status: Optional[bool] = Field(None, alias="hasCancelableStatus")
154
154
  id: Optional[int] = None
155
155
 
156
156
 
157
157
  class SaleOrderShipmentMethod(BaseModel):
158
- trackingNumber: Optional[str] = None
159
- trackingUrl: Optional[str] = None
158
+ tracking_number: Optional[str] = Field(None, alias="trackingNumber")
159
+ tracking_url: Optional[str] = Field(None, alias="trackingUrl")
160
160
  courier: Optional[str] = None
161
161
  mode: Optional[str] = None
162
162
  cost: Optional[float] = None
@@ -173,7 +173,7 @@ class SaleOrderShipmentProduct(BaseModel):
173
173
 
174
174
  class SaleOrderShipmentIntegration(BaseModel):
175
175
  app: int
176
- integrationId: str
176
+ integration_id: str = Field(alias="integrationId")
177
177
  status: str
178
178
  id: int
179
179
 
@@ -187,70 +187,101 @@ class SaleOrderShipment(BaseModel):
187
187
  id: int
188
188
 
189
189
 
190
- class SaleOrderInvoiceIntegration(BaseModel):
191
- id: Optional[int] = None
192
- integrationId: Optional[str] = None
193
- app: Optional[int] = None
194
- createdAt: Optional[str] = None
195
- documentUrl: Optional[str] = None
196
- xmlUrl: Optional[str] = None
197
- decreaseStock: Optional[bool] = None
190
+ class SaleOrderInvoiceIntegrationAbstract(BaseModel):
191
+ id: int
192
+ integration_id: str = Field(alias="integrationId")
193
+ app: int
194
+ created_at: str = Field(alias="createdAt")
195
+ decrease_stock: bool = Field(alias="decreaseStock")
196
+
197
+
198
+ class SaleOrderInvoiceIntegration(SaleOrderInvoiceIntegrationAbstract):
199
+ document_url: Optional[str] = Field(None, alias="documentUrl")
200
+ xml_url: Optional[str] = Field(None, alias="xmlUrl")
201
+
202
+
203
+ class SaleOrderInvoiceIntegrationPut(SaleOrderInvoiceIntegrationAbstract):
204
+ document_url: str = Field(alias="documentUrl")
205
+ xml_url: str = Field(alias="xmlUrl")
198
206
 
199
207
 
200
208
  class SaleOrder(BaseModel):
201
209
  tags: Optional[List[str]] = None
202
210
  integrations: Optional[List[SaleOrderIntegrationId]] = None
203
- invoiceIntegration: Optional[SaleOrderInvoiceIntegration] = None
211
+ invoice_integration: SaleOrderInvoiceIntegration = Field(alias="invoiceIntegration")
204
212
  channel: Optional[str] = None
205
- piiExpired: Optional[bool] = None
213
+ pii_expired: Optional[bool] = Field(None, alias="piiExpired")
206
214
  contact: Optional[SaleOrderContact] = None
207
215
  lines: Optional[List[SaleOrderLine]] = None
208
216
  warehouse: Optional[str] = None
209
- warehouseId: Optional[int] = None
210
- warehouseIntegration: Optional[str] = None
211
- pickUpStore: Optional[str] = None
217
+ warehouse_id: Optional[int] = Field(None, alias="warehouseId")
218
+ warehouse_integration: Optional[str] = Field(None, alias="warehouseIntegration")
219
+ pick_up_store: Optional[str] = Field(None, alias="pickUpStore")
212
220
  payments: Optional[List[SaleOrderPayment]] = None
213
221
  shipments: Optional[List[SaleOrderShipment]] = None
214
222
  amount: Optional[float] = None
215
- shippingCost: Optional[float] = None
216
- financialCost: Optional[float] = None
217
- paidApproved: Optional[float] = None
218
- paymentStatus: Optional[str] = None
219
- deliveryStatus: Optional[str] = None
220
- paymentFulfillmentStatus: Optional[str] = None
221
- deliveryFulfillmentStatus: Optional[str] = None
222
- deliveryMethod: Optional[str] = None
223
- paymentTerm: Optional[str] = None
223
+ shipping_cost: Optional[float] = Field(None, alias="shippingCost")
224
+ financial_cost: Optional[float] = Field(None, alias="financialCost")
225
+ paid_approved: Optional[float] = Field(None, alias="paidApproved")
226
+ payment_status: Optional[str] = Field(None, alias="paymentStatus")
227
+ delivery_status: Optional[str] = Field(None, alias="deliveryStatus")
228
+ payment_fulfillment_status: Optional[str] = Field(None, alias="paymentFulfillmentStatus")
229
+ delivery_fulfillment_status: Optional[str] = Field(None, alias="deliveryFulfillmentStatus")
230
+ delivery_method: Optional[str] = Field(None, alias="deliveryMethod")
231
+ payment_term: Optional[str] = Field(None, alias="paymentTerm")
224
232
  currency: Optional[str] = None
225
- customId: Optional[str] = None
226
- isOpen: Optional[bool] = None
227
- isCanceled: Optional[bool] = None
228
- cartId: Optional[str] = None
233
+ custom_id: Optional[str] = Field(None, alias="customId")
234
+ is_open: Optional[bool] = Field(None, alias="isOpen")
235
+ is_canceled: Optional[bool] = Field(None, alias="isCanceled")
236
+ cart_id: Optional[str] = Field(None, alias="cartId")
229
237
  draft: Optional[bool] = None
230
- promiseDeliveryDate: Optional[str] = None
231
- promiseDispatchDate: Optional[str] = None
232
- hasAnyShipments: Optional[bool] = None
233
- hasAnyPayments: Optional[bool] = None
238
+ promise_delivery_date: Optional[str] = Field(None, alias="promiseDeliveryDate")
239
+ promise_dispatch_date: Optional[str] = Field(None, alias="promiseDispatchDate")
240
+ has_any_shipments: Optional[bool] = Field(None, alias="hasAnyShipments")
241
+ has_any_payments: Optional[bool] = Field(None, alias="hasAnyPayments")
234
242
  date: Optional[str] = None
235
243
  notes: Optional[str] = None
236
244
  id: int
237
245
 
238
246
 
247
+ class SaleOrderSynchronize(BaseModel):
248
+ id: int
249
+ invoice_integration: SaleOrderInvoiceIntegration = Field(alias="invoiceIntegration")
250
+ notes: Optional[str] = None
251
+ tags: Optional[List[str]] = None
252
+
253
+
254
+ class UpdateStatus(BaseModel):
255
+ updated: bool = False
256
+
257
+
258
+ class SaleOrderSyncResponse(BaseModel):
259
+ basic: UpdateStatus = Field(default_factory=UpdateStatus)
260
+ contact: UpdateStatus = Field(default_factory=UpdateStatus)
261
+ shipments: UpdateStatus = Field(default_factory=UpdateStatus)
262
+ payments: UpdateStatus = Field(default_factory=UpdateStatus)
263
+ invoice_integration: UpdateStatus = Field(alias="invoiceIntegration", default_factory=UpdateStatus)
264
+
265
+
239
266
  @dataclass
240
267
  class SaleOrderService(BaseService[SaleOrder]):
241
- endpoint: str = Field(default='salesorders', exclude=True)
268
+ endpoint: str = 'salesorders'
242
269
 
243
270
  def __call__(self, **payload):
244
271
  self._record = SaleOrder(**payload)
245
272
  return self
246
273
 
247
- def get(self, sale_order_id: int) -> "SaleOrder":
274
+ def __repr__(self):
275
+ return repr(self._record)
276
+
277
+ def get(self, sale_order_id: int) -> "SaleOrderService":
248
278
  endpoint = f'{self.endpoint}/{sale_order_id}'
249
279
  url = self.config.get_endpoint(endpoint)
250
280
  response = requests.get(url, headers=self.config.headers)
251
281
  if not response.ok:
252
282
  raise Exception("Order could not be fetched")
253
- return SaleOrder(**response.json())
283
+ response_data = response.json()
284
+ return self(**response_data)
254
285
 
255
286
  def get_shipping_labels(self):
256
287
  if not self._record:
@@ -278,25 +309,32 @@ class SaleOrderService(BaseService[SaleOrder]):
278
309
  url = self.config.get_endpoint(endpoint)
279
310
  response = requests.post(url, headers=self.config.headers)
280
311
  if not response.ok:
281
- raise Exception("Order could not be closed")
312
+ raise Exception("Order could not be cancelled")
282
313
 
283
- def synchronize(self, payload: "SaleOrder") -> "SaleOrder":
314
+ def synchronize(self) -> "SaleOrderService":
315
+ if not self._record:
316
+ raise Exception("You need to add a record by calling the resource and adding info")
284
317
  endpoint = f'{self.endpoint}/synchronize'
285
318
  url = self.config.get_endpoint(endpoint)
286
- response = requests.post(url, data=payload.model_dump_json(exclude_none=True), headers=self.config.headers)
319
+ # TODO: Check what can we sync, and what can we not sync
320
+ sync_body = SaleOrderSynchronize(**self._record.model_dump(by_alias=True))
321
+ response = requests.post(url, json=sync_body.model_dump(by_alias=True), headers=self.config.headers)
287
322
  if not response.ok:
288
- raise Exception(f"Synchronize error {response.text}")
289
- return SaleOrder(**response.json())
323
+ raise Exception(f"Synchronize error {response.status_code} {response.text}")
324
+ sync_res = SaleOrderSyncResponse(**response.json()) # noqa
325
+ return self
290
326
 
291
327
  def invoice_integration(self):
292
328
  if not self._record:
293
329
  raise Exception("You need to add a record id")
294
330
  endpoint = f'{self.endpoint}/{self._record.id}/invoiceIntegration'
295
331
  url = self.config.get_endpoint(endpoint)
296
- response = requests.put(url, headers=self.config.headers, data=self._record.model_dump_json(exclude_none=True))
332
+ response = requests.put(url, headers=self.config.headers,
333
+ json={"id": self._record.id,
334
+ "invoiceIntegration": SaleOrderInvoiceIntegrationPut(**self._record.invoice_integration.model_dump(by_alias=True)).model_dump()})
297
335
  if not response.ok:
298
336
  raise Exception(f"Error on resposne {response.text}")
299
- return SaleOrder(**response.json())
337
+ return response.ok
300
338
 
301
339
  def search(self, params: SearchSalesOrderParams):
302
340
  endpoint: str = f"search/{self.endpoint}"
@@ -308,41 +346,46 @@ class SaleOrderService(BaseService[SaleOrder]):
308
346
  headers=headers,
309
347
  )
310
348
  if not response.ok:
311
- raise Exception(f"Error on resposne {response.text}")
312
- return SearchSalesOrder(**response.json())
349
+ raise Exception(f"Error on resposne {response.status_code} - {response.text}")
350
+ response_data = response.json()
351
+ return SearchSalesOrder(**response_data)
313
352
 
314
- def add_payment(self, payload: "Payment") -> "Payment":
353
+ def add_payment(self, payload) -> Payment:
315
354
  if not self._record:
316
355
  raise Exception("You need to add a record id")
356
+ payment = Payment(**payload)
317
357
  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)
358
+ res = requests.post(url, json=payment.model_dump(by_alias=True, exclude_none=True), headers=self.config.headers)
319
359
  if not res.ok:
320
360
  raise Exception(f"Error on resposne {res.text}")
321
361
  return Payment(**res.json())
322
362
 
323
- def update_payment(self, payment_id: int, payload: "Payment") -> "Payment":
363
+ def update_payment(self, payment_id: int, payload) -> "Payment":
324
364
  if not self._record:
325
365
  raise Exception("You need to add a record id")
366
+ payment = Payment(**payload)
326
367
  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)
368
+ res = requests.put(url, json=payment.model_dump(by_alias=True, exclude_none=True), headers=self.config.headers)
328
369
  if not res.ok:
329
370
  raise Exception(f"Error on payment update {res.text}")
330
371
  return Payment(**res.json())
331
372
 
332
- def add_shipment(self, payload: "Shipment") -> "Shipment":
373
+ def add_shipment(self, payload) -> "Shipment":
333
374
  if not self._record:
334
375
  raise Exception("You need to add a record id")
376
+ shipment = Shipment(**payload)
335
377
  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)
378
+ res = requests.post(url, json=shipment.model_dump(by_alias=True, exclude_none=True), headers=self.config.headers)
337
379
  if not res.ok:
338
380
  raise Exception(f"Error on shipment add {res.text}")
339
381
  return Shipment(**res.json())
340
382
 
341
- def update_shipment(self, shipment_id: str, payload: "Shipment") -> "Shipment":
383
+ def update_shipment(self, shipment_id: str, payload) -> "Shipment":
342
384
  if not self._record:
343
385
  raise Exception("You need to add a record id")
386
+ shipment = Shipment(**payload)
344
387
  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)
388
+ res = requests.put(url, json=shipment.model_dump(by_alias=True, exclude_none=True), headers=self.config.headers)
346
389
  if not res.ok:
347
390
  raise Exception(f"Error on shipment update {res.text}")
348
391
  return Shipment(**res.json())