Skip to content

Add script#4074

Open
pepeladeira wants to merge 2 commits into
mainfrom
script-update-excluded-products
Open

Add script#4074
pepeladeira wants to merge 2 commits into
mainfrom
script-update-excluded-products

Conversation

@pepeladeira

@pepeladeira pepeladeira commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features
    • Added an administrative script to enforce “excluded product IDs” rules for sale reward modifiers and to recalculate impacted commission earnings.
    • Supports safe preview via dry-run mode (runs by default unless execution is explicitly enabled).
  • Bug Fixes
    • Corrects reward and commission calculations when excluded products appear in sale event data.
    • Automatically reconciles commissions, including canceling or adjusting payouts/totals when recalculated earnings change.

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dub Ready Ready Preview Jun 24, 2026 10:16pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf8d0688-7ae4-4517-930e-a2d476fc084e

📥 Commits

Reviewing files that changed from the base of the PR and between 3335c47 and accd306.

📒 Files selected for processing (1)
  • apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/scripts/customers/privy/update-excluded-product-rewards.ts

📝 Walkthrough

Walkthrough

Adds a Privy maintenance script that updates sale reward modifiers to exclude selected Stripe products and recalculates affected commission earnings, payouts, and partner totals in dry-run or execute mode.

Changes

Privy excluded product reward sync

Layer / File(s) Summary
Setup and modifier helpers
apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Defines the target workspace and program, dry-run selection, sale metadata types, and reward-modifier merge helpers.
Sale parsing and recalculation
apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Parses sale-event metadata into normalized sale products, fetches commission sale products, and recalculates commission earnings after exclusions.
Reward modifier updates
apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Finds sale rewards used by program groups and updates each reward’s modifiers to include the excluded Stripe product IDs.
Commission updates and entrypoint
apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Scans eligible commissions, applies cancel or update plans, reconciles payouts and partner totals, validates the program, and runs the script with exit handling.

Sequence Diagram(s)

sequenceDiagram
  participant main
  participant updateRewards
  participant updateCommissions
  participant getSaleEvent
  participant determinePartnerRewards
  participant calculateSaleEarnings
  participant Prisma
  participant reconcilePayoutAmounts
  participant syncTotalCommissions

  main->>updateRewards: merge excluded product IDs into reward.modifiers
  updateRewards->>Prisma: update reward.modifiers
  main->>updateCommissions: recalculate eligible commissions
  updateCommissions->>getSaleEvent: load sale event metadata
  getSaleEvent-->>updateCommissions: normalized sale products
  updateCommissions->>determinePartnerRewards: compute eligible rewards
  determinePartnerRewards-->>updateCommissions: reward allocations
  updateCommissions->>calculateSaleEarnings: sum recalculated earnings
  calculateSaleEarnings-->>updateCommissions: new earnings
  updateCommissions->>Prisma: cancel or update commissions
  updateCommissions->>reconcilePayoutAmounts: reconcile affected payouts
  updateCommissions->>syncTotalCommissions: sync partner totals
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • steven-tey

Poem

