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

5242 add delete response requisitions #5269

Merged
merged 22 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3dcc56a
Add service layer with validation checks for deleting response requis…
fergie-nz Oct 29, 2024
c6706f3
Add delete service layer tests
fergie-nz Oct 29, 2024
280bdb5
Add graphql layer and tests for delete response requisition
fergie-nz Oct 30, 2024
1cdc67c
Add batch delete response requisition
fergie-nz Oct 30, 2024
0084314
Add batch mutation tests
fergie-nz Oct 30, 2024
c0f3ce3
Add generated graphql schema
fergie-nz Oct 30, 2024
c52453b
Add front end delete response requisitions
fergie-nz Oct 30, 2024
8a539e8
Merge branch 'develop' into 5242-add-delete-response-requisitions
fergie-nz Oct 30, 2024
796127d
Merge branch 'develop' into 5242-add-delete-response-requisitions
fergie-nz Nov 4, 2024
16c81ef
Update operations.generated.ts
fergie-nz Nov 4, 2024
06c5f6a
Update client/packages/requisitions/src/ResponseRequisition/ListView/…
fergie-nz Nov 4, 2024
c06bd90
Merge branch '5242-add-delete-response-requisitions' of https://githu…
fergie-nz Nov 4, 2024
c66114f
Add error snacks
fergie-nz Nov 4, 2024
2b31081
Remove comments
fergie-nz Nov 4, 2024
3283a7a
Structure line delete error
fergie-nz Nov 4, 2024
2107d5d
Update client/packages/requisitions/src/ResponseRequisition/ListView/…
fergie-nz Nov 6, 2024
86a33a5
Add only one toast with structured error
fergie-nz Nov 6, 2024
43dfb08
remove console logs
fergie-nz Nov 6, 2024
55a0104
Fix missing propagation of error
fergie-nz Nov 7, 2024
a89a24d
Merge branch 'develop' into 5242-add-delete-response-requisitions
fergie-nz Nov 7, 2024
9f3c0b9
Fix merge conflicts
fergie-nz Nov 7, 2024
db379c0
Transfer -> Transferred
roxy-dao Nov 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion client/packages/common/src/types/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -763,11 +763,13 @@ export type BatchRequestRequisitionResponse = {
export type BatchResponseRequisitionInput = {
continueOnError?: InputMaybe<Scalars['Boolean']['input']>;
deleteResponseRequisitionLines?: InputMaybe<Array<DeleteResponseRequisitionLineInput>>;
deleteResponseRequisitions?: InputMaybe<Array<DeleteResponseRequisitionInput>>;
};

export type BatchResponseRequisitionResponse = {
__typename: 'BatchResponseRequisitionResponse';
deleteResponseRequisitionLines?: Maybe<Array<DeleteResponseRequisitionLineResponseWithId>>;
deleteResponseRequisitions?: Maybe<Array<DeleteResponseRequisitionResponseWithId>>;
};

export type BatchStocktakeInput = {
Expand Down Expand Up @@ -1521,6 +1523,19 @@ export type DeleteResponse = {
id: Scalars['String']['output'];
};

export type DeleteResponseRequisitionError = {
__typename: 'DeleteResponseRequisitionError';
error: DeleteResponseRequisitionErrorInterface;
};

export type DeleteResponseRequisitionErrorInterface = {
description: Scalars['String']['output'];
};

export type DeleteResponseRequisitionInput = {
id: Scalars['String']['input'];
};

export type DeleteResponseRequisitionLineError = {
__typename: 'DeleteResponseRequisitionLineError';
error: DeleteResponseRequisitionLineErrorInterface;
Expand All @@ -1542,6 +1557,14 @@ export type DeleteResponseRequisitionLineResponseWithId = {
response: DeleteResponseRequisitionLineResponse;
};

export type DeleteResponseRequisitionResponse = DeleteResponse | DeleteResponseRequisitionError;

export type DeleteResponseRequisitionResponseWithId = {
__typename: 'DeleteResponseRequisitionResponseWithId';
id: Scalars['String']['output'];
response: DeleteResponseRequisitionResponse;
};

export type DeleteStocktakeError = {
__typename: 'DeleteStocktakeError';
error: DeleteStocktakeErrorInterface;
Expand Down Expand Up @@ -2142,6 +2165,11 @@ export type FinaliseRnRFormInput = {

export type FinaliseRnRFormResponse = RnRFormNode;

export type FinalisedRequisition = DeleteResponseRequisitionErrorInterface & {
__typename: 'FinalisedRequisition';
description: Scalars['String']['output'];
};

export enum ForeignKey {
InvoiceId = 'invoiceId',
ItemId = 'itemId',
Expand Down Expand Up @@ -3877,6 +3905,7 @@ export type Mutations = {
deletePrescriptionLine: DeletePrescriptionLineResponse;
deleteRequestRequisition: DeleteRequestRequisitionResponse;
deleteRequestRequisitionLine: DeleteRequestRequisitionLineResponse;
deleteResponseRequisition: DeleteResponseRequisitionResponse;
deleteResponseRequisitionLine: DeleteResponseRequisitionLineResponse;
deleteStocktake: DeleteStocktakeResponse;
deleteStocktakeLine: DeleteStocktakeLineResponse;
Expand Down Expand Up @@ -4145,6 +4174,12 @@ export type MutationsDeleteRequestRequisitionLineArgs = {
};


export type MutationsDeleteResponseRequisitionArgs = {
input: DeleteResponseRequisitionInput;
storeId: Scalars['String']['input'];
};


export type MutationsDeleteResponseRequisitionLineArgs = {
input: DeleteResponseRequisitionLineInput;
storeId: Scalars['String']['input'];
Expand Down Expand Up @@ -6205,7 +6240,7 @@ export type RecordBelongsToAnotherStore = DeleteAssetErrorInterface & DeleteAsse
description: Scalars['String']['output'];
};

export type RecordNotFound = AddFromMasterListErrorInterface & AddToInboundShipmentFromMasterListErrorInterface & AddToOutboundShipmentFromMasterListErrorInterface & AllocateOutboundShipmentUnallocatedLineErrorInterface & CreateRequisitionShipmentErrorInterface & DeleteAssetCatalogueItemErrorInterface & DeleteAssetErrorInterface & DeleteAssetLogReasonErrorInterface & DeleteCustomerReturnErrorInterface & DeleteErrorInterface & DeleteInboundShipmentErrorInterface & DeleteInboundShipmentLineErrorInterface & DeleteInboundShipmentServiceLineErrorInterface & DeleteLocationErrorInterface & DeleteOutboundShipmentLineErrorInterface & DeleteOutboundShipmentServiceLineErrorInterface & DeleteOutboundShipmentUnallocatedLineErrorInterface & DeletePrescriptionErrorInterface & DeletePrescriptionLineErrorInterface & DeleteRequestRequisitionErrorInterface & DeleteRequestRequisitionLineErrorInterface & DeleteResponseRequisitionLineErrorInterface & DeleteSupplierReturnErrorInterface & DeleteVaccineCourseErrorInterface & NodeErrorInterface & RequisitionLineChartErrorInterface & RequisitionLineStatsErrorInterface & SupplyRequestedQuantityErrorInterface & UpdateAssetErrorInterface & UpdateErrorInterface & UpdateInboundShipmentErrorInterface & UpdateInboundShipmentLineErrorInterface & UpdateInboundShipmentServiceLineErrorInterface & UpdateLocationErrorInterface & UpdateNameErrorInterface & UpdateNamePropertiesErrorInterface & UpdateOutboundShipmentLineErrorInterface & UpdateOutboundShipmentServiceLineErrorInterface & UpdateOutboundShipmentUnallocatedLineErrorInterface & UpdatePrescriptionErrorInterface & UpdatePrescriptionLineErrorInterface & UpdateRequestRequisitionErrorInterface & UpdateRequestRequisitionLineErrorInterface & UpdateResponseRequisitionErrorInterface & UpdateResponseRequisitionLineErrorInterface & UpdateReturnOtherPartyErrorInterface & UpdateSensorErrorInterface & UpdateStockLineErrorInterface & UseSuggestedQuantityErrorInterface & {
export type RecordNotFound = AddFromMasterListErrorInterface & AddToInboundShipmentFromMasterListErrorInterface & AddToOutboundShipmentFromMasterListErrorInterface & AllocateOutboundShipmentUnallocatedLineErrorInterface & CreateRequisitionShipmentErrorInterface & DeleteAssetCatalogueItemErrorInterface & DeleteAssetErrorInterface & DeleteAssetLogReasonErrorInterface & DeleteCustomerReturnErrorInterface & DeleteErrorInterface & DeleteInboundShipmentErrorInterface & DeleteInboundShipmentLineErrorInterface & DeleteInboundShipmentServiceLineErrorInterface & DeleteLocationErrorInterface & DeleteOutboundShipmentLineErrorInterface & DeleteOutboundShipmentServiceLineErrorInterface & DeleteOutboundShipmentUnallocatedLineErrorInterface & DeletePrescriptionErrorInterface & DeletePrescriptionLineErrorInterface & DeleteRequestRequisitionErrorInterface & DeleteRequestRequisitionLineErrorInterface & DeleteResponseRequisitionErrorInterface & DeleteResponseRequisitionLineErrorInterface & DeleteSupplierReturnErrorInterface & DeleteVaccineCourseErrorInterface & NodeErrorInterface & RequisitionLineChartErrorInterface & RequisitionLineStatsErrorInterface & SupplyRequestedQuantityErrorInterface & UpdateAssetErrorInterface & UpdateErrorInterface & UpdateInboundShipmentErrorInterface & UpdateInboundShipmentLineErrorInterface & UpdateInboundShipmentServiceLineErrorInterface & UpdateLocationErrorInterface & UpdateNameErrorInterface & UpdateNamePropertiesErrorInterface & UpdateOutboundShipmentLineErrorInterface & UpdateOutboundShipmentServiceLineErrorInterface & UpdateOutboundShipmentUnallocatedLineErrorInterface & UpdatePrescriptionErrorInterface & UpdatePrescriptionLineErrorInterface & UpdateRequestRequisitionErrorInterface & UpdateRequestRequisitionLineErrorInterface & UpdateResponseRequisitionErrorInterface & UpdateResponseRequisitionLineErrorInterface & UpdateReturnOtherPartyErrorInterface & UpdateSensorErrorInterface & UpdateStockLineErrorInterface & UseSuggestedQuantityErrorInterface & {
__typename: 'RecordNotFound';
description: Scalars['String']['output'];
};
Expand Down Expand Up @@ -6564,6 +6599,11 @@ export type RequisitionSortInput = {
key: RequisitionSortFieldInput;
};

export type RequisitionWithShipment = DeleteResponseRequisitionErrorInterface & {
__typename: 'RequisitionWithShipment';
description: Scalars['String']['output'];
};

export type RequisitionsResponse = RequisitionConnector;

export type ResponseRequisitionCounts = {
Expand Down Expand Up @@ -7413,6 +7453,11 @@ export type TokenExpired = RefreshTokenErrorInterface & {
description: Scalars['String']['output'];
};

export type TransferRequisition = DeleteResponseRequisitionErrorInterface & {
__typename: 'TransferRequisition';
description: Scalars['String']['output'];
};

export type UnallocatedLineForItemAlreadyExists = InsertOutboundShipmentUnallocatedLineErrorInterface & {
__typename: 'UnallocatedLineForItemAlreadyExists';
description: Scalars['String']['output'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ export const ResponseRequisitionListView: FC = () => {
}
columnDefinitions.push(['comment', { minWidth: 400, Cell: TooltipTextCell }]);
fergie-nz marked this conversation as resolved.
Show resolved Hide resolved

columnDefinitions.push('selection');

const columns = useColumns<ResponseRowFragment>(
columnDefinitions,
{ onChangeSortBy: updateSortQuery, sortBy },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import {
Box,
useTranslation,
RequisitionNodeStatus,
DeleteIcon,
DropdownMenu,
DropdownMenuItem,
} from '@openmsupply-client/common';
import { useResponse } from '../api';

export const Toolbar: FC<{
filter: FilterController;
}> = () => {
const onDelete = useResponse.document.deleteSelected();
const t = useTranslation();

return (
Expand Down Expand Up @@ -51,6 +56,11 @@ export const Toolbar: FC<{
]}
/>
</Box>
<DropdownMenu label={t('label.actions')}>
<DropdownMenuItem IconComponent={DeleteIcon} onClick={onDelete}>
{t('button.delete-lines')}
</DropdownMenuItem>
</DropdownMenu>
</AppBarContentPortal>
);
};
20 changes: 20 additions & 0 deletions client/packages/requisitions/src/ResponseRequisition/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ const responseParser = {
status: responseParser.toStatus(requisition),
};
},
toDelete: (line: ResponseFragment) => {
return { id: line.id };
},
toDeleteLine: (line: ResponseLineFragment) => ({ id: line.id }),
toUpdateLine: (
patch: DraftResponseLine
Expand Down Expand Up @@ -212,6 +215,23 @@ export const getResponseQueries = (sdk: Sdk, storeId: string) => ({

throw new Error('Unable to update requisition');
},
deleteResponses: async (requisitions: ResponseFragment[]) => {
const deleteResponseRequisitions = requisitions.map(
responseParser.toDelete
);
const result = await sdk.deleteRequest({
storeId,
input: { deleteResponseRequisitions },
});

const { batchResponseRequisition } = result || {};

if (batchResponseRequisition?.deleteResponseRequisitions) {
return batchResponseRequisition.deleteResponseRequisitions.length;
fergie-nz marked this conversation as resolved.
Show resolved Hide resolved
}

throw new Error('Could not delete requisitions');
},
deleteLines: async (responseLines: ResponseLineFragment[]) => {
const ids = responseLines.map(responseParser.toDeleteLine);
const result = await sdk.deleteResponseLines({ ids, storeId });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import { useResponseFields } from './useResponseFields';
import { useResponses } from './useResponses';
import { useResponsesAll } from './useResponsesAll';
import { useUpdateResponse } from './useUpdateResponse';
import { useDeleteResponses } from './useDeleteResponses';
import { useDeleteSelectedResponseRequisitions } from './useDeleteSelectedResponseRequisitions';

export const Document = {
useResponse,
useResponseFields,
useResponses,
useResponsesAll,
useUpdateResponse,
useDeleteResponses,
useDeleteSelectedResponseRequisitions,
useInsertResponse,
useInsertProgramResponse,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useQueryClient, useMutation } from '@openmsupply-client/common';
import { useResponseApi } from '../utils/useResponseApi';

export const useDeleteResponses = () => {
const queryClient = useQueryClient();
const api = useResponseApi();
return useMutation(api.deleteResponses, {
onSuccess: () => {
queryClient.invalidateQueries(api.keys.base());
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
useTranslation,
useTableStore,
RequisitionNodeStatus,
useDeleteConfirmation,
useUrlQueryParams,
} from '@openmsupply-client/common';
import { ResponseFragment } from '../../operations.generated';
import { useDeleteResponses } from './useDeleteResponses';
import { useResponses } from './useResponses';

export const useDeleteSelectedResponseRequisitions = () => {
const { queryParams } = useUrlQueryParams({
initialSort: { key: 'createdDatetime', dir: 'desc' },
});
const { data: rows } = useResponses(queryParams);
const { mutateAsync } = useDeleteResponses();
const t = useTranslation();
const { selectedRows } = useTableStore(state => ({
selectedRows: Object.keys(state.rowState)
.filter(id => state.rowState[id]?.isSelected)
.map(selectedId => rows?.nodes?.find(({ id }) => selectedId === id))
.filter(Boolean) as ResponseFragment[],
}));
const deleteAction = async () => {
await mutateAsync(selectedRows).catch(err => {
throw err;
});
};

const confirmAndDelete = useDeleteConfirmation({
selectedRows,
deleteAction,
canDelete: selectedRows.every(
({ status }) => status !== RequisitionNodeStatus.Finalised
),
messages: {
confirmMessage: t('messages.confirm-delete-requisitions', {
count: selectedRows.length,
}),
deleteSuccess: t('messages.deleted-orders', {
count: selectedRows.length,
}),
cantDelete: t('messages.cant-delete-requisitions'),
},
});
return confirmAndDelete;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export const useResponse = {
insert: Document.useInsertResponse,
insertProgram: Document.useInsertProgramResponse,
update: Document.useUpdateResponse,

delete: Document.useDeleteResponses,
deleteSelected: Document.useDeleteSelectedResponseRequisitions,
fields: Document.useResponseFields,
},
line: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export type UpdateResponseMutationVariables = Types.Exact<{

export type UpdateResponseMutation = { __typename: 'Mutations', updateResponseRequisition: { __typename: 'RequisitionNode', id: string } | { __typename: 'UpdateResponseRequisitionError' } };

export type DeleteRequestMutationVariables = Types.Exact<{
storeId: Types.Scalars['String']['input'];
input: Types.BatchResponseRequisitionInput;
}>;


export type DeleteRequestMutation = { __typename: 'Mutations', batchResponseRequisition: { __typename: 'BatchResponseRequisitionResponse', deleteResponseRequisitions?: Array<{ __typename: 'DeleteResponseRequisitionResponseWithId', id: string, response: { __typename: 'DeleteResponse', id: string } | { __typename: 'DeleteResponseRequisitionError', error: { __typename: 'FinalisedRequisition', description: string } | { __typename: 'RecordNotFound', description: string } | { __typename: 'RequisitionWithShipment', description: string } | { __typename: 'TransferRequisition', description: string } } }> | null } };

export type ResponseLineFragment = { __typename: 'RequisitionLineNode', id: string, itemId: string, requestedQuantity: number, supplyQuantity: number, remainingQuantityToSupply: number, alreadyIssued: number, comment?: string | null, approvedQuantity: number, approvalComment?: string | null, itemStats: { __typename: 'ItemStatsNode', availableStockOnHand: number, availableMonthsOfStockOnHand?: number | null, averageMonthlyConsumption: number }, item: { __typename: 'ItemNode', id: string, name: string, code: string, unitName?: string | null }, linkedRequisitionLine?: { __typename: 'RequisitionLineNode', itemStats: { __typename: 'ItemStatsNode', availableStockOnHand: number } } | null };

export type ResponseFragment = { __typename: 'RequisitionNode', id: string, type: Types.RequisitionNodeType, status: Types.RequisitionNodeStatus, createdDatetime: string, sentDatetime?: string | null, finalisedDatetime?: string | null, requisitionNumber: number, colour?: string | null, theirReference?: string | null, comment?: string | null, otherPartyName: string, otherPartyId: string, maxMonthsOfStock: number, minMonthsOfStock: number, approvalStatus: Types.RequisitionNodeApprovalStatus, programName?: string | null, orderType?: string | null, user?: { __typename: 'UserNode', username: string, email?: string | null } | null, shipments: { __typename: 'InvoiceConnector', totalCount: number, nodes: Array<{ __typename: 'InvoiceNode', id: string, invoiceNumber: number, createdDatetime: string, user?: { __typename: 'UserNode', username: string } | null }> }, linesRemainingToSupply: { __typename: 'RequisitionLineConnector', totalCount: number }, lines: { __typename: 'RequisitionLineConnector', totalCount: number, nodes: Array<{ __typename: 'RequisitionLineNode', id: string, itemId: string, requestedQuantity: number, supplyQuantity: number, remainingQuantityToSupply: number, alreadyIssued: number, comment?: string | null, approvedQuantity: number, approvalComment?: string | null, itemStats: { __typename: 'ItemStatsNode', availableStockOnHand: number, availableMonthsOfStockOnHand?: number | null, averageMonthlyConsumption: number }, item: { __typename: 'ItemNode', id: string, name: string, code: string, unitName?: string | null }, linkedRequisitionLine?: { __typename: 'RequisitionLineNode', itemStats: { __typename: 'ItemStatsNode', availableStockOnHand: number } } | null }> }, otherParty: { __typename: 'NameNode', id: string, code: string, isCustomer: boolean, isSupplier: boolean, isOnHold: boolean, name: string, store?: { __typename: 'StoreNode', id: string, code: string } | null }, period?: { __typename: 'PeriodNode', name: string, startDate: string, endDate: string } | null, linkedRequisition?: { __typename: 'RequisitionNode', id: string } | null };
Expand Down Expand Up @@ -263,6 +271,42 @@ export const UpdateResponseDocument = gql`
}
}
`;
export const DeleteRequestDocument = gql`
mutation deleteRequest($storeId: String!, $input: BatchResponseRequisitionInput!) {
batchResponseRequisition(storeId: $storeId, input: $input) {
deleteResponseRequisitions {
id
response {
... on DeleteResponseRequisitionError {
__typename
error {
description
... on RecordNotFound {
__typename
description
}
... on FinalisedRequisition {
__typename
description
}
... on TransferRequisition {
__typename
description
}
... on RequisitionWithShipment {
__typename
description
}
}
}
... on DeleteResponse {
id
}
}
}
}
}
`;
export const ResponseByNumberDocument = gql`
query responseByNumber($storeId: String!, $requisitionNumber: Int!) {
requisitionByNumber(
Expand Down Expand Up @@ -499,6 +543,9 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper =
updateResponse(variables: UpdateResponseMutationVariables, requestHeaders?: GraphQLClientRequestHeaders): Promise<UpdateResponseMutation> {
return withWrapper((wrappedRequestHeaders) => client.request<UpdateResponseMutation>(UpdateResponseDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'updateResponse', 'mutation', variables);
},
deleteRequest(variables: DeleteRequestMutationVariables, requestHeaders?: GraphQLClientRequestHeaders): Promise<DeleteRequestMutation> {
return withWrapper((wrappedRequestHeaders) => client.request<DeleteRequestMutation>(DeleteRequestDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'deleteRequest', 'mutation', variables);
},
responseByNumber(variables: ResponseByNumberQueryVariables, requestHeaders?: GraphQLClientRequestHeaders): Promise<ResponseByNumberQuery> {
return withWrapper((wrappedRequestHeaders) => client.request<ResponseByNumberQuery>(ResponseByNumberDocument, variables, {...requestHeaders, ...wrappedRequestHeaders}), 'responseByNumber', 'query', variables);
},
Expand Down
Loading
Loading