Skip to content

fix(team-plans): track departed member usage so value not lost - #2118

Merged
icecrasher321 merged 12 commits into
stagingfrom
fix/orgs-leave
Nov 30, 2025
Merged

fix(team-plans): track departed member usage so value not lost#2118
icecrasher321 merged 12 commits into
stagingfrom
fix/orgs-leave

Conversation

@icecrasher321

@icecrasher321icecrasher321 commented Nov 26, 2025

Copy link
Copy Markdown
Collaborator

Summary

Must track departed member usage so that is billed by the org.

Type of Change

  • Bug fix

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercelBot commented Nov 26, 2025

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentPreviewCommentsUpdated (UTC)
docsSkippedSkippedNov 30, 2025 2:16am

@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Overview

Greptile Summary

This PR implements tracking of departed member usage for team plans to ensure organizations are properly billed for usage incurred before members leave. Previously, when a member was removed from an organization, their currentPeriodCost was lost, potentially allowing organizations to avoid billing for consumed resources.

Key Changes:

  • Added departedMemberUsage decimal field to the organization table to accumulate usage from removed members
  • Modified member removal endpoint to capture departing member's currentPeriodCost and add it to organization's departedMemberUsage using SQL increment
  • Updated calculateSubscriptionOverage() to include departed member usage when computing team overage charges
  • Added reset logic in invoice webhook to clear departedMemberUsage at the end of each billing period
  • Removed 126 lines of unused code from seat-management.ts (updateOrganizationSeats and validateMemberRemoval functions)

Confidence Score: 4/5

  • This PR is safe to merge with minor concerns around error handling
  • The implementation correctly solves the billing gap by tracking departed member usage. The logic is straightforward: capture usage on removal, include in billing calculations, and reset at period end. The try-catch around usage capture prevents member removal failures. However, the lack of transaction wrapping means there's a small window where a member could be removed but their usage not captured if the update fails (though this is logged). The SQL increment pattern is correct and handles concurrent removals safely.
  • Pay attention to apps/sim/app/api/organizations/[id]/members/[memberId]/route.ts - ensure the non-transactional usage capture approach is acceptable for your use case

Important Files Changed

File Analysis

FilenameScoreOverview
packages/db/schema.ts5/5Added departedMemberUsage decimal field to organization table with default value '0'
apps/sim/app/api/organizations/[id]/members/[memberId]/route.ts4/5Added logic to capture departing member's current period usage and accumulate it in organization's departedMemberUsage field before member deletion
apps/sim/lib/billing/core/billing.ts5/5Updated team overage calculation to include departed member usage in total team usage before computing overage charges
apps/sim/lib/billing/webhooks/invoices.ts5/5Added reset of departedMemberUsage to '0' for team plans when resetting usage at billing period end

Sequence Diagram

sequenceDiagram
participant Admin as Admin/Owner
participant API as DELETE /api/organizations/[id]/members/[memberId]
participant DB as Database
participant Billing as calculateSubscriptionOverage()
participant Webhook as Invoice Webhook Handler
Note over Admin,API: Member Removal Flow
Admin->>API: DELETE request to remove member
API->>DB: Query member role
alt is owner
API-->>Admin: Error: Cannot remove owner
end
API->>DB: SELECT currentPeriodCost FROM userStats WHERE userId = memberId
DB-->>API: Return departed member's usage
alt usage > 0
API->>DB: UPDATE organization SET departedMemberUsage = departedMemberUsage + usage
DB-->>API: Usage accumulated
end
API->>DB: DELETE FROM member WHERE userId = memberId
DB-->>API: Member removed
API-->>Admin: Success response
Note over Billing,Webhook: Billing Calculation Flow
Billing->>DB: SELECT userId FROM member WHERE organizationId = orgId
DB-->>Billing: Return current members
loop For each member
Billing->>DB: Get member's currentPeriodCost
DB-->>Billing: Return usage
end
Billing->>DB: SELECT departedMemberUsage FROM organization
DB-->>Billing: Return departed member usage
Billing->>Billing: totalUsage = currentMemberUsage + departedMemberUsage
Billing->>Billing: Calculate overage = max(0, totalUsage - baseSubscriptionAmount)
Note over Webhook: End of Billing Period
Webhook->>DB: SELECT members for organization
loop For each member
Webhook->>DB: UPDATE userStats SET currentPeriodCost = '0'
end
Webhook->>DB: UPDATE organization SET departedMemberUsage = '0'
DB-->>Webhook: Usage reset for new period
Loading

@greptile-appsgreptile-appsBot 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.

8 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@icecrasher321
icecrasher321 merged commit fc5f815 into stagingNov 30, 2025
9 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/orgs-leave branch November 30, 2025 22:23
waleedlatif1 added a commit that referenced this pull request Dec 1, 2025
… sendgrid, linkedin, more tools (#2148)
* feat(tools): added smtp, sendgrid, mailgun, linkedin, fixed permissions in context menu (#2133)
* feat(tools): added twilio sendgrid integration
* feat(tools): added smtp, sendgrid, mailgun, fixed permissions in context menu
* added top level mocks for sporadically failing tests
* incr type safety
* fix(team-plans): track departed member usage so value not lost (#2118)
* fix(team-plans): track departed member usage so value not lost
* reset usage to 0 when they leave team
* prep merge with stagig
* regen migrations
* fix org invite + ws selection'
---------
Co-authored-by: Waleed <walif6@gmail.com>
* feat(i18n): update translations (#2134)
Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>
* feat(creators): add verification for creators (#2135)
* feat(tools): added apify block/tools (#2136)
* feat(tools): added apify
* cleanup
* feat(i18n): update translations (#2137)
Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>
* feat(env): added more optional env var examples (#2138)
* feat(statuspage): added statuspage, updated list of tools in footer, renamed routes (#2139)
* feat(statuspage): added statuspage, updated list of tools in footer, renamed routes
* ack PR comments
* feat(tools): add generic search tool (#2140)
* feat(i18n): update translations (#2141)
* fix(sdks): bump sdk versions (#2142)
* fix(webhooks): count test webhooks towards usage limit (#2143)
* fix(bill): add requestId to webhook processing (#2144)
* improvement(subflow): remove all associated edges when moving a block into a subflow (#2145)
* improvement(subflow): remove all associated edges when moving a block into a subflow
* ack PR comments
* fix(polling): mark webhook failed on webhook trigger errors (#2146)
* fix(deps): declare core transient deps explicitly (#2147)
* fix(deps): declare core transient deps explicitly
* ack PR comments
---------
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: waleedlatif1 <waleedlatif1@users.noreply.github.com>
Sign up for freeto 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.

2 participants

@icecrasher321@waleedlatif1