diff --git a/InvenTree/order/migrations/0053_salesordershipment.py b/InvenTree/order/migrations/0053_salesordershipment.py new file mode 100644 index 0000000000..c981e9c4c3 --- /dev/null +++ b/InvenTree/order/migrations/0053_salesordershipment.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.5 on 2021-10-25 02:08 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('order', '0052_auto_20211014_0631'), + ] + + operations = [ + migrations.CreateModel( + 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')), + ('checked_by', models.ForeignKey(blank=True, help_text='User who checked this shipment', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Checked By')), + ('order', models.ForeignKey(help_text='Sales Order', on_delete=django.db.models.deletion.CASCADE, related_name='shipments', to='order.salesorder', verbose_name='Order')), + ], + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 0c45e3746a..be75cf9821 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -903,6 +903,68 @@ class SalesOrderLineItem(OrderLineItem): return self.allocated_quantity() > self.quantity +class SalesOrderShipment(models.Model): + """ + The SalesOrderShipment model represents a physical shipment made against a SalesOrder. + + - Points to a single SalesOrder object + - Multiple SalesOrderAllocation objects point to a particular SalesOrderShipment + - When a given SalesOrderShipment is "shipped", stock items are removed from stock + + Attributes: + order: SalesOrder reference + status: Status of this shipment (see SalesOrderStatus) + shipment_date: Date this shipment was "shipped" (or null) + checked_by: User reference field indicating who checked this order + reference: Custom reference text for this shipment (e.g. consignment number?) + notes: Custom notes field for this shipment + """ + + order = models.ForeignKey( + SalesOrder, + on_delete=models.CASCADE, + blank=False, null=False, + related_name='shipments', + verbose_name=_('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( + null=True, blank=True, + verbose_name=_('Shipment Date'), + help_text=_('Date of shipment'), + ) + + checked_by = models.ForeignKey( + User, + on_delete=models.SET_NULL, + blank=True, null=True, + verbose_name=_('Checked By'), + help_text=_('User who checked this shipment'), + related_name='+', + ) + + reference = models.CharField( + max_length=100, + blank=True, + verbose_name=('Reference'), + help_text=_('Shipment reference'), + ) + + notes = MarkdownxField( + blank=True, + verbose_name=_('Notes'), + help_text=_('Shipment notes'), + ) + + class SalesOrderAllocation(models.Model): """ This model is used to 'allocate' stock items to a SalesOrder.