Skip to content

fix(tax-code): fix tax code delete#4555

Open
borbelyr-kong wants to merge 7 commits into
mainfrom
fix/tax-code-delete
Open

fix(tax-code): fix tax code delete#4555
borbelyr-kong wants to merge 7 commits into
mainfrom
fix/tax-code-delete

Conversation

@borbelyr-kong

@borbelyr-kong borbelyr-kong commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @greptileai review this draft

Summary by CodeRabbit

  • New Features
    • Added support for filtering returned plans by tax code IDs.
  • Bug Fixes
    • Prevent tax-code deletion when it’s referenced by existing plans, returning a 409 Conflict with the related plan IDs.
    • Updated tax-code retrieval to no longer allow requesting soft-deleted tax codes.
    • Improved organization default tax-code upsert to reject soft-deleted/inactive tax codes.
  • Tests
    • Expanded coverage for plan-by-tax-code filtering and the “tax code referenced by plan” deletion rule (integration-style checks).

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f646e7de-9214-4ff3-b508-59b1d70420ed

📥 Commits

Reviewing files that changed from the base of the PR and between 7d5e9a3 and 55d7233.

📒 Files selected for processing (3)
  • openmeter/taxcode/service/hooks/planhook.go
  • openmeter/taxcode/service/organizationdefaulttaxcodes.go
  • openmeter/taxcode/service/taxcode.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • openmeter/taxcode/service/hooks/planhook.go
  • openmeter/taxcode/service/organizationdefaulttaxcodes.go
  • openmeter/taxcode/service/taxcode.go

📝 Walkthrough

Walkthrough

Adds tax-code lifecycle hooks, blocks deletion when a plan references a tax code, adds TaxCodes filtering to plan listing, removes the delete feature flag, and rejects soft-deleted tax codes in organization-default tax code updates.

Changes

Tax code deletion guard via plan-reference hooks

Layer / File(s) Summary
Service interface, error types, and ListPlans filter contract
openmeter/taxcode/service.go, openmeter/productcatalog/plan/service.go, openmeter/taxcode/errors.go
Service now embeds models.ServiceHooks[TaxCode], GetTaxCodeInput drops IncludeDeleted, ListPlansInput gains a TaxCodes *filter.FilterString field with validation, and a new 409-conflict ErrTaxCodeReferencedByPlan error type with constructor and detector is added.
Service hooks registry and PlanHook wiring
openmeter/taxcode/service/service.go, app/common/taxcode.go, cmd/server/wire.go, cmd/server/wire_gen.go
Adds the tax-code hook registry to the service implementation, exposes RegisterHooks, initializes the registry in the constructor, and wires NewTaxCodePlanServiceHook into the application and Wire graph.
PlanHook pre-delete check and tests
openmeter/taxcode/service/hooks/planhook.go, openmeter/taxcode/service/hooks/planhook_test.go
Defines the tax-code plan hook aliases, validates plan-hook configuration, lists plans by tax code across active-like statuses during PreDelete, and tests both the blocking and allowing deletion paths with a real environment.
Tax code CRUD hooks and lookup cleanup
openmeter/taxcode/service/taxcode.go, openmeter/taxcode/adapter/taxcode.go
CreateTaxCode, UpdateTaxCode, GetOrCreateByAppMapping, and DeleteTaxCode now invoke the appropriate hooks around adapter calls. GetTaxCode query predicates are grouped into a single Where call.
ListPlans TaxCodes filter in adapter and integration test
openmeter/productcatalog/plan/adapter/plan.go, openmeter/productcatalog/plan/adapter/adapter_test.go
ListPlans applies an optional TaxCodes predicate against non-deleted rate cards, and the adapter test creates tax-coded plans to verify matching and empty-result filtering.
Reject soft-deleted tax codes in org defaults upsert
openmeter/taxcode/service/organizationdefaulttaxcodes.go, openmeter/taxcode/service/organizationdefaulttaxcodes_test.go
UpsertOrganizationDefaultTaxCodes now checks both referenced tax codes through a helper that rejects soft-deleted records, and the tests cover soft-deleted invoicing and credit-grant inputs.
Delete handler always calls tax code deletion
api/v3/handlers/taxcodes/delete.go
Removes the deleteTaxCodeEnabled constant and the Forbidden branch from the tax-code delete handler so it always delegates to the service and returns 204 on success.
Service test stubs implement RegisterHooks
openmeter/productcatalog/tax_test.go, openmeter/server/server_test.go
Adds no-op RegisterHooks methods to the tax-code service stubs used by product-catalog and server tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • openmeterio/openmeter#4061: Both PRs change tax code deletion behavior in openmeter/taxcode/service/taxcode.go, with overlapping delete-path checks and guards.
  • openmeterio/openmeter#4405: Both PRs modify the tax-code delete flow by adding additional deletion-guard logic around DeleteTaxCode.
  • openmeterio/openmeter#4540: Both PRs touch api/v3/handlers/taxcodes/delete.go and the feature-flag gating around tax-code deletion.

