feat: allow quantity of entries accept decimal value (#753)

This commit is contained in:
Ahmed Bouhuolia
2024-11-13 18:35:57 +02:00
committed by GitHub
parent 908bbb9fa6
commit 5d6f901d33
12 changed files with 83 additions and 47 deletions

View File

@@ -121,7 +121,7 @@ export default class BillsController extends BaseController {
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(),
check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(),
check('entries.*.quantity').exists().isNumeric().toInt(), check('entries.*.quantity').exists().isNumeric().toFloat(),
check('entries.*.discount') check('entries.*.discount')
.optional({ nullable: true }) .optional({ nullable: true })
.isNumeric() .isNumeric()

View File

@@ -170,7 +170,7 @@ export default class VendorCreditController extends BaseController {
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(),
check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(),
check('entries.*.quantity').exists().isNumeric().toInt(), check('entries.*.quantity').exists().isNumeric().toFloat(),
check('entries.*.discount') check('entries.*.discount')
.optional({ nullable: true }) .optional({ nullable: true })
.isNumeric() .isNumeric()
@@ -209,7 +209,7 @@ export default class VendorCreditController extends BaseController {
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(),
check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(),
check('entries.*.quantity').exists().isNumeric().toInt(), check('entries.*.quantity').exists().isNumeric().toFloat(),
check('entries.*.discount') check('entries.*.discount')
.optional({ nullable: true }) .optional({ nullable: true })
.isNumeric() .isNumeric()

View File

@@ -233,7 +233,7 @@ export default class PaymentReceivesController extends BaseController {
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').exists().isNumeric().toInt(), check('entries.*.item_id').exists().isNumeric().toInt(),
check('entries.*.rate').exists().isNumeric().toFloat(), check('entries.*.rate').exists().isNumeric().toFloat(),
check('entries.*.quantity').exists().isNumeric().toInt(), check('entries.*.quantity').exists().isNumeric().toFloat(),
check('entries.*.discount') check('entries.*.discount')
.optional({ nullable: true }) .optional({ nullable: true })
.isNumeric() .isNumeric()
@@ -755,9 +755,8 @@ export default class PaymentReceivesController extends BaseController {
const { tenantId } = req; const { tenantId } = req;
try { try {
const data = await this.getCreditNoteStateService.getCreditNoteState( const data =
tenantId await this.getCreditNoteStateService.getCreditNoteState(tenantId);
);
return res.status(200).send({ data }); return res.status(200).send({ data });
} catch (error) { } catch (error) {
next(error); next(error);

View File

@@ -172,7 +172,7 @@ export default class SalesEstimatesController extends BaseController {
check('entries').exists().isArray({ min: 1 }), check('entries').exists().isArray({ min: 1 }),
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').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.*.rate').exists().isNumeric().toFloat(),
check('entries.*.description').optional({ nullable: true }).trim(), check('entries.*.description').optional({ nullable: true }).trim(),
check('entries.*.discount') check('entries.*.discount')
@@ -562,9 +562,8 @@ export default class SalesEstimatesController extends BaseController {
const { tenantId } = req; const { tenantId } = req;
try { try {
const data = await this.saleEstimatesApplication.getSaleEstimateState( const data =
tenantId await this.saleEstimatesApplication.getSaleEstimateState(tenantId);
);
return res.status(200).send({ data }); return res.status(200).send({ data });
} catch (error) { } catch (error) {
next(error); next(error);

View File

@@ -148,7 +148,7 @@ export default class SalesReceiptsController extends BaseController {
check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(), check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
check('entries.*.index').exists().isNumeric().toInt(), check('entries.*.index').exists().isNumeric().toInt(),
check('entries.*.item_id').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.*.rate').exists().isNumeric().toFloat(),
check('entries.*.discount') check('entries.*.discount')
.optional({ nullable: true }) .optional({ nullable: true })
@@ -392,9 +392,8 @@ export default class SalesReceiptsController extends BaseController {
// Retrieves receipt in pdf format. // Retrieves receipt in pdf format.
try { try {
const data = await this.saleReceiptsApplication.getSaleReceiptState( const data =
tenantId await this.saleReceiptsApplication.getSaleReceiptState(tenantId);
);
return res.status(200).send({ data }); return res.status(200).send({ data });
} catch (error) { } catch (error) {
next(error); next(error);

View File

@@ -0,0 +1,39 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
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<void> }
*/
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();
});
};

View File

@@ -1,8 +1,6 @@
// @ts-nocheck
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { FormGroup, NumericInput, Intent } from '@blueprintjs/core'; import { FormGroup, NumericInput, Intent } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { CellType } from '@/constants'; import { CellType } from '@/constants';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
@@ -12,37 +10,44 @@ import { CLASSES } from '@/constants/classes';
export default function NumericInputCell({ export default function NumericInputCell({
row: { index }, row: { index },
column: { id }, column: { id },
cell: { value: initialValue }, cell: { value: controlledInputValue },
payload, payload,
}) { }: any) {
const [value, setValue] = useState(initialValue); const [valueAsNumber, setValueAsNumber] = useState<number | null>(
controlledInputValue || null,
);
const handleInputValueChange = (
valueAsNumber: number,
valueAsString: string,
) => {
setValueAsNumber(valueAsNumber);
};
const handleInputBlur = () => {
payload.updateData(index, id, valueAsNumber);
};
const handleValueChange = (newValue) => {
setValue(newValue);
};
const onBlur = () => {
payload.updateData(index, id, value);
};
useEffect(() => { useEffect(() => {
setValue(initialValue); setValueAsNumber(controlledInputValue);
}, [initialValue]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [controlledInputValue]);
const error = payload.errors?.[index]?.[id]; const error = payload.errors?.[index]?.[id];
return ( return (
<FormGroup <FormGroup
intent={error ? Intent.DANGER : null} intent={error ? Intent.DANGER : undefined}
className={classNames(CLASSES.FILL)} className={classNames(CLASSES.FILL)}
> >
<NumericInput <NumericInput
value={value} asyncControl
onValueChange={handleValueChange} value={controlledInputValue}
onBlur={onBlur} onValueChange={handleInputValueChange}
fill={true} onBlur={handleInputBlur}
buttonPosition={'none'} buttonPosition={'none'}
fill
/> />
</FormGroup> </FormGroup>
); );
} }
NumericInputCell.cellType = CellType.Field; NumericInputCell.cellType = CellType.Field;

View File

@@ -13,7 +13,6 @@ import {
Tag, Tag,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
FormatNumberCell,
TextOverviewTooltipCell, TextOverviewTooltipCell,
FormattedMessage as T, FormattedMessage as T,
Choose, Choose,
@@ -51,9 +50,8 @@ export const useBillReadonlyEntriesTableColumns = () => {
}, },
{ {
Header: intl.get('quantity'), Header: intl.get('quantity'),
accessor: 'quantity', accessor: 'quantity_formatted',
Cell: FormatNumberCell, width: getColumnWidth(entries, 'quantity_formatted', {
width: getColumnWidth(entries, 'quantity', {
minWidth: 60, minWidth: 60,
magicSpacing: 5, magicSpacing: 5,
}), }),

View File

@@ -48,9 +48,8 @@ export const useCreditNoteReadOnlyEntriesColumns = () => {
}, },
{ {
Header: intl.get('quantity'), Header: intl.get('quantity'),
accessor: 'quantity', accessor: 'quantity_formatted',
Cell: FormatNumberCell, width: getColumnWidth(entries, 'quantity_formatted', {
width: getColumnWidth(entries, 'quantity', {
minWidth: 60, minWidth: 60,
magicSpacing: 5, magicSpacing: 5,
}), }),

View File

@@ -54,11 +54,10 @@ export const useInvoiceReadonlyEntriesColumns = () => {
{ {
Header: intl.get('quantity'), Header: intl.get('quantity'),
accessor: 'quantity', accessor: 'quantity',
Cell: FormatNumberCell,
align: 'right', align: 'right',
disableSortBy: true, disableSortBy: true,
textOverview: true, textOverview: true,
width: getColumnWidth(entries, 'quantity', { width: getColumnWidth(entries, 'quantity_formatted', {
minWidth: 60, minWidth: 60,
magicSpacing: 5, magicSpacing: 5,
}), }),

View File

@@ -72,7 +72,7 @@ export const useEstimateTransactionsColumns = () => {
{ {
id: 'qunatity', id: 'qunatity',
Header: intl.get('item.drawer_quantity_sold'), Header: intl.get('item.drawer_quantity_sold'),
accessor: 'quantity', accessor: 'quantity_formatted',
align: 'right', align: 'right',
width: 100, width: 100,
}, },

View File

@@ -31,9 +31,8 @@ export const useReceiptReadonlyEntriesTableColumns = () => {
}, },
{ {
Header: intl.get('quantity'), Header: intl.get('quantity'),
accessor: 'quantity', accessor: 'quantity_formatted',
Cell: FormatNumberCell, width: getColumnWidth(entries, 'quantity_formatted', {
width: getColumnWidth(entries, 'quantity', {
minWidth: 60, minWidth: 60,
magicSpacing: 5, magicSpacing: 5,
}), }),