Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: save invoice and hold invoice for later use in POS #975

Merged
merged 9 commits into from
Oct 15, 2024
2 changes: 1 addition & 1 deletion src/components/POS/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type ItemSerialNumbers = { [item: string]: string };

export type DiscountType = "percent" | "amount";

export type ModalName = 'ShiftOpen' | 'ShiftClose' | 'Payment' | 'LoyaltyProgram' | 'RouteToInvoiceList'
export type ModalName = 'ShiftOpen' | 'ShiftClose' | 'Payment' | 'LoyaltyProgram' | 'SavedInvoice' | 'RouteToInvoiceList'

export interface POSItem {
image?:string,
Expand Down
125 changes: 98 additions & 27 deletions src/pages/POS/POS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
@set-loyalty-points="setLoyaltyPoints"
@toggle-modal="toggleModal"
/>
<SavedInvoiceModal
:open-modal="openSavedInvoiceModal"
:modal-status="openSavedInvoiceModal"
@selected-invoice-name="selectedInvoiceName"
@toggle-modal="toggleModal"
/>

<PaymentModal
:open-modal="openPaymentModal"
Expand Down Expand Up @@ -325,31 +331,55 @@
/>
</div>
</div>

<div class="">
<Button
class="w-full bg-red-500 dark:bg-red-700 py-6"
:disabled="!sinvDoc.items?.length"
@click="clearValues"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Cancel` }}
</p>
</slot>
</Button>

<Button
class="mt-4 w-full bg-green-500 dark:bg-green-700 py-6"
:disabled="disablePayButton"
@click="toggleModal('Payment', true)"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Pay` }}
</p>
</slot>
</Button>
<div class="flex w-full gap-2">
<div class="w-full">
<Button
class="w-full bg-violet-500 dark:bg-violet-700 py-6"
:disabled="!sinvDoc.party || !sinvDoc.items?.length"
@click="handleSaveInvoiceAction"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Save` }}
</p>
</slot>
</Button>
<Button
class="w-full mt-4 bg-blue-500 dark:bg-blue-700 py-6"
@click="toggleModal('SavedInvoice', true)"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`held` }}
</p>
</slot>
</Button>
</div>
<div class="w-full">
<Button
class="w-full bg-red-500 dark:bg-red-700 py-6"
:disabled="!sinvDoc.items?.length"
@click="clearValues"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Cancel` }}
</p>
</slot>
</Button>

