From 5fcc5eb26788730e06bdd4273f27ac9d691fa56c Mon Sep 17 00:00:00 2001 From: AbleKSaju <126228406+AbleKSaju@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:09:01 +0530 Subject: [PATCH] fix: filter returned invoices --- .../AccountingSettings/AccountingSettings.ts | 1 + models/baseModels/Invoice/Invoice.ts | 18 ++++++++++-- models/baseModels/Payment/Payment.ts | 28 ++++++++----------- models/baseModels/tests/testInvoice.spec.ts | 2 +- schemas/app/inventory/InventorySettings.json | 7 ----- src/pages/POS/ClassicPOS.vue | 1 + src/pages/POS/POS.vue | 10 +++---- src/pages/POS/PaymentModal.vue | 6 ++++ src/pages/POS/ReturnSalesInvoiceModal.vue | 28 +++++++++++++++---- src/utils/erpnextSync.ts | 6 ++-- 10 files changed, 67 insertions(+), 40 deletions(-) diff --git a/models/baseModels/AccountingSettings/AccountingSettings.ts b/models/baseModels/AccountingSettings/AccountingSettings.ts index d4392a73..05d570ba 100644 --- a/models/baseModels/AccountingSettings/AccountingSettings.ts +++ b/models/baseModels/AccountingSettings/AccountingSettings.ts @@ -26,6 +26,7 @@ export class AccountingSettings extends Doc { enableERPNextSync?: boolean; enablePointOfSaleWithOutInventory?: boolean; enablePartialPayment?: boolean; + enableitemGroup?: boolean; static filters: FiltersMap = { writeOffAccount: () => ({ diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index ca66f02a..954a2a2b 100644 --- a/models/baseModels/Invoice/Invoice.ts +++ b/models/baseModels/Invoice/Invoice.ts @@ -339,6 +339,10 @@ export abstract class Invoice extends Transactional { for (const details of (tax.details ?? []) as TaxDetail[]) { let amount = item.amount!; + if (this.isReturn && amount.isPositive()) { + amount = amount.neg(); + } + if (!this.discountAfterTax) { let itemDiscountAmount = this.getDiscountAmount(item); @@ -895,11 +899,21 @@ export abstract class Invoice extends Transactional { this.returnAgainst )) as Invoice; if (sinvreturnedDoc.outstandingAmount?.isZero()) { - return this.grandTotal; + return this.grandTotal?.abs(); } else { - return this.grandTotal + const totalPaid = this.grandTotal ?.abs() .sub(sinvreturnedDoc.outstandingAmount as Money); + + if (!sinvreturnedDoc.isReturn) { + return totalPaid?.abs(); + } + + if (!this.grandTotal?.isNegative()) { + this.grandTotal = this.grandTotal?.neg(); + } + + return this.grandTotal?.add(totalPaid as Money).abs(); } } diff --git a/models/baseModels/Payment/Payment.ts b/models/baseModels/Payment/Payment.ts index 058e845c..6993d865 100644 --- a/models/baseModels/Payment/Payment.ts +++ b/models/baseModels/Payment/Payment.ts @@ -459,6 +459,16 @@ export class Payment extends Transactional { row.referenceName ); + const previousOutstandingAmount = referenceDoc.outstandingAmount as Money; + const outstandingAmount = previousOutstandingAmount.sub(row.amount!); + await referenceDoc.setAndSync({ outstandingAmount }); + } + } + + async beforeSync(): Promise { + await super.beforeSync(); + + for (const row of this.for ?? []) { if (!this.fyo.singles.AccountingSettings?.enablePartialPayment) { const amount = !(this.amountPaid as Money).isZero() ? (this.amountPaid as Money) @@ -466,7 +476,7 @@ export class Payment extends Transactional { const initialAmount = this.initialAmount as Money; if (amount.lt(initialAmount) && !amount.eq(initialAmount)) { if (this.writeoff?.isZero()) { - row.amount = this.initialAmount; + this.amount = this.initialAmount; row.amountPaid = this.fyo.pesa(0); throw new ValidationError( this.fyo.t`Enable Partial payment to pay partial amount` @@ -474,10 +484,6 @@ export class Payment extends Transactional { } } } - - const previousOutstandingAmount = referenceDoc.outstandingAmount as Money; - const outstandingAmount = previousOutstandingAmount.sub(row.amount!); - await referenceDoc.setAndSync({ outstandingAmount }); } } @@ -648,23 +654,13 @@ export class Payment extends Transactional { } const reference = this?.for?.[0]; - if (!reference) { - return null; - } - const refDoc = (await reference.loadAndGetLink( + const refDoc = (await reference?.loadAndGetLink( 'referenceName' )) as Invoice | null; const partyDoc = (await this.loadAndGetLink('party')) as Party; const outstanding = partyDoc.outstandingAmount as Money; - if (outstanding.isNegative()) { - if (this.referenceType === ModelNameEnum.PurchaseInvoice) { - return 'Pay'; - } - return 'Receive'; - } - if (partyDoc.role === 'Supplier') { if (refDoc?.isReturn) { return 'Receive'; diff --git a/models/baseModels/tests/testInvoice.spec.ts b/models/baseModels/tests/testInvoice.spec.ts index fa59f0fc..a688b797 100644 --- a/models/baseModels/tests/testInvoice.spec.ts +++ b/models/baseModels/tests/testInvoice.spec.ts @@ -180,7 +180,7 @@ test('create SINV return for balance qty', async (t) => { t.equals( returnDoc.outstandingAmount?.float, - -itemData.rate, + itemData.rate, 'return doc outstanding amount matches' ); }); diff --git a/schemas/app/inventory/InventorySettings.json b/schemas/app/inventory/InventorySettings.json index 1cd3a479..cc445ae8 100644 --- a/schemas/app/inventory/InventorySettings.json +++ b/schemas/app/inventory/InventorySettings.json @@ -57,13 +57,6 @@ "fieldtype": "Check", "section": "Features" }, - { - "fieldname": "enableStockReturns", - "label": "Enable Stock Returns", - "fieldtype": "Check", - "default": false, - "section": "Features" - }, { "fieldname": "enablePointOfSale", "label": "Enable Point of Sale", diff --git a/src/pages/POS/ClassicPOS.vue b/src/pages/POS/ClassicPOS.vue index 1deca7c6..cc28f544 100644 --- a/src/pages/POS/ClassicPOS.vue +++ b/src/pages/POS/ClassicPOS.vue @@ -105,6 +105,7 @@ /> @@ -41,6 +42,7 @@ :show-label="true" :border="true" :required="!transferAmount.isZero()" + :read-only="false" :value="transferClearanceDate" @change="(value:Date) => $emit('setTransferClearanceDate', value)" /> @@ -306,6 +308,10 @@ export default defineComponent({ return true; }, showPaidChange(): boolean { + if (this.sinvDoc.isReturn) { + return false; + } + if ( this.fyo.pesa(this.paidAmount.float).eq(fyo.pesa(0)) && this.transferAmount.eq(fyo.pesa(0)) diff --git a/src/pages/POS/ReturnSalesInvoiceModal.vue b/src/pages/POS/ReturnSalesInvoiceModal.vue index 7ef31682..405b5dc1 100644 --- a/src/pages/POS/ReturnSalesInvoiceModal.vue +++ b/src/pages/POS/ReturnSalesInvoiceModal.vue @@ -108,6 +108,7 @@ import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice'; import { defineComponent, inject } from 'vue'; import { ModelNameEnum } from 'models/types'; import { Field } from 'schemas/types'; +import { Money } from 'pesa'; export default defineComponent({ name: 'ReturnSalesInvoice', @@ -169,7 +170,7 @@ export default defineComponent({ }, filteredInvoices() { return this.returnedInvoices.filter((invoice) => - invoice.name + (invoice.name as string) .toLowerCase() .includes(this.invoiceSearchTerm.toLowerCase()) ); @@ -210,11 +211,28 @@ export default defineComponent({ }); const returnedInvoiceNames = allInvoices - .filter((inv) => inv.returnAgainst) - .map((inv) => inv.returnAgainst); + .filter((inv) => { + if (inv.isReturned) { + return false; + } - this.returnedInvoices = allInvoices.filter( - (inv) => !inv.returnAgainst && !returnedInvoiceNames.includes(inv.name) + if (inv.isReturned && !(inv.outstandingAmount as Money).isZero()) { + return true; + } + + if (!inv.isReturned && !inv.returnAgainst) { + return true; + } + + if (!inv.isReturned && !(inv.outstandingAmount as Money).isZero()) { + return true; + } + + return false; + }) + .map((inv) => inv.name); + this.returnedInvoices = allInvoices.filter((inv) => + returnedInvoiceNames.includes(inv.name) ) as SalesInvoice[]; }, }, diff --git a/src/utils/erpnextSync.ts b/src/utils/erpnextSync.ts index fc305ab9..d83cf018 100644 --- a/src/utils/erpnextSync.ts +++ b/src/utils/erpnextSync.ts @@ -186,7 +186,7 @@ export async function syncDocumentsFromERPNext(fyo: Fyo) { } } } catch (error) { - return await fyo.doc + await fyo.doc .getNewDoc(ErrorLogEnum.IntegrationErrorLog, { error: error as string, data: JSON.stringify({ instance: deviceID, records: docsToSync }), @@ -220,9 +220,7 @@ export async function syncDocumentsFromERPNext(fyo: Fyo) { (doc.erpnextDocName as string) || (doc.name as string), newDoc.name as string ); - } catch (error) { - return error; - } + } catch (error) {} } }