Redemption rate part 3 + update cogs options

This commit is contained in:
2025-09-26 00:11:09 -04:00
parent dc774862a7
commit 1696ecf591
4 changed files with 95 additions and 87 deletions

View File

@@ -165,6 +165,7 @@ router.post('/simulate', async (req, res) => {
shippingTiers = [],
merchantFeePercent,
fixedCostPerOrder,
cogsCalculationMode = 'actual',
pointsConfig = {}
} = req.body || {};
@@ -373,74 +374,25 @@ router.post('/simulate', async (req, res) => {
const pointDollarValue = config.points.pointDollarValue || DEFAULT_POINT_DOLLAR_VALUE;
// Calculate redemption rate using aggregated award vs redemption pairing per customer
// Calculate redemption rate using dollars redeemed from the matched order set
let calculatedRedemptionRate = 0;
if (config.points.redemptionRate != null) {
calculatedRedemptionRate = config.points.redemptionRate;
} else if (totals.pointsAwarded > 0 && pointDollarValue > 0) {
const extendedEndDt = DateTime.min(
endDt.plus({ months: 12 }),
DateTime.now().endOf('day')
);
const redemptionStatsQuery = `
SELECT
SUM(awards.points_awarded) AS total_awarded_points,
SUM(
LEAST(
awards.points_awarded,
COALESCE(redemptions.redemption_amount, 0) / ?
)
) AS matched_redeemed_points
FROM (
SELECT
o.order_cid,
SUM(o.summary_points) AS points_awarded
FROM _order o
${promoJoin}
WHERE o.summary_shipping > 0
AND o.summary_total > 0
AND o.order_status NOT IN (15)
AND o.ship_method_selected <> 'holdit'
AND o.ship_country = ?
AND o.date_placed BETWEEN ? AND ?
${promoFilterClause}
GROUP BY o.order_cid
) AS awards
LEFT JOIN (
SELECT
o.order_cid,
SUM(od.discount_amount) AS redemption_amount
FROM order_discounts od
JOIN _order o ON od.order_id = o.order_id
WHERE od.discount_type = 20 AND od.discount_active = 1
AND o.order_status NOT IN (15)
AND o.ship_country = ?
AND o.date_placed BETWEEN ? AND ?
GROUP BY o.order_cid
) AS redemptions ON redemptions.order_cid = awards.order_cid
`;
const redemptionStatsParams = [
pointDollarValue,
...filteredOrdersParams,
shipCountry,
formatDateForSql(startDt),
formatDateForSql(extendedEndDt)
];
const [redemptionStatsRows] = await connection.execute(redemptionStatsQuery, redemptionStatsParams);
const redemptionStats = redemptionStatsRows[0] || {};
const totalAwardedPoints = Number(redemptionStats.total_awarded_points || 0);
const matchedRedeemedPoints = Number(redemptionStats.matched_redeemed_points || 0);
if (totalAwardedPoints > 0 && matchedRedeemedPoints > 0) {
calculatedRedemptionRate = Math.min(1, matchedRedeemedPoints / totalAwardedPoints);
const totalRedeemedPoints = totals.pointsRedeemed / pointDollarValue;
if (totalRedeemedPoints > 0) {
calculatedRedemptionRate = Math.min(1, totalRedeemedPoints / totals.pointsAwarded);
}
}
const redemptionRate = calculatedRedemptionRate;
// Calculate overall average COGS percentage for 'average' mode
let overallCogsPercentage = 0;
if (cogsCalculationMode === 'average' && totals.subtotal > 0) {
overallCogsPercentage = totals.cogs / totals.subtotal;
}
const bucketResults = [];
let weightedProfitAmount = 0;
let weightedProfitPercent = 0;
@@ -457,7 +409,16 @@ router.post('/simulate', async (req, res) => {
const orderValue = data.avgSubtotal > 0 ? data.avgSubtotal : getMidpoint(range);
const shippingChargeBase = data.avgShipRate > 0 ? data.avgShipRate : 0;
const actualShippingCost = data.avgShipCost > 0 ? data.avgShipCost : 0;
const productCogs = data.avgCogs > 0 ? data.avgCogs : 0;
// Calculate COGS based on the selected mode
let productCogs;
if (cogsCalculationMode === 'average') {
// Use overall average COGS percentage applied to this bucket's order value
productCogs = orderValue * overallCogsPercentage;
} else {
// Use actual COGS data from this bucket (existing behavior)
productCogs = data.avgCogs > 0 ? data.avgCogs : 0;
}
const productDiscountAmount = orderValue * productDiscountRate;
const effectiveRegularPrice = productDiscountRate < 0.99
? orderValue / (1 - productDiscountRate)
@@ -557,7 +518,8 @@ router.post('/simulate', async (req, res) => {
redemptionRate,
pointDollarValue,
weightedProfitAmount,
weightedProfitPercent
weightedProfitPercent,
overallCogsPercentage: cogsCalculationMode === 'average' ? overallCogsPercentage : undefined
},
buckets: bucketResults
});