Skip to content

Commit

Permalink
Merge branch 'master' of github.com:folio-org/ui-receiving into feat/…
Browse files Browse the repository at this point in the history
…numberGenerator
  • Loading branch information
EthanFreestone committed Oct 23, 2023
2 parents 29b1296 + 77a5d65 commit 81f66d6
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 49 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# Change history for ui-receiving

## 4.0.0 (IN PROGRESS)
## 4.1.0 (IN PROGRESS)

## [4.0.0](https://github.com/folio-org/ui-receiving/tree/v4.0.0) (2023-10-12)
[Full Changelog](https://github.com/folio-org/ui-receiving/compare/v3.0.0...v4.0.0)

* Unpin `@rehooks/local-storage` now that it's no longer broken. Refs UIREC-259.
* Also support `circulation` `14.0`. Refs UIREC-270.
* Receiving an item with an open request, the warning dialogue shows "undefined" instead of title. Refs UIREC-278.
* Upgrade `Node.js` to `18` version in GitHub Actions. Refs UIREC-281.
* *BREAKING* Upgrade React to v18. Refs UIREC-280.
* *BREAKING* bump `react-intl` to `v6.4.4`. Refs UIREC-286.
* Bump optional plugins to their `@folio/stripes` `v9` compatible versions. Refs UIREC-290.
* Check if a holding exists during the abandonment check. Refs UIREC-294.

## [3.0.0](https://github.com/folio-org/ui-receiving/tree/v3.0.0) (2023-02-22)
[Full Changelog](https://github.com/folio-org/ui-receiving/compare/v2.3.1...v3.0.0)
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@
"react-router-prop-types": "^1.0.4"
},
"optionalDependencies": {
"@folio/plugin-find-instance": "^6.3.0",
"@folio/plugin-find-organization": "^4.0.0",
"@folio/plugin-find-po-line": "^4.0.0"
"@folio/plugin-find-instance": "^7.0.0",
"@folio/plugin-find-organization": "^5.0.0",
"@folio/plugin-find-po-line": "^5.0.0"
},
"peerDependencies": {
"@folio/stripes": "^9.0.0",
Expand Down
50 changes: 31 additions & 19 deletions src/TitleDetails/AddPieceModal/AddPieceModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
TextField,
checkScope,
} from '@folio/stripes/components';
import { useOkapiKy } from '@folio/stripes/core';
import stripesFinalForm from '@folio/stripes/final-form';
import {
FieldDatepickerFinal,
Expand All @@ -33,6 +34,7 @@ import {
CreateItemField,
LineLocationsView,
} from '../../common/components';
import { HOLDINGS_API } from '../../common/constants';
import { DeletePieceModal } from '../DeletePieceModal';
import { DeleteHoldingsModal } from '../DeleteHoldingsModal';

Expand Down Expand Up @@ -62,6 +64,7 @@ const AddPieceModal = ({
const [isDeleteConfirmation, toggleDeleteConfirmation] = useModalToggle();
const [isDeleteHoldingsConfirmation, toggleDeleteHoldingsConfirmation] = useModalToggle();

const ky = useOkapiKy();
const intl = useIntl();
const modalLabel = intl.formatMessage({ id: labelId });

Expand All @@ -88,33 +91,42 @@ const AddPieceModal = ({
if (!checked) change('discoverySuppress', checked);
};

const onSave = useCallback((e) => {
const checkHoldingAbandonment = useCallback((holdingId) => {
return ky.get(`${HOLDINGS_API}/${holdingId}`)
.json()
.then((holding) => getHoldingsItemsAndPieces(holding.id, { limit: 1 }))
.then(({ pieces, items }) => {
const willAbandoned = Boolean(
pieces && items
&& (pieces.totalRecords === 1)
&& ((items.totalRecords === 1 && itemId) || items.totalRecords === 0),
);

return { willAbandoned };
})
.catch(() => ({ willAbandoned: false }));
}, [getHoldingsItemsAndPieces, itemId, ky]);

const onSave = useCallback(async (e) => {
const holdingId = getState().values?.holdingId;

if ((id && initialHoldingId) && (holdingId !== initialHoldingId)) {
return getHoldingsItemsAndPieces(initialHoldingId, { limit: 1 })
.then(({ pieces, items }) => {
const canDeleteHolding = Boolean(
pieces && items
&& (pieces.totalRecords === 1)
&& ((items.totalRecords === 1 && itemId) || items.totalRecords === 0),
);

if (canDeleteHolding) {
return toggleDeleteHoldingsConfirmation();
}

return handleSubmit(e);
});
const shouldCheckHoldingAbandonment = (id && initialHoldingId) && (holdingId !== initialHoldingId);

if (shouldCheckHoldingAbandonment) {
return checkHoldingAbandonment(initialHoldingId)
.then(({ willAbandoned }) => (
willAbandoned
? toggleDeleteHoldingsConfirmation()
: handleSubmit(e)
));
}

return handleSubmit(e);
}, []);
}, [checkHoldingAbandonment, getState, handleSubmit, id, initialHoldingId, toggleDeleteHoldingsConfirmation]);

const onDeleteHoldings = useCallback(() => {
change('deleteHolding', true);
handleSubmit();
}, []);
}, [change, handleSubmit]);

const start = (
<Button
Expand Down
96 changes: 75 additions & 21 deletions src/TitleDetails/AddPieceModal/AddPieceModal.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@folio/jest-config-stripes/testing-library/react';
import user from '@folio/jest-config-stripes/testing-library/user-event';

import user from '@folio/jest-config-stripes/testing-library/user-event';
import { act, render, screen } from '@folio/jest-config-stripes/testing-library/react';
import { useOkapiKy } from '@folio/stripes/core';
import {
FieldInventory,
INVENTORY_RECORDS_TYPE,
PIECE_FORMAT,
} from '@folio/stripes-acq-components';

import AddPieceModal from './AddPieceModal';
Expand Down Expand Up @@ -41,9 +43,17 @@ const defaultProps = {
values: {},
poLine: { locations: [{ locationId: '001' }] },
setSearchParams: jest.fn(),
getHoldingsItemsAndPieces: jest.fn().mockReturnValue({
then: () => ({}),
}),
getHoldingsItemsAndPieces: jest.fn(),
};

const holding = {
id: 'holdingId',
};

const kyMock = {
get: jest.fn(() => ({
json: () => Promise.resolve(holding),
})),
};

const renderAddPieceModal = (props = defaultProps) => (render(
Expand All @@ -53,11 +63,21 @@ const renderAddPieceModal = (props = defaultProps) => (render(
{ wrapper: MemoryRouter },
));

const findButton = (name) => screen.findByRole('button', { name });

const createNewHoldingForThePiece = (newHoldingId = 'newHoldingUUID') => {
return act(async () => FieldInventory.mock.calls[0][0].onChange(null, 'locationId', 'holdingId', newHoldingId));
};

describe('AddPieceModal', () => {
beforeEach(() => {
defaultProps.close.mockClear();
defaultProps.onCheckIn.mockClear();
defaultProps.onSubmit.mockClear();
defaultProps.getHoldingsItemsAndPieces.mockClear();
FieldInventory.mockClear();
kyMock.get.mockClear();
useOkapiKy.mockClear().mockReturnValue(kyMock);
});

it('should display Add piece modal', () => {
Expand All @@ -70,15 +90,15 @@ describe('AddPieceModal', () => {
it('should close Add piece modal', async () => {
renderAddPieceModal();

await user.click(screen.getByText('ui-receiving.piece.actions.cancel'));
await user.click(await findButton('ui-receiving.piece.actions.cancel'));

expect(defaultProps.close).toHaveBeenCalled();
});
});

describe('Check display on holding', () => {
it.skip('should enable discovery suppress when clicked', async () => {
const format = 'Electronic';
const format = PIECE_FORMAT.electronic;

renderAddPieceModal({
...defaultProps,
Expand Down Expand Up @@ -107,24 +127,63 @@ describe('AddPieceModal', () => {

describe('Save piece', () => {
it('should call \'onSubmit\' when save button was clicked', async () => {
const format = 'Electronic';
const format = PIECE_FORMAT.electronic;

renderAddPieceModal({
...defaultProps,
createInventoryValues: { [format]: INVENTORY_RECORDS_TYPE.instanceAndHolding },
initialValues: {
format,
id: 'pieceId',
holdingId: 'holdingId',
holdingId: holding.id,
},
});

const saveAndCloseBtn = await screen.findByRole('button', {
name: 'ui-receiving.piece.actions.saveAndClose',
await user.click(await findButton('ui-receiving.piece.actions.saveAndClose'));
expect(defaultProps.onSubmit).toHaveBeenCalled();
});

describe('Abandoned holdings', () => {
it('should display the modal for deleting abandoned holding when the original holding is empty after changing to a new one', async () => {
defaultProps.getHoldingsItemsAndPieces.mockResolvedValue({
pieces: { totalRecords: 1 },
items: { totalRecords: 0 },
});

renderAddPieceModal({
...defaultProps,
initialValues: {
id: 'pieceId',
format: PIECE_FORMAT.physical,
holdingId: holding.id,
},
});

await createNewHoldingForThePiece();
await user.click(await findButton('ui-receiving.piece.actions.saveAndClose'));

expect(await screen.findByText('ui-receiving.piece.actions.edit.deleteHoldings.message')).toBeInTheDocument();
expect(defaultProps.onSubmit).not.toHaveBeenCalled();
});

await user.click(saveAndCloseBtn);
expect(defaultProps.onSubmit).toHaveBeenCalled();
it('should NOT display the modal for deleting abandoned holding if it has already been deleted', async () => {
kyMock.get.mockReturnValue(({ json: () => Promise.reject(new Error('404')) }));

renderAddPieceModal({
...defaultProps,
initialValues: {
id: 'pieceId',
format: PIECE_FORMAT.physical,
holdingId: holding.id,
},
});

await createNewHoldingForThePiece();
await user.click(await findButton('ui-receiving.piece.actions.saveAndClose'));

expect(screen.queryByText('ui-receiving.piece.actions.edit.deleteHoldings.message')).not.toBeInTheDocument();
expect(defaultProps.onSubmit).toHaveBeenCalled();
});
});
});

Expand All @@ -135,13 +194,8 @@ describe('AddPieceModal', () => {
initialValues: { isCreateAnother: true },
});

const saveBtn = await screen.findByRole('button', {
name: 'stripes-core.button.save',
});

const quickReceiveBtn = await screen.findByRole('button', {
name: 'ui-receiving.piece.actions.quickReceive',
});
const saveBtn = await findButton('ui-receiving.piece.actions.quickReceive');
const quickReceiveBtn = await findButton('ui-receiving.piece.actions.quickReceive');

expect(saveBtn).toBeInTheDocument();
expect(quickReceiveBtn.classList.contains('primary')).toBeTruthy();
Expand Down
2 changes: 1 addition & 1 deletion translations/ui-receiving/es_ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
"piece.displayOnHolding": "Display on holding",
"piece.discoverySuppress": "Suppress from discovery",
"piece.lineLocations": "Order line locations",
"piece.delete.deleteHoldingsAndItem.message": "Esta pieza está conectada a los registros del inventario. No hay ninguna otra pieza conectada al registro de fondos relacionado. ¿Después de eliminar esta pieza quieres que FOLIO elimine los fondos?",
"piece.delete.deleteHoldingsAndItem.message": "Esta pieza está conectada a los registros del inventario. No hay ninguna otra pieza conectada al existencias relacionado. ¿Después de eliminar esta pieza quieres que FOLIO elimine los fondos?",
"shortcut.receive": "Receive pieces/Quick receive",
"piece.actions.edit.keepHoldings": "Mantener las Holdings",
"piece.actions.edit.deleteHoldings.message": "This piece is connected to records in inventory. After this edit there will be no other pieces OR items connected to the related Holdings record. After making this change would you like FOLIO to delete the Holdings?",
Expand Down
6 changes: 3 additions & 3 deletions translations/ui-receiving/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,19 @@
"filter.nonSupplements": "Non supplements",
"piece.itemStatus.info": "When receiving pieces that have connected items. A connected item with the status of \"Order closed\" or \"On order\" will be updated to a status of \"In process\". Items in other statuses will not have their status changed.",
"filter.rush": "Rush",
"exportSettings.error": "Failed to load data for export results (CSV)",
"exportSettings.error": "Nie udało się załadować danych dla eksportu wyników (CSV)",
"exportSettings.export": "Export",
"exportSettings.export.all": "All",
"exportSettings.label": "Export settings",
"exportSettings.message": "This export could take a few minutes. If you reload or close the page the export will not be completed. Once the file is ready it could take another minute for your browser to finish downloading the file. You can continue to work with titles and pieces in a different browser tab if needed.",
"exportSettings.message": "Ten eksport może potrwać kilka minut. Jeśli przeładujesz lub zamkniesz stronę, eksport nie zostanie ukończony. Gdy plik będzie gotowy, może minąć kolejna minuta, zanim przeglądarka zakończy jego pobieranie. W razie potrzeby możesz kontynuować pracę z zamówieniami i pozycjami zamówień w innej zakładce przeglądarki.",
"exportSettings.piece.all": "Export all piece fields",
"exportSettings.piece.fieldsLabel": "Piece fields",
"exportSettings.piece.selected": "Export selected piece fields",
"exportSettings.title.all": "Export all title fields",
"exportSettings.title.fieldsLabel": "Title fields",
"exportSettings.title.selected": "Export selected title fields",
"exportSettings.success": "Export has been started successfully",
"title.actions.exportCSV": "Export results (CSV)",
"title.actions.exportCSV": "Eksport wyniki (CSV)",
"permission.view": "Receiving: View",
"permission.edit": "Receiving: View, edit",
"permission.create": "Receiving: View, edit, create",
Expand Down
2 changes: 1 addition & 1 deletion translations/ui-receiving/pt_BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"title.accessProvider": "Provedor de acesso",
"title.materialSupplier": "Fornecedor de material",
"title.orderType.One-Time": "Uma vez",
"title.orderType.Ongoing": "Em curso",
"title.orderType.Ongoing": "Em andamento",
"title.orderType": "Tipo de pedido",
"title.vendor": "Fornecedor",
"piece.actions.selectAll": "Selecionar todas as peças",
Expand Down

0 comments on commit 81f66d6

Please sign in to comment.