Skip to content

Creating and editing a price

Prices are entered in a dialog. The fields come from field management (table prices), so they are configurable per installation — custom fields appear automatically.

Permission: price_edit

Entry points

  • Create price — button at the top right of the price list
  • Edit — row action in the list or on the detail page
  • A cell in the price matrix — creates or edits with the device type and price group already filled in

Form fields

Field Required Description
Device type Yes Device type the price applies to
Price group Yes Customer segment the price applies to
Price Yes Amount per unit
Complexity — Effort level (pick list, ISO/DAkkS calibration by default)
Start date / End date — Validity period; empty means open-ended
Quantity / Unit — Reference quantity (fractions allowed) and unit
VAT Yes Tax rate in percent
Discount — Discount in percent
Price min / Price max — Price range (0 means "not set")
Costs — Internal costs

Which fields appear and which are mandatory is controlled by field management. By default Price min and Discount are read-only, matching the V1 setup.

Rules on save

  • One row per combination. Device type, price group, start date and complexity may occur together only once. Two rows in the same slot would force price resolution to pick one of them arbitrarily.
  • Plausible validity period. The end date must not precede the start date — such a window would never be valid.
  • Plausible price range. If both minimum and maximum are set, the minimum must not exceed the maximum.
  • Amounts must not be negative.

Partial updates are checked against the stored record: changing only the end date is still validated against the start date already on file.

Validity periods

Setup Meaning
No dates Valid indefinitely
Start date only Valid from that day onwards
Start and end Valid within the period only

If more than one row is valid on a day, the more specific one wins: a dated row beats an open-ended one, and a later start date beats an earlier one. The result is identical on every supported database.

End dates from legacy data: 2099-12-31

Where a V1 form demanded an end date that does not exist in business terms, a date that never arrives was often entered instead — usually 2099-12-31. V2 reads that as open-ended: list, grid and printed document show nothing there, and the row ranks correctly, namely as open-ended.

The value stays in the database on purpose: V1 selects prices for a booking via end_date >= today and would no longer find a cleared row. If you have switched V1 off and want to clean up for real, use php artisan prices:clear-open-end-sentinel — without --apply it only reports.

Treat a price change as a new validity

For a price increase, do not overwrite the existing price. Duplicate it, set an end date on the original and a start date on the copy. That keeps it traceable which price applied when.

Duplicating

The Duplicate row action opens a pre-filled dialog. The copy needs at least one difference in price group, start date or complexity — otherwise it occupies the same combination as the original and is rejected.

The API can copy with overrides directly:

POST /api/v2/prices/{id}/duplicate
{
  "start_date": "2027-01-01",
  "price": 140.00
}

Effect on existing orders

Order positions copy the price when they are created. Later changes to the price list do not apply retroactively. Inside an order the Refresh prices button deliberately pulls the current values.

API

POST /api/v2/prices
{
  "type_id": "…",
  "category_id": "…",
  "price": 85.00,
  "tax": 19,
  "unit": "EA",
  "complexity": "ISO-Kalibrierung",
  "start_date": "2026-01-01",
  "end_date": null
}

PUT /api/v2/prices/{id}

Device type and price group can also be changed afterwards, to move a row that was filed under the wrong type.

Permissions

Creating, editing and duplicating require price_edit; deleting requires price_delete.