Suggested labels

release-note/bug-fix, area/product-catalog

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly points to the main tax code deletion fix in the changeset.
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 fix/tax-code-delete

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.

@borbelyr-kong borbelyr-kong changed the title Fix/tax code delete fix(tax-code): fix tax code delete Jun 23, 2026
@borbelyr-kong borbelyr-kong added the release-note/misc Miscellaneous changes label Jun 23, 2026
@borbelyr-kong

Copy link
Copy Markdown
Contributor Author

@greptileai review this draft

@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR enables tax code deletion by removing the feature-flag guard and introducing a PreDelete hook that blocks deletion when active plans still reference the tax code (HTTP 409). It also adds a TaxCodes filter to ListPlans, hardens UpsertOrganizationDefaultTaxCodes to reject soft-deleted codes, and wires the plan hook into the service via the existing ServiceHookRegistry infrastructure.

  • Delete enforcement: A new planHook.PreDelete queries ListPlans scoped to the tax code's namespace across all non-deleted plan statuses before allowing the soft-delete to proceed.
  • GetTaxCode adapter change: The DeletedAtIsNil() guard was removed so the service layer can retrieve a just-deleted record for PostDelete; callers that need to enforce "not deleted" (e.g. UpdateTaxCode, requireActiveTaxCode) now do so explicitly via IsDeleted() checks.
  • Plan filter: ListPlansInput gains a TaxCodes field that filters by rate card references, used both in the hook and exposed as a general API.

Confidence Score: 4/5

Safe to merge with awareness of the open soft-delete visibility regression in GetTaxCode — all new enforcement logic is sound, but fetching a tax code by ID now returns deleted records to any caller that does not add its own IsDeleted guard.

The adapter's GetTaxCode no longer filters out soft-deleted records, and the public service GetTaxCode method passes through without adding the guard. Every call site introduced in this PR adds an explicit IsDeleted check, but pre-existing callers (including the GET /taxcodes/{id} API handler) have not been updated, so they will return deleted records instead of 404. The rest of the change — the plan hook, the org-defaults hardening, the ListPlans filter — is well-constructed and tested.

openmeter/taxcode/adapter/taxcode.go and openmeter/taxcode/service/taxcode.go — the removal of DeletedAtIsNil from GetTaxCode needs a corresponding guard in the service-level GetTaxCode to avoid exposing soft-deleted records through the public API.

Important Files Changed

