Skip to content

VCST-6309: Validate list, sale and min quantity on price update API - #242

Merged
OlegoO merged 2 commits into
devfrom
fix/VCST-6309-validate-price-values
Oct 16, 2026
Merged

OlegoO merged 2 commits into
devfrom
fix/VCST-6309-validate-price-values

Conversation

@OlegoO

@OlegoO OlegoO commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Description

The product price update API now validates price values on the server. Before this, PUT /api/products/prices, PUT /api/products/{productId}/prices and PATCH /api/products/prices/{id} stored whatever they received. Integrations, imports and scripts could save a negative or zero list price, a negative sale price, a sale price above the list price, or a min quantity of 0. Only the Admin price grid blocked these values, and only on the client.

Each price in the request must now meet these rules:

  • list > 0
  • sale ≥ 0 and sale ≤ list, when sale is set
  • minQuantity > 0

These are the rules the Admin grid already applies before it enables Save. If any price breaks a rule, nothing is saved. The endpoint returns 400 Bad Request with errors keyed by field. The key holds the index of the product entry and of the price inside it:

{ "[1].Prices[0].List": ["List price must be greater than 0"] }

PATCH /api/products/prices/{id} used to ignore the result of the update it delegates to and always answered 204. It now returns that result, so an invalid patch gets the same 400.

No schema change, no migrations, no new settings, no new dependencies.

New GraphQL queries and mutations

None. This module has no GraphQL surface.

Changes to existing GraphQL queries and mutations

None.

New public services / interfaces / methods

  • VirtoCommerce.PricingModule.Data.Validators.PriceValidator (AbstractValidator<Price>) holds the per-price rules.
  • VirtoCommerce.PricingModule.Data.Validators.ProductPriceValidator (AbstractValidator<ProductPrice>) applies AbstractValidator<Price> to each price in a ProductPrice.

Both are registered in DI as AbstractValidator<Price> and AbstractValidator<ProductPrice>. To relax or extend the rules, for example to allow a zero list price for free items, register your own AbstractValidator<Price> in your module. The controller doesn't need to change.

New protected methods (extensibility)

None.

Breaking changes

  • Compile: PricingModuleController has a new constructor parameter, AbstractValidator<ProductPrice> productPriceValidator. Code that constructs or subclasses the controller directly must pass it. No [Obsolete] overload was added, because the controller is resolved by DI and is not meant to be constructed by hand.
  • Package upgrade: none. No public member was removed or renamed.
  • Runtime: requests that used to succeed with 204 now fail with 400 when a price breaks one of the rules above. This applies to PUT /api/products/prices, PUT /api/products/{productId}/prices and PATCH /api/products/prices/{id}. Check that integrations which write prices through these endpoints don't send zero or negative list prices, negative sale prices, sale prices above the list price, or a minQuantity of 0.

New dependencies

None.

Note (scope): validation runs in the API controller, not in IPriceService. Callers that save through the service directly, such as CSV price import and bulk actions, keep their current behaviour. The CSV importer (vc-module-price-export-import) still accepts list = 0 and doesn't compare sale against list. Prices imported that way are rejected if they are later re-saved through this API unchanged.

Note (error format): errors use the same ModelState / SerializableError shape that PATCH /api/products/prices/{id} already returns for JSON Patch errors. That gives one 400 format across the price endpoints, and it doesn't need a ProblemDetailsFactory.

References

QA-test:

Jira-link:

https://virtocommerce.atlassian.net/browse/VCST-6309

Artifact URL:

https://vc3prerelease.blob.core.windows.net/packages/VirtoCommerce.Pricing_3.1009.0-pr-242-db99.zip
🤖 Generated with Claude Code

@sonarqubecloud

sonarqubecloud Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

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