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
75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { jsonQuery } from "../../lib/apiAdapter";
|
|
|
|
interface Batch {
|
|
id: number;
|
|
quantity: number;
|
|
unit_price: number;
|
|
received_at: string;
|
|
is_consumed: boolean;
|
|
}
|
|
|
|
interface BatchesResponse {
|
|
batches: Batch[];
|
|
total_stock: number;
|
|
reserved_quantity: number;
|
|
available_quantity: number;
|
|
}
|
|
|
|
interface BatchPickerProps {
|
|
itemId: number | null;
|
|
value: number | null;
|
|
onChange: (batchId: number, unitPrice: number) => void;
|
|
}
|
|
|
|
export default function BatchPicker({
|
|
itemId,
|
|
value,
|
|
onChange,
|
|
}: BatchPickerProps) {
|
|
const { data: response } = useQuery({
|
|
queryKey: ["warehouse", "batches", itemId],
|
|
queryFn: () =>
|
|
jsonQuery<BatchesResponse>(
|
|
`/api/admin/warehouse/items/${itemId}/batches`,
|
|
),
|
|
enabled: !!itemId,
|
|
});
|
|
|
|
const batches = response?.batches ?? [];
|
|
|
|
return (
|
|
<div>
|
|
{response && response.reserved_quantity > 0 && (
|
|
<div
|
|
style={{
|
|
fontSize: "0.75rem",
|
|
color: "var(--text-tertiary)",
|
|
marginBottom: "0.25rem",
|
|
}}
|
|
>
|
|
Dostupné: {response.available_quantity} ks (z toho rezervováno:{" "}
|
|
{response.reserved_quantity} ks)
|
|
</div>
|
|
)}
|
|
<select
|
|
className="admin-form-select"
|
|
value={value ?? ""}
|
|
onChange={(e) => {
|
|
const batchId = Number(e.target.value);
|
|
const batch = batches.find((b) => b.id === batchId);
|
|
if (batch) onChange(batch.id, Number(batch.unit_price));
|
|
}}
|
|
>
|
|
<option value="">-- auto FIFO --</option>
|
|
{batches.map((b) => (
|
|
<option key={b.id} value={b.id}>
|
|
{new Date(b.received_at).toLocaleDateString("cs-CZ")} | {b.quantity}{" "}
|
|
ks | {Number(b.unit_price).toFixed(2)} Kč
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
);
|
|
}
|