mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Shipment delivery date (#4825)
* Add delivery date setting to Shipment model * Add delivery_date to serializer * Correct test for is_delivered * Add relevant fields to API and forms * Add test * Increment API version * Move migration file because of conflict
This commit is contained in:
parent
397419f365
commit
98d87c84e3
@ -7,6 +7,9 @@ INVENTREE_API_VERSION = 113
|
||||
"""
|
||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||
|
||||
v114 -> 2023-05-16 : https://github.com/inventree/InvenTree/pull/4825
|
||||
- Adds "delivery_date" to shipments
|
||||
|
||||
v113 -> 2023-05-13 : https://github.com/inventree/InvenTree/pull/4800
|
||||
- Adds API endpoints for scrapping a build output
|
||||
|
||||
|
@ -1020,6 +1020,15 @@ class SalesOrderShipmentFilter(rest_filters.FilterSet):
|
||||
else:
|
||||
return queryset.filter(shipment_date=None)
|
||||
|
||||
delivered = rest_filters.BooleanFilter(label='delivered', method='filter_delivered')
|
||||
|
||||
def filter_delivered(self, queryset, name, value):
|
||||
"""Filter SalesOrder list by 'delivered' status (boolean)"""
|
||||
if str2bool(value):
|
||||
return queryset.exclude(delivery_date=None)
|
||||
else:
|
||||
return queryset.filter(delivery_date=None)
|
||||
|
||||
|
||||
class SalesOrderShipmentList(ListCreateAPI):
|
||||
"""API list endpoint for SalesOrderShipment model."""
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.19 on 2023-05-13 06:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('order', '0094_auto_20230514_2331'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='salesordershipment',
|
||||
name='delivery_date',
|
||||
field=models.DateField(blank=True, help_text='Date of delivery of shipment', null=True, verbose_name='Delivery Date'),
|
||||
),
|
||||
]
|
@ -1406,6 +1406,12 @@ class SalesOrderShipment(InvenTreeNotesMixin, MetadataMixin, models.Model):
|
||||
help_text=_('Date of shipment'),
|
||||
)
|
||||
|
||||
delivery_date = models.DateField(
|
||||
null=True, blank=True,
|
||||
verbose_name=_('Delivery Date'),
|
||||
help_text=_('Date of delivery of shipment'),
|
||||
)
|
||||
|
||||
checked_by = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.SET_NULL,
|
||||
@ -1449,6 +1455,10 @@ class SalesOrderShipment(InvenTreeNotesMixin, MetadataMixin, models.Model):
|
||||
"""Return True if this shipment has already been completed"""
|
||||
return self.shipment_date is not None
|
||||
|
||||
def is_delivered(self):
|
||||
"""Return True if this shipment has already been delivered"""
|
||||
return self.delivery_date is not None
|
||||
|
||||
def check_can_complete(self, raise_error=True):
|
||||
"""Check if this shipment is able to be completed"""
|
||||
try:
|
||||
@ -1508,6 +1518,12 @@ class SalesOrderShipment(InvenTreeNotesMixin, MetadataMixin, models.Model):
|
||||
if link is not None:
|
||||
self.link = link
|
||||
|
||||
# Was a delivery date provided?
|
||||
delivery_date = kwargs.get('delivery_date', None)
|
||||
|
||||
if delivery_date is not None:
|
||||
self.delivery_date = delivery_date
|
||||
|
||||
self.save()
|
||||
|
||||
trigger_event('salesordershipment.completed', id=self.pk)
|
||||
|
@ -965,6 +965,7 @@ class SalesOrderShipmentSerializer(InvenTreeModelSerializer):
|
||||
'order_detail',
|
||||
'allocations',
|
||||
'shipment_date',
|
||||
'delivery_date',
|
||||
'checked_by',
|
||||
'reference',
|
||||
'tracking_number',
|
||||
@ -988,6 +989,7 @@ class SalesOrderShipmentCompleteSerializer(serializers.ModelSerializer):
|
||||
|
||||
fields = [
|
||||
'shipment_date',
|
||||
'delivery_date',
|
||||
'tracking_number',
|
||||
'invoice_number',
|
||||
'link',
|
||||
@ -1034,6 +1036,7 @@ class SalesOrderShipmentCompleteSerializer(serializers.ModelSerializer):
|
||||
invoice_number=data.get('invoice_number', shipment.invoice_number),
|
||||
link=data.get('link', shipment.link),
|
||||
shipment_date=shipment_date,
|
||||
delivery_date=data.get('delivery_date', shipment.delivery_date),
|
||||
)
|
||||
|
||||
|
||||
|
@ -1829,6 +1829,7 @@ class SalesOrderAllocateTest(OrderTest):
|
||||
'link': 'http://test.com/link.html',
|
||||
'tracking_number': 'TRK12345',
|
||||
'shipment_date': '2020-12-05',
|
||||
'delivery_date': '2023-12-05',
|
||||
},
|
||||
expected_code=201,
|
||||
)
|
||||
@ -1839,6 +1840,48 @@ class SalesOrderAllocateTest(OrderTest):
|
||||
self.assertEqual(self.shipment.tracking_number, 'TRK12345')
|
||||
self.assertEqual(self.shipment.invoice_number, 'INV01234')
|
||||
self.assertEqual(self.shipment.link, 'http://test.com/link.html')
|
||||
self.assertEqual(self.shipment.delivery_date, datetime(2023, 12, 5).date())
|
||||
self.assertTrue(self.shipment.is_delivered())
|
||||
|
||||
def test_shipment_deliverydate(self):
|
||||
"""Test delivery date functions via API."""
|
||||
url = reverse('api-so-shipment-detail', kwargs={'pk': self.shipment.pk})
|
||||
|
||||
# Attempt remove delivery_date from shipment
|
||||
response = self.patch(
|
||||
url,
|
||||
{
|
||||
'delivery_date': None,
|
||||
},
|
||||
expected_code=200,
|
||||
)
|
||||
|
||||
# Shipment should not be marked as delivered
|
||||
self.assertFalse(self.shipment.is_delivered())
|
||||
|
||||
# Attempt to set delivery date
|
||||
response = self.patch(
|
||||
url,
|
||||
{
|
||||
'delivery_date': 'asfasd',
|
||||
},
|
||||
expected_code=400,
|
||||
)
|
||||
|
||||
self.assertIn('Date has wrong format', str(response.data))
|
||||
|
||||
response = self.patch(
|
||||
url,
|
||||
{
|
||||
'delivery_date': '2023-05-15',
|
||||
},
|
||||
expected_code=200,
|
||||
)
|
||||
self.shipment.refresh_from_db()
|
||||
|
||||
# Shipment should now be marked as delivered
|
||||
self.assertTrue(self.shipment.is_delivered())
|
||||
self.assertEqual(self.shipment.delivery_date, datetime(2023, 5, 15).date())
|
||||
|
||||
def test_sales_order_shipment_list(self):
|
||||
"""Test the SalesOrderShipment list API endpoint"""
|
||||
|
@ -257,6 +257,13 @@ class SalesOrderTest(TestCase):
|
||||
# Shipment should have default reference of '1'
|
||||
self.assertEqual('1', order_2.pending_shipments()[0].reference)
|
||||
|
||||
def test_shipment_delivery(self):
|
||||
"""Test the shipment delivery settings"""
|
||||
|
||||
# Shipment delivery date should be empty before setting date
|
||||
self.assertIsNone(self.shipment.delivery_date)
|
||||
self.assertFalse(self.shipment.is_delivered())
|
||||
|
||||
def test_overdue_notification(self):
|
||||
"""Test overdue sales order notification"""
|
||||
|
||||
|
@ -209,6 +209,9 @@ function salesOrderShipmentFields(options={}) {
|
||||
},
|
||||
link: {
|
||||
icon: 'fa-link',
|
||||
},
|
||||
delivery_date: {
|
||||
icon: 'fa-calendar-check',
|
||||
}
|
||||
};
|
||||
|
||||
@ -298,7 +301,11 @@ function completeSalesOrderShipment(shipment_id, options={}) {
|
||||
link: {
|
||||
value: shipment.link,
|
||||
icon: 'fa-link',
|
||||
}
|
||||
},
|
||||
delivery_date: {
|
||||
value: shipment.delivery_date,
|
||||
icon: 'fa-calendar-check',
|
||||
},
|
||||
},
|
||||
preFormContent: html,
|
||||
confirm: true,
|
||||
@ -979,6 +986,18 @@ function loadSalesOrderShipmentTable(table, options={}) {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'delivery_date',
|
||||
title: '{% trans "Delivery Date" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (value) {
|
||||
return renderDate(value);
|
||||
} else {
|
||||
return '<em>{% trans "Unknown" %}</em>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'tracking_number',
|
||||
title: '{% trans "Tracking" %}',
|
||||
|
Loading…
Reference in New Issue
Block a user