|
|
@@ -34,6 +34,7 @@ export default function LeaseDetail() {
|
|
|
const [revisions, setRevisions] = useState([])
|
|
|
const [pendingReg, setPendingReg] = useState({ pending: [], total: 0 })
|
|
|
const [showModal, setShowModal] = useState(false)
|
|
|
+ const [editPayment, setEditPayment] = useState(null) // null = création, sinon paiement existant
|
|
|
const [showRevisionModal, setShowRevisionModal] = useState(false)
|
|
|
const [loading, setLoading] = useState(false)
|
|
|
const [revLoading, setRevLoading] = useState(false)
|
|
|
@@ -76,19 +77,52 @@ export default function LeaseDetail() {
|
|
|
|
|
|
useEffect(() => { load() }, [id])
|
|
|
|
|
|
+ const openNewPayment = () => {
|
|
|
+ setEditPayment(null)
|
|
|
+ setForm(f => ({ ...f,
|
|
|
+ period_month: now.getMonth() + 1, period_year: now.getFullYear(),
|
|
|
+ rent_paid: lease.rent_amount, charges_paid: lease.charges_amount,
|
|
|
+ payment_date: now.toISOString().slice(0, 10), payment_method: 'virement',
|
|
|
+ notes: '', apply_regularization: false, is_prorata: false, prorata_days: '', prorata_total_days: '',
|
|
|
+ }))
|
|
|
+ setShowModal(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ const openEditPayment = p => {
|
|
|
+ setEditPayment(p)
|
|
|
+ setForm({
|
|
|
+ period_month: p.period_month, period_year: p.period_year,
|
|
|
+ rent_paid: p.rent_paid, charges_paid: p.charges_paid,
|
|
|
+ payment_date: p.payment_date.slice(0, 10), payment_method: p.payment_method,
|
|
|
+ notes: p.notes || '', apply_regularization: false,
|
|
|
+ is_prorata: !!p.is_prorata, prorata_days: p.prorata_days || '', prorata_total_days: p.prorata_total_days || '',
|
|
|
+ })
|
|
|
+ setShowModal(true)
|
|
|
+ }
|
|
|
+
|
|
|
const handlePayment = async e => {
|
|
|
e.preventDefault(); setLoading(true)
|
|
|
try {
|
|
|
- const payload = {
|
|
|
- ...form,
|
|
|
- lease_id: Number(id),
|
|
|
- charge_regularization: form.apply_regularization ? pendingReg.total : 0,
|
|
|
- is_prorata: form.is_prorata ? 1 : 0,
|
|
|
- prorata_days: form.is_prorata ? form.prorata_days : null,
|
|
|
- prorata_total_days: form.is_prorata ? form.prorata_total_days : null,
|
|
|
+ if (editPayment) {
|
|
|
+ await api.put(`/payments/${editPayment.id}`, {
|
|
|
+ ...form,
|
|
|
+ is_prorata: form.is_prorata ? 1 : 0,
|
|
|
+ prorata_days: form.is_prorata ? form.prorata_days : null,
|
|
|
+ prorata_total_days: form.is_prorata ? form.prorata_total_days : null,
|
|
|
+ })
|
|
|
+ toast.success('Paiement mis à jour !')
|
|
|
+ } else {
|
|
|
+ const payload = {
|
|
|
+ ...form,
|
|
|
+ lease_id: Number(id),
|
|
|
+ charge_regularization: form.apply_regularization ? pendingReg.total : 0,
|
|
|
+ is_prorata: form.is_prorata ? 1 : 0,
|
|
|
+ prorata_days: form.is_prorata ? form.prorata_days : null,
|
|
|
+ prorata_total_days: form.is_prorata ? form.prorata_total_days : null,
|
|
|
+ }
|
|
|
+ await api.post('/payments', payload)
|
|
|
+ toast.success('Paiement enregistré !')
|
|
|
}
|
|
|
- await api.post('/payments', payload)
|
|
|
- toast.success('Paiement enregistré !')
|
|
|
setShowModal(false); load()
|
|
|
} catch (err) { toast.error(err.response?.data?.error || 'Erreur') }
|
|
|
finally { setLoading(false) }
|
|
|
@@ -242,7 +276,7 @@ export default function LeaseDetail() {
|
|
|
<div className="flex items-center justify-between mb-4">
|
|
|
<h2 className="text-xl font-bold text-gray-900">💰 Historique des paiements</h2>
|
|
|
{lease.active && (
|
|
|
- <button onClick={() => setShowModal(true)} className="btn-primary">+ Enregistrer un paiement</button>
|
|
|
+ <button onClick={openNewPayment} className="btn-primary">+ Enregistrer un paiement</button>
|
|
|
)}
|
|
|
</div>
|
|
|
|
|
|
@@ -308,6 +342,7 @@ export default function LeaseDetail() {
|
|
|
<td className="px-6 py-4 text-right font-semibold text-green-700">{fmt(net)}</td>
|
|
|
<td className="px-6 py-4 text-right space-x-2">
|
|
|
<button onClick={() => downloadReceipt(p.id)} className="text-blue-600 hover:text-blue-800 text-sm font-medium" title="Télécharger la quittance PDF">📄 Quittance</button>
|
|
|
+ <button onClick={() => openEditPayment(p)} className="text-gray-500 hover:text-indigo-600 ml-2" title="Modifier">✏️</button>
|
|
|
<button onClick={() => handleDeletePayment(p.id)} className="text-gray-400 hover:text-red-600 ml-2">🗑️</button>
|
|
|
</td>
|
|
|
</tr>
|
|
|
@@ -320,18 +355,21 @@ export default function LeaseDetail() {
|
|
|
|
|
|
{/* Modal paiement */}
|
|
|
{showModal && (
|
|
|
- <Modal title="Enregistrer un paiement" onClose={() => setShowModal(false)}>
|
|
|
+ <Modal title={editPayment ? '✏️ Modifier le paiement' : 'Enregistrer un paiement'} onClose={() => setShowModal(false)}>
|
|
|
<form onSubmit={handlePayment} className="space-y-4">
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
<div>
|
|
|
<label className="label">Mois *</label>
|
|
|
- <select className="input" value={form.period_month} onChange={e => setForm(f => ({ ...f, period_month: Number(e.target.value) }))}>
|
|
|
- {MONTHS.map((m, i) => <option key={i} value={i+1}>{m}</option>)}
|
|
|
- </select>
|
|
|
+ {editPayment
|
|
|
+ ? <input className="input bg-gray-50 text-gray-500" readOnly value={MONTHS[form.period_month - 1]} />
|
|
|
+ : <select className="input" value={form.period_month} onChange={e => setForm(f => ({ ...f, period_month: Number(e.target.value) }))}>
|
|
|
+ {MONTHS.map((m, i) => <option key={i} value={i+1}>{m}</option>)}
|
|
|
+ </select>}
|
|
|
</div>
|
|
|
<div>
|
|
|
<label className="label">Année *</label>
|
|
|
<input className="input" type="number" min="2000" max="2099" value={form.period_year}
|
|
|
+ readOnly={!!editPayment}
|
|
|
onChange={e => setForm(f => ({ ...f, period_year: Number(e.target.value) }))} />
|
|
|
</div>
|
|
|
<div>
|
|
|
@@ -422,7 +460,7 @@ export default function LeaseDetail() {
|
|
|
</div>
|
|
|
)}
|
|
|
|
|
|
- {pendingReg.pending.length > 0 && (
|
|
|
+ {!editPayment && pendingReg.pending.length > 0 && (
|
|
|
<label className={`flex items-start gap-3 p-3 rounded-lg border cursor-pointer ${form.apply_regularization ? (pendingReg.total >= 0 ? 'bg-green-50 border-green-300' : 'bg-orange-50 border-orange-300') : 'bg-gray-50 border-gray-200'}`}>
|
|
|
<input type="checkbox" className="mt-0.5" checked={form.apply_regularization}
|
|
|
onChange={e => setForm(f => ({ ...f, apply_regularization: e.target.checked }))} />
|
|
|
@@ -438,15 +476,15 @@ export default function LeaseDetail() {
|
|
|
)}
|
|
|
|
|
|
<div className="bg-blue-50 rounded-lg p-3 text-sm text-blue-700">
|
|
|
- <strong>Total à encaisser :</strong>{' '}
|
|
|
+ <strong>Total :</strong>{' '}
|
|
|
{fmt(
|
|
|
Number(form.rent_paid || 0) + Number(form.charges_paid || 0) -
|
|
|
- (form.apply_regularization ? (pendingReg.total || 0) : 0)
|
|
|
+ (!editPayment && form.apply_regularization ? (pendingReg.total || 0) : 0)
|
|
|
)}
|
|
|
</div>
|
|
|
<div className="flex gap-3 pt-2">
|
|
|
<button type="button" onClick={() => setShowModal(false)} className="btn-secondary flex-1">Annuler</button>
|
|
|
- <button type="submit" disabled={loading} className="btn-primary flex-1">{loading ? '...' : 'Enregistrer'}</button>
|
|
|
+ <button type="submit" disabled={loading} className="btn-primary flex-1">{loading ? '...' : editPayment ? 'Mettre à jour' : 'Enregistrer'}</button>
|
|
|
</div>
|
|
|
</form>
|
|
|
</Modal>
|