From 521c0d4b8f6e73c2e311fb86464fef578a4520ab Mon Sep 17 00:00:00 2001 From: James Brunskill Date: Wed, 11 Dec 2024 17:05:11 +1300 Subject: [PATCH 01/10] Handle optional gs1 warranty dates --- server/service/src/asset/parse.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/service/src/asset/parse.rs b/server/service/src/asset/parse.rs index f823ac7a2f..5c2556a3c3 100644 --- a/server/service/src/asset/parse.rs +++ b/server/service/src/asset/parse.rs @@ -81,11 +81,12 @@ fn create_draft_asset_from_gs1(ctx: &ServiceContext, gs1: GS1) -> Result Date: Tue, 17 Dec 2024 16:17:33 +1300 Subject: [PATCH 02/10] add permission check to scan button --- .../ListView/AddFromScannerButton.tsx | 52 +++++++++++-------- .../common/src/intl/locales/en/common.json | 1 + 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx b/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx index 5c0f70dff1..e337fe808e 100644 --- a/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx +++ b/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx @@ -15,6 +15,8 @@ import { useConfirmationModal, FnUtils, AssetLogStatusInput, + UserPermission, + useAuthContext, } from '@openmsupply-client/common'; import { AppRoute } from '@openmsupply-client/config'; import { useAssets } from '../api'; @@ -24,7 +26,7 @@ export const AddFromScannerButtonComponent = () => { const t = useTranslation(); const { isConnected, isEnabled, isScanning, startScanning, stopScan } = useBarcodeScannerContext(); - const { error } = useNotification(); + const { error, info } = useNotification(); const buttonRef = useRef(null); const navigate = useNavigate(); const { DisabledNotification, show } = useDisabledNotificationPopover({ @@ -35,11 +37,13 @@ export const AddFromScannerButtonComponent = () => { AppRoute.Equipment ); const { mutateAsync: fetchAsset } = useAssets.document.fetch(); - const { mutateAsync: fetchOrCreateFromGS1 } = useAssets.document.gs1(); + const { mutateAsync: fetchFromGS1 } = useAssets.document.gs1(); const { mutateAsync: saveNewAsset } = useAssets.document.insert(); const { insertLog, invalidateQueries } = useAssets.log.insert(); const newAssetData = useRef(); + const { userHasPermission } = useAuthContext(); + const showCreateConfirmation = useConfirmationModal({ onConfirm: () => { if (newAssetData.current) { @@ -59,8 +63,8 @@ export const AddFromScannerButtonComponent = () => { .catch(e => error(t('error.unable-to-save-asset', { error: e }))()); } }, - message: t('heading.create-new-asset'), - title: t('messages.create-new-asset-confirmation'), + title: t('heading.create-new-asset'), + message: t('messages.create-new-asset-confirmation'), }); const handleScanResult = async (result: ScanResult) => { @@ -81,7 +85,7 @@ export const AddFromScannerButtonComponent = () => { } // send the GS1 data to backend to handle - const asset = await fetchOrCreateFromGS1(gs1).catch(() => {}); + const asset = await fetchFromGS1(gs1).catch(() => {}); if (asset?.__typename !== 'AssetNode') { error(t('error.no-matching-asset', { id: result.content }))(); @@ -93,7 +97,8 @@ export const AddFromScannerButtonComponent = () => { } // If not existing, offer to create from the parsed GS1 data - if (!asset?.id) { + const permission = UserPermission.AssetMutate; + if (userHasPermission(permission)) { newAssetData.current = { ...asset, id: FnUtils.generateUUID(), @@ -102,26 +107,29 @@ export const AddFromScannerButtonComponent = () => { parsedCatalogProperties: {}, }; showCreateConfirmation(); - } + } else info(t('error.no-asset-create-permission'))(); } }; const handleClick = async (e: React.MouseEvent) => { - if (!isConnected) { - show(e); - return; - } + const permission = UserPermission.AssetQuery; - buttonRef.current?.blur(); - if (isScanning) { - stopScan(); - } else { - try { - await startScanning(handleScanResult); - } catch (e) { - error(t('error.unable-to-start-scanning', { error: e }))(); + if (userHasPermission(permission)) { + if (!isConnected) { + show(e); + return; } - } + buttonRef.current?.blur(); + if (isScanning) { + stopScan(); + } else { + try { + await startScanning(handleScanResult); + } catch (e) { + error(t('error.unable-to-start-scanning', { error: e }))(); + } + } + } else info(t('error.no-asset-view-permission'))(); }; // stop scanning when the component unloads @@ -151,7 +159,9 @@ export const AddFromScannerButtonComponent = () => { { + handleClick(e); + }} Icon={ isScanning ? ( diff --git a/client/packages/common/src/intl/locales/en/common.json b/client/packages/common/src/intl/locales/en/common.json index 40c26940e5..cc5b8ada61 100644 --- a/client/packages/common/src/intl/locales/en/common.json +++ b/client/packages/common/src/intl/locales/en/common.json @@ -277,6 +277,7 @@ "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-view-permission": "You do not have permission to view assets.", "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-data": "No data available", From ffaac44aff7542da7a47e6b488fba4c7d989dc47 Mon Sep 17 00:00:00 2001 From: Aimee <163234798+aimee-mcneil-melville@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:33:21 +1300 Subject: [PATCH 03/10] Add permission check to update status button --- .../Equipment/DetailView/UpdateStatusButton.tsx | 15 +++++++++++++-- .../common/src/intl/locales/en/common.json | 17 +++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx b/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx index 958dc0a829..42a2916164 100644 --- a/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx +++ b/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx @@ -14,6 +14,8 @@ import { InsertAssetLogInput, FnUtils, ClickableStepper, + UserPermission, + useAuthContext, } from '@openmsupply-client/common'; import { StatusTab } from './StatusTab'; import { UploadTab } from './UploadTab'; @@ -43,10 +45,19 @@ export const UpdateStatusButtonComponent = ({ const { currentTab, onChangeTab } = useTabs(Tabs.Status); const t = useTranslation(); const { Modal, hideDialog, showDialog } = useDialog({ onClose }); - const { error, success } = useNotification(); + const { error, success, info } = useNotification(); const [draft, setDraft] = useState>(getEmptyAssetLog('')); const { insertLog, invalidateQueries } = useAssets.log.insert(); + const permission = UserPermission.AssetMutate; + const { userHasPermission } = useAuthContext(); + + const onUpdateStatus = () => { + if (userHasPermission(permission)) { + showDialog; + } else info(t('error.no-asset-edit-permission'))(); + }; + const onNext = useDebounceCallback(() => { onChangeTab(Tabs.Upload); }, []); @@ -188,7 +199,7 @@ export const UpdateStatusButtonComponent = ({ } label={t('button.update-status')} - onClick={showDialog} + onClick={onUpdateStatus} /> ); diff --git a/client/packages/common/src/intl/locales/en/common.json b/client/packages/common/src/intl/locales/en/common.json index 7aa81bdbeb..f151f79db4 100644 --- a/client/packages/common/src/intl/locales/en/common.json +++ b/client/packages/common/src/intl/locales/en/common.json @@ -278,6 +278,7 @@ "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-customer-return-items": "No items have been added to this return.", "error.no-customer-returns": "There are no Customer Returns to display.", @@ -1404,6 +1405,7 @@ "messages.logout-confirm": "This will log you out.", "messages.max-or-min-temperature": "Max / min temperature", "messages.message-not-sent": "Error! Your message was not sent", + "messages.message-sent": "Your message has been sent successfully!", "messages.must-allocate-all-lines": "Cannot change the status until all lines have been allocated.", "messages.native-mode": "Select the mode which you would like to run. Note that you can change this option later if you have administrator access.", "messages.native-mode-client": "This mode allows you to select which server to connect to.", @@ -1485,7 +1487,6 @@ "messages.select-rows-to-delete": "Select rows to delete them", "messages.select-rows-to-delete-them": "Select rows to delete them", "messages.select-rows-to-return": "Select rows to return them", - "messages.message-sent": "Your message has been sent successfully!", "messages.service-charges-description": "Total amounts of service charges. The calculated tax amount is an effective tax rate using the total tax paid over the subtotal of all service charges.", "messages.shipment-saved": "Shipment saved 🥳", "messages.stock-charges-description": "Total charges for stock lines. The calculated tax amount is an effective tax rate using the total tax paid over the subtotal of all stock lines.", @@ -1552,11 +1553,13 @@ "reason.stored": "Stored", "reason.unknown": "Unknown", "replenishment": "Replenishment", + "report.AMC-lookback": "AMC Lookback Period", "report.actual": "Actual", "report.actual-stock": "Actual stock", "report.amc-12-months": "AMC (12 months)", "report.amc-24-months": "AMC (24 months)", "report.authorized-by": "Authorized-by", + "report.available-stock-on-hand": "Available stock on hand", "report.collected-by": "Collected by", "report.comments": "Comments", "report.confirm-date": "Confirm date", @@ -1567,6 +1570,7 @@ "report.counted-packs": "Counted packs", "report.created-date": "Created date", "report.entered-code": "Entered code", + "report.error-translating": "Error generating translation for key {{key}}", "report.expected-usage": "Expected usage", "report.expiring": "Expiring", "report.expiring-12-months": "Expiring in 12 months", @@ -1576,11 +1580,11 @@ "report.extension": "Extension", "report.global-total": "Global total", "report.in-stock": "In stock", - "report.available-stock-on-hand": "Available stock on hand", "report.invoice": "Invoice", "report.invoice-type": "Invoice type", "report.issued": "Issued", "report.item-code": "Item code", + "report.item-code-or-name": "Item Code or Name", "report.item-name": "Item name", "report.line": "Line", "report.months-cover": "Months cover", @@ -1606,6 +1610,8 @@ "report.sell-price": "Sell price", "report.shipped-date": "Shipped date", "report.snapshot-packs": "Snapshot packs", + "report.sort-by": "Sort by", + "report.sort-direction": "Sort direction", "report.stat": "Stat", "report.stock-at-risk": "Stock at risk", "report.stock-on-hand": "Stock on hand", @@ -1624,11 +1630,6 @@ "report.variance-packs": "Variance (packs)", "report.variance-value": "Variance (value)", "report.well-stocked": "Well stocked", - "report.item-code-or-name": "Item Code or Name", - "report.AMC-lookback": "AMC Lookback Period", - "report.error-translating": "Error generating translation for key {{key}}", - "report.sort-by": "Sort by", - "report.sort-direction": "Sort direction", "reports": "Reports", "returns": "Returns", "saving": "Saving…", @@ -1711,4 +1712,4 @@ "warning.caps-lock": "Warning: Caps lock is on", "warning.field-not-parsed": "{{field}} not parsed", "warning.nothing-to-supply": "Nothing left to supply!" -} +} \ No newline at end of file From 2c0dc6b0d7836d419d4ba9d2ea59e885c5a5301e Mon Sep 17 00:00:00 2001 From: Aimee <163234798+aimee-mcneil-melville@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:49:41 +1300 Subject: [PATCH 04/10] update android studio readme --- client/packages/android/README.MD | 32 +++++++++++++++--- .../doc/omSupply_android_gradle_jdk.png | Bin 0 -> 40433 bytes 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 client/packages/android/doc/omSupply_android_gradle_jdk.png diff --git a/client/packages/android/README.MD b/client/packages/android/README.MD index e45288c28a..5dc9df58a6 100644 --- a/client/packages/android/README.MD +++ b/client/packages/android/README.MD @@ -19,11 +19,10 @@ This requires a couple of steps. Currently, we support only 1 Android architecture (64bit); -| rust target | android ABI | -| aarch64-linux-android | arm64-v8a | +| rust target | android ABI | +| aarch64-linux-android | arm64-v8a | | ----------------------- | ----------- | - To add the required build targets to Rust run: ```bash @@ -41,7 +40,30 @@ echo "export NDK_BIN=~/Library/Android/sdk/ndk/26.1.10909125/toolchains/llvm/pre Open a new terminal and validate that `$NDK_BIN` is set correctly: `ls $NDK_BIN` (this should give a list of files starting with aarch64 and armv7a) Note, which linker Rust should use is defined in `server/android/.cargo/config.toml`, under [target.*]. -You can now use `yarn build:server` from this directory, this builds the `libremote_server_lib.so` binaries and relocate them to `app/src/main/jniLibs`. +### Java Installation + +In your terminal, run `java --version` to check if you have it installed. As at 19/12/2024 version `17.0.7-tem` is tested and works with our setup + +- install [SDK man](https://sdkman.io/) through your terminal by running `curl -s "https://get.sdkman.io" | bash` +- Open a new terminal + +Install Java: Run `sdk install java 17.0.7-tem` + +Then set the defaults using the following commands: + +- `sdk use java 17.0.7-tem` +- `sdk default java 17.0.7-tem` + +Go to Android Studio settings -> Build -> Build Settings + +- Change Gradle JDK to 17.0.7-tem + ![omSupply Gradle JDK](./doc/omSupply_android_gradle_jdk.png) + +You may also see prompts in Android Studio to sync - keep an eye out for these and run the sync as needed + +## Running Android Studio + +You can now use `yarn build:server` from the `server/android/` directory, this builds the `libremote_server_lib.so` binaries and relocate them to `app/src/main/jniLibs`. Please see `client/packages/android/app/src/main/java/org/openmsupply/client/RemoteServer.java` for more details of how these libs are loaded. It's important to note that web app is bundled in the remote server binary, and web app needs to be built from `client` directory with `yarn build` command, so it's best to use `yarn android:build:server` from client directory as it does both (builds web app and then build android remote server). @@ -76,7 +98,7 @@ yarn android:build:debug yarn android:build:release ``` -### Know script issues +### Known script issues When building apk `properties.local` files is required (it can be empty). Also can sometime get a lock on gradle build, can run `find ~/.gradle -type f -name "*.lock" -delete` to fix it diff --git a/client/packages/android/doc/omSupply_android_gradle_jdk.png b/client/packages/android/doc/omSupply_android_gradle_jdk.png new file mode 100644 index 0000000000000000000000000000000000000000..ea8ff3bdf7704caf35e81cd49b06e4cacb0235f8 GIT binary patch literal 40433 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 Date: Thu, 19 Dec 2024 12:06:12 +1300 Subject: [PATCH 05/10] Add switch for item packs --- .../RequestLineEdit/RequestEditPage.tsx | 7 +- .../RequestLineEdit/RequestLineEdit.tsx | 67 +++++++++++++++++++ .../DetailView/RequestLineEdit/hooks.tsx | 3 + 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestEditPage.tsx b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestEditPage.tsx index 855e30b444..11521842ef 100644 --- a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestEditPage.tsx +++ b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestEditPage.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { BasicSpinner, DetailContainer, @@ -27,6 +27,8 @@ export const RequestLineEditPage = () => { lines, currentItem ); + const isPacksEnabled = !!draft?.defaultPackSize; + const [isPacks, setIsPacks] = useState(isPacksEnabled); const enteredLineIds = lines ? lines .filter(line => line.requestedQuantity !== 0) @@ -71,6 +73,9 @@ export const RequestLineEditPage = () => { hasPrevious={hasPrevious} previous={previous} isProgram={!!data?.programName} + isPacksEnabled={isPacksEnabled} + isPacks={isPacks} + setIsPacks={setIsPacks} /> } diff --git a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx index e698fcf2c2..d9dca951e4 100644 --- a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx +++ b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx @@ -12,6 +12,7 @@ import { NumUtils, Popover, ReasonOptionNodeType, + Switch, TextArea, useAuthContext, useToggle, @@ -33,6 +34,9 @@ interface RequestLineEditProps { hasPrevious: boolean; previous: ItemRowFragment | null; isProgram: boolean; + isPacksEnabled: boolean; + isPacks: boolean; + setIsPacks: React.Dispatch>; } export const RequestLineEdit = ({ @@ -44,6 +48,9 @@ export const RequestLineEdit = ({ hasPrevious, previous, isProgram, + isPacksEnabled, + isPacks, + setIsPacks, }: RequestLineEditProps) => { const t = useTranslation(); const { isOn, toggle } = useToggle(); @@ -180,12 +187,29 @@ export const RequestLineEdit = ({ {/* Right column content */} + + {isPacksEnabled && ( + + setIsPacks(checked)} + size="small" + /> + + {t('label.packs')} + + + )} + + { if (draft?.suggestedQuantity === value) { update({ @@ -231,6 +255,49 @@ export const RequestLineEdit = ({ )} + + {isPacksEnabled && ( + { + update({ + requestedQuantity: + (quantity ?? 0) * (draft?.defaultPackSize ?? 0), + }); + }} + /> + } + labelWidth={LABEL_WIDTH} + sx={{ marginBottom: 1 }} + label={t('label.requested-packs')} + /> + )} + + {isPacksEnabled ? ( + + } + labelWidth={LABEL_WIDTH} + label={t('label.default-pack-size')} + sx={{ marginBottom: 1 }} + /> + ) : null} + & { isCreated: boolean; requisitionId: string; + defaultPackSize: number; }; const createDraftFromItem = ( @@ -44,6 +45,7 @@ const createDraftFromItem = ( additionInUnits: 0, daysOutOfStock: 0, expiringUnits: 0, + defaultPackSize: item.defaultPackSize, }; }; @@ -58,6 +60,7 @@ const createDraftFromRequestLine = ( suggestedQuantity: line.suggestedQuantity, isCreated: false, itemStats: line.itemStats, + defaultPackSize: line.item.defaultPackSize, }); export const useDraftRequisitionLine = ( From 56688b218459fc3760b7d2ae9893f38a07b16af0 Mon Sep 17 00:00:00 2001 From: Aimee <163234798+aimee-mcneil-melville@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:47:19 +1300 Subject: [PATCH 06/10] change to early return on scan function --- .../ListView/AddFromScannerButton.tsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx b/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx index e337fe808e..eafa725e47 100644 --- a/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx +++ b/client/packages/coldchain/src/Equipment/ListView/AddFromScannerButton.tsx @@ -114,22 +114,24 @@ export const AddFromScannerButtonComponent = () => { const handleClick = async (e: React.MouseEvent) => { const permission = UserPermission.AssetQuery; - if (userHasPermission(permission)) { - if (!isConnected) { - show(e); - return; - } - buttonRef.current?.blur(); - if (isScanning) { - stopScan(); - } else { - try { - await startScanning(handleScanResult); - } catch (e) { - error(t('error.unable-to-start-scanning', { error: e }))(); - } + if (!userHasPermission(permission)) { + info(t('error.no-asset-view-permission'))(); + return; + } + if (!isConnected) { + show(e); + return; + } + buttonRef.current?.blur(); + if (isScanning) { + stopScan(); + } else { + try { + await startScanning(handleScanResult); + } catch (e) { + error(t('error.unable-to-start-scanning', { error: e }))(); } - } else info(t('error.no-asset-view-permission'))(); + } }; // stop scanning when the component unloads From f9a4525bbd64435f1b073f6c0d470bfeb48b6b3f Mon Sep 17 00:00:00 2001 From: Aimee <163234798+aimee-mcneil-melville@users.noreply.github.com> Date: Fri, 20 Dec 2024 10:30:04 +1300 Subject: [PATCH 07/10] fix show dialog --- .../coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx b/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx index 42a2916164..d2f59b07e5 100644 --- a/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx +++ b/client/packages/coldchain/src/Equipment/DetailView/UpdateStatusButton.tsx @@ -54,7 +54,7 @@ export const UpdateStatusButtonComponent = ({ const onUpdateStatus = () => { if (userHasPermission(permission)) { - showDialog; + showDialog(); } else info(t('error.no-asset-edit-permission'))(); }; From 2db76c8dab0336695aeb72d81021c8dd912bba91 Mon Sep 17 00:00:00 2001 From: Fergus Roache <90807420+fergie-nz@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:46:44 +1300 Subject: [PATCH 08/10] Update client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx Co-authored-by: roxy-dao --- .../DetailView/RequestLineEdit/RequestLineEdit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx index d9dca951e4..a19a964dfd 100644 --- a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx +++ b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx @@ -36,7 +36,7 @@ interface RequestLineEditProps { isProgram: boolean; isPacksEnabled: boolean; isPacks: boolean; - setIsPacks: React.Dispatch>; + setIsPacks: (isPacks: boolean) => void; } export const RequestLineEdit = ({ From 6ba6d0bcd54210819b35a474cda0704783835a6c Mon Sep 17 00:00:00 2001 From: Fergus Roache <90807420+fergie-nz@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:46:55 +1300 Subject: [PATCH 09/10] Update client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx Co-authored-by: roxy-dao --- .../DetailView/RequestLineEdit/RequestLineEdit.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx index a19a964dfd..4a53d2b6db 100644 --- a/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx +++ b/client/packages/requisitions/src/RequestRequisition/DetailView/RequestLineEdit/RequestLineEdit.tsx @@ -187,9 +187,15 @@ export const RequestLineEdit = ({ {/* Right column content */} - + {isPacksEnabled && ( - + Date: Fri, 20 Dec 2024 14:00:49 +1300 Subject: [PATCH 10/10] update translations --- .../common/src/intl/locales/en/common.json | 2 +- .../common/src/intl/locales/fr/common.json | 350 +++++++++--------- .../utils/ColumnDefinitionSetBuilder.ts | 4 +- .../modals/InboundLineEdit/TabTables.tsx | 2 - .../DetailView/OutboundLineEdit/columns.ts | 2 +- .../Prescription/StockLineTable.tsx | 2 +- .../programs/src/icons/Contraceptive.tsx | 4 +- client/packages/programs/src/icons/Liver.tsx | 4 +- .../programs/src/icons/LungsVirus.tsx | 4 +- .../programs/src/icons/MedicalBag.tsx | 4 +- .../packages/programs/src/icons/Referrals.tsx | 4 +- .../packages/programs/src/icons/_gradient.tsx | 4 +- .../src/Item/DetailView/Tabs/ItemLedger.tsx | 1 - .../InventoryAdjustmentModal.tsx | 2 +- .../src/Stock/Components/StockLineForm.tsx | 2 +- .../system/src/Stock/ListView/ListView.tsx | 4 +- 16 files changed, 197 insertions(+), 198 deletions(-) diff --git a/client/packages/common/src/intl/locales/en/common.json b/client/packages/common/src/intl/locales/en/common.json index 4d9451b3d8..823088d40e 100644 --- a/client/packages/common/src/intl/locales/en/common.json +++ b/client/packages/common/src/intl/locales/en/common.json @@ -859,7 +859,7 @@ "label.not-set": "Not set", "label.note": "Note", "label.notes": "Notes", - "label.num-packs": "Pack Qty", + "label.num-packs": "Number of packs", "label.number": "Number", "label.number-months_few": "{{count}} Months", "label.number-months_many": "{{count}} Months", diff --git a/client/packages/common/src/intl/locales/fr/common.json b/client/packages/common/src/intl/locales/fr/common.json index bc4c7b4619..faa7375242 100644 --- a/client/packages/common/src/intl/locales/fr/common.json +++ b/client/packages/common/src/intl/locales/fr/common.json @@ -41,6 +41,7 @@ "button.create": "Créer", "button.create-a-new-one": "Créer un nouveau", "button.create-log-reason": "Créer un motif d'entrée", + "button.create-new": "Créer un élément", "button.create-shipment": "Créer une livraison", "button.dashboard": "Tableau de bord", "button.delete": "Supprimer", @@ -49,6 +50,7 @@ "button.edit": "Modifier", "button.edit-linked-patient": "Modifier le patient associé", "button.export": "Exporter", + "button.hiv": "VIH", "button.import": "Importer", "button.import-fridge-tag": "Importer Fridge-tag", "button.import-properties": "Propriétés d'importation", @@ -64,19 +66,24 @@ "button.new-outbound-shipment": "Nouvelle Livraison Sortante", "button.new-patient": "Nouveau patient", "button.new-prescription": "Nouvelle prescription", + "button.new-requisition": "Nouvelle Réquisition", "button.new-return": "Nouveau retour", "button.new-shipment": "Nouvelle livraison", "button.new-stock": "Ajouter du stock", + "button.next": "Suivant", "button.next-step": "Étape suivante", "button.ok": "OK", "button.ok-and-next": "OK & Suivant", "button.open-the-menu": "Ouvrir le menu", "button.order-more": "Nouvelle commande", + "button.previous": "Précédent", "button.print": "Imprimer", "button.reduce-lines-to-zero": "Réduire les lignes à 0", "button.refresh": "Rafraîchir", + "button.regimen": "Régime", "button.remove-file": "Supprimer le fichier", "button.repack": "Reconditionnement", + "button.replenishment-return-lines": "Retourner les Lignes Sélectionnées", "button.requested-to-suggested": "Utiliser Quantités Suggérées", "button.retry": "Réessayer", "button.return-lines": "Créer un retour pour les lignes sélectionnées", @@ -85,6 +92,7 @@ "button.save-log": "Enregistrer le journal", "button.scan": "Scanner", "button.select-a-color": "Sélectionner une couleur", + "button.send": "Envoyer", "button.stop": "Stop", "button.supply-to-approved": "Fournir Qtés Autorisées", "button.supply-to-requested": "Quantité demandée", @@ -92,10 +100,13 @@ "button.test": "Test", "button.try-again": "Essayez à nouveau", "button.unlink-patient": "Dissocier le patient", + "button.update-status": "Mettre à jour le statut", "button.upload-assets": "Importer", "button.view": "Afficher", "button.view-all-breaches": "Voir toutes les anomalies", "button.view-details": "Vue détaillée", + "button.view-patient": "Voir Patient", + "button.view-prescription": "Consulter la prescription", "button.zero-line-quantity": "Mettre les quantités à 0", "catalogue": "Catalogue", "cmdk.drawer-toggle": "Menu à bascule", @@ -138,8 +149,11 @@ "customers": "Clients", "dashboard": "Tableau de bord", "description.already-issued": "Quantité déjà émise.", + "description.available-stock": "Stock initial du client + stock entrant +/- ajustements d'inventaire - stock sortant", "description.average-monthly-consumption": "Consommation mensuelle moyenne", "description.breach-type": "Type d'excursion en cours", + "description.bundle-ratio": "Le nombre d'unités de l'article groupé pour chaque unité de l'article de base", + "description.bundled-item-ratio": "Le nombre d'unités de l'article de base pour chaque unité de cet article", "description.counted-num-of-packs": "Stock Physique (boites)", "description.customer-reference": "Ref. Client", "description.customer-soh": "Stock client", @@ -150,6 +164,7 @@ "description.fc-line-total": "Total ligne en devise étrangère", "description.fc-sell-price": "Prix de vente en devise étrangère par conditionnement", "description.forecast-quantity": "Quantité prévue pour atteindre la cible", + "description.initial-stock-on-hand": "Stock disponible au premier jour de la période du programme", "description.invoice-number": "Numéro d'expédition", "description.last-reading-datetime": "Date et heure du dernier relevé", "description.max-min-temperature": "Relevé de temperature maximum ou minimum", @@ -161,13 +176,17 @@ "description.program": "Les bons de commande \"programme\" sont utilisés pour gérer des groupes d'articles et des calendriers de commande.", "description.remaining-to-supply": "La quantité restante à livrer, c'est à dire la quantité demandée moins la quantité déjà livrée pour cet article sur les livraisons sortantes associées", "description.requested-quantity": "Quantité d'unités demandée par le client", + "description.rnr-adjustments": "Ajustements effectués pour cet article durant cette période (via les prises d'inventaire ou ajustements d'inventaire)", "description.rnr-amc": "La Consommation Mensuelle Moyenne est calculée en utilisant la Valeur de Consommation Ajustée, ce formulaire rapport-réquisition et les deux CMM précédentes, si disponibles", "description.rnr-approved-quantity": "La quantité à commander ayant été approuvée. Cette donnée est alimentée après finalisation et autorisation du formulaire R&R.", "description.rnr-consumed": "La quantité d'articles distribuée durant cette période (par Bons de Livraison ou Prescriptions)", "description.rnr-consumed-adjusted": "Montre la consommation ajustée prenant en compte les jours de rupture =(Consommation x 30)/(30 - Durée cumulée des ruptures)", "description.rnr-final-balance": "Niveau de stock à la fin de la période = Solde Initial + Q reçue - Q consommée ± Ajustements", + "description.rnr-initial-balance": "Stock disponible au début de la période. Cela est pris à partir du formulaire rapport-réquisition précédent, si disponible, ou calculé en utilisant le stock disponible à la date de début de la période.", + "description.rnr-losses": "Enregistrer manuellement les pertes de cet article durant la période", "description.rnr-low-stock": "! = Le sold final est inférieur à la moitié du maximum, !! = moins d'un quart (25%)", "description.rnr-maximum-quantity": "La quantité cible de stock disponible. = CMM x Préférence du dépôt 'Seuil pour l'excès de stock'", + "description.rnr-minimum-quantity": "La quantité minimale de stock disponible à maintenir. = CMM x Préférence du dépôt 'Seuil de sous-stock'", "description.rnr-received": "La quantité de produits reçue durant cette période (par Bons de Réception)", "description.rnr-requested-quantity": "La quantité à commander. = Quantité Maximum - Solde Final", "description.snapshot-num-of-packs": "Nombre de boites en stock avant selon mSupply (stock théorique)", @@ -196,6 +215,8 @@ "error.batch-is-reserved": "Le lot est déjà réservé/émis", "error.cannot-add-pack-size-of-zero": "Impossible d'ajouter une variante avec un conditionnement égal à zéro", "error.cannot-add-with-no-abbreviation-and-name": "Impossible d'ajouter une variante sans abréviation ni nom", + "error.cannot-backdate-prescription": "Le stock n'est pas disponible à la date spécifiée", + "error.cannot-edit-requisition": "La réquisition n'est pas modifiable.", "error.cant-save": "Problème rencontré lors de la sauvegarde.", "error.cce-asset-number-already-used": "Numéro d'actif ECF déjà utilisé", "error.code-no-match": "{{field}} non trouvé dans le catalogue", @@ -210,7 +231,9 @@ "error.date_invalidDate": "La date est invalide", "error.date_maxDate": "La date est trop élevée", "error.date_minDate": "La date est trop basse", + "error.dose-ages-out-of-order": "Chaque dose nécessite un âge minimum plus élevé que la dose précédente", "error.duplicate-asset-number": "Numéro d'actif déjà existant", + "error.duplicate-item-variant-name": "Une variante avec ce nom existe déjà pour cet article", "error.duplicated-field": "{{field}} existe déjà dans le fichier d'import", "error.encounter-not-created": "Impossible de créer une rencontre", "error.encounter-not-found": "Rencontre non trouvée.", @@ -219,9 +242,14 @@ "error.failed-to-create-prescription": "Impossible de créer une prescription !", "error.failed-to-create-requisition": "Impossible de créer le bon de commande {{message}}", "error.failed-to-create-return": "Impossible de créer un retour !", + "error.failed-to-delete-bundled-item": "Échec de la suppression de l'article groupé", + "error.failed-to-delete-item-variant": "Échec de la suppression de la variante de l'article", "error.failed-to-generate-excel": "Impossible de générer le fichier Excel", "error.failed-to-generate-report": "Impossible de générer le rapport", + "error.failed-to-save-bundled-item": "Échec de la suppression de l'élément groupé", + "error.failed-to-save-item-variant": "Échec de l'enregistrement de la variante d'article", "error.failed-to-save-service-charges": "Échec lors de la sauvegardes des frais de service", + "error.failed-to-save-vaccination": "Échec de la sauvegarde de la vaccination !", "error.failed-to-save-vaccine-course": "La sauvegarde du schéma de vaccination a échoué", "error.fetch-notifications": "Impossible d'afficher les notifications de la chaîne du froid", "error.field-must-be-specified": "{{field}} doit être spécifié", @@ -245,15 +273,22 @@ "error.master-list-not-found": "Liste maîtresse introuvable", "error.missing-central-sync": "Impossible d'accéder au serveur central mSupply", "error.missing-inputs": "{{count}}", + "error.more-info": "Plus d'informations", "error.name-program-duplicate": "Le nom du schéma de vaccination existe déjà pour ce programme", "error.no-asset-create-permission": "Vous n'avez pas les autorisations pour créer un nouvel actif.", + "error.no-customer-return-items": "Aucun article n'a été ajouté à ce retour.", + "error.no-customer-returns": "Aucun Retour Client à afficher.", "error.no-data": "Aucune donnée disponible", "error.no-immunisation-programs": "Programme de vaccination introuvable", "error.no-inbound-items": "Aucun article n'a été ajouté à cette livraison.", "error.no-inbound-shipments": "Il n'y pas de bon de livraison à afficher.", + "error.no-indicators": "Il n'y a pas d'indicateurs pour cette réquisition", "error.no-internal-orders": "Il n'y a pas de commande interne à afficher.", + "error.no-items": "Aucun article", "error.no-items-filter-on": "Aucun élément à afficher. Essayez de modifier les critères de filtrage.", + "error.no-items-to-display": "Aucun article à afficher.", "error.no-locations": "Il n'y a pas d'emplacement à afficher.", + "error.no-master-list": "Cet article n'est pas attribué à une liste maîtresse, veuillez contacter votre administrateur si cela est une erreur. Notez qu'un article peut être visible s'il y a du stock disponible, même s'il ne figure pas sur une liste maîtresse.", "error.no-master-lists": "Aucune liste maîtresse à afficher.", "error.no-matching-asset": "Actif ECF introuvable avec le numéro d'identification {{id}}", "error.no-matching-item": "Aucun article correspondant", @@ -276,9 +311,16 @@ "error.no-stock": "Il n'y a pas de stock à afficher.", "error.no-stocktake-items": "Aucun article n'a été ajouté à cet inventaire.", "error.no-stocktakes": "Il n'y a pas d'inventaire à afficher.", + "error.no-supplier-returns": "Aucun Retour Fournisseur à afficher.", "error.no-temperature-breaches": "Aucune excursion de température trouvée", "error.no-temperature-logs": "Aucune entrée de température trouvée", "error.not-editable": "L'inventaire ne peut être modifié.", + "error.not-most-recent-given-dose": "Ceci n'est pas la vaccination la plus récente. Veuillez modifier la vaccination la plus récente si une dose n'a pas été administrée.", + "error.order-not-found": "Commande Interne non trouvée", + "error.ordering-too-many-items_one": "Vous ne pouvez pas finaliser une commande d'urgence avec plus de {{ count }} articles. Réduisez le nombre d'articles et réessayez.", + "error.ordering-too-many-items_other": "Vous ne pouvez pas finaliser une commande d'urgence avec plus de {{ count }} articles. Réduisez le nombre d'articles et réessayez.", + "error.other-party-not-a-supplier": "L'autre partie n'est pas un fournisseur", + "error.other-party-not-visible": "Autre partie non visible dans ce magasin", "error.pack-variant-exists": "Une variante de conditionnement avec la même taille de conditionnement existe déjà pour l'article", "error.plugin": "Une erreur est survenue en chargeant le plugin {{name}}", "error.plugin-unavailable": "Plugin non disponible", @@ -287,6 +329,7 @@ "error.program-already-exists": "Le Programme de Vaccination existe déjà", "error.provide-reason": "Une raison doit être renseignée pour toutes les lignes où un écart a été constaté.", "error.provide-valid-reason": "La raison de l'ajustement de stock ne correspond pas à la direction de l'ajustement (positif ou négatif)", + "error.reasons-not-provided-program-requisition": "Les raisons doivent être fournies lorsque la quantité suggérée diffère de la quantité demandée.", "error.record-already-exists": "Un enregistrement avec cet identifiant existe déjà", "error.reduced-below-zero": "Une ligne de stock est allouée dans une nouvelle livraison sortante. La quantité ne peut pas être en dessous de zéro.", "error.repack-cannot-be-fractional": "Impossible de reconditionner dans un conditionnement fractionnaire", @@ -305,11 +348,13 @@ "error.site-incorrect-password": "Mot de passe incorrect", "error.site-mismatch": "Inadéquation des sites", "error.site-name-not-found": "Le nom du site est introuvable", + "error.snapshot-total-mismatch": "La quantité de stock est maintenant différente de celle au début de l'inventaire, car une partie du stock a été émise dans des livraisons sortantes ou des prescriptions. Veuillez supprimer la ligne et réessayer.", "error.soh-and-suggested-quantity-are-zero": "Pas de valeurs de Stocks Disponibles ou de Quantités Suggérées", "error.something-wrong": "Oups ! Une erreur s'est produite.", "error.stock-line-stock-reduced-below-zero": "Cette ligne de stock ne peut être ajustée car un partie du stock est allouée à de nouveaux Bons de Livraison.", "error.stocktake-has-stock-reduced-below-zero": "L'inventaire ne peut pas être finalisé car une partie du stock est utilisé dans une nouvelle livraison sortante.", "error.stocktake-not-found": "Inventaire introuvable", + "error.stocktake-snapshot-total-mismatch": "L'inventaire ne peut pas être finalisé. La quantité de stock est maintenant différente de celle au début de l'inventaire, car une partie du stock a été émise dans des livraisons sortantes ou des prescriptions. Veuillez supprimer la ligne et réessayer.", "error.sync-api-incompatible": "La version de l'API de Synchronisation n'est pas compatible", "error.sync-api-incompatible-hint": "Le serveur central mSupply doit être mis à jour vers une version plus récente avant que vous puissiez vous connecter - veuillez contacter support@msupply.foundation", "error.sync-v6-api-incompatible": "La version V6 de l'API de synchronisation n'est pas compatible", @@ -343,8 +388,10 @@ "error.v6-server-not-configured": "Serveur central V6 non configuré", "error.v6-server-not-configured-hint": "Vérifier l'URL du serveur central", "error.vaccine-course-update-failed": "Echec de la sauvegarde du calendrier de vaccination", + "error.value-type-not-correct": "Le type de valeur n'est pas correct", "facilities": "Sites", "filename.asset-categories": "Catégories d'équipement", + "filename.asset-import-example": "Exemple Importation d'équipements", "filename.cce": "Modèle de téléchargement des équipements", "filename.cce-failed-uploads": "Le téléchargement des actifs a échoué", "filename.cold-chain-equipment": "Equipement de la chaine du froid", @@ -383,6 +430,8 @@ "heading.configuration": "Configuration", "heading.confirm-finalise": "Êtes vous sûr(e) de vouloir finaliser ?", "heading.consumption-history": "Historique des consommations (par mois)", + "heading.contact-us": "Nous contacter", + "heading.create-new-asset": "Créer un nouvel équipement", "heading.create-outbound-shipment": "Créer une livraison sortante", "heading.create-vaccine-course": "Créer un calendrier vaccinal", "heading.custom": "Personnalisation", @@ -412,7 +461,9 @@ "heading.logout-confirm": "Êtes vous sûr(e) ?", "heading.notification-preferences": "Préférences de notification", "heading.order": "Commande", + "heading.order-info": "Info commande", "heading.password": "Mot de passe", + "heading.program-info": "info programme", "heading.rate": "Taux", "heading.reference": "Référence", "heading.related-documents": "Documents connexes", @@ -445,8 +496,10 @@ "heading.transport-details": "Détails transport", "heading.unable-to-print": "Impossible d'imprimer", "heading.upload-cce-documents": "Télécharger les documents des actifs du froid", + "heading.user-guide": "Guide de l'utilisateur", "heading.user-sync": "Statut de synchronisation de l'utilisateur", "heading.username": "Nom d'utilisateur", + "help": "Aide", "immunisations": "Vaccinations", "inbound-shipment": "Bons de livraison", "indicators-demographics": "Données démographiques", @@ -464,6 +517,7 @@ "internal-order": "Bons de commande", "inventory": "Gestion de stock", "inventory-addition": "Ajout de stock", + "inventory-adjustment": "Ajustement d'inventaire", "inventory-management": "Gestion de stock", "inventory-reduction": "Réduction de stock", "items": "Articles", @@ -472,13 +526,18 @@ "label.actions": "Actions", "label.add-another": "Ajouter un autre", "label.add-batch": "Ajouter le lot", + "label.add-bundled-item": "Ajouter un article groupé", + "label.add-charge": "Ajouter des frais", "label.add-charges": "Ajouter frais", "label.add-new-line": "Ajouter une ligne", "label.add-new-vaccine-course": "Ajouter un calendrier de vaccination", + "label.add-variant": "Ajouter une variante", "label.additional-info": "Informations additionnelles", + "label.additions": "Ajouts", "label.address": "Adresse", "label.adjust": "Ajuster", "label.adjust-by": "par", + "label.adjusted": "Ajusté(e)", "label.age": "Âge", "label.age-days_one": "{{count}} jour(s)", "label.age-days_other": "{{count}} jours", @@ -486,10 +545,12 @@ "label.age-months-and_other": "{{count}} mois, ", "label.age-months-count_one": "{{count}} mois", "label.age-months-count_other": "{{count}} mois", - "label.other-requested-quantity": "Autres", + "label.age-years_one": "{{count}} année", + "label.age-years_other": "{{count}} années", "label.allocated": "Alloué(e)", "label.already-issued": "Livrés", "label.amc": "CMM", + "label.amc/amd": "CMM/DMD", "label.amount": "Montant", "label.any": "Tous", "label.api-version": "Version API:", @@ -502,6 +563,8 @@ "label.asset-properties": "Propriétés de l'actif", "label.atc-category": "Catégorie ATC", "label.auth-status": "Statut Autorisation", + "label.available": "Disponible", + "label.available-batches": "Lot(s) disponible(s)", "label.available-packs": "Stock Dispo (boites)", "label.available-quantity": "Quantité disponible : {{number}} unités", "label.available-quantity-for-return": "Quantité disponible pour le retour", @@ -533,13 +596,15 @@ "label.clear-filter": "Effacer le filtre", "label.clear-selection": "Effacer la sélection", "label.click-to-sort": "Cliquez pour trier par ", + "label.click-to-view": "Cliquez pour voir les détails", "label.client": "Client", - "label.clinician": "Médecin", + "label.clinician": "Praticien(ne)", "label.code": "Code", "label.code-or-name": "Code ou nom", "label.cold-consecutive": "Froid consécutif", "label.cold-cumulative": "Froid cumulatif", "label.cold-storage-location": "Lieu de stockage frigorifique", + "label.cold-storage-type": "Type de stockage à froid", "label.collapse": "Réduire", "label.collapse-all": "Tout réduire", "label.color": "Couleur", @@ -554,8 +619,10 @@ "label.contact-tracing-type": "Type de contact", "label.context": "Contexte", "label.cost": "Coût", + "label.cost-per-unit": "Coût par unité", "label.cost-price": "Prix d'achat", "label.count-this-line": "Ligne à inventorier", + "label.counted-num-of-packs": "Boites Comptées", "label.country": "Pays", "label.coverage-rate": "Taux de couverture", "label.create": "Créer", @@ -563,8 +630,10 @@ "label.create-log-reason": "Créer une raison", "label.create-new-program": "Créer un programme de vaccination", "label.create-pack-variant": "Créer une variante de conditionnement", + "label.create-prescription": "Créer une prescription", "label.created": "Créé(e) le", "label.created-datetime": "Date/heure de création", + "label.created-datetime-UTC": "Date/Heure de création (UTC)", "label.cumulative": "Cumulatif", "label.currency": "Devise", "label.current": "Actuel", @@ -572,16 +641,19 @@ "label.current-population": "Population actuelle", "label.current-status": "Etat actuel", "label.custom": "Personnalisé :", + "label.custom-age-label": "Étiquette d'âge personnalisée", "label.customer": "Client", "label.customer-name": "Nom du Client", "label.customer-ref": "Référence client", "label.customer-soh": "Stock client", "label.date": "Date", "label.date-created": "Date de création", + "label.date-format": "JJ/MM/AAAA", "label.date-given": "Date donnée", "label.date-of-birth": "Date de naissance", "label.date-time": "Date heure", "label.day": "jour", + "label.days-out-of-stock": "Jour(s) en rupture", "label.ddd": "Dose Quotidienne Définie", "label.deceased": "Décédé(e)", "label.decrease-qty": "Réduire Quantité", @@ -596,11 +668,13 @@ "label.difference": "Différence", "label.direction": "Direction d'ajustement", "label.directions": "Mode d'emploi", + "label.document-edit-history": "Historique de Modifications du Document", "label.documents": "Documents", "label.donor": "Donateur", "label.dose": "Dose", "label.dose-number": "Dose #", "label.doses": "Doses", + "label.doses-per-unit": "Doses par unité", "label.download-database": "Télécharger la base de données", "label.dps": "Cond.", "label.draft": "Brouillon", @@ -610,6 +684,7 @@ "label.edit-location": "Éditer un emplacement", "label.edit-pack-variant": "Editer la variante de conditionnement", "label.edit-store-properties": "Modifier les propriétés des dépôts", + "label.edit-variant": "Modifier la Variante", "label.edited-by": "Édité(e) par", "label.encounter": "Visite", "label.encounter-end": "Fin", @@ -633,6 +708,7 @@ "label.entered-on": "Créé(e) le", "label.error-message": "Message d'erreur", "label.event": "Evénement", + "label.exit": "Quitter", "label.expand": "Développer", "label.expand-all": "Tout développer", "label.expired_few": "Lots expirés", @@ -658,6 +734,7 @@ "label.from-datetime": "A partir de la date/heure", "label.from-expiry": "A partir de la date d'expiration", "label.from-start-datetime": "À partir de la date/heure de début", + "label.full-screen": "Plein écran", "label.functional-status": "Statut fonctionnel", "label.gender": "Genre", "label.general": "Général", @@ -679,8 +756,11 @@ "label.inbound-not-delivered": "Bon(s) de livraison pas encore livré(s)", "label.inbound-shipment": "Livraison entrante", "label.inbound-shipment-cant-delete-reserved-line": "Le lot {{batch}} (code article {{itemCode}})) est déjà alloué ou distribué", + "label.incoming": "Entrant(e)", "label.incoming-stock": "en transit", "label.increase-qty": "Augmenter quantité", + "label.indicators": "Indicateurs", + "label.initial-stock-on-hand": "Stock Disponible Initial", "label.initialise-store-properties": "Initialiser les propriétés des dépôts pour GAPS", "label.initialised": "Initialisé", "label.installation-date": "Date d'installation", @@ -688,6 +768,7 @@ "label.is-vaccine": "Vaccin", "label.issue": "Distribuer", "label.item": "Article", + "label.item-variant": "Variante Article", "label.item_few": "Articles", "label.item_many": "Articles", "label.item_one": "Article", @@ -718,6 +799,7 @@ "label.location": "Emplacement", "label.locked": "Verrouillé", "label.log": "Journal", + "label.losses": "Pertes", "label.low-stock": "Stock faible", "label.low-stock-items_few": "Articles avec moins de 3 mois de stock", "label.low-stock-items_many": "Articles avec mois de 3 mois de stock", @@ -737,8 +819,10 @@ "label.mode": "Mode", "label.model": "Modèle", "label.modified-datetime": "Date/heure de modification", + "label.modified-datetime-UTC": "Date /Heure de modification (UTC)", "label.monthly-consumption-look-back-period": "Historique (en mois) pour le calcul de la CMM", "label.months": "mois", + "label.months-abbreviation": "M", "label.months-of-stock": "MDS", "label.months_few": "mois", "label.months_many": "mois", @@ -757,6 +841,7 @@ "label.new-contact-trace": "Ajouter le contact", "label.new-encounter": "Nouvelle rencontre", "label.new-functional-status": "Nouvel état fonctionnel", + "label.new-internal-order": "Nouvelle Commande", "label.new-location": "Nouvel emplacement", "label.new-num-packs": "Nouvelle quantité de boites", "label.new-pack-qty": "Nouvelle quantité de boites", @@ -767,13 +852,14 @@ "label.new-rnr-form": "Nouveau Formulaire R&R", "label.new-row": "Nouvelle Ligne", "label.new-stocktake": "Nouvel Inventaire", + "label.no-reason": "Aucune raison", "label.no-unallocated-rows-selected": "Tous les lignes sélectionnées sont déjà allouées", "label.non-catalogue": "Hors catalogue", "label.not-sent": "pas encore envoyé(s)", "label.not-set": "Non défini", "label.note": "Note", "label.notes": "Notes", - "label.num-packs": "Qté (boites)", + "label.num-packs": "Quantité", "label.number": "Numéro", "label.number-months_few": "{{count}} Mois", "label.number-months_many": "{{count}} Mois", @@ -788,9 +874,14 @@ "label.order-history": "Historique des commandes", "label.order-quantity": "Qté demandée", "label.order-type": "Type de Commande", + "label.other-facility": "Autre site", + "label.other-requested-quantity": "Autres", "label.our-soh": "Notre Stock", + "label.our-stock": "Notre stock", + "label.out-of-stock": "En rupture", "label.outbound-shipment": "Livraison sortante", "label.outer-pack-size": "Conditionnement externe", + "label.outgoing": "Sortant(e)", "label.pack": "Boite", "label.pack-cost-price": "Prix d’achat (boite)", "label.pack-quantity": "Qté (boites)", @@ -816,8 +907,10 @@ "label.phone": "Téléphone", "label.picked": "Prélevé(e)", "label.placeholder": "En attente", + "label.prescription-date": "Date de prescription", "label.previous-encounters": "Rencontres précédentes", "label.pricing": "Prix", + "label.primary": "Primaire", "label.program": "Programme", "label.program-enrolment": "Inscription au programme", "label.program-enrolments": "Inscriptions programme", @@ -830,9 +923,12 @@ "label.quantity": "Quantité", "label.quantity-returned": "Quantité retournée", "label.quantity-to-return": "Quantité à retourner", + "label.ratio": "Ratio", "label.reason": "Raison", + "label.record-stock-transaction": "Enregistrer la transaction de stock pour la vaccination précédente", "label.recorded-contact-differs": "Contact enregistré : {{recordedName}}", "label.reference": "Référence", + "label.refused": "Refusé", "label.relationship": "Relation", "label.remaining-to-supply": "Quantité restante", "label.remove": "Enlever", @@ -840,12 +936,14 @@ "label.repack": "Reconditionnement", "label.replacement-date": "Remplacement dû", "label.report-filters": "Filtres du rapport", + "label.requested": "Demandé", "label.requested-number-packs": "Qté de boites demandées", "label.requested-packs": "Qté de boites demandées", "label.requested-quantity": "Qté demandée", "label.requisition": "Réquisition", "label.requisition-general": "Général", "label.requisition-program": "Bon de commande", + "label.revert-existing-transaction": "Inverser une transaction de stock existante", "label.review": "Revue", "label.rnr-adjustments": "Ajustements", "label.rnr-consumed": "Consommation", @@ -861,8 +959,10 @@ "label.save-log": "Sauvegarder le journal dans le fichier", "label.schedule": "Calendrier", "label.search-results": "Résultats de recherche", + "label.secondary": "Secondaire", "label.select": "Sélectionner", "label.select-all": "Tout sélectionner", + "label.select-batch": "Sélectionner le lot", "label.select-quantity": "Sélectionner la quantité", "label.select-rows-to-allocate-them": "Sélectionner les lignes pour les allouer", "label.selected": "Sélectionné", @@ -880,8 +980,10 @@ "label.settings-url": "URL Serveur central", "label.settings-username": "Nom du Site", "label.shipment": "Bon de livraison", + "label.shipment-created": "Livraison créée", "label.shipments": "Envois", "label.shipped": "Expédié(e)", + "label.short-expiry": "Courte Péremption", "label.showing": "Affiche", "label.site": "Site :", "label.snapshot-num-of-packs": "Stock théorique (boites)", @@ -889,13 +991,18 @@ "label.start-datetime": "Date/heure de début", "label.status": "Statut", "label.status-given": "Donné", + "label.status-late": "En retard", + "label.status-not-given": "Non administré(e)", + "label.status-pending": "En attente", "label.statushistory": "Historique du statut", "label.stock-level": "Niveau de stock", "label.stock-on-hand": "Stock disponible", + "label.stock-on-hand-remaining": "Stock Disponible (Est. restant)", "label.stock-on-order": "en commande", "label.stocktake-comment": "Commentaire", "label.stocktake-date": "Date d'inventaire", "label.stocktake-frequency": "Fréquence des inventaires", + "label.storage-type": "Type de stockage", "label.store": "Dépôt", "label.strength": "Force", "label.sub-catalogue": "Sous-catalogue", @@ -907,12 +1014,14 @@ "label.supplier": "Fournisseur", "label.supplier-name": "Nom du fournisseur", "label.supplier-ref": "Référence", + "label.supply": "Fournir", "label.supply-quantity": "Quantité à fournir", "label.systolic": "Systolique", "label.target-demographic": "Cible démographique", "label.target-stock": "Quantité cible", "label.tax": "Taxe", "label.temperature": "Température", + "label.tertiary": "Tertiaire", "label.this-week": "Cette Semaine", "label.threshold-for-overstock": "Seuil pour l'excès de stock", "label.threshold-for-understock": "Seuil pour le sous-stock", @@ -952,14 +1061,23 @@ "label.units-plural_other": "unités", "label.universal-code": "Code universel", "label.universal-name": "Nom universel", + "label.update-transactions": "Mettre à jour les transactions de stock", "label.upload": "Chargement", "label.upload-files": "Télécharger les fichiers", "label.use-catalogue": "Utilisez le catalogue des actifs", "label.user": "Utilisateur", + "label.user-guide": "Voir la version en ligne (nécessite une connexion internet)", + "label.vaccination": "Vaccination", "label.vaccination-card": "Carte de Vaccination", "label.vaccination-cards": "Cartes de Vaccination", + "label.vaccinations": "Vaccinations", "label.vaccine-courses": "Calendriers de Vaccination", + "label.vaccine-given": "Vaccin administré", + "label.vaccine-item": "Article de vaccin", "label.vaccine-items": "Articles de vaccination", + "label.vaccine-not-given": "Vaccin non-administré", + "label.variant": "Variante", + "label.variants": "Variantes", "label.ven": "VEN", "label.verified": "Vérifié(e)", "label.visit-date": "Date de la visite", @@ -968,12 +1086,15 @@ "label.visit-start": "Début", "label.volume-per-outer-pack": "Volume par emballage externe", "label.volume-per-pack": "Volume par emballage", + "label.volume-per-unit": "Volume par unité (L)", "label.warning-message": "Avertissement", "label.warranty-end-date": "Fin de Garantie", "label.warranty-start-date": "Début de Garantie", "label.wastage-rate": "Taux de déperdition", "label.website": "Site internet", "label.weight": "Poids (kg)", + "label.years-abbreviation": "A", + "label.your-email-address": "Votre adresse email", "link.copy-to-clipboard": "Copier vers le Presse-papier", "loading": "Chargement…", "locations": "Emplacements", @@ -1016,6 +1137,7 @@ "logout": "Se déconnecter", "manage": "Gestion", "master-lists": "Listes Maîtresses", + "message.add-a-dose": "Aucune dose configurée pour le moment. Cliquez sur le bouton '+ Dose' pour ajouter une dose.", "message.all-lines-have-been-fulfilled": "Toutes les lignes de cette réquisition avec une quantité fournie ont déjà une ligne de livraison correspondante.", "message.all-lines-have-no-supply-quantity": "Aucune quantité à fournir n'a été spécifiée pour toutes les lignes de commande non satisfaites. Merci de bien vouloir entrer une quantité à fournir pour au moins une ligne.", "message.already-saving": "Sauvegarde déjà en cours...", @@ -1026,6 +1148,7 @@ "message.copy-success": "Copié dans le presse-papiers avec succès", "message.database-not-local": "La base de données est basée sur un serveur et ne peut donc pas être téléchargée ici.", "message.database-not-sqlite": "Le téléchargement des bases de données n'est disponible que pour les bases de données SQLite", + "message.failed-to-create-requisition": "Échec de la création de la réquisition !", "message.no-supplier": "Ajustement de stock", "message.nothing-to-copy": "Rien à copier", "message.nothing-to-save": "Rien à sauvegarder", @@ -1051,11 +1174,19 @@ "messages.allocated-lines_other": "{{count}} lignes allouées", "messages.asset-saved": "Actif sauvegardé 🥳", "messages.breach-ongoing": "Cette anomalie est en cours et ne peut être acceptée avant d'être terminée", + "messages.bundled-item-saved": "Article groupé sauvegardé avec succès", "messages.by-user": "par {{username}}", + "messages.cannot-bundle": "Vous ne pouvez pas regrouper d'autres variantes d'articles avec celle-ci, cette variante est déjà regroupée avec d'autres articles", + "messages.cannot-delete-finalised-requisition": "Il est impossible de supprimer une réquisition finalisée", "messages.cannot-delete-multiple-lines": "Une ou plusieurs lignes ne peuvent pas être supprimées", + "messages.cannot-delete-requisition-with-shipment": "Impossible de supprimer une réquisition liée à une livraison", + "messages.cannot-delete-transfer-requisition": "Impossible de supprimer une réquisition de transfert", + "messages.cannot-view-vaccine-card": "Vous ne pouvez pas consulter la Carte de Vaccination de ce patient depuis ce dépôt, car il a été inscrit au {{ programName }} par un autre dépôt", "messages.cant-delete-generic": "Vous ne pouvez pas supprimer le ou les articles articles sélectionnés", "messages.cant-delete-requisitions": "Vous pouvez uniquement supprimer les réquisitions avec un statut 'Brouillon'", + "messages.cant-download-android": "Le fichier ne peut pas être téléchargé sur cet appareil", "messages.cant-return-shipment": "Impossible de procéder au retour des lignes tant que le statut n'est pas \"Expédié(e)\"", + "messages.cant-return-shipment-replenishment": "Les lignes ne peuvent pas être retournées tant que le statut n'est pas 'Livré(e)'", "messages.cant-send-order": "Impossible d'envoyer le bon de commande car is n y pas de lignes", "messages.catalogue-property": "Cette propriété est définie dans le catalogue", "messages.cce-created": "ECF créé avec succès", @@ -1069,6 +1200,7 @@ "messages.click-to-return": "Impossible de trouver un inventaire avec ce numéro. Cliquez sur OK pour retourner à la liste des inventaires", "messages.click-to-return-to-assets": "Impossible de trouver un équipement de chaîne du froid avec cet identifiant. Cliquez sur OK pour revenir à la liste des équipements", "messages.click-to-return-to-contact-traces": "Impossible de trouver une trace de contact avec cet identifiant. Cliquez sur OK pour revenir à la liste des traces de contact", + "messages.click-to-return-to-customer-returns": "Impossible de trouver un retour avec ce numéro d'identification. Cliquez sur OK pour revenir à la liste des retours clients", "messages.click-to-return-to-encounters": "Impossible de trouver une rencontre avec cet identifiant. Cliquez sur OK pour revenir à la liste des rencontres", "messages.click-to-return-to-item-list": "Impossible de trouver un article avec ce code. Cliquez sur OK pour revenir à la liste des articles.", "messages.click-to-return-to-master-lists": "Impossible de trouver la liste maîtresse recherchée. Cliquez sur OK pour revenir à la liste des listes maîtres", @@ -1084,6 +1216,8 @@ "messages.confirm-changing-from-new": "Note : changer le statut va supprimer les lignes avec zéro quantité.", "messages.confirm-delete-assets_one": "Cela supprimera définitivement cet actif.", "messages.confirm-delete-assets_other": "Cela supprimera définitivement les {{count}} actifs sélectionnés.", + "messages.confirm-delete-bundled-item": "Cette opération va supprimer cet élément du groupe", + "messages.confirm-delete-customer-return": "Cela supprimera définitivement le retour client n°{{number}}", "messages.confirm-delete-document": "Cela supprimera ce document.", "messages.confirm-delete-generic": "Cela supprimera définitivement les données", "messages.confirm-delete-immunisation-programs_one": "Cela supprimera définitivement ce programme de vaccination.", @@ -1092,6 +1226,7 @@ "messages.confirm-delete-invoice-lines_many": "Cela supprimera définitivement {{count}} lignes de cette transaction", "messages.confirm-delete-invoice-lines_one": "Cela supprimera définitivement 1 ligne de cette transaction", "messages.confirm-delete-invoice-lines_other": "Cela supprimera définitivement {{count}} lignes de cette transaction", + "messages.confirm-delete-item-variant": "Cela supprimera définitivement cette variante d'article", "messages.confirm-delete-lines_few": "Cela supprimera définitivement {{count}} lignes de cette transaction", "messages.confirm-delete-lines_many": "Cela supprimera définitivement {{count}} lignes de cette transaction", "messages.confirm-delete-lines_one": "Cela supprimera définitivement 1 ligne de cette livraison", @@ -1101,6 +1236,7 @@ "messages.confirm-delete-locations_one": "Cela supprimera définitivement 1 emplacement", "messages.confirm-delete-locations_other": "Cela supprimera définitivement {{count}} emplacements", "messages.confirm-delete-prescription": "Cela supprimera définitivement la prescription n°{{number}}", + "messages.confirm-delete-prescription-lines": "Cela supprimera définitivement toutes les lignes de cette prescription", "messages.confirm-delete-prescriptions_few": "Cela supprimera définitivement {{count}} prescriptions", "messages.confirm-delete-prescriptions_many": "Cela supprimera définitivement {{count}} prescriptions", "messages.confirm-delete-prescriptions_one": "Cela supprimera définitivement 1 prescription", @@ -1162,6 +1298,7 @@ "messages.confirm-zero-shipment-lines_other": "Cela va mettre la quantité de {{count}} lignes à 0", "messages.connected-to-printer": "Connection avec succès à l'imprimante!", "messages.could-not-save": "Sauvegarde impossible", + "messages.create-new-asset-confirmation": "L'équipement que vous avez scanné n'est pas actuellement dans le système, mais il a fourni les données GS1 appropriées. Souhaitez-vous créer un nouvel équipement avec ces données ?", "messages.create-outbound-from-requisition": "Êtes-vous sûr(e) de vouloir créer un bon de livraison pour cette commande client ?", "messages.create-stocktake-1": "Vous pouvez créer un inventaire pour les articles se trouvant dans un emplacement spécifique, pour les articles en stock actuellement, ou pour les articles périmant avant une date spécifique,", "messages.create-stocktake-2": "pour créer un inventaire manuel, cliquez sur OK pour continuer.", @@ -1170,12 +1307,14 @@ "messages.delete-this-line": "Supprimer cette ligne", "messages.deleted-assets_one": "{{count}} actif supprimé", "messages.deleted-assets_other": "{{count}} actifs supprimés", + "messages.deleted-bundled-item": "Article groupé supprimé avec succès", "messages.deleted-generic_few": "{{count}} enregistrements supprimés", "messages.deleted-generic_many": "{{count}} enregistrements supprimés", "messages.deleted-generic_one": "{{count}} enregistrement supprimé", "messages.deleted-generic_other": "{{count}} enregistrements supprimés", "messages.deleted-immunisation-programs_one": "{{count}} programme de vaccination supprimé", "messages.deleted-immunisation-programs_other": "{{count}} programmes de vaccination supprimés", + "messages.deleted-item-variant": "Variante d'article supprimée avec succès", "messages.deleted-lines_few": "{{count}} lignes supprimées", "messages.deleted-lines_many": "{{count}} lignes supprimées", "messages.deleted-lines_one": "{{count}} ligne supprimée", @@ -1184,6 +1323,10 @@ "messages.deleted-locations_many": "{{count}} emplacements supprimés", "messages.deleted-locations_one": "{{count}} emplacement supprimé", "messages.deleted-locations_other": "{{count}} emplacements supprimés", + "messages.deleted-orders_few": "{{count}} commandes supprimées", + "messages.deleted-orders_many": "{{count}} commandes supprimées", + "messages.deleted-orders_one": "{{count}} commandes supprimées", + "messages.deleted-orders_other": "{{count}} commandes supprimées", "messages.deleted-pack-variant_one": "{{count}} variantes supprimées", "messages.deleted-pack-variant_other": "{{count}} variantes supprimées", "messages.deleted-prescriptions_few": "{{count}} prescriptions supprimées", @@ -1197,6 +1340,7 @@ "messages.deleted-requisition_one": "{{count}} réquisitions supprimées", "messages.deleted-requisitions_few": "{{count}} Réquisitions client supprimées", "messages.deleted-requisitions_many": "{{count}} Réquisitions client supprimées", + "messages.deleted-requisitions_one": "{{count}} commandes supprimées", "messages.deleted-requisitions_other": "{{count}} réquisitions supprimées", "messages.deleted-returns_one": "1 retour supprimé", "messages.deleted-returns_other": "{{count}} retours supprimés", @@ -1234,6 +1378,12 @@ "messages.finalise-previous-form": "Finalisez le Formulaire R&R précédent dans le calendrier pour en créer un nouveau", "messages.finalised-stock-take": "Cet inventaire est finalisé et ne peut être modifié", "messages.fridge-tag-import-successful": "Succès ! {{numberOfLogs}} journaux et {{numberOfBreaches}} anomalies importés.", + "messages.full-screen-enabled": "Mode plein écran activé, appuyez sur ESC ou cliquez sur le bouton Quitter en haut à droite pour quitter", + "messages.how-to-read-expiring-items": "Descriptions des colonnes :\n* Expiration dans (jours) : Nombre de jours restants avant l'expiration du lot en utilisant la période d'expiration des articles.\nJaune - lots en dessous de la période d'expiration des articles.\nVert - tout ce qui est au-dessus de la période d'expiration des articles.\nRouge - articles expirés.\n* Utilisation prévue : CMM de l'article multipliée par le nombre de mois restants avant l'expiration.\n* Stock à risque : Quantité de stock qui risque d'expirer avant d'être utilisée.\nStock Disponible - Utilisation prévue. Si le stock est expiré, cela doit afficher tout le stock disponible pour cette ligne de stock.", + "messages.how-to-read-item-usage": "Descriptions des colonnes :\n* Stock en commande : Somme de la quantité dans les commandes internes moins les livraisons entrantes liées.\n* Durée de couverture en mois : Nombre de mois pendant lesquels le stock actuel devrait suffire. La valeur est \"En stock\"/\"CMM\". Notez que la CMM est calculée a partir du nombre de mois donnés par la \"période rétrospective de CMM\" visible dans la filtre du rapport. Celui-ci est configuré avec la préférence du dépôt \"Consommation Mensuelle sur la Période Rétrospective\".", + "messages.how-to-read-report": "Comment lire le rapport {{reportName}} ?", + "messages.how-to-read-stock-detail": "Ce rapport contient les mêmes informations que la page de stock, sans aucune interactivité.", + "messages.how-to-read-stock-status": "Descriptions des statuts :\n* Sous-stocké - La MDS est inférieure à la MDS minimale (préférence dépôt : seuil pour sous-stock)\n* En excès de stock - La MDS est supérieure à la MDS maximale (préférence dépôt : seuil pour excès de stock)\n* En rupture de stock - Stock disponible et CMM sont à 0.\n* En quantité suffisante - La MDS est entre la MDS minimale et maximale\n* Pas de consommation - La CMM est à 0", "messages.import-error": "L'importation de certains ou de tous les éléments a échoué. Cliquez sur Exporter pour télécharger un fichier CSV contenant les lignes qui ont provoqué une erreur. Les lignes exemptes d'erreur auront été importées", "messages.import-error-on-upload": "Erreur d'import lors du chargement. Corrigez les erreurs et réessayez", "messages.import-generic": "Import réussi", @@ -1242,12 +1392,16 @@ "messages.internal-order-created-on": "Commande interne créée le {{date}}", "messages.invalid-file": "Fichier invalider", "messages.inventory-adjustment-saved": "Ajustement de stock sauvegardé 🥳", + "messages.item-variant-saved": "Variante d'article sauvegardée avec succès", "messages.last-temperature": "Dernière mesure de température : {{temperature}} °C", + "messages.loading-report": "Chargement du rapport en cours...", "messages.location": "Emplacement :", "messages.locked-description": "Cela empêchera les changements de cet inventaire jusqu'au déverrouillage.", "messages.log-saved-successfully": "Journal sauvegardé avec succès", "messages.logout-confirm": "Cela vous déconnectera.", "messages.max-or-min-temperature": "Température Max/Min", + "messages.message-not-sent": "Erreur ! Message non envoyé", + "messages.message-sent": "Votre message a été envoyé avec succès!", "messages.must-allocate-all-lines": "Impossible de changer le statut tant que toutes les lignes n'ont pas été allouées (ou supprimées).", "messages.native-mode": "Sélectionnez le mode que vous souhaitez utiliser. Notez que vous pouvez modifier cette option ultérieurement si vous disposez d'un accès administrateur.", "messages.native-mode-client": "Ce mode permet de sélectionner le serveur auquel se connecter.", @@ -1255,10 +1409,13 @@ "messages.new-sensor": "Un nouveau capteur a été ajouté suite à l'importation de ces journaux. Souhaitez-vous attribuer un emplacement au nouveau capteur maintenant ?", "messages.no": "Non", "messages.no-available-periods": "Aucune période disponible trouvée pour le calendrier", + "messages.no-batch-selected": "Vous n'avez pas sélectionné un lot pour cette vaccination. Aucune transaction de stock ne sera créée. Êtes-vous sûr de vouloir continuer ?", + "messages.no-bundled-items": "Pas d'articles groupés configurés", "messages.no-contact-traces": "Ce patient n'a aucune trace de contact", "messages.no-data-available": "Aucune donnée disponible", "messages.no-data-found": "Aucune donnée trouvée", "messages.no-documents-uploaded": "Aucun document n'a été téléchargé", + "messages.no-item-variants": "Aucune variante d'article configurée", "messages.no-items-with-stock": "Aucun article avec du stock disponible", "messages.no-ledger": "Cette ligne de stock n'a pas de mouvement de stock à afficher", "messages.no-lines": "Impossible de changer le statut car il n'y a pas de ligne ou uniquement des lignes réservées", @@ -1278,6 +1435,8 @@ "messages.no-shipments-yet": "Aucun bon de livraison n'a encore été créé.", "messages.no-status-logs": "Aucun journal d'état n'a été créé pour cet actif. Cliquez sur le bouton « Mettre à jour le statut » pour créer un nouveau journal d'état.", "messages.no-stock-available": "Il n'y a pas de stock disponible", + "messages.no-transaction-other-facility": "Les transactions de stock ne sont pas enregistrées pour les vaccinations administrées dans d'autres sites", + "messages.no-vaccine-items-configured": "Aucun article de vaccin configuré pour ce calendrier de vaccination. Les transactions de stock ne seront pas enregistrées.", "messages.not-applicable": "N/A", "messages.not-configured": "Non configuré", "messages.not-initialised": "[ non configuré ]", @@ -1298,15 +1457,19 @@ "messages.patients-found_other": "{{count}} patients trouvés correspondant aux détails fournis", "messages.period-not-available": "Aucune période disponible", "messages.placeholder-allocated": "Il n'y a pas assez de stock disponible pour allouer la quantité demandée. Une ligne temporaire a été ajoutée pour {{placeholderQuantity}} unités.", + "messages.prescription-created": "Prescription #{{count}} créée", "messages.prescription-saved": "Prescription sauvegardée 🥳", + "messages.prescription-will-be-created": "L'ordonnance sera créée quand le formulaire sera sauvegardé", "messages.properties-download-example": "Téléchargez un fichier modèle CSV", "messages.properties-template-download-text": " avec les propriétés actuelles des sites ", + "messages.record-not-found": "Enregistrement non trouvé", "messages.recorded-on": "Enregistré le {{datetime}}", "messages.reduced-to-zero_one": "La quantité de 1 ligne a été réduite à 0", "messages.reduced-to-zero_other": "La quantité de {{ count }} lignes réduite à 0", "messages.regenerate-id-confirm": "Cela créera un nouvel identifiant et ne pourra pas être annulé.", "messages.repack-log-info": "Reconditionné depuis la ligne de stock", "messages.requested-to-suggested": "Cela définira les quantités demandées avec les quantités suggérées.", + "messages.requisition-no-stock": "Aucun stock disponible actuellement", "messages.results-found": "{{totalCount}} résultats trouvés", "messages.results-over-limit": "Affichage des {{limit}} premiers résultats uniquement - veuillez affiner votre recherche", "messages.return-saved": "Retour sauvegardé 🥳", @@ -1339,6 +1502,8 @@ "messages.upload-error": "Erreur lors du chargement du fichier {{ error }}", "messages.upload-invite": "Glisser-déplacer pour télécharger", "messages.upload-or": "ou", + "messages.vaccination-saved": "Vaccination sauvegardée 🥳", + "messages.vaccination-was-given": "Vaccination administrée le {{date}}.", "messages.vaccine-course-saved": "Calendrier de vaccination mis à jour", "messages.yes": "Oui", "messages.zero-line-quantities_few": "La quantité de {{count}} lignes a été mise à 0", @@ -1352,6 +1517,7 @@ "outbound-shipments": "Livraisons Sortantes", "patients": "Patients", "placeholder.enter-an-item-code-or-name": "Entrer le code ou le nom de l'article", + "placeholder.enter-facility-code-or-name": "Entrez le code ou le nom du site", "placeholder.enter-facility-name": "Entrer le nom du site", "placeholder.filter-by-status": "Filtrer par statut", "placeholder.filter-items": "Filtrer les articles", @@ -1361,6 +1527,7 @@ "placeholder.search-by-last-name": "Recherche par nom de famille", "placeholder.search-by-location-code": "Rechercher par code d'emplacement", "placeholder.search-by-location-name": "Rechercher par nom d'emplacement", + "placeholder.search-by-master-list-name": "Rechercher par nom de liste", "placeholder.search-by-name": "Rechercher par nom", "placeholder.search-by-name-or-code": "Recherche par nom ou par code", "placeholder.search-by-notes": "Rechercher dans les notes", @@ -1386,6 +1553,7 @@ "report.amc-12-months": "CMM (12 mois)", "report.amc-24-months": "CMM (24 mois)", "report.authorized-by": "Autorisé par", + "report.available-stock-on-hand": "Quantité de stock disponible", "report.collected-by": "Collecté par", "report.comments": "Commentaires", "report.confirm-date": "Confirmé le", @@ -1474,6 +1642,7 @@ "status.new": "Nouvel(le)", "status.not-functioning": "En panne", "status.not-in-use": "Non utilisé", + "status.unserviceable": "Hors service", "stock": "Afficher le stock", "stocktake": "Inventaire", "stocktake-comment-items-have-stock-template": "Créé(e) pour tous les articles en stock", @@ -1513,6 +1682,8 @@ "text.months": "Mois", "title.adjustment-details": "Détails de l'ajustement", "title.amc": "CMM", + "title.bundle-with": "Grouper avec", + "title.bundled-on": "Grouper sur", "title.categories": "Catégories", "title.confirm-delete-encounter": "Supprimer la visite", "title.details": "Détails", @@ -1532,176 +1703,5 @@ "warning.cannot-create-placeholder-units": "Il y a un total de {{allocatedQuantity}} unités disponibles. Impossible d'allouer toutes les {{requestedQuantity}} unités demandées.", "warning.caps-lock": "Avertissement: Verrouillage majuscule activé", "warning.field-not-parsed": "{{field}} non analysé", - "warning.nothing-to-supply": "La quantité demandée à été fournie !", - "button.new-requisition": "Nouvelle Réquisition", - "button.update-status": "Mettre à jour le statut", - "button.view-prescription": "Consulter la prescription", - "button.replenishment-return-lines": "Retourner les Lignes Sélectionnées", - "description.initial-stock-on-hand": "Stock disponible au premier jour de la période du programme", - "description.available-stock": "Stock initial du client + stock entrant +/- ajustements d'inventaire - stock sortant", - "description.rnr-adjustments": "Ajustements effectués pour cet article durant cette période (via les prises d'inventaire ou ajustements d'inventaire)", - "description.rnr-losses": "Enregistrer manuellement les pertes de cet article durant la période", - "label.additions": "Ajouts", - "label.custom-age-label": "Étiquette d'âge personnalisée", - "label.out-of-stock": "En rupture", - "label.status-late": "En retard", - "label.status-not-given": "Non administré(e)", - "messages.cannot-view-vaccine-card": "Vous ne pouvez pas consulter la Carte de Vaccination de ce patient depuis ce dépôt, car il a été inscrit au {{ programName }} par un autre dépôt", - "messages.deleted-orders_few": "{{count}} commandes supprimées", - "messages.how-to-read-expiring-items": "Descriptions des colonnes :\n* Expiration dans (jours) : Nombre de jours restants avant l'expiration du lot en utilisant la période d'expiration des articles.\nJaune - lots en dessous de la période d'expiration des articles.\nVert - tout ce qui est au-dessus de la période d'expiration des articles.\nRouge - articles expirés.\n* Utilisation prévue : CMM de l'article multipliée par le nombre de mois restants avant l'expiration.\n* Stock à risque : Quantité de stock qui risque d'expirer avant d'être utilisée.\nStock Disponible - Utilisation prévue. Si le stock est expiré, cela doit afficher tout le stock disponible pour cette ligne de stock.", - "messages.no-batch-selected": "Vous n'avez pas sélectionné un lot pour cette vaccination. Aucune transaction de stock ne sera créée. Êtes-vous sûr de vouloir continuer ?", - "messages.no-vaccine-items-configured": "Aucun article de vaccin configuré pour ce calendrier de vaccination. Les transactions de stock ne seront pas enregistrées.", - "messages.vaccination-was-given": "Vaccination administrée le {{date}}.", - "status.unserviceable": "Hors service", - "messages.deleted-item-variant": "Variante d'article supprimée avec succès", - "messages.loading-report": "Chargement du rapport en cours...", - "placeholder.search-by-master-list-name": "Rechercher par nom de liste", - "error.no-customer-return-items": "Aucun article n'a été ajouté à ce retour.", - "error.no-customer-returns": "Aucun Retour Client à afficher.", - "heading.program-info": "info programme", - "messages.how-to-read-report": "Comment lire le rapport {{reportName}} ?", - "messages.how-to-read-stock-detail": "Ce rapport contient les mêmes informations que la page de stock, sans aucune interactivité.", - "error.failed-to-save-item-variant": "Échec de l'enregistrement de la variante d'article", - "error.more-info": "Plus d'informations", - "messages.vaccination-saved": "Vaccination sauvegardée 🥳", - "label.tertiary": "Tertiaire", - "error.snapshot-total-mismatch": "La quantité de stock est maintenant différente de celle au début de l'inventaire, car une partie du stock a été émise dans des livraisons sortantes ou des prescriptions. Veuillez supprimer la ligne et réessayer.", - "filename.asset-import-example": "Exemple Importation d'équipements", - "label.no-reason": "Aucune raison", - "label.other-facility": "Autre site", - "label.update-transactions": "Mettre à jour les transactions de stock", - "description.rnr-initial-balance": "Stock disponible au début de la période. Cela est pris à partir du formulaire rapport-réquisition précédent, si disponible, ou calculé en utilisant le stock disponible à la date de début de la période.", - "label.document-edit-history": "Historique de Modifications du Document", - "label.months-abbreviation": "M", - "label.record-stock-transaction": "Enregistrer la transaction de stock pour la vaccination précédente", - "label.refused": "Refusé", - "label.vaccination": "Vaccination", - "label.vaccinations": "Vaccinations", - "label.vaccine-given": "Vaccin administré", - "label.vaccine-item": "Article de vaccin", - "label.variant": "Variante", - "label.requested": "Demandé", - "label.secondary": "Secondaire", - "messages.confirm-delete-customer-return": "Cela supprimera définitivement le retour client n°{{number}}", - "description.rnr-minimum-quantity": "La quantité minimale de stock disponible à maintenir. = CMM x Préférence du dépôt 'Seuil de sous-stock'", - "error.cannot-backdate-prescription": "Le stock n'est pas disponible à la date spécifiée", - "error.dose-ages-out-of-order": "Chaque dose nécessite un âge minimum plus élevé que la dose précédente", - "messages.deleted-orders_many": "{{count}} commandes supprimées", - "error.failed-to-save-vaccination": "Échec de la sauvegarde de la vaccination !", - "error.stocktake-snapshot-total-mismatch": "L'inventaire ne peut pas être finalisé. La quantité de stock est maintenant différente de celle au début de l'inventaire, car une partie du stock a été émise dans des livraisons sortantes ou des prescriptions. Veuillez supprimer la ligne et réessayer.", - "label.supply": "Fournir", - "label.add-variant": "Ajouter une variante", - "label.vaccine-not-given": "Vaccin non-administré", - "error.failed-to-delete-item-variant": "Échec de la suppression de la variante de l'article", - "error.duplicate-item-variant-name": "Une variante avec ce nom existe déjà pour cet article", - "error.no-items": "Aucun article", - "error.no-items-to-display": "Aucun article à afficher.", - "error.no-master-list": "Cet article n'est pas attribué à une liste maîtresse, veuillez contacter votre administrateur si cela est une erreur. Notez qu'un article peut être visible s'il y a du stock disponible, même s'il ne figure pas sur une liste maîtresse.", - "error.no-supplier-returns": "Aucun Retour Fournisseur à afficher.", - "error.not-most-recent-given-dose": "Ceci n'est pas la vaccination la plus récente. Veuillez modifier la vaccination la plus récente si une dose n'a pas été administrée.", - "error.order-not-found": "Commande Interne non trouvée", - "heading.order-info": "Info commande", - "label.add-charge": "Ajouter des frais", - "label.adjusted": "Ajusté(e)", - "label.age-years_one": "{{count}} année", - "label.age-years_other": "{{count}} années", - "label.amc/amd": "CMM/DMD", - "label.available": "Disponible", - "label.available-batches": "Lot(s) disponible(s)", - "label.cost-per-unit": "Coût par unité", - "label.counted-num-of-packs": "Boites Comptées", - "label.days-out-of-stock": "Jour(s) en rupture", - "label.doses-per-unit": "Doses par unité", - "label.edit-variant": "Modifier la Variante", - "label.exit": "Quitter", - "label.full-screen": "Plein écran", - "label.incoming": "Entrant(e)", - "label.initial-stock-on-hand": "Stock Disponible Initial", - "label.item-variant": "Variante Article", - "label.losses": "Pertes", - "label.new-internal-order": "Nouvelle Commande", - "label.outgoing": "Sortant(e)", - "label.primary": "Primaire", - "label.select-batch": "Sélectionner le lot", - "label.shipment-created": "Livraison créée", - "label.short-expiry": "Courte Péremption", - "label.status-pending": "En attente", - "label.stock-on-hand-remaining": "Stock Disponible (Est. restant)", - "label.storage-type": "Type de stockage", - "label.variants": "Variantes", - "label.volume-per-unit": "Volume par unité (L)", - "label.years-abbreviation": "A", - "message.add-a-dose": "Aucune dose configurée pour le moment. Cliquez sur le bouton '+ Dose' pour ajouter une dose.", - "message.failed-to-create-requisition": "Échec de la création de la réquisition !", - "messages.cant-return-shipment-replenishment": "Les lignes ne peuvent pas être retournées tant que le statut n'est pas 'Livré(e)'", - "messages.click-to-return-to-customer-returns": "Impossible de trouver un retour avec ce numéro d'identification. Cliquez sur OK pour revenir à la liste des retours clients", - "messages.confirm-delete-item-variant": "Cela supprimera définitivement cette variante d'article", - "messages.confirm-delete-prescription-lines": "Cela supprimera définitivement toutes les lignes de cette prescription", - "messages.deleted-orders_one": "{{count}} commandes supprimées", - "messages.deleted-orders_other": "{{count}} commandes supprimées", - "messages.deleted-requisitions_one": "{{count}} commandes supprimées", - "messages.full-screen-enabled": "Mode plein écran activé, appuyez sur ESC ou cliquez sur le bouton Quitter en haut à droite pour quitter", - "messages.how-to-read-item-usage": "Descriptions des colonnes :\n* Stock en commande : Somme de la quantité dans les commandes internes moins les livraisons entrantes liées.\n* Durée de couverture en mois : Nombre de mois pendant lesquels le stock actuel devrait suffire. La valeur est \"En stock\"/\"CMM\". Notez que la CMM est calculée a partir du nombre de mois donnés par la \"période rétrospective de CMM\" visible dans la filtre du rapport. Celui-ci est configuré avec la préférence du dépôt \"Consommation Mensuelle sur la Période Rétrospective\".", - "messages.how-to-read-stock-status": "Descriptions des statuts :\n* Sous-stocké - La MDS est inférieure à la MDS minimale (préférence dépôt : seuil pour sous-stock)\n* En excès de stock - La MDS est supérieure à la MDS maximale (préférence dépôt : seuil pour excès de stock)\n* En rupture de stock - Stock disponible et CMM sont à 0.\n* En quantité suffisante - La MDS est entre la MDS minimale et maximale\n* Pas de consommation - La CMM est à 0", - "messages.item-variant-saved": "Variante d'article sauvegardée avec succès", - "messages.no-item-variants": "Aucune variante d'article configurée", - "messages.no-transaction-other-facility": "Les transactions de stock ne sont pas enregistrées pour les vaccinations administrées dans d'autres sites", - "messages.requisition-no-stock": "Aucun stock disponible actuellement", - "placeholder.enter-facility-code-or-name": "Entrez le code ou le nom du site", - "error.failed-to-delete-bundled-item": "Échec de la suppression de l'article groupé", - "description.bundle-ratio": "Le nombre d'unités de l'article groupé pour chaque unité de l'article de base", - "description.bundled-item-ratio": "Le nombre d'unités de l'article de base pour chaque unité de cet article", - "button.create-new": "Créer un élément", - "button.view-patient": "Voir Patient", - "error.failed-to-save-bundled-item": "Échec de la suppression de l'élément groupé", - "button.next": "Suivant", - "button.previous": "Précédent", - "label.prescription-date": "Date de prescription", - "error.ordering-too-many-items_one": "Vous ne pouvez pas finaliser une commande d'urgence avec plus de {{ count }} articles. Réduisez le nombre d'articles et réessayez.", - "error.ordering-too-many-items_other": "Vous ne pouvez pas finaliser une commande d'urgence avec plus de {{ count }} articles. Réduisez le nombre d'articles et réessayez.", - "error.other-party-not-a-supplier": "L'autre partie n'est pas un fournisseur", - "error.other-party-not-visible": "Autre partie non visible dans ce magasin", - "error.cannot-edit-requisition": "La réquisition n'est pas modifiable.", - "error.value-type-not-correct": "Le type de valeur n'est pas correct", - "heading.user-guide": "Guide de l'utilisateur", - "label.date-format": "JJ/MM/AAAA", - "messages.cant-download-android": "Le fichier ne peut pas être téléchargé sur cet appareil", - "label.click-to-view": "Cliquez pour voir les détails", - "label.user-guide": "Voir la version en ligne (nécessite une connexion internet)", - "messages.cannot-bundle": "Vous ne pouvez pas regrouper d'autres variantes d'articles avec celle-ci, cette variante est déjà regroupée avec d'autres articles", - "title.bundled-on": "Grouper sur", - "messages.cannot-delete-requisition-with-shipment": "Impossible de supprimer une réquisition liée à une livraison", - "messages.record-not-found": "Enregistrement non trouvé", - "messages.cannot-delete-finalised-requisition": "Il est impossible de supprimer une réquisition finalisée", - "messages.cannot-delete-transfer-requisition": "Impossible de supprimer une réquisition de transfert", - "title.bundle-with": "Grouper avec", - "label.revert-existing-transaction": "Inverser une transaction de stock existante", - "button.hiv": "VIH", - "button.regimen": "Régime", - "error.no-indicators": "Il n'y a pas d'indicateurs pour cette réquisition", - "error.reasons-not-provided-program-requisition": "Les raisons doivent être fournies lorsque la quantité suggérée diffère de la quantité demandée.", - "help": "Aide", - "label.create-prescription": "Créer une prescription", - "label.indicators": "Indicateurs", - "label.our-stock": "Notre stock", - "label.ratio": "Ratio", - "label.cold-storage-type": "Type de stockage à froid", - "messages.bundled-item-saved": "Article groupé sauvegardé avec succès", - "messages.confirm-delete-bundled-item": "Cette opération va supprimer cet élément du groupe", - "messages.create-new-asset-confirmation": "L'équipement que vous avez scanné n'est pas actuellement dans le système, mais il a fourni les données GS1 appropriées. Souhaitez-vous créer un nouvel équipement avec ces données ?", - "messages.deleted-bundled-item": "Article groupé supprimé avec succès", - "messages.no-bundled-items": "Pas d'articles groupés configurés", - "messages.prescription-created": "Prescription #{{count}} créée", - "messages.prescription-will-be-created": "L'ordonnance sera créée quand le formulaire sera sauvegardé", - "label.add-bundled-item": "Ajouter un article groupé", - "heading.create-new-asset": "Créer un nouvel équipement", - "inventory-adjustment": "Ajustement d'inventaire", - "label.created-datetime-UTC": "Date/Heure de création (UTC)", - "label.modified-datetime-UTC": "Date /Heure de modification (UTC)", - "label.your-email-address": "Votre adresse email", - "report.available-stock-on-hand": "Quantité de stock disponible", - "messages.message-not-sent": "Erreur ! Message non envoyé", - "messages.message-sent": "Votre message a été envoyé avec succès!", - "button.send": "Envoyer", - "heading.contact-us": "Nous contacter" + "warning.nothing-to-supply": "La quantité demandée à été fournie !" } diff --git a/client/packages/common/src/ui/layout/tables/utils/ColumnDefinitionSetBuilder.ts b/client/packages/common/src/ui/layout/tables/utils/ColumnDefinitionSetBuilder.ts index b13847c686..70cd3768e5 100644 --- a/client/packages/common/src/ui/layout/tables/utils/ColumnDefinitionSetBuilder.ts +++ b/client/packages/common/src/ui/layout/tables/utils/ColumnDefinitionSetBuilder.ts @@ -75,7 +75,7 @@ const getColumnLookup = (): Record< format: ColumnFormat.Integer, align: ColumnAlign.Right, description: 'description.pack-quantity', - label: 'label.num-packs', + label: 'label.pack-quantity', width: 100, Cell: NumberCell, }, @@ -191,7 +191,7 @@ const getColumnLookup = (): Record< }, quantity: { description: 'description.pack-quantity', - label: 'label.num-packs', + label: 'label.pack-quantity', key: 'quantity', width: 100, align: ColumnAlign.Right, diff --git a/client/packages/invoices/src/InboundShipment/DetailView/modals/InboundLineEdit/TabTables.tsx b/client/packages/invoices/src/InboundShipment/DetailView/modals/InboundLineEdit/TabTables.tsx index f5ce950c44..0e559200bf 100644 --- a/client/packages/invoices/src/InboundShipment/DetailView/modals/InboundLineEdit/TabTables.tsx +++ b/client/packages/invoices/src/InboundShipment/DetailView/modals/InboundLineEdit/TabTables.tsx @@ -114,7 +114,6 @@ export const QuantityTableComponent: FC = ({ { Cell: NumberOfPacksCell, width: 100, - label: 'label.num-packs', setter: updateDraftLine, }, ], @@ -181,7 +180,6 @@ export const PricingTableComponent: FC = ({ 'numberOfPacks', { width: 100, - label: 'label.num-packs', }, ], [ diff --git a/client/packages/invoices/src/OutboundShipment/DetailView/OutboundLineEdit/columns.ts b/client/packages/invoices/src/OutboundShipment/DetailView/OutboundLineEdit/columns.ts index 7111fa0dd3..c839f01a10 100644 --- a/client/packages/invoices/src/OutboundShipment/DetailView/OutboundLineEdit/columns.ts +++ b/client/packages/invoices/src/OutboundShipment/DetailView/OutboundLineEdit/columns.ts @@ -149,7 +149,7 @@ export const useExpansionColumns = (): Column[] => { accessor: ({ rowData }) => rowData.item.unitName, }, ], - 'packSize', + ['packSize', { Cell: NumberCell }], 'numberOfPacks', [ 'unitQuantity', diff --git a/client/packages/programs/src/JsonForms/components/Prescription/StockLineTable.tsx b/client/packages/programs/src/JsonForms/components/Prescription/StockLineTable.tsx index 3924745e4c..ee95a6fefe 100644 --- a/client/packages/programs/src/JsonForms/components/Prescription/StockLineTable.tsx +++ b/client/packages/programs/src/JsonForms/components/Prescription/StockLineTable.tsx @@ -54,7 +54,7 @@ export const StockLineTable = ({ { width: '55px', key: 'numberOfPacks', - label: 'label.amount', + label: 'label.num-packs', accessor: ({ rowData }) => rowData.numberOfPacks, setter: handleUpdateDraft, Cell: PackQuantityCell, diff --git a/client/packages/programs/src/icons/Contraceptive.tsx b/client/packages/programs/src/icons/Contraceptive.tsx index 2686dc2ccf..539b071905 100644 --- a/client/packages/programs/src/icons/Contraceptive.tsx +++ b/client/packages/programs/src/icons/Contraceptive.tsx @@ -5,8 +5,8 @@ import { GradientStops } from './_gradient'; export const ContraceptiveIcon = (props: SvgIconProps): JSX.Element => ( diff --git a/client/packages/programs/src/icons/Liver.tsx b/client/packages/programs/src/icons/Liver.tsx index 26b9d0260e..e236d1300c 100644 --- a/client/packages/programs/src/icons/Liver.tsx +++ b/client/packages/programs/src/icons/Liver.tsx @@ -5,8 +5,8 @@ import { GradientStops } from './_gradient'; export const LiverIcon = (props: SvgIconProps): JSX.Element => ( diff --git a/client/packages/programs/src/icons/LungsVirus.tsx b/client/packages/programs/src/icons/LungsVirus.tsx index c3ecadc7b8..af1ab7f3a1 100644 --- a/client/packages/programs/src/icons/LungsVirus.tsx +++ b/client/packages/programs/src/icons/LungsVirus.tsx @@ -5,8 +5,8 @@ import { GradientStops } from './_gradient'; export const LungsVirusIcon = (props: SvgIconProps): JSX.Element => ( diff --git a/client/packages/programs/src/icons/MedicalBag.tsx b/client/packages/programs/src/icons/MedicalBag.tsx index da8ea88f10..57cd2c26b9 100644 --- a/client/packages/programs/src/icons/MedicalBag.tsx +++ b/client/packages/programs/src/icons/MedicalBag.tsx @@ -5,8 +5,8 @@ import { GradientStops } from './_gradient'; export const MedicalBagIcon = (props: SvgIconProps): JSX.Element => ( diff --git a/client/packages/programs/src/icons/Referrals.tsx b/client/packages/programs/src/icons/Referrals.tsx index f39e4449d5..8533a16381 100644 --- a/client/packages/programs/src/icons/Referrals.tsx +++ b/client/packages/programs/src/icons/Referrals.tsx @@ -5,8 +5,8 @@ import { GradientStops } from './_gradient'; export const ReferralsIcon = (props: SvgIconProps): JSX.Element => ( diff --git a/client/packages/programs/src/icons/_gradient.tsx b/client/packages/programs/src/icons/_gradient.tsx index 93e0fd8ec7..96a342de28 100644 --- a/client/packages/programs/src/icons/_gradient.tsx +++ b/client/packages/programs/src/icons/_gradient.tsx @@ -7,8 +7,8 @@ export const GradientStops = () => { const theme = useTheme(); return ( <> - - + + ); }; diff --git a/client/packages/system/src/Item/DetailView/Tabs/ItemLedger.tsx b/client/packages/system/src/Item/DetailView/Tabs/ItemLedger.tsx index 749b7d44d2..1dc9319a7e 100644 --- a/client/packages/system/src/Item/DetailView/Tabs/ItemLedger.tsx +++ b/client/packages/system/src/Item/DetailView/Tabs/ItemLedger.tsx @@ -98,7 +98,6 @@ const ItemLedgerTable = ({ }, { key: 'numberOfPacks', - label: 'label.num-packs', sortable: false, }, { diff --git a/client/packages/system/src/Stock/Components/InventoryAdjustment/InventoryAdjustmentModal.tsx b/client/packages/system/src/Stock/Components/InventoryAdjustment/InventoryAdjustmentModal.tsx index e1479830b8..675d735f85 100644 --- a/client/packages/system/src/Stock/Components/InventoryAdjustment/InventoryAdjustmentModal.tsx +++ b/client/packages/system/src/Stock/Components/InventoryAdjustment/InventoryAdjustmentModal.tsx @@ -107,7 +107,7 @@ export const InventoryAdjustmentModal: FC = ({ flex={1} > = ({ gap={1} > { }, { key: 'numberOfPacks', - label: 'label.num-packs', + Cell: NumberCell, accessor: ({ rowData }) => rowData.totalNumberOfPacks, width: 125, }, { key: 'stockOnHand', label: 'label.soh', + Cell: NumberCell, accessor: ({ rowData }) => rowData.totalNumberOfPacks * rowData.packSize, description: 'description.soh', sortable: false,