v1.8.0: warehouse module (16 commits), docházka mzda model, leave_type=holiday removal, api.ts race fix

Highlights:
- Warehouse module: receipts, issues, reservations, inventory, reports, dashboard,
  master data (categories, suppliers, locations), FIFO service, integration tests
- Docházka: mzda PDF counting model (Odpracováno / Vč. svátků / Přesčas / Svátek /
  So/Ne / Noc) with Czech weekday names and decimal hours
- AttendanceAdmin/AttendanceHistory KPI cards unified to mzda formula with
  fund bar colored by delta, badges for Práce/Dov/Nem/Sv/Nep
- Remove leave_type=holiday entirely (auto-computed from Czech public holidays)
- Allow multiple work shifts per day (overlap detection only)
- Pre-flight refresh in api.ts eliminates spurious 401s on fresh page loads
- Prisma: company_settings gets 6 nullable columns for warehouse numbering
  (PRI/VYD/INV prefixes, default patterns); migration seeds defaults
This commit is contained in:
BOHA
2026-06-03 23:13:10 +02:00
parent dac45baaa8
commit 5233db2002
149 changed files with 11132 additions and 26950 deletions

View File

@@ -37,11 +37,12 @@ export interface WarehouseReceipt {
first_name: string;
last_name: string;
} | null;
lines?: WarehouseReceiptLine[];
_count?: { items: number };
items?: WarehouseReceiptItem[];
attachments?: WarehouseReceiptAttachment[];
}
export interface WarehouseReceiptLine {
export interface WarehouseReceiptItem {
id: number;
receipt_id: number;
item_id: number;
@@ -74,10 +75,11 @@ export interface WarehouseIssue {
modified_at: string | null;
project?: { id: number; name: string; project_number: string } | null;
issued_by_user?: { id: number; first_name: string; last_name: string } | null;
lines?: WarehouseIssueLine[];
_count?: { items: number };
items?: WarehouseIssueItem[];
}
export interface WarehouseIssueLine {
export interface WarehouseIssueItem {
id: number;
issue_id: number;
item_id: number;
@@ -124,10 +126,10 @@ export interface WarehouseInventorySession {
status: "DRAFT" | "CONFIRMED";
created_at: string;
modified_at: string | null;
lines?: WarehouseInventoryLine[];
items?: WarehouseInventoryItem[];
}
export interface WarehouseInventoryLine {
export interface WarehouseInventoryItem {
id: number;
session_id: number;
item_id: number;
@@ -168,6 +170,16 @@ export interface WarehouseSupplier {
is_active: boolean;
}
export interface MovementLogRow {
date: string;
type: string;
document_number: string;
item_name: string;
quantity: number;
unit_price: number;
supplier_or_project: string;
}
// --- Query Options ---
export const warehouseItemListOptions = (filters: {
@@ -196,11 +208,14 @@ export const warehouseItemListOptions = (filters: {
},
});
export const warehouseItemDetailOptions = (id: string | undefined) =>
export const warehouseItemDetailOptions = (
id: string | undefined,
enabled?: boolean,
) =>
queryOptions({
queryKey: ["warehouse", "items", id],
queryFn: () => jsonQuery<WarehouseItem>(`/api/admin/warehouse/items/${id}`),
enabled: !!id,
enabled: enabled ?? !!id,
});
export const warehouseCategoryListOptions = () =>
@@ -229,11 +244,17 @@ export const warehouseSupplierListOptions = (filters: {
},
});
export const warehouseLocationListOptions = () =>
export const warehouseLocationListOptions = (filters?: {
active?: "true" | "false" | "all";
}) =>
queryOptions({
queryKey: ["warehouse", "locations"],
queryFn: () =>
jsonQuery<WarehouseLocation[]>("/api/admin/warehouse/locations"),
queryKey: ["warehouse", "locations", filters ?? { active: "true" }],
queryFn: () => {
const active = filters?.active ?? "true";
return jsonQuery<WarehouseLocation[]>(
`/api/admin/warehouse/locations?active=${active}`,
);
},
});
export const warehouseReceiptListOptions = (filters: {
@@ -346,7 +367,7 @@ export const warehouseInventoryListOptions = (filters: {
if (filters.status) params.set("status", filters.status);
const qs = params.toString();
return paginatedJsonQuery<WarehouseInventorySession>(
`/api/admin/warehouse/inventory${qs ? `?${qs}` : ""}`,
`/api/admin/warehouse/inventory-sessions${qs ? `?${qs}` : ""}`,
);
},
});
@@ -356,7 +377,7 @@ export const warehouseInventoryDetailOptions = (id: string | undefined) =>
queryKey: ["warehouse", "inventory", id],
queryFn: () =>
jsonQuery<WarehouseInventorySession>(
`/api/admin/warehouse/inventory/${id}`,
`/api/admin/warehouse/inventory-sessions/${id}`,
),
enabled: !!id,
});
@@ -372,7 +393,7 @@ export const warehouseStockStatusOptions = (filters?: {
params.set("category_id", String(filters.category_id));
const qs = params.toString();
return jsonQuery<WarehouseItem[]>(
`/api/admin/warehouse/stock-status${qs ? `?${qs}` : ""}`,
`/api/admin/warehouse/reports/stock-status${qs ? `?${qs}` : ""}`,
);
},
});
@@ -381,5 +402,29 @@ export const warehouseBelowMinimumOptions = () =>
queryOptions({
queryKey: ["warehouse", "below-minimum"],
queryFn: () =>
jsonQuery<WarehouseItem[]>("/api/admin/warehouse/below-minimum"),
jsonQuery<WarehouseItem[]>("/api/admin/warehouse/reports/below-minimum"),
});
export const warehouseMovementLogOptions = (filters?: {
limit?: number;
type?: string;
project_id?: number;
date_from?: string;
date_to?: string;
}) =>
queryOptions({
queryKey: ["warehouse", "movement-log", filters],
queryFn: () => {
const params = new URLSearchParams();
if (filters?.limit) params.set("limit", String(filters.limit));
if (filters?.type) params.set("type", filters.type);
if (filters?.project_id)
params.set("project_id", String(filters.project_id));
if (filters?.date_from) params.set("date_from", filters.date_from);
if (filters?.date_to) params.set("date_to", filters.date_to);
const qs = params.toString();
return jsonQuery<MovementLogRow[]>(
`/api/admin/warehouse/reports/movement-log${qs ? `?${qs}` : ""}`,
);
},
});