feat(berths): bulk price update + per-berth price API

Two new endpoints lift price editing out of the full berth-update form:

- `PATCH /api/v1/berths/[id]/price` — single-berth price edit triggered
  inline from the berth list / detail (no need to open the heavy edit
  modal just to retag a price).
- `POST /api/v1/berths/bulk-update-prices` — multi-row update from a
  selection in the berth list; transactional, audit-logged per row.

Berth list column gets an inline price-edit affordance backed by the
single-berth endpoint; the bulk action lives in the row-selection
toolbar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 15:54:27 +02:00
parent b4bf9cca3f
commit 8c669e2918
5 changed files with 330 additions and 2 deletions

View File

@@ -120,6 +120,39 @@ export const listBerthsSchema = baseListQuerySchema.extend({
export type ListBerthsQuery = z.infer<typeof listBerthsSchema>;
// ─── Update Berth Price ───────────────────────────────────────────────────────
// Single + bulk price update. Carved out from the general updateBerthSchema
// so that callers with the `berths.update_prices` permission (but NOT the
// generic `berths.edit`) can only mutate price + currency, not dimensions
// or mooring metadata.
export const updateBerthPriceSchema = z.object({
price: z.coerce.number().min(0, 'Price must be ≥ 0').nullable(),
priceCurrency: z
.string()
.trim()
.length(3, 'Currency must be a 3-letter ISO code')
.toUpperCase()
.optional(),
});
export type UpdateBerthPriceInput = z.infer<typeof updateBerthPriceSchema>;
export const bulkUpdateBerthPricesSchema = z.object({
updates: z
.array(
z.object({
berthId: z.string().uuid(),
price: z.coerce.number().min(0).nullable(),
priceCurrency: z.string().trim().length(3).toUpperCase().optional(),
}),
)
.min(1, 'At least one berth required')
.max(500, 'Bulk price updates capped at 500 berths per call'),
});
export type BulkUpdateBerthPricesInput = z.infer<typeof bulkUpdateBerthPricesSchema>;
// ─── Add Maintenance Log ──────────────────────────────────────────────────────
export const addMaintenanceLogSchema = z.object({