mirror of
https://github.com/frappe/books.git
synced 2025-02-08 23:18:31 +00:00
Merge pull request #975 from AbleKSaju/feat-pos-save-order
feat: save invoice and hold invoice for later use in POS
This commit is contained in:
commit
6fb81a56d7
@ -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,
|
||||
|
@ -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"
|
||||
@ -325,31 +331,55 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
@ -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',
|
||||
@ -419,6 +450,7 @@ export default defineComponent({
|
||||
PageHeader,
|
||||
PaymentModal,
|
||||
LoyaltyProgramModal,
|
||||
SavedInvoiceModal,
|
||||
SelectedItemTable,
|
||||
Barcode,
|
||||
},
|
||||
@ -446,6 +478,7 @@ export default defineComponent({
|
||||
isItemsSeeded: false,
|
||||
openPaymentModal: false,
|
||||
openLoyaltyProgramModal: false,
|
||||
openSavedInvoiceModal: false,
|
||||
openShiftCloseModal: false,
|
||||
openShiftOpenModal: false,
|
||||
openRouteToInvoiceListModal: false,
|
||||
@ -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: [],
|
||||
@ -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;
|
||||
},
|
||||
@ -832,7 +894,10 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async afterSync() {
|
||||
await this.clearValues();
|
||||
this.setSinvDoc();
|
||||
},
|
||||
async afterTransaction() {
|
||||
await this.setItemQtyMap();
|
||||
await this.clearValues();
|
||||
@ -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,
|
||||
},
|
||||
|
186
src/pages/POS/SavedInvoiceModal.vue
Normal file
186
src/pages/POS/SavedInvoiceModal.vue
Normal file
@ -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…
x
Reference in New Issue
Block a user