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: PriceList functionality in POS #1036

Merged
merged 7 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions models/baseModels/Invoice/Invoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { AppliedCouponCodes } from '../AppliedCouponCodes/AppliedCouponCodes';
import { CouponCode } from '../CouponCode/CouponCode';
import { SalesInvoice } from '../SalesInvoice/SalesInvoice';
import { SalesInvoiceItem } from '../SalesInvoiceItem/SalesInvoiceItem';
import { PriceListItem } from '../PriceList/PriceListItem';
import { PricingRuleItem } from '../PricingRuleItem/PricingRuleItem';

export type TaxDetail = {
account: string;
Expand Down Expand Up @@ -1332,7 +1332,7 @@ export abstract class Invoice extends Transactional {
item: item.item as string,
unit: item.unit as string,
},
})) as PriceListItem[];
})) as PricingRuleItem[];

return docs.map((doc) => doc.parent) as string[];
}
Expand Down
44 changes: 5 additions & 39 deletions models/baseModels/InvoiceItem/InvoiceItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import { safeParseFloat } from 'utils/index';
import { Invoice } from '../Invoice/Invoice';
import { Item } from '../Item/Item';
import { StockTransfer } from 'models/inventory/StockTransfer';
import { PriceList } from '../PriceList/PriceList';
import { isPesa } from 'fyo/utils';
import { PricingRule } from '../PricingRule/PricingRule';
import { getItemRateFromPriceList } from 'models/helpers';

