const toNum = (v, fallback = 0) => (v == null ? fallback : Number(v)); export function validateOffers( item, OverAllproductBasedOfferDatas, CartData = [], TakAwayId, DineinId ) { const qty = toNum(item.OrderQty); const amount = toNum(item.TotalAmt); const allOffers = (OverAllproductBasedOfferDatas?.ProdDtl || []).filter( (offer) => offer.OfferType !== "S" && offer.ProdId === item?.ProdId && (offer.LimitUsage > 0 || offer.LimitUsage == null) && (offer.ProdVariantDetails || []).some((variant) => (variant.StockDetails || []).some( (stock) => stock.InwardDtlId === item?.InwardDtlId ) ) ) || []; // filter by offer applicability const applicableOffers = allOffers.filter((offer) => { if (offer.OfferType === "I") { return amount >= (offer.MinPurchase || 0) || qty >= (offer.MinQty || 0); } if (offer.OfferType === "Q") { return qty >= (offer.FromQty || 0) && qty <= (offer.ToQty || Infinity); } if (offer.OfferType === "B") { const cartQty = CartData?.filter((c) => c.ProdId === item.ProdId).reduce( (acc, cur) => acc + toNum(cur.OrderQty), 0 ); return cartQty >= (offer.MinQty || 0); } return false; }); // separate B (buy/get) from others const buyGetOffers = []; let bestNonB = null; let bestDiscount = 0; for (const offer of applicableOffers) { if (offer.OfferType === "B") buyGetOffers.push(offer); else { const discount = offer.ValueType === "F" ? toNum(offer.OfferAmt) : (toNum(offer.OfferAmt) * amount) / 100; if (discount >= bestDiscount) { bestDiscount = discount; bestNonB = offer; } } } // dedupe circular buy/get relationships (keep simpler: remove offers that are circular duplicates) const dedupedBuyGet = buyGetOffers.filter((o, idx, arr) => { if (!o.FreeProducts && !o.FreeProductsList) return true; return !o.FreeProductsList?.some((fp) => arr.some( (other) => other !== o && other.ProdId === fp.FreeProdId && other.FreeProductsList?.some((ofp) => ofp.FreeProdId === o.ProdId) ) ); }); const results = []; if (dedupedBuyGet.length > 0) { for (const o of dedupedBuyGet) results.push(buildOfferObj(o, o.OfferAmt || 0, item, DineinId, TakAwayId)); } else if (bestNonB) { results.push( buildOfferObj(bestNonB, bestDiscount, item, DineinId, TakAwayId) ); } return results; } function buildOfferObj(offer, discount, item, DineinId, TakAwayId) { const freeProductsRaw = offer.FreeProducts || offer.FreeProductsList; const freeProductsArray = freeProductsRaw ? Array.isArray(freeProductsRaw) ? freeProductsRaw : [freeProductsRaw] : []; return { OfferId: offer.OfferId || "", OfferAmount: discount || 0, OfferMode: offer.OfferType, // I/Q/B AcuvalOfferAmount: offer.OfferAmt, OfferValue: offer.OfferAmt || 0, TableName: offer.TableName || "", TableUniqueName: offer.TableUniqueName || "", TableUniqueId: offer.TableUniqueId || "", ActualFreeQty: offer.ActualFreeQty || 0, OfferType: offer.ValueType || "", // F / P Detail: offer.Detail || [], OfferCode: offer.OfferCode || "", CustId: offer.CustId || "", UsedCount: offer.UsedCount || 0, AppliesTo: offer.AppliesTo || "", BookingType: item.BookingTypeName === "Dine In" ? DineinId : TakAwayId, FreeProductsList: freeProductsArray.map((fp) => ({ FreeProdId: fp.FreeProdId || "", FreeQty: fp.FreeQty || 0, FreeProdName: fp.FreeProdName || "", ProdVariantDetails: fp.ProdVariantDetails || [], })), // product-level fields ProdId: item?.ProdId || "", SinglePc: item?.SinglePc || "", StockAvailable: item?.StockAvailable || "", ProdVariantName: item?.ProdVariantName || "", Type: item?.Type || "", BookingType: item?.BookingType || 0, InwardDtlId: item?.InwardDtlId || "", ProdCat: item?.ProdCat || "", HalfPrice: offer?.HalfPrice, MinQty: offer?.MinQty, }; }