Markus Michalski FAQ

Small Business: Price migration

Move product prices in a Sylius shop to the 0% tax category under §19 UStG and back: admin button, console command with all options, rounding limits, skipped variants.

Deutsche Version

Back to overview

Small Business: Price migration

Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net

What the migration does

Existing products keep their tax category (for example 19% or 7%) even after you activate the regulation. The migration moves every product variant to the 0% tax category kleinunternehmer_zero and recalculates the price:

  1. The net price is computed from the current gross price: net = gross / (1 + tax rate), rounded to the nearest cent. The tax rate is the one of the previous tax category for the zone DE.
  2. The variant gets the category kleinunternehmer_zero, and the net price becomes its new price.
  3. The plugin remembers each variant's original tax category, so that a restore knows which category to put back.

Work is done in batches of 100 variants.

graph TD
    A["Variant on its previous tax category"] --> B{"Category, code and tax rate for zone DE present?"}
    B -->|No| C["Skipped, left unchanged"]
    B -->|Yes| D["Net = gross divided by 1 plus tax rate, rounded"]
    D --> E["Category kleinunternehmer_zero, price = net"]
    E --> F["Remember original category in mmd_kleinunternehmer_migrated_variant"]

The migration changes prices in the shop. Back up your database first and check the count with --dry-run.

Migration in the admin

On the settings page (Admin → MMKreativ Plugins → Kleinunternehmer §19 UStG), the "Migrate prices" card shows two counters: how many variants are not yet migrated and how many are already migrated. The Migrate now button only appears while variants are still open, and asks for confirmation.

The card also warns about contradictions:

The button triggers a protected POST request (CSRF token, permission ROLE_ADMINISTRATION_ACCESS). If some variants could not be migrated, you see the message "Some variants could not be migrated (no tax rate for the DE zone on their tax category) and were left unchanged."

The admin only offers the direction towards the small business regulation. Restoring is possible only through the console command.

Migration via console

For scripts and for restoring there is mmd:kleinunternehmer:migrate-prices:

Option Shortcut Description
--to-small-business Migrate prices to the 0% category
--restore Restore previously migrated variants to their original tax category and price
--dry-run Only report how many variants would be affected, without writing anything
--force -f Skip the confirmation prompt

Exactly one of --to-small-business and --restore is required, otherwise the command aborts.

# Preview: how many variants would be affected?
bin/console mmd:kleinunternehmer:migrate-prices --to-small-business --dry-run

# Migrate, with a confirmation prompt
bin/console mmd:kleinunternehmer:migrate-prices --to-small-business

# Migrate in a script without a prompt
bin/console mmd:kleinunternehmer:migrate-prices --to-small-business --force

# Restore the original tax category
bin/console mmd:kleinunternehmer:migrate-prices --restore

Without --force the command refuses to run in a non-interactive environment, because the switch is a one-time step and restoring has rounding deviations. In a script, always pass --force.

With an invalid option combination, or without --force and without a terminal, the command exits with the code INVALID. While working it shows a progress bar. After --to-small-business it checks whether variants are left over and then warns that they were skipped because of a missing tax rate for the zone DE. bin/console mmd:kleinunternehmer:migrate-prices --help shows the detailed help text.

Restoring and its limits

--restore puts back the original tax category of each remembered variant and recalculates the gross price from the variant's current price: gross = net x (1 + original tax rate), rounded to the cent. Only the original tax category is stored, not the price. If you changed the price by hand after the migration, restoring calculates from that new price.

Restoring is not exact to the cent. Because the net price was already rounded to the cent when migrating, the recalculated gross price can deviate from the original by one or two cents. This applies to most tax rates and is not a bug.

If the original tax category or its tax rate for the zone DE no longer exists, the variant stays on the 0% category and its price. The remembered entry is deleted anyway, because retrying would change nothing, and the reported number of restored variants includes such entries.

What is skipped

The plugin does not guess prices, so it skips variants it cannot convert:

Limits of the price conversion