Checkpoint: Ajout d'un champ texte libre qui s'affiche quand "Autre..." est sélectionné dans les selects typeAchat, serviceConcerne et ventilationComptable des règles d'automatisme. Le texte saisi remplace "AUTRE" dans le tampon BAP. Disponible dans les deux modes (wizard et avancé).
This commit is contained in:
@@ -68,6 +68,21 @@ export default function AutomationRules() {
|
|||||||
const [conditionsLogic, setConditionsLogic] = useState<"AND" | "OR">("AND");
|
const [conditionsLogic, setConditionsLogic] = useState<"AND" | "OR">("AND");
|
||||||
const [conditions, setConditions] = useState<Condition[]>([{ field: "supplierName", operator: "contains", value: "" }]);
|
const [conditions, setConditions] = useState<Condition[]>([{ field: "supplierName", operator: "contains", value: "" }]);
|
||||||
const [actions, setActions] = useState<Actions>({});
|
const [actions, setActions] = useState<Actions>({});
|
||||||
|
// Textes personnalisés quand "Autre" est sélectionné
|
||||||
|
const [customTypeAchat, setCustomTypeAchat] = useState("");
|
||||||
|
const [customServiceConcerne, setCustomServiceConcerne] = useState("");
|
||||||
|
const [customVentilation, setCustomVentilation] = useState("");
|
||||||
|
|
||||||
|
// Helper : détecte si une valeur est "Autre" (insensible à la casse)
|
||||||
|
const isAutre = (val?: string) => val?.toUpperCase() === "AUTRE";
|
||||||
|
|
||||||
|
// Helper : résout la valeur finale (si Autre + texte perso, retourne le texte perso)
|
||||||
|
const resolveAction = (val?: string, custom?: string) => {
|
||||||
|
if (!val || val === "__NONE__") return undefined;
|
||||||
|
if (isAutre(val) && custom?.trim()) return custom.trim().toUpperCase();
|
||||||
|
if (isAutre(val)) return "AUTRE";
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
const createMutation = trpc.automationRules.create.useMutation({
|
const createMutation = trpc.automationRules.create.useMutation({
|
||||||
onSuccess: (rule) => {
|
onSuccess: (rule) => {
|
||||||
@@ -149,6 +164,9 @@ export default function AutomationRules() {
|
|||||||
setConditionsLogic("AND");
|
setConditionsLogic("AND");
|
||||||
setConditions([{ field: "supplierName", operator: "contains", value: "" }]);
|
setConditions([{ field: "supplierName", operator: "contains", value: "" }]);
|
||||||
setActions({});
|
setActions({});
|
||||||
|
setCustomTypeAchat("");
|
||||||
|
setCustomServiceConcerne("");
|
||||||
|
setCustomVentilation("");
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,9 +180,36 @@ export default function AutomationRules() {
|
|||||||
setConditions([{ field: "supplierName", operator: "contains", value: "" }]);
|
setConditions([{ field: "supplierName", operator: "contains", value: "" }]);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
setActions(JSON.parse(rule.actions));
|
const parsedActions = JSON.parse(rule.actions);
|
||||||
|
// Détecter si les valeurs stockées ne correspondent pas aux valeurs fixes
|
||||||
|
// (ce qui signifie qu'un texte personnalisé avait été saisi)
|
||||||
|
const knownTypeAchat = ["CAPEX", "OPEX", "AUTRE", undefined];
|
||||||
|
const deptNames = departments?.map(d => d.name) || [];
|
||||||
|
const allocNames = allocations?.map(a => a.name) || [];
|
||||||
|
if (parsedActions.typeAchat && !knownTypeAchat.includes(parsedActions.typeAchat)) {
|
||||||
|
setCustomTypeAchat(parsedActions.typeAchat);
|
||||||
|
parsedActions.typeAchat = "AUTRE";
|
||||||
|
} else {
|
||||||
|
setCustomTypeAchat("");
|
||||||
|
}
|
||||||
|
if (parsedActions.serviceConcerne && !deptNames.includes(parsedActions.serviceConcerne) && parsedActions.serviceConcerne !== "AUTRE") {
|
||||||
|
setCustomServiceConcerne(parsedActions.serviceConcerne);
|
||||||
|
parsedActions.serviceConcerne = "AUTRE";
|
||||||
|
} else {
|
||||||
|
setCustomServiceConcerne("");
|
||||||
|
}
|
||||||
|
if (parsedActions.ventilationComptable && !allocNames.includes(parsedActions.ventilationComptable) && parsedActions.ventilationComptable !== "AUTRE") {
|
||||||
|
setCustomVentilation(parsedActions.ventilationComptable);
|
||||||
|
parsedActions.ventilationComptable = "AUTRE";
|
||||||
|
} else {
|
||||||
|
setCustomVentilation("");
|
||||||
|
}
|
||||||
|
setActions(parsedActions);
|
||||||
} catch {
|
} catch {
|
||||||
setActions({});
|
setActions({});
|
||||||
|
setCustomTypeAchat("");
|
||||||
|
setCustomServiceConcerne("");
|
||||||
|
setCustomVentilation("");
|
||||||
}
|
}
|
||||||
setDialogOpen(true);
|
setDialogOpen(true);
|
||||||
};
|
};
|
||||||
@@ -181,7 +226,17 @@ export default function AutomationRules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const conditionsJSON = JSON.stringify(conditions);
|
const conditionsJSON = JSON.stringify(conditions);
|
||||||
const actionsJSON = JSON.stringify(actions);
|
// Résoudre les valeurs finales (remplacer AUTRE par le texte personnalisé si fourni)
|
||||||
|
const resolvedActions: Actions = {
|
||||||
|
typeAchat: resolveAction(actions.typeAchat, customTypeAchat),
|
||||||
|
serviceConcerne: resolveAction(actions.serviceConcerne, customServiceConcerne),
|
||||||
|
ventilationComptable: resolveAction(actions.ventilationComptable, customVentilation),
|
||||||
|
};
|
||||||
|
// Supprimer les clés undefined
|
||||||
|
if (!resolvedActions.typeAchat) delete resolvedActions.typeAchat;
|
||||||
|
if (!resolvedActions.serviceConcerne) delete resolvedActions.serviceConcerne;
|
||||||
|
if (!resolvedActions.ventilationComptable) delete resolvedActions.ventilationComptable;
|
||||||
|
const actionsJSON = JSON.stringify(resolvedActions);
|
||||||
|
|
||||||
if (editingRule) {
|
if (editingRule) {
|
||||||
updateMutation.mutate({
|
updateMutation.mutate({
|
||||||
@@ -476,7 +531,7 @@ export default function AutomationRules() {
|
|||||||
<Label htmlFor="typeAchat">Type d'achat</Label>
|
<Label htmlFor="typeAchat">Type d'achat</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.typeAchat || "__NONE__"}
|
value={actions.typeAchat || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, typeAchat: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, typeAchat: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomTypeAchat(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -485,15 +540,24 @@ export default function AutomationRules() {
|
|||||||
<SelectItem value="__NONE__">Ne pas modifier</SelectItem>
|
<SelectItem value="__NONE__">Ne pas modifier</SelectItem>
|
||||||
<SelectItem value="CAPEX">CAPEX</SelectItem>
|
<SelectItem value="CAPEX">CAPEX</SelectItem>
|
||||||
<SelectItem value="OPEX">OPEX</SelectItem>
|
<SelectItem value="OPEX">OPEX</SelectItem>
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.typeAchat) && (
|
||||||
|
<Input
|
||||||
|
value={customTypeAchat}
|
||||||
|
onChange={(e) => setCustomTypeAchat(e.target.value)}
|
||||||
|
placeholder="Texte à afficher sur le BAP (ex: INVESTISSEMENT)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="serviceConcerne">Service concerné</Label>
|
<Label htmlFor="serviceConcerne">Service concerné</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.serviceConcerne || "__NONE__"}
|
value={actions.serviceConcerne || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, serviceConcerne: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, serviceConcerne: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomServiceConcerne(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -505,15 +569,24 @@ export default function AutomationRules() {
|
|||||||
{dept.name}
|
{dept.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.serviceConcerne) && (
|
||||||
|
<Input
|
||||||
|
value={customServiceConcerne}
|
||||||
|
onChange={(e) => setCustomServiceConcerne(e.target.value)}
|
||||||
|
placeholder="Texte à afficher sur le BAP (ex: LOGISTIQUE)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="ventilationComptable">Ventilation comptable</Label>
|
<Label htmlFor="ventilationComptable">Ventilation comptable</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.ventilationComptable || "__NONE__"}
|
value={actions.ventilationComptable || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, ventilationComptable: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, ventilationComptable: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomVentilation(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -525,8 +598,17 @@ export default function AutomationRules() {
|
|||||||
{alloc.name}
|
{alloc.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.ventilationComptable) && (
|
||||||
|
<Input
|
||||||
|
value={customVentilation}
|
||||||
|
onChange={(e) => setCustomVentilation(e.target.value)}
|
||||||
|
placeholder="Texte à afficher sur le BAP (ex: SANITAIRE)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -667,7 +749,7 @@ export default function AutomationRules() {
|
|||||||
<Label htmlFor="typeAchat">Type d'achat</Label>
|
<Label htmlFor="typeAchat">Type d'achat</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.typeAchat || "__NONE__"}
|
value={actions.typeAchat || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, typeAchat: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, typeAchat: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomTypeAchat(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -676,15 +758,25 @@ export default function AutomationRules() {
|
|||||||
<SelectItem value="__NONE__">Ne pas modifier</SelectItem>
|
<SelectItem value="__NONE__">Ne pas modifier</SelectItem>
|
||||||
<SelectItem value="CAPEX">CAPEX</SelectItem>
|
<SelectItem value="CAPEX">CAPEX</SelectItem>
|
||||||
<SelectItem value="OPEX">OPEX</SelectItem>
|
<SelectItem value="OPEX">OPEX</SelectItem>
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.typeAchat) && (
|
||||||
|
<Input
|
||||||
|
value={customTypeAchat}
|
||||||
|
onChange={(e) => setCustomTypeAchat(e.target.value)}
|
||||||
|
placeholder="Saisir le texte à afficher sur le BAP (ex: INVESTISSEMENT)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="serviceConcerne">Service concerné</Label>
|
<Label htmlFor="serviceConcerne">Service concerné</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.serviceConcerne || "__NONE__"}
|
value={actions.serviceConcerne || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, serviceConcerne: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, serviceConcerne: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomServiceConcerne(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -696,15 +788,24 @@ export default function AutomationRules() {
|
|||||||
{dept.name}
|
{dept.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.serviceConcerne) && (
|
||||||
|
<Input
|
||||||
|
value={customServiceConcerne}
|
||||||
|
onChange={(e) => setCustomServiceConcerne(e.target.value)}
|
||||||
|
placeholder="Saisir le texte à afficher sur le BAP (ex: LOGISTIQUE)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="ventilationComptable">Ventilation comptable</Label>
|
<Label htmlFor="ventilationComptable">Ventilation comptable</Label>
|
||||||
<Select
|
<Select
|
||||||
value={actions.ventilationComptable || "__NONE__"}
|
value={actions.ventilationComptable || "__NONE__"}
|
||||||
onValueChange={(value) => setActions({ ...actions, ventilationComptable: value === "__NONE__" ? undefined : value })}
|
onValueChange={(value) => { setActions({ ...actions, ventilationComptable: value === "__NONE__" ? undefined : value }); if (value !== "AUTRE") setCustomVentilation(""); }}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Ne pas modifier" />
|
<SelectValue placeholder="Ne pas modifier" />
|
||||||
@@ -716,8 +817,17 @@ export default function AutomationRules() {
|
|||||||
{alloc.name}
|
{alloc.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
<SelectItem value="AUTRE">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
{isAutre(actions.ventilationComptable) && (
|
||||||
|
<Input
|
||||||
|
value={customVentilation}
|
||||||
|
onChange={(e) => setCustomVentilation(e.target.value)}
|
||||||
|
placeholder="Saisir le texte à afficher sur le BAP (ex: SANITAIRE)"
|
||||||
|
className="mt-1 border-orange-300 focus:border-orange-500"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user