Merge pull request #1407 from Gadha2311/uom-quantity

fix: Uom quantity
This commit is contained in:
Able k Saju
2026-01-13 15:10:07 +05:30
committed by GitHub
8 changed files with 119 additions and 37 deletions
+17 -1
View File
@@ -36,6 +36,7 @@ export abstract class InvoiceItem extends Doc {
transferUnit?: string;
quantity?: number;
transferQuantity?: number;
qty?: number;
unitConversionFactor?: number;
batch?: string;
@@ -231,13 +232,28 @@ export abstract class InvoiceItem extends Doc {
},
transferQuantity: {
formula: (fieldname) => {
if (fieldname === 'qty') {
return this.qty;
}
if (fieldname === 'quantity' || this.unit === this.transferUnit) {
return this.quantity;
}
return this.transferQuantity;
},
dependsOn: ['item', 'quantity'],
dependsOn: ['item', 'quantity', 'qty'],
},
qty: {
formula: (fieldname) => {
if (fieldname === 'transferQuantity') {
return this.transferQuantity;
}
if (fieldname === 'quantity' || this.unit === this.transferUnit) {
return this.quantity;
}
return this.transferQuantity;
},
dependsOn: ['transferQuantity', 'quantity'],
},
quantity: {
formula: async (fieldname) => {
+8 -1
View File
@@ -44,6 +44,13 @@
"default": 1,
"required": true
},
{
"fieldname": "qty",
"label": "Qty",
"fieldtype": "Float",
"default": 1,
"computed": true
},
{
"fieldname": "unit",
"label": "Stock Unit",
@@ -140,7 +147,7 @@
"readOnly": true
}
],
"tableFields": ["item", "tax", "quantity", "rate", "amount"],
"tableFields": ["item", "tax", "qty", "rate", "amount"],
"keywordFields": ["item", "tax"],
"quickEditFields": [
"item",
+53 -9
View File
@@ -36,7 +36,7 @@
}"
size="small"
:border="false"
:value="row.quantity"
:value="getDisplayTransferQuantity()"
:read-only="true"
/>
<div class="flex flex-col ml-1">
@@ -70,13 +70,13 @@
<Link
class="ml-5"
:df="{
fieldname: 'unit',
fieldname: 'transferUnit',
fieldtype: 'Data',
label: 'Unit',
}"
size="small"
:border="false"
:value="row.unit"
:value="row.transferUnit || row.unit"
:read-only="true"
/>
@@ -133,18 +133,19 @@
</div>
<div class="px-4 pt-6 col-span-2">
<Link
v-if="isUOMConversionEnabled"
<AutoComplete
v-if="isUOMConversionEnabled && transferUnitOptions.length"
:key="row.item"
:df="{
fieldtype: 'AutoComplete',
fieldname: 'transferUnit',
fieldtype: 'Link',
target: 'UOM',
label: t`Transfer Unit`,
options: transferUnitOptions,
}"
class="flex-1"
:show-label="true"
:border="true"
:value="row.transferUnit"
:value="row.transferUnit ?? ''"
@change="(value:string) => row.set('transferUnit', value)"
:read-only="isReadOnly"
/>
@@ -295,10 +296,11 @@ import { InvoiceItem } from 'models/baseModels/InvoiceItem/InvoiceItem';
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
import { showToast } from 'src/utils/interactive';
import { ModelNameEnum } from 'models/types';
import AutoComplete from 'src/components/Controls/AutoComplete.vue';
export default defineComponent({
name: 'SelectedItemRow',
components: { Currency, Data, Float, Int, Link, Text },
components: { Currency, Data, Float, Int, Link, Text, AutoComplete },
props: {
row: { type: SalesInvoiceItem, required: true },
batchAdded: { type: Boolean, default: false },
@@ -321,6 +323,7 @@ export default defineComponent({
defaultRate: this.row.rate as Money,
profileDiscountSetting: null as boolean | null,
profileRateSetting: null as boolean | null,
transferUnitOptions: [] as Array<{ label: string; value: string }>,
};
},
watch: {
@@ -333,6 +336,16 @@ export default defineComponent({
},
immediate: true,
},
'row.item': {
async handler(newItem) {
if (newItem) {
await this.updateTransferUnitOptions();
} else {
this.transferUnitOptions = [];
}
},
immediate: true,
},
},
computed: {
isUOMConversionEnabled(): boolean {
@@ -394,6 +407,37 @@ export default defineComponent({
this.setQuantity(newQuantity);
},
async updateTransferUnitOptions() {
if (!this.row.item) {
this.transferUnitOptions = [];
return;
}
const itemDoc = await fyo.doc.getDoc('Item', this.row.item as string);
const conversions = (itemDoc?.uomConversions ?? []) as Array<{
uom: string;
conversionFactor: number;
}>;
const allowedUoms = new Set<string>();
if (typeof itemDoc?.unit === 'string') {
allowedUoms.add(itemDoc.unit);
}
for (const c of conversions) {
if (typeof c.uom === 'string') {
allowedUoms.add(c.uom);
}
}
this.transferUnitOptions = [...allowedUoms].map((uom) => ({
label: uom,
value: uom,
}));
},
async getAvailableQtyInBatch(): Promise<number> {
if (!this.row.batch) {
return 0;
@@ -125,7 +125,7 @@ export default defineComponent({
},
{
fieldname: 'unit',
label: 'Stock Unit',
label: 'Unit Type',
placeholder: 'Unit',
fieldtype: 'Link',
required: true,
+11 -8
View File
@@ -60,12 +60,12 @@
<section class="mt-8 text-base">
<!-- Heading Row -->
<section class="text-gray-600 w-full flex border-b">
<div class="py-4 w-5/12">{{ t`Item` }}</div>
<div class="py-4 w-5/12" v-if="doc.description">{{ t`Description` }}</div>
<div class="py-4 text-right w-2/12" v-if="doc.showHSN">
<div class="py-4 w-4/12">{{ t`Item` }}</div>
<div class="py-4 w-4/12" v-if="doc.description">{{ t`Description` }}</div>
<div class="py-4 text-right w-3/12" v-if="doc.showHSN">
{{ t`HSN/SAC` }}
</div>
<div class="py-4 text-right w-1/12">{{ t`Quantity` }}</div>
<div class="py-4 text-right w-3/12">{{ t`Qty` }}</div>
<div class="py-4 text-right w-3/12">{{ t`Rate` }}</div>
<div class="py-4 text-right w-3/12">{{ t`Amount` }}</div>
</section>
@@ -76,14 +76,17 @@
v-for="row in doc.items"
:key="row.name"
>
<div class="w-5/12 py-4">{{ row.item }}</div>
<div class="w-5/12 py-4" v-if="doc.description">
<div class="w-4/12 py-4">{{ row.item }}</div>
<div class="w-4/12 py-4" v-if="doc.description">
{{ row.description }}
</div>
<div class="w-2/12 text-right py-4" v-if="doc.showHSN">
<div class="w-3/12 text-right py-4" v-if="doc.showHSN">
{{ row.hsnCode }}
</div>
<div class="w-1/12 text-right py-4">{{ row.quantity }}</div>
<div class="w-3/12 text-right py-4">
<div v-if="row.transferUnit">{{ row.transferUnit }} {{ row.qty }}</div>
<div v-else>{{ row.qty }}</div>
</div>
<div class="w-3/12 text-right py-4">{{ row.rate }}</div>
<div class="w-3/12 text-right py-4">{{ row.amount }}</div>
</section>
+7 -1
View File
@@ -81,7 +81,13 @@
{{ row.hsnCode }}
</div>
<div class="w-1/4 text-right py-1">{{ row.location }}</div>
<div class="w-1/4 text-right py-1">{{ row.quantity }}</div>
<div class="w-1/4 text-right py-1">
<div>{{ row.quantity }}</div>
<div v-if="row.transferUnit">
({{row.transferQuantity}} of {{ row.transferUnit }})
</div>
<div v-else-if="row.unit">({{row.quantity}} of {{ row.unit }})</div>
</div>
<div class="w-3/12 text-right py-1">{{ row.rate }}</div>
<div class="w-3/12 text-right py-1">{{ row.amount }}</div>
</section>
+11 -8
View File
@@ -60,10 +60,10 @@
<section class="px-12 pt-12 text-lg">
<!-- Heading Row -->
<section class="mb-4 flex font-semibold">
<div class="w-4/12">{{ t`Item` }}</div>
<div class="w-4/12" v-if="doc.description">{{ t`Description` }}</div>
<div class="w-2/12 text-right" v-if="doc.showHSN">{{ t`HSN/SAC` }}</div>
<div class="w-2/12 text-right">{{ t`Quantity` }}</div>
<div class="w-3/12">{{ t`Item` }}</div>
<div class="w-3/12" v-if="doc.description">{{ t`Description` }}</div>
<div class="w-3/12 text-right" v-if="doc.showHSN">{{ t`HSN/SAC` }}</div>
<div class="w-3/12 text-right">{{ t`Qty` }}</div>
<div class="w-3/12 text-right">{{ t`Rate` }}</div>
<div class="w-3/12 text-right">{{ t`Amount` }}</div>
</section>
@@ -74,10 +74,13 @@
v-for="row in doc.items"
:key="row.name"
>
<div class="w-4/12">{{ row.item }}</div>
<div class="w-4/12" v-if="doc.description">{{ row.description }}</div>
<div class="w-2/12 text-right" v-if="doc.showHSN">{{ row.hsnCode }}</div>
<div class="w-2/12 text-right">{{ row.quantity }}</div>
<div class="w-3/12">{{ row.item }}</div>
<div class="w-3/12" v-if="doc.description">{{ row.description }}</div>
<div class="w-3/12 text-right" v-if="doc.showHSN">{{ row.hsnCode }}</div>
<div class="w-3/12 text-right">
<div v-if="row.transferUnit">{{ row.transferUnit }} {{ row.qty }}</div>
<div v-else>{{ row.qty }}</div>
</div>
<div class="w-3/12 text-right">{{ row.rate }}</div>
<div class="w-3/12 text-right">{{ row.amount }}</div>
</section>
+11 -8
View File
@@ -98,24 +98,27 @@
text-gray-800
"
>
<div class="w-4/12 text-left">{{ t`Item` }}</div>
<div class="w-4/12 text-left" v-if="doc.description">
<div class="w-3/12 text-left">{{ t`Item` }}</div>
<div class="w-3/12 text-left" v-if="doc.description">
{{ t`Description` }}
</div>
<div class="w-2/12 text-right" v-if="doc.showHSN">{{ t`HSN/SAC` }}</div>
<div class="w-2/12 text-right">{{ t`Quantity` }}</div>
<div class="w-3/12 text-right" v-if="doc.showHSN">{{ t`HSN/SAC` }}</div>
<div class="w-3/12 text-right">{{ t`Qty` }}</div>
<div class="w-3/12 text-right">{{ t`Rate` }}</div>
<div class="w-3/12 text-right">{{ t`Amount`}}</div>
</section>
<!-- Body Rows -->
<section class="flex py-1 text-lg" v-for="row in doc.items" :key="row.name">
<div class="w-4/12 text-left">{{ row.item }}</div>
<div class="w-4/12 text-left" v-if="doc.description">
<div class="w-3/12 text-left">{{ row.item }}</div>
<div class="w-3/12 text-left" v-if="doc.description">
{{ row.description }}
</div>
<div class="w-2/12 text-right" v-if="doc.showHSN">{{ row.hsnCode }}</div>
<div class="w-2/12 text-right">{{ row.quantity }}</div>
<div class="w-3/12 text-right" v-if="doc.showHSN">{{ row.hsnCode }}</div>
<div class="w-3/12 text-right">
<div v-if="row.transferUnit">{{ row.transferUnit }} {{ row.qty }}</div>
<div v-else>{{ row.qty }}</div>
</div>
<div class="w-3/12 text-right">{{ row.rate }}</div>
<div class="w-3/12 text-right">{{ row.amount }}</div>
</section>