Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Dec 16, 2025

Summary by CodeRabbit

  • New Features

    • Added support for manual commission creation and tracking.
  • Improvements

    • Implemented automatic currency conversion for non-USD earnings.
    • Enhanced deduplication to prevent duplicate commission processing.
    • Strengthened error handling for incomplete transaction or customer data.
    • Commission payload now requires a partnership email for partner-linked commissions.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Contributor

vercel bot commented Dec 16, 2025

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

Project Deployment Review Updated (UTC)
dub Ready Ready Preview Dec 16, 2025 9:31am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

Adds upfront deduplication by invoiceId_programId, consolidates currency conversion for non-USD earnings, and introduces a manual commission path that finds partners by partnership.email to create "custom" commissions and update partner/program totals.

Changes

Cohort / File(s) Change Summary
Import, deduplication, and commission flows
apps/web/lib/partnerstack/import-commissions.ts
Adds upfront deduplication using invoiceId_programId; moves earnings currency conversion to the start of processing; implements manual commission path (no customer/transaction) that looks up partner by partnership.email, creates a custom commission, persists fields, updates partner-program total commissions, and adds explicit missing-transaction/customer error handling. Removes duplicate dedup and duplicate conversion in sale path.
Schema extension for partnership data
apps/web/lib/partnerstack/schemas.ts
Adds required partnership object with email: string to the partnerStackCommission schema.

Sequence Diagram

sequenceDiagram
    participant PS as PartnerStack
    participant Import as ImportProcess
    participant DB as Database
    participant PartnerSvc as PartnerLookup
    participant CommStore as CommissionStore

    PS->>Import: Send commission record

    alt Dedup check (invoiceId_programId)
        Import->>DB: Query by invoiceId_programId
        DB-->>Import: Found / Not Found
        alt Found
            Import-->>PS: Skip (duplicate)
        end
    end

    Note over Import: Apply currency conversion if non-USD

    alt Sale (has customer & transaction)
        Import->>CommStore: Create sale commission (with customer, transaction)
        CommStore->>DB: Persist commission
    else Manual (no customer & no transaction)
        Import->>PartnerSvc: Lookup partner by partnership.email
        PartnerSvc-->>Import: Partner ID / NotFound
        alt Partner found
            Import->>CommStore: Create custom commission (partner, program, earnings)
            CommStore->>DB: Persist commission
            Import->>DB: Update partner+program totalCommissions
            DB-->>Import: OK
        else Partner not found
            Import->>DB: Log PARTNER_NOT_FOUND
            Import-->>PS: Abort / Error
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect import-commissions.ts for correctness of deduplication key and race conditions.
  • Verify upfront currency conversion covers all code paths and preserves rounding/precision.
  • Validate partner lookup by partnership.email, error handling, and totalCommissions update calls.
  • Confirm schema change doesn't break existing validators/consumers.

Possibly related PRs

Suggested reviewers

  • steven-tey
  • TWilson023

Poem

🐇 I hop through ledger lines at dawn,
Skipping duplicates on the lawn.
Found partners by a tiny mail,
Custom coins in a rabbit-tail.
Hooray — totals updated, then I'm gone! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: handling manual commissions in the Partnerstack import process, which is the central addition in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch investigate-ps-commissions

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcff398 and fe1010e.

📒 Files selected for processing (2)
  • apps/web/lib/partnerstack/import-commissions.ts (1 hunks)
  • apps/web/lib/partnerstack/schemas.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: devkiran
Repo: dubinc/dub PR: 2635
File: packages/prisma/schema/payout.prisma:24-25
Timestamp: 2025-07-11T16:28:55.693Z
Learning: In the Dub codebase, multiple payout records can now share the same stripeTransferId because payouts are grouped by partner and processed as single Stripe transfers. This is why the unique constraint was removed from the stripeTransferId field in the Payout model - a single transfer can include multiple payouts for the same partner.
📚 Learning: 2025-08-16T11:14:00.667Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2754
File: apps/web/lib/partnerstack/schemas.ts:47-52
Timestamp: 2025-08-16T11:14:00.667Z
Learning: The PartnerStack API always includes the `group` field in partner responses, so the schema should use `.nullable()` rather than `.nullish()` since the field is never omitted/undefined.

