Skip to content

Commit 39a75f5

Browse files
committed
Merge branch 'master' of https://github.com/inventree/inventree-python into add-oauth2
2 parents cf5c641 + 7b9b5a3 commit 39a75f5

File tree

9 files changed

+112
-21
lines changed

9 files changed

+112
-21
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ The InvenTree python library can be easily installed using PIP:
1818
pip install inventree
1919
```
2020

21+
If you need to rely on system certificates from the OS certificate store instead of the bundled certificates, use
22+
23+
```
24+
pip install inventree[system-certs]
25+
```
26+
27+
This allows pip and Python applications to verify TLS/SSL connections to servers whose certificates are trusted by your system, and can be helpful if you're using a custom certificate authority (CA) for your InvenTree instance's cert.
28+
2129
## Documentation
2230

2331
Refer to the [InvenTree documentation](https://docs.inventree.org/en/latest/api/python/python/)

inventree/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from . import api as inventree_api
99

10-
INVENTREE_PYTHON_VERSION = "0.17.5"
10+
INVENTREE_PYTHON_VERSION = "0.18.0"
1111

1212

1313
logger = logging.getLogger('inventree')

inventree/part.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ class BomItem(
186186
URL = 'bom'
187187

188188

189+
class BomItemSubstitute(
190+
inventree.base.InventreeObject,
191+
inventree.base.MetadataMixin,
192+
):
193+
"""Class representing the BomItemSubstitute database model"""
194+
195+
URL = "bom/substitute"
196+
197+
189198
class InternalPrice(inventree.base.InventreeObject):
190199
""" Class representing the InternalPrice model """
191200

inventree/stock.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import inventree.report
1212

1313

14+
logger = logging.getLogger('inventree')
15+
16+
1417
class StockLocation(
1518
inventree.base.BarcodeMixin,
1619
inventree.base.MetadataMixin,
@@ -58,6 +61,31 @@ class StockItem(
5861

5962
MODEL_TYPE = 'stockitem'
6063

64+
@classmethod
65+
def create(cls, api, data, **kwargs):
66+
""" Override default create method to support multiple object return. """
67+
68+
cls.checkApiVersion(api)
69+
70+
# Ensure the pk value is None so an existing object is not updated
71+
if cls.getPkField() in data.keys():
72+
data.pop(cls.getPkField())
73+
74+
response = api.post(cls.URL, data, **kwargs)
75+
76+
if response is None:
77+
logger.error("Error creating new object")
78+
return None
79+
80+
if isinstance(response, list):
81+
allResponses = []
82+
for element in response:
83+
allResponses.append(cls(api, data=element))
84+
return allResponses
85+
86+
else:
87+
return [cls(api, data=response)]
88+
6189
@classmethod
6290
def adjustStockItems(cls, api: inventree.api.InvenTreeAPI, method: str, items: list, **kwargs):
6391
"""Perform a generic stock 'adjustment' action.

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ keywords = [
2323
"stock",
2424
]
2525
dependencies = [
26-
"pip-system-certs>=4.0",
27-
"requests>=2.27.0",
26+
"requests>=2.27.0",
2827
"urllib3>=2.3.0",
2928
"requests-oauthlib",
3029
]
30+
[project.optional-dependencies]
31+
"system-certs" = ["pip-system-certs>=4.0"]
32+
3133

3234
[project.urls]
3335
Homepage = "https://github.com/inventree/inventree-python/"

test/test_api.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,7 @@ def test_create_stuff(self):
209209
'part': p.pk,
210210
'quantity': 45,
211211
'notes': 'This is a note',
212-
213-
})
212+
})[0]
214213

215214
self.assertIsNotNone(s)
216215
self.assertEqual(s.part, p.pk)
@@ -273,12 +272,12 @@ def test_add_result(self):
273272
'value': '0x123456',
274273
}
275274

276-
result = item.uploadTestResult('firmware', False, **args)
275+
result = item.uploadTestResult('firmwareversion', False, **args)
277276

278277
self.assertTrue(result)
279278

280-
item.uploadTestResult('paint', True)
281-
item.uploadTestResult('extra test', False, value='some data')
279+
item.uploadTestResult('temperaturetest', True)
280+
item.uploadTestResult('settingschecksum', False, value='some data')
282281

283282
# There should be 3 more test results now!
284283
results = item.getTestResults()

test/test_order.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,11 +269,15 @@ def test_order_complete_with_receive(self):
269269
result = po.receiveAll(location=use_location.pk)
270270

271271
# Check the result returned
272-
self.assertIsInstance(result, dict)
273-
self.assertIn('items', result)
274-
self.assertIn('location', result)
275-
# Check that all except one line were marked
276-
self.assertEqual(len(result['items']), len(po.getLineItems()) - 1)
272+
if self.api.api_version < 385: # Ref: https://github.com/inventree/InvenTree/pull/10174/
273+
self.assertIsInstance(result, dict)
274+
self.assertIn('items', result)
275+
self.assertIn('location', result)
276+
# Check that all except one line were marked
277+
self.assertEqual(len(result['items']), len(po.getLineItems()) - 1)
278+
else:
279+
self.assertIsInstance(result, list)
280+
self.assertEqual(len(result), len(po.getLineItems()) - 1)
277281

278282
# Receive all line items again - make sure answer is None
279283
# use the StockLocation item here

test/test_part.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -703,14 +703,32 @@ def test_get_requirements(self):
703703

704704
# Check for expected content
705705
self.assertIsInstance(req, dict)
706-
self.assertIn('available_stock', req)
707-
self.assertIn('on_order', req)
708-
self.assertIn('required_build_order_quantity', req)
709-
self.assertIn('allocated_build_order_quantity', req)
710-
self.assertIn('required_sales_order_quantity', req)
711-
self.assertIn('allocated_sales_order_quantity', req)
712-
self.assertIn('allocated', req)
713-
self.assertIn('required', req)
706+
707+
# Ref: https://github.com/inventree/InvenTree/pull/9798
708+
if self.api.api_version < 350:
709+
fields = [
710+
'on_order',
711+
'allocated_build_order_quantity',
712+
'allocated_sales_order_quantity',
713+
'required_build_order_quantity',
714+
'required_sales_order_quantity',
715+
]
716+
else:
717+
fields = [
718+
'total_stock',
719+
'unallocated_stock',
720+
'can_build',
721+
'ordering',
722+
'building',
723+
'scheduled_to_build',
724+
'required_for_build_orders',
725+
'allocated_to_build_orders',
726+
'required_for_sales_orders',
727+
'allocated_to_sales_orders',
728+
]
729+
730+
for f in fields:
731+
self.assertIn(f, req)
714732

715733

716734
class PartBarcodeTest(InvenTreeTestCase):

test/test_stock.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,25 @@ def test_barcode_support(self):
248248

249249
item.unassignBarcode()
250250

251+
def test_serialized(self):
252+
"""Test serializing multiple objects on create"""
253+
254+
# Create items with serial numbers
255+
items = StockItem.create(
256+
self.api,
257+
{
258+
"part": 10004,
259+
"quantity": 3,
260+
"serial_numbers": "1005,1006,1007"
261+
}
262+
)
263+
264+
self.assertEqual(3, len(items))
265+
266+
self.assertEqual('1005', items[0].serial)
267+
self.assertEqual('1006', items[1].serial)
268+
self.assertEqual('1007', items[2].serial)
269+
251270

252271
class StockAdjustTest(InvenTreeTestCase):
253272
"""Unit tests for stock 'adjustment' actions"""
@@ -407,6 +426,10 @@ def test_assign_stock(self):
407426
}
408427
)
409428

429+
# Verify a single result was returned
430+
self.assertEqual(1, len(assignitem))
431+
assignitem = assignitem[0]
432+
410433
# Assign the item
411434
assignitem.assignStock(customer=customer, notes='Sell on the side')
412435

0 commit comments

Comments
 (0)