Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5675.2 link requisition modal #6330

Merged
merged 11 commits into from
Jan 30, 2025
14 changes: 8 additions & 6 deletions client/packages/common/src/intl/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,16 +275,17 @@
"error.login-support": "Please contact [email protected] if you are unable to login to your account",
"error.manufacturer-model-unique": "An item already exists with this manufacturer and model",
"error.master-list-not-found": "Master list not found",
"error.max-orders-reached-for-period": "Maximum requisitions for this period already created",
"error.missing-central-sync": "Could not reach mSupply central server",
"error.missing-inputs": "{{count}}",
"error.more-info": "More information",
"error.name-program-duplicate": "Vaccine course name already exists for this program",
"error.no-asset-create-permission": "You do not have permission to create a new asset.",
"error.no-asset-edit-permission": "You do not have permission to edit assets.",
"error.no-asset-view-permission": "You do not have permission to view assets.",
"error.no-create-outbound-shipment-permission": "You do not have permission to create an Outbound Shipment from a Requisition",
"error.no-customer-return-items": "No items have been added to this return.",
"error.no-customer-returns": "There are no Customer Returns to display.",
"error.no-create-outbound-shipment-permission": "You do not have permission to create an Outbound Shipment from a Requisition",
"error.no-data": "No data available",
"error.no-immunisation-programs": "No Immunization programs found",
"error.no-inbound-items": "No items have been added to this shipment.",
Expand Down Expand Up @@ -373,6 +374,7 @@
"error.unable-to-connect-to-printer": "Unable to connect to printer.",
"error.unable-to-create-cce": "Unable to create CCE",
"error.unable-to-create-immunisation-program": "Unable to create Immunisation Program",
"error.unable-to-create-requisition": "Unable to creare requisition",
"error.unable-to-detect-scanner": "Unable to detect a scanner",
"error.unable-to-initialise": "Unable to initialise",
"error.unable-to-insert-vaccine-course": "Unable to insert vaccine course",
Expand All @@ -397,8 +399,6 @@
"error.v6-server-not-configured-hint": "Check the central server URL",
"error.vaccine-course-update-failed": "Vaccine course failed to save",
"error.value-type-not-correct": "Value type not correct",
"error.unable-to-create-requisition": "Unable to creare requisition",
"error.max-orders-reached-for-period": "Maximum requisitions for this period already created",
"facilities": "Facilities",
"filename.asset-categories": "asset-categories",
"filename.asset-import-example": "Example Asset Item Import",
Expand All @@ -420,6 +420,7 @@
"filename.stocktakes": "stocktakes",
"filename.supplier-returns": "supplier-returns",
"format.comment": "Acknowledged by {{name}} on {{date}}: {{comment}}.",
"header.link-internal-order": "Link Internal Order",
"heading.404": "Feeling lost?",
"heading.acknowledgeBreach": "Acknowledge Breach",
"heading.actions": "Actions",
Expand Down Expand Up @@ -595,8 +596,8 @@
"label.calculated-demand": "Calculated Demand",
"label.cant-change-location": "Can only change location of lines when status is New",
"label.cant-delete-disabled": "Can only delete lines when status is New",
"label.cant-delete-disabled-requisition": "Can only delete lines when requisition is in Draft",
"label.cant-delete-disabled-internal-order": "Can only delete lines when internal order is in Draft",
"label.cant-delete-disabled-requisition": "Can only delete lines when requisition is in Draft",
fergie-nz marked this conversation as resolved.
Show resolved Hide resolved
"label.cant-zero-quantity-disabled": "Quantities of lines can only be set to 0 when status is New",
"label.cant-zero-stock-lines-disabled": "Quantites of lines can only be reduced to 0 when status is New",
"label.catalogue-item": "Catalogue item",
Expand Down Expand Up @@ -751,6 +752,7 @@
"label.forecast-quantity": "Suggested Quantity",
"label.from-age": "From age",
"label.from-created-datetime": "From created date / time",
"label.from-date": "From date",
"label.from-datetime": "From date / time",
"label.from-expiry": "From expiry",
"label.from-start-datetime": "From start date / time",
Expand Down Expand Up @@ -1057,10 +1059,9 @@
"label.time": "Time",
"label.to-age": "To age",
"label.to-created-datetime": "To created date / time",
"label.to-date": "To date",
"label.to-datetime": "To date / time",
"label.to-expiry": "To expiry",
"label.from-date": "From date",
"label.to-date": "To date",
"label.to-start-datetime": "To start date / time",
"label.today": "Today",
"label.toggle-password-visibility": "Toggle password visibility",
Expand Down Expand Up @@ -1193,6 +1194,7 @@
"message.confirm-delete-encounter": "Are you sure?",
"message.confirm-save-new": "Click OK to save the new item, or Cancel to continue editing",
"message.contact-support": "Please contact [email protected] about configuring reports",
"message.continue-to-make-inbound-shipment": "Click Next to continue to make an Inbound Dhipment without linking an Internal Order.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo on Shipment :)

Copy link
Contributor Author

@roxy-dao roxy-dao Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling is hard Ferg 🀣

