Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into UIREC-312
Browse files Browse the repository at this point in the history
  • Loading branch information
usavkov-epam committed Jan 30, 2024
2 parents 6a24812 + 0f78880 commit 8245e81
Show file tree
Hide file tree
Showing 18 changed files with 269 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Delay claim action for piece record. Refs UIREC-303.
* Send claim action for piece record. Refs UIREC-304.
* Align the display of fields in full screen receiving view and piece edit form. Refs UIREC-296.
* Expect "Unreceivable" pieces on the full screen form. Refs UIREC-307.
* Display "Interval" column in the piece status logs. Refs UIREC-312.

## [4.0.0](https://github.com/folio-org/ui-receiving/tree/v4.0.0) (2023-10-12)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
"subPermissions": [
"acquisition.piece.events.get",
"orders.check-in.collection.post",
"orders.expect.collection.post",
"orders.receiving.collection.post",
"settings.receiving.enabled",
"ui-receiving.basic.view",
Expand Down
24 changes: 19 additions & 5 deletions src/TitleDetails/AddPieceModal/AddPieceModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,24 @@ import { PieceFields } from './PieceFields';
import { ReceivingStatusChangeLog } from './ReceivingStatusChangeLog';

const AddPieceModal = ({
canDeletePiece,
close,
createInventoryValues,
deletePiece,
canDeletePiece,
form,
initialValues,
getHoldingsItemsAndPieces,
handleSubmit,
hasValidationErrors,
pristine,
initialValues,
instanceId,
locationIds,
locations,
onCheckIn,
onUnreceive,
pieceFormatOptions,
values: formValues,
poLine,
getHoldingsItemsAndPieces,
pristine,
values: formValues,
}) => {
const {
batch,
Expand Down Expand Up @@ -179,6 +180,17 @@ const AddPieceModal = ({
onSave();
}, [change, onSave]);

const onUnreceivePiece = useCallback(async () => {
const currentPiece = {
...formValues,
checked: true,
};

await onUnreceive([currentPiece]);
close();
},
[close, onUnreceive, formValues]);

const onClaimDelay = useCallback(({ claimingDate }) => {
change('claimingInterval', getClaimingIntervalFromDate(claimingDate));
onStatusChange(PIECE_STATUS.claimDelayed);
Expand Down Expand Up @@ -219,6 +231,7 @@ const AddPieceModal = ({
onClaimSend={toggleClaimSendModal}
onDelete={toggleDeleteConfirmation}
onReceive={onReceive}
onUnreceivePiece={onUnreceivePiece}
onSave={onSave}
onStatusChange={onStatusChange}
status={receivingStatus}
Expand Down Expand Up @@ -369,6 +382,7 @@ AddPieceModal.propTypes = {
deletePiece: PropTypes.func.isRequired,
canDeletePiece: PropTypes.bool,
handleSubmit: PropTypes.func.isRequired,
onUnreceive: PropTypes.func.isRequired,
form: PropTypes.object,
values: PropTypes.object.isRequired,
instanceId: PropTypes.string,
Expand Down
32 changes: 32 additions & 0 deletions src/TitleDetails/AddPieceModal/AddPieceModal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ jest.mock('@folio/stripes-acq-components', () => {
});
jest.mock('../../common/components/LineLocationsView/LineLocationsView',
() => jest.fn().mockReturnValue('LineLocationsView'));
jest.mock('../../common/hooks', () => ({
...jest.requireActual('../../common/hooks'),
useUnreceive: jest.fn().mockReturnValue({ unreceive: jest.fn(() => Promise.resolve()) }),
}));
jest.mock('../hooks', () => ({
...jest.requireActual('../hooks'),
usePieceStatusChangeLog: jest.fn(),
Expand Down Expand Up @@ -262,6 +266,34 @@ describe('AddPieceModal', () => {
expect(defaultProps.onSubmit).toHaveBeenCalled();
});

it('should unreceive piece', async () => {
const onUnreceive = jest.fn();

renderAddPieceModal({
onUnreceive,
hasValidationErrors: false,
initialValues: {
'id': 'cd3fd1e7-c195-4d8e-af75-525e1039d643',
'format': 'Other',
'poLineId': 'a92ae36c-e093-4daf-b234-b4c6dc33a258',
'titleId': '03329fea-1b5d-43ab-b955-20bcd9ba530d',
'holdingId': '60c67dc5-b646-425e-bf08-a8bf2d0681fb',
'isCreateAnother': false,
'isCreateItem': false,
receivingStatus: PIECE_STATUS.received,
receivedDate: new Date().toISOString(),
},
});

await user.click(screen.getByTestId('dropdown-trigger-button'));
const unReceiveButton = await screen.findByTestId('unReceive-piece-button');

expect(unReceiveButton).toBeInTheDocument();
await user.click(unReceiveButton);

expect(onUnreceive).toHaveBeenCalled();
});

describe('Actions', () => {
const initialValues = {
format: PIECE_FORMAT.other,
Expand Down
3 changes: 3 additions & 0 deletions src/TitleDetails/AddPieceModal/AddPieceModalContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const AddPieceModalContainer = ({
close,
deletePiece,
canDeletePiece,
onUnreceive,
initialValues,
instanceId,
locations,
Expand Down Expand Up @@ -70,6 +71,7 @@ const AddPieceModalContainer = ({
onCheckIn={onQuickReceive}
onSubmit={onSavePiece}
pieceFormatOptions={pieceFormatOptions}
onUnreceive={onUnreceive}
poLine={poLine}
getHoldingsItemsAndPieces={getHoldingsItemsAndPieces}
/>
Expand All @@ -88,6 +90,7 @@ AddPieceModalContainer.propTypes = {
onSubmit: PropTypes.func.isRequired,
poLine: PropTypes.object.isRequired,
getHoldingsItemsAndPieces: PropTypes.func.isRequired,
onUnreceive: PropTypes.func.isRequired,
};

export default AddPieceModalContainer;
4 changes: 4 additions & 0 deletions src/TitleDetails/AddPieceModal/AddPieceModalContainer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ jest.mock('@folio/stripes-acq-components', () => ({
}));
jest.mock('../../common/components/LineLocationsView/LineLocationsView',
() => jest.fn().mockReturnValue('LineLocationsView'));
jest.mock('../../common/hooks', () => ({
...jest.requireActual('../../common/hooks'),
useUnreceive: jest.fn().mockReturnValue({ unreceive: jest.fn(() => Promise.resolve()) }),
}));
jest.mock('../hooks', () => ({
...jest.requireActual('../hooks'),
usePieceStatusChangeLog: jest.fn(() => ({ data: [] })),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const ModalActionButtons = ({
onReceive,
onSave,
onStatusChange,
onUnreceivePiece,
status,
}) => {
const actionMenu = getPieceActionMenu({
Expand All @@ -37,6 +38,7 @@ export const ModalActionButtons = ({
onDelete,
onReceive,
onStatusChange,
onUnreceivePiece,
status,
});
const saveButtonLabelId = 'ui-receiving.piece.actions.saveAndClose';
Expand Down Expand Up @@ -95,6 +97,7 @@ ModalActionButtons.propTypes = {
onReceive: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired,
onStatusChange: PropTypes.func.isRequired,
onUnreceivePiece: PropTypes.func.isRequired,
status: PropTypes.string,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const PIECE_ACTIONS = ({
onStatusChange,
onDelete,
onReceive,
onUnreceivePiece,
}) => ({
delayClaim: (
<Button
Expand Down Expand Up @@ -131,7 +132,7 @@ export const PIECE_ACTIONS = ({
disabled={actionsDisabled[PIECE_ACTION_NAMES.unReceive]}
buttonStyle="dropdownItem"
data-testid="unReceive-piece-button"
onClick={() => onStatusChange(PIECE_STATUS.expected)}
onClick={onUnreceivePiece}
>
<Icon icon="cancel">
<FormattedMessage id="ui-receiving.piece.action.button.unReceive" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ describe('getPieceActionMenus', () => {
});

describe('unReceive action', () => {
it('should `onStatusChange` be called with `Expected` status value', () => {
const onStatusChange = jest.fn();
const result = getPieceActionMenu({ status: received, onStatusChange });
it('should `onUnreceivePiece` be called with `Expected` status value', () => {
const onUnreceivePiece = jest.fn();
const result = getPieceActionMenu({ status: received, onUnreceivePiece });
const receiveButton = result.find(i => i.props['data-testid'] === 'unReceive-piece-button');

receiveButton.props.onClick();

expect(onStatusChange).toHaveBeenCalledWith(PIECE_STATUS.expected);
expect(onUnreceivePiece).toHaveBeenCalledWith();
});
});

Expand Down
3 changes: 3 additions & 0 deletions src/TitleDetails/TitleDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const TitleDetails = ({
piecesExistance,
poLine,
title,
onUnreceive,
vendorsMap,
getHoldingsItemsAndPieces,
getPieceValues,
Expand Down Expand Up @@ -601,6 +602,7 @@ const TitleDetails = ({
onCheckIn={onQuickReceive}
onSubmit={onSave}
poLine={poLine}
onUnreceive={onUnreceive}
getHoldingsItemsAndPieces={getHoldingsItemsAndPieces}
/>
)}
Expand Down Expand Up @@ -638,6 +640,7 @@ TitleDetails.propTypes = {
vendorsMap: PropTypes.object.isRequired,
getHoldingsItemsAndPieces: PropTypes.func.isRequired,
getPieceValues: PropTypes.func.isRequired,
onUnreceive: PropTypes.func.isRequired,
};

export default withRouter(TitleDetails);
24 changes: 21 additions & 3 deletions src/TitleDetails/TitleDetailsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ import {
PIECE_STATUS,
} from '@folio/stripes-acq-components';

import {
titleResource,
} from '../common/resources';
import { titleResource } from '../common/resources';
import {
usePieceMutator,
useQuickReceive,
useUnreceive,
} from '../common/hooks';
import {
handleCommonErrors,
Expand All @@ -48,6 +47,7 @@ const TitleDetailsContainer = ({ location, history, mutator, match }) => {

const { mutatePiece } = usePieceMutator();
const { quickReceive } = useQuickReceive();
const { unreceive } = useUnreceive();

const hasPieces = useCallback((lineId, status) => (
mutator.pieces.GET({
Expand Down Expand Up @@ -269,6 +269,23 @@ const TitleDetailsContainer = ({ location, history, mutator, match }) => {
).finally(() => fetchReceivingResources(poLine.id));
}, [fetchReceivingResources, poLine.id, showCallout, mutatePiece]);

const onUnreceive = useCallback((pieces) => {
return unreceive(pieces)
.then(async () => {
await fetchReceivingResources(poLine.id);
showCallout({
messageId: 'ui-receiving.title.actions.unreceive.success',
type: 'success',
});
})
.catch(() => {
showCallout({
type: 'error',
messageId: 'ui-receiving.title.actions.unreceive.error',
});
});
}, [fetchReceivingResources, poLine.id, showCallout, unreceive]);

if (isLoading || !(locations || vendorsMap)) {
return (
<LoadingPane
Expand All @@ -293,6 +310,7 @@ const TitleDetailsContainer = ({ location, history, mutator, match }) => {
vendorsMap={vendorsMap}
getHoldingsItemsAndPieces={getHoldingsItemsAndPieces}
getPieceValues={getPieceById(mutator.orderPieces)}
onUnreceive={onUnreceive}
/>
);
};
Expand Down
16 changes: 16 additions & 0 deletions src/TitleDetails/TitleDetailsContainer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { QueryClient, QueryClientProvider } from 'react-query';
import {
usePieceMutator,
useQuickReceive,
useUnreceive,
} from '../common/hooks';
import TitleDetails from './TitleDetails';
import TitleDetailsContainer from './TitleDetailsContainer';

jest.mock('../common/hooks', () => ({
usePieceMutator: jest.fn().mockReturnValue({}),
useQuickReceive: jest.fn().mockReturnValue({}),
useUnreceive: jest.fn().mockReturnValue({ unreceive: Promise.resolve() }),
}));
jest.mock('./TitleDetails', () => jest.fn().mockReturnValue('TitleDetails'));

Expand Down Expand Up @@ -127,6 +129,20 @@ describe('TitleDetailsContainer', () => {
expect(quickReceiveMock).toHaveBeenCalled();
});

it('should receive piece when onUnreceive is called', async () => {
const onUnreceive = jest.fn().mockReturnValue(Promise.resolve());

useUnreceive.mockClear().mockReturnValue({ unreceive: onUnreceive });

await act(async () => {
renderTitleDetailsContainer();
});

await TitleDetails.mock.calls[0][0].onUnreceive(pieces[0]);

expect(onUnreceive).toHaveBeenCalled();
});

it('should fetch items and pieces in holding', async () => {
await act(async () => {
renderTitleDetailsContainer();
Expand Down
1 change: 1 addition & 0 deletions src/common/constants/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const ACQ_AUDIT_API = 'audit-data/acquisition';
export const CHECKIN_API = 'orders/check-in';
export const EXPECT_API = 'orders/expect';
export const HOLDINGS_API = 'holdings-storage/holdings';
export const PIECE_AUDIT_API = `${ACQ_AUDIT_API}/piece`;
export const TITLES_API = 'orders/titles';
Expand Down
1 change: 1 addition & 0 deletions src/common/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './usePiecesExpect';
export * from './useQuickReceive';
export * from './useReceive';
export * from './useTitle';
export * from './useUnreceive';
34 changes: 32 additions & 2 deletions src/common/hooks/usePiecesExpect/usePiecesExpect.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
import { useMutation } from 'react-query';

import { useOkapiKy } from '@folio/stripes/core';

import { EXPECT_API } from '../../constants';

export const usePiecesExpect = () => {
const ky = useOkapiKy();

const { isLoading, mutateAsync } = useMutation({
mutationFn: (_pieces) => {
return Promise.reject(new Error('TODO: UIREC-307'));
mutationFn: (pieces) => {
const selectedPieces = pieces
.filter(({ checked }) => checked === true)
.map(piece => ({
id: piece.id,
comment: piece.comment,
}));

const json = {
toBeExpected: [{
poLineId: pieces[0]?.poLineId,
expected: selectedPieces.length,
expectPieces: selectedPieces,
}],
totalRecords: selectedPieces.length,
};

return ky.post(EXPECT_API, { json })
.json()
.then(({ receivingResults }) => {
if (receivingResults?.some(({ processedWithError }) => processedWithError > 0)) {
return Promise.reject(receivingResults);
}

return receivingResults;
});
},
});

Expand Down
Loading

0 comments on commit 8245e81

Please sign in to comment.