diff --git a/packages/server/src/api/controllers/Purchases/Bills.ts b/packages/server/src/api/controllers/Purchases/Bills.ts index 7248c97df0..94bfb814d5 100644 --- a/packages/server/src/api/controllers/Purchases/Bills.ts +++ b/packages/server/src/api/controllers/Purchases/Bills.ts @@ -121,7 +121,7 @@ export default class BillsController extends BaseController { check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.rate').exists().isNumeric().toFloat(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.discount') .optional({ nullable: true }) .isNumeric() diff --git a/packages/server/src/api/controllers/Purchases/VendorCredit.ts b/packages/server/src/api/controllers/Purchases/VendorCredit.ts index 26e3f85b91..e97fbf6875 100644 --- a/packages/server/src/api/controllers/Purchases/VendorCredit.ts +++ b/packages/server/src/api/controllers/Purchases/VendorCredit.ts @@ -170,7 +170,7 @@ export default class VendorCreditController extends BaseController { check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.rate').exists().isNumeric().toFloat(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.discount') .optional({ nullable: true }) .isNumeric() @@ -209,7 +209,7 @@ export default class VendorCreditController extends BaseController { check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.rate').exists().isNumeric().toFloat(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.discount') .optional({ nullable: true }) .isNumeric() diff --git a/packages/server/src/api/controllers/Sales/CreditNotes.ts b/packages/server/src/api/controllers/Sales/CreditNotes.ts index 3037d33f14..a88b45939c 100644 --- a/packages/server/src/api/controllers/Sales/CreditNotes.ts +++ b/packages/server/src/api/controllers/Sales/CreditNotes.ts @@ -233,7 +233,7 @@ export default class PaymentReceivesController extends BaseController { check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.rate').exists().isNumeric().toFloat(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.discount') .optional({ nullable: true }) .isNumeric() @@ -755,9 +755,8 @@ export default class PaymentReceivesController extends BaseController { const { tenantId } = req; try { - const data = await this.getCreditNoteStateService.getCreditNoteState( - tenantId - ); + const data = + await this.getCreditNoteStateService.getCreditNoteState(tenantId); return res.status(200).send({ data }); } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/Sales/SalesEstimates.ts b/packages/server/src/api/controllers/Sales/SalesEstimates.ts index 556e96fd66..5a2a806733 100644 --- a/packages/server/src/api/controllers/Sales/SalesEstimates.ts +++ b/packages/server/src/api/controllers/Sales/SalesEstimates.ts @@ -172,7 +172,7 @@ export default class SalesEstimatesController extends BaseController { check('entries').exists().isArray({ min: 1 }), check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.description').optional({ nullable: true }).trim(), check('entries.*.discount') @@ -562,9 +562,8 @@ export default class SalesEstimatesController extends BaseController { const { tenantId } = req; try { - const data = await this.saleEstimatesApplication.getSaleEstimateState( - tenantId - ); + const data = + await this.saleEstimatesApplication.getSaleEstimateState(tenantId); return res.status(200).send({ data }); } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/Sales/SalesReceipts.ts b/packages/server/src/api/controllers/Sales/SalesReceipts.ts index caf93d02ac..6b7d6ef7ab 100644 --- a/packages/server/src/api/controllers/Sales/SalesReceipts.ts +++ b/packages/server/src/api/controllers/Sales/SalesReceipts.ts @@ -148,7 +148,7 @@ export default class SalesReceiptsController extends BaseController { check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(), - check('entries.*.quantity').exists().isNumeric().toInt(), + check('entries.*.quantity').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.discount') .optional({ nullable: true }) @@ -392,9 +392,8 @@ export default class SalesReceiptsController extends BaseController { // Retrieves receipt in pdf format. try { - const data = await this.saleReceiptsApplication.getSaleReceiptState( - tenantId - ); + const data = + await this.saleReceiptsApplication.getSaleReceiptState(tenantId); return res.status(200).send({ data }); } catch (error) { next(error); diff --git a/packages/server/src/database/migrations/20241113113437_change_quantity_in_items_entries_to_decimal.js b/packages/server/src/database/migrations/20241113113437_change_quantity_in_items_entries_to_decimal.js new file mode 100644 index 0000000000..dcc711ffce --- /dev/null +++ b/packages/server/src/database/migrations/20241113113437_change_quantity_in_items_entries_to_decimal.js @@ -0,0 +1,39 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return knex.schema + .table('items_entries', (table) => { + table.decimal('quantity', 13, 3).alter(); + }) + .table('inventory_transactions', (table) => { + table.decimal('quantity', 13, 3).alter(); + }) + .table('inventory_cost_lot_tracker', (table) => { + table.decimal('quantity', 13, 3).alter(); + }) + .table('items', (table) => { + table.decimal('quantityOnHand', 13, 3).alter(); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return knex.schema + .table('items_entries', (table) => { + table.integer('quantity').alter(); + }) + .table('inventory_transactions', (table) => { + table.integer('quantity').alter(); + }) + .table('inventory_cost_lot_tracker', (table) => { + table.integer('quantity').alter(); + }) + .table('items', (table) => { + table.integer('quantityOnHand').alter(); + }); +}; diff --git a/packages/webapp/src/components/DataTableCells/NumericInputCell.tsx b/packages/webapp/src/components/DataTableCells/NumericInputCell.tsx index 71e2d637d9..b3432267c5 100644 --- a/packages/webapp/src/components/DataTableCells/NumericInputCell.tsx +++ b/packages/webapp/src/components/DataTableCells/NumericInputCell.tsx @@ -1,8 +1,6 @@ -// @ts-nocheck import React, { useState, useEffect } from 'react'; import { FormGroup, NumericInput, Intent } from '@blueprintjs/core'; import classNames from 'classnames'; - import { CellType } from '@/constants'; import { CLASSES } from '@/constants/classes'; @@ -12,37 +10,44 @@ import { CLASSES } from '@/constants/classes'; export default function NumericInputCell({ row: { index }, column: { id }, - cell: { value: initialValue }, + cell: { value: controlledInputValue }, payload, -}) { - const [value, setValue] = useState(initialValue); - - const handleValueChange = (newValue) => { - setValue(newValue); +}: any) { + const [valueAsNumber, setValueAsNumber] = useState( + controlledInputValue || null, + ); + const handleInputValueChange = ( + valueAsNumber: number, + valueAsString: string, + ) => { + setValueAsNumber(valueAsNumber); }; - const onBlur = () => { - payload.updateData(index, id, value); + const handleInputBlur = () => { + payload.updateData(index, id, valueAsNumber); }; + useEffect(() => { - setValue(initialValue); - }, [initialValue]); + setValueAsNumber(controlledInputValue); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [controlledInputValue]); const error = payload.errors?.[index]?.[id]; return ( ); } -NumericInputCell.cellType = CellType.Field; \ No newline at end of file +NumericInputCell.cellType = CellType.Field; diff --git a/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx index 9b9691ddfa..cc2d2c4660 100644 --- a/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx +++ b/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx @@ -13,7 +13,6 @@ import { Tag, } from '@blueprintjs/core'; import { - FormatNumberCell, TextOverviewTooltipCell, FormattedMessage as T, Choose, @@ -51,9 +50,8 @@ export const useBillReadonlyEntriesTableColumns = () => { }, { Header: intl.get('quantity'), - accessor: 'quantity', - Cell: FormatNumberCell, - width: getColumnWidth(entries, 'quantity', { + accessor: 'quantity_formatted', + width: getColumnWidth(entries, 'quantity_formatted', { minWidth: 60, magicSpacing: 5, }), diff --git a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx index 85e57c5ee9..c4a5bcd74c 100644 --- a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx +++ b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx @@ -48,9 +48,8 @@ export const useCreditNoteReadOnlyEntriesColumns = () => { }, { Header: intl.get('quantity'), - accessor: 'quantity', - Cell: FormatNumberCell, - width: getColumnWidth(entries, 'quantity', { + accessor: 'quantity_formatted', + width: getColumnWidth(entries, 'quantity_formatted', { minWidth: 60, magicSpacing: 5, }), diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx index bb7f8ebc8b..33396a2c57 100644 --- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx +++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx @@ -54,11 +54,10 @@ export const useInvoiceReadonlyEntriesColumns = () => { { Header: intl.get('quantity'), accessor: 'quantity', - Cell: FormatNumberCell, align: 'right', disableSortBy: true, textOverview: true, - width: getColumnWidth(entries, 'quantity', { + width: getColumnWidth(entries, 'quantity_formatted', { minWidth: 60, magicSpacing: 5, }), diff --git a/packages/webapp/src/containers/Drawers/ItemDetailDrawer/ItemPaymentTransactions/EstimatePaymentTransactions/components.tsx b/packages/webapp/src/containers/Drawers/ItemDetailDrawer/ItemPaymentTransactions/EstimatePaymentTransactions/components.tsx index 08ddf152f2..8055c41378 100644 --- a/packages/webapp/src/containers/Drawers/ItemDetailDrawer/ItemPaymentTransactions/EstimatePaymentTransactions/components.tsx +++ b/packages/webapp/src/containers/Drawers/ItemDetailDrawer/ItemPaymentTransactions/EstimatePaymentTransactions/components.tsx @@ -72,7 +72,7 @@ export const useEstimateTransactionsColumns = () => { { id: 'qunatity', Header: intl.get('item.drawer_quantity_sold'), - accessor: 'quantity', + accessor: 'quantity_formatted', align: 'right', width: 100, }, diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx index 0241d3e762..87399cd859 100644 --- a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx +++ b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx @@ -31,9 +31,8 @@ export const useReceiptReadonlyEntriesTableColumns = () => { }, { Header: intl.get('quantity'), - accessor: 'quantity', - Cell: FormatNumberCell, - width: getColumnWidth(entries, 'quantity', { + accessor: 'quantity_formatted', + width: getColumnWidth(entries, 'quantity_formatted', { minWidth: 60, magicSpacing: 5, }),