"message.copy-success": "Copied to clipboard successfully",
"message.database-not-local": "Database is running on a server, so can't be downloaded here",
"message.database-not-sqlite": "Database download is only available for SQLite databases",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC } from 'react';
import React, { useEffect, useState } from 'react';
import { AppRoute } from '@openmsupply-client/config';
import {
FnUtils,
Expand All @@ -16,23 +16,38 @@ import {
EnvUtils,
useNavigate,
RouteBuilder,
useAuthContext,
} from '@openmsupply-client/common';
import { SupplierSearchModal } from '@openmsupply-client/system';
import { useInbound } from '../api';
import {
NameRowFragment,
SupplierSearchModal,
} from '@openmsupply-client/system';
import { LinkedRequestRowFragment, useInbound } from '../api';
import { inboundsToCsv } from '../../utils';
import { LinkInternalOrderModal } from './LinkInternalOrderModal';

export const AppBarButtons: FC<{
modalController: ToggleState;
}> = ({ modalController }) => {
export const AppBarButtons = ({
invoiceModalController,
linkRequestModalController,
}: {
invoiceModalController: ToggleState;
linkRequestModalController: ToggleState;
}) => {
const t = useTranslation();
const navigate = useNavigate();
const { mutateAsync: onCreate } = useInbound.document.insert();
const { success, error } = useNotification();
const { store } = useAuthContext();
const [name, setName] = useState<NameRowFragment | null>(null);
const { mutateAsync: onCreate } = useInbound.document.insert();
const { isLoading, fetchAsync } = useInbound.document.listAll({
key: 'createdDateTime',
direction: 'desc',
isDesc: true,
});
const { data, isLoading: internalOrderIsLoading } =
useInbound.document.listInternalOrders(name?.id ?? '');
const manuallyLinkInternalOrder =
store?.preferences.manuallyLinkInternalOrderToInboundShipment;

const csvExport = async () => {
const data = await fetchAsync();
Expand All @@ -46,13 +61,47 @@ export const AppBarButtons: FC<{
success(t('success'))();
};

const createInvoice = async (nameId: string) => {
const invoiceNumber = await onCreate({
id: FnUtils.generateUUID(),
otherPartyId: nameId,
});

navigate(
RouteBuilder.create(AppRoute.Replenishment)
.addPart(AppRoute.InboundShipment)
.addPart(String(invoiceNumber))
.build()
);
};
useEffect(() => {
if (name && (data?.totalCount === 0 || !manuallyLinkInternalOrder)) {
createInvoice(name.id);
}
}, [name, data]);

Comment on lines +77 to +81
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to think of a way of doing this without useEffect... but.. yeah can't call in the supplier's modal onChange since it will never stay on the 'list view' page

const onRowClick = async (row: LinkedRequestRowFragment) => {
const invoiceNumber = await onCreate({
id: FnUtils.generateUUID(),
otherPartyId: name?.id ?? '',
requisitionId: row.id,
});

navigate(
RouteBuilder.create(AppRoute.Replenishment)
.addPart(AppRoute.InboundShipment)
.addPart(String(invoiceNumber))
.build()
);
};

return (
<AppBarButtonsPortal>
<Grid container gap={1}>
<ButtonWithIcon
Icon={<PlusCircleIcon />}
label={t('button.new-shipment')}
onClick={modalController.toggleOn}
onClick={invoiceModalController.toggleOn}
/>
<LoadingButton
startIcon={<DownloadIcon />}
Expand All @@ -63,22 +112,30 @@ export const AppBarButtons: FC<{
label={t('button.export')}
/>
</Grid>

{data?.totalCount !== 0 && manuallyLinkInternalOrder && (
<LinkInternalOrderModal
requestRequisitions={data?.nodes}
isOpen={linkRequestModalController.isOn}
onClose={linkRequestModalController.toggleOff}
onRowClick={onRowClick}
isLoading={internalOrderIsLoading}
onNextClick={() => {
if (name) {
createInvoice(name.id);
}
}}
/>
)}
<SupplierSearchModal
open={modalController.isOn}
onClose={modalController.toggleOff}
onChange={async name => {
modalController.toggleOff();
await onCreate({
id: FnUtils.generateUUID(),
otherPartyId: name?.id,
}).then(invoiceNumber => {
navigate(
RouteBuilder.create(AppRoute.Replenishment)
.addPart(AppRoute.InboundShipment)
.addPart(String(invoiceNumber))
.build()
);
});
open={invoiceModalController.isOn}
onClose={invoiceModalController.toggleOff}
onChange={nameRow => {
setName(nameRow);
invoiceModalController.toggleOff();
if (manuallyLinkInternalOrder) {
linkRequestModalController.toggleOn();
}
}}
/>
</AppBarButtonsPortal>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import { LinkedRequestRowFragment } from '../api';
import {
useColumns,
getNotePopoverColumn,
ColumnAlign,
DataTable,
useWindowDimensions,
useTranslation,
useDialog,
DialogButton,
Typography,
} from '@openmsupply-client/common';

interface LinkInternalOrderModalProps {
isOpen: boolean;
onClose: () => void;
requestRequisitions?: LinkedRequestRowFragment[];
onRowClick: (row: LinkedRequestRowFragment) => void;
isLoading: boolean;
onNextClick: () => void;
}

export const LinkInternalOrderModal = ({
isOpen,
onClose,
requestRequisitions: data,
onRowClick,
isLoading,
onNextClick: createInvoice,
}: LinkInternalOrderModalProps) => {
const t = useTranslation();
const { width, height } = useWindowDimensions();
const { Modal } = useDialog({ isOpen, onClose });

const columns = useColumns<LinkedRequestRowFragment>([
{
Copy link
Contributor Author

@roxy-dao roxy-dao Jan 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have removed the selection box from design and have used onRowClick instead as per our pattern. Design also doesn't allow users to create an IS without linking from this modal. SO have added a next button with message to state what it does

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! On first pass, it wasn't obvious to me that the next button would allow you to create a linked in bound shipment. I wonder if maybe some UX to show this better?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind! I just saw now your latest commit adds messaging

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still thinking a different text for next button would be better (and then doesn't require messaging) would be preferred - but this still works great

Copy link
Contributor Author

@roxy-dao roxy-dao Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continue or next. Either way it's not clear and we don't wanna put lots of text into a button

key: 'requisitionNumber',
label: 'label.number',
width: 80,
align: ColumnAlign.Right,
},
['createdDatetime', { width: 80, align: ColumnAlign.Right }],
{
key: 'username',
label: 'label.entered-by',
width: 150,
accessor: ({ rowData }) => rowData?.user?.username ?? '',
},
{
key: 'programName',
label: 'label.program',
accessor: ({ rowData }) => rowData.program?.name ?? '',
width: 200,
},
['theirReference', { width: 150 }],
[
getNotePopoverColumn(),
{
accessor: ({ rowData }) => {
return { header: '', body: rowData.comment };
},
},
],
]);

return (
<Modal
title={t('header.link-internal-order')}
width={width * 0.7}
height={height * 0.8}
nextButton={<DialogButton variant="next" onClick={createInvoice} />}
cancelButton={<DialogButton variant="cancel" onClick={onClose} />}
>
<>
<Typography
sx={{
fontStyle: 'italic',
}}
>
{t('message.continue-to-make-inbound-shipment')}
</Typography>
<DataTable
id="link-internal-order-to-inbound"
columns={columns}
data={data ?? []}
dense
onRowClick={onRowClick}
isLoading={isLoading}
/>
</>
</Modal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export const InboundListView: FC = () => {
const queryParams = { ...filter, sortBy, first, offset };

const navigate = useNavigate();
const modalController = useToggle();
const invoiceModalController = useToggle();
const linkRequestModalController = useToggle();

const { data, isError, isLoading } = useInbound.document.list(queryParams);
useDisableInboundRows(data?.nodes);
Expand Down Expand Up @@ -96,7 +97,10 @@ export const InboundListView: FC = () => {
return (
<>
<Toolbar filter={filter} />
<AppBarButtons modalController={modalController} />
<AppBarButtons
invoiceModalController={invoiceModalController}
linkRequestModalController={linkRequestModalController}
/>

<DataTable
id="inbound-line-list"
Expand All @@ -112,7 +116,7 @@ export const InboundListView: FC = () => {
noDataElement={
<NothingHere
body={t('error.no-inbound-shipments')}
onCreate={modalController.toggleOn}
onCreate={invoiceModalController.toggleOn}
/>
}
enableColumnSelection
Expand Down
17 changes: 17 additions & 0 deletions client/packages/invoices/src/InboundShipment/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
InsertInboundShipmentServiceLineInput,
UpdateInboundShipmentServiceLineInput,
DeleteInboundShipmentServiceLineInput,
RequisitionSortFieldInput,
RequisitionNodeType,
} from '@openmsupply-client/common';
import { DraftInboundLine } from './../../types';
import { isA } from '../../utils';
Expand Down Expand Up @@ -208,6 +210,21 @@ export const getInboundQueries = (sdk: Sdk, storeId: string) => ({

throw new Error('Could not find invoice!');
},
listInternalOrders: async (otherPartyId: string) => {
const filter = {
type: { equalTo: RequisitionNodeType.Request },
otherPartyId: { equalTo: otherPartyId },
};
const result = await sdk.requests({
storeId,
sort: {
key: RequisitionSortFieldInput.CreatedDatetime,
desc: true,
},
filter,
});
return result?.requisitions;
},
},
delete: async (invoices: InboundRowFragment[]): Promise<string[]> => {
const result =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useNextItem } from './useNextItem';
import { useUpdateInbound } from './useUpdateInbound';
import { useUpdateInboundServiceTax } from './useInboundUpdateServiceTax';
import { useInboundDelete } from './useInboundDelete';
import { useListInternalOrders } from './useListInternalOrders';

export const Document = {
useInboundDeleteRows,
Expand All @@ -20,4 +21,5 @@ export const Document = {
useNextItem,
useUpdateInbound,
useUpdateInboundServiceTax,
useListInternalOrders,
};
Loading
Loading