Filename Overview
openmeter/taxcode/adapter/taxcode.go Removed DeletedAtIsNil() guard from GetTaxCode so soft-deleted records are now returned; callers such as the public service GetTaxCode method no longer filter them out, causing a regression where deleted tax codes are visible via the API.
openmeter/taxcode/service/taxcode.go DeleteTaxCode and UpdateTaxCode now invoke pre/post hooks; UpdateTaxCode adds an explicit IsDeleted guard; DeleteTaxCode does an extra GetTaxCode round-trip after deletion solely to supply PostDelete, which could be eliminated by reusing the already-fetched existing record.
openmeter/taxcode/service/hooks/planhook.go New PreDelete hook that queries ListPlans to block deletion when plans reference the tax code; includes namespace scoping; page cap of 5 means conflict errors may list fewer than all blocking plans.
openmeter/taxcode/service/organizationdefaulttaxcodes.go Added requireActiveTaxCode helper that explicitly rejects soft-deleted tax codes when setting org defaults; correctly pairs with the now-inclusive GetTaxCode adapter.
openmeter/productcatalog/plan/adapter/plan.go Added TaxCodes filter to ListPlans that joins through phases to non-deleted rate cards; correctly scoped to active rate cards only.
app/common/taxcode.go Wires TaxCodePlanHook into the service via NewTaxCodePlanServiceHook; correctly breaks the plan-taxcode construction cycle by registering the hook after both services exist.
api/v3/handlers/taxcodes/delete.go Removes the deleteTaxCodeEnabled=false guard, enabling the delete endpoint; service-layer checks now provide the real enforcement.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant API as API Handler
    participant SVC as TaxCode Service
    participant Hook as PlanHook (PreDelete)
    participant PlanSVC as Plan Service
    participant DB as Adapter / DB

    API->>SVC: DeleteTaxCode(id)
    SVC->>DB: GetTaxCode(id) — includes soft-deleted
    DB-->>SVC: existing TaxCode
    SVC->>SVC: IsDeleted? → return nil (idempotent)
    SVC->>SVC: IsManagedBySystem? → 409
    SVC->>DB: GetOrganizationDefaultTaxCodes
    DB-->>SVC: defaults
    SVC->>SVC: Is org default? → 409
    SVC->>Hook: PreDelete(taxCode)
    Hook->>PlanSVC: "ListPlans(namespace, allStatuses, taxCodeID, page=1/5)"
    PlanSVC-->>Hook: "matching plans (<=5)"
    alt plans found
        Hook-->>SVC: ErrTaxCodeReferencedByPlan (409)
        SVC-->>API: 409 Conflict + plan_ids
    else no plans
        Hook-->>SVC: nil
        SVC->>DB: DeleteTaxCode (soft-delete)
        SVC->>DB: GetTaxCode (re-fetch deleted record)
        DB-->>SVC: deleted TaxCode
        SVC->>Hook: PostDelete(deletedTaxCode) — noop
        SVC-->>API: 204 No Content
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant API as API Handler
    participant SVC as TaxCode Service
    participant Hook as PlanHook (PreDelete)
    participant PlanSVC as Plan Service
    participant DB as Adapter / DB

    API->>SVC: DeleteTaxCode(id)
    SVC->>DB: GetTaxCode(id) — includes soft-deleted
    DB-->>SVC: existing TaxCode
    SVC->>SVC: IsDeleted? → return nil (idempotent)
    SVC->>SVC: IsManagedBySystem? → 409
    SVC->>DB: GetOrganizationDefaultTaxCodes
    DB-->>SVC: defaults
    SVC->>SVC: Is org default? → 409
    SVC->>Hook: PreDelete(taxCode)
    Hook->>PlanSVC: "ListPlans(namespace, allStatuses, taxCodeID, page=1/5)"
    PlanSVC-->>Hook: "matching plans (<=5)"
    alt plans found
        Hook-->>SVC: ErrTaxCodeReferencedByPlan (409)
        SVC-->>API: 409 Conflict + plan_ids
    else no plans
        Hook-->>SVC: nil
        SVC->>DB: DeleteTaxCode (soft-delete)
        SVC->>DB: GetTaxCode (re-fetch deleted record)
        DB-->>SVC: deleted TaxCode
        SVC->>Hook: PostDelete(deletedTaxCode) — noop
        SVC-->>API: 204 No Content
    end
