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:
@ -170,6 +170,9 @@ export function usePurchaseOrderFields({
|
||||
order_currency: {
|
||||
icon: <IconCoins />
|
||||
},
|
||||
start_date: {
|
||||
icon: <IconCalendar />
|
||||
},
|
||||
target_date: {
|
||||
icon: <IconCalendar />
|
||||
},
|
||||
|
@ -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 />,
|
||||
|
@ -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 />,
|
||||
|
@ -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
|
||||
},
|
||||
{
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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({}),
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
});
|
||||
|
Reference in New Issue
Block a user