fix(capacity): stabilize PTO flows and calendar consistency

Make PTO creation immediately approved, add PTO deletion, and ensure cache invalidation updates individual/team/revenue capacity consistently.

Harden holiday duplicate handling (422), support PTO-day availability overrides without disabling edits, and align tests plus OpenSpec artifacts with the new behavior.
This commit is contained in:
2026-02-19 22:47:39 -05:00
parent 0a9fdd248b
commit b821713cc7
21 changed files with 1081 additions and 128 deletions

View File

@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest';
import { GENERIC_SERVER_ERROR_MESSAGE, sanitizeApiErrorMessage } from '$lib/services/api';
describe('sanitizeApiErrorMessage', () => {
it('replaces HTML payloads with the generic server error message', () => {
const htmlMessage = '<!DOCTYPE html><html><body>SQL error</body></html>';
expect(sanitizeApiErrorMessage(htmlMessage)).toBe(GENERIC_SERVER_ERROR_MESSAGE);
});
it('replaces SQLSTATE content with the generic server error message', () => {
const sqlMessage = 'SQLSTATE[HY000]: General error: 1 Unknown column';
expect(sanitizeApiErrorMessage(sqlMessage)).toBe(GENERIC_SERVER_ERROR_MESSAGE);
});
it('returns short API messages unchanged', () => {
const userMessage = 'User not found';
expect(sanitizeApiErrorMessage(userMessage)).toBe(userMessage);
});
});

View File

@@ -0,0 +1,40 @@
import { describe, expect, it, vi } from 'vitest';
vi.mock('$lib/services/api', () => ({
api: {
get: vi.fn()
}
}));
import { getTeamCapacity } from '$lib/api/capacity';
import { api } from '$lib/services/api';
describe('capacity api mapping', () => {
it('maps legacy team capacity payload keys', async () => {
vi.mocked(api.get).mockResolvedValueOnce({
month: '2026-02',
person_days: 10.5,
hours: 84,
members: []
});
const payload = await getTeamCapacity('2026-02');
expect(payload.total_person_days).toBe(10.5);
expect(payload.total_hours).toBe(84);
});
it('maps new team capacity payload keys', async () => {
vi.mocked(api.get).mockResolvedValueOnce({
month: '2026-03',
total_person_days: 12,
total_hours: 96,
members: []
});
const payload = await getTeamCapacity('2026-03');
expect(payload.total_person_days).toBe(12);
expect(payload.total_hours).toBe(96);
});
});