mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Fix: Allow allocation of variants to sales order lines (#5656)
* Add tests for allocating a variant to a sales order line * Add check for variants to match template allocation * Tweak fixtures for inventree-python, improve test checks * Optimize check for item variants
This commit is contained in:
parent
06eb948528
commit
c18bc4e1d1
@ -1602,7 +1602,9 @@ class SalesOrderAllocation(models.Model):
|
||||
|
||||
try:
|
||||
if self.line.part != self.item.part:
|
||||
errors['item'] = _('Cannot allocate stock item to a line with a different part')
|
||||
variants = self.line.part.get_descendants(include_self=True)
|
||||
if self.line.part not in variants:
|
||||
errors['item'] = _('Cannot allocate stock item to a line with a different part')
|
||||
except PartModels.Part.DoesNotExist:
|
||||
errors['line'] = _('Cannot allocate stock to a line without a part')
|
||||
|
||||
|
@ -1716,7 +1716,7 @@ class SalesOrderAllocateTest(OrderTest):
|
||||
self.assertIn('Shipment is not associated with this order', str(response.data['shipment']))
|
||||
|
||||
def test_allocate(self):
|
||||
"""Test the the allocation endpoint acts as expected, when provided with valid data!"""
|
||||
"""Test that the allocation endpoint acts as expected, when provided with valid data!"""
|
||||
# First, check that there are no line items allocated against this SalesOrder
|
||||
self.assertEqual(self.order.stock_allocations.count(), 0)
|
||||
|
||||
@ -1745,6 +1745,43 @@ class SalesOrderAllocateTest(OrderTest):
|
||||
for line in self.order.lines.all():
|
||||
self.assertEqual(line.allocations.count(), 1)
|
||||
|
||||
def test_allocate_variant(self):
|
||||
"""Test that the allocation endpoint acts as expected, when provided with variant"""
|
||||
# First, check that there are no line items allocated against this SalesOrder
|
||||
self.assertEqual(self.order.stock_allocations.count(), 0)
|
||||
|
||||
data = {
|
||||
"items": [],
|
||||
"shipment": self.shipment.pk,
|
||||
}
|
||||
|
||||
def check_template(line_item):
|
||||
return line_item.part.is_template
|
||||
|
||||
for line in filter(check_template, self.order.lines.all()):
|
||||
|
||||
stock_item = None
|
||||
|
||||
# Allocate a matching variant
|
||||
parts = Part.objects.filter(salable=True).filter(variant_of=line.part.pk)
|
||||
for part in parts:
|
||||
stock_item = part.stock_items.last()
|
||||
break
|
||||
|
||||
# Fully-allocate each line
|
||||
data['items'].append({
|
||||
"line_item": line.pk,
|
||||
"stock_item": stock_item.pk,
|
||||
"quantity": 5
|
||||
})
|
||||
|
||||
self.post(self.url, data, expected_code=201)
|
||||
|
||||
# At least one item should be allocated, and all should be variants
|
||||
self.assertGreater(self.order.stock_allocations.count(), 0)
|
||||
for allocation in self.order.stock_allocations.all():
|
||||
self.assertNotEquals(allocation.item.part.pk, allocation.line.part.pk)
|
||||
|
||||
def test_shipment_complete(self):
|
||||
"""Test that we can complete a shipment via the API."""
|
||||
url = reverse('api-so-shipment-ship', kwargs={'pk': self.shipment.pk})
|
||||
|
@ -33,11 +33,23 @@ class SalesOrderTest(TestCase):
|
||||
cls.customer = Company.objects.create(name="ABC Co", description="My customer", is_customer=True)
|
||||
|
||||
# Create a Part to ship
|
||||
cls.part = Part.objects.create(name='Spanner', salable=True, description='A spanner that I sell')
|
||||
cls.part = Part.objects.create(
|
||||
name='Spanner',
|
||||
salable=True,
|
||||
description='A spanner that I sell',
|
||||
is_template=True,
|
||||
)
|
||||
cls.variant = Part.objects.create(
|
||||
name='Blue Spanner',
|
||||
salable=True,
|
||||
description='A blue spanner that I sell',
|
||||
variant_of=cls.part,
|
||||
)
|
||||
|
||||
# Create some stock!
|
||||
cls.Sa = StockItem.objects.create(part=cls.part, quantity=100)
|
||||
cls.Sb = StockItem.objects.create(part=cls.part, quantity=200)
|
||||
cls.Sc = StockItem.objects.create(part=cls.variant, quantity=100)
|
||||
|
||||
# Create a SalesOrder to ship against
|
||||
cls.order = SalesOrder.objects.create(
|
||||
@ -145,6 +157,16 @@ class SalesOrderTest(TestCase):
|
||||
self.assertTrue(self.line.is_fully_allocated())
|
||||
self.assertEqual(self.line.allocated_quantity(), 50)
|
||||
|
||||
def test_allocate_variant(self):
|
||||
"""Allocate a variant of the designated item"""
|
||||
SalesOrderAllocation.objects.create(
|
||||
line=self.line,
|
||||
shipment=self.shipment,
|
||||
item=StockItem.objects.get(pk=self.Sc.pk),
|
||||
quantity=50
|
||||
)
|
||||
self.assertEqual(self.line.allocated_quantity(), 50)
|
||||
|
||||
def test_order_cancel(self):
|
||||
"""Allocate line items then cancel the order"""
|
||||
self.allocate_stock(True)
|
||||
@ -166,8 +188,8 @@ class SalesOrderTest(TestCase):
|
||||
def test_complete_order(self):
|
||||
"""Allocate line items, then ship the order"""
|
||||
# Assert some stuff before we run the test
|
||||
# Initially there are two stock items
|
||||
self.assertEqual(StockItem.objects.count(), 2)
|
||||
# Initially there are three stock items
|
||||
self.assertEqual(StockItem.objects.count(), 3)
|
||||
|
||||
# Take 25 units from each StockItem
|
||||
self.allocate_stock(True)
|
||||
@ -194,15 +216,17 @@ class SalesOrderTest(TestCase):
|
||||
self.assertEqual(self.order.status, status.SalesOrderStatus.SHIPPED)
|
||||
self.assertIsNotNone(self.order.shipment_date)
|
||||
|
||||
# There should now be 4 stock items
|
||||
self.assertEqual(StockItem.objects.count(), 4)
|
||||
# There should now be 5 stock items
|
||||
self.assertEqual(StockItem.objects.count(), 5)
|
||||
|
||||
sa = StockItem.objects.get(pk=self.Sa.pk)
|
||||
sb = StockItem.objects.get(pk=self.Sb.pk)
|
||||
sc = StockItem.objects.get(pk=self.Sc.pk)
|
||||
|
||||
# 25 units subtracted from each of the original items
|
||||
# 25 units subtracted from each of the original non-variant items
|
||||
self.assertEqual(sa.quantity, 75)
|
||||
self.assertEqual(sb.quantity, 175)
|
||||
self.assertEqual(sc.quantity, 100)
|
||||
|
||||
# And 2 items created which are associated with the order
|
||||
outputs = StockItem.objects.filter(sales_order=self.order)
|
||||
|
@ -156,6 +156,7 @@
|
||||
variant_of: 10000
|
||||
IPN: "R.CH"
|
||||
trackable: true
|
||||
salable: true
|
||||
category: 7
|
||||
tree_id: 1
|
||||
level: 0
|
||||
|
Loading…
Reference in New Issue
Block a user