Fix duplicate top campaign clients by phone
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m22s

This commit is contained in:
Cauê Faleiros
2026-07-29 10:44:22 -03:00
parent 496f9d432d
commit 9c7a383ee2
2 changed files with 7 additions and 23 deletions

View File

@@ -25,24 +25,6 @@ const WHATSAPP_CUSTOMER_PHONE_SQL = `
ELSE ${NORMALIZED_CUSTOMER_PHONE_SQL}
END
`;
const CANONICAL_CAMPAIGN_CUSTOMER_NAME_SQL = `
NULLIF(TRIM(regexp_replace(
regexp_replace(
regexp_replace(
regexp_replace(LOWER(COALESCE(cliente_nome, '')), '[^[:alnum:][:space:]]+', ' ', 'g'),
'(^|[[:space:]])[0-9]{2,14}([[:space:]]|$)',
' ',
'g'
),
'(^|[[:space:]])(ltda|me|eireli|epp)([[:space:]]|$)',
' ',
'g'
),
'[[:space:]]+',
' ',
'g'
)), '')
`;
const CUSTOMER_IDENTITY_CTE = `
WITH customer_phone_by_name AS (
SELECT
@@ -177,7 +159,6 @@ const getTopClientsForCampaign = async ({ days, limit, start, end } = {}) => {
WITH campaign_orders AS (
SELECT
orders.*,
${CANONICAL_CAMPAIGN_CUSTOMER_NAME_SQL} as canonical_customer_name,
${WHATSAPP_CUSTOMER_PHONE_SQL} as whatsapp_phone
FROM orders
)
@@ -199,7 +180,9 @@ const getTopClientsForCampaign = async ({ days, limit, start, end } = {}) => {
WHERE data_pedido_date >= $1::date
AND data_pedido_date <= $2::date
AND whatsapp_phone IS NOT NULL
GROUP BY COALESCE(canonical_customer_name, whatsapp_phone)
-- A campaign recipient is a WhatsApp destination, so each normalized
-- phone number must produce exactly one exported customer.
GROUP BY whatsapp_phone
ORDER BY total_gasto DESC
LIMIT $3;
`, [range.start, range.end, normalizedLimit]);

View File

@@ -75,7 +75,8 @@ test('getTopClientsForCampaign returns top clients for an explicit date range',
assert.equal(queries.length, 1);
assert.deepEqual(queries[0].params, ['2026-06-28', '2026-07-27', 1000]);
assert.match(queries[0].sql, /GROUP BY COALESCE\(canonical_customer_name, whatsapp_phone\)/);
assert.match(queries[0].sql, /GROUP BY whatsapp_phone/);
assert.doesNotMatch(queries[0].sql, /GROUP BY COALESCE\(canonical_customer_name, whatsapp_phone\)/);
assert.match(queries[0].sql, /ARRAY_AGG\(DISTINCT whatsapp_phone\)/);
assert.match(queries[0].sql, /ORDER BY total_gasto DESC/);
});
@@ -95,7 +96,7 @@ test('getTopClientsForCampaign derives an inclusive 30 day range from the end da
});
});
test('getTopClientsForCampaign normalizes phones and ranks one row per canonical client name', async () => {
test('getTopClientsForCampaign normalizes phones and groups one row per WhatsApp number', async () => {
await withCampaignService(async () => ({ rows: [] }), async ({ getTopClientsForCampaign }, queries) => {
await getTopClientsForCampaign({
days: '30',
@@ -105,6 +106,6 @@ test('getTopClientsForCampaign normalizes phones and ranks one row per canonical
assert.match(queries[0].sql, /regexp_replace\(COALESCE\(cliente_fone, ''\), '\\D', '', 'g'\)/);
assert.match(queries[0].sql, /WHEN length\(/);
assert.match(queries[0].sql, /'55' \|\|/);
assert.match(queries[0].sql, /canonical_customer_name/);
assert.match(queries[0].sql, /GROUP BY whatsapp_phone/);
});
});