Applied to files:

  • apps/web/lib/partnerstack/schemas.ts
📚 Learning: 2025-12-08T09:44:28.429Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.

Applied to files:

  • apps/web/lib/partnerstack/import-commissions.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
apps/web/lib/partnerstack/import-commissions.ts (3)

156-168: LGTM!

Upfront deduplication using the invoiceId_programId unique constraint is a clean approach. The inline comment clarifies the repurposing of the commission key.


170-182: LGTM!

Currency conversion for earnings is handled correctly with a case-insensitive check and null-safety for fxRates.


220-220: This concern is not applicable. The PartnerStack API returns created_at as a number already in milliseconds, making new Date(commission.created_at) the correct approach. This is confirmed by the ±1 hour window queries elsewhere in the code that would be non-functional if the timestamp format were wrong.

apps/web/lib/partnerstack/schemas.ts (1)

98-100: Verify partnership field is always present in PartnerStack commission responses.

The schema defines partnership as required (non-nullable), while customer and transaction use .nullable(). If PartnerStack commission responses sometimes omit this field, parsing will fail. Cross-reference with PartnerStack API documentation or actual response logs to confirm the field is consistently included across all commission types.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe1010e and 4cd866b.

📒 Files selected for processing (1)
  • apps/web/lib/partnerstack/import-commissions.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-08T09:44:28.429Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3200
File: apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts:55-73
Timestamp: 2025-12-08T09:44:28.429Z
Learning: In apps/web/lib/api/fraud/detect-duplicate-payout-method-fraud.ts, the fraud event creation logic intentionally generates self-referential fraud events (where partnerId equals duplicatePartnerId) for partners with duplicate payout methods. This is by design to create raw events for all partners involved in a duplicate payout method scenario, regardless of whether they reference themselves.

Applied to files:

  • apps/web/lib/partnerstack/import-commissions.ts
📚 Learning: 2025-11-12T22:23:10.414Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 3098
File: apps/web/lib/actions/partners/message-program.ts:49-58
Timestamp: 2025-11-12T22:23:10.414Z
Learning: In apps/web/lib/actions/partners/message-program.ts, when checking if a partner can continue messaging after messaging is disabled, the code intentionally requires `senderPartnerId: null` (program-initiated messages) to prevent partners from continuing to send junk messages. Only conversations started by the program should continue after messaging is disabled, as a spam prevention mechanism.

Applied to files:

  • apps/web/lib/partnerstack/import-commissions.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
apps/web/lib/partnerstack/import-commissions.ts (3)

156-168: LGTM!

Good upfront deduplication using the composite key invoiceId_programId. This prevents duplicate commission imports efficiently at the start of processing.


184-231: LGTM - Manual commission handling with proper program scoping.

The programId filter is now correctly included in the programEnrollment lookup (line 188), addressing the previous review concern. The custom commission creation with amount: 0 and proper earnings is appropriate for manual commissions without transactions.


288-307: Verify amount comparison uses consistent currency basis.

Line 298 uses commission.transaction.amount (the original PartnerStack amount, possibly non-USD) for the deduplication lookup. If existing Dub commissions store converted USD amounts while this compares against the original currency amount, the deduplication check could fail to find matches.

Please confirm whether the amount field in existing Dub commissions stores the original currency value or the USD-converted value. If stored as converted USD, consider using the converted amount variable instead:

-      amount: commission.transaction.amount,
+      amount,

@steven-tey steven-tey merged commit 75d08f3 into main Dec 16, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the investigate-ps-commissions branch December 16, 2025 16:54
@coderabbitai coderabbitai bot mentioned this pull request Dec 16, 2025
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.

3 participants