Skip to content

fix(core): Persist customFields in updateGlobalSettings mutation - #4343

Merged
michaelbromley merged 6 commits into
vendurehq:masterfrom
Ryrahul:fix/global-settings-custom-fields-overwrite
Feb 21, 2026
Merged

fix(core): Persist customFields in updateGlobalSettings mutation#4343
michaelbromley merged 6 commits into
vendurehq:masterfrom
Ryrahul:fix/global-settings-custom-fields-overwrite

Conversation

@Ryrahul

@Ryrahul Ryrahul commented Feb 12, 2026

Copy link
Copy Markdown
Contributor

Closes #4342

Bug: updateGlobalSettings mutation not persisting custom fields

Issue

The updateGlobalSettings mutation did not persist updates to customFields.

When updating global settings, the custom field values were being overwritten during the update flow, resulting in changes not being saved correctly.

Root Cause

The update flow caused customFields to be reset before the entity was persisted, leading to loss of the updated values.

Fix

Adjusted the update order in GlobalSettingsService.updateSettings() so that custom field updates are preserved and correctly persisted when saving the entity.

Impact

  • No breaking changes
  • No schema changes
  • Ensures consistent and expected behavior for updateGlobalSettings

@vercel

vercel Bot commented Feb 12, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
vendure-storybook Ready Ready Preview, Comment Feb 21, 2026 9:39pm

Request Review

@coderabbitai

coderabbitai Bot commented Feb 12, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The global settings update flow was reordered: the entity is patched, a GlobalSettingsEvent is published, the repository.save is called to persist changes, and then customFieldRelationService.updateRelations is invoked. The method now returns the in-memory settings object rather than performing a final save and returning that result.

🚥 Pre-merge checks | ✅ 5 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (6 files):

⚔️ packages/core/e2e/custom-field-relations.e2e-spec.ts (content)
⚔️ packages/core/src/service/services/administrator.service.ts (content)
⚔️ packages/core/src/service/services/global-settings.service.ts (content)
⚔️ packages/core/src/service/services/payment-method.service.ts (content)
⚔️ packages/core/src/service/services/promotion.service.ts (content)
⚔️ packages/core/src/service/services/shipping-method.service.ts (content)

These conflicts must be resolved before merging into master.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly and specifically describes the main change: fixing custom field persistence in the updateGlobalSettings mutation.
Description check ✅ Passed Description includes issue reference, problem statement, root cause, fix approach, and impact assessment covering all key sections of the template.
Linked Issues check ✅ Passed Code changes implement the required fix: updateSettings now follows patchEntity → publish event → save → updateRelations pattern, and a test case verifies scalar custom field persistence with relational fields.
Out of Scope Changes check ✅ Passed All changes directly address the linked issue: service method refactoring and a corresponding e2e test case with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch fix/global-settings-custom-fields-overwrite
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉


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.

@michaelbromley michaelbromley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR — good diagnosis of the root cause!

The fix needs a couple of adjustments to match established patterns:

1. Use the standard patchEntity → save → updateRelations pattern

Every other service (zone.service.ts, channel.service.ts, etc.) saves the entity between patching and updating relations. This ensures updateRelations() re-fetches the already-persisted scalar values. The method should look like:

async updateSettings(ctx: RequestContext, input: UpdateGlobalSettingsInput): Promise<GlobalSettings> {
    const settings = await this.getSettings(ctx);
    patchEntity(settings, input);
    await this.eventBus.publish(new GlobalSettingsEvent(ctx, settings, input));
    await this.connection.getRepository(ctx, GlobalSettings).save(settings);
    await this.customFieldRelationService.updateRelations(ctx, GlobalSettings, input, settings);
    return settings;
}

Note: the event should be published after patchEntity so listeners receive the updated entity, not the pre-change version.

2. Add a test case

The existing GlobalSettings test in custom-field-relations.e2e-spec.ts only asserts relational custom fields. Please add a case that verifies scalar custom fields persist alongside relational ones.

@Ryrahul

Ryrahul commented Feb 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the PR — good diagnosis of the root cause!

The fix needs a couple of adjustments to match established patterns:

1. Use the standard patchEntity → save → updateRelations pattern

Every other service (zone.service.ts, channel.service.ts, etc.) saves the entity between patching and updating relations. This ensures updateRelations() re-fetches the already-persisted scalar values. The method should look like:

async updateSettings(ctx: RequestContext, input: UpdateGlobalSettingsInput): Promise<GlobalSettings> {
    const settings = await this.getSettings(ctx);
    patchEntity(settings, input);
    await this.eventBus.publish(new GlobalSettingsEvent(ctx, settings, input));
    await this.connection.getRepository(ctx, GlobalSettings).save(settings);
    await this.customFieldRelationService.updateRelations(ctx, GlobalSettings, input, settings);
    return settings;
}

Note: the event should be published after patchEntity so listeners receive the updated entity, not the pre-change version.

2. Add a test case

The existing GlobalSettings test in custom-field-relations.e2e-spec.ts only asserts relational custom fields. Please add a case that verifies scalar custom fields persist alongside relational ones.

Sure, completly missed the event publishing part

@Ryrahul

Ryrahul commented Feb 14, 2026

Copy link
Copy Markdown
Contributor Author

Do we also need to assert the multi relation here? I didn’t add it since similar tests for other entities don’t assert multi in this case, to keep things consistent.

@michaelbromley michaelbromley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the update, looks good 👍

@michaelbromley
michaelbromley enabled auto-merge (squash) February 21, 2026 21:42
@michaelbromley
michaelbromley merged commit 1633446 into vendurehq:master Feb 21, 2026
18 checks passed
@vendure-ci-automation-bot vendure-ci-automation-bot Bot locked and limited conversation to collaborators Feb 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

updateGlobalSettings does not persist scalar custom fields when a relational custom field exists

2 participants