export abstract class InvoiceItem extends Doc {
item?: string;
Expand Down Expand Up @@ -629,7 +629,10 @@ async function getItemRate(doc: InvoiceItem): Promise<Money | undefined> {
let priceListRate: Money | undefined;

if (doc.fyo.singles.AccountingSettings?.enablePriceList) {
priceListRate = await getItemRateFromPriceList(doc);
priceListRate = await getItemRateFromPriceList(
doc,
doc.parentdoc?.priceList as string
);
}

if (priceListRate) {
Expand Down Expand Up @@ -675,43 +678,6 @@ async function getItemRateFromPricingRule(
return pricingRuleDoc.discountRate;
}

async function getItemRateFromPriceList(
doc: InvoiceItem
): Promise<Money | undefined> {
const priceListName = doc.parentdoc?.priceList;
const item = doc.item;
if (!priceListName || !item) {
return;
}

const priceList = await doc.fyo.doc.getDoc(
ModelNameEnum.PriceList,
priceListName
);

if (!(priceList instanceof PriceList)) {
return;
}

const unit = doc.unit;
const transferUnit = doc.transferUnit;
const plItem = priceList.priceListItem?.find((pli) => {
if (pli.item !== item) {
return false;
}

if (transferUnit && pli.unit !== transferUnit) {
return false;
} else if (unit && pli.unit !== unit) {
return false;
}

return true;
});

return plItem?.rate;
}

function getDiscountedTotalBeforeTaxation(
rate: Money,
quantity: number,
Expand Down
40 changes: 40 additions & 0 deletions models/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import { ValidationError } from 'fyo/utils/errors';
import { isPesa } from 'fyo/utils';
import { numberSeriesDefaultsMap } from './baseModels/Defaults/Defaults';
import { safeParseFloat } from 'utils/index';
import { PriceList } from './baseModels/PriceList/PriceList';
import { InvoiceItem } from './baseModels/InvoiceItem/InvoiceItem';
import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem';

export function getQuoteActions(
fyo: Fyo,
Expand Down Expand Up @@ -947,6 +950,43 @@ export async function getPricingRule(
return pricingRules;
}

export async function getItemRateFromPriceList(
doc: InvoiceItem | SalesInvoiceItem,
priceListName: string
): Promise<Money | undefined> {
const item = doc.item;
if (!priceListName || !item) {
return;
}

const priceList = await doc.fyo.doc.getDoc(
ModelNameEnum.PriceList,
priceListName
);

if (!(priceList instanceof PriceList)) {
return;
}

const unit = doc.unit;
const transferUnit = doc.transferUnit;
const plItem = priceList.priceListItem?.find((pli) => {
if (pli.item !== item) {
return false;
}

if (transferUnit && pli.unit !== transferUnit) {
return false;
} else if (unit && pli.unit !== unit) {
return false;
}

return true;
});

return plItem?.rate;
}

export function filterPricingRules(
pricingRuleDocsForItem: PricingRule[],
sinvDate: Date,
Expand Down
3 changes: 2 additions & 1 deletion src/components/POS/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export type ModalName =
| 'LoyaltyProgram'
| 'SavedInvoice'
| 'Alert'
| 'CouponCode';
| 'CouponCode'
| 'PriceList';

export type PosEmits =
| 'addItem'
Expand Down
10 changes: 9 additions & 1 deletion src/pages/POS/ClassicPOS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
@set-coupons-count="(count) => emitEvent('setCouponsCount', count)"
/>

<PriceListModal
:open-modal="openPriceListModal"
@toggle-modal="emitEvent('toggleModal', 'PriceList')"
/>

<PaymentModal
:open-modal="openPaymentModal"
@toggle-modal="emitEvent('toggleModal', 'Payment')"
Expand Down Expand Up @@ -287,6 +292,7 @@ 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 { Item } from 'models/baseModels/Item/Item';
import Link from 'src/components/Controls/Link.vue';
import CouponCodeModal from './CouponCodeModal.vue';
Expand Down Expand Up @@ -318,8 +324,9 @@ export default defineComponent({
ItemsTable,
PaymentModal,
MultiLabelLink,
POSQuickActions,
PriceListModal,
CouponCodeModal,
POSQuickActions,
OpenPOSShiftModal,
SelectedItemTable,
SavedInvoiceModal,
Expand All @@ -336,6 +343,7 @@ export default defineComponent({
isPosShiftOpen: Boolean,
disablePayButton: Boolean,
openPaymentModal: Boolean,
openPriceListModal: Boolean,
openCouponCodeModal: Boolean,
openShiftCloseModal: Boolean,
openSavedInvoiceModal: Boolean,
Expand Down
8 changes: 8 additions & 0 deletions src/pages/POS/ModernPOS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
@set-coupons-count="(count) => emitEvent('setCouponsCount', count)"
/>

<PriceListModal
:open-modal="openPriceListModal"
@toggle-modal="emitEvent('toggleModal', 'PriceList')"
/>

<PaymentModal
:open-modal="openPaymentModal"
@toggle-modal="emitEvent('toggleModal', 'Payment')"
Expand Down Expand Up @@ -297,6 +302,7 @@ import AlertModal from './AlertModal.vue';
import PaymentModal from './PaymentModal.vue';
import Button from 'src/components/Button.vue';
import KeyboardModal from './KeyboardModal.vue';
import PriceListModal from './PriceListModal.vue';
import { Item } from 'models/baseModels/Item/Item';
import Link from 'src/components/Controls/Link.vue';
import CouponCodeModal from './CouponCodeModal.vue';
Expand Down Expand Up @@ -327,6 +333,7 @@ export default defineComponent({
PaymentModal,
KeyboardModal,
MultiLabelLink,
PriceListModal,
POSQuickActions,
CouponCodeModal,
OpenPOSShiftModal,
Expand All @@ -348,6 +355,7 @@ export default defineComponent({
disablePayButton: Boolean,
openPaymentModal: Boolean,
openKeyboardModal: Boolean,
openPriceListModal: Boolean,
openCouponCodeModal: Boolean,
openShiftCloseModal: Boolean,
openSavedInvoiceModal: Boolean,
Expand Down
20 changes: 19 additions & 1 deletion src/pages/POS/POS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
:open-payment-modal="openPaymentModal"
:item-discounts="(itemDiscounts as Money)"
:coupons="(coupons as AppliedCouponCodes)"
:open-price-list-modal="openPriceListModal"
:applied-coupons-count="appliedCouponsCount"
:open-shift-close-modal="openShiftCloseModal"
:open-coupon-code-modal="openCouponCodeModal"
Expand Down Expand Up @@ -66,6 +67,7 @@
:open-keyboard-modal="openKeyboardModal"
:item-discounts="(itemDiscounts as Money)"
:coupons="(coupons as AppliedCouponCodes)"
:open-price-list-modal="openPriceListModal"
:applied-coupons-count="appliedCouponsCount"
:open-shift-close-modal="openShiftCloseModal"
:open-coupon-code-modal="openCouponCodeModal"
Expand Down Expand Up @@ -124,6 +126,7 @@ import {
getPricingRule,
removeFreeItems,
getAddedLPWithGrandTotal,
getItemRateFromPriceList,
} from 'models/helpers';
import {
POSItem,
Expand Down Expand Up @@ -165,6 +168,7 @@ export default defineComponent({
openAlertModal: false,
openPaymentModal: false,
openKeyboardModal: false,
openPriceListModal: false,
openCouponCodeModal: false,
openShiftCloseModal: false,
openSavedInvoiceModal: false,
Expand Down Expand Up @@ -440,7 +444,10 @@ export default defineComponent({
}

if (existingItems.length) {
existingItems[0].rate = item.rate as Money;
if (!this.sinvDoc.priceList) {
existingItems[0].rate = item.rate as Money;
}

existingItems[0].quantity = (existingItems[0].quantity as number) + 1;

await this.applyPricingRule();
Expand All @@ -454,6 +461,17 @@ export default defineComponent({
item: item.name,
});

if (this.sinvDoc.priceList) {
let itemData = this.sinvDoc.items?.filter(
(val) => val.item == item.name
) as SalesInvoiceItem[];

itemData[0].rate = await getItemRateFromPriceList(
itemData[0],
this.sinvDoc.priceList
);
}

await this.applyPricingRule();
await this.sinvDoc.runFormulas();
},
Expand Down
49 changes: 48 additions & 1 deletion src/pages/POS/POSQuickActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@
<div
class="p-0.5 rounded-md bg-gray-100"
:class="{
'bg-gray-100': loyaltyPoints,
'dark:bg-gray-600 cursor-not-allowed':
!sinvDoc?.party || !sinvDoc?.items?.length,
}"
Expand Down Expand Up @@ -249,6 +248,54 @@
{{ appliedCouponsCount }}
</div>
</div>

<div
class="relative group"
:class="{
hidden: !fyo.singles.AccountingSettings?.enablePriceList,
}"
>
<div
class="p-1 rounded-md bg-gray-100"
@click="$emit('toggleModal', 'PriceList')"
>
<svg
xmlns="http://www.w3.org/2000/svg"
height="23px"
viewBox="0 -960 960 960"
width="24px"
fill="#000"
>
<path
d="M180.31-164q-27.01 0-45.66-18.65Q116-201.3 116-228.31v-503.38q0-27.01 18.65-45.66Q153.3-796 180.31-796h599.38q27.01 0 45.66 18.65Q844-758.7 844-731.69v503.38q0 27.01-18.65 45.66Q806.7-164 779.69-164H180.31Zm0-52h599.38q4.62 0 8.46-3.85 3.85-3.84 3.85-8.46v-503.38q0-4.62-3.85-8.46-3.84-3.85-8.46-3.85H180.31q-4.62 0-8.46 3.85-3.85 3.84-3.85 8.46v503.38q0 4.62 3.85 8.46 3.84 3.85 8.46 3.85ZM221-297h172v-52H221v52Zm361-77.23L737.77-530 701-566.77l-119 119-51-51L494.23-462 582-374.23ZM221-454h172v-52H221v52Zm0-156h172v-52H221v52Zm-53 394v-528 528Z"
/>
</svg>
</div>

<span
class="
absolute
bottom-full
left-1/2
transform
-translate-x-1/2
mb-2
bg-gray-100
dark:bg-gray-800 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
"
>
Price List
</span>
</div>
</template>

<script lang="ts">
Expand Down
Loading
Loading