浏览代码

modifcation paiement

jeremy 4 月之前
父节点
当前提交
ef9adad94a
共有 2 个文件被更改,包括 73 次插入18 次删除
  1. 17 0
      backend/src/routes/payments.js
  2. 56 18
      frontend/src/pages/LeaseDetail.jsx

+ 17 - 0
backend/src/routes/payments.js

@@ -65,6 +65,23 @@ router.delete('/:id', (req, res) => {
   res.json({ success: true });
 });
 
+router.put('/:id', (req, res) => {
+  const payment = db.prepare('SELECT id FROM payments WHERE id = ? AND user_id = ?').get(req.params.id, req.userId);
+  if (!payment) return res.status(404).json({ error: 'Paiement non trouvé' });
+
+  const { rent_paid, charges_paid, payment_date, payment_method, notes, is_prorata, prorata_days, prorata_total_days } = req.body;
+  if (rent_paid === undefined || !payment_date) return res.status(400).json({ error: 'Champs requis manquants' });
+
+  db.prepare(`
+    UPDATE payments SET rent_paid = ?, charges_paid = ?, payment_date = ?, payment_method = ?, notes = ?,
+      is_prorata = ?, prorata_days = ?, prorata_total_days = ?
+    WHERE id = ?
+  `).run(rent_paid, charges_paid || 0, payment_date, payment_method || 'virement', notes || null,
+    is_prorata ? 1 : 0, prorata_days || null, prorata_total_days || null, req.params.id);
+
+  res.json({ success: true });
+});
+
 // Pending regularization for a lease
 router.get('/regularization/:lease_id', (req, res) => {
   const lease = db.prepare('SELECT id FROM leases WHERE id = ? AND user_id = ?').get(req.params.lease_id, req.userId);

+ 56 - 18
frontend/src/pages/LeaseDetail.jsx

@@ -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>