Allow shipment numbers to be non-unique for different sales orders

- must be unique for a given sales order
This commit is contained in:
Oliver 2021-11-30 00:42:30 +11:00
parent f3f3030b37
commit 3f9b280e17
6 changed files with 100 additions and 52 deletions

View File

@ -22,7 +22,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('shipment_date', models.DateField(blank=True, help_text='Date of shipment', null=True, verbose_name='Shipment Date')),
('reference', models.CharField(default=order.models.get_next_shipment_number, unique=True, help_text='Shipment reference', max_length=100, verbose_name='Reference')),
('reference', models.CharField(default='1', 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')),

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.5 on 2021-11-29 13:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0059_salesordershipment_tracking_number'),
]
operations = [
migrations.AlterField(
model_name='salesordershipment',
name='reference',
field=models.CharField(default='1', help_text='Shipment number', max_length=100, verbose_name='Shipment'),
),
migrations.AlterUniqueTogether(
name='salesordershipment',
unique_together={('order', 'reference')},
),
]

View File

@ -900,35 +900,6 @@ class SalesOrderLineItem(OrderLineItem):
return self.shipped >= self.quantity
def get_next_shipment_number():
"""
Returns the next available SalesOrderShipment reference number"
"""
if SalesOrderShipment.objects.count() == 0:
return "001"
shipment = SalesOrderShipment.objects.exclude(reference=None).last()
attempts = set([shipment.reference])
reference = shipment.reference
while 1:
reference = increment(reference)
if reference in attempts:
# Escape infinite recursion
return reference
if SalesOrderShipment.objects.filter(reference=reference).exists():
attempts.add(reference)
else:
break
return reference
class SalesOrderShipment(models.Model):
"""
The SalesOrderShipment model represents a physical shipment made against a SalesOrder.
@ -945,6 +916,12 @@ class SalesOrderShipment(models.Model):
notes: Custom notes field for this shipment
"""
class Meta:
# Shipment reference must be unique for a given sales order
unique_together = [
'order', 'reference',
]
@staticmethod
def get_api_url():
return reverse('api-so-shipment-list')
@ -976,10 +953,9 @@ class SalesOrderShipment(models.Model):
reference = models.CharField(
max_length=100,
blank=False,
unique=True,
verbose_name=('Reference'),
help_text=_('Shipment reference'),
default=get_next_shipment_number,
verbose_name=('Shipment'),
help_text=_('Shipment number'),
default='1',
)
notes = MarkdownxField(

View File

@ -155,6 +155,7 @@
$('#new-shipment').click(function() {
createSalesOrderShipment({
order: {{ order.pk }},
reference: '{{ order.reference }}',
onSuccess: function(data) {
$('#pending-shipments-table').bootstrapTable('refresh');
}

View File

@ -7,11 +7,15 @@ from django.core.exceptions import ValidationError
from datetime import datetime, timedelta
from company.models import Company
from stock.models import StockItem
from order.models import SalesOrder, SalesOrderLineItem, SalesOrderAllocation
from part.models import Part
from InvenTree import status_codes as status
from order.models import SalesOrder, SalesOrderLineItem, SalesOrderShipment, SalesOrderAllocation
from part.models import Part
from stock.models import StockItem
class SalesOrderTest(TestCase):
"""

View File

@ -75,16 +75,56 @@ function completeShipment(shipment_id) {
// Open a dialog to create a new sales order shipment
function createSalesOrderShipment(options={}) {
constructForm('{% url "api-so-shipment-list" %}', {
method: 'POST',
fields: salesOrderShipmentFields(options),
title: '{% trans "Create New Shipment" %}',
onSuccess: function(data) {
if (options.onSuccess) {
options.onSuccess(data);
// Work out the next shipment number for the given order
inventreeGet(
'{% url "api-so-shipment-list" %}',
{
order: options.order,
},
{
success: function(results) {
// "predict" the next reference number
var ref = results.length + 1;
var found = false;
while (!found) {
var no_match = true;
for (var ii = 0; ii < results.length; ii++) {
if (ref.toString() == results[ii].reference.toString()) {
no_match = false;
break;
}
}
if (no_match) {
break;
} else {
ref++;
}
}
var fields = salesOrderShipmentFields(options);
fields.reference.value = ref;
fields.reference.prefix = global_settings.SALESORDER_REFERENCE_PREFIX + options.reference;
constructForm('{% url "api-so-shipment-list" %}', {
method: 'POST',
fields: fields,
title: '{% trans "Create New Shipment" %}',
onSuccess: function(data) {
if (options.onSuccess) {
options.onSuccess(data);
}
}
});
}
}
});
);
}
@ -1271,15 +1311,20 @@ function loadSalesOrderShipmentTable(table, options={}) {
title: '{% trans "Shipment" %}',
switchable: false,
},
{
field: 'status',
title: '{% trans "Status" %}',
},
{
field: 'shipment_date',
title: '{% trans "Shipment Date" %}',
visible: options.shipped,
switchable: false,
formatter: function(value, row) {
if (value) {
return value;
} else {
return '{% trans "Not shipped" %}';
}
}
},
{
field: 'tracking_number',
title: '{% trans "Tracking" %}',
},
{
field: 'notes',
@ -1711,7 +1756,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
field: 'quantity',
title: '{% trans "Quantity" %}',
sortable: true,
}
},
]
});
}