mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-18 18:56:31 +00:00
Merge branch 'master' of https://github.com/inventree/InvenTree into matmair/issue6281
This commit is contained in:
docs/docs/build
src
backend
InvenTree
InvenTree
build
common
setting
importer
part
stock
frontend
package.json
src
components
forms
functions
pages
Index
Settings
AdminCenter
build
sales
stock
tables
tests
yarn.lock@@ -11,6 +11,10 @@ v303 - 2025-01-20 : https://github.com/inventree/InvenTree/pull/6293
|
||||
- Removes a considerable amount of old auth endpoints
|
||||
- Introduces allauth based REST API
|
||||
|
||||
v303 - 2025-01-20 - https://github.com/inventree/InvenTree/pull/8915
|
||||
- Adds "start_date" field to Build model and API endpoints
|
||||
- Adds additional API filtering and sorting options for Build list
|
||||
|
||||
v302 - 2025-01-18 - https://github.com/inventree/InvenTree/pull/8905
|
||||
- Fix schema definition on the /label/print endpoint
|
||||
|
||||
|
@@ -188,6 +188,30 @@ class BuildFilter(rest_filters.FilterSet):
|
||||
label=_('Created after'), field_name='creation_date', lookup_expr='gt'
|
||||
)
|
||||
|
||||
has_start_date = rest_filters.BooleanFilter(
|
||||
label=_('Has start date'), method='filter_has_start_date'
|
||||
)
|
||||
|
||||
def filter_has_start_date(self, queryset, name, value):
|
||||
"""Filter by whether or not the order has a start date."""
|
||||
return queryset.filter(start_date__isnull=not str2bool(value))
|
||||
|
||||
start_date_before = InvenTreeDateFilter(
|
||||
label=_('Start date before'), field_name='start_date', lookup_expr='lt'
|
||||
)
|
||||
|
||||
start_date_after = InvenTreeDateFilter(
|
||||
label=_('Start date after'), field_name='start_date', lookup_expr='gt'
|
||||
)
|
||||
|
||||
has_target_date = rest_filters.BooleanFilter(
|
||||
label=_('Has target date'), method='filter_has_target_date'
|
||||
)
|
||||
|
||||
def filter_has_target_date(self, queryset, name, value):
|
||||
"""Filter by whether or not the order has a target date."""
|
||||
return queryset.filter(target_date__isnull=not str2bool(value))
|
||||
|
||||
target_date_before = InvenTreeDateFilter(
|
||||
label=_('Target date before'), field_name='target_date', lookup_expr='lt'
|
||||
)
|
||||
@@ -244,6 +268,7 @@ class BuildList(DataExportViewMixin, BuildMixin, ListCreateAPI):
|
||||
'part__name',
|
||||
'status',
|
||||
'creation_date',
|
||||
'start_date',
|
||||
'target_date',
|
||||
'completion_date',
|
||||
'quantity',
|
||||
|
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.18 on 2025-01-20 02:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('build', '0053_alter_build_part'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='build',
|
||||
name='start_date',
|
||||
field=models.DateField(blank=True, help_text='Scheduled start date for this build order', null=True, verbose_name='Build start date'),
|
||||
),
|
||||
]
|
@@ -67,7 +67,7 @@ class Build(
|
||||
Attributes:
|
||||
part: The part to be built (from component BOM items)
|
||||
reference: Build order reference (required, must be unique)
|
||||
title: Brief title describing the build (required)
|
||||
title: Brief title describing the build (optional)
|
||||
quantity: Number of units to be built
|
||||
parent: Reference to a Build object for which this Build is required
|
||||
sales_order: References to a SalesOrder object for which this Build is required (e.g. the output of this build will be used to fulfil a sales order)
|
||||
@@ -178,6 +178,12 @@ class Build(
|
||||
if self.has_field_changed('part'):
|
||||
raise ValidationError({'part': _('Build order part cannot be changed')})
|
||||
|
||||
# Target date should be *after* the start date
|
||||
if self.start_date and self.target_date and self.start_date > self.target_date:
|
||||
raise ValidationError({
|
||||
'target_date': _('Target date must be after start date')
|
||||
})
|
||||
|
||||
def report_context(self) -> dict:
|
||||
"""Generate custom report context data."""
|
||||
return {
|
||||
@@ -344,6 +350,13 @@ class Build(
|
||||
auto_now_add=True, editable=False, verbose_name=_('Creation Date')
|
||||
)
|
||||
|
||||
start_date = models.DateField(
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name=_('Build start date'),
|
||||
help_text=_('Scheduled start date for this build order'),
|
||||
)
|
||||
|
||||
target_date = models.DateField(
|
||||
null=True,
|
||||
blank=True,
|
||||
|
@@ -81,6 +81,7 @@ class BuildSerializer(
|
||||
'reference',
|
||||
'sales_order',
|
||||
'quantity',
|
||||
'start_date',
|
||||
'status',
|
||||
'status_text',
|
||||
'status_custom_key',
|
||||
|
@@ -1003,6 +1003,12 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
|
||||
'validator': bool,
|
||||
'after_save': reload_plugin_registry,
|
||||
},
|
||||
'PROJECT_CODES_ENABLED': {
|
||||
'name': _('Enable project codes'),
|
||||
'description': _('Enable project codes for tracking projects'),
|
||||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'STOCKTAKE_ENABLE': {
|
||||
'name': _('Stocktake Functionality'),
|
||||
'description': _(
|
||||
|
@@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import tablib
|
||||
from rest_framework import fields, serializers
|
||||
from taggit.serializers import TagListSerializerField
|
||||
|
||||
import importer.operations
|
||||
from InvenTree.helpers import DownloadFile, GetExportFormats, current_date
|
||||
@@ -81,6 +82,11 @@ class DataImportSerializerMixin:
|
||||
if issubclass(field.__class__, fields.FileField):
|
||||
continue
|
||||
|
||||
# Skip tags fields
|
||||
# TODO: Implement tag field support
|
||||
if issubclass(field.__class__, TagListSerializerField):
|
||||
continue
|
||||
|
||||
importable_fields[name] = field
|
||||
|
||||
return importable_fields
|
||||
|
@@ -683,7 +683,7 @@ class PartSerializer(
|
||||
Used when displaying all details of a single component.
|
||||
"""
|
||||
|
||||
import_exclude_fields = ['duplicate', 'tags']
|
||||
import_exclude_fields = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass defining serializer fields."""
|
||||
|
@@ -1985,9 +1985,18 @@ class StockItem(
|
||||
Returns:
|
||||
The new StockItem object
|
||||
|
||||
Raises:
|
||||
ValidationError: If the stock item cannot be split
|
||||
|
||||
- The provided quantity will be subtracted from this item and given to the new one.
|
||||
- The new item will have a different StockItem ID, while this will remain the same.
|
||||
"""
|
||||
# Run initial checks to test if the stock item can actually be "split"
|
||||
|
||||
# Cannot split a stock item which is in production
|
||||
if self.is_building:
|
||||
raise ValidationError(_('Stock item is currently in production'))
|
||||
|
||||
notes = kwargs.get('notes', '')
|
||||
|
||||
# Do not split a serialized part
|
||||
|
@@ -344,7 +344,7 @@ class StockItemSerializer(
|
||||
|
||||
export_only_fields = ['part_pricing_min', 'part_pricing_max']
|
||||
|
||||
import_exclude_fields = ['use_pack_size', 'tags']
|
||||
import_exclude_fields = ['use_pack_size']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
@@ -1142,7 +1142,7 @@ class LocationSerializer(
|
||||
):
|
||||
"""Detailed information about a stock location."""
|
||||
|
||||
import_exclude_fields = ['tags']
|
||||
import_exclude_fields = []
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
@@ -1565,18 +1565,18 @@ class StockAdjustmentItemSerializer(serializers.Serializer):
|
||||
help_text=_('StockItem primary key value'),
|
||||
)
|
||||
|
||||
def validate_pk(self, pk):
|
||||
def validate_pk(self, stock_item: StockItem) -> StockItem:
|
||||
"""Ensure the stock item is valid."""
|
||||
allow_out_of_stock_transfer = get_global_setting(
|
||||
'STOCK_ALLOW_OUT_OF_STOCK_TRANSFER', backup_value=False, cache=False
|
||||
)
|
||||
|
||||
if not allow_out_of_stock_transfer and not pk.is_in_stock(
|
||||
if not allow_out_of_stock_transfer and not stock_item.is_in_stock(
|
||||
check_status=False, check_quantity=False
|
||||
):
|
||||
raise ValidationError(_('Stock item is not in stock'))
|
||||
|
||||
return pk
|
||||
return stock_item
|
||||
|
||||
quantity = serializers.DecimalField(
|
||||
max_digits=15, decimal_places=5, min_value=Decimal(0), required=True
|
||||
|
Reference in New Issue
Block a user