mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Timestamp issues (#6867)
* Adjust default values for test result fields * Add helper functions: - current_time() - current_date() Handles timezone "awareness" * Use new helper function widely * Update defaults - do not use None * Allow null field values
This commit is contained in:
parent
cd0d35047d
commit
4059d9ffeb
@ -872,6 +872,29 @@ def hash_file(filename: Union[str, Path], storage: Union[Storage, None] = None):
|
|||||||
return hashlib.md5(content).hexdigest()
|
return hashlib.md5(content).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def current_time(local=True):
|
||||||
|
"""Return the current date and time as a datetime object.
|
||||||
|
|
||||||
|
- If timezone support is active, returns a timezone aware time
|
||||||
|
- If timezone support is not active, returns a timezone naive time
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
local: Return the time in the local timezone, otherwise UTC (default = True)
|
||||||
|
|
||||||
|
"""
|
||||||
|
if settings.USE_TZ:
|
||||||
|
now = timezone.now()
|
||||||
|
now = to_local_time(now, target_tz=server_timezone() if local else 'UTC')
|
||||||
|
return now
|
||||||
|
else:
|
||||||
|
return datetime.datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
def current_date(local=True):
|
||||||
|
"""Return the current date."""
|
||||||
|
return current_time(local=local).date()
|
||||||
|
|
||||||
|
|
||||||
def server_timezone() -> str:
|
def server_timezone() -> str:
|
||||||
"""Return the timezone of the server as a string.
|
"""Return the timezone of the server as a string.
|
||||||
|
|
||||||
|
@ -952,6 +952,8 @@ USE_I18N = True
|
|||||||
# It generates a *lot* of cruft in the logs
|
# It generates a *lot* of cruft in the logs
|
||||||
if not TESTING:
|
if not TESTING:
|
||||||
USE_TZ = True # pragma: no cover
|
USE_TZ = True # pragma: no cover
|
||||||
|
else:
|
||||||
|
USE_TZ = False
|
||||||
|
|
||||||
DATE_INPUT_FORMATS = ['%Y-%m-%d']
|
DATE_INPUT_FORMATS = ['%Y-%m-%d']
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class Build(InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.InvenTreeNo
|
|||||||
verbose_name = _("Build Order")
|
verbose_name = _("Build Order")
|
||||||
verbose_name_plural = _("Build Orders")
|
verbose_name_plural = _("Build Orders")
|
||||||
|
|
||||||
OVERDUE_FILTER = Q(status__in=BuildStatusGroups.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
OVERDUE_FILTER = Q(status__in=BuildStatusGroups.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=InvenTree.helpers.current_date())
|
||||||
|
|
||||||
# Global setting for specifying reference pattern
|
# Global setting for specifying reference pattern
|
||||||
REFERENCE_PATTERN_SETTING = 'BUILDORDER_REFERENCE_PATTERN'
|
REFERENCE_PATTERN_SETTING = 'BUILDORDER_REFERENCE_PATTERN'
|
||||||
@ -546,7 +546,7 @@ class Build(InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.InvenTreeNo
|
|||||||
if self.incomplete_count > 0:
|
if self.incomplete_count > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.completion_date = datetime.now().date()
|
self.completion_date = InvenTree.helpers.current_date()
|
||||||
self.completed_by = user
|
self.completed_by = user
|
||||||
self.status = BuildStatus.COMPLETE.value
|
self.status = BuildStatus.COMPLETE.value
|
||||||
self.save()
|
self.save()
|
||||||
@ -628,7 +628,7 @@ class Build(InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.InvenTreeNo
|
|||||||
output.delete()
|
output.delete()
|
||||||
|
|
||||||
# Date of 'completion' is the date the build was cancelled
|
# Date of 'completion' is the date the build was cancelled
|
||||||
self.completion_date = datetime.now().date()
|
self.completion_date = InvenTree.helpers.current_date()
|
||||||
self.completed_by = user
|
self.completed_by = user
|
||||||
|
|
||||||
self.status = BuildStatus.CANCELLED.value
|
self.status = BuildStatus.CANCELLED.value
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Background task definitions for the BuildOrder app"""
|
"""Background task definitions for the BuildOrder app"""
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ from plugin.events import trigger_event
|
|||||||
import common.notifications
|
import common.notifications
|
||||||
import build.models
|
import build.models
|
||||||
import InvenTree.email
|
import InvenTree.email
|
||||||
|
import InvenTree.helpers
|
||||||
import InvenTree.helpers_model
|
import InvenTree.helpers_model
|
||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
from InvenTree.status_codes import BuildStatusGroups
|
from InvenTree.status_codes import BuildStatusGroups
|
||||||
@ -222,7 +223,7 @@ def check_overdue_build_orders():
|
|||||||
- Look at the 'target_date' of any outstanding BuildOrder objects
|
- Look at the 'target_date' of any outstanding BuildOrder objects
|
||||||
- If the 'target_date' expired *yesterday* then the order is just out of date
|
- If the 'target_date' expired *yesterday* then the order is just out of date
|
||||||
"""
|
"""
|
||||||
yesterday = datetime.now().date() - timedelta(days=1)
|
yesterday = InvenTree.helpers.current_date() - timedelta(days=1)
|
||||||
|
|
||||||
overdue_orders = build.models.Build.objects.filter(
|
overdue_orders = build.models.Build.objects.filter(
|
||||||
target_date=yesterday,
|
target_date=yesterday,
|
||||||
|
@ -13,7 +13,7 @@ import math
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import timedelta, timezone
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
from typing import Any, Callable, TypedDict, Union
|
from typing import Any, Callable, TypedDict, Union
|
||||||
@ -2915,7 +2915,7 @@ class NotificationEntry(MetaMixin):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def check_recent(cls, key: str, uid: int, delta: timedelta):
|
def check_recent(cls, key: str, uid: int, delta: timedelta):
|
||||||
"""Test if a particular notification has been sent in the specified time period."""
|
"""Test if a particular notification has been sent in the specified time period."""
|
||||||
since = datetime.now().date() - delta
|
since = InvenTree.helpers.current_date() - delta
|
||||||
|
|
||||||
entries = cls.objects.filter(key=key, uid=uid, updated__gte=since)
|
entries = cls.objects.filter(key=key, uid=uid, updated__gte=since)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from datetime import datetime, timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import AppRegistryNotReady
|
from django.core.exceptions import AppRegistryNotReady
|
||||||
@ -12,6 +12,7 @@ from django.utils import timezone
|
|||||||
import feedparser
|
import feedparser
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
import InvenTree.helpers
|
||||||
from InvenTree.helpers_model import getModelsWithMixin
|
from InvenTree.helpers_model import getModelsWithMixin
|
||||||
from InvenTree.models import InvenTreeNotesMixin
|
from InvenTree.models import InvenTreeNotesMixin
|
||||||
from InvenTree.tasks import ScheduledTask, scheduled_task
|
from InvenTree.tasks import ScheduledTask, scheduled_task
|
||||||
@ -107,7 +108,7 @@ def delete_old_notes_images():
|
|||||||
note.delete()
|
note.delete()
|
||||||
|
|
||||||
note_classes = getModelsWithMixin(InvenTreeNotesMixin)
|
note_classes = getModelsWithMixin(InvenTreeNotesMixin)
|
||||||
before = datetime.now() - timedelta(days=90)
|
before = InvenTree.helpers.current_date() - timedelta(days=90)
|
||||||
|
|
||||||
for note in NotesImage.objects.filter(date__lte=before):
|
for note in NotesImage.objects.filter(date__lte=before):
|
||||||
# Find any images which are no longer referenced by a note
|
# Find any images which are no longer referenced by a note
|
||||||
|
@ -901,7 +901,7 @@ class SupplierPart(
|
|||||||
def update_available_quantity(self, quantity):
|
def update_available_quantity(self, quantity):
|
||||||
"""Update the available quantity for this SupplierPart."""
|
"""Update the available quantity for this SupplierPart."""
|
||||||
self.available = quantity
|
self.available = quantity
|
||||||
self.availability_updated = datetime.now()
|
self.availability_updated = InvenTree.helpers.current_time()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""Label printing models."""
|
"""Label printing models."""
|
||||||
|
|
||||||
import datetime
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@ -15,6 +14,7 @@ from django.urls import reverse
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
import build.models
|
import build.models
|
||||||
|
import InvenTree.helpers
|
||||||
import InvenTree.models
|
import InvenTree.models
|
||||||
import part.models
|
import part.models
|
||||||
import stock.models
|
import stock.models
|
||||||
@ -228,8 +228,8 @@ class LabelTemplate(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
|
|
||||||
# Add "basic" context data which gets passed to every label
|
# Add "basic" context data which gets passed to every label
|
||||||
context['base_url'] = get_base_url(request=request)
|
context['base_url'] = get_base_url(request=request)
|
||||||
context['date'] = datetime.datetime.now().date()
|
context['date'] = InvenTree.helpers.current_date()
|
||||||
context['datetime'] = datetime.datetime.now()
|
context['datetime'] = InvenTree.helpers.current_time()
|
||||||
context['request'] = request
|
context['request'] = request
|
||||||
context['user'] = request.user
|
context['user'] = request.user
|
||||||
context['width'] = self.width
|
context['width'] = self.width
|
||||||
|
@ -221,7 +221,7 @@ class Order(
|
|||||||
"""
|
"""
|
||||||
self.reference_int = self.rebuild_reference_field(self.reference)
|
self.reference_int = self.rebuild_reference_field(self.reference)
|
||||||
if not self.creation_date:
|
if not self.creation_date:
|
||||||
self.creation_date = datetime.now().date()
|
self.creation_date = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ class Order(
|
|||||||
|
|
||||||
It requires any subclasses to implement the get_status_class() class method
|
It requires any subclasses to implement the get_status_class() class method
|
||||||
"""
|
"""
|
||||||
today = datetime.now().date()
|
today = InvenTree.helpers.current_date()
|
||||||
return (
|
return (
|
||||||
Q(status__in=cls.get_status_class().OPEN)
|
Q(status__in=cls.get_status_class().OPEN)
|
||||||
& ~Q(target_date=None)
|
& ~Q(target_date=None)
|
||||||
@ -584,7 +584,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
|
|||||||
"""
|
"""
|
||||||
if self.is_pending:
|
if self.is_pending:
|
||||||
self.status = PurchaseOrderStatus.PLACED.value
|
self.status = PurchaseOrderStatus.PLACED.value
|
||||||
self.issue_date = datetime.now().date()
|
self.issue_date = InvenTree.helpers.current_date()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
trigger_event('purchaseorder.placed', id=self.pk)
|
trigger_event('purchaseorder.placed', id=self.pk)
|
||||||
@ -604,7 +604,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
|
|||||||
"""
|
"""
|
||||||
if self.status == PurchaseOrderStatus.PLACED:
|
if self.status == PurchaseOrderStatus.PLACED:
|
||||||
self.status = PurchaseOrderStatus.COMPLETE.value
|
self.status = PurchaseOrderStatus.COMPLETE.value
|
||||||
self.complete_date = datetime.now().date()
|
self.complete_date = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -1030,7 +1030,7 @@ class SalesOrder(TotalPriceMixin, Order):
|
|||||||
"""Change this order from 'PENDING' to 'IN_PROGRESS'."""
|
"""Change this order from 'PENDING' to 'IN_PROGRESS'."""
|
||||||
if self.status == SalesOrderStatus.PENDING:
|
if self.status == SalesOrderStatus.PENDING:
|
||||||
self.status = SalesOrderStatus.IN_PROGRESS.value
|
self.status = SalesOrderStatus.IN_PROGRESS.value
|
||||||
self.issue_date = datetime.now().date()
|
self.issue_date = InvenTree.helpers.current_date()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
trigger_event('salesorder.issued', id=self.pk)
|
trigger_event('salesorder.issued', id=self.pk)
|
||||||
@ -1044,7 +1044,7 @@ class SalesOrder(TotalPriceMixin, Order):
|
|||||||
|
|
||||||
self.status = SalesOrderStatus.SHIPPED.value
|
self.status = SalesOrderStatus.SHIPPED.value
|
||||||
self.shipped_by = user
|
self.shipped_by = user
|
||||||
self.shipment_date = datetime.now()
|
self.shipment_date = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -1346,7 +1346,7 @@ class PurchaseOrderLineItem(OrderLineItem):
|
|||||||
OVERDUE_FILTER = (
|
OVERDUE_FILTER = (
|
||||||
Q(received__lt=F('quantity'))
|
Q(received__lt=F('quantity'))
|
||||||
& ~Q(target_date=None)
|
& ~Q(target_date=None)
|
||||||
& Q(target_date__lt=datetime.now().date())
|
& Q(target_date__lt=InvenTree.helpers.current_date())
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -1505,7 +1505,7 @@ class SalesOrderLineItem(OrderLineItem):
|
|||||||
OVERDUE_FILTER = (
|
OVERDUE_FILTER = (
|
||||||
Q(shipped__lt=F('quantity'))
|
Q(shipped__lt=F('quantity'))
|
||||||
& ~Q(target_date=None)
|
& ~Q(target_date=None)
|
||||||
& Q(target_date__lt=datetime.now().date())
|
& Q(target_date__lt=InvenTree.helpers.current_date())
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -1748,7 +1748,9 @@ class SalesOrderShipment(
|
|||||||
allocation.complete_allocation(user)
|
allocation.complete_allocation(user)
|
||||||
|
|
||||||
# Update the "shipment" date
|
# Update the "shipment" date
|
||||||
self.shipment_date = kwargs.get('shipment_date', datetime.now())
|
self.shipment_date = kwargs.get(
|
||||||
|
'shipment_date', InvenTree.helpers.current_date()
|
||||||
|
)
|
||||||
self.shipped_by = user
|
self.shipped_by = user
|
||||||
|
|
||||||
# Was a tracking number provided?
|
# Was a tracking number provided?
|
||||||
@ -2076,7 +2078,7 @@ class ReturnOrder(TotalPriceMixin, Order):
|
|||||||
"""Complete this ReturnOrder (if not already completed)."""
|
"""Complete this ReturnOrder (if not already completed)."""
|
||||||
if self.status == ReturnOrderStatus.IN_PROGRESS:
|
if self.status == ReturnOrderStatus.IN_PROGRESS:
|
||||||
self.status = ReturnOrderStatus.COMPLETE.value
|
self.status = ReturnOrderStatus.COMPLETE.value
|
||||||
self.complete_date = datetime.now().date()
|
self.complete_date = InvenTree.helpers.current_date()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
trigger_event('returnorder.completed', id=self.pk)
|
trigger_event('returnorder.completed', id=self.pk)
|
||||||
@ -2089,7 +2091,7 @@ class ReturnOrder(TotalPriceMixin, Order):
|
|||||||
"""Issue this ReturnOrder (if currently pending)."""
|
"""Issue this ReturnOrder (if currently pending)."""
|
||||||
if self.status == ReturnOrderStatus.PENDING:
|
if self.status == ReturnOrderStatus.PENDING:
|
||||||
self.status = ReturnOrderStatus.IN_PROGRESS.value
|
self.status = ReturnOrderStatus.IN_PROGRESS.value
|
||||||
self.issue_date = datetime.now().date()
|
self.issue_date = InvenTree.helpers.current_date()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
trigger_event('returnorder.issued', id=self.pk)
|
trigger_event('returnorder.issued', id=self.pk)
|
||||||
@ -2162,7 +2164,7 @@ class ReturnOrder(TotalPriceMixin, Order):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Update the LineItem
|
# Update the LineItem
|
||||||
line.received_date = datetime.now().date()
|
line.received_date = InvenTree.helpers.current_date()
|
||||||
line.save()
|
line.save()
|
||||||
|
|
||||||
trigger_event('returnorder.received', id=self.pk)
|
trigger_event('returnorder.received', id=self.pk)
|
||||||
|
@ -34,7 +34,13 @@ from company.serializers import (
|
|||||||
ContactSerializer,
|
ContactSerializer,
|
||||||
SupplierPartSerializer,
|
SupplierPartSerializer,
|
||||||
)
|
)
|
||||||
from InvenTree.helpers import extract_serial_numbers, hash_barcode, normalize, str2bool
|
from InvenTree.helpers import (
|
||||||
|
current_date,
|
||||||
|
extract_serial_numbers,
|
||||||
|
hash_barcode,
|
||||||
|
normalize,
|
||||||
|
str2bool,
|
||||||
|
)
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
InvenTreeAttachmentSerializer,
|
InvenTreeAttachmentSerializer,
|
||||||
InvenTreeCurrencySerializer,
|
InvenTreeCurrencySerializer,
|
||||||
@ -1140,11 +1146,12 @@ class SalesOrderShipmentCompleteSerializer(serializers.ModelSerializer):
|
|||||||
user = request.user
|
user = request.user
|
||||||
|
|
||||||
# Extract shipping date (defaults to today's date)
|
# Extract shipping date (defaults to today's date)
|
||||||
shipment_date = data.get('shipment_date', datetime.now())
|
now = current_date()
|
||||||
|
shipment_date = data.get('shipment_date', now)
|
||||||
if shipment_date is None:
|
if shipment_date is None:
|
||||||
# Shipment date should not be None - check above only
|
# Shipment date should not be None - check above only
|
||||||
# checks if shipment_date exists in data
|
# checks if shipment_date exists in data
|
||||||
shipment_date = datetime.now()
|
shipment_date = now
|
||||||
|
|
||||||
shipment.complete_shipment(
|
shipment.complete_shipment(
|
||||||
user,
|
user,
|
||||||
|
@ -37,6 +37,7 @@ import common.models
|
|||||||
import common.settings
|
import common.settings
|
||||||
import InvenTree.conversion
|
import InvenTree.conversion
|
||||||
import InvenTree.fields
|
import InvenTree.fields
|
||||||
|
import InvenTree.helpers
|
||||||
import InvenTree.models
|
import InvenTree.models
|
||||||
import InvenTree.ready
|
import InvenTree.ready
|
||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
@ -1728,7 +1729,7 @@ class Part(
|
|||||||
|
|
||||||
self.bom_checksum = self.get_bom_hash()
|
self.bom_checksum = self.get_bom_hash()
|
||||||
self.bom_checked_by = user
|
self.bom_checked_by = user
|
||||||
self.bom_checked_date = datetime.now().date()
|
self.bom_checked_date = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -2715,7 +2716,7 @@ class PartPricing(common.models.MetaMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if days > 0:
|
if days > 0:
|
||||||
date_threshold = datetime.now().date() - timedelta(days=days)
|
date_threshold = InvenTree.helpers.current_date() - timedelta(days=days)
|
||||||
items = items.filter(updated__gte=date_threshold)
|
items = items.filter(updated__gte=date_threshold)
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
|
@ -266,7 +266,7 @@ def generate_stocktake_report(**kwargs):
|
|||||||
buffer = io.StringIO()
|
buffer = io.StringIO()
|
||||||
buffer.write(dataset.export('csv'))
|
buffer.write(dataset.export('csv'))
|
||||||
|
|
||||||
today = datetime.now().date().isoformat()
|
today = InvenTree.helpers.current_date().isoformat()
|
||||||
filename = f'InvenTree_Stocktake_{today}.csv'
|
filename = f'InvenTree_Stocktake_{today}.csv'
|
||||||
report_file = ContentFile(buffer.getvalue(), name=filename)
|
report_file = ContentFile(buffer.getvalue(), name=filename)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
import build.models
|
import build.models
|
||||||
import common.models
|
import common.models
|
||||||
import InvenTree.exceptions
|
import InvenTree.exceptions
|
||||||
|
import InvenTree.helpers
|
||||||
import InvenTree.models
|
import InvenTree.models
|
||||||
import order.models
|
import order.models
|
||||||
import part.models
|
import part.models
|
||||||
@ -250,8 +251,8 @@ class ReportTemplateBase(MetadataMixin, ReportBase):
|
|||||||
context = self.get_context_data(request)
|
context = self.get_context_data(request)
|
||||||
|
|
||||||
context['base_url'] = get_base_url(request=request)
|
context['base_url'] = get_base_url(request=request)
|
||||||
context['date'] = datetime.datetime.now().date()
|
context['date'] = InvenTree.helpers.current_date()
|
||||||
context['datetime'] = datetime.datetime.now()
|
context['datetime'] = InvenTree.helpers.current_time()
|
||||||
context['page_size'] = self.get_report_size()
|
context['page_size'] = self.get_report_size()
|
||||||
context['report_template'] = self
|
context['report_template'] = self
|
||||||
context['report_description'] = self.description
|
context['report_description'] = self.description
|
||||||
|
@ -19,6 +19,7 @@ from rest_framework.serializers import ValidationError
|
|||||||
|
|
||||||
import common.models
|
import common.models
|
||||||
import common.settings
|
import common.settings
|
||||||
|
import InvenTree.helpers
|
||||||
import stock.serializers as StockSerializers
|
import stock.serializers as StockSerializers
|
||||||
from build.models import Build
|
from build.models import Build
|
||||||
from build.serializers import BuildSerializer
|
from build.serializers import BuildSerializer
|
||||||
@ -810,7 +811,7 @@ class StockFilter(rest_filters.FilterSet):
|
|||||||
# No filtering, does not make sense
|
# No filtering, does not make sense
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
stale_date = datetime.now().date() + timedelta(days=stale_days)
|
stale_date = InvenTree.helpers.current_date() + timedelta(days=stale_days)
|
||||||
stale_filter = (
|
stale_filter = (
|
||||||
StockItem.IN_STOCK_FILTER
|
StockItem.IN_STOCK_FILTER
|
||||||
& ~Q(expiry_date=None)
|
& ~Q(expiry_date=None)
|
||||||
@ -906,7 +907,7 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
|||||||
|
|
||||||
# An expiry date was *not* specified - try to infer it!
|
# An expiry date was *not* specified - try to infer it!
|
||||||
if expiry_date is None and part.default_expiry > 0:
|
if expiry_date is None and part.default_expiry > 0:
|
||||||
data['expiry_date'] = datetime.now().date() + timedelta(
|
data['expiry_date'] = InvenTree.helpers.current_date() + timedelta(
|
||||||
days=part.default_expiry
|
days=part.default_expiry
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1050,7 +1051,7 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
|||||||
|
|
||||||
filedata = dataset.export(export_format)
|
filedata = dataset.export(export_format)
|
||||||
|
|
||||||
filename = f'InvenTree_StockItems_{datetime.now().strftime("%d-%b-%Y")}.{export_format}'
|
filename = f'InvenTree_StockItems_{InvenTree.helpers.current_date().strftime("%d-%b-%Y")}.{export_format}'
|
||||||
|
|
||||||
return DownloadFile(filedata, filename)
|
return DownloadFile(filedata, filename)
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# Generated by Django 3.2.23 on 2023-12-18 18:52
|
# Generated by Django 3.2.23 on 2023-12-18 18:52
|
||||||
|
|
||||||
import datetime
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -14,12 +13,12 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='stockitemtestresult',
|
model_name='stockitemtestresult',
|
||||||
name='finished_datetime',
|
name='finished_datetime',
|
||||||
field=models.DateTimeField(blank=True, default=datetime.datetime.now, help_text='The timestamp of the test finish', verbose_name='Finished'),
|
field=models.DateTimeField(blank=True, help_text='The timestamp of the test finish', verbose_name='Finished'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='stockitemtestresult',
|
model_name='stockitemtestresult',
|
||||||
name='started_datetime',
|
name='started_datetime',
|
||||||
field=models.DateTimeField(blank=True, default=datetime.datetime.now, help_text='The timestamp of the test start', verbose_name='Started'),
|
field=models.DateTimeField(blank=True, help_text='The timestamp of the test start', verbose_name='Started'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='stockitemtestresult',
|
model_name='stockitemtestresult',
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.2.11 on 2024-03-27 04:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0109_add_additional_test_fields'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stockitemtestresult',
|
||||||
|
name='finished_datetime',
|
||||||
|
field=models.DateTimeField(blank=True, help_text='The timestamp of the test finish', null=True, verbose_name='Finished'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stockitemtestresult',
|
||||||
|
name='started_datetime',
|
||||||
|
field=models.DateTimeField(blank=True, help_text='The timestamp of the test start', null=True, verbose_name='Started'),
|
||||||
|
),
|
||||||
|
]
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from datetime import datetime, timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal, InvalidOperation
|
from decimal import Decimal, InvalidOperation
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -319,9 +319,9 @@ def generate_batch_code():
|
|||||||
'STOCK_BATCH_CODE_TEMPLATE', ''
|
'STOCK_BATCH_CODE_TEMPLATE', ''
|
||||||
)
|
)
|
||||||
|
|
||||||
now = datetime.now()
|
now = InvenTree.helpers.current_time()
|
||||||
|
|
||||||
# Pass context data through to the template randering.
|
# Pass context data through to the template rendering.
|
||||||
# The following context variables are available for custom batch code generation
|
# The following context variables are available for custom batch code generation
|
||||||
context = {
|
context = {
|
||||||
'date': now,
|
'date': now,
|
||||||
@ -412,7 +412,7 @@ class StockItem(
|
|||||||
EXPIRED_FILTER = (
|
EXPIRED_FILTER = (
|
||||||
IN_STOCK_FILTER
|
IN_STOCK_FILTER
|
||||||
& ~Q(expiry_date=None)
|
& ~Q(expiry_date=None)
|
||||||
& Q(expiry_date__lt=datetime.now().date())
|
& Q(expiry_date__lt=InvenTree.helpers.current_date())
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_serial_number(self):
|
def update_serial_number(self):
|
||||||
@ -1011,7 +1011,7 @@ class StockItem(
|
|||||||
if not self.in_stock:
|
if not self.in_stock:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
today = datetime.now().date()
|
today = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
||||||
|
|
||||||
@ -1036,7 +1036,7 @@ class StockItem(
|
|||||||
if not self.in_stock:
|
if not self.in_stock:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
today = datetime.now().date()
|
today = InvenTree.helpers.current_date()
|
||||||
|
|
||||||
return self.expiry_date < today
|
return self.expiry_date < today
|
||||||
|
|
||||||
@ -1438,7 +1438,7 @@ class StockItem(
|
|||||||
item=self,
|
item=self,
|
||||||
tracking_type=entry_type.value,
|
tracking_type=entry_type.value,
|
||||||
user=user,
|
user=user,
|
||||||
date=datetime.now(),
|
date=InvenTree.helpers.current_time(),
|
||||||
notes=notes,
|
notes=notes,
|
||||||
deltas=deltas,
|
deltas=deltas,
|
||||||
)
|
)
|
||||||
@ -1962,7 +1962,7 @@ class StockItem(
|
|||||||
if count < 0:
|
if count < 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.stocktake_date = datetime.now().date()
|
self.stocktake_date = InvenTree.helpers.current_date()
|
||||||
self.stocktake_user = user
|
self.stocktake_user = user
|
||||||
|
|
||||||
if self.updateQuantity(count):
|
if self.updateQuantity(count):
|
||||||
@ -2464,15 +2464,15 @@ class StockItemTestResult(InvenTree.models.InvenTreeMetadataModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
started_datetime = models.DateTimeField(
|
started_datetime = models.DateTimeField(
|
||||||
default=datetime.now,
|
|
||||||
blank=True,
|
blank=True,
|
||||||
|
null=True,
|
||||||
verbose_name=_('Started'),
|
verbose_name=_('Started'),
|
||||||
help_text=_('The timestamp of the test start'),
|
help_text=_('The timestamp of the test start'),
|
||||||
)
|
)
|
||||||
|
|
||||||
finished_datetime = models.DateTimeField(
|
finished_datetime = models.DateTimeField(
|
||||||
default=datetime.now,
|
|
||||||
blank=True,
|
blank=True,
|
||||||
|
null=True,
|
||||||
verbose_name=_('Finished'),
|
verbose_name=_('Finished'),
|
||||||
help_text=_('The timestamp of the test finish'),
|
help_text=_('The timestamp of the test finish'),
|
||||||
)
|
)
|
||||||
|
@ -345,7 +345,7 @@ class StockItemSerializer(InvenTree.serializers.InvenTreeTagModelSerializer):
|
|||||||
|
|
||||||
# Add flag to indicate if the StockItem is stale
|
# Add flag to indicate if the StockItem is stale
|
||||||
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
stale_days = common.models.InvenTreeSetting.get_setting('STOCK_STALE_DAYS')
|
||||||
stale_date = datetime.now().date() + timedelta(days=stale_days)
|
stale_date = InvenTree.helpers.current_date() + timedelta(days=stale_days)
|
||||||
stale_filter = (
|
stale_filter = (
|
||||||
StockItem.IN_STOCK_FILTER
|
StockItem.IN_STOCK_FILTER
|
||||||
& ~Q(expiry_date=None)
|
& ~Q(expiry_date=None)
|
||||||
@ -826,7 +826,7 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
deltas = {'status': status}
|
deltas = {'status': status}
|
||||||
|
|
||||||
now = datetime.now()
|
now = InvenTree.helpers.current_time()
|
||||||
|
|
||||||
# Instead of performing database updates for each item,
|
# Instead of performing database updates for each item,
|
||||||
# perform bulk database updates (much more efficient)
|
# perform bulk database updates (much more efficient)
|
||||||
|
@ -53,7 +53,7 @@ def default_token_expiry():
|
|||||||
"""Generate an expiry date for a newly created token."""
|
"""Generate an expiry date for a newly created token."""
|
||||||
# TODO: Custom value for default expiry timeout
|
# TODO: Custom value for default expiry timeout
|
||||||
# TODO: For now, tokens last for 1 year
|
# TODO: For now, tokens last for 1 year
|
||||||
return datetime.datetime.now().date() + datetime.timedelta(days=365)
|
return InvenTree.helpers.current_date() + datetime.timedelta(days=365)
|
||||||
|
|
||||||
|
|
||||||
class ApiToken(AuthToken, InvenTree.models.MetadataMixin):
|
class ApiToken(AuthToken, InvenTree.models.MetadataMixin):
|
||||||
@ -163,7 +163,9 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin):
|
|||||||
@admin.display(boolean=True, description=_('Expired'))
|
@admin.display(boolean=True, description=_('Expired'))
|
||||||
def expired(self):
|
def expired(self):
|
||||||
"""Test if this token has expired."""
|
"""Test if this token has expired."""
|
||||||
return self.expiry is not None and self.expiry < datetime.datetime.now().date()
|
return (
|
||||||
|
self.expiry is not None and self.expiry < InvenTree.helpers.current_date()
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@admin.display(boolean=True, description=_('Active'))
|
@admin.display(boolean=True, description=_('Active'))
|
||||||
|
Loading…
Reference in New Issue
Block a user