Files
books/src/pages/POS/ClassicPOS.vue
T

553 lines
18 KiB
Vue

<template>
<div>
<OpenPOSShiftModal
v-if="!isPosShiftOpen"
:open-modal="!isPosShiftOpen"
@toggle-modal="emitEvent('toggleModal', 'ShiftOpen')"
/>
<ClosePOSShiftModal
:open-modal="openShiftCloseModal"
@toggle-modal="emitEvent('toggleModal', 'ShiftClose')"
/>
<LoyaltyProgramModal
:open-modal="openLoyaltyProgramModal"
:loyalty-points="loyaltyPoints"
:loyalty-program="loyaltyProgram"
@toggle-modal="emitEvent('toggleModal', 'LoyaltyProgram')"
@set-loyalty-points="(points) => emitEvent('setLoyaltyPoints', points)"
/>
<BatchSelectionModal
:open-modal="openBatchSelectionModal"
:item-code="selectedItemForBatch"
@toggle-modal="emitEvent('toggleModal', 'BatchSelection')"
@batch-selected="(batch) => emitEvent('batchSelected', batch)"
/>
<SavedInvoiceModal
:open-modal="openSavedInvoiceModal"
:modal-status="openSavedInvoiceModal"
@toggle-modal="emitEvent('toggleModal', 'SavedInvoice')"
@selected-invoice-name="
(invName) => emitEvent('selectedInvoiceName', invName)
"
/>
<CouponCodeModal
:open-modal="openCouponCodeModal"
@apply-pricing-rule="emitEvent('applyPricingRule')"
@toggle-modal="emitEvent('toggleModal', 'CouponCode')"
@set-coupons-count="(count) => emitEvent('setCouponsCount', count)"
/>
<PriceListModal
:open-modal="openPriceListModal"
@toggle-modal="emitEvent('toggleModal', 'PriceList')"
/>
<ItemEnquiryModal
:open-modal="openItemEnquiryModal"
@toggle-modal="emitEvent('toggleModal', 'ItemEnquiry')"
/>
<PaymentModal
:open-modal="openPaymentModal"
@toggle-modal="emitEvent('toggleModal', 'Payment')"
@set-paid-amount="(amount: Money) => emitEvent('setPaidAmount', amount)"
@set-payment-method="
(paymentMethod) => emitEvent('setPaymentMethod', paymentMethod)
"
@set-transfer-ref-no="(ref) => emitEvent('setTransferRefNo', ref)"
@set-transfer-clearance-date="
(date) => emitEvent('setTransferClearanceDate', date)
"
@create-transaction="
(print, status) => emitEvent('createTransaction', print, status)
"
/>
<ReturnSalesInvoiceModal
:open-modal="openReturnSalesInvoiceModal"
:modal-status="openReturnSalesInvoiceModal"
@selected-return-invoice="(value:any) => emitEvent('selectedReturnInvoice', value)"
@toggle-modal="emitEvent('toggleModal', 'ReturnSalesInvoice')"
/>
<AlertModal
:open-modal="openAlertModal"
@toggle-modal="emitEvent('toggleModal', 'Alert')"
@save-and-continue="(value:any)=>emitEvent('saveAndContinue',value)"
/>
<div
class="bg-gray-25 dark:bg-gray-875 grid grid-cols-12 gap-2 p-4"
style="height: calc(100vh - var(--h-row-largest))"
>
<div
class="
col-span-5
bg-white
border
rounded-md
dark:border-gray-800 dark:bg-gray-850
"
>
<div class="rounded-md p-4 col-span-5">
<div class="flex gap-x-2">
<!-- Item Search -->
<MultiLabelLink
class="w-full"
secondary-link="barcode"
third-link="itemCode"
:df="{
label: t`Search Item (Name or
Barcode)`,
fieldtype: 'Link',
fieldname: 'item',
target: 'Item',
}"
:border="true"
:value="itemSearchTerm"
:show-clear-button="true"
@keyup.enter="(event: KeyboardEvent) => emitEvent('handleItemSearch', (event.target as HTMLInputElement).value, true)"
@change="(item: string) => emitEvent('handleItemSearch', item)"
/>
<Link
v-if="fyo.singles.AccountingSettings?.enableitemGroup"
:df="{
label: t`Filter by Group`,
fieldtype: 'Link',
fieldname: 'itemGroup',
target: 'ItemGroup',
}"
:border="true"
:show-clear-button="true"
:value="selectedItemGroup"
@change="(group: string) => emitEvent('setItemGroup',group)"
/>
</div>
<ItemsTable
v-if="tableView"
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item) => emitEvent('addItem', item)"
/>
<ItemsGrid
v-else
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item) => emitEvent('addItem', item)"
/>
<div class="flex fixed bottom-0 p-1 mb-7 gap-x-3">
<POSQuickActions
:sinv-doc="sinvDoc"
:loyalty-points="loyaltyPoints"
:loyalty-program="loyaltyProgram"
:applied-coupons-count="appliedCouponsCount"
@toggle-view="emitEvent('toggleView')"
@emit-route-to-sinv-list="emitEvent('routeToSinvList')"
@toggle-modal="(modalName) => emitEvent('toggleModal', modalName)"
/>
</div>
</div>
</div>
<div class="col-span-7">
<div class="flex flex-col gap-3" style="height: calc(100vh - 6rem)">
<div
class="
p-4
bg-white
border
rounded-md
grow
h-full
dark:border-gray-800 dark:bg-gray-850
"
>
<!-- Customer Search -->
<MultiLabelLink
v-if="sinvDoc?.fieldMap"
class="flex-shrink-0"
secondary-link="phone"
:border="true"
:value="sinvDoc?.party"
:df="sinvDoc?.fieldMap.party"
:show-clear-button="true"
@change="(value:string) => $emit('setCustomer',value)"
/>
<SelectedItemTable
@apply-pricing-rule="emitEvent('applyPricingRule')"
@selected-row="(row) => $emit('selectedRow', row)"
/>
</div>
<div
class="
p-3
bg-white
border
rounded-md
dark:border-gray-800 dark:bg-gray-850
"
>
<div class="w-full grid grid-cols-2 gap-y-2 gap-x-3">
<div class="flex flex-col justify-end">
<div class="grid grid-cols-2 gap-2">
<FloatingLabelFloatInput
:df="{
label: t`Total Quantity`,
fieldtype: 'Int',
fieldname: 'totalQuantity',
minvalue: 0,
maxvalue: 1000,
}"
size="large"
:value="totalQuantity"
:read-only="true"
:text-right="true"
/>
<FloatingLabelCurrencyInput
:df="{
label: t`Add'l Discounts`,
fieldtype: 'Int',
fieldname: 'additionalDiscount',
minvalue: 0,
}"
size="large"
:value="additionalDiscounts"
:read-only="true"
:text-right="true"
@change="(amount:Money)=> additionalDiscounts= amount"
/>
</div>
<div class="mt-4 grid grid-cols-2 gap-2">
<FloatingLabelCurrencyInput
:df="{
label: t`Item Discounts`,
fieldtype: 'Currency',
fieldname: 'itemDiscounts',
}"
size="large"
:value="itemDiscounts"
:read-only="true"
:text-right="true"
/>
<FloatingLabelCurrencyInput
v-if="sinvDoc?.fieldMap"
:df="sinvDoc?.fieldMap.grandTotal"
size="large"
:value="sinvDoc?.grandTotal"
:read-only="true"
:text-right="true"
/>
</div>
</div>
<div class="w-full">
<div class="w-full flex gap-2">
<Button
class="w-full"
:style="{
backgroundColor:
profile?.saveButtonColour ||
fyo.singles.Defaults?.saveButtonColour,
}"
:class="`${isReturnInvoiceEnabledReturn ? 'py-5' : 'py-6'}`"
@click="$emit('saveInvoiceAction')"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Save` }}
</p>
</slot>
</Button>
<Button
class="w-full"
:style="{
backgroundColor:
profile?.cancelButtonColour ||
fyo.singles.Defaults?.cancelButtonColour,
}"
:class="`${isReturnInvoiceEnabledReturn ? 'py-5' : 'py-6'}`"
@click="() => $emit('clearValues')"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Cancel` }}
</p>
</slot>
</Button>
</div>
<div
class="w-full flex gap-2"
:class="`${isReturnInvoiceEnabledReturn ? 'mt-2' : 'mt-4'}`"
>
<Button
class="w-full"
:style="{
backgroundColor:
profile?.heldButtonColour ||
fyo.singles.Defaults?.heldButtonColour,
}"
:class="`${isReturnInvoiceEnabledReturn ? 'py-5' : 'py-6'}`"
@click="emitEvent('toggleModal', 'SavedInvoice', true)"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`held` }}
</p>
</slot>
</Button>
<Button
v-if="isReturnInvoiceEnabledReturn"
class="w-full py-5"
:style="{
backgroundColor:
profile?.returnButtonColour ||
fyo.singles.Defaults?.returnButtonColour,
}"
@click="
emitEvent('toggleModal', 'ReturnSalesInvoice', true)
"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Return` }}
</p>
</slot>
</Button>
<Button
v-else
class="w-full"
:style="{
backgroundColor:
profile?.payButton ||
fyo.singles.Defaults?.payButtonColour,
}"
:class="`${isReturnInvoiceEnabledReturn ? 'py-5' : 'py-6'}`"
@click="emitEvent('handlePaymentAction')"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Pay` }}
</p>
</slot>
</Button>
</div>
<Button
v-if="isReturnInvoiceEnabledReturn"
class="w-full mt-2 py-5"
:style="{
backgroundColor:
profile?.payButtonColour ||
fyo.singles.Defaults?.payButtonColour,
}"
@click="emitEvent('handlePaymentAction')"
>
<slot>
<p class="uppercase text-lg text-white font-semibold">
{{ t`Pay` }}
</p>
</slot>
</Button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Money } from 'pesa';
import { fyo } from 'src/initFyo';
import { getItem } from 'src/utils/pos';
import AlertModal from './AlertModal.vue';
import PaymentModal from './PaymentModal.vue';
import Button from 'src/components/Button.vue';
import { defineComponent, PropType } from 'vue';
import PriceListModal from './PriceListModal.vue';
import ItemEnquiryModal from './ItemEnquiryModal.vue';
import { Item } from 'models/baseModels/Item/Item';
import CouponCodeModal from './CouponCodeModal.vue';
import POSQuickActions from './POSQuickActions.vue';
import { PosEmits } from 'src/components/POS/types';
import Link from 'src/components/Controls/Link.vue';
import SavedInvoiceModal from './SavedInvoiceModal.vue';
import OpenPOSShiftModal from './OpenPOSShiftModal.vue';
import ClosePOSShiftModal from './ClosePOSShiftModal.vue';
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 { POSProfile } from 'models/baseModels/POSProfile/PosProfile';
import MultiLabelLink from 'src/components/Controls/MultiLabelLink.vue';
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
import SelectedItemTable from 'src/components/POS/Classic/SelectedItemTable.vue';
import FloatingLabelFloatInput from 'src/components/POS/FloatingLabelFloatInput.vue';
import FloatingLabelCurrencyInput from 'src/components/POS/FloatingLabelCurrencyInput.vue';
import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes';
import BatchSelectionModal from 'src/pages/POS/BatchSelectionModal.vue';
export default defineComponent({
name: 'ClassicPOS',
components: {
Link,
Button,
ItemsGrid,
AlertModal,
ItemsTable,
PaymentModal,
MultiLabelLink,
PriceListModal,
ItemEnquiryModal,
CouponCodeModal,
POSQuickActions,
OpenPOSShiftModal,
SelectedItemTable,
SavedInvoiceModal,
ClosePOSShiftModal,
LoyaltyProgramModal,
FloatingLabelFloatInput,
ReturnSalesInvoiceModal,
FloatingLabelCurrencyInput,
BatchSelectionModal,
},
props: {
paidAmount: Money,
tableView: Boolean,
itemDiscounts: Money,
openAlertModal: Boolean,
isPosShiftOpen: Boolean,
disablePayButton: Boolean,
openPaymentModal: Boolean,
openPriceListModal: Boolean,
openItemEnquiryModal: Boolean,
openCouponCodeModal: Boolean,
openShiftCloseModal: Boolean,
openSavedInvoiceModal: Boolean,
openLoyaltyProgramModal: Boolean,
openAppliedCouponsModal: Boolean,
openReturnSalesInvoiceModal: Boolean,
openBatchSelectionModal: Boolean,
totalQuantity: {
type: Number,
default: 0,
},
loyaltyPoints: {
type: Number,
default: 0,
},
itemSearchTerm: {
type: String,
default: '',
},
selectedItemGroup: {
type: String,
default: '',
},
loyaltyProgram: {
type: String,
default: '',
},
appliedCouponsCount: {
type: Number,
default: 0,
},
sinvDoc: {
type: Object as PropType<SalesInvoice | undefined>,
default: undefined,
},
itemQuantityMap: {
type: Object as PropType<ItemQtyMap>,
default: () => ({}),
},
coupons: {
type: Object as PropType<AppliedCouponCodes>,
default: () => ({}),
},
items: {
type: Array as PropType<POSItem[] | undefined>,
default: () => [],
},
isErpSync: {
type: Boolean,
default: false,
},
profile: {
type: Object as PropType<POSProfile>,
required: false,
default: null,
},
batchAddedItems: {
type: Array as () => string[],
default: () => [],
},
selectedItemForBatch: {
type: String,
default: '',
},
},
emits: [
'addItem',
'toggleView',
'toggleModal',
'setCustomer',
'clearValues',
'setItemGroup',
'setPaidAmount',
'setCouponsCount',
'routeToSinvList',
'handleItemSearch',
'setPaymentMethod',
'setTransferRefNo',
'setLoyaltyPoints',
'applyPricingRule',
'saveInvoiceAction',
'createTransaction',
'setTransferAmount',
'selectedInvoiceName',
'selectedReturnInvoice',
'setTransferClearanceDate',
'saveAndContinue',
'handlePaymentAction',
'selectedRow',
'batchSelected',
],
data() {
return {
itemGroupFilter: '',
additionalDiscounts: fyo.pesa(0),
};
},
computed: {
isReturnInvoiceEnabledReturn: () =>
fyo.singles.AccountingSettings?.enableInvoiceReturns ?? undefined,
},
methods: {
emitEvent(
eventName: PosEmits,
...args: (string | boolean | Item | number | Money)[]
) {
this.$emit(eventName, ...args);
},
getItem,
},
});
</script>