diff --git a/models/baseModels/Invoice/Invoice.ts b/models/baseModels/Invoice/Invoice.ts index 840fb283..825fdb8a 100644 --- a/models/baseModels/Invoice/Invoice.ts +++ b/models/baseModels/Invoice/Invoice.ts @@ -50,6 +50,7 @@ import { CouponCode } from '../CouponCode/CouponCode'; import { SalesInvoice } from '../SalesInvoice/SalesInvoice'; import { SalesInvoiceItem } from '../SalesInvoiceItem/SalesInvoiceItem'; import { PricingRuleItem } from '../PricingRuleItem/PricingRuleItem'; +import { getLinkedEntries } from 'src/utils/doc'; export type TaxDetail = { account: string; @@ -982,6 +983,17 @@ export abstract class Invoice extends Transactional { return null; } + let linkedEntries; + + if (this.returnAgainst) { + const sinvDoc = (await this.fyo.doc.getDoc( + ModelNameEnum.SalesInvoice, + this.returnAgainst + )) as SalesInvoice; + + linkedEntries = await getLinkedEntries(sinvDoc); + } + if (!this.stockNotTransferred) { return null; } @@ -1005,6 +1017,7 @@ export abstract class Invoice extends Transactional { terms, numberSeries, backReference: this.name, + returnAgainst: linkedEntries ? linkedEntries.Shipment![0] : '', }; let location = this.autoStockTransferLocation; diff --git a/schemas/app/inventory/Point of Sale/POSSettings.json b/schemas/app/inventory/Point of Sale/POSSettings.json index cab39a43..b644128d 100644 --- a/schemas/app/inventory/Point of Sale/POSSettings.json +++ b/schemas/app/inventory/Point of Sale/POSSettings.json @@ -55,8 +55,7 @@ "label": "Is POS Shift Open", "fieldtype": "Check", "default": false, - "hidden": true, - "section": "Default" + "hidden": true }, { "fieldname": "weightEnabledBarcode", diff --git a/src/components/POS/types.ts b/src/components/POS/types.ts index 950680c6..1f562ef1 100644 --- a/src/components/POS/types.ts +++ b/src/components/POS/types.ts @@ -17,6 +17,7 @@ export const modalNames = [ 'Alert', 'CouponCode', 'PriceList', + 'ReturnSalesInvoice', ] as const; export type ModalName = typeof modalNames[number]; @@ -35,6 +36,7 @@ export type PosEmits = | 'setTransferAmount' | 'createTransaction' | 'selectedInvoiceName' + | 'selectedReturnInvoice' | 'setTransferClearanceDate'; export interface POSItem { diff --git a/src/pages/POS/ClassicPOS.vue b/src/pages/POS/ClassicPOS.vue index 363d0c54..64ef4486 100644 --- a/src/pages/POS/ClassicPOS.vue +++ b/src/pages/POS/ClassicPOS.vue @@ -56,6 +56,13 @@ " /> + +
-
+
-
+
+
- -
-
- +
+
+ +
+
@@ -323,6 +362,7 @@ import LoyaltyProgramModal from './LoyaltyProgramModal.vue'; import { POSItem, ItemQtyMap } from 'src/components/POS/types'; import ItemsGrid from 'src/components/POS/Classic/ItemsGrid.vue'; import ItemsTable from 'src/components/POS/Classic/ItemsTable.vue'; +import ReturnSalesInvoiceModal from './ReturnSalesInvoiceModal.vue'; import MultiLabelLink from 'src/components/Controls/MultiLabelLink.vue'; import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice'; import SelectedItemTable from 'src/components/POS/Classic/SelectedItemTable.vue'; @@ -352,6 +392,7 @@ export default defineComponent({ LoyaltyProgramModal, WeightEnabledBarcode, FloatingLabelFloatInput, + ReturnSalesInvoiceModal, FloatingLabelCurrencyInput, }, props: { @@ -368,6 +409,7 @@ export default defineComponent({ openSavedInvoiceModal: Boolean, openLoyaltyProgramModal: Boolean, openAppliedCouponsModal: Boolean, + openReturnSalesInvoiceModal: Boolean, totalQuantity: { type: Number, default: 0, @@ -418,6 +460,7 @@ export default defineComponent({ 'createTransaction', 'setTransferAmount', 'selectedInvoiceName', + 'selectedReturnInvoice', 'setTransferClearanceDate', ], data() { @@ -426,6 +469,10 @@ export default defineComponent({ itemSearchTerm: '', }; }, + computed: { + isReturnInvoiceEnabledReturn: () => + fyo.singles.AccountingSettings?.enableInvoiceReturns ?? undefined, + }, methods: { emitEvent( eventName: PosEmits, diff --git a/src/pages/POS/ModernPOS.vue b/src/pages/POS/ModernPOS.vue index b7470809..2e1943bd 100644 --- a/src/pages/POS/ModernPOS.vue +++ b/src/pages/POS/ModernPOS.vue @@ -56,6 +56,13 @@ " /> + +

- {{ t`held` }} + {{ t`Held` }}

@@ -202,8 +209,19 @@

- +
+
@@ -329,6 +359,7 @@ import SavedInvoiceModal from './SavedInvoiceModal.vue'; import Barcode from 'src/components/Controls/Barcode.vue'; import ClosePOSShiftModal from './ClosePOSShiftModal.vue'; import LoyaltyProgramModal from './LoyaltyProgramModal.vue'; +import ReturnSalesInvoiceModal from './ReturnSalesInvoiceModal.vue'; import MultiLabelLink from 'src/components/Controls/MultiLabelLink.vue'; import { POSItem, PosEmits, ItemQtyMap } from 'src/components/POS/types'; import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice'; @@ -362,6 +393,7 @@ export default defineComponent({ ModernPOSItemsTable, WeightEnabledBarcode, FloatingLabelFloatInput, + ReturnSalesInvoiceModal, FloatingLabelCurrencyInput, ModernPOSSelectedItemTable, }, @@ -380,6 +412,7 @@ export default defineComponent({ openSavedInvoiceModal: Boolean, openLoyaltyProgramModal: Boolean, openAppliedCouponsModal: Boolean, + openReturnSalesInvoiceModal: Boolean, totalQuantity: { type: Number, default: 0, @@ -430,6 +463,7 @@ export default defineComponent({ 'createTransaction', 'setTransferAmount', 'selectedInvoiceName', + 'selectedReturnInvoice', 'setTransferClearanceDate', ], data() { @@ -442,6 +476,10 @@ export default defineComponent({ itemSearchTerm: '', }; }, + computed: { + isReturnInvoiceEnabledReturn: () => + fyo.singles.AccountingSettings?.enableInvoiceReturns ?? undefined, + }, methods: { emitEvent( eventName: PosEmits, diff --git a/src/pages/POS/POS.vue b/src/pages/POS/POS.vue index bfc8aa4c..d1322db0 100644 --- a/src/pages/POS/POS.vue +++ b/src/pages/POS/POS.vue @@ -32,6 +32,7 @@ :open-saved-invoice-modal="openSavedInvoiceModal" :open-loyalty-program-modal="openLoyaltyProgramModal" :open-applied-coupons-modal="openAppliedCouponsModal" + :open-return-sales-invoice-modal="openReturnSalesInvoiceModal" @add-item="addItem" @toggle-view="toggleView" @set-sinv-doc="setSinvDoc" @@ -49,6 +50,7 @@ @save-invoice-action="saveInvoiceAction" @set-transfer-amount="setTransferAmount" @selected-invoice-name="selectedInvoiceName" + @selected-return-invoice="selectedReturnInvoice" @set-transfer-clearance-date="setTransferClearanceDate" /> @@ -188,6 +192,7 @@ export default defineComponent({ openSavedInvoiceModal: false, openLoyaltyProgramModal: false, openAppliedCouponsModal: false, + openReturnSalesInvoiceModal: false, totalQuantity: 0, paidAmount: fyo.pesa(0), @@ -396,6 +401,20 @@ export default defineComponent({ }); } }, + async selectedReturnInvoice(invoiceName: string) { + const salesInvoiceDoc = (await this.fyo.doc.getDoc( + ModelNameEnum.SalesInvoice, + invoiceName + )) as SalesInvoice; + + let returnDoc = (await salesInvoiceDoc.getReturnDoc()) as SalesInvoice; + + if (!returnDoc || !returnDoc.name) { + return; + } + + this.sinvDoc = returnDoc; + }, toggleView() { this.tableView = !this.tableView; }, @@ -481,16 +500,23 @@ export default defineComponent({ setTransferRefNo(ref: string) { this.transferRefNo = ref; }, + validateInvoice() { + if (this.sinvDoc.isSubmitted) { + throw new ValidationError( + t`Cannot add an item to a submitted invoice.` + ); + } + if (this.sinvDoc.returnAgainst) { + throw new ValidationError( + t`Unable to add an item to the return invoice.` + ); + } + }, async addItem(item: POSItem | Item | undefined, quantity?: number) { try { await this.sinvDoc.runFormulas(); - - if (this.sinvDoc.isSubmitted) { - throw new ValidationError( - t`Cannot add an item to a submitted invoice.` - ); - } + this.validateInvoice(); if (!item) { return; @@ -626,7 +652,7 @@ export default defineComponent({ if (paymentMethodDoc?.type !== 'Cash') { await this.paymentDoc.setMultiple({ - amount: this.paidAmount as Money, + amount: this.fyo.pesa(this.paidAmount as unknown as number).abs(), referenceId: this.transferRefNo, clearanceDate: this.transferClearanceDate, }); @@ -635,7 +661,7 @@ export default defineComponent({ if (paymentMethodDoc?.type === 'Cash') { await this.paymentDoc.setMultiple({ paymentAccount: this.defaultPOSCashAccount, - amount: this.paidAmount as Money, + amount: this.fyo.pesa(this.paidAmount as unknown as number).abs(), }); } diff --git a/src/pages/POS/PaymentModal.vue b/src/pages/POS/PaymentModal.vue index bdde65a6..ce2d64bd 100644 --- a/src/pages/POS/PaymentModal.vue +++ b/src/pages/POS/PaymentModal.vue @@ -318,7 +318,8 @@ export default defineComponent({ if ( (this.sinvDoc.grandTotal?.float as number) < 1 && - this.fyo.pesa(this.paidAmount.float).isZero() + this.fyo.pesa(this.paidAmount.float).isZero() && + !this.sinvDoc.returnAgainst ) { return true; } @@ -334,7 +335,8 @@ export default defineComponent({ disablePayButton(): boolean { if ( (this.sinvDoc.grandTotal?.float as number) < 1 && - this.fyo.pesa(this.paidAmount.float).isZero() + this.fyo.pesa(this.paidAmount.float).isZero() && + !this.sinvDoc.returnAgainst ) { return true; } @@ -345,6 +347,7 @@ export default defineComponent({ ) { return true; } + return false; }, }, diff --git a/src/pages/POS/ReturnSalesInvoiceModal.vue b/src/pages/POS/ReturnSalesInvoiceModal.vue new file mode 100644 index 00000000..e77c0160 --- /dev/null +++ b/src/pages/POS/ReturnSalesInvoiceModal.vue @@ -0,0 +1,179 @@ + + + diff --git a/src/pages/POS/SavedInvoiceModal.vue b/src/pages/POS/SavedInvoiceModal.vue index 3db5f3f9..2ba9e5cf 100644 --- a/src/pages/POS/SavedInvoiceModal.vue +++ b/src/pages/POS/SavedInvoiceModal.vue @@ -129,7 +129,6 @@ export default defineComponent({ savedInvoiceList: true, savedInvoices: [] as SalesInvoice[], submittedInvoices: [] as SalesInvoice[], - isModalVisible: false, }; }, computed: { diff --git a/src/utils/pos.ts b/src/utils/pos.ts index 4c3018b4..221e2758 100644 --- a/src/utils/pos.ts +++ b/src/utils/pos.ts @@ -81,15 +81,20 @@ export function validateSinv(sinvDoc: SalesInvoice, itemQtyMap: ItemQtyMap) { return; } - validateSinvItems(sinvDoc.items as SalesInvoiceItem[], itemQtyMap); + validateSinvItems( + sinvDoc.items as SalesInvoiceItem[], + itemQtyMap, + sinvDoc.returnAgainst as string + ); } function validateSinvItems( sinvItems: SalesInvoiceItem[], - itemQtyMap: ItemQtyMap + itemQtyMap: ItemQtyMap, + isReturn?: string ) { for (const item of sinvItems) { - if (!item.quantity || item.quantity < 1) { + if (!item.quantity || (item.quantity < 1 && !isReturn)) { throw new ValidationError( t`Invalid Quantity for Item ${item.item as string}` );