mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Added data migration for existing SalesOrder instances
- If a SalesOrder is "PENDING" or there are allocations available, a shipment is created
This commit is contained in:
parent
2f7e0974b7
commit
ce5b47460a
@ -18,7 +18,6 @@ class Migration(migrations.Migration):
|
|||||||
name='SalesOrderShipment',
|
name='SalesOrderShipment',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('status', models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'Shipped'), (40, 'Cancelled'), (50, 'Lost'), (60, 'Returned')], default=10, help_text='Shipment status', verbose_name='Status')),
|
|
||||||
('shipment_date', models.DateField(blank=True, help_text='Date of shipment', null=True, verbose_name='Shipment Date')),
|
('shipment_date', models.DateField(blank=True, help_text='Date of shipment', null=True, verbose_name='Shipment Date')),
|
||||||
('reference', models.CharField(blank=True, help_text='Shipment reference', max_length=100, verbose_name='Reference')),
|
('reference', models.CharField(blank=True, help_text='Shipment reference', max_length=100, verbose_name='Reference')),
|
||||||
('notes', markdownx.models.MarkdownxField(blank=True, help_text='Shipment notes', verbose_name='Notes')),
|
('notes', markdownx.models.MarkdownxField(blank=True, help_text='Shipment notes', verbose_name='Notes')),
|
||||||
|
89
InvenTree/order/migrations/0055_auto_20211025_0645.py
Normal file
89
InvenTree/order/migrations/0055_auto_20211025_0645.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Generated by Django 3.2.5 on 2021-10-25 06:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
from InvenTree.status_codes import SalesOrderStatus
|
||||||
|
|
||||||
|
|
||||||
|
def add_shipment(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Create a SalesOrderShipment for each existing SalesOrder instance.
|
||||||
|
|
||||||
|
Any "allocations" are marked against that shipment.
|
||||||
|
|
||||||
|
For each existing SalesOrder instance, we create a default SalesOrderShipment,
|
||||||
|
and associate each SalesOrderAllocation with this shipment
|
||||||
|
"""
|
||||||
|
|
||||||
|
Allocation = apps.get_model('order', 'salesorderallocation')
|
||||||
|
SalesOrder = apps.get_model('order', 'salesorder')
|
||||||
|
Shipment = apps.get_model('order', 'salesordershipment')
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
for order in SalesOrder.objects.all():
|
||||||
|
|
||||||
|
"""
|
||||||
|
We only create an automatic shipment for "PENDING" orders,
|
||||||
|
as SalesOrderAllocations were historically deleted for "SHIPPED" or "CANCELLED" orders
|
||||||
|
"""
|
||||||
|
|
||||||
|
allocations = Allocation.objects.filter(
|
||||||
|
line__order=order
|
||||||
|
)
|
||||||
|
|
||||||
|
if allocations.count() == 0 and order.status != SalesOrderStatus.PENDING:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Create a new Shipment instance against this order
|
||||||
|
shipment = Shipment.objects.create(
|
||||||
|
order=order,
|
||||||
|
)
|
||||||
|
|
||||||
|
shipment.save()
|
||||||
|
|
||||||
|
# Iterate through each allocation associated with this order
|
||||||
|
for allocation in allocations:
|
||||||
|
allocation.shipment = shipment
|
||||||
|
allocation.save()
|
||||||
|
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
if n > 0:
|
||||||
|
print(f"\nCreated SalesOrderShipment for {n} SalesOrder instances")
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_add_shipment(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Reverse the migration, delete and SalesOrderShipment instances
|
||||||
|
"""
|
||||||
|
|
||||||
|
Allocation = apps.get_model('order', 'salesorderallocation')
|
||||||
|
|
||||||
|
# First, ensure that all SalesOrderAllocation objects point to a null shipment
|
||||||
|
for allocation in Allocation.objects.exclude(shipment=None):
|
||||||
|
allocation.shipment = None
|
||||||
|
allocation.save()
|
||||||
|
|
||||||
|
SOS = apps.get_model('order', 'salesordershipment')
|
||||||
|
|
||||||
|
n = SOS.objects.count()
|
||||||
|
|
||||||
|
print(f"Deleting {n} SalesOrderShipment instances")
|
||||||
|
|
||||||
|
SOS.objects.all().delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0054_salesorderallocation_shipment'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
add_shipment,
|
||||||
|
reverse_code=reverse_add_shipment,
|
||||||
|
)
|
||||||
|
]
|
@ -929,13 +929,6 @@ class SalesOrderShipment(models.Model):
|
|||||||
help_text=_('Sales Order'),
|
help_text=_('Sales Order'),
|
||||||
)
|
)
|
||||||
|
|
||||||
status = models.PositiveIntegerField(
|
|
||||||
default=SalesOrderStatus.PENDING,
|
|
||||||
choices=SalesOrderStatus.items(),
|
|
||||||
verbose_name=_('Status'),
|
|
||||||
help_text=_('Shipment status'),
|
|
||||||
)
|
|
||||||
|
|
||||||
shipment_date = models.DateField(
|
shipment_date = models.DateField(
|
||||||
null=True, blank=True,
|
null=True, blank=True,
|
||||||
verbose_name=_('Shipment Date'),
|
verbose_name=_('Shipment Date'),
|
||||||
|
@ -5,6 +5,7 @@ Unit tests for the 'order' model data migrations
|
|||||||
from django_test_migrations.contrib.unittest_case import MigratorTestCase
|
from django_test_migrations.contrib.unittest_case import MigratorTestCase
|
||||||
|
|
||||||
from InvenTree import helpers
|
from InvenTree import helpers
|
||||||
|
from InvenTree.status_codes import SalesOrderStatus
|
||||||
|
|
||||||
|
|
||||||
class TestForwardMigrations(MigratorTestCase):
|
class TestForwardMigrations(MigratorTestCase):
|
||||||
@ -57,3 +58,49 @@ class TestForwardMigrations(MigratorTestCase):
|
|||||||
|
|
||||||
# The integer reference field must have been correctly updated
|
# The integer reference field must have been correctly updated
|
||||||
self.assertEqual(order.reference_int, ii)
|
self.assertEqual(order.reference_int, ii)
|
||||||
|
|
||||||
|
|
||||||
|
class TestShipmentMigration(MigratorTestCase):
|
||||||
|
"""
|
||||||
|
Test data migration for the "SalesOrderShipment" model
|
||||||
|
"""
|
||||||
|
|
||||||
|
migrate_from = ('order', '0051_auto_20211014_0623')
|
||||||
|
migrate_to = ('order', '0055_auto_20211025_0645')
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
"""
|
||||||
|
Create an initial SalesOrder
|
||||||
|
"""
|
||||||
|
|
||||||
|
Company = self.old_state.apps.get_model('company', 'company')
|
||||||
|
|
||||||
|
customer = Company.objects.create(
|
||||||
|
name='My customer',
|
||||||
|
description='A customer we sell stuff too',
|
||||||
|
is_customer=True
|
||||||
|
)
|
||||||
|
|
||||||
|
SalesOrder = self.old_state.apps.get_model('order', 'salesorder')
|
||||||
|
|
||||||
|
for ii in range(5):
|
||||||
|
order = SalesOrder.objects.create(
|
||||||
|
reference=f'SO{ii}',
|
||||||
|
customer=customer,
|
||||||
|
description='A sales order for stuffs',
|
||||||
|
status=SalesOrderStatus.PENDING,
|
||||||
|
)
|
||||||
|
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
def test_shipment_creation(self):
|
||||||
|
"""
|
||||||
|
Check that a SalesOrderShipment has been created
|
||||||
|
"""
|
||||||
|
|
||||||
|
SalesOrder = self.new_state.apps.get_model('order', 'salesorder')
|
||||||
|
Shipment = self.new_state.apps.get_model('order', 'salesordershipment')
|
||||||
|
|
||||||
|
# Check that the correct number of Shipments have been created
|
||||||
|
self.assertEqual(SalesOrder.objects.count(), 5)
|
||||||
|
self.assertEqual(Shipment.objects.count(), 5)
|
||||||
|
@ -1681,6 +1681,7 @@ function loadSalesOrderLineItemTable(table, options={}) {
|
|||||||
location_detail: true,
|
location_detail: true,
|
||||||
in_stock: true,
|
in_stock: true,
|
||||||
part: line_item.part,
|
part: line_item.part,
|
||||||
|
include_variants: false,
|
||||||
exclude_so_allocation: options.order,
|
exclude_so_allocation: options.order,
|
||||||
},
|
},
|
||||||
auto_fill: true,
|
auto_fill: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user