feat: warn against harvesting honey during a treatment's Wartezeit

Treatments (Ameisensäure, Oxalsäure, etc.) can require a legally
mandated withdrawal period before honey from that colony may be sold.
Nothing in the app tracked this before, so a beekeeper had no
safeguard against harvesting into an active withdrawal window.

Treatments now optionally record withdrawalPeriodDays (from the
product's Packungsbeilage). The new harvest form fetches each
candidate colony's active withdrawal window and shows an inline
warning naming the product and the date it clears, computed as
max(endDate ?? date) + withdrawalPeriodDays across a colony's
treatments, restricted to windows still in the future.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Sonnet 5 committed 2026-09-06 02:50:34 +02:00
1 parent 0881a38800
commit d42f8331f9
13 files changed
+270 -56

No files matched your search

+37 -36
View File
@@ -569,22 +569,23 @@ model SwarmControlCheck {
// ---------------------------------------------------------------------------
model Treatment {
id String @id @default(cuid())
colonyId String
colony Colony @relation(fields: [colonyId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
date DateTime
startDate DateTime?
endDate DateTime?
product String
activeIngredient String?
amount String?
method String?
reason String?
batchNumber String?
notes String?
createdAt DateTime @default(now())
id String @id @default(cuid())
colonyId String
colony Colony @relation(fields: [colonyId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
date DateTime
startDate DateTime?
endDate DateTime?
product String
activeIngredient String?
amount String?
method String?
reason String?
batchNumber String?
notes String?
withdrawalPeriodDays Int?
createdAt DateTime @default(now())
@@index([colonyId, date])
}
@@ -708,9 +709,9 @@ model HoneyBatch {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
measurements HoneyMeasurement[]
bottlingBatches BottlingBatch[]
relocations HoneyBatchRelocation[]
measurements HoneyMeasurement[]
bottlingBatches BottlingBatch[]
relocations HoneyBatchRelocation[]
containerAllocations HoneyBatchContainerAllocation[]
@@index([status])
@@ -757,10 +758,10 @@ model StorageContainer {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
honeyBatches HoneyBatch[]
relocationsFrom HoneyBatchRelocation[] @relation("RelocationFrom")
relocationsTo HoneyBatchRelocation[] @relation("RelocationTo")
batchAllocations HoneyBatchContainerAllocation[]
honeyBatches HoneyBatch[]
relocationsFrom HoneyBatchRelocation[] @relation("RelocationFrom")
relocationsTo HoneyBatchRelocation[] @relation("RelocationTo")
batchAllocations HoneyBatchContainerAllocation[]
@@index([status])
}
@@ -879,14 +880,14 @@ model Product {
// Etikettenvorlage mit {{Platzhalter}}-Text, wird beim Drucken mit den
// Daten einer Abfuellung befuellt (siehe LabelTemplatesService.renderLabelsPdf).
model LabelTemplate {
id String @id @default(cuid())
name String
id String @id @default(cuid())
name String
// Array of LabelElement objects (text/placeholder/qrCode/image/line), see
// label-templates.service.ts. Drives both the in-browser canvas designer
// and the pdfkit print renderer from the same source of truth.
elements Json @default("[]")
widthMm Float @default(90)
heightMm Float @default(35)
elements Json @default("[]")
widthMm Float @default(90)
heightMm Float @default(35)
// A4 sheet layout. columns/rows are nullable: null means "auto-fit as many
// as fit" (the original behaviour); a real label sheet product (e.g. a
// specific Avery SKU) publishes an exact columns/rows/margin/gap grid, so
@@ -894,14 +895,14 @@ model LabelTemplate {
// pre-die-cut sheet instead of just whatever the naive fit computes.
columns Int?
rows Int?
marginTopMm Float @default(5)
marginLeftMm Float @default(5)
gapXMm Float @default(2)
gapYMm Float @default(2)
isDefault Boolean @default(false)
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
marginTopMm Float @default(5)
marginLeftMm Float @default(5)
gapXMm Float @default(2)
gapYMm Float @default(2)
isDefault Boolean @default(false)
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([active])
}