feat: Profilseite, Etikettendruck mit QR-Code, mehr Automatisierungen und Entra-ID-SSO
- Profilseite mit MFA-Einrichtung, Passwort/E-Mail/Name aendern, Konto deaktivieren - Bearbeiten-Buttons fuer Bienenstaende/Voelker/Koeniginnen/Aufgaben-Datensaetze - Restliche englische Enum-Werte durch deutsche Labels ersetzt (SelectValue-Fix) - Sidebar-Eintraege fuer Ernten/Schleuderungen ergaenzt - Automatisierungen von 3 auf 6 Regeln erweitert (Schwarmstimmung, kritischer Gesundheitsstatus, Lagerbestand) - Responsive Grid-Layout fuer Volk-/Koeniginnen-/Honigchargen-/Bienenstand-Detailseiten - Etikettenvorlagen mit Platzhaltern inkl. QR-Code (verweist auf Herkunftsseite) und PDF-Druck - Entra-ID-SSO (Authorization Code + PKCE, kein Auto-Provisioning, Secrets nur ueber Environment-Variablen)
This commit is contained in:
1 parent
0a52b29c57
commit
8432313fa9
83 files changed
+2684
-289
No files matched your search
@@ -70,7 +70,7 @@ describe('AutomationService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('findAll seeds the three default rules before returning them', async () => {
|
||||
it('findAll seeds all default rules before returning them', async () => {
|
||||
prisma.automationRule.findMany.mockResolvedValue([
|
||||
queenlessRule,
|
||||
varroaRule,
|
||||
@@ -79,7 +79,7 @@ describe('AutomationService', () => {
|
||||
|
||||
const result = await service.findAll();
|
||||
|
||||
expect(prisma.automationRule.upsert).toHaveBeenCalledTimes(3);
|
||||
expect(prisma.automationRule.upsert).toHaveBeenCalledTimes(6);
|
||||
expect(result).toHaveLength(3);
|
||||
});
|
||||
|
||||
@@ -188,6 +188,106 @@ describe('AutomationService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluateSwarmControlCheck', () => {
|
||||
const swarmRule = {
|
||||
id: 'rule-4',
|
||||
triggerType: 'SWARM_MOOD_HIGH',
|
||||
active: true,
|
||||
config: {},
|
||||
actionTemplate: 'Schwarmkontrolle dringend',
|
||||
};
|
||||
|
||||
it('creates a task when swarm mood is HIGH', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(swarmRule);
|
||||
|
||||
await service.evaluateSwarmControlCheck({
|
||||
id: 'check-1',
|
||||
colonyId: 'colony-1',
|
||||
swarmMood: 'HIGH',
|
||||
} as never);
|
||||
|
||||
expect(prisma.task.create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not trigger for a low swarm mood', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(swarmRule);
|
||||
|
||||
await service.evaluateSwarmControlCheck({
|
||||
id: 'check-2',
|
||||
colonyId: 'colony-1',
|
||||
swarmMood: 'LOW',
|
||||
} as never);
|
||||
|
||||
expect(prisma.task.create).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluateColonyHealth', () => {
|
||||
const healthRule = {
|
||||
id: 'rule-5',
|
||||
triggerType: 'COLONY_HEALTH_CRITICAL',
|
||||
active: true,
|
||||
config: {},
|
||||
actionTemplate: 'Kontrolle erforderlich',
|
||||
};
|
||||
|
||||
it('creates a task on the transition into CRITICAL', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(healthRule);
|
||||
|
||||
await service.evaluateColonyHealth(
|
||||
{ id: 'colony-1', healthStatus: 'AVERAGE' } as never,
|
||||
{ id: 'colony-1', healthStatus: 'CRITICAL' } as never,
|
||||
);
|
||||
|
||||
expect(prisma.task.create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not re-trigger when already CRITICAL before the update', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(healthRule);
|
||||
|
||||
await service.evaluateColonyHealth(
|
||||
{ id: 'colony-1', healthStatus: 'CRITICAL' } as never,
|
||||
{ id: 'colony-1', healthStatus: 'CRITICAL' } as never,
|
||||
);
|
||||
|
||||
expect(prisma.task.create).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluateStockItem', () => {
|
||||
const stockRule = {
|
||||
id: 'rule-6',
|
||||
triggerType: 'STOCK_ITEM_LOW',
|
||||
active: true,
|
||||
config: {},
|
||||
actionTemplate: 'Nachbestellung prüfen',
|
||||
};
|
||||
|
||||
it('creates a task when quantity drops below minThreshold', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(stockRule);
|
||||
|
||||
await service.evaluateStockItem({
|
||||
id: 'item-1',
|
||||
quantity: 2,
|
||||
minThreshold: 5,
|
||||
} as never);
|
||||
|
||||
expect(prisma.task.create).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not trigger when minThreshold is not set', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(stockRule);
|
||||
|
||||
await service.evaluateStockItem({
|
||||
id: 'item-2',
|
||||
quantity: 2,
|
||||
minThreshold: null,
|
||||
} as never);
|
||||
|
||||
expect(prisma.task.create).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('records an audit log entry with before/after data', async () => {
|
||||
prisma.automationRule.findUnique.mockResolvedValue(varroaRule);
|
||||
|
||||
Reference in new issue
Block a user