<Button
class="mt-4 w-full bg-green-500 dark:bg-green-700 py-6"
:disabled="disablePayButton"
@click="toggleModal('Payment', true)"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Pay` }}
</p>
</slot>
</Button>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -403,6 +433,7 @@ import Barcode from 'src/components/Controls/Barcode.vue';
import { getAddedLPWithGrandTotal, getPricingRule } from 'models/helpers';
import LoyaltyProgramModal from './LoyaltyprogramModal.vue';
import AlertModal from './AlertModal.vue';
import SavedInvoiceModal from './SavedInvoiceModal.vue';

export default defineComponent({
name: 'POS',
Expand All @@ -419,6 +450,7 @@ export default defineComponent({
PageHeader,
PaymentModal,
LoyaltyProgramModal,
SavedInvoiceModal,
SelectedItemTable,
Barcode,
},
Expand Down Expand Up @@ -446,6 +478,7 @@ export default defineComponent({
isItemsSeeded: false,
openPaymentModal: false,
openLoyaltyProgramModal: false,
openSavedInvoiceModal: false,
openShiftCloseModal: false,
openShiftOpenModal: false,
openRouteToInvoiceListModal: false,
Expand Down Expand Up @@ -541,6 +574,26 @@ export default defineComponent({
this.loyaltyProgram = party[0]?.loyaltyProgram as string;
this.loyaltyPoints = party[0].loyaltyPoints as number;
},
async saveOrder() {
try {
await this.validate();
await this.sinvDoc.runFormulas();
await this.sinvDoc.sync();
} catch (error) {
return showToast({
type: 'error',
message: t`${error as string}`,
});
}

showToast({
type: 'success',
message: t`Sales Invoice ${this.sinvDoc.name as string} is Saved`,
duration: 'short',
});

await this.afterSync();
},
async setItems() {
const items = (await fyo.db.getAll(ModelNameEnum.Item, {
fields: [],
Expand Down Expand Up @@ -620,6 +673,15 @@ export default defineComponent({

this.sinvDoc.grandTotal = total;
},
async selectedInvoiceName(doc: SalesInvoice) {
const salesInvoiceDoc = (await this.fyo.doc.getDoc(
ModelNameEnum.SalesInvoice,
doc.name
)) as SalesInvoice;

this.sinvDoc = salesInvoiceDoc;
this.toggleModal('SavedInvoice', false);
},
setTransferAmount(amount: Money = fyo.pesa(0)) {
this.transferAmount = amount;
},
Expand Down Expand Up @@ -832,7 +894,10 @@ export default defineComponent({
});
}
},

async afterSync() {
await this.clearValues();
this.setSinvDoc();
},
async afterTransaction() {
await this.setItemQtyMap();
await this.clearValues();
Expand Down Expand Up @@ -890,12 +955,18 @@ export default defineComponent({
}, 1);
},
async routeToSinvList() {
if (!this.sinvDoc.items.length) {
if (!this.sinvDoc.items?.length) {
return await routeTo('/list/SalesInvoice');
}

this.openRouteToInvoiceListModal = true;
},
async handleSaveInvoiceAction() {
if (!this.sinvDoc.party && !this.sinvDoc.items?.length) {
return;
}
await this.saveOrder();
},
routeTo,
getItem,
},
Expand Down
186 changes: 186 additions & 0 deletions src/pages/POS/SavedInvoiceModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<template>
<Modal class="h-auto w-auto p-6" :set-close-listener="false">
<p class="text-center font-semibold">{{ t`Saved Invoices` }}</p>

<hr class="mt-2 dark:border-gray-800" />

<Row
:ratio="ratio"
class="
border
flex
items-center
mt-4
px-2
w-full
rounded-t-md
text-gray-600
dark:border-gray-800 dark:text-gray-400
"
>
<div
v-for="df in tableFields"
:key="df.fieldname"
class="flex items-center px-2 py-2 text-lg"
>
{{ df.label }}
</div>
</Row>

<div
v-if="savedInvoices.length"
class="overflow-y-auto custom-scroll custom-scroll-thumb2"
style="height: 65vh; width: 60vh"
>
<Row
v-for="row in savedInvoices as any"
:key="row.name"
:ratio="ratio"
:border="true"
class="
border-b border-l border-r
dark:border-gray-800 dark:bg-gray-890
flex
group
h-row-mid
hover:bg-gray-25
items-center
justify-center
px-2
w-full
"
@click="$emit('selectedInvoiceName', row)"
>
<FormControl
v-for="df in tableFields"
:key="df.fieldname"
size="large"
:df="df"
:value="row[df.fieldname]"
:read-only="true"
/>
</Row>
</div>

<div class="row-start-6 grid grid-cols-2 gap-4 mt-4">
<div class="col-span-2">
<Button
class="w-full p-5 bg-red-500 dark:bg-red-700"
@click="$emit('toggleModal', 'SavedInvoice')"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Cancel` }}
</p>
</slot>
</Button>
</div>
</div>
</Modal>
</template>

<script lang="ts">
import Button from 'src/components/Button.vue';
import Modal from 'src/components/Modal.vue';
import Row from 'src/components/Row.vue';
import FormControl from 'src/components/Controls/FormControl.vue';
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
import { defineComponent, inject } from 'vue';
import { ModelNameEnum } from 'models/types';
import { Field } from 'schemas/types';

export default defineComponent({
name: 'SavedInvoiceModal',
components: {
Modal,
Button,
FormControl,
Row,
},
props: {
modalStatus: Boolean,
},
emits: ['toggleModal', 'selectedInvoiceName'],
setup() {
return {
sinvDoc: inject('sinvDoc') as SalesInvoice,
};
},
data() {
return {
savedInvoices: [] as SalesInvoice[],
isModalVisible: false,
};
},
computed: {
ratio() {
return [1, 1, 1, 0.8];
},
tableFields() {
return [
{
fieldname: 'name',
label: 'Name',
fieldtype: 'Link',
target: 'SalesInvoice',
readOnly: true,
},
{
fieldname: 'party',
fieldtype: 'Link',
label: 'Customer',
target: 'Party',
placeholder: 'Customer',
readOnly: true,
},
{
fieldname: 'date',
label: 'Date',
fieldtype: 'Date',
readOnly: true,
},
{
fieldname: 'grandTotal',
label: 'Grand Total',
fieldtype: 'Currency',
readOnly: true,
},
] as Field[];
},
},
watch: {
async modalStatus(newVal) {
if (newVal) {
await this.setSavedInvoices();
}
},
},
async mounted() {
await this.setSavedInvoices();
},
async activated() {
await this.setSavedInvoices();
},

methods: {
async setSavedInvoices() {
this.savedInvoices = (await this.fyo.db.getAll(
ModelNameEnum.SalesInvoice,
{
fields: [],
filters: { isPOS: true, submitted: false },
}
)) as SalesInvoice[];
},
async selectedInvoice(row: SalesInvoice) {
let selectedInvoiceDoc = (await this.fyo.doc.getDoc(
ModelNameEnum.SalesInvoice,
row.name
)) as SalesInvoice;

this.sinvDoc = selectedInvoiceDoc;
this.$emit('toggleModal', 'SavedInvoice');
},
},
});
</script>
Loading