feat: allow correcting honey measurements and queen evaluations
Backend Image / build-and-push (push) Successful in 2m3s
Frontend Image / build-and-push (push) Successful in 1m41s

Both records could be created but never changed. A water-content reading
decides whether a batch may be sold as honey at all, and queen ratings drive
breeding decisions - a slipped digit in either is exactly the kind of wrong
value that must not be left standing.

- New PATCH /honey-batches/measurements/:measurementId behind
  honey-batches:measure, and PATCH /queens/evaluations/:evaluationId behind
  queens:evaluate. Both are addressed by the child record's own id, so the
  routes take two path segments and do not collide with PATCH /:id.
- Both log before and after data, like every other correction.
- The measurement list on the honey batch page and the rating list on the queen
  page gained an edit dialog; the rating dialog reuses the existing criteria
  list rather than restating it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5 committed 2026-09-19 08:15:54 +02:00
1 parent b0e05daa42
commit 42ceb33844
14 files changed
+503 -15

No files matched your search

@@ -14,7 +14,11 @@ describe('HoneyBatchesService', () => {
create: jest.Mock;
update: jest.Mock;
};
honeyMeasurement: { create: jest.Mock };
honeyMeasurement: {
create: jest.Mock;
findUnique: jest.Mock;
update: jest.Mock;
};
storageContainer: { findUnique: jest.Mock };
honeyBatchRelocation: { create: jest.Mock; findMany: jest.Mock };
honeyBatchContainerAllocation: {
@@ -60,7 +64,11 @@ describe('HoneyBatchesService', () => {
create: jest.fn(),
update: jest.fn(),
},
honeyMeasurement: { create: jest.fn() },
honeyMeasurement: {
create: jest.fn(),
findUnique: jest.fn(),
update: jest.fn(),
},
storageContainer: { findUnique: jest.fn() },
honeyBatchRelocation: { create: jest.fn(), findMany: jest.fn() },
honeyBatchContainerAllocation: {
@@ -398,4 +406,41 @@ describe('HoneyBatchesService', () => {
expect(prisma.honeyBatchRelocation.create).not.toHaveBeenCalled();
});
});
it('updateMeasurement corrects a reading and logs before/after', async () => {
const before = {
id: 'measurement-1',
honeyBatchId: 'batch-1',
waterContent: 22,
};
prisma.honeyMeasurement.findUnique.mockResolvedValue(before);
prisma.honeyMeasurement.update.mockResolvedValue({
...before,
waterContent: 17.5,
});
prisma.honeyBatch.findUnique.mockResolvedValue(honeyBatch);
await service.updateMeasurement(
'measurement-1',
{ waterContent: 17.5 },
'user-1',
);
expect(auditLog.record).toHaveBeenCalledWith(
expect.objectContaining({
entityType: 'HoneyMeasurement',
entityId: 'measurement-1',
action: 'UPDATE',
beforeData: before,
}),
);
});
it('updateMeasurement throws NotFoundException for an unknown reading', async () => {
prisma.honeyMeasurement.findUnique.mockResolvedValue(null);
await expect(
service.updateMeasurement('missing', { waterContent: 17.5 }, 'user-1'),
).rejects.toBeInstanceOf(NotFoundException);
});
});