Loading

Reviews (5): Last reviewed commit: "fix(taxcode): fix review comments" | Re-trigger Greptile

Comment thread openmeter/taxcode/service/taxcode.go
Comment thread openmeter/taxcode/service/hooks/planhook.go

@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: 2

🧹 Nitpick comments (2)
openmeter/taxcode/service/hooks/planvalidator.go (1)

26-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align Validate() with the repo’s validation aggregation convention.

This method returns on first error. In this codebase, Validate() error is expected to aggregate errors and return models.NewNillableGenericValidationError(errors.Join(errs...)).

♻️ Suggested refactor
 import (
 	"context"
+	"errors"
 	"fmt"
@@
 func (e PlanValidatorHookConfig) Validate() error {
+	var errs []error
+
 	if e.PlanService == nil {
-		return fmt.Errorf("plan service is required")
+		errs = append(errs, fmt.Errorf("plan service is required"))
 	}
 
-	return nil
+	return models.NewNillableGenericValidationError(errors.Join(errs...))
 }

As per coding guidelines For Go Validate() error methods, prefer collecting all validation issues into var errs []error and returning models.NewNillableGenericValidationError(errors.Join(errs...)).

🤖 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 `@openmeter/taxcode/service/hooks/planvalidator.go` around lines 26 - 32, The
Validate() method in PlanValidatorHookConfig currently returns immediately on
the first error instead of aggregating all validation errors as per the codebase
convention. Refactor the method to collect validation errors in a slice (var
errs []error) rather than returning early. When the PlanService field is nil,
append the error to the errs slice and continue with any other validations.
Finally, return models.NewNillableGenericValidationError(errors.Join(errs...))
to aggregate and return all collected errors together.

Source: Coding guidelines

openmeter/taxcode/service/hooks/planvalidator_test.go (1)

61-115: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Nice coverage on the core flow—please add the two missing error-path tests.

Would be great to add subtests for:

  1. NewPlanValidatorHook with PlanService: nil
  2. PreDelete when ListPlans returns an error

That closes coverage for all new branches in this file.

As per path instructions **/*_test.go: Make sure the tests are comprehensive and cover the changes.

🤖 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 `@openmeter/taxcode/service/hooks/planvalidator_test.go` around lines 61 - 115,
The TestPlanValidatorHook_PreDelete test function is missing coverage for error
paths. Add two new subtests: one that calls NewPlanValidatorHook with a nil
PlanService value in the PlanValidatorHookConfig to verify it properly handles
and returns an error, and another subtest that uses a stubPlanService configured
to return an error from ListPlans (by adding an error field to the stub) and
verifies that PreDelete properly propagates that error. These error-path tests
will close the coverage gaps for all branches in the hook implementation.

Source: Path instructions

🤖 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 `@openmeter/taxcode/adapter/taxcode.go`:
- Around line 113-116: The GetTaxCode adapter query (lines 113-116) is missing
the DeletedAtIsNil() filter that all other adapter queries like
GetTaxCodeByAppMapping and ListTaxCodes include, allowing it to unexpectedly
return soft-deleted records. Fix this by adding an IncludeDeleted field to the
GetTaxCodeInput struct, then conditionally apply the DeletedAtIsNil() filter in
the GetTaxCode adapter method based on this field (defaulting to false),
ensuring callers can explicitly opt-in to retrieving soft-deleted records.
Alternatively, add DeletedAtIsNil() unconditionally to the GetTaxCode query and
refactor DeleteTaxCode.PostDelete to use a separate internal query method that
explicitly handles soft-deleted records to maintain consistency across all
adapter queries.

In `@openmeter/taxcode/service/hooks/planvalidator.go`:
- Around line 54-59: The pre-delete integrity check for tax codes uses a
hard-coded Status slice that excludes PlanStatusInvalid and will regress when
new plan statuses are introduced. Instead of explicitly listing specific
statuses in the Status field, modify the query to include all possible plan
statuses or query without status filtering (or filter only for deleted plans if
applicable) so that the integrity check catches references in plans with any
status, including invalid and future statuses.

---

Nitpick comments:
In `@openmeter/taxcode/service/hooks/planvalidator_test.go`:
- Around line 61-115: The TestPlanValidatorHook_PreDelete test function is
missing coverage for error paths. Add two new subtests: one that calls
NewPlanValidatorHook with a nil PlanService value in the PlanValidatorHookConfig
to verify it properly handles and returns an error, and another subtest that
uses a stubPlanService configured to return an error from ListPlans (by adding
an error field to the stub) and verifies that PreDelete properly propagates that
error. These error-path tests will close the coverage gaps for all branches in
the hook implementation.

In `@openmeter/taxcode/service/hooks/planvalidator.go`:
- Around line 26-32: The Validate() method in PlanValidatorHookConfig currently
returns immediately on the first error instead of aggregating all validation
errors as per the codebase convention. Refactor the method to collect validation
errors in a slice (var errs []error) rather than returning early. When the
PlanService field is nil, append the error to the errs slice and continue with
any other validations. Finally, return
models.NewNillableGenericValidationError(errors.Join(errs...)) to aggregate and
return all collected errors together.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e988c293-4668-4ac6-b727-1f60ca7ec354

📥 Commits

Reviewing files that changed from the base of the PR and between 277f8d3 and d99b721.

📒 Files selected for processing (16)
  • api/v3/handlers/taxcodes/delete.go
  • app/common/taxcode.go
  • cmd/server/wire.go
  • cmd/server/wire_gen.go
  • openmeter/productcatalog/plan/adapter/adapter_test.go
  • openmeter/productcatalog/plan/adapter/plan.go
  • openmeter/productcatalog/plan/service.go
  • openmeter/productcatalog/tax_test.go
  • openmeter/server/server_test.go
  • openmeter/taxcode/adapter/taxcode.go
  • openmeter/taxcode/errors.go
  • openmeter/taxcode/service.go
  • openmeter/taxcode/service/hooks/planvalidator.go
  • openmeter/taxcode/service/hooks/planvalidator_test.go
  • openmeter/taxcode/service/service.go
  • openmeter/taxcode/service/taxcode.go
💤 Files with no reviewable changes (1)
  • api/v3/handlers/taxcodes/delete.go

Comment on lines +113 to +116
Where(
taxcodedb.Namespace(input.Namespace),
taxcodedb.ID(input.ID),
)

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.

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect TaxCode service methods, especially GetTaxCode and delete flow
ast-grep outline openmeter/taxcode/service/taxcode.go --view expanded

# 2) Find all GetTaxCode call sites in taxcode service + v3 taxcode handlers
rg -n --type=go '\bGetTaxCode\s*\(' openmeter/taxcode openmeter/api/v3/handlers/taxcodes

# 3) Check whether deleted-row guards still exist in service/handler paths
rg -n --type=go 'DeletedAt|IncludeDeleted|IsDeleted|NotFound' openmeter/taxcode openmeter/api/v3/handlers/taxcodes

Repository: openmeterio/openmeter

Length of output: 2389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Get the full GetTaxCode adapter implementation (lines 106-130)
sed -n '106,130p' openmeter/taxcode/adapter/taxcode.go

# 2) Get the DeleteTaxCode service implementation, especially the refetch at line 182
sed -n '149,195p' openmeter/taxcode/service/taxcode.go

# 3) Check UpdateTaxCode service method for soft-delete guards
sed -n '34,67p' openmeter/taxcode/service/taxcode.go

# 4) Look for any NotFound or deletion-aware logic in the service
rg -n --type=go 'ErrNotFound|NotFound|soft.*delete' openmeter/taxcode/service/ -A 2

Repository: openmeterio/openmeter

Length of output: 6314


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Look at adapter.DeleteTaxCode implementation
sed -n '127,150p' openmeter/taxcode/adapter/taxcode.go

# 2) Check ListTaxCodes for soft-delete filtering
sed -n '60,90p' openmeter/taxcode/adapter/taxcode.go

# 3) Search for test coverage on GetTaxCode post-deletion
rg -n --type=go 'GetTaxCode.*after.*[dD]elete|[dD]elete.*GetTaxCode' openmeter/taxcode -A 5

# 4) Check if taxcodedb schema has DeletedAt and how it's used
rg -n --type=go 'DeletedAt|WithDeletedAt' openmeter/taxcode/adapter

Repository: openmeterio/openmeter

Length of output: 3311


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if GetTaxCodeInput has any IncludeDeleted parameter
rg -n --type=go 'type GetTaxCodeInput' openmeter/taxcode -A 10

# Verify the complete DeleteTaxCode adapter to see the soft-delete operation
sed -n '200,220p' openmeter/taxcode/adapter/taxcode.go

# Check if there are any tests specifically for getting a deleted tax code
rg -n --type=go 'Delete.*GetTaxCode|GetTaxCode.*[Dd]elete' openmeter/taxcode --type=go -B 2 -A 8

Repository: openmeterio/openmeter

Length of output: 1235


Add an IncludeDeleted parameter to GetTaxCodeInput or refactor DeleteTaxCode.PostDelete to avoid exposing soft-deleted records.

The GetTaxCode adapter (lines 113–116) queries only by namespace+ID and lacks the DeletedAtIsNil() filter that all other adapter queries use (e.g., GetTaxCodeByAppMapping, UpdateTaxCode, ListTaxCodes). This creates an asymmetry: GetTaxCode can return soft-deleted records, but callers have no way to opt into this behavior since GetTaxCodeInput has no IncludeDeleted field.

The refetch in DeleteTaxCode.PostDelete (service line 182) relies on this unprotected access, but regular reads—like UpdateTaxCode calling GetTaxCode at service line 40—could also unexpectedly receive deleted records. Either add explicit opt-in via IncludeDeleted or refactor the delete hook pattern to preserve consistency with the rest of the adapter.

🤖 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 `@openmeter/taxcode/adapter/taxcode.go` around lines 113 - 116, The GetTaxCode
adapter query (lines 113-116) is missing the DeletedAtIsNil() filter that all
other adapter queries like GetTaxCodeByAppMapping and ListTaxCodes include,
allowing it to unexpectedly return soft-deleted records. Fix this by adding an
IncludeDeleted field to the GetTaxCodeInput struct, then conditionally apply the
DeletedAtIsNil() filter in the GetTaxCode adapter method based on this field
(defaulting to false), ensuring callers can explicitly opt-in to retrieving
soft-deleted records. Alternatively, add DeletedAtIsNil() unconditionally to the
GetTaxCode query and refactor DeleteTaxCode.PostDelete to use a separate
internal query method that explicitly handles soft-deleted records to maintain
consistency across all adapter queries.

Comment thread openmeter/taxcode/service/hooks/planhook.go
@borbelyr-kong borbelyr-kong marked this pull request as ready for review June 23, 2026 21:02
@borbelyr-kong borbelyr-kong requested a review from a team as a code owner June 23, 2026 21:02

@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.

♻️ Duplicate comments (1)
openmeter/taxcode/service/hooks/planhook.go (1)

52-82: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

The status filtering gap flagged in the previous review is still present.

The previous review correctly identified that the hard-coded status list excludes PlanStatusInvalid, which means a tax code can be deleted even when invalid plans reference it. Additionally, this explicit list will need manual updates when new plan statuses are introduced.

🤖 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 `@openmeter/taxcode/service/hooks/planhook.go` around lines 52 - 82, In the
PreDelete method of the planHook struct, the Status filter is using a hard-coded
list that excludes PlanStatusInvalid and will require manual updates when new
statuses are added. Either add PlanStatusInvalid to the Status filter list to
include invalid plans in the reference check, or remove the Status filter
entirely if the intent is to verify that no plans of any status reference the
tax code being deleted. This ensures all referenced plans are detected
regardless of their status.
🤖 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.

Duplicate comments:
In `@openmeter/taxcode/service/hooks/planhook.go`:
- Around line 52-82: In the PreDelete method of the planHook struct, the Status
filter is using a hard-coded list that excludes PlanStatusInvalid and will
require manual updates when new statuses are added. Either add PlanStatusInvalid
to the Status filter list to include invalid plans in the reference check, or
remove the Status filter entirely if the intent is to verify that no plans of
any status reference the tax code being deleted. This ensures all referenced
plans are detected regardless of their status.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9b801067-be76-44bb-94a3-abeb7bee6e98

📥 Commits

Reviewing files that changed from the base of the PR and between d99b721 and ec4da11.

📒 Files selected for processing (7)
  • app/common/taxcode.go
  • cmd/server/wire.go
  • cmd/server/wire_gen.go
  • openmeter/taxcode/service/hooks/planhook.go
  • openmeter/taxcode/service/hooks/planhook_test.go
  • openmeter/taxcode/service/organizationdefaulttaxcodes.go
  • openmeter/taxcode/service/organizationdefaulttaxcodes_test.go
✅ Files skipped from review due to trivial changes (2)
  • openmeter/taxcode/service/hooks/planhook_test.go
  • cmd/server/wire_gen.go

…on update, and use a service-backed plan hook test

@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.

🧹 Nitpick comments (1)
openmeter/taxcode/service/hooks/planhook_test.go (1)

48-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Nice, this reads really cleanly! The given/when/then comments make the two scenarios super easy to follow, and reusing the real pctestutils environment gives you genuine end-to-end confidence in the hook path. 👍

One small thought for later: both subtests share the same ns and run sequentially, so they're correctly relying on no t.Parallel(). If anyone adds parallelism down the road, the shared namespace (and the plan created in the first subtest) would leak across cases. A tiny // note: subtests share ns; do not run in parallel would save a future reader a head-scratch.

🤖 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 `@openmeter/taxcode/service/hooks/planhook_test.go` around lines 48 - 137, The
shared namespace setup in TestPlanHookPreDelete means both subtests depend on
the same state and must not be parallelized; add a brief note near the shared ns
setup or test body making that constraint explicit. Use the
TestPlanHookPreDelete subtests and the shared ns variable as the reference point
so future changes don’t introduce t.Parallel() or other parallel execution that
would leak plan/tax code state between cases.
🤖 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.

Nitpick comments:
In `@openmeter/taxcode/service/hooks/planhook_test.go`:
- Around line 48-137: The shared namespace setup in TestPlanHookPreDelete means
both subtests depend on the same state and must not be parallelized; add a brief
note near the shared ns setup or test body making that constraint explicit. Use
the TestPlanHookPreDelete subtests and the shared ns variable as the reference
point so future changes don’t introduce t.Parallel() or other parallel execution
that would leak plan/tax code state between cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4b811fdd-7359-453d-9583-eeb5833ae377

📥 Commits

Reviewing files that changed from the base of the PR and between ec4da11 and 805f044.

📒 Files selected for processing (4)
  • openmeter/taxcode/service/hooks/planhook.go
  • openmeter/taxcode/service/hooks/planhook_test.go
  • openmeter/taxcode/service/organizationdefaulttaxcodes.go
  • openmeter/taxcode/service/taxcode.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • openmeter/taxcode/service/organizationdefaulttaxcodes.go
  • openmeter/taxcode/service/hooks/planhook.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/misc Miscellaneous changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants