mirror of
https://github.com/frappe/books.git
synced 2024-11-14 09:24:04 +00:00
Merge pull request #969 from AbleKSaju/feat-pos-coupon-code
feat: Coupon Code functionality in POS
This commit is contained in:
commit
20ecdf8dc6
@ -1,11 +1,7 @@
|
|||||||
import { DocValue } from 'fyo/core/types';
|
import { DocValue } from 'fyo/core/types';
|
||||||
import { ValidationMap } from 'fyo/model/types';
|
import { ValidationMap } from 'fyo/model/types';
|
||||||
import { ValidationError } from 'fyo/utils/errors';
|
|
||||||
import { ModelNameEnum } from 'models/types';
|
|
||||||
import { Money } from 'pesa';
|
|
||||||
import { InvoiceItem } from '../InvoiceItem/InvoiceItem';
|
import { InvoiceItem } from '../InvoiceItem/InvoiceItem';
|
||||||
import { getApplicableCouponCodesName } from 'models/helpers';
|
import { validateCouponCode } from 'models/helpers';
|
||||||
import { SalesInvoice } from '../SalesInvoice/SalesInvoice';
|
|
||||||
|
|
||||||
export class AppliedCouponCodes extends InvoiceItem {
|
export class AppliedCouponCodes extends InvoiceItem {
|
||||||
coupons?: string;
|
coupons?: string;
|
||||||
@ -16,92 +12,7 @@ export class AppliedCouponCodes extends InvoiceItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coupon = await this.fyo.db.getAll(ModelNameEnum.CouponCode, {
|
await validateCouponCode(this as AppliedCouponCodes, value as string);
|
||||||
fields: [
|
|
||||||
'minAmount',
|
|
||||||
'maxAmount',
|
|
||||||
'pricingRule',
|
|
||||||
'validFrom',
|
|
||||||
'validTo',
|
|
||||||
'maximumUse',
|
|
||||||
'used',
|
|
||||||
'isEnabled',
|
|
||||||
],
|
|
||||||
filters: { name: value as string },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!coupon[0].isEnabled) {
|
|
||||||
throw new ValidationError(
|
|
||||||
'Coupon code cannot be applied as it is not enabled'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((coupon[0]?.maximumUse as number) <= (coupon[0]?.used as number)) {
|
|
||||||
throw new ValidationError(
|
|
||||||
'Coupon code has been used maximum number of times'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const applicableCouponCodesNames = await getApplicableCouponCodesName(
|
|
||||||
value as string,
|
|
||||||
this.parentdoc as SalesInvoice
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!applicableCouponCodesNames?.length) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`Coupon ${
|
|
||||||
value as string
|
|
||||||
} is not applicable for applied items.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const couponExist = this.parentdoc?.coupons?.some(
|
|
||||||
(coupon) => coupon?.coupons === value
|
|
||||||
);
|
|
||||||
|
|
||||||
if (couponExist) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`${value as string} already applied.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(coupon[0].minAmount as Money).gte(
|
|
||||||
this.parentdoc?.grandTotal as Money
|
|
||||||
) &&
|
|
||||||
!(coupon[0].minAmount as Money).isZero()
|
|
||||||
) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`The Grand Total must exceed ${
|
|
||||||
(coupon[0].minAmount as Money).float
|
|
||||||
} to apply the coupon ${value as string}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(coupon[0].maxAmount as Money).lte(
|
|
||||||
this.parentdoc?.grandTotal as Money
|
|
||||||
) &&
|
|
||||||
!(coupon[0].maxAmount as Money).isZero()
|
|
||||||
) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`The Grand Total must be less than ${
|
|
||||||
(coupon[0].maxAmount as Money).float
|
|
||||||
} to apply this coupon.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((coupon[0].validFrom as Date) > (this.parentdoc?.date as Date)) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`Valid From Date should be less than Valid To Date.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((coupon[0].validTo as Date) < (this.parentdoc?.date as Date)) {
|
|
||||||
throw new ValidationError(
|
|
||||||
this.fyo.t`Valid To Date should be greater than Valid From Date.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Fyo, t } from 'fyo';
|
import { Fyo } from 'fyo';
|
||||||
import { DocValueMap } from 'fyo/core/types';
|
import { DocValueMap } from 'fyo/core/types';
|
||||||
import { Doc } from 'fyo/model/doc';
|
import { Doc } from 'fyo/model/doc';
|
||||||
import {
|
import {
|
||||||
@ -1355,14 +1355,6 @@ export abstract class Invoice extends Transactional {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (duplicatePricingRule && duplicatePricingRule?.length >= 2) {
|
if (duplicatePricingRule && duplicatePricingRule?.length >= 2) {
|
||||||
const { showToast } = await import('src/utils/interactive');
|
|
||||||
const message = t`Pricing Rule '${
|
|
||||||
duplicatePricingRule[0]?.referenceName as string
|
|
||||||
}' is already applied to item '${
|
|
||||||
item.item as string
|
|
||||||
}' in another batch.`;
|
|
||||||
showToast({ type: 'error', message });
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ import { isPesa } from 'fyo/utils';
|
|||||||
import { Party } from './baseModels/Party/Party';
|
import { Party } from './baseModels/Party/Party';
|
||||||
import { CouponCode } from './baseModels/CouponCode/CouponCode';
|
import { CouponCode } from './baseModels/CouponCode/CouponCode';
|
||||||
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
||||||
|
import { AppliedCouponCodes } from './baseModels/AppliedCouponCodes/AppliedCouponCodes';
|
||||||
|
import { ValidationError } from 'fyo/utils/errors';
|
||||||
|
|
||||||
export function getQuoteActions(
|
export function getQuoteActions(
|
||||||
fyo: Fyo,
|
fyo: Fyo,
|
||||||
@ -794,8 +796,59 @@ export async function removeLoyaltyPoint(doc: Doc) {
|
|||||||
await party.updateLoyaltyPoints();
|
await party.updateLoyaltyPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getPricingRulesOfCoupons(
|
||||||
|
doc: SalesInvoice,
|
||||||
|
couponName?: string,
|
||||||
|
pricingRuleDocNames?: string[]
|
||||||
|
): Promise<PricingRule[] | undefined> {
|
||||||
|
if (!doc?.coupons?.length && !couponName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let appliedCoupons: CouponCode[] = [];
|
||||||
|
|
||||||
|
const couponsToFetch = couponName
|
||||||
|
? [couponName]
|
||||||
|
: (doc?.coupons?.map((coupon) => coupon.coupons) as string[] | []);
|
||||||
|
|
||||||
|
if (couponsToFetch?.length) {
|
||||||
|
appliedCoupons = (await doc.fyo.db.getAll(ModelNameEnum.CouponCode, {
|
||||||
|
fields: ['*'],
|
||||||
|
filters: { name: ['in', couponsToFetch] },
|
||||||
|
})) as CouponCode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('pricingRuleDocNames', pricingRuleDocNames);
|
||||||
|
|
||||||
|
const filteredPricingRuleNames = appliedCoupons.filter(
|
||||||
|
(val) => val.pricingRule === pricingRuleDocNames![0]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!filteredPricingRuleNames.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pricingRuleDocsForItem = (await doc.fyo.db.getAll(
|
||||||
|
ModelNameEnum.PricingRule,
|
||||||
|
{
|
||||||
|
fields: ['*'],
|
||||||
|
filters: {
|
||||||
|
name: ['in', pricingRuleDocNames as string[]],
|
||||||
|
isEnabled: true,
|
||||||
|
isCouponCodeBased: true,
|
||||||
|
},
|
||||||
|
orderBy: 'priority',
|
||||||
|
order: 'desc',
|
||||||
|
}
|
||||||
|
)) as PricingRule[];
|
||||||
|
|
||||||
|
console.log('pricingRuleDocsForItem', pricingRuleDocsForItem);
|
||||||
|
return pricingRuleDocsForItem;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getPricingRule(
|
export async function getPricingRule(
|
||||||
doc: Invoice
|
doc: Invoice,
|
||||||
|
couponName?: string
|
||||||
): Promise<ApplicablePricingRules[] | undefined> {
|
): Promise<ApplicablePricingRules[] | undefined> {
|
||||||
if (
|
if (
|
||||||
!doc.fyo.singles.AccountingSettings?.enablePricingRule ||
|
!doc.fyo.singles.AccountingSettings?.enablePricingRule ||
|
||||||
@ -822,19 +875,41 @@ export async function getPricingRule(
|
|||||||
})
|
})
|
||||||
).map((doc) => doc.parent) as string[];
|
).map((doc) => doc.parent) as string[];
|
||||||
|
|
||||||
const pricingRuleDocsForItem = (await doc.fyo.db.getAll(
|
let pricingRuleDocsForItem;
|
||||||
|
|
||||||
|
const pricingRuleDocs = (await doc.fyo.db.getAll(
|
||||||
ModelNameEnum.PricingRule,
|
ModelNameEnum.PricingRule,
|
||||||
{
|
{
|
||||||
fields: ['*'],
|
fields: ['*'],
|
||||||
filters: {
|
filters: {
|
||||||
name: ['in', pricingRuleDocNames],
|
name: ['in', pricingRuleDocNames],
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
|
isCouponCodeBased: false,
|
||||||
},
|
},
|
||||||
orderBy: 'priority',
|
orderBy: 'priority',
|
||||||
order: 'desc',
|
order: 'desc',
|
||||||
}
|
}
|
||||||
)) as PricingRule[];
|
)) as PricingRule[];
|
||||||
|
|
||||||
|
if (pricingRuleDocs.length) {
|
||||||
|
pricingRuleDocsForItem = pricingRuleDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pricingRuleDocs.length || couponName) {
|
||||||
|
const couponPricingRules: PricingRule[] | undefined =
|
||||||
|
await getPricingRulesOfCoupons(
|
||||||
|
doc as SalesInvoice,
|
||||||
|
couponName,
|
||||||
|
pricingRuleDocNames
|
||||||
|
);
|
||||||
|
|
||||||
|
pricingRuleDocsForItem = couponPricingRules as PricingRule[];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pricingRuleDocsForItem) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const filtered = filterPricingRules(
|
const filtered = filterPricingRules(
|
||||||
pricingRuleDocsForItem,
|
pricingRuleDocsForItem,
|
||||||
doc.date as Date,
|
doc.date as Date,
|
||||||
@ -857,6 +932,7 @@ export async function getPricingRule(
|
|||||||
pricingRule: filtered[0],
|
pricingRule: filtered[0],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return pricingRules;
|
return pricingRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,11 +1062,11 @@ export async function getApplicableCouponCodesName(
|
|||||||
}
|
}
|
||||||
)) as CouponCode[];
|
)) as CouponCode[];
|
||||||
|
|
||||||
if (!couponCodeDatas || couponCodeDatas.length === 0) {
|
if (!couponCodeDatas || !couponCodeDatas.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const applicablePricingRules = await getPricingRule(sinvDoc);
|
const applicablePricingRules = await getPricingRule(sinvDoc, couponName);
|
||||||
|
|
||||||
if (!applicablePricingRules?.length) {
|
if (!applicablePricingRules?.length) {
|
||||||
return [];
|
return [];
|
||||||
@ -1006,6 +1082,137 @@ export async function getApplicableCouponCodesName(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function validateCouponCode(
|
||||||
|
doc: AppliedCouponCodes,
|
||||||
|
value: string,
|
||||||
|
sinvDoc?: SalesInvoice
|
||||||
|
) {
|
||||||
|
const coupon = await doc.fyo.db.getAll(ModelNameEnum.CouponCode, {
|
||||||
|
fields: [
|
||||||
|
'minAmount',
|
||||||
|
'maxAmount',
|
||||||
|
'pricingRule',
|
||||||
|
'validFrom',
|
||||||
|
'validTo',
|
||||||
|
'maximumUse',
|
||||||
|
'used',
|
||||||
|
'isEnabled',
|
||||||
|
],
|
||||||
|
filters: { name: value },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!coupon[0]?.isEnabled) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'Coupon code cannot be applied as it is not enabled'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((coupon[0]?.maximumUse as number) <= (coupon[0]?.used as number)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'Coupon code has been used maximum number of times'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doc.parentdoc) {
|
||||||
|
doc.parentdoc = sinvDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const applicableCouponCodesNames = await getApplicableCouponCodesName(
|
||||||
|
value,
|
||||||
|
doc.parentdoc as SalesInvoice
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!applicableCouponCodesNames?.length) {
|
||||||
|
throw new ValidationError(
|
||||||
|
t`Coupon ${value} is not applicable for applied items.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const couponExist = doc.parentdoc?.coupons?.some(
|
||||||
|
(coupon) => coupon?.coupons === value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (couponExist) {
|
||||||
|
throw new ValidationError(t`${value} already applied.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(coupon[0].minAmount as Money).gte(doc.parentdoc?.grandTotal as Money) &&
|
||||||
|
!(coupon[0].minAmount as Money).isZero()
|
||||||
|
) {
|
||||||
|
throw new ValidationError(
|
||||||
|
t`The Grand Total must exceed ${
|
||||||
|
(coupon[0].minAmount as Money).float
|
||||||
|
} to apply the coupon ${value}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(coupon[0].maxAmount as Money).lte(doc.parentdoc?.grandTotal as Money) &&
|
||||||
|
!(coupon[0].maxAmount as Money).isZero()
|
||||||
|
) {
|
||||||
|
throw new ValidationError(
|
||||||
|
t`The Grand Total must be less than ${
|
||||||
|
(coupon[0].maxAmount as Money).float
|
||||||
|
} to apply this coupon.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((coupon[0].validFrom as Date) > (doc.parentdoc?.date as Date)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
t`Valid From Date should be less than Valid To Date.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((coupon[0].validTo as Date) < (doc.parentdoc?.date as Date)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
t`Valid To Date should be greater than Valid From Date.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeFreeItems(sinvDoc: SalesInvoice) {
|
||||||
|
if (!sinvDoc || !sinvDoc.items) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!sinvDoc.isPricingRuleApplied) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of sinvDoc.items) {
|
||||||
|
if (item.isFreeItem) {
|
||||||
|
sinvDoc.items = sinvDoc.items?.filter(
|
||||||
|
(invoiceItem) => invoiceItem.name !== item.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updatePricingRule(sinvDoc: SalesInvoice) {
|
||||||
|
const applicablePricingRuleNames = await getPricingRule(sinvDoc);
|
||||||
|
|
||||||
|
if (!applicablePricingRuleNames || !applicablePricingRuleNames.length) {
|
||||||
|
sinvDoc.pricingRuleDetail = undefined;
|
||||||
|
sinvDoc.isPricingRuleApplied = false;
|
||||||
|
removeFreeItems(sinvDoc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appliedPricingRuleCount = sinvDoc?.items?.filter(
|
||||||
|
(val) => val.isFreeItem
|
||||||
|
).length;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
(async () => {
|
||||||
|
if (appliedPricingRuleCount !== applicablePricingRuleNames?.length) {
|
||||||
|
await sinvDoc.appendPricingRuleDetail(applicablePricingRuleNames);
|
||||||
|
await sinvDoc.applyProductDiscount();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
export function getPricingRulesConflicts(
|
export function getPricingRulesConflicts(
|
||||||
pricingRules: PricingRule[]
|
pricingRules: PricingRule[]
|
||||||
): undefined | boolean {
|
): undefined | boolean {
|
||||||
|
@ -377,15 +377,15 @@ export default defineComponent({
|
|||||||
const pricingRule =
|
const pricingRule =
|
||||||
(await this.row.parentdoc?.getPricingRule()) as ApplicablePricingRules[];
|
(await this.row.parentdoc?.getPricingRule()) as ApplicablePricingRules[];
|
||||||
|
|
||||||
let appliedPricingRuleCount: number;
|
let appliedPricingRuleCount =
|
||||||
setTimeout(async () => {
|
this.row.parentdoc?.pricingRuleDetail?.length;
|
||||||
|
|
||||||
if (appliedPricingRuleCount !== pricingRule?.length) {
|
if (appliedPricingRuleCount !== pricingRule?.length) {
|
||||||
appliedPricingRuleCount = pricingRule?.length;
|
appliedPricingRuleCount = pricingRule?.length;
|
||||||
await this.row.parentdoc?.appendPricingRuleDetail(pricingRule);
|
|
||||||
|
|
||||||
|
await this.row.parentdoc?.appendPricingRuleDetail(pricingRule);
|
||||||
await this.row.parentdoc?.applyProductDiscount();
|
await this.row.parentdoc?.applyProductDiscount();
|
||||||
}
|
}
|
||||||
}, 1);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,21 +1,28 @@
|
|||||||
import { Money } from "pesa";
|
import { Money } from 'pesa';
|
||||||
|
|
||||||
export type ItemQtyMap = {
|
export type ItemQtyMap = {
|
||||||
[item: string]: { availableQty: number;[batch: string]: number };
|
[item: string]: { availableQty: number; [batch: string]: number };
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ItemSerialNumbers = { [item: string]: string };
|
export type ItemSerialNumbers = { [item: string]: string };
|
||||||
|
|
||||||
export type DiscountType = "percent" | "amount";
|
export type DiscountType = 'percent' | 'amount';
|
||||||
|
|
||||||
export type ModalName = 'ShiftOpen' | 'ShiftClose' | 'Payment' | 'LoyaltyProgram' | 'SavedInvoice' | 'RouteToInvoiceList'
|
export type ModalName =
|
||||||
|
| 'ShiftOpen'
|
||||||
|
| 'ShiftClose'
|
||||||
|
| 'Payment'
|
||||||
|
| 'LoyaltyProgram'
|
||||||
|
| 'SavedInvoice'
|
||||||
|
| 'RouteToInvoiceList'
|
||||||
|
| 'CouponCode';
|
||||||
|
|
||||||
export interface POSItem {
|
export interface POSItem {
|
||||||
image?:string,
|
image?: string;
|
||||||
name: string,
|
name: string;
|
||||||
rate: Money,
|
rate: Money;
|
||||||
availableQty: number,
|
availableQty: number;
|
||||||
unit: string,
|
unit: string;
|
||||||
hasBatch: boolean,
|
hasBatch: boolean;
|
||||||
hasSerialNumber: boolean,
|
hasSerialNumber: boolean;
|
||||||
}
|
}
|
214
src/pages/POS/CouponCodeModal.vue
Normal file
214
src/pages/POS/CouponCodeModal.vue
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<template>
|
||||||
|
<Modal class="h-auto w-96" :set-close-listener="false">
|
||||||
|
<p class="text-center font-semibold py-3">Apply Coupon Code</p>
|
||||||
|
<div class="px-10">
|
||||||
|
<hr class="dark:border-gray-800" />
|
||||||
|
<p v-if="appliedCoupons.length" class="text-xs m-2 text-gray-500">
|
||||||
|
{{ t`Applied Coupon Codes` }}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
v-if="appliedCoupons.length"
|
||||||
|
class="overflow-y-auto mt-2 custom-scroll custom-scroll-thumb2"
|
||||||
|
:style="{ height: appliedCoupons.length >= 2 ? '11vh' : '8vh' }"
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
v-for="(coupon,index) in appliedCoupons as any"
|
||||||
|
:key="index"
|
||||||
|
:ratio="ratio"
|
||||||
|
:border="true"
|
||||||
|
class="
|
||||||
|
border-b border-l border-r
|
||||||
|
dark:border-gray-800
|
||||||
|
relative
|
||||||
|
group
|
||||||
|
h-coupon-mid
|
||||||
|
hover:bg-gray-25
|
||||||
|
dark:bg-gray-890
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="flex flex-row w-full items-center">
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<FormControl
|
||||||
|
v-for="df in tableFields"
|
||||||
|
:key="df.fieldname"
|
||||||
|
size="large"
|
||||||
|
class="w-full"
|
||||||
|
:df="df"
|
||||||
|
:value="coupon[df.fieldname]"
|
||||||
|
:read-only="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="absolute right-3">
|
||||||
|
<feather-icon
|
||||||
|
name="trash"
|
||||||
|
class="w-4 text-xl text-red-500 cursor-pointer"
|
||||||
|
@click="removeAppliedCoupon(coupon)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="coupons.fieldMap"
|
||||||
|
class="flex justify-center"
|
||||||
|
:class="appliedCoupons.length ? 'pb-0 pt-4' : 'pt-10'"
|
||||||
|
>
|
||||||
|
<div class="w-80" :class="appliedCoupons.length ? 'pb-4' : 'pb-10'">
|
||||||
|
<Link
|
||||||
|
v-if="coupons.fieldMap"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
:show-label="true"
|
||||||
|
:border="true"
|
||||||
|
:value="couponCode"
|
||||||
|
:df="coupons.fieldMap.coupons"
|
||||||
|
@change="updateCouponCode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row-start-6 grid grid-cols-2 gap-4 mt-auto mb-2">
|
||||||
|
<div class="col-span-2">
|
||||||
|
<Button
|
||||||
|
class="w-full bg-green-500 dark:bg-green-700"
|
||||||
|
style="padding: 1.35rem"
|
||||||
|
:disabled="validationError"
|
||||||
|
@click="setCouponCode()"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
<p class="uppercase text-lg text-white font-semibold">
|
||||||
|
{{ t`Save` }}
|
||||||
|
</p>
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row-start-6 grid grid-cols-2 gap-4 mt-auto mb-8">
|
||||||
|
<div class="col-span-2">
|
||||||
|
<Button
|
||||||
|
class="w-full bg-red-500 dark:bg-red-700"
|
||||||
|
style="padding: 1.35rem"
|
||||||
|
@click="cancelApplyCouponCode()"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
<p class="uppercase text-lg text-white font-semibold">
|
||||||
|
{{ t`Cancel` }}
|
||||||
|
</p>
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Button from 'src/components/Button.vue';
|
||||||
|
import Modal from 'src/components/Modal.vue';
|
||||||
|
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
|
||||||
|
import { defineComponent, inject } from 'vue';
|
||||||
|
import { t } from 'fyo';
|
||||||
|
import { showToast } from 'src/utils/interactive';
|
||||||
|
import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes';
|
||||||
|
import Link from 'src/components/Controls/Link.vue';
|
||||||
|
import { ModelNameEnum } from 'models/types';
|
||||||
|
import { updatePricingRule, validateCouponCode } from 'models/helpers';
|
||||||
|
import { Field } from 'schemas/types';
|
||||||
|
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||||
|
import Row from 'src/components/Row.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'CouponCodeModal',
|
||||||
|
components: {
|
||||||
|
Modal,
|
||||||
|
Button,
|
||||||
|
Link,
|
||||||
|
FormControl,
|
||||||
|
Row,
|
||||||
|
},
|
||||||
|
emits: ['setCouponsCount', 'toggleModal'],
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
sinvDoc: inject('sinvDoc') as SalesInvoice,
|
||||||
|
coupons: inject('coupons') as AppliedCouponCodes,
|
||||||
|
appliedCoupons: inject('appliedCoupons') as AppliedCouponCodes[],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
validationError: false,
|
||||||
|
couponCode: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
ratio() {
|
||||||
|
return [1, 0.1, 1, 0.7];
|
||||||
|
},
|
||||||
|
tableFields() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldname: 'coupons',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
required: true,
|
||||||
|
readOnly: true,
|
||||||
|
},
|
||||||
|
] as Field[];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateCouponCode(value: string) {
|
||||||
|
(this.validationError = false), (this.couponCode = value);
|
||||||
|
},
|
||||||
|
async setCouponCode() {
|
||||||
|
try {
|
||||||
|
if (!this.couponCode) {
|
||||||
|
throw new Error(t`Must be select a coupon code`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const appliedCouponCodes = this.fyo.doc.getNewDoc(
|
||||||
|
ModelNameEnum.AppliedCouponCodes
|
||||||
|
);
|
||||||
|
|
||||||
|
await validateCouponCode(
|
||||||
|
appliedCouponCodes as AppliedCouponCodes,
|
||||||
|
this.couponCode,
|
||||||
|
this.sinvDoc
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.sinvDoc.append('coupons', { coupons: this.couponCode });
|
||||||
|
|
||||||
|
await updatePricingRule(this.sinvDoc);
|
||||||
|
this.$emit('toggleModal', 'CouponCode');
|
||||||
|
|
||||||
|
this.couponCode = '';
|
||||||
|
this.validationError = false;
|
||||||
|
|
||||||
|
this.$emit('setCouponsCount', this.sinvDoc.coupons?.length);
|
||||||
|
} catch (error) {
|
||||||
|
this.validationError = true;
|
||||||
|
|
||||||
|
showToast({
|
||||||
|
type: 'error',
|
||||||
|
message: t`${error as string}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async removeAppliedCoupon(coupon: AppliedCouponCodes) {
|
||||||
|
this.sinvDoc.coupons = this.sinvDoc.coupons?.filter(
|
||||||
|
(coup) => coup.coupons !== coupon?.coupons
|
||||||
|
);
|
||||||
|
|
||||||
|
await updatePricingRule(this.sinvDoc);
|
||||||
|
this.$emit('setCouponsCount', this.sinvDoc.coupons?.length);
|
||||||
|
},
|
||||||
|
cancelApplyCouponCode() {
|
||||||
|
this.couponCode = '';
|
||||||
|
this.$emit('toggleModal', 'CouponCode');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -36,6 +36,12 @@
|
|||||||
@toggle-modal="toggleModal"
|
@toggle-modal="toggleModal"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<CouponCodeModal
|
||||||
|
:open-modal="openCouponCodeModal"
|
||||||
|
@set-coupons-count="setCouponsCount"
|
||||||
|
@toggle-modal="toggleModal"
|
||||||
|
/>
|
||||||
|
|
||||||
<PaymentModal
|
<PaymentModal
|
||||||
:open-modal="openPaymentModal"
|
:open-modal="openPaymentModal"
|
||||||
@create-transaction="createTransaction"
|
@create-transaction="createTransaction"
|
||||||
@ -43,6 +49,7 @@
|
|||||||
@set-cash-amount="setCashAmount"
|
@set-cash-amount="setCashAmount"
|
||||||
@set-transfer-amount="setTransferAmount"
|
@set-transfer-amount="setTransferAmount"
|
||||||
@set-transfer-ref-no="setTransferRefNo"
|
@set-transfer-ref-no="setTransferRefNo"
|
||||||
|
@set-coupons-count="setCouponsCount"
|
||||||
@set-transfer-clearance-date="setTransferClearanceDate"
|
@set-transfer-clearance-date="setTransferClearanceDate"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -105,6 +112,7 @@
|
|||||||
:item-qty-map="itemQtyMap"
|
:item-qty-map="itemQtyMap"
|
||||||
@add-item="addItem"
|
@add-item="addItem"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemsGrid
|
<ItemsGrid
|
||||||
v-else
|
v-else
|
||||||
:items="items"
|
:items="items"
|
||||||
@ -197,6 +205,7 @@
|
|||||||
Loyalty Program
|
Loyalty Program
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative group">
|
<div class="relative group">
|
||||||
<div class="p-1 rounded-md bg-gray-100" @click="routeToSinvList">
|
<div class="p-1 rounded-md bg-gray-100" @click="routeToSinvList">
|
||||||
<svg
|
<svg
|
||||||
@ -236,6 +245,122 @@
|
|||||||
Sales Invoice List
|
Sales Invoice List
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="relative group">
|
||||||
|
<div
|
||||||
|
class="p-0.5 rounded-md bg-gray-100"
|
||||||
|
:class="{
|
||||||
|
hidden: !fyo.singles.AccountingSettings?.enableCouponCode,
|
||||||
|
'bg-gray-100': loyaltyPoints,
|
||||||
|
'dark:bg-gray-600 cursor-not-allowed':
|
||||||
|
!sinvDoc.party || !sinvDoc.items?.length,
|
||||||
|
}"
|
||||||
|
@click="openCouponModal()"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="#000000"
|
||||||
|
width="28px"
|
||||||
|
height="28px"
|
||||||
|
viewBox="0 0 512.00 512.00"
|
||||||
|
enable-background="new 0 0 512 512"
|
||||||
|
version="1.1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="9.312000000000001"
|
||||||
|
transform="matrix(1, 0, 0, 1, 0, 0)rotate(0)"
|
||||||
|
>
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||||
|
<g
|
||||||
|
id="SVGRepo_tracerCarrier"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke="#CCCCCC"
|
||||||
|
stroke-width="19.456"
|
||||||
|
></g>
|
||||||
|
<g id="SVGRepo_iconCarrier">
|
||||||
|
<g id="Layer_1"></g>
|
||||||
|
<g id="Layer_2">
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M412.7,134.4H229.6c-2,0-3.9,0.8-5.3,2.2l-27.8,27.8L169.1,137c-1.4-1.4-3.3-2.2-5.3-2.2H99.3c-4.1,0-7.5,3.4-7.5,7.5 v227.4c0,4.1,3.4,7.5,7.5,7.5h64.5c2,0,3.9-0.8,5.3-2.2l27.4-27.4l27.8,27.8c1.4,1.4,3.3,2.2,5.3,2.2h183.1c4.1,0,7.5-3.4,7.5-7.5 V141.9C420.2,137.7,416.8,134.4,412.7,134.4z M405.2,362.6H232.7l-30.9-30.9c-2.9-2.9-7.7-2.9-10.6,0l-30.5,30.5h-53.9V149.8h53.9 l30.5,30.5c2.9,2.9,7.7,2.9,10.6,0l30.9-30.9h172.5V362.6z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M276.9,235.2c15.4,0,28-12.6,28-28s-12.6-28-28-28s-28,12.6-28,28S261.4,235.2,276.9,235.2z M276.9,194.2 c7.2,0,13,5.8,13,13s-5.8,13-13,13s-13-5.8-13-13S269.7,194.2,276.9,194.2z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M360,262.4c-15.4,0-28,12.6-28,28s12.6,28,28,28s28-12.6,28-28S375.4,262.4,360,262.4z M360,303.4c-7.2,0-13-5.8-13-13 s5.8-13,13-13s13,5.8,13,13S367.2,303.4,360,303.4z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M256.6,310.7c1.5,1.5,3.4,2.2,5.3,2.2s3.8-0.7,5.3-2.2l113.1-113.1c2.9-2.9,2.9-7.7,0-10.6c-2.9-2.9-7.7-2.9-10.6,0 L256.6,300.1C253.6,303,253.6,307.7,256.6,310.7z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M196.5,202.5c-2,0-3.9,0.8-5.3,2.2c-1.4,1.4-2.2,3.3-2.2,5.3c0,2,0.8,3.9,2.2,5.3c1.4,1.4,3.3,2.2,5.3,2.2 c2,0,3.9-0.8,5.3-2.2c1.4-1.4,2.2-3.3,2.2-5.3c0-2-0.8-3.9-2.2-5.3C200.4,203.3,198.4,202.5,196.5,202.5z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M196.5,233.2c-2,0-3.9,0.8-5.3,2.2c-1.4,1.4-2.2,3.3-2.2,5.3c0,2,0.8,3.9,2.2,5.3c1.4,1.4,3.3,2.2,5.3,2.2 c2,0,3.9-0.8,5.3-2.2c1.4-1.4,2.2-3.3,2.2-5.3c0-2-0.8-3.9-2.2-5.3C200.4,234,198.4,233.2,196.5,233.2z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M196.5,263.8c-2,0-3.9,0.8-5.3,2.2c-1.4,1.4-2.2,3.3-2.2,5.3c0,2,0.8,3.9,2.2,5.3c1.4,1.4,3.3,2.2,5.3,2.2 c2,0,3.9-0.8,5.3-2.2c1.4-1.4,2.2-3.3,2.2-5.3c0-2-0.8-3.9-2.2-5.3C200.4,264.6,198.4,263.8,196.5,263.8z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M196.5,294.5c-2,0-3.9,0.8-5.3,2.2c-1.4,1.4-2.2,3.3-2.2,5.3c0,2,0.8,3.9,2.2,5.3c1.4,1.4,3.3,2.2,5.3,2.2 c2,0,3.9-0.8,5.3-2.2c1.4-1.4,2.2-3.3,2.2-5.3c0-2-0.8-3.9-2.2-5.3C200.4,295.3,198.4,294.5,196.5,294.5z"
|
||||||
|
></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="
|
||||||
|
absolute
|
||||||
|
bottom-full
|
||||||
|
left-1/2
|
||||||
|
transform
|
||||||
|
-translate-x-1/2
|
||||||
|
mb-2
|
||||||
|
bg-gray-100
|
||||||
|
dark:bg-gray-850 dark:text-white
|
||||||
|
text-black text-xs
|
||||||
|
rounded-md
|
||||||
|
p-2
|
||||||
|
w-28
|
||||||
|
text-center
|
||||||
|
opacity-0
|
||||||
|
group-hover:opacity-100
|
||||||
|
transition-opacity
|
||||||
|
duration-300
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Coupon Code
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
v-if="appliedCouponsCount !== 0"
|
||||||
|
class="
|
||||||
|
absolute
|
||||||
|
top-0
|
||||||
|
right-0
|
||||||
|
transform
|
||||||
|
translate-x-1/2
|
||||||
|
-translate-y-1/2
|
||||||
|
h-4
|
||||||
|
w-4
|
||||||
|
bg-green-400
|
||||||
|
text-green-900
|
||||||
|
rounded-full
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
text-xs
|
||||||
|
cursor-pointer
|
||||||
|
border-red-500
|
||||||
|
p-2
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ appliedCouponsCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -430,10 +555,16 @@ import {
|
|||||||
validateSinv,
|
validateSinv,
|
||||||
} from 'src/utils/pos';
|
} from 'src/utils/pos';
|
||||||
import Barcode from 'src/components/Controls/Barcode.vue';
|
import Barcode from 'src/components/Controls/Barcode.vue';
|
||||||
import { getAddedLPWithGrandTotal, getPricingRule } from 'models/helpers';
|
import {
|
||||||
|
getAddedLPWithGrandTotal,
|
||||||
|
getPricingRule,
|
||||||
|
removeFreeItems,
|
||||||
|
} from 'models/helpers';
|
||||||
import LoyaltyProgramModal from './LoyaltyprogramModal.vue';
|
import LoyaltyProgramModal from './LoyaltyprogramModal.vue';
|
||||||
import AlertModal from './AlertModal.vue';
|
import AlertModal from './AlertModal.vue';
|
||||||
import SavedInvoiceModal from './SavedInvoiceModal.vue';
|
import SavedInvoiceModal from './SavedInvoiceModal.vue';
|
||||||
|
import CouponCodeModal from './CouponCodeModal.vue';
|
||||||
|
import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'POS',
|
name: 'POS',
|
||||||
@ -451,6 +582,7 @@ export default defineComponent({
|
|||||||
PaymentModal,
|
PaymentModal,
|
||||||
LoyaltyProgramModal,
|
LoyaltyProgramModal,
|
||||||
SavedInvoiceModal,
|
SavedInvoiceModal,
|
||||||
|
CouponCodeModal,
|
||||||
SelectedItemTable,
|
SelectedItemTable,
|
||||||
Barcode,
|
Barcode,
|
||||||
},
|
},
|
||||||
@ -463,6 +595,8 @@ export default defineComponent({
|
|||||||
itemQtyMap: computed(() => this.itemQtyMap),
|
itemQtyMap: computed(() => this.itemQtyMap),
|
||||||
itemSerialNumbers: computed(() => this.itemSerialNumbers),
|
itemSerialNumbers: computed(() => this.itemSerialNumbers),
|
||||||
sinvDoc: computed(() => this.sinvDoc),
|
sinvDoc: computed(() => this.sinvDoc),
|
||||||
|
appliedCoupons: computed(() => this.sinvDoc.coupons),
|
||||||
|
coupons: computed(() => this.coupons),
|
||||||
totalTaxedAmount: computed(() => this.totalTaxedAmount),
|
totalTaxedAmount: computed(() => this.totalTaxedAmount),
|
||||||
transferAmount: computed(() => this.transferAmount),
|
transferAmount: computed(() => this.transferAmount),
|
||||||
transferClearanceDate: computed(() => this.transferClearanceDate),
|
transferClearanceDate: computed(() => this.transferClearanceDate),
|
||||||
@ -479,6 +613,8 @@ export default defineComponent({
|
|||||||
openPaymentModal: false,
|
openPaymentModal: false,
|
||||||
openLoyaltyProgramModal: false,
|
openLoyaltyProgramModal: false,
|
||||||
openSavedInvoiceModal: false,
|
openSavedInvoiceModal: false,
|
||||||
|
openCouponCodeModal: false,
|
||||||
|
openAppliedCouponsModal: false,
|
||||||
openShiftCloseModal: false,
|
openShiftCloseModal: false,
|
||||||
openShiftOpenModal: false,
|
openShiftOpenModal: false,
|
||||||
openRouteToInvoiceListModal: false,
|
openRouteToInvoiceListModal: false,
|
||||||
@ -495,6 +631,9 @@ export default defineComponent({
|
|||||||
appliedLoyaltyPoints: 0,
|
appliedLoyaltyPoints: 0,
|
||||||
loyaltyProgram: '' as string,
|
loyaltyProgram: '' as string,
|
||||||
|
|
||||||
|
appliedCoupons: [] as AppliedCouponCodes[],
|
||||||
|
appliedCouponsCount: 0,
|
||||||
|
|
||||||
defaultCustomer: undefined as string | undefined,
|
defaultCustomer: undefined as string | undefined,
|
||||||
itemSearchTerm: '',
|
itemSearchTerm: '',
|
||||||
transferRefNo: undefined as string | undefined,
|
transferRefNo: undefined as string | undefined,
|
||||||
@ -505,6 +644,7 @@ export default defineComponent({
|
|||||||
itemSerialNumbers: {} as ItemSerialNumbers,
|
itemSerialNumbers: {} as ItemSerialNumbers,
|
||||||
paymentDoc: {} as Payment,
|
paymentDoc: {} as Payment,
|
||||||
sinvDoc: {} as SalesInvoice,
|
sinvDoc: {} as SalesInvoice,
|
||||||
|
coupons: {} as AppliedCouponCodes,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -543,12 +683,14 @@ export default defineComponent({
|
|||||||
deep: true,
|
deep: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.setItems();
|
await this.setItems();
|
||||||
},
|
},
|
||||||
async activated() {
|
async activated() {
|
||||||
toggleSidebar(false);
|
toggleSidebar(false);
|
||||||
validateIsPosSettingsSet(fyo);
|
validateIsPosSettingsSet(fyo);
|
||||||
|
this.setCouponCodeDoc();
|
||||||
this.setSinvDoc();
|
this.setSinvDoc();
|
||||||
this.setDefaultCustomer();
|
this.setDefaultCustomer();
|
||||||
await this.setItemQtyMap();
|
await this.setItemQtyMap();
|
||||||
@ -648,6 +790,14 @@ export default defineComponent({
|
|||||||
isPOS: true,
|
isPOS: true,
|
||||||
}) as SalesInvoice;
|
}) as SalesInvoice;
|
||||||
},
|
},
|
||||||
|
setCouponCodeDoc() {
|
||||||
|
this.coupons = this.fyo.doc.getNewDoc(
|
||||||
|
ModelNameEnum.AppliedCouponCodes
|
||||||
|
) as AppliedCouponCodes;
|
||||||
|
},
|
||||||
|
setAppliedCoupons() {
|
||||||
|
this.appliedCoupons = this.sinvDoc.coupons as AppliedCouponCodes[];
|
||||||
|
},
|
||||||
setTotalQuantity() {
|
setTotalQuantity() {
|
||||||
this.totalQuantity = getTotalQuantity(
|
this.totalQuantity = getTotalQuantity(
|
||||||
this.sinvDoc.items as SalesInvoiceItem[]
|
this.sinvDoc.items as SalesInvoiceItem[]
|
||||||
@ -656,6 +806,9 @@ export default defineComponent({
|
|||||||
setTotalTaxedAmount() {
|
setTotalTaxedAmount() {
|
||||||
this.totalTaxedAmount = getTotalTaxedAmount(this.sinvDoc as SalesInvoice);
|
this.totalTaxedAmount = getTotalTaxedAmount(this.sinvDoc as SalesInvoice);
|
||||||
},
|
},
|
||||||
|
setCouponsCount(value: number) {
|
||||||
|
this.appliedCouponsCount = value;
|
||||||
|
},
|
||||||
async setLoyaltyPoints(value: number) {
|
async setLoyaltyPoints(value: number) {
|
||||||
this.appliedLoyaltyPoints = value;
|
this.appliedLoyaltyPoints = value;
|
||||||
|
|
||||||
@ -691,23 +844,6 @@ export default defineComponent({
|
|||||||
setTransferRefNo(ref: string) {
|
setTransferRefNo(ref: string) {
|
||||||
this.transferRefNo = ref;
|
this.transferRefNo = ref;
|
||||||
},
|
},
|
||||||
removeFreeItems() {
|
|
||||||
if (!this.sinvDoc || !this.sinvDoc.items) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!this.sinvDoc.isPricingRuleApplied) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const item of this.sinvDoc.items) {
|
|
||||||
if (item.isFreeItem) {
|
|
||||||
this.sinvDoc.items = this.sinvDoc.items?.filter(
|
|
||||||
(invoiceItem) => invoiceItem.name !== item.name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async addItem(item: POSItem | Item | undefined) {
|
async addItem(item: POSItem | Item | undefined) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
@ -867,6 +1003,11 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
openCouponModal() {
|
||||||
|
if (this.sinvDoc.party && this.sinvDoc.items?.length) {
|
||||||
|
this.toggleModal('CouponCode', true);
|
||||||
|
}
|
||||||
|
},
|
||||||
async submitSinvDoc(shouldPrint: boolean) {
|
async submitSinvDoc(shouldPrint: boolean) {
|
||||||
this.sinvDoc.once('afterSubmit', async () => {
|
this.sinvDoc.once('afterSubmit', async () => {
|
||||||
showToast({
|
showToast({
|
||||||
@ -940,15 +1081,15 @@ export default defineComponent({
|
|||||||
if (!hasPricingRules || !hasPricingRules.length) {
|
if (!hasPricingRules || !hasPricingRules.length) {
|
||||||
this.sinvDoc.pricingRuleDetail = undefined;
|
this.sinvDoc.pricingRuleDetail = undefined;
|
||||||
this.sinvDoc.isPricingRuleApplied = false;
|
this.sinvDoc.isPricingRuleApplied = false;
|
||||||
this.removeFreeItems();
|
removeFreeItems(this.sinvDoc as SalesInvoice);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
const appliedPricingRuleCount = this.sinvDoc?.items?.filter(
|
const appliedPricingRuleCount = this.sinvDoc?.items?.filter(
|
||||||
(val) => val.isFreeItem
|
(val) => val.isFreeItem
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
if (appliedPricingRuleCount !== hasPricingRules?.length) {
|
if (appliedPricingRuleCount !== hasPricingRules?.length) {
|
||||||
await this.sinvDoc.appendPricingRuleDetail(hasPricingRules);
|
await this.sinvDoc.appendPricingRuleDetail(hasPricingRules);
|
||||||
await this.sinvDoc.applyProductDiscount();
|
await this.sinvDoc.applyProductDiscount();
|
||||||
|
@ -169,7 +169,7 @@
|
|||||||
class="w-full bg-blue-500"
|
class="w-full bg-blue-500"
|
||||||
style="padding: 1.35rem"
|
style="padding: 1.35rem"
|
||||||
:disabled="disableSubmitButton"
|
:disabled="disableSubmitButton"
|
||||||
@click="$emit('createTransaction')"
|
@click="submitTransaction()"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<p class="uppercase text-lg text-white font-semibold">
|
<p class="uppercase text-lg text-white font-semibold">
|
||||||
@ -224,6 +224,7 @@ export default defineComponent({
|
|||||||
'setTransferClearanceDate',
|
'setTransferClearanceDate',
|
||||||
'setTransferRefNo',
|
'setTransferRefNo',
|
||||||
'toggleModal',
|
'toggleModal',
|
||||||
|
'setCouponsCount',
|
||||||
],
|
],
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
@ -320,6 +321,10 @@ export default defineComponent({
|
|||||||
this.$emit('setTransferAmount', fyo.pesa(0));
|
this.$emit('setTransferAmount', fyo.pesa(0));
|
||||||
this.$emit('setCashAmount', this.sinvDoc?.grandTotal);
|
this.$emit('setCashAmount', this.sinvDoc?.grandTotal);
|
||||||
},
|
},
|
||||||
|
submitTransaction() {
|
||||||
|
this.$emit('createTransaction');
|
||||||
|
this.$emit('setCouponsCount', 0);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user