diff --git a/src/common/components/ApprovedBy/ApprovedBy.js b/src/common/components/ApprovedBy/ApprovedBy.js index 883b806d..8dae38c7 100644 --- a/src/common/components/ApprovedBy/ApprovedBy.js +++ b/src/common/components/ApprovedBy/ApprovedBy.js @@ -11,17 +11,21 @@ import { stripesConnect } from '@folio/stripes/core'; import { baseManifest, USERS_API, + VersionKeyValue, } from '@folio/stripes-acq-components'; import { getUserName } from '../../utils'; -export const ApprovedBy = ({ approvedByUserId, resources }) => { +export const ApprovedBy = ({ approvedByUserId, isVersionView, name, resources }) => { const { failed, records } = resources.approvedByUser || {}; const approvedByUser = failed ? null : get(records, '0'); const value = approvedByUserId ? getUserName(approvedByUser) : ; + const KeyValueComponent = isVersionView ? VersionKeyValue : KeyValue; + return ( - } value={value} /> @@ -37,6 +41,8 @@ ApprovedBy.manifest = Object.freeze({ ApprovedBy.propTypes = { approvedByUserId: PropTypes.string, + isVersionView: PropTypes.bool, + name: PropTypes.string, resources: PropTypes.shape({ approvedByUser: PropTypes.object, }).isRequired, diff --git a/src/common/components/CalculatedExchangeAmount/CalculatedExchangeAmount.js b/src/common/components/CalculatedExchangeAmount/CalculatedExchangeAmount.js index 28b21a69..e7e07e40 100644 --- a/src/common/components/CalculatedExchangeAmount/CalculatedExchangeAmount.js +++ b/src/common/components/CalculatedExchangeAmount/CalculatedExchangeAmount.js @@ -1,13 +1,22 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import { AmountWithCurrencyField } from '@folio/stripes-acq-components'; +import { + AmountWithCurrencyField, + VersionKeyValue, +} from '@folio/stripes-acq-components'; import { KeyValue } from '@folio/stripes/components'; import { useStripes } from '@folio/stripes/core'; import { useExchangeCalculation } from '../../hooks'; -export const CalculatedExchangeAmount = ({ currency, exchangeRate, total }) => { +export const CalculatedExchangeAmount = ({ + currency, + exchangeRate, + isVersionView = false, + name, + total, +}) => { const stripes = useStripes(); const systemCurrency = stripes.currency; const enabled = Boolean(systemCurrency !== currency && total); @@ -19,22 +28,29 @@ export const CalculatedExchangeAmount = ({ currency, exchangeRate, total }) => { to: systemCurrency, }, { enabled }); + const KeyValueComponent = isVersionView ? VersionKeyValue : KeyValue; + if (!enabled) { return null; } return ( - }> + } + > - + ); }; CalculatedExchangeAmount.propTypes = { currency: PropTypes.string, exchangeRate: PropTypes.number, + isVersionView: PropTypes.bool, + name: PropTypes.string, total: PropTypes.number, }; diff --git a/src/common/components/FiscalYearValue/FiscalYearValue.js b/src/common/components/FiscalYearValue/FiscalYearValue.js index 3469a74e..6e5ba7b4 100644 --- a/src/common/components/FiscalYearValue/FiscalYearValue.js +++ b/src/common/components/FiscalYearValue/FiscalYearValue.js @@ -2,10 +2,14 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { KeyValue } from '@folio/stripes/components'; +import { VersionKeyValue } from '@folio/stripes-acq-components'; + +export const FiscalYearValue = ({ isVersionView, name, value }) => { + const KeyValueComponent = isVersionView ? VersionKeyValue : KeyValue; -export const FiscalYearValue = ({ value }) => { return ( - } value={value} /> @@ -13,5 +17,7 @@ export const FiscalYearValue = ({ value }) => { }; FiscalYearValue.propTypes = { + isVersionView: PropTypes.bool, + name: PropTypes.string, value: PropTypes.string, }; diff --git a/src/common/components/FiscalYearValue/FiscalYearValueContainer.js b/src/common/components/FiscalYearValue/FiscalYearValueContainer.js index 348df74c..94612673 100644 --- a/src/common/components/FiscalYearValue/FiscalYearValueContainer.js +++ b/src/common/components/FiscalYearValue/FiscalYearValueContainer.js @@ -5,7 +5,7 @@ import { Loading } from '@folio/stripes/components'; import { useFiscalYear } from '../../hooks'; import { FiscalYearValue } from './FiscalYearValue'; -export const FiscalYearValueContainer = ({ fiscalYearId }) => { +export const FiscalYearValueContainer = ({ fiscalYearId, ...rest }) => { const { fiscalYear, isLoading, @@ -14,7 +14,7 @@ export const FiscalYearValueContainer = ({ fiscalYearId }) => { if (isLoading) return ; return ( - + ); }; diff --git a/src/common/components/Status/StatusValue.js b/src/common/components/Status/StatusValue.js index 079c4ab1..425b7a4c 100644 --- a/src/common/components/Status/StatusValue.js +++ b/src/common/components/Status/StatusValue.js @@ -3,16 +3,26 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { KeyValue } from '@folio/stripes/components'; +import { VersionKeyValue } from '@folio/stripes-acq-components'; import { getInvoiceStatusLabel } from '../../utils'; -const StatusValue = ({ value }) => ( - }> - - -); +const StatusValue = ({ isVersionView, name, value }) => { + const KeyValueComponent = isVersionView ? VersionKeyValue : KeyValue; + + return ( + } + name={name} + > + + + ); +}; StatusValue.propTypes = { + isVersionView: PropTypes.bool, + name: PropTypes.string, value: PropTypes.string.isRequired, }; diff --git a/src/common/hooks/useOrderLines/useOrderLines.js b/src/common/hooks/useOrderLines/useOrderLines.js index 18082928..4f008044 100644 --- a/src/common/hooks/useOrderLines/useOrderLines.js +++ b/src/common/hooks/useOrderLines/useOrderLines.js @@ -19,6 +19,7 @@ const buildQueryByOrderId = (itemsChunk) => { }; export const useOrderLines = (orderIds, options = {}) => { + const { enabled = true, buildQuery = buildQueryByOrderId, ...otherOptions } = options; const ky = useOkapiKy(); const [namespace] = useNamespace({ key: 'order-lines' }); @@ -31,10 +32,12 @@ export const useOrderLines = (orderIds, options = {}) => { .then(({ poLines }) => poLines) .catch(() => []), orderIds, - buildQueryByOrderId, - + buildQuery, ), - { enabled: Boolean(orderIds?.length), ...options }, + { + enabled: enabled && Boolean(orderIds?.length), + ...otherOptions, + }, ); return ({ diff --git a/src/common/hooks/useSelectedInvoiceVersion/useSelectedInvoiceVersion.js b/src/common/hooks/useSelectedInvoiceVersion/useSelectedInvoiceVersion.js index 8e61bcbd..991ae5a0 100644 --- a/src/common/hooks/useSelectedInvoiceVersion/useSelectedInvoiceVersion.js +++ b/src/common/hooks/useSelectedInvoiceVersion/useSelectedInvoiceVersion.js @@ -1,10 +1,6 @@ -import { - filter, - flow, - get, - keyBy, - uniq, -} from 'lodash/fp'; +import get from 'lodash/get'; +import keyBy from 'lodash/keyBy'; +import uniq from 'lodash/uniq'; import { useMemo } from 'react'; import { useIntl } from 'react-intl'; import { useQuery } from 'react-query'; @@ -16,10 +12,6 @@ import { import { getFullName } from '@folio/stripes/util'; import { ACQUISITIONS_UNITS_API, - CONFIG_ADDRESSES, - CONFIG_API, - LIMIT_MAX, - MODULE_TENANT, fetchExportDataByIds, fetchOrganizationsByIds, getAddresses, @@ -27,28 +19,9 @@ import { } from '@folio/stripes-acq-components'; import { useInvoice } from '../useInvoice'; +import { getTenantAddresses, getVersionMetadata } from './utils'; -const getUniqItems = (arr) => ( - flow( - uniq, - filter(Boolean), - )(arr) -); - -export const getTenantAddresses = (ky) => async () => { - const searchParams = { - limit: LIMIT_MAX, - query: `(module=${MODULE_TENANT} and configName=${CONFIG_ADDRESSES})`, - }; - - return ky.get(CONFIG_API, { searchParams }).json(); -}; - -export const getVersionMetadata = (version, entity) => ({ - ...get(entity, 'metadata', {}), - updatedByUserId: version?.userId, - updatedDate: version?.actionDate, -}); +const DEFAULT_VALUE = []; export const useSelectedInvoiceVersion = ({ versionId, versions, snapshotPath }, options = {}) => { const intl = useIntl(); @@ -60,26 +33,26 @@ export const useSelectedInvoiceVersion = ({ versionId, versions, snapshotPath }, versions?.find(({ id }) => id === versionId) ), [versionId, versions]); const versionSnapshot = useMemo(() => ( - get(snapshotPath, currentVersion) + get(currentVersion, snapshotPath) ), [snapshotPath, currentVersion]); const { invoice, isLoading: isInvoiceLoading, - } = useInvoice(currentVersion?.id); + } = useInvoice(currentVersion?.invoiceId); const metadata = useMemo(() => getVersionMetadata(currentVersion, invoice), [currentVersion, invoice]); - const assignedToId = versionSnapshot?.assignedTo; const createdByUserId = metadata?.createdByUserId; - const vendorId = versionSnapshot?.vendor; + const updatedByUserId = metadata?.updatedByUserId; + const vendorId = versionSnapshot?.vendorId; const billToId = versionSnapshot?.billTo; - const versionUserIds = useMemo(() => getUniqItems([assignedToId, createdByUserId]), [assignedToId, createdByUserId]); + const versionUserIds = useMemo(() => uniq([updatedByUserId, createdByUserId]), [updatedByUserId, createdByUserId]); const { - users, + users = DEFAULT_VALUE, isLoading: isUsersLoading, } = useUsersBatch(versionUserIds); - const versionUsersMap = keyBy('id', users); + const versionUsersMap = keyBy(users, 'id'); const { isLoading: isVersionDataLoading, @@ -88,24 +61,25 @@ export const useSelectedInvoiceVersion = ({ versionId, versions, snapshotPath }, [namespace, versionId, versionSnapshot?.id], async () => { const organizationIds = [vendorId]; - const acqUnitsIds = versionSnapshot?.acqUnitIds || []; + const acqUnitsIds = versionSnapshot?.acqUnitIds || DEFAULT_VALUE; const [ organizationsMap, acqUnitsMap, addressesMap, ] = await Promise.all([ - fetchOrganizationsByIds(ky)(organizationIds).then(keyBy('id')), - fetchExportDataByIds({ ky, ids: acqUnitsIds, api: ACQUISITIONS_UNITS_API, records: 'acquisitionsUnits' })(acqUnitsIds).then(keyBy('id')), + fetchOrganizationsByIds(ky)(organizationIds).then(({ organizations }) => keyBy(organizations, 'id')), + fetchExportDataByIds({ + ky, + ids: acqUnitsIds, + api: ACQUISITIONS_UNITS_API, + records: 'acquisitionsUnits', + }).then(data => keyBy(data, 'id')), getTenantAddresses(ky)() .then(({ configs }) => getAddresses(configs)) - .then(keyBy('id')), + .then(data => keyBy(data, 'id')), ]); - const assignedTo = versionUsersMap[assignedToId] - ? getFullName(versionUsersMap[assignedToId]) - : deletedRecordLabel; - const createdByUser = versionUsersMap[createdByUserId] ? getFullName(versionUsersMap[createdByUserId]) : deletedRecordLabel; @@ -113,7 +87,6 @@ export const useSelectedInvoiceVersion = ({ versionId, versions, snapshotPath }, return { ...versionSnapshot, acqUnits: acqUnitsIds.map(acqUnitsId => acqUnitsMap[acqUnitsId]?.name || deletedRecordLabel).join(', '), - assignedTo: assignedToId && assignedTo, vendor: organizationsMap[vendorId]?.name || deletedRecordLabel, createdByUser: createdByUserId && createdByUser, billTo: billToId && (addressesMap[billToId]?.address || deletedRecordLabel), @@ -133,8 +106,8 @@ export const useSelectedInvoiceVersion = ({ versionId, versions, snapshotPath }, const isLoading = ( isInvoiceLoading - || isUsersLoading || isVersionDataLoading + || isUsersLoading ); return { diff --git a/src/common/hooks/useSelectedInvoiceVersion/utils.js b/src/common/hooks/useSelectedInvoiceVersion/utils.js new file mode 100644 index 00000000..8f6c8b41 --- /dev/null +++ b/src/common/hooks/useSelectedInvoiceVersion/utils.js @@ -0,0 +1,23 @@ +import get from 'lodash/get'; + +import { + CONFIG_ADDRESSES, + CONFIG_API, + LIMIT_MAX, + MODULE_TENANT, +} from '@folio/stripes-acq-components'; + +export const getTenantAddresses = (ky) => async () => { + const searchParams = { + limit: LIMIT_MAX, + query: `(module=${MODULE_TENANT} and configName=${CONFIG_ADDRESSES})`, + }; + + return ky.get(CONFIG_API, { searchParams }).json(); +}; + +export const getVersionMetadata = (version, entity) => ({ + ...get(entity, 'metadata', {}), + updatedByUserId: version?.userId, + updatedDate: version?.actionDate, +}); diff --git a/src/invoices/InvoiceDetails/BatchGroupValue/BatchGroupValue.js b/src/invoices/InvoiceDetails/BatchGroupValue/BatchGroupValue.js index fae2aced..b538b70d 100644 --- a/src/invoices/InvoiceDetails/BatchGroupValue/BatchGroupValue.js +++ b/src/invoices/InvoiceDetails/BatchGroupValue/BatchGroupValue.js @@ -9,10 +9,11 @@ import { KeyValue, Loading, } from '@folio/stripes/components'; +import { VersionKeyValue } from '@folio/stripes-acq-components'; import { batchGroupByPropResource } from '../../../common/resources'; -export const BatchGroupValue = ({ id, label, mutator }) => { +export const BatchGroupValue = ({ id, isVersionView, name, label, mutator }) => { const [batchGroup, setBatchGroup] = useState(); useEffect( @@ -29,13 +30,16 @@ export const BatchGroupValue = ({ id, label, mutator }) => { [id], ); + const KeyValueComponent = isVersionView ? VersionKeyValue : KeyValue; + if (!batchGroup) { return ; } return ( - ); @@ -47,8 +51,10 @@ BatchGroupValue.manifest = Object.freeze({ BatchGroupValue.propTypes = { id: PropTypes.string, + isVersionView: PropTypes.bool, label: PropTypes.node.isRequired, mutator: PropTypes.object.isRequired, + name: PropTypes.string, }; export default stripesConnect(BatchGroupValue); diff --git a/src/invoices/InvoicesList/InvoicesList.js b/src/invoices/InvoicesList/InvoicesList.js index 56c34f95..4baab594 100644 --- a/src/invoices/InvoicesList/InvoicesList.js +++ b/src/invoices/InvoicesList/InvoicesList.js @@ -276,7 +276,7 @@ const InvoicesList = ({ exact /> diff --git a/src/invoices/VersionHistory/VersionHistory.js b/src/invoices/VersionHistory/VersionHistory.js index 4f158c14..86925cfe 100644 --- a/src/invoices/VersionHistory/VersionHistory.js +++ b/src/invoices/VersionHistory/VersionHistory.js @@ -73,7 +73,7 @@ const VersionHistory = ({ - // ); - - // const vendorInvoiceNo = invoice.vendorInvoiceNo; - // const adjustments = get(invoice, 'adjustments', []); - // const fundDistributions = useMemo( - // () => adjustments.reduce((acc, adjustment) => { - // if (adjustment.fundDistributions) { - // adjustment.fundDistributions.forEach((distr) => { - // acc.push({ - // ...distr, - // adjustmentDescription: adjustment.description, - // adjustmentId: adjustment.id, - // totalAmount: calculateAdjustmentAmount(adjustment, subTotal, currency), - // }); - // }); - // } - - // return acc; - // }, []), - // [adjustments, currency, subTotal], - // ); + const adjustments = get(version, 'adjustments', []); + const poNumbers = get(version, 'poNumbers', []); return ( - + } id="information" > - - - {/* } - id={SECTIONS.lines} - displayWhenOpen={renderLinesActions} - displayWhenClosed={ -
- {totalInvoiceLines} -
- } - > - -
*/} - - {/* {Boolean(fundDistributions.length) && ( - } - > - - - )} */} - - {/* {Boolean(adjustments.length) && ( - } - id={SECTIONS.adjustments} - > - + - )} */} + { + Boolean(poNumbers.length) && ( + } + id="invoiceLines" + > + + + ) + } - {/* } - id={SECTIONS.vendorDetails} - > - - */} - {/* } - id={SECTIONS.extendedInformation} - > - - */} - {/* {showVoucherInformation && batchVoucherExport && ( - } - id={SECTIONS.batchVoucherExport} - > - - - )} */} - {/* {showVoucherInformation && } - } - id={SECTIONS.documents} - > - - */} + { + Boolean(adjustments.length) && ( + } + id="adjustments" + > + + + ) + }
@@ -187,5 +89,5 @@ export function VersionHistoryView({ version = {} }) { } VersionHistoryView.propTypes = { - version: PropTypes.object, + version: PropTypes.object.isRequired, }; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js new file mode 100644 index 00000000..54c91d64 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js @@ -0,0 +1,81 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + Row, +} from '@folio/stripes/components'; +import { + AmountWithCurrencyField, + FrontendSortingMCL, + VersionKeyValue, +} from '@folio/stripes-acq-components'; + +import { + ADJUSTMENT_PRORATE_LABELS, + ADJUSTMENT_RELATION_TO_TOTAL_LABELS, + ADJUSTMENT_TYPE_VALUES, +} from '../../../../common/constants'; +import { + COLUMN_MAPPING, + SORTED_COLUMN, + SORTERS, VISIBLE_COLUMNS, +} from './constants'; + +export const VersionHistoryViewAdjustments = ({ adjustments, currency }) => { + const resultsFormatter = { + description: ({ rowIndex, description }) => ( + ), + value: ({ rowIndex, type, value }) => ( + + ) + : `${value}%` + )} + />), + prorate: ({ prorate, rowIndex }) => ( + } + /> + ), + relationToTotal: ({ relationToTotal, rowIndex }) => ( + } + /> + ), + }; + + return ( + + + + + + ); +}; + +VersionHistoryViewAdjustments.propTypes = { + adjustments: PropTypes.arrayOf(PropTypes.object), + currency: PropTypes.string, +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/constants.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/constants.js new file mode 100644 index 00000000..a350ec23 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/constants.js @@ -0,0 +1,12 @@ +import { FormattedMessage } from 'react-intl'; + +export const SORTED_COLUMN = 'description'; +export const VISIBLE_COLUMNS = ['description', 'value', 'prorate', 'relationToTotal']; +export const SORTERS = { description: ({ description }) => description?.toLowerCase() }; + +export const COLUMN_MAPPING = { + description: , + value: , + prorate: , + relationToTotal: , +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js new file mode 100644 index 00000000..4eab1eed --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js @@ -0,0 +1 @@ +export { VersionHistoryViewAdjustments } from './VersionHistoryViewAdjustments'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js index 0ace19e7..ddb2ca6f 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js @@ -1,4 +1,4 @@ -import { isNumber } from 'lodash'; +import isNumber from 'lodash/isNumber'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; @@ -8,17 +8,20 @@ import { } from '@folio/stripes/components'; import { ViewMetaData } from '@folio/stripes/smart-components'; import { - AcqUnitsView, AmountWithCurrencyField, FolioFormattedDate, VersionKeyValue, sourceLabels, } from '@folio/stripes-acq-components'; +import { + ApprovedBy, + CalculatedExchangeAmount, + FiscalYearValueContainer, + StatusValue, +} from '../../../../common/components'; import { isCancelled } from '../../../../common/utils'; -import { ApprovedBy, CalculatedExchangeAmount, FiscalYearValue, StatusValue } from '../../../../common/components'; import BatchGroupValue from '../../../InvoiceDetails/BatchGroupValue'; -import BillTo from '../../../InvoiceDetails/Information/BillTo'; export const VersionHistoryViewInformation = ({ version = {} }) => { const { @@ -38,7 +41,7 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { metadata, billTo, invoiceTotalUnits, - acqUnits, + acqUnits = [], currency, note, lockTotal, @@ -53,22 +56,32 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } value={} /> - + - + {isCancelled(status) && ( } value={cancellationNote} /> @@ -77,6 +90,7 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } value={} /> @@ -84,6 +98,7 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } value={paymentTerms} /> @@ -91,6 +106,7 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } value={} /> @@ -100,16 +116,26 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { data-test-approved-by xs={3} > - + - + } + value={acqUnits} + multiple + /> } + name="source" value={sourceLabels[source]} /> @@ -119,25 +145,34 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } + name="note" value={note} /> - + } + value={billTo} + /> } /> - }> - - + } + value={} + /> @@ -145,36 +180,34 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { } value={invoiceTotalUnits} /> - }> - - + } + value={} + /> - }> - - + } + value={} + /> - }> - - + } + value={} + /> @@ -184,19 +217,22 @@ export const VersionHistoryViewInformation = ({ version = {} }) => { currency={currency} exchangeRate={exchangeRate} total={total} + name="exchangeRate" + isVersionView /> - {isLockTotal && ( + + {isLockTotal && ( + - }> - - + } + value={} + /> - )} - + + )} ); }; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js new file mode 100644 index 00000000..c43abed5 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js @@ -0,0 +1,193 @@ +import invert from 'lodash/invert'; +import keyBy from 'lodash/keyBy'; +import PropTypes from 'prop-types'; +import { useMemo } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Icon, + Loading, + NoValue, +} from '@folio/stripes/components'; +import { useColumnManager } from '@folio/stripes/smart-components'; +import { + AmountWithCurrencyField, + PAYMENT_STATUS, + FrontendSortingMCL, + ORDER_STATUS_LABEL, + RECEIPT_STATUS, +} from '@folio/stripes-acq-components'; + +import { + useOrderLines, + useVendors, +} from '../../../../common/hooks'; +import { INVOICE_LINES_COLUMN_MAPPING } from '../../../constants'; +import { + useInvoiceLinesByInvoiceId, + useOrdersByPoNumbers, +} from '../hooks'; +import { buildQueryByIds } from './utils'; + +import styles from './style.css'; + +const COLUMN_LINE_NUMBER = 'lineNumber'; + +export const VersionHistoryViewInvoiceLine = ({ version = {} }) => { + const { + invoiceLines = [], + isLoading: isInvoiceLinesLoading, + } = useInvoiceLinesByInvoiceId(version?.id); + const { + orders = [], + isLoading: isOrdersLoading, + } = useOrdersByPoNumbers(version?.poNumbers); + + const orderLineIds = useMemo(() => invoiceLines.map(({ poLineId }) => poLineId), [invoiceLines]); + + const { + orderLines, + isLoading: isOrderLinesLoading, + } = useOrderLines(orderLineIds, { buildQuery: buildQueryByIds }); + const { + vendors, + isLoading: isVendorsLoading, + } = useVendors(orders.map(({ vendor }) => vendor)); + + const currency = version?.currency; + + const orderLinesMap = useMemo(() => keyBy(orderLines, 'id'), [orderLines]); + const ordersMap = useMemo(() => keyBy(orders, 'id'), [orders]); + const vendorsMap = useMemo(() => keyBy(vendors, 'id'), [vendors]); + + const { visibleColumns } = useColumnManager( + 'invoice-lines-column-manager', + INVOICE_LINES_COLUMN_MAPPING, + ); + + const sorters = useMemo(() => ({ + [COLUMN_LINE_NUMBER]: ({ invoiceLineNumber }) => Number(invoiceLineNumber), + polNumber: ({ poLineId }) => Number(orderLinesMap?.[poLineId]?.poLineNumber?.replace('-', '.')), + description: ({ description }) => description, + }), [orderLinesMap]); + + const resultsFormatter = useMemo(() => ({ + // eslint-disable-next-line react/prop-types + [COLUMN_LINE_NUMBER]: ({ poLineId, invoiceLineNumber, id }) => { + const poLineIsFullyPaid = orderLinesMap?.[poLineId]?.paymentStatus === PAYMENT_STATUS.fullyPaid; + + return ( + <> + {!poLineIsFullyPaid ? null : ( + <> + +   + + )} + {invoiceLineNumber} + + ); + }, + // eslint-disable-next-line react/prop-types + adjustmentsTotal: ({ adjustmentsTotal }) => ( + + ), + // eslint-disable-next-line react/prop-types + total: ({ total }) => ( + + ), + // eslint-disable-next-line react/prop-types + subTotal: ({ subTotal }) => ( + + ), + // eslint-disable-next-line + polNumber: ({ rowIndex, ...line }) => orderLinesMap?.[line?.poLineId]?.poLineNumber, + fundCode: line => line.fundDistributions?.map(({ code }) => code)?.join(', ') || , + poStatus: line => { + const orderLine = orderLinesMap?.[line.poLineId]; + + return ORDER_STATUS_LABEL[ordersMap[orderLine?.purchaseOrderId]?.workflowStatus] || ; + }, + receiptStatus: line => { + const status = orderLinesMap?.[line.poLineId]?.receiptStatus; + const translationKey = invert(RECEIPT_STATUS)[status]; + + return status ? + ( + + ) + : ; + }, + paymentStatus: line => { + const status = orderLinesMap?.[line.poLineId]?.paymentStatus; + const translationKey = invert(PAYMENT_STATUS)[status]; + + return status ? + ( + + ) + : ; + }, + vendorCode: line => { + const orderLine = orderLinesMap?.[line.poLineId]; + const vendorId = ordersMap[orderLine?.purchaseOrderId]?.vendor; + + return vendorsMap[vendorId]?.code || ; + }, + vendorRefNo: line => ( + line.referenceNumbers?.map(({ refNumber }) => refNumber)?.join(', ') || + ), + }), [orderLinesMap, currency, ordersMap, vendorsMap]); + + const isLoading = isInvoiceLinesLoading || isOrderLinesLoading || isVendorsLoading || isOrdersLoading; + + if (isLoading) { + return ; + } + + return ( + <> +
+ +
+ + + + ); +}; + +VersionHistoryViewInvoiceLine.propTypes = { + version: PropTypes.object.isRequired, +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js new file mode 100644 index 00000000..bdd22691 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js @@ -0,0 +1 @@ +export { VersionHistoryViewInvoiceLine } from './VersionHistoryViewInvoiceLine'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css new file mode 100644 index 00000000..b9e2a410 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css @@ -0,0 +1,4 @@ +.invoiceLinesTotal { + font-weight: 600; + padding: 0 15px; +} diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js new file mode 100644 index 00000000..2a02714c --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js @@ -0,0 +1,7 @@ +export const buildQueryByIds = (itemsChunk) => { + const query = itemsChunk + .map(id => `id==${id}`) + .join(' or '); + + return query || ''; +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/index.js b/src/invoices/VersionHistory/VersionHistoryView/hooks/index.js new file mode 100644 index 00000000..dbaa0abe --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/hooks/index.js @@ -0,0 +1,2 @@ +export { useInvoiceLinesByInvoiceId } from './useInvoiceLinesByInvoiceId'; +export { useOrdersByPoNumbers } from './useOrdersByPoNumbers'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId.js b/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId.js new file mode 100644 index 00000000..2b32d6da --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId.js @@ -0,0 +1,29 @@ +import { useQuery } from 'react-query'; + +import { useOkapiKy } from '@folio/stripes/core'; +import { + INVOICE_LINE_API, + INVOICES_API, LIMIT_MAX, +} from '@folio/stripes-acq-components'; + +const DEFAULT_VALUE = []; + +export const useInvoiceLinesByInvoiceId = (invoiceId) => { + const ky = useOkapiKy(); + + const searchParams = { + limit: `${LIMIT_MAX}`, + query: `(invoiceId==${invoiceId}) sortBy metadata.createdDate invoiceLineNumber`, + }; + + const { isLoading, data } = useQuery( + [INVOICES_API, invoiceId], + ({ signal }) => ky.get(`${INVOICE_LINE_API}`, { searchParams, signal }).json(), + { enabled: Boolean(invoiceId) }, + ); + + return ({ + isLoading, + invoiceLines: data?.invoiceLines || DEFAULT_VALUE, + }); +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers.js b/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers.js new file mode 100644 index 00000000..0e26ec73 --- /dev/null +++ b/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers.js @@ -0,0 +1,41 @@ +import { useQuery } from 'react-query'; + +import { + useOkapiKy, + useNamespace, +} from '@folio/stripes/core'; +import { + batchRequest, + ORDERS_API, +} from '@folio/stripes-acq-components'; + +export const useOrdersByPoNumbers = (poNumbers = [], options = {}) => { + const ky = useOkapiKy(); + const [namespace] = useNamespace({ key: 'orders-by-poNumbers' }); + + const searchParams = { + limit: '1000', + query: `poNumber==(${poNumbers.join(' or ')})`, + }; + + const { isLoading, data: orders = [] } = useQuery( + [namespace, poNumbers], + () => batchRequest( + ({ signal }) => ky + .get(ORDERS_API, { searchParams, signal }) + .json() + .then(({ purchaseOrders }) => purchaseOrders) + .catch(() => []), + poNumbers, + ), + { + enabled: Boolean(poNumbers.length), + ...options, + }, + ); + + return ({ + isLoading, + orders, + }); +}; diff --git a/src/invoices/VersionHistory/constants.js b/src/invoices/VersionHistory/constants.js index a68a3e6c..cfdd019c 100644 --- a/src/invoices/VersionHistory/constants.js +++ b/src/invoices/VersionHistory/constants.js @@ -7,7 +7,7 @@ export const INVOICE_FIELDS_LABEL_MAP = { 'adjustments[\\d].relationToTotal': 'ui-invoice.settings.adjustments.relationToTotal', 'adjustments[\\d].type': 'ui-invoice.settings.adjustments.type', 'adjustments[\\d].value': 'ui-invoice.settings.adjustments.value', - 'adjustments[\\d]': 'ui-invoice.invoice.details.lines.list.adjustments', + 'adjustments[\\d].id': 'ui-invoice.invoice.details.lines.list.adjustments', 'adjustmentsTotal': 'ui-invoice.invoice.details.information.adjustment', 'approvalDate': 'ui-invoice.invoice.approvalDate', 'approvedBy': 'ui-invoice.invoice.approvedBy',