2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-16 20:15:44 +00:00

Order start dates (#8966)

* Add 'start_date' field to orders

- PurchaseOrder
- SalesOrder
- ReturnOrder

* Add serializer field

* Add API filters

* Add table columns

* Add fields to forms

* Table filters

* Add validation check

* Refactor BuildOrderTable

* Update detail page

* Bump API version

* Allow sorting by start_date

* Fix for purchase order field

* Update detail pages

* Update playwright tests

* Updated playwright tests

* Documentation updates

* Updated playwright tests
This commit is contained in:
Oliver
2025-01-29 22:45:39 +11:00
committed by GitHub
parent 0c56a3132b
commit eee4916350
24 changed files with 317 additions and 45 deletions

View File

@ -170,6 +170,9 @@ export function usePurchaseOrderFields({
order_currency: {
icon: <IconCoins />
},
start_date: {
icon: <IconCalendar />
},
target_date: {
icon: <IconCalendar />
},

View File

@ -1,6 +1,11 @@
import { t } from '@lingui/macro';
import { Flex, Table } from '@mantine/core';
import { IconAddressBook, IconUser, IconUsers } from '@tabler/icons-react';
import {
IconAddressBook,
IconCalendar,
IconUser,
IconUsers
} from '@tabler/icons-react';
import { useMemo } from 'react';
import RemoveRowButton from '../components/buttons/RemoveRowButton';
@ -39,7 +44,12 @@ export function useReturnOrderFields({
customer_reference: {},
project_code: {},
order_currency: {},
target_date: {},
start_date: {
icon: <IconCalendar />
},
target_date: {
icon: <IconCalendar />
},
link: {},
contact: {
icon: <IconUser />,

View File

@ -1,6 +1,11 @@
import { t } from '@lingui/macro';
import { Table } from '@mantine/core';
import { IconAddressBook, IconUser, IconUsers } from '@tabler/icons-react';
import {
IconAddressBook,
IconCalendar,
IconUser,
IconUsers
} from '@tabler/icons-react';
import { useEffect, useMemo, useState } from 'react';
import RemoveRowButton from '../components/buttons/RemoveRowButton';
@ -40,7 +45,12 @@ export function useSalesOrderFields({
customer_reference: {},
project_code: {},
order_currency: {},
target_date: {},
start_date: {
icon: <IconCalendar />
},
target_date: {
icon: <IconCalendar />
},
link: {},
contact: {
icon: <IconUser />,

View File

@ -186,6 +186,7 @@ export default function BuildDetail() {
name: 'creation_date',
label: t`Created`,
icon: 'calendar',
copy: true,
hidden: !build.creation_date
},
{
@ -193,6 +194,7 @@ export default function BuildDetail() {
name: 'start_date',
label: t`Start Date`,
icon: 'calendar',
copy: true,
hidden: !build.start_date
},
{
@ -200,6 +202,7 @@ export default function BuildDetail() {
name: 'target_date',
label: t`Target Date`,
icon: 'calendar',
copy: true,
hidden: !build.target_date
},
{
@ -207,6 +210,7 @@ export default function BuildDetail() {
name: 'completion_date',
label: t`Completed`,
icon: 'calendar',
copy: true,
hidden: !build.completion_date
},
{

View File

@ -243,6 +243,14 @@ export default function PurchaseOrderDetail() {
copy: true,
hidden: !order.issue_date
},
{
type: 'date',
name: 'start_date',
label: t`Start Date`,
icon: 'calendar',
copy: true,
hidden: !order.start_date
},
{
type: 'date',
name: 'target_date',

View File

@ -214,6 +214,14 @@ export default function ReturnOrderDetail() {
copy: true,
hidden: !order.issue_date
},
{
type: 'date',
name: 'start_date',
label: t`Start Date`,
icon: 'calendar',
copy: true,
hidden: !order.start_date
},
{
type: 'date',
name: 'target_date',

View File

@ -225,6 +225,14 @@ export default function SalesOrderDetail() {
copy: true,
hidden: !order.issue_date
},
{
type: 'date',
name: 'start_date',
label: t`Start Date`,
icon: 'calendar',
hidden: !order.start_date,
copy: true
},
{
type: 'date',
name: 'target_date',

View File

@ -243,6 +243,14 @@ export function DateColumn(props: TableColumnProps): TableColumn {
};
}
export function StartDateColumn(props: TableColumnProps): TableColumn {
return DateColumn({
accessor: 'start_date',
title: t`Start Date`,
...props
});
}
export function TargetDateColumn(props: TableColumnProps): TableColumn {
return DateColumn({
accessor: 'target_date',

View File

@ -169,6 +169,24 @@ export function CreatedAfterFilter(): TableFilter {
};
}
export function StartDateBeforeFilter(): TableFilter {
return {
name: 'start_date_before',
label: t`Start Date Before`,
description: t`Show items with a start date before this date`,
type: 'date'
};
}
export function StartDateAfterFilter(): TableFilter {
return {
name: 'start_date_after',
label: t`Start Date After`,
description: t`Show items with a start date after this date`,
type: 'date'
};
}
export function TargetDateBeforeFilter(): TableFilter {
return {
name: 'target_date_before',

View File

@ -26,6 +26,7 @@ import {
ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn,
StartDateColumn,
StatusColumn,
TargetDateColumn
} from '../ColumnRenderers';
@ -43,6 +44,8 @@ import {
OverdueFilter,
ProjectCodeFilter,
ResponsibleFilter,
StartDateAfterFilter,
StartDateBeforeFilter,
type TableFilter,
TargetDateAfterFilter,
TargetDateBeforeFilter
@ -107,11 +110,7 @@ export function BuildOrderTable({
sortable: true
},
CreationDateColumn({}),
DateColumn({
accessor: 'start_date',
title: t`Start Date`,
sortable: true
}),
StartDateColumn({}),
TargetDateColumn({}),
DateColumn({
accessor: 'completion_date',
@ -156,18 +155,8 @@ export function BuildOrderTable({
CreatedAfterFilter(),
TargetDateBeforeFilter(),
TargetDateAfterFilter(),
{
name: 'start_date_before',
type: 'date',
label: t`Start Date Before`,
description: t`Show items with a start date before this date`
},
{
name: 'start_date_after',
type: 'date',
label: t`Start Date After`,
description: t`Show items with a start date after this date`
},
StartDateBeforeFilter(),
StartDateAfterFilter(),
{
name: 'has_target_date',
type: 'boolean',

View File

@ -26,6 +26,7 @@ import {
ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn,
StartDateColumn,
StatusColumn,
TargetDateColumn
} from '../ColumnRenderers';
@ -44,6 +45,8 @@ import {
OverdueFilter,
ProjectCodeFilter,
ResponsibleFilter,
StartDateAfterFilter,
StartDateBeforeFilter,
type TableFilter,
TargetDateAfterFilter,
TargetDateBeforeFilter
@ -79,6 +82,20 @@ export function PurchaseOrderTable({
CreatedAfterFilter(),
TargetDateBeforeFilter(),
TargetDateAfterFilter(),
StartDateBeforeFilter(),
StartDateAfterFilter(),
{
name: 'has_target_date',
type: 'boolean',
label: t`Has Target Date`,
description: t`Show orders with a target date`
},
{
name: 'has_start_date',
type: 'boolean',
label: t`Has Start Date`,
description: t`Show orders with a start date`
},
CompletedBeforeFilter(),
CompletedAfterFilter(),
ProjectCodeFilter({ choices: projectCodeFilters.choices }),
@ -120,6 +137,7 @@ export function PurchaseOrderTable({
ProjectCodeColumn({}),
CreationDateColumn({}),
CreatedByColumn({}),
StartDateColumn({}),
TargetDateColumn({}),
CompletionDateColumn({
accessor: 'complete_date'

View File

@ -26,6 +26,7 @@ import {
ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn,
StartDateColumn,
StatusColumn,
TargetDateColumn
} from '../ColumnRenderers';
@ -44,6 +45,8 @@ import {
OverdueFilter,
ProjectCodeFilter,
ResponsibleFilter,
StartDateAfterFilter,
StartDateBeforeFilter,
type TableFilter,
TargetDateAfterFilter,
TargetDateBeforeFilter
@ -76,6 +79,20 @@ export function ReturnOrderTable({
CreatedAfterFilter(),
TargetDateBeforeFilter(),
TargetDateAfterFilter(),
StartDateBeforeFilter(),
StartDateAfterFilter(),
{
name: 'has_target_date',
type: 'boolean',
label: t`Has Target Date`,
description: t`Show orders with a target date`
},
{
name: 'has_start_date',
type: 'boolean',
label: t`Has Start Date`,
description: t`Show orders with a start date`
},
CompletedBeforeFilter(),
CompletedAfterFilter(),
HasProjectCodeFilter(),
@ -129,6 +146,7 @@ export function ReturnOrderTable({
ProjectCodeColumn({}),
CreationDateColumn({}),
CreatedByColumn({}),
StartDateColumn({}),
TargetDateColumn({}),
CompletionDateColumn({
accessor: 'complete_date'

View File

@ -27,6 +27,7 @@ import {
ReferenceColumn,
ResponsibleColumn,
ShipmentDateColumn,
StartDateColumn,
StatusColumn,
TargetDateColumn
} from '../ColumnRenderers';
@ -45,6 +46,8 @@ import {
OverdueFilter,
ProjectCodeFilter,
ResponsibleFilter,
StartDateAfterFilter,
StartDateBeforeFilter,
type TableFilter,
TargetDateAfterFilter,
TargetDateBeforeFilter
@ -77,6 +80,20 @@ export function SalesOrderTable({
CreatedAfterFilter(),
TargetDateBeforeFilter(),
TargetDateAfterFilter(),
StartDateBeforeFilter(),
StartDateAfterFilter(),
{
name: 'has_target_date',
type: 'boolean',
label: t`Has Target Date`,
description: t`Show orders with a target date`
},
{
name: 'has_start_date',
type: 'boolean',
label: t`Has Start Date`,
description: t`Show orders with a start date`
},
CompletedBeforeFilter(),
CompletedAfterFilter(),
HasProjectCodeFilter(),
@ -166,6 +183,7 @@ export function SalesOrderTable({
ProjectCodeColumn({}),
CreationDateColumn({}),
CreatedByColumn({}),
StartDateColumn({}),
TargetDateColumn({}),
ShipmentDateColumn({}),
ResponsibleColumn({}),

View File

@ -3,11 +3,12 @@ import { baseUrl } from '../defaults.ts';
import {
clearTableFilters,
clickButtonIfVisible,
openFilterDrawer
openFilterDrawer,
setTableChoiceFilter
} from '../helpers.ts';
import { doQuickLogin } from '../login.ts';
test('Purchase Orders', async ({ page }) => {
test('Purchase Orders - List', async ({ page }) => {
await doQuickLogin(page);
await page.getByRole('tab', { name: 'Purchasing' }).click();
@ -22,10 +23,17 @@ test('Purchase Orders', async ({ page }) => {
await page.getByText('Pending').first().waitFor();
await page.getByText('On Hold').first().waitFor();
// Click through to a particular purchase order
await page.getByRole('cell', { name: 'PO0013' }).click();
// Filter by 'has start date'
await setTableChoiceFilter(page, 'Has Start Date', 'Yes');
await page.getByRole('cell', { name: 'Scheduled purchase order' }).waitFor();
// Click through to a particular purchase order
await page.getByRole('cell', { name: 'PO0015' }).click();
await page.getByRole('button', { name: 'Issue Order' }).waitFor();
// Expected values
await page.getByText('2025-06-12').waitFor(); // Start Date
await page.getByText('2025-07-17').waitFor(); // Target Date
});
test('Purchase Orders - Barcodes', async ({ page }) => {
@ -70,7 +78,7 @@ test('Purchase Orders - Barcodes', async ({ page }) => {
await page.getByRole('button', { name: 'Issue Order' }).waitFor();
// Ensure we can scan back to this page, with the associated barcode
await page.goto(`${baseUrl}/`);
await page.getByRole('tab', { name: 'Sales' }).click();
await page.waitForTimeout(250);
await page.getByRole('button', { name: 'Open Barcode Scanner' }).click();
await page.getByPlaceholder('Enter barcode data').fill('1234567890');

View File

@ -33,6 +33,7 @@ test('Tables - Filters', async ({ page }) => {
await setTableChoiceFilter(page, 'Responsible', 'readers');
await setTableChoiceFilter(page, 'Assigned to me', 'No');
await setTableChoiceFilter(page, 'Project Code', 'PRO-ZEN');
await setTableChoiceFilter(page, 'Has Start Date', 'Yes');
await clearTableFilters(page);
});
@ -49,4 +50,17 @@ test('Tables - Columns', async ({ page }) => {
// De-select some items
await page.getByRole('menuitem', { name: 'Description' }).click();
await page.getByRole('menuitem', { name: 'Stocktake' }).click();
await page.keyboard.press('Escape');
await page.goto(`${baseUrl}/sales/index/salesorders`);
// Open column selector
await page.getByLabel('table-select-columns').click();
await page.getByRole('menuitem', { name: 'Start Date' }).click();
await page.getByRole('menuitem', { name: 'Target Date' }).click();
await page.getByRole('menuitem', { name: 'Reference', exact: true }).click();
await page.getByRole('menuitem', { name: 'Project Code' }).click();
await page.waitForTimeout(1000);
});