mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +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:
		| @@ -18,7 +18,6 @@ class Migration(migrations.Migration): | ||||
|             name='SalesOrderShipment', | ||||
|             fields=[ | ||||
|                 ('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')), | ||||
|                 ('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')), | ||||
|   | ||||
							
								
								
									
										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'), | ||||
|     ) | ||||
|  | ||||
|     status = models.PositiveIntegerField( | ||||
|         default=SalesOrderStatus.PENDING, | ||||
|         choices=SalesOrderStatus.items(), | ||||
|         verbose_name=_('Status'), | ||||
|         help_text=_('Shipment status'), | ||||
|     ) | ||||
|  | ||||
|     shipment_date = models.DateField( | ||||
|         null=True, blank=True, | ||||
|         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 InvenTree import helpers | ||||
| from InvenTree.status_codes import SalesOrderStatus | ||||
|  | ||||
|  | ||||
| class TestForwardMigrations(MigratorTestCase): | ||||
| @@ -57,3 +58,49 @@ class TestForwardMigrations(MigratorTestCase): | ||||
|  | ||||
|             # The integer reference field must have been correctly updated | ||||
|         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, | ||||
|                         in_stock: true, | ||||
|                         part: line_item.part, | ||||
|                         include_variants: false, | ||||
|                         exclude_so_allocation: options.order, | ||||
|                     }, | ||||
|                     auto_fill: true, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user