🐇 I hopped through modifiers by starlit light,
Excluding products that no longer fit right.
Dry-run first, then execute with care,
Commissions and payouts all settled fair.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too generic and doesn't describe what the new script does. Rename it to reflect the main change, e.g. 'Add script to update excluded product rewards and commissions'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch script-update-excluded-products

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/scripts/customers/privy/update-excluded-product-rewards.ts`:
- Around line 251-256: The first-sale lookup in
update-excluded-product-rewards.ts is too broad because the
prisma.commission.findFirst call in the recalculation flow only filters by
partnerId, customerId, and type: "sale". Update that lookup, and any related
logic in the affected recalculation block, to also scope by the current program
so firstCommission cannot come from a different program. Use the existing
commission/program identifiers in this function to keep subscriptionStartDate,
subscriptionDurationMonths, and sale.type based only on the current program’s
first sale.
- Around line 44-54: The exclusion detection in isExclusionModifier is too broad
and matches any zero-value reward modifier with a sale.productId in condition,
which can cause unrelated modifiers to be rewritten. Narrow the match to only
the exact generated exclusion modifier shape by checking the full modifier
structure, including the expected conditions set and absence of extra
country/duration/other constraints, then update the replacement logic in
update-excluded-product-rewards.ts to only replace that specific modifier when
scanning and rebuilding the modifiers array.
- Around line 21-23: The updater currently allows an empty EXCLUDED_PRODUCT_IDS
list, which can cause `updateExcludedProductRewards` to run in `--execute` mode
with a meaningless `productId in []` modifier. Add a fail-fast guard near the
EXCLUDED_PRODUCT_IDS/DRY_RUN setup and in the `updateExcludedProductRewards`
flow so the script exits or skips execution when no product IDs are configured,
preserving `DRY_RUN` behavior only for valid lists.
- Around line 143-150: The `update-excluded-product-rewards` flow is creating a
fake zero-value sale row when `parsed.productId` exists, which later causes
`calculateSaleEarnings` and the commission-cancel path to treat a real sale as
zero revenue. Update the logic around `parsed.productId` in
`update-excluded-product-rewards.ts` so it does not return a synthetic row with
`amount: 0` unless the real amount is known; instead skip the row or populate it
from the verified commission amount only for a confirmed single-product sale.
Make sure the downstream recalculation/cancellation paths that use
`calculateSaleEarnings` and the commission handling at the affected reward
update steps keep the original sale amount intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e8893718-6f4d-42b4-9022-17b413005406

📥 Commits

Reviewing files that changed from the base of the PR and between 83b9bec and 3335c47.

📒 Files selected for processing (1)
  • apps/web/scripts/customers/privy/update-excluded-product-rewards.ts

Comment thread apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Comment on lines +44 to +54
function isExclusionModifier(modifier: RewardConditionsArray[number]) {
const amountIsZero =
modifier.amountInCents === 0 || modifier.amountInPercentage === 0;

return modifier.conditions.some(
(condition) =>
condition.entity === "sale" &&
condition.attribute === "productId" &&
condition.operator === "in" &&
amountIsZero,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Match only the generated exclusion modifier shape.

Line 48 treats any zero-value modifier with a sale.productId in condition as the global exclusion modifier. If an existing modifier also has country/duration/other conditions, Lines 121-130 replace it with a single product condition and change reward semantics.

Suggested narrowing
 function isExclusionModifier(modifier: RewardConditionsArray[number]) {
+  const condition = modifier.conditions[0];
   const amountIsZero =
-    modifier.amountInCents === 0 || modifier.amountInPercentage === 0;
+    modifier.type === RewardStructureEnum.percentage
+      ? modifier.amountInPercentage === 0
+      : modifier.amountInCents === 0;
 
-  return modifier.conditions.some(
-    (condition) =>
+  return Boolean(
+    condition &&
+      modifier.operator === "AND" &&
+      modifier.maxDuration === null &&
+      modifier.conditions.length === 1 &&
       condition.entity === "sale" &&
       condition.attribute === "productId" &&
       condition.operator === "in" &&
       amountIsZero,
   );
 }

Also applies to: 121-130

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/scripts/customers/privy/update-excluded-product-rewards.ts` around
lines 44 - 54, The exclusion detection in isExclusionModifier is too broad and
matches any zero-value reward modifier with a sale.productId in condition, which
can cause unrelated modifiers to be rewritten. Narrow the match to only the
exact generated exclusion modifier shape by checking the full modifier
structure, including the expected conditions set and absence of extra
country/duration/other constraints, then update the replacement logic in
update-excluded-product-rewards.ts to only replace that specific modifier when
scanning and rebuilding the modifiers array.

Comment thread apps/web/scripts/customers/privy/update-excluded-product-rewards.ts Outdated
Comment thread apps/web/scripts/customers/privy/update-excluded-product-rewards.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant