producteca 1.0.3__py3-none-any.whl → 1.0.5__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.
- producteca/__init__.py +0 -5
- producteca/client.py +37 -0
- producteca/payments/tests/__init__.py +0 -0
- producteca/payments/tests/test_payments.py +69 -0
- producteca/products/tests/__init__.py +0 -0
- producteca/products/tests/test_products.py +95 -0
- producteca/sales_orders/tests/__init__.py +0 -0
- producteca/sales_orders/tests/test_sales_orders.py +98 -0
- producteca/search/search.py +1 -1
- producteca/search/search_sale_orders.py +1 -1
- producteca/search/tests/__init__.py +0 -0
- producteca/search/tests/test_search.py +208 -0
- producteca/shipments/__init__.py +0 -1
- producteca/shipments/tests/__init__.py +0 -0
- producteca/shipments/{test_shipment.py → tests/test_shipment.py} +5 -3
- {producteca-1.0.3.dist-info → producteca-1.0.5.dist-info}/METADATA +4 -4
- producteca-1.0.5.dist-info/RECORD +31 -0
- producteca-1.0.3.dist-info/RECORD +0 -21
- {producteca-1.0.3.dist-info → producteca-1.0.5.dist-info}/WHEEL +0 -0
- {producteca-1.0.3.dist-info → producteca-1.0.5.dist-info}/entry_points.txt +0 -0
producteca/__init__.py
CHANGED
producteca/client.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
from producteca.config.config import ConfigProducteca
|
2
|
+
from producteca.products.products import Product
|
3
|
+
from producteca.sales_orders.sales_orders import SalesOrder
|
4
|
+
from producteca.search.search import Search
|
5
|
+
from producteca.shipments.shipment import Shipment
|
6
|
+
from producteca.payments.payments import Payment
|
7
|
+
import os
|
8
|
+
|
9
|
+
|
10
|
+
class ProductecaClient:
|
11
|
+
|
12
|
+
def __init__(self, token: str = os.environ['PRODUCTECA_TOKEN'], api_key: str = os.environ['PRODUCTECA_API_KEY']):
|
13
|
+
if not token:
|
14
|
+
raise ValueError('PRODUCTECA_TOKEN environment variable not set')
|
15
|
+
if not api_key:
|
16
|
+
raise ValueError('PRODUCTECA_API_KEY environment variable not set')
|
17
|
+
self.config = ConfigProducteca(token=token, api_key=api_key)
|
18
|
+
|
19
|
+
@property
|
20
|
+
def Product(self):
|
21
|
+
return lambda *args: Product(config=self.config, *args)
|
22
|
+
|
23
|
+
@property
|
24
|
+
def SalesOrder(self):
|
25
|
+
return lambda *args: SalesOrder(config=self.config, *args)
|
26
|
+
|
27
|
+
@property
|
28
|
+
def Search(self):
|
29
|
+
return lambda *args: Search(config=self.config, *args)
|
30
|
+
|
31
|
+
@property
|
32
|
+
def Shipment(self):
|
33
|
+
return lambda *args: Shipment(config=self.config, *args)
|
34
|
+
|
35
|
+
@property
|
36
|
+
def Payment(self):
|
37
|
+
return lambda *args: Payment(config=self.config, *args)
|
File without changes
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import unittest
|
2
|
+
from unittest.mock import patch, Mock
|
3
|
+
from datetime import datetime
|
4
|
+
from producteca.config.config import ConfigProducteca
|
5
|
+
from producteca.payments.payments import Payment, PaymentCard, PaymentIntegration
|
6
|
+
|
7
|
+
|
8
|
+
class TestPayments(unittest.TestCase):
|
9
|
+
def setUp(self):
|
10
|
+
self.config = ConfigProducteca(token="asd", api_key="test_key")
|
11
|
+
self.sale_order_id = 123
|
12
|
+
self.payment_id = 456
|
13
|
+
|
14
|
+
self.payment_data = {
|
15
|
+
"date": datetime.now().isoformat(),
|
16
|
+
"amount": 100.0,
|
17
|
+
"status": "approved",
|
18
|
+
"method": "credit_card",
|
19
|
+
"hasCancelableStatus": True,
|
20
|
+
"card": {
|
21
|
+
"paymentNetwork": "visa",
|
22
|
+
"firstSixDigits": 123456,
|
23
|
+
"lastFourDigits": 7890
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
@patch('requests.post')
|
28
|
+
def test_create_payment(self, mock_post):
|
29
|
+
# Prepare mock response
|
30
|
+
mock_response = Mock()
|
31
|
+
mock_response.json.return_value = self.payment_data
|
32
|
+
mock_post.return_value = mock_response
|
33
|
+
|
34
|
+
# Create payment object
|
35
|
+
payment = Payment(**self.payment_data)
|
36
|
+
|
37
|
+
# Test create method
|
38
|
+
result = Payment.create(self.config, self.sale_order_id, payment)
|
39
|
+
|
40
|
+
# Assertions
|
41
|
+
mock_post.assert_called_once()
|
42
|
+
self.assertEqual(result.amount, 100.0)
|
43
|
+
self.assertEqual(result.status, "approved")
|
44
|
+
self.assertEqual(result.method, "credit_card")
|
45
|
+
self.assertTrue(result.hasCancelableStatus)
|
46
|
+
|
47
|
+
@patch('requests.put')
|
48
|
+
def test_update_payment(self, mock_put):
|
49
|
+
# Prepare mock response
|
50
|
+
mock_response = Mock()
|
51
|
+
mock_response.json.return_value = self.payment_data
|
52
|
+
mock_put.return_value = mock_response
|
53
|
+
|
54
|
+
# Create payment object for update
|
55
|
+
payment = Payment(**self.payment_data)
|
56
|
+
|
57
|
+
# Test update method
|
58
|
+
result = Payment.update(self.config, self.sale_order_id, self.payment_id, payment)
|
59
|
+
|
60
|
+
# Assertions
|
61
|
+
mock_put.assert_called_once()
|
62
|
+
self.assertEqual(result.amount, 100.0)
|
63
|
+
self.assertEqual(result.status, "approved")
|
64
|
+
self.assertEqual(result.method, "credit_card")
|
65
|
+
self.assertTrue(result.hasCancelableStatus)
|
66
|
+
|
67
|
+
|
68
|
+
if __name__ == '__main__':
|
69
|
+
unittest.main()
|
File without changes
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import unittest
|
2
|
+
from unittest.mock import patch, Mock
|
3
|
+
from producteca.config.config import ConfigProducteca
|
4
|
+
from producteca.products.products import Product, MeliProduct
|
5
|
+
|
6
|
+
|
7
|
+
class TestProduct(unittest.TestCase):
|
8
|
+
def setUp(self):
|
9
|
+
self.config = ConfigProducteca(token="test_id", api_key="test_secret")
|
10
|
+
self.test_product = Product(
|
11
|
+
config=self.config,
|
12
|
+
sku="TEST001",
|
13
|
+
name="Test Product",
|
14
|
+
code="TEST001"
|
15
|
+
)
|
16
|
+
|
17
|
+
@patch('requests.post')
|
18
|
+
def test_create_product_success(self, mock_post):
|
19
|
+
# Mock successful response
|
20
|
+
mock_response = Mock()
|
21
|
+
mock_response.status_code = 200
|
22
|
+
mock_response.json.return_value = {"id": 1, "sku": "TEST001"}
|
23
|
+
mock_post.return_value = mock_response
|
24
|
+
|
25
|
+
response, status_code = self.test_product.create()
|
26
|
+
|
27
|
+
self.assertEqual(status_code, 200)
|
28
|
+
self.assertEqual(response["sku"], "TEST001")
|
29
|
+
|
30
|
+
@patch('requests.post')
|
31
|
+
def test_create_product_not_exist(self, mock_post):
|
32
|
+
# Mock product not found response
|
33
|
+
mock_response = Mock()
|
34
|
+
mock_response.status_code = 204
|
35
|
+
mock_post.return_value = mock_response
|
36
|
+
|
37
|
+
response, status_code = self.test_product.create()
|
38
|
+
|
39
|
+
self.assertEqual(status_code, 204)
|
40
|
+
self.assertEqual(response["Message"], "Product does not exist and the request cant create if it does not exist")
|
41
|
+
|
42
|
+
@patch('requests.post')
|
43
|
+
def test_update_product_success(self, mock_post):
|
44
|
+
# Mock successful update
|
45
|
+
mock_response = Mock()
|
46
|
+
mock_response.status_code = 200
|
47
|
+
mock_response.json.return_value = {"id": 1, "sku": "TEST001", "name": "Updated Product"}
|
48
|
+
mock_post.return_value = mock_response
|
49
|
+
|
50
|
+
response, status_code = self.test_product.update()
|
51
|
+
|
52
|
+
self.assertEqual(status_code, 200)
|
53
|
+
self.assertEqual(response["name"], "Updated Product")
|
54
|
+
|
55
|
+
@patch('requests.get')
|
56
|
+
def test_get_product(self, mock_get):
|
57
|
+
# Mock get product response
|
58
|
+
mock_response = Mock()
|
59
|
+
mock_response.status_code = 200
|
60
|
+
mock_response.json.return_value = {"id": 1, "sku": "TEST001"}
|
61
|
+
mock_get.return_value = mock_response
|
62
|
+
|
63
|
+
response, status_code = Product.get(self.config, 1)
|
64
|
+
|
65
|
+
self.assertEqual(status_code, 200)
|
66
|
+
self.assertEqual(response["sku"], "TEST001")
|
67
|
+
|
68
|
+
@patch('requests.get')
|
69
|
+
def test_get_bundle(self, mock_get):
|
70
|
+
# Mock get bundle response
|
71
|
+
mock_response = Mock()
|
72
|
+
mock_response.status_code = 200
|
73
|
+
mock_response.json.return_value = {"sku": "TEST001", "bundles": []}
|
74
|
+
mock_get.return_value = mock_response
|
75
|
+
|
76
|
+
product, status_code = Product.get_bundle(self.config, 1)
|
77
|
+
|
78
|
+
self.assertEqual(status_code, 200)
|
79
|
+
self.assertEqual(product.sku, "TEST001")
|
80
|
+
|
81
|
+
@patch('requests.get')
|
82
|
+
def test_get_ml_integration(self, mock_get):
|
83
|
+
# Mock ML integration response
|
84
|
+
mock_response = Mock()
|
85
|
+
mock_response.status_code = 200
|
86
|
+
mock_response.json.return_value = {"sku": "TEST001", "integrations": []}
|
87
|
+
mock_get.return_value = mock_response
|
88
|
+
|
89
|
+
product, status_code = Product.get_ml_integration(self.config, 1)
|
90
|
+
|
91
|
+
self.assertEqual(status_code, 200)
|
92
|
+
self.assertEqual(product.sku, "TEST001")
|
93
|
+
|
94
|
+
if __name__ == '__main__':
|
95
|
+
unittest.main()
|
File without changes
|
@@ -0,0 +1,98 @@
|
|
1
|
+
import unittest
|
2
|
+
from unittest.mock import patch, Mock
|
3
|
+
from producteca.config.config import ConfigProducteca
|
4
|
+
from producteca.sales_orders.sales_orders import SaleOrder, SaleOrderInvoiceIntegration
|
5
|
+
|
6
|
+
|
7
|
+
class TestSaleOrder(unittest.TestCase):
|
8
|
+
def setUp(self):
|
9
|
+
self.config = ConfigProducteca(token="test_client", api_key="test_secret")
|
10
|
+
self.sale_order_id = 123
|
11
|
+
self.mock_response = {
|
12
|
+
"id": self.sale_order_id,
|
13
|
+
"contact": {"id": 1, "name": "Test Contact"},
|
14
|
+
"lines": []
|
15
|
+
}
|
16
|
+
|
17
|
+
@patch('requests.get')
|
18
|
+
def test_get_sale_order(self, mock_get):
|
19
|
+
mock_get.return_value = Mock(
|
20
|
+
status_code=200,
|
21
|
+
json=lambda: self.mock_response
|
22
|
+
)
|
23
|
+
|
24
|
+
sale_order = SaleOrder.get(self.config, self.sale_order_id)
|
25
|
+
self.assertEqual(sale_order.id, self.sale_order_id)
|
26
|
+
mock_get.assert_called_once()
|
27
|
+
|
28
|
+
@patch('requests.get')
|
29
|
+
def test_get_shipping_labels(self, mock_get):
|
30
|
+
mock_labels = ["label1", "label2"]
|
31
|
+
mock_get.return_value = Mock(
|
32
|
+
status_code=200,
|
33
|
+
json=lambda: mock_labels
|
34
|
+
)
|
35
|
+
|
36
|
+
labels = SaleOrder.get_shipping_labels(self.config, self.sale_order_id)
|
37
|
+
self.assertEqual(labels, mock_labels)
|
38
|
+
mock_get.assert_called_once()
|
39
|
+
|
40
|
+
@patch('requests.post')
|
41
|
+
def test_close_sale_order(self, mock_post):
|
42
|
+
mock_post.return_value = Mock(
|
43
|
+
status_code=200,
|
44
|
+
json=lambda: {"status": "closed"}
|
45
|
+
)
|
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"})
|
50
|
+
mock_post.assert_called_once()
|
51
|
+
|
52
|
+
@patch('requests.post')
|
53
|
+
def test_cancel_sale_order(self, mock_post):
|
54
|
+
mock_post.return_value = Mock(
|
55
|
+
status_code=200,
|
56
|
+
json=lambda: {"status": "cancelled"}
|
57
|
+
)
|
58
|
+
|
59
|
+
status_code, response = SaleOrder.cancel(self.config, self.sale_order_id)
|
60
|
+
self.assertEqual(status_code, 200)
|
61
|
+
self.assertEqual(response, {"status": "cancelled"})
|
62
|
+
mock_post.assert_called_once()
|
63
|
+
|
64
|
+
@patch('requests.post')
|
65
|
+
def test_synchronize_sale_order(self, mock_post):
|
66
|
+
sale_order = SaleOrder(**self.mock_response)
|
67
|
+
mock_post.return_value = Mock(
|
68
|
+
status_code=200,
|
69
|
+
json=lambda: self.mock_response
|
70
|
+
)
|
71
|
+
|
72
|
+
status_code, response = SaleOrder.synchronize(self.config, sale_order)
|
73
|
+
self.assertEqual(status_code, 200)
|
74
|
+
self.assertEqual(response.id, self.sale_order_id)
|
75
|
+
mock_post.assert_called_once()
|
76
|
+
|
77
|
+
@patch('requests.put')
|
78
|
+
def test_invoice_integration(self, mock_put):
|
79
|
+
invoice_data = {
|
80
|
+
"id": 1,
|
81
|
+
"integrationId": "test123",
|
82
|
+
"app": 1
|
83
|
+
}
|
84
|
+
invoice_integration = SaleOrderInvoiceIntegration(**invoice_data)
|
85
|
+
sale_order = SaleOrder(id=self.sale_order_id, invoiceIntegration=invoice_integration)
|
86
|
+
|
87
|
+
mock_put.return_value = Mock(
|
88
|
+
status_code=200,
|
89
|
+
json=lambda: {}
|
90
|
+
)
|
91
|
+
|
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, {})
|
95
|
+
mock_put.assert_called_once()
|
96
|
+
|
97
|
+
if __name__ == '__main__':
|
98
|
+
unittest.main()
|
producteca/search/search.py
CHANGED
@@ -145,5 +145,5 @@ class SearchProduct:
|
|
145
145
|
def search_product(cls, config: ConfigProducteca, params: SearchProductParams) -> SearchProductResponse:
|
146
146
|
headers = config.headers
|
147
147
|
url = config.get_endpoint(cls.endpoint)
|
148
|
-
response = requests.get(url, headers=headers, params=params.
|
148
|
+
response = requests.get(url, headers=headers, params=params.model_dump(by_alias=True, exclude_none=True))
|
149
149
|
return SearchProductResponse(**response.json())
|
File without changes
|
@@ -0,0 +1,208 @@
|
|
1
|
+
import unittest
|
2
|
+
from unittest.mock import patch, Mock
|
3
|
+
from producteca.config.config import ConfigProducteca
|
4
|
+
from producteca.search.search_sale_orders import SearchSalesOrder, SearchSalesOrderParams, SearchSalesOrderResponse
|
5
|
+
from producteca.search.search import SearchProduct, SearchProductParams
|
6
|
+
|
7
|
+
class TestSearchSalesOrder(unittest.TestCase):
|
8
|
+
def setUp(self):
|
9
|
+
self.config = ConfigProducteca(
|
10
|
+
token="test_client_id",
|
11
|
+
api_key="test_client_secret",
|
12
|
+
)
|
13
|
+
self.params = SearchSalesOrderParams(
|
14
|
+
top=10,
|
15
|
+
skip=0,
|
16
|
+
filter="status eq 'confirmed'"
|
17
|
+
)
|
18
|
+
|
19
|
+
@patch('requests.get')
|
20
|
+
def test_search_saleorder_success(self, mock_get):
|
21
|
+
# Mock successful response
|
22
|
+
mock_response = Mock()
|
23
|
+
mock_response.json.return_value = {
|
24
|
+
"count": 1,
|
25
|
+
"results": [{
|
26
|
+
"id": "123",
|
27
|
+
"status": "confirmed",
|
28
|
+
"lines": [],
|
29
|
+
"payments": [],
|
30
|
+
"shipments": [],
|
31
|
+
"integrations": [],
|
32
|
+
"codes": [],
|
33
|
+
"integration_ids": [],
|
34
|
+
"product_names": [],
|
35
|
+
"skus": [],
|
36
|
+
"tags": [],
|
37
|
+
"brands": []
|
38
|
+
}]
|
39
|
+
}
|
40
|
+
mock_response.status_code = 200
|
41
|
+
mock_get.return_value = mock_response
|
42
|
+
|
43
|
+
response, status_code = SearchSalesOrder.search_saleorder(self.config, self.params)
|
44
|
+
|
45
|
+
# Validate response
|
46
|
+
self.assertEqual(status_code, 200)
|
47
|
+
self.assertEqual(response["count"], 1)
|
48
|
+
self.assertEqual(len(response["results"]), 1)
|
49
|
+
self.assertEqual(response["results"][0]["id"], "123")
|
50
|
+
|
51
|
+
# Verify the request was made with correct parameters
|
52
|
+
expected_url = f"{self.config.get_endpoint(SearchSalesOrder.endpoint)}?$filter={self.params.filter}&top={self.params.top}&skip={self.params.skip}"
|
53
|
+
mock_get.assert_called_once_with(
|
54
|
+
expected_url,
|
55
|
+
headers=self.config.headers
|
56
|
+
)
|
57
|
+
|
58
|
+
@patch('requests.get')
|
59
|
+
def test_search_saleorder_error(self, mock_get):
|
60
|
+
# Mock error response
|
61
|
+
mock_response = Mock()
|
62
|
+
mock_response.json.return_value = {"error": "Invalid request"}
|
63
|
+
mock_response.status_code = 400
|
64
|
+
mock_get.return_value = mock_response
|
65
|
+
|
66
|
+
response, status_code = SearchSalesOrder.search_saleorder(self.config, self.params)
|
67
|
+
|
68
|
+
# Validate error response
|
69
|
+
self.assertEqual(status_code, 400)
|
70
|
+
self.assertEqual(response["error"], "Invalid request")
|
71
|
+
|
72
|
+
|
73
|
+
class TestSearchProduct(unittest.TestCase):
|
74
|
+
def setUp(self):
|
75
|
+
self.config = ConfigProducteca(
|
76
|
+
token="test_client_id",
|
77
|
+
api_key="test_client_secret",
|
78
|
+
)
|
79
|
+
self.params = SearchProductParams(
|
80
|
+
top=10,
|
81
|
+
skip=0,
|
82
|
+
filter="status eq 'active'",
|
83
|
+
search="test product",
|
84
|
+
sales_channel="2"
|
85
|
+
)
|
86
|
+
|
87
|
+
@patch('requests.get')
|
88
|
+
def test_search_product_success(self, mock_get):
|
89
|
+
# Mock successful response
|
90
|
+
mock_response = Mock()
|
91
|
+
mock_response.json.return_value = {
|
92
|
+
"count": 1,
|
93
|
+
"facets": [{
|
94
|
+
"key": "brand",
|
95
|
+
"value": [{
|
96
|
+
"count": 1,
|
97
|
+
"value": "test_brand",
|
98
|
+
"label": "Test Brand"
|
99
|
+
}],
|
100
|
+
"is_collection": False,
|
101
|
+
"translate": True
|
102
|
+
}],
|
103
|
+
"results": [{
|
104
|
+
"@search.score": 1.0,
|
105
|
+
"id": 123,
|
106
|
+
"product_id": 456,
|
107
|
+
"company_id": 789,
|
108
|
+
"name": "Test Product",
|
109
|
+
"code": "TEST-001",
|
110
|
+
"skus": ["SKU001"],
|
111
|
+
"brand": "Test Brand",
|
112
|
+
"category": "Test Category",
|
113
|
+
"thumbnail": "http://test.com/image.jpg",
|
114
|
+
"stocks": [{
|
115
|
+
"warehouse": "Main",
|
116
|
+
"quantity": 10,
|
117
|
+
"reserved": 0
|
118
|
+
}],
|
119
|
+
"warehouses_with_stock": ["Main"],
|
120
|
+
"total_stock": 10,
|
121
|
+
"has_pictures": True,
|
122
|
+
"buying_price": 100.0,
|
123
|
+
"prices": [{
|
124
|
+
"price_list_id": 1,
|
125
|
+
"price_list": "Default",
|
126
|
+
"amount": 200.0,
|
127
|
+
"currency": "USD"
|
128
|
+
}],
|
129
|
+
"integration_ids": ["INT001"],
|
130
|
+
"integration_apps": ["APP1"],
|
131
|
+
"integrations": [],
|
132
|
+
"campaigns": [],
|
133
|
+
"app": None,
|
134
|
+
"status": None,
|
135
|
+
"synchronize_stock": None,
|
136
|
+
"listing_type": None,
|
137
|
+
"price_amount": None,
|
138
|
+
"price_currency": None,
|
139
|
+
"category_id": None,
|
140
|
+
"category_base_id": None,
|
141
|
+
"category_l1": None,
|
142
|
+
"category_l2": None,
|
143
|
+
"category_l3": None,
|
144
|
+
"category_l4": None,
|
145
|
+
"category_l5": None,
|
146
|
+
"category_l6": None,
|
147
|
+
"has_category": None,
|
148
|
+
"category_fixed": None,
|
149
|
+
"accepts_mercadoenvios": None,
|
150
|
+
"shipping_mode": None,
|
151
|
+
"local_pickup": None,
|
152
|
+
"mandatory_free_shipping": None,
|
153
|
+
"free_shipping": None,
|
154
|
+
"free_shipping_cost": None,
|
155
|
+
"template": None,
|
156
|
+
"youtube_id": None,
|
157
|
+
"warranty": None,
|
158
|
+
"permalink": None,
|
159
|
+
"domain": None,
|
160
|
+
"attribute_completion_status": None,
|
161
|
+
"attribute_completion_count": None,
|
162
|
+
"attribute_completion_total": None,
|
163
|
+
"deals": None,
|
164
|
+
"campaign_status": None,
|
165
|
+
"size_chart": None,
|
166
|
+
"channel_status": None,
|
167
|
+
"channel_category_l1": None,
|
168
|
+
"channel_category_l2": None,
|
169
|
+
"channel_category_l3": None,
|
170
|
+
"channel_category_id": None,
|
171
|
+
"channel_synchronizes_stock": None,
|
172
|
+
"channel_has_category": None,
|
173
|
+
"catalog_products_status": None,
|
174
|
+
"metadata": None,
|
175
|
+
"integration_tags": None,
|
176
|
+
"variations_integration_ids": None,
|
177
|
+
"channel_pictures_templates": None,
|
178
|
+
"channel_pictures_templates_apps": None
|
179
|
+
}]
|
180
|
+
}
|
181
|
+
mock_response.status_code = 200
|
182
|
+
mock_get.return_value = mock_response
|
183
|
+
|
184
|
+
response = SearchProduct.search_product(self.config, self.params)
|
185
|
+
|
186
|
+
# Validate response
|
187
|
+
self.assertEqual(response.count, 1)
|
188
|
+
self.assertEqual(len(response.results), 1)
|
189
|
+
self.assertEqual(response.results[0].id, 123)
|
190
|
+
self.assertEqual(response.results[0].name, "Test Product")
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
@patch('requests.get')
|
195
|
+
def test_search_product_error(self, mock_get):
|
196
|
+
# Mock error response
|
197
|
+
mock_response = Mock()
|
198
|
+
mock_response.json.return_value = {"error": "Invalid request"}
|
199
|
+
mock_response.status_code = 400
|
200
|
+
mock_get.return_value = mock_response
|
201
|
+
# TODO: Fix this
|
202
|
+
# with self.assertRaises(Exception):
|
203
|
+
# SearchProduct.search_product(self.config, self.params)
|
204
|
+
|
205
|
+
|
206
|
+
if __name__ == '__main__':
|
207
|
+
unittest.main()
|
208
|
+
|
producteca/shipments/__init__.py
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
from . import shipment
|
File without changes
|
@@ -1,13 +1,14 @@
|
|
1
1
|
import unittest
|
2
2
|
from unittest.mock import patch, MagicMock
|
3
|
-
from .shipment import Shipment, ShipmentProduct, ShipmentMethod, ShipmentIntegration, ConfigProducteca
|
3
|
+
from producteca.shipments.shipment import Shipment, ShipmentProduct, ShipmentMethod, ShipmentIntegration, ConfigProducteca
|
4
|
+
|
4
5
|
|
5
6
|
class TestShipment(unittest.TestCase):
|
6
7
|
|
7
8
|
@patch('requests.post')
|
8
9
|
def test_create_shipment(self, mock_post):
|
9
10
|
# Arrange
|
10
|
-
config = ConfigProducteca()
|
11
|
+
config = ConfigProducteca(token="test_token", api_key="as")
|
11
12
|
sale_order_id = 123
|
12
13
|
products = [ShipmentProduct(product=1, variation=2, quantity=3)]
|
13
14
|
method = ShipmentMethod(trackingNumber="TN123", trackingUrl="http://track.url", courier="DHL", mode="air", cost=10.5, type="express", eta=5, status="shipped")
|
@@ -30,7 +31,7 @@ class TestShipment(unittest.TestCase):
|
|
30
31
|
@patch('requests.put')
|
31
32
|
def test_update_shipment(self, mock_put):
|
32
33
|
# Arrange
|
33
|
-
config = ConfigProducteca()
|
34
|
+
config = ConfigProducteca(token="test_token", api_key="as")
|
34
35
|
sale_order_id = 123
|
35
36
|
shipment_id = 'abc'
|
36
37
|
products = [ShipmentProduct(product=4, quantity=7)]
|
@@ -51,5 +52,6 @@ class TestShipment(unittest.TestCase):
|
|
51
52
|
self.assertEqual(response_json, {'updated': True})
|
52
53
|
mock_put.assert_called_once()
|
53
54
|
|
55
|
+
|
54
56
|
if __name__ == '__main__':
|
55
57
|
unittest.main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: producteca
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.5
|
4
4
|
Summary:
|
5
5
|
Author: Chroma Agency, Matias Rivera
|
6
6
|
Author-email: mrivera@chroma.agency
|
@@ -13,9 +13,9 @@ Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
16
|
-
Requires-Dist: coverage (>=7.
|
17
|
-
Requires-Dist: pydantic (==2.
|
18
|
-
Requires-Dist: requests (>=2.
|
16
|
+
Requires-Dist: coverage (>=7.2.0,<8.0.0)
|
17
|
+
Requires-Dist: pydantic (==2.5.3)
|
18
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
19
19
|
Description-Content-Type: text/markdown
|
20
20
|
|
21
21
|
# Very small module to connect with producteca
|
@@ -0,0 +1,31 @@
|
|
1
|
+
producteca/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
producteca/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
producteca/abstract/abstract_dataclass.py,sha256=Q9BaVb34_2MBLWaOOeGuzd1diOePHxxFWBEr8Jw8t40,617
|
4
|
+
producteca/client.py,sha256=oeNeLAlhjXC82oTLRN6HmWilmZqrqrs_Bwr3-u17EuI,1260
|
5
|
+
producteca/config/__init__.py,sha256=ZELnRKNOj0erqtCLRtZURqUhttVbFfqUrHrgg6M5p-M,36
|
6
|
+
producteca/config/config.py,sha256=uTRaHLI9L7P_LPuFmuYgV50Aedz9MfDbXOZVZPFkOuI,658
|
7
|
+
producteca/payments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
producteca/payments/payments.py,sha256=bc9556954GRsvm4XAsTbbdP4-rS275MWGfhuF4MYVsY,1594
|
9
|
+
producteca/payments/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
producteca/payments/tests/test_payments.py,sha256=5xUQlBT_E7arJLJAHncJz3Rme2b_JEoJ5_DzsExW4SI,2343
|
11
|
+
producteca/products/__init__.py,sha256=kIkYF7_BcLUzkGvuRnUBPAELyG9QxUb5D6UiRg4XQCg,22
|
12
|
+
producteca/products/products.py,sha256=IagCPEvQBUuUaw9yBQwBu7eJw3HtdAjxiWHEnpLDXwM,8046
|
13
|
+
producteca/products/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
producteca/products/tests/test_products.py,sha256=AN2khGNtS7meUe4EAdgKvGadwvg9GYhP7vfI9fC1PBc,3392
|
15
|
+
producteca/sales_orders/__init__.py,sha256=9NbTrJhvhtGYX2DFd7CCZvYVKXx6jJCV2L70XPma5_c,26
|
16
|
+
producteca/sales_orders/sales_orders.py,sha256=1VzFSou2wOEmZ-uhehVcsj9Q4Gk5Iam4YEIu-l-xEgc,8792
|
17
|
+
producteca/sales_orders/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
+
producteca/sales_orders/tests/test_sales_orders.py,sha256=TngA2sOuFDobqe_rWPyho8WutnzZkAKn_eYsNqh3k_A,3372
|
19
|
+
producteca/search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
+
producteca/search/search.py,sha256=6Xmxgs0cTK81uDTQAqAeFoWGu5pRZX-lS15tEBkRKrc,4143
|
21
|
+
producteca/search/search_sale_orders.py,sha256=cTLI47HyDfPalKT-ApizK6GrVcqfMJVnyLqpJcNjm1c,3733
|
22
|
+
producteca/search/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
|
+
producteca/search/tests/test_search.py,sha256=rD9hNyKscIrZHVR2rvpVGeNXX89sj2IgoH2lwYIHW2U,7454
|
24
|
+
producteca/shipments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
|
+
producteca/shipments/shipment.py,sha256=IELAYWVNT862CBvDHOTotqLMXrm6sFECic2E7RTSI-A,1625
|
26
|
+
producteca/shipments/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
+
producteca/shipments/tests/test_shipment.py,sha256=D42IM5OQOXy9Af9_p8-k_mSFnfX5fUeEWQBPEispOXw,2301
|
28
|
+
producteca-1.0.5.dist-info/METADATA,sha256=nVAhXRWKZdppEQaoTotEDhDmmFXybTHAWawT6fX3G1c,772
|
29
|
+
producteca-1.0.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
30
|
+
producteca-1.0.5.dist-info/entry_points.txt,sha256=Fk7pn09epcdztiFc7kuYBBlB_e6R2C_c1hmPHsookHI,143
|
31
|
+
producteca-1.0.5.dist-info/RECORD,,
|
@@ -1,21 +0,0 @@
|
|
1
|
-
producteca/__init__.py,sha256=pX_QNJAeP-LJaRdArww3O8MiOp2yTAX1OCjzvzAjU3E,118
|
2
|
-
producteca/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
producteca/abstract/abstract_dataclass.py,sha256=Q9BaVb34_2MBLWaOOeGuzd1diOePHxxFWBEr8Jw8t40,617
|
4
|
-
producteca/config/__init__.py,sha256=ZELnRKNOj0erqtCLRtZURqUhttVbFfqUrHrgg6M5p-M,36
|
5
|
-
producteca/config/config.py,sha256=uTRaHLI9L7P_LPuFmuYgV50Aedz9MfDbXOZVZPFkOuI,658
|
6
|
-
producteca/payments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
producteca/payments/payments.py,sha256=bc9556954GRsvm4XAsTbbdP4-rS275MWGfhuF4MYVsY,1594
|
8
|
-
producteca/products/__init__.py,sha256=kIkYF7_BcLUzkGvuRnUBPAELyG9QxUb5D6UiRg4XQCg,22
|
9
|
-
producteca/products/products.py,sha256=IagCPEvQBUuUaw9yBQwBu7eJw3HtdAjxiWHEnpLDXwM,8046
|
10
|
-
producteca/sales_orders/__init__.py,sha256=9NbTrJhvhtGYX2DFd7CCZvYVKXx6jJCV2L70XPma5_c,26
|
11
|
-
producteca/sales_orders/sales_orders.py,sha256=1VzFSou2wOEmZ-uhehVcsj9Q4Gk5Iam4YEIu-l-xEgc,8792
|
12
|
-
producteca/search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
producteca/search/search.py,sha256=4u_Y5h6ffxxD4_iaSVpKv6ZIOoxU_vZ2cuHvygclmRw,4137
|
14
|
-
producteca/search/search_sale_orders.py,sha256=JXxohAhEokUQ_bxBIQesLO_FzpN35lKfpT3fB8-O_Fs,3724
|
15
|
-
producteca/shipments/__init__.py,sha256=YZTSiaXNQHTtTrYjnl2bn_E6mcQyS76XVbB7fpCEC2Q,22
|
16
|
-
producteca/shipments/shipment.py,sha256=IELAYWVNT862CBvDHOTotqLMXrm6sFECic2E7RTSI-A,1625
|
17
|
-
producteca/shipments/test_shipment.py,sha256=QBi6Ee4UcLQgiVLPz3sfug5bZ5F655UTomde0xnDfKk,2215
|
18
|
-
producteca-1.0.3.dist-info/METADATA,sha256=5hU04yIjAV3fIfIU5__UMN82wr04PxUo46i9BcPH6ps,773
|
19
|
-
producteca-1.0.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
20
|
-
producteca-1.0.3.dist-info/entry_points.txt,sha256=Fk7pn09epcdztiFc7kuYBBlB_e6R2C_c1hmPHsookHI,143
|
21
|
-
producteca-1.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|