2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 19:46:46 +00:00

Duplicate orders via API (#8145)

* Refactor API endpoint for duplicating line items from a purchase order

- Previously was "hidden" (undocumented)
- Cleanup / refactor code
- Now matches part duplication options
- Generic implementation supports all order types

* Update forms

* Refactor line item duplication

* Implement front-end support for return orders

* Enable duplication of sales orders from PUI

* Bump API version
This commit is contained in:
Oliver 2024-09-19 13:17:50 +10:00 committed by GitHub
parent 461317c5c5
commit 6a8875a4a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 292 additions and 150 deletions

View File

@ -1,13 +1,16 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 254 INVENTREE_API_VERSION = 255
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v255 - 2024-09-19 : https://github.com/inventree/InvenTree/pull/8145
- Enables copying line items when duplicating an order
v254 - 2024-09-14 : https://github.com/inventree/InvenTree/pull/7470 v254 - 2024-09-14 : https://github.com/inventree/InvenTree/pull/7470
- Implements new API endpoints for enabling custom UI functionality via plugins - Implements new API endpoints for enabling custom UI functionality via plugins

View File

@ -5,7 +5,6 @@ from typing import cast
from django.conf import settings from django.conf import settings
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.db import transaction
from django.db.models import F, Q from django.db.models import F, Q
from django.http.response import JsonResponse from django.http.response import JsonResponse
from django.urls import include, path, re_path from django.urls import include, path, re_path
@ -14,7 +13,6 @@ from django.utils.translation import gettext_lazy as _
from django_filters import rest_framework as rest_filters from django_filters import rest_framework as rest_filters
from django_ical.views import ICalFeed from django_ical.views import ICalFeed
from rest_framework import status from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response from rest_framework.response import Response
import common.models import common.models
@ -214,54 +212,6 @@ class PurchaseOrderList(PurchaseOrderMixin, DataExportViewMixin, ListCreateAPI):
filterset_class = PurchaseOrderFilter filterset_class = PurchaseOrderFilter
def create(self, request, *args, **kwargs):
"""Save user information on create."""
data = self.clean_data(request.data)
duplicate_order = data.pop('duplicate_order', None)
duplicate_line_items = str2bool(data.pop('duplicate_line_items', False))
duplicate_extra_lines = str2bool(data.pop('duplicate_extra_lines', False))
if duplicate_order is not None:
try:
duplicate_order = models.PurchaseOrder.objects.get(pk=duplicate_order)
except (ValueError, models.PurchaseOrder.DoesNotExist):
raise ValidationError({
'duplicate_order': [_('No matching purchase order found')]
})
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
with transaction.atomic():
order = serializer.save()
order.created_by = request.user
order.save()
# Duplicate line items from other order if required
if duplicate_order is not None:
if duplicate_line_items:
for line in duplicate_order.lines.all():
# Copy the line across to the new order
line.pk = None
line.order = order
line.received = 0
line.save()
if duplicate_extra_lines:
for line in duplicate_order.extra_lines.all():
# Copy the line across to the new order
line.pk = None
line.order = order
line.save()
headers = self.get_success_headers(serializer.data)
return Response(
serializer.data, status=status.HTTP_201_CREATED, headers=headers
)
def filter_queryset(self, queryset): def filter_queryset(self, queryset):
"""Custom queryset filtering.""" """Custom queryset filtering."""
# Perform basic filtering # Perform basic filtering

View File

@ -247,6 +247,16 @@ class Order(
'contact': _('Contact does not match selected company') 'contact': _('Contact does not match selected company')
}) })
def clean_line_item(self, line):
"""Clean a line item for this order.
Used when duplicating an existing line item,
to ensure it is 'fresh'.
"""
line.pk = None
line.target_date = None
line.order = self
def report_context(self): def report_context(self):
"""Generate context data for the reporting interface.""" """Generate context data for the reporting interface."""
return { return {
@ -379,6 +389,11 @@ class PurchaseOrder(TotalPriceMixin, Order):
verbose_name = _('Purchase Order') verbose_name = _('Purchase Order')
def clean_line_item(self, line):
"""Clean a line item for this PurchaseOrder."""
super().clean_line_item(line)
line.received = 0
def report_context(self): def report_context(self):
"""Return report context data for this PurchaseOrder.""" """Return report context data for this PurchaseOrder."""
return {**super().report_context(), 'supplier': self.supplier} return {**super().report_context(), 'supplier': self.supplier}
@ -892,6 +907,11 @@ class SalesOrder(TotalPriceMixin, Order):
verbose_name = _('Sales Order') verbose_name = _('Sales Order')
def clean_line_item(self, line):
"""Clean a line item for this SalesOrder."""
super().clean_line_item(line)
line.shipped = 0
def report_context(self): def report_context(self):
"""Generate report context data for this SalesOrder.""" """Generate report context data for this SalesOrder."""
return {**super().report_context(), 'customer': self.customer} return {**super().report_context(), 'customer': self.customer}
@ -2083,6 +2103,12 @@ class ReturnOrder(TotalPriceMixin, Order):
verbose_name = _('Return Order') verbose_name = _('Return Order')
def clean_line_item(self, line):
"""Clean a line item for this ReturnOrder."""
super().clean_line_item(line)
line.received_date = None
line.outcome = ReturnOrderLineStatus.PENDING.value
def report_context(self): def report_context(self):
"""Generate report context data for this ReturnOrder.""" """Generate report context data for this ReturnOrder."""
return {**super().report_context(), 'customer': self.customer} return {**super().report_context(), 'customer': self.customer}

View File

@ -74,10 +74,39 @@ class TotalPriceMixin(serializers.Serializer):
) )
class DuplicateOrderSerializer(serializers.Serializer):
"""Serializer for specifying options when duplicating an order."""
class Meta:
"""Metaclass options."""
fields = ['order_id', 'copy_lines', 'copy_extra_lines']
order_id = serializers.IntegerField(
required=True, label=_('Order ID'), help_text=_('ID of the order to duplicate')
)
copy_lines = serializers.BooleanField(
required=False,
default=True,
label=_('Copy Lines'),
help_text=_('Copy line items from the original order'),
)
copy_extra_lines = serializers.BooleanField(
required=False,
default=True,
label=_('Copy Extra Lines'),
help_text=_('Copy extra line items from the original order'),
)
class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Serializer): class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Serializer):
"""Abstract serializer class which provides fields common to all order types.""" """Abstract serializer class which provides fields common to all order types."""
export_exclude_fields = ['notes'] export_exclude_fields = ['notes', 'duplicate']
import_exclude_fields = ['notes', 'duplicate']
# Number of line items in this order # Number of line items in this order
line_items = serializers.IntegerField(read_only=True, label=_('Line Items')) line_items = serializers.IntegerField(read_only=True, label=_('Line Items'))
@ -127,6 +156,13 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
required=False, allow_null=True, label=_('Creation Date') required=False, allow_null=True, label=_('Creation Date')
) )
duplicate = DuplicateOrderSerializer(
label=_('Duplicate Order'),
help_text=_('Specify options for duplicating this order'),
required=False,
write_only=True,
)
def validate_reference(self, reference): def validate_reference(self, reference):
"""Custom validation for the reference field.""" """Custom validation for the reference field."""
self.Meta.model.validate_reference_field(reference) self.Meta.model.validate_reference_field(reference)
@ -166,9 +202,49 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
'notes', 'notes',
'barcode_hash', 'barcode_hash',
'overdue', 'overdue',
'duplicate',
*extra_fields, *extra_fields,
] ]
def clean_line_item(self, line):
"""Clean a line item object (when duplicating)."""
line.pk = None
line.order = self
@transaction.atomic
def create(self, validated_data):
"""Create a new order object.
Optionally, copy line items from an existing order.
"""
duplicate = validated_data.pop('duplicate', None)
instance = super().create(validated_data)
if duplicate:
order_id = duplicate.get('order_id', None)
copy_lines = duplicate.get('copy_lines', True)
copy_extra_lines = duplicate.get('copy_extra_lines', True)
try:
copy_from = instance.__class__.objects.get(pk=order_id)
except Exception:
# If the order ID is invalid, raise a validation error
raise ValidationError(_('Invalid order ID'))
if copy_lines:
for line in copy_from.lines.all():
instance.clean_line_item(line)
line.save()
if copy_extra_lines:
for line in copy_from.extra_lines.all():
line.pk = None
line.order = instance
line.save()
return instance
class AbstractLineItemSerializer: class AbstractLineItemSerializer:
"""Abstract serializer for LineItem object.""" """Abstract serializer for LineItem object."""
@ -259,6 +335,12 @@ class PurchaseOrderSerializer(
if supplier_detail is not True: if supplier_detail is not True:
self.fields.pop('supplier_detail', None) self.fields.pop('supplier_detail', None)
def skip_create_fields(self):
"""Skip these fields when instantiating a new object."""
fields = super().skip_create_fields()
return [*fields, 'duplicate']
@staticmethod @staticmethod
def annotate_queryset(queryset): def annotate_queryset(queryset):
"""Add extra information to the queryset. """Add extra information to the queryset.
@ -900,6 +982,12 @@ class SalesOrderSerializer(
if customer_detail is not True: if customer_detail is not True:
self.fields.pop('customer_detail', None) self.fields.pop('customer_detail', None)
def skip_create_fields(self):
"""Skip these fields when instantiating a new object."""
fields = super().skip_create_fields()
return [*fields, 'duplicate']
@staticmethod @staticmethod
def annotate_queryset(queryset): def annotate_queryset(queryset):
"""Add extra information to the queryset. """Add extra information to the queryset.
@ -1692,6 +1780,12 @@ class ReturnOrderSerializer(
if customer_detail is not True: if customer_detail is not True:
self.fields.pop('customer_detail', None) self.fields.pop('customer_detail', None)
def skip_create_fields(self):
"""Skip these fields when instantiating a new object."""
fields = super().skip_create_fields()
return [*fields, 'duplicate']
@staticmethod @staticmethod
def annotate_queryset(queryset): def annotate_queryset(queryset):
"""Custom annotation for the serializer queryset.""" """Custom annotation for the serializer queryset."""

View File

@ -439,18 +439,22 @@ class PurchaseOrderTest(OrderTest):
del data['reference'] del data['reference']
# Duplicate with non-existent PK to provoke error # Duplicate with non-existent PK to provoke error
data['duplicate_order'] = 10000001 data['duplicate'] = {
data['duplicate_line_items'] = True 'order_id': 10000001,
data['duplicate_extra_lines'] = False 'copy_lines': True,
'copy_extra_lines': False,
}
data['reference'] = 'PO-9999' data['reference'] = 'PO-9999'
# Duplicate via the API # Duplicate via the API
response = self.post(reverse('api-po-list'), data, expected_code=400) response = self.post(reverse('api-po-list'), data, expected_code=400)
data['duplicate_order'] = 1 data['duplicate'] = {
data['duplicate_line_items'] = True 'order_id': 1,
data['duplicate_extra_lines'] = False 'copy_lines': True,
'copy_extra_lines': False,
}
data['reference'] = 'PO-9999' data['reference'] = 'PO-9999'
@ -466,8 +470,12 @@ class PurchaseOrderTest(OrderTest):
self.assertEqual(po_dup.lines.count(), po.lines.count()) self.assertEqual(po_dup.lines.count(), po.lines.count())
data['reference'] = 'PO-9998' data['reference'] = 'PO-9998'
data['duplicate_line_items'] = False
data['duplicate_extra_lines'] = True data['duplicate'] = {
'order_id': 1,
'copy_lines': False,
'copy_extra_lines': True,
}
response = self.post(reverse('api-po-list'), data, expected_code=201) response = self.post(reverse('api-po-list'), data, expected_code=201)

View File

@ -98,7 +98,8 @@ function purchaseOrderFields(options={}) {
return fields; return fields;
} }
} },
disabled: !!options.duplicate_order,
}, },
supplier_reference: {}, supplier_reference: {},
project_code: { project_code: {
@ -155,35 +156,13 @@ function purchaseOrderFields(options={}) {
// Add fields for order duplication (only if required) // Add fields for order duplication (only if required)
if (options.duplicate_order) { if (options.duplicate_order) {
fields.duplicate_order = { fields.duplicate__order_id = {
value: options.duplicate_order, value: options.duplicate_order,
group: 'duplicate', hidden: true,
required: 'true',
type: 'related field',
model: 'purchaseorder',
filters: {
supplier_detail: true,
},
api_url: '{% url "api-po-list" %}',
label: '{% trans "Purchase Order" %}',
help_text: '{% trans "Select purchase order to duplicate" %}',
}; };
fields.duplicate_line_items = { fields.duplicate__copy_lines = {};
value: true, fields.duplicate__copy_extra_lines = {};
group: 'duplicate',
type: 'boolean',
label: '{% trans "Duplicate Line Items" %}',
help_text: '{% trans "Duplicate all line items from the selected order" %}',
};
fields.duplicate_extra_lines = {
value: true,
group: 'duplicate',
type: 'boolean',
label: '{% trans "Duplicate Extra Lines" %}',
help_text: '{% trans "Duplicate extra line items from the selected order" %}',
};
} }
if (!global_settings.PROJECT_CODES_ENABLED) { if (!global_settings.PROJECT_CODES_ENABLED) {

View File

@ -138,14 +138,19 @@ export function usePurchaseOrderLineItemFields({
/** /**
* Construct a set of fields for creating / editing a PurchaseOrder instance * Construct a set of fields for creating / editing a PurchaseOrder instance
*/ */
export function usePurchaseOrderFields(): ApiFormFieldSet { export function usePurchaseOrderFields({
duplicateOrderId
}: {
duplicateOrderId?: number;
}): ApiFormFieldSet {
return useMemo(() => { return useMemo(() => {
return { let fields: ApiFormFieldSet = {
reference: { reference: {
icon: <IconHash /> icon: <IconHash />
}, },
description: {}, description: {},
supplier: { supplier: {
disabled: duplicateOrderId !== undefined,
filters: { filters: {
is_supplier: true, is_supplier: true,
active: true active: true
@ -187,7 +192,23 @@ export function usePurchaseOrderFields(): ApiFormFieldSet {
icon: <IconUsers /> icon: <IconUsers />
} }
}; };
}, []);
// Order duplication fields
if (!!duplicateOrderId) {
fields.duplicate = {
children: {
order_id: {
hidden: true,
value: duplicateOrderId
},
copy_lines: {},
copy_extra_lines: {}
}
};
}
return fields;
}, [duplicateOrderId]);
} }
/** /**

View File

@ -1,16 +1,88 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Flex, Table } from '@mantine/core'; import { Flex, Table } from '@mantine/core';
import { IconUsers } from '@tabler/icons-react'; import { IconAddressBook, IconUser, IconUsers } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import RemoveRowButton from '../components/buttons/RemoveRowButton'; import RemoveRowButton from '../components/buttons/RemoveRowButton';
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; import {
ApiFormAdjustFilterType,
ApiFormFieldSet
} from '../components/forms/fields/ApiFormField';
import { TableFieldRowProps } from '../components/forms/fields/TableField'; import { TableFieldRowProps } from '../components/forms/fields/TableField';
import { Thumbnail } from '../components/images/Thumbnail'; import { Thumbnail } from '../components/images/Thumbnail';
import { ApiEndpoints } from '../enums/ApiEndpoints'; import { ApiEndpoints } from '../enums/ApiEndpoints';
import { useCreateApiFormModal } from '../hooks/UseForm'; import { useCreateApiFormModal } from '../hooks/UseForm';
import { apiUrl } from '../states/ApiState'; import { apiUrl } from '../states/ApiState';
export function useReturnOrderFields({
duplicateOrderId
}: {
duplicateOrderId?: number;
}): ApiFormFieldSet {
return useMemo(() => {
let fields: ApiFormFieldSet = {
reference: {},
description: {},
customer: {
disabled: duplicateOrderId != undefined,
filters: {
is_customer: true,
active: true
}
},
customer_reference: {},
project_code: {},
order_currency: {},
target_date: {},
link: {},
contact: {
icon: <IconUser />,
adjustFilters: (value: ApiFormAdjustFilterType) => {
return {
...value.filters,
company: value.data.customer
};
}
},
address: {
icon: <IconAddressBook />,
adjustFilters: (value: ApiFormAdjustFilterType) => {
return {
...value.filters,
company: value.data.customer
};
}
},
responsible: {
filters: {
is_active: true
},
icon: <IconUsers />
}
};
// Order duplication fields
if (!!duplicateOrderId) {
fields.duplicate = {
children: {
order_id: {
hidden: true,
value: duplicateOrderId
},
copy_lines: {
// Cannot duplicate lines from a return order!
value: false,
hidden: true
},
copy_extra_lines: {}
}
};
}
return fields;
}, [duplicateOrderId]);
}
export function useReturnOrderLineItemFields({ export function useReturnOrderLineItemFields({
orderId, orderId,
customerId, customerId,

View File

@ -6,12 +6,17 @@ import {
ApiFormFieldSet ApiFormFieldSet
} from '../components/forms/fields/ApiFormField'; } from '../components/forms/fields/ApiFormField';
export function useSalesOrderFields(): ApiFormFieldSet { export function useSalesOrderFields({
duplicateOrderId
}: {
duplicateOrderId?: number;
}): ApiFormFieldSet {
return useMemo(() => { return useMemo(() => {
return { let fields: ApiFormFieldSet = {
reference: {}, reference: {},
description: {}, description: {},
customer: { customer: {
disabled: duplicateOrderId != undefined,
filters: { filters: {
is_customer: true, is_customer: true,
active: true active: true
@ -44,7 +49,23 @@ export function useSalesOrderFields(): ApiFormFieldSet {
icon: <IconUsers /> icon: <IconUsers />
} }
}; };
}, []);
// Order duplication fields
if (!!duplicateOrderId) {
fields.duplicate = {
children: {
order_id: {
hidden: true,
value: duplicateOrderId
},
copy_lines: {},
copy_extra_lines: {}
}
};
}
return fields;
}, [duplicateOrderId]);
} }
export function useSalesOrderLineItemFields({ export function useSalesOrderLineItemFields({
@ -125,47 +146,3 @@ export function useSalesOrderShipmentFields(): ApiFormFieldSet {
}; };
}, []); }, []);
} }
export function useReturnOrderFields(): ApiFormFieldSet {
return useMemo(() => {
return {
reference: {},
description: {},
customer: {
filters: {
is_customer: true,
active: true
}
},
customer_reference: {},
project_code: {},
order_currency: {},
target_date: {},
link: {},
contact: {
icon: <IconUser />,
adjustFilters: (value: ApiFormAdjustFilterType) => {
return {
...value.filters,
company: value.data.customer
};
}
},
address: {
icon: <IconAddressBook />,
adjustFilters: (value: ApiFormAdjustFilterType) => {
return {
...value.filters,
company: value.data.customer
};
}
},
responsible: {
filters: {
is_active: true
},
icon: <IconUsers />
}
};
}, []);
}

View File

@ -81,7 +81,11 @@ export default function PurchaseOrderDetail() {
); );
}, [order, globalSettings]); }, [order, globalSettings]);
const purchaseOrderFields = usePurchaseOrderFields(); const purchaseOrderFields = usePurchaseOrderFields({});
const duplicatePurchaseOrderFields = usePurchaseOrderFields({
duplicateOrderId: order.pk
});
const editPurchaseOrder = useEditApiFormModal({ const editPurchaseOrder = useEditApiFormModal({
url: ApiEndpoints.purchase_order_list, url: ApiEndpoints.purchase_order_list,
@ -96,7 +100,7 @@ export default function PurchaseOrderDetail() {
const duplicatePurchaseOrder = useCreateApiFormModal({ const duplicatePurchaseOrder = useCreateApiFormModal({
url: ApiEndpoints.purchase_order_list, url: ApiEndpoints.purchase_order_list,
title: t`Add Purchase Order`, title: t`Add Purchase Order`,
fields: purchaseOrderFields, fields: duplicatePurchaseOrderFields,
initialData: { initialData: {
...order, ...order,
reference: undefined reference: undefined

View File

@ -34,7 +34,7 @@ import { formatCurrency } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useReturnOrderFields } from '../../forms/SalesOrderForms'; import { useReturnOrderFields } from '../../forms/ReturnOrderForms';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useEditApiFormModal useEditApiFormModal
@ -304,7 +304,11 @@ export default function ReturnOrderDetail() {
]; ];
}, [order, instanceQuery]); }, [order, instanceQuery]);
const returnOrderFields = useReturnOrderFields(); const returnOrderFields = useReturnOrderFields({});
const duplicateReturnOrderFields = useReturnOrderFields({
duplicateOrderId: order.pk
});
const editReturnOrder = useEditApiFormModal({ const editReturnOrder = useEditApiFormModal({
url: ApiEndpoints.return_order_list, url: ApiEndpoints.return_order_list,
@ -319,7 +323,7 @@ export default function ReturnOrderDetail() {
const duplicateReturnOrder = useCreateApiFormModal({ const duplicateReturnOrder = useCreateApiFormModal({
url: ApiEndpoints.return_order_list, url: ApiEndpoints.return_order_list,
title: t`Add Return Order`, title: t`Add Return Order`,
fields: returnOrderFields, fields: duplicateReturnOrderFields,
initialData: { initialData: {
...order, ...order,
reference: undefined reference: undefined

View File

@ -231,7 +231,7 @@ export default function SalesOrderDetail() {
const soStatus = useStatusCodes({ modelType: ModelType.salesorder }); const soStatus = useStatusCodes({ modelType: ModelType.salesorder });
const salesOrderFields = useSalesOrderFields(); const salesOrderFields = useSalesOrderFields({});
const editSalesOrder = useEditApiFormModal({ const editSalesOrder = useEditApiFormModal({
url: ApiEndpoints.sales_order_list, url: ApiEndpoints.sales_order_list,
@ -243,10 +243,14 @@ export default function SalesOrderDetail() {
} }
}); });
const duplicateOrderFields = useSalesOrderFields({
duplicateOrderId: order.pk
});
const duplicateSalesOrder = useCreateApiFormModal({ const duplicateSalesOrder = useCreateApiFormModal({
url: ApiEndpoints.sales_order_list, url: ApiEndpoints.sales_order_list,
title: t`Add Sales Order`, title: t`Add Sales Order`,
fields: salesOrderFields, fields: duplicateOrderFields,
initialData: { initialData: {
...order, ...order,
reference: undefined reference: undefined

View File

@ -121,7 +121,7 @@ export function PurchaseOrderTable({
]; ];
}, []); }, []);
const purchaseOrderFields = usePurchaseOrderFields(); const purchaseOrderFields = usePurchaseOrderFields({});
const newPurchaseOrder = useCreateApiFormModal({ const newPurchaseOrder = useCreateApiFormModal({
url: ApiEndpoints.purchase_order_list, url: ApiEndpoints.purchase_order_list,

View File

@ -7,7 +7,7 @@ import { formatCurrency } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useReturnOrderFields } from '../../forms/SalesOrderForms'; import { useReturnOrderFields } from '../../forms/ReturnOrderForms';
import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter'; import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
@ -112,7 +112,7 @@ export function ReturnOrderTable({ params }: Readonly<{ params?: any }>) {
]; ];
}, []); }, []);
const returnOrderFields = useReturnOrderFields(); const returnOrderFields = useReturnOrderFields({});
const newReturnOrder = useCreateApiFormModal({ const newReturnOrder = useCreateApiFormModal({
url: ApiEndpoints.return_order_list, url: ApiEndpoints.return_order_list,

View File

@ -77,7 +77,7 @@ export function SalesOrderTable({
]; ];
}, [projectCodeFilters.choices, responsibleFilters.choices]); }, [projectCodeFilters.choices, responsibleFilters.choices]);
const salesOrderFields = useSalesOrderFields(); const salesOrderFields = useSalesOrderFields({});
const newSalesOrder = useCreateApiFormModal({ const newSalesOrder = useCreateApiFormModal({
url: ApiEndpoints.sales_order_list, url: ApiEndpoints.sales_order_list,