feat(documents): shared CustomFieldsPrintPicker + detail query types

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-16 20:17:23 +02:00
parent bce0280846
commit 44cfea22ca
4 changed files with 63 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
import { FormControlLabel, Checkbox, Box, Typography } from "@mui/material";
import type { CompanySettingsCustomField } from "../../lib/queries/settings";
interface Props {
/** Company custom field definitions, in positional order (index = print key). */
fields: CompanySettingsCustomField[];
/** Currently selected positional indices. */
selected: number[];
/** Read-only (document not editable / locked by another user). */
disabled?: boolean;
onChange: (next: number[]) => void;
}
/**
* Per-document picker: choose which COMPANY custom fields print on this
* document's PDF. Selection is positional (matches the PDF `custom_<i>` keys).
* Renders nothing when the company has defined no printable custom fields.
*/
export default function CustomFieldsPrintPicker({
fields,
selected,
disabled = false,
onChange,
}: Props) {
const printable = fields.filter((f) => (f.value || "").trim());
if (printable.length === 0) return null;
const toggle = (idx: number, checked: boolean) => {
const set = new Set(selected);
if (checked) set.add(idx);
else set.delete(idx);
onChange([...set].sort((a, b) => a - b));
};
return (
<Box>
<Typography variant="subtitle2" sx={{ mb: 0.5 }}>
Vlastní pole na PDF
</Typography>
{fields.map((f, idx) => {
if (!(f.value || "").trim()) return null;
const label = (f.name || "").trim() ? `${f.name}: ${f.value}` : f.value;
return (
<FormControlLabel
key={idx}
control={
<Checkbox
size="small"
checked={selected.includes(idx)}
disabled={disabled}
onChange={(e) => toggle(idx, e.target.checked)}
/>
}
label={<Typography variant="body2">{label}</Typography>}
/>
);
})}
</Box>
);
}

View File

@@ -85,6 +85,7 @@ export interface InvoiceDetail {
bank_account_id?: number | null; bank_account_id?: number | null;
items?: InvoiceItem[]; items?: InvoiceItem[];
sections?: InvoiceSection[]; sections?: InvoiceSection[];
selected_custom_fields?: number[];
subtotal: number; subtotal: number;
vat_amount: number; vat_amount: number;
total: number; total: number;

View File

@@ -60,6 +60,7 @@ export interface IssuedOrderDetail extends IssuedOrder {
sections: IssuedOrderSection[]; sections: IssuedOrderSection[];
supplier: Record<string, unknown> | null; supplier: Record<string, unknown> | null;
valid_transitions: string[]; valid_transitions: string[];
selected_custom_fields: number[];
/** Fresh edit lock held by ANOTHER user (same shape as offers), else null. */ /** Fresh edit lock held by ANOTHER user (same shape as offers), else null. */
locked_by: { locked_by: {
user_id: number; user_id: number;

View File

@@ -184,6 +184,7 @@ export interface OfferDetailData {
locked_by: OfferLockInfo | null; locked_by: OfferLockInfo | null;
/** Legal next statuses, computed server-side (same contract as issued orders). */ /** Legal next statuses, computed server-side (same contract as issued orders). */
valid_transitions: string[]; valid_transitions: string[];
selected_custom_fields: number[];
} }
export const offerDetailOptions = (id: string | undefined) => export const offerDetailOptions = (id: string | undefined) =>