Compare commits
No commits in common. "08fe3954a2bb6e9bf5e0007e4d7916a0ff0ae6ec" and "422e4006130b754b41176030c39fec484acef2e3" have entirely different histories.
08fe3954a2
...
422e400613
5 changed files with 17 additions and 156 deletions
|
|
@ -149,54 +149,3 @@ export const PUT = withAuth(async (req, { session, prisma, params }) => {
|
||||||
return NextResponse.json({ plan: updatedPlan, versioned: false });
|
return NextResponse.json({ plan: updatedPlan, versioned: false });
|
||||||
}
|
}
|
||||||
}, ['admin', 'director']);
|
}, ['admin', 'director']);
|
||||||
|
|
||||||
// DELETE: Delete a plan (restricted to admin and director, and only allowed for DRAFT plans)
|
|
||||||
export const DELETE = withAuth(async (req, { session, prisma, params }) => {
|
|
||||||
const unwrappedParams = await params;
|
|
||||||
const id = parseInt(unwrappedParams.id);
|
|
||||||
|
|
||||||
if (isNaN(id)) {
|
|
||||||
return NextResponse.json({ error: 'ID no válido.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const plan = await prisma.compensationPlan.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: { settlements: true }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!plan) {
|
|
||||||
return NextResponse.json({ error: 'Plan no encontrado.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plan.status !== 'DRAFT') {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: 'Solo se pueden eliminar planes en estado BORRADOR (DRAFT).' },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plan.settlements && plan.settlements.length > 0) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: 'No se puede eliminar el plan porque tiene liquidaciones asociadas.' },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.$transaction(async (tx: any) => {
|
|
||||||
await createAuditLog(tx, {
|
|
||||||
userId: session.userId,
|
|
||||||
action: 'DELETE',
|
|
||||||
targetTable: 'compensation_plans',
|
|
||||||
targetId: id,
|
|
||||||
previousValue: plan,
|
|
||||||
newValue: null,
|
|
||||||
ipAddress: req.headers.get('x-forwarded-for') || '127.0.0.1'
|
|
||||||
});
|
|
||||||
|
|
||||||
await tx.compensationPlan.delete({
|
|
||||||
where: { id }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
}, ['admin', 'director']);
|
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,6 @@
|
||||||
|
|
||||||
.cardFooter {
|
.cardFooter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,29 +36,12 @@ export default function PlansPage() {
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
const [code, setCode] = useState('');
|
const [code, setCode] = useState('');
|
||||||
const [validityStart, setValidityStart] = useState('');
|
const [validityStart, setValidityStart] = useState('');
|
||||||
const [validityEnd, setValidityEnd] = useState('');
|
|
||||||
const [type, setType] = useState('PERCENTAGE');
|
const [type, setType] = useState('PERCENTAGE');
|
||||||
const [metaAmount, setMetaAmount] = useState('');
|
const [metaAmount, setMetaAmount] = useState('');
|
||||||
const [percentageRate, setPercentageRate] = useState('');
|
const [percentageRate, setPercentageRate] = useState('');
|
||||||
const [maxCap, setMaxCap] = useState('');
|
const [maxCap, setMaxCap] = useState('');
|
||||||
const [status, setStatus] = useState('DRAFT');
|
const [status, setStatus] = useState('DRAFT');
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [editPlanId, setEditPlanId] = useState<number | null>(null);
|
|
||||||
|
|
||||||
const handleCloseModal = () => {
|
|
||||||
setName('');
|
|
||||||
setCode('');
|
|
||||||
setValidityStart('');
|
|
||||||
setValidityEnd('');
|
|
||||||
setType('PERCENTAGE');
|
|
||||||
setMetaAmount('');
|
|
||||||
setPercentageRate('');
|
|
||||||
setMaxCap('');
|
|
||||||
setStatus('DRAFT');
|
|
||||||
setEditPlanId(null);
|
|
||||||
setError(null);
|
|
||||||
setShowModal(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchPlans = async () => {
|
const fetchPlans = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -96,16 +79,13 @@ export default function PlansPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = editPlanId ? `/api/plans/${editPlanId}` : '/api/plans';
|
const res = await fetch('/api/plans', {
|
||||||
const method = editPlanId ? 'PUT' : 'POST';
|
method: 'POST',
|
||||||
const res = await fetch(url, {
|
|
||||||
method,
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name,
|
name,
|
||||||
code,
|
code,
|
||||||
validityStart,
|
validityStart,
|
||||||
validityEnd: validityEnd || undefined,
|
|
||||||
type,
|
type,
|
||||||
metaAmount: metaAmount ? parseFloat(metaAmount) : undefined,
|
metaAmount: metaAmount ? parseFloat(metaAmount) : undefined,
|
||||||
percentageRate: percentageRate ? parseFloat(percentageRate) : undefined,
|
percentageRate: percentageRate ? parseFloat(percentageRate) : undefined,
|
||||||
|
|
@ -117,53 +97,26 @@ export default function PlansPage() {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
setError(data.error || 'Failed to submit plan');
|
setError(data.error || 'Failed to create plan');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCloseModal();
|
// Reset form & reload
|
||||||
|
setName('');
|
||||||
|
setCode('');
|
||||||
|
setValidityStart('');
|
||||||
|
setType('PERCENTAGE');
|
||||||
|
setMetaAmount('');
|
||||||
|
setPercentageRate('');
|
||||||
|
setMaxCap('');
|
||||||
|
setStatus('DRAFT');
|
||||||
|
setShowModal(false);
|
||||||
fetchPlans();
|
fetchPlans();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError('An error occurred during submission.');
|
setError('An error occurred during submission.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditClick = (plan: Plan) => {
|
|
||||||
setName(plan.name);
|
|
||||||
setCode(plan.code);
|
|
||||||
setValidityStart(plan.validityStart ? plan.validityStart.substring(0, 10) : '');
|
|
||||||
setValidityEnd(plan.validityEnd ? plan.validityEnd.substring(0, 10) : '');
|
|
||||||
setType(plan.type);
|
|
||||||
setMetaAmount(plan.metaAmount ? plan.metaAmount.toString() : '');
|
|
||||||
setPercentageRate(plan.percentageRate ? plan.percentageRate.toString() : '');
|
|
||||||
setMaxCap(plan.maxCap ? plan.maxCap.toString() : '');
|
|
||||||
setStatus(plan.status);
|
|
||||||
setEditPlanId(plan.id);
|
|
||||||
setShowModal(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeletePlan = async (planId: number) => {
|
|
||||||
if (!confirm(t('plans.confirmDelete'))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(`/api/plans/${planId}`, {
|
|
||||||
method: 'DELETE'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const data = await res.json();
|
|
||||||
alert(data.error || 'Failed to delete plan');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchPlans();
|
|
||||||
} catch (err) {
|
|
||||||
alert('An error occurred while deleting the plan.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggleStatus = async (plan: Plan) => {
|
const handleToggleStatus = async (plan: Plan) => {
|
||||||
const nextStatus = plan.status === 'ACTIVE' ? 'INACTIVE' : 'ACTIVE';
|
const nextStatus = plan.status === 'ACTIVE' ? 'INACTIVE' : 'ACTIVE';
|
||||||
try {
|
try {
|
||||||
|
|
@ -251,23 +204,6 @@ export default function PlansPage() {
|
||||||
>
|
>
|
||||||
{plan.status === 'ACTIVE' ? t('plans.deactivateVersion') : t('plans.activate')}
|
{plan.status === 'ACTIVE' ? t('plans.deactivateVersion') : t('plans.activate')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
onClick={() => handleEditClick(plan)}
|
|
||||||
className={styles.btnSecondary}
|
|
||||||
id={`btn-edit-${plan.id}`}
|
|
||||||
>
|
|
||||||
{t('plans.editPlan')}
|
|
||||||
</button>
|
|
||||||
{plan.status === 'DRAFT' && (
|
|
||||||
<button
|
|
||||||
onClick={() => handleDeletePlan(plan.id)}
|
|
||||||
className={styles.btnSecondary}
|
|
||||||
style={{ borderColor: 'hsl(0, 75%, 60%)', color: 'hsl(0, 75%, 60%)' }}
|
|
||||||
id={`btn-delete-${plan.id}`}
|
|
||||||
>
|
|
||||||
{t('plans.deletePlan')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Link href={`/plans/${plan.id}/rules`} className={styles.btnSecondary} id={`btn-rules-${plan.id}`}>
|
<Link href={`/plans/${plan.id}/rules`} className={styles.btnSecondary} id={`btn-rules-${plan.id}`}>
|
||||||
|
|
@ -285,7 +221,7 @@ export default function PlansPage() {
|
||||||
{showModal && (
|
{showModal && (
|
||||||
<div className={styles.modalOverlay} role="dialog">
|
<div className={styles.modalOverlay} role="dialog">
|
||||||
<div className={styles.modal}>
|
<div className={styles.modal}>
|
||||||
<h2 className={styles.modalTitle}>{editPlanId ? t('plans.modalEditTitle') : t('plans.modalCreateTitle')}</h2>
|
<h2 className={styles.modalTitle}>Crear {t('plans.newPlan')}</h2>
|
||||||
<form onSubmit={handleCreatePlan} className={styles.form}>
|
<form onSubmit={handleCreatePlan} className={styles.form}>
|
||||||
{error && <div className={styles.errorText}>{error}</div>}
|
{error && <div className={styles.errorText}>{error}</div>}
|
||||||
|
|
||||||
|
|
@ -327,17 +263,6 @@ export default function PlansPage() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label className={styles.label} htmlFor="plan-validity-end">{t('plans.modalValidityEnd')}</label>
|
|
||||||
<input
|
|
||||||
id="plan-validity-end"
|
|
||||||
type="date"
|
|
||||||
className={styles.input}
|
|
||||||
value={validityEnd}
|
|
||||||
onChange={(e) => setValidityEnd(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.formGroup}>
|
||||||
<label className={styles.label} htmlFor="plan-type">{t('plans.modalType')}</label>
|
<label className={styles.label} htmlFor="plan-type">{t('plans.modalType')}</label>
|
||||||
<select
|
<select
|
||||||
|
|
@ -393,7 +318,7 @@ export default function PlansPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formActions}>
|
<div className={styles.formActions}>
|
||||||
<button type="button" onClick={handleCloseModal} className={styles.btnSecondary}>
|
<button type="button" onClick={() => setShowModal(false)} className={styles.btnSecondary}>
|
||||||
{t('plans.modalCancel')}
|
{t('plans.modalCancel')}
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" className={styles.btnPrimary} id="btn-save-plan">
|
<button type="submit" className={styles.btnPrimary} id="btn-save-plan">
|
||||||
|
|
|
||||||
|
|
@ -148,13 +148,7 @@
|
||||||
"FIXED": "Fixed Commission"
|
"FIXED": "Fixed Commission"
|
||||||
},
|
},
|
||||||
"errorFind": "Could not find the plan.",
|
"errorFind": "Could not find the plan.",
|
||||||
"errorLoad": "Error loading plan information.",
|
"errorLoad": "Error loading plan information."
|
||||||
"modalValidityEnd": "End Validity (Optional)",
|
|
||||||
"editPlan": "Edit Details",
|
|
||||||
"deletePlan": "Delete Plan",
|
|
||||||
"confirmDelete": "Are you sure you want to delete this plan? This action cannot be undone.",
|
|
||||||
"modalEditTitle": "Edit Plan",
|
|
||||||
"modalCreateTitle": "Create New Plan"
|
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"back": "Back to Plans",
|
"back": "Back to Plans",
|
||||||
|
|
|
||||||
|
|
@ -148,13 +148,7 @@
|
||||||
"FIXED": "Comisión Fija"
|
"FIXED": "Comisión Fija"
|
||||||
},
|
},
|
||||||
"errorFind": "No se pudo encontrar el plan.",
|
"errorFind": "No se pudo encontrar el plan.",
|
||||||
"errorLoad": "Error al cargar la información del plan.",
|
"errorLoad": "Error al cargar la información del plan."
|
||||||
"modalValidityEnd": "Fin de Vigencia (Opcional)",
|
|
||||||
"editPlan": "Editar Detalles",
|
|
||||||
"deletePlan": "Eliminar Plan",
|
|
||||||
"confirmDelete": "¿Está seguro de que desea eliminar este plan? Esta acción no se puede deshacer.",
|
|
||||||
"modalEditTitle": "Editar Plan",
|
|
||||||
"modalCreateTitle": "Crear Nuevo Plan"
|
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"back": "Volver a Planes",
|
"back": "Volver a Planes",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue