|
|
@@ -4,7 +4,7 @@ const fs = require('fs');
|
|
|
const multer = require('multer');
|
|
|
const PDFDocument = require('pdfkit');
|
|
|
const { PDFDocument: LibPDFDocument, rgb, StandardFonts } = require('pdf-lib');
|
|
|
-const db = require('../db');
|
|
|
+const pool = require('../db');
|
|
|
const { authMiddleware } = require('../auth');
|
|
|
|
|
|
const router = express.Router();
|
|
|
@@ -32,44 +32,44 @@ const upload = multer({
|
|
|
});
|
|
|
|
|
|
// List charges (filter by property_id, year)
|
|
|
-router.get('/', (req, res) => {
|
|
|
+router.get('/', async (req, res) => {
|
|
|
const { property_id, year } = req.query;
|
|
|
+ const params = [req.userId];
|
|
|
let query = `
|
|
|
SELECT c.*, p.name as property_name
|
|
|
FROM charges c
|
|
|
JOIN properties p ON c.property_id = p.id
|
|
|
- WHERE c.user_id = ?
|
|
|
+ WHERE c.user_id = $1
|
|
|
`;
|
|
|
- const params = [req.userId];
|
|
|
- if (property_id) { query += ' AND c.property_id = ?'; params.push(property_id); }
|
|
|
- if (year) { query += ' AND c.year = ?'; params.push(year); }
|
|
|
+ if (property_id) { query += ` AND c.property_id = $${params.push(property_id)}`; }
|
|
|
+ if (year) { query += ` AND c.year = $${params.push(year)}`; }
|
|
|
query += ' ORDER BY c.date DESC';
|
|
|
- res.json(db.prepare(query).all(...params));
|
|
|
+ res.json((await pool.query(query, params)).rows);
|
|
|
});
|
|
|
|
|
|
// Create charge (with optional invoice file)
|
|
|
-router.post('/', upload.single('invoice'), (req, res) => {
|
|
|
+router.post('/', upload.single('invoice'), async (req, res) => {
|
|
|
const { property_id, category, label, amount, date, year, notes, recoverable } = req.body;
|
|
|
if (!property_id || !category || !label || !amount || !date || !year)
|
|
|
return res.status(400).json({ error: 'Champs requis manquants' });
|
|
|
|
|
|
- const prop = db.prepare('SELECT id FROM properties WHERE id = ? AND user_id = ?').get(property_id, req.userId);
|
|
|
+ const prop = (await pool.query('SELECT id FROM properties WHERE id = $1 AND user_id = $2', [property_id, req.userId])).rows[0];
|
|
|
if (!prop) return res.status(403).json({ error: 'Bien non autorisé' });
|
|
|
|
|
|
const invoice_path = req.file ? req.file.filename : null;
|
|
|
const invoice_name = req.file ? req.file.originalname : null;
|
|
|
|
|
|
- const result = db.prepare(`
|
|
|
+ const result = await pool.query(`
|
|
|
INSERT INTO charges (user_id, property_id, category, label, amount, date, year, invoice_path, invoice_name, notes, recoverable)
|
|
|
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
- `).run(req.userId, property_id, category, label, parseFloat(amount), date, parseInt(year), invoice_path, invoice_name, notes || null, recoverable === 'false' || recoverable === '0' ? 0 : 1);
|
|
|
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id
|
|
|
+ `, [req.userId, property_id, category, label, parseFloat(amount), date, parseInt(year), invoice_path, invoice_name, notes || null, recoverable === 'false' || recoverable === '0' ? 0 : 1]);
|
|
|
|
|
|
- res.status(201).json({ id: result.lastInsertRowid });
|
|
|
+ res.status(201).json({ id: result.rows[0].id });
|
|
|
});
|
|
|
|
|
|
// Update charge (with optional new invoice)
|
|
|
-router.put('/:id', upload.single('invoice'), (req, res) => {
|
|
|
- const charge = db.prepare('SELECT * FROM charges WHERE id = ? AND user_id = ?').get(req.params.id, req.userId);
|
|
|
+router.put('/:id', upload.single('invoice'), async (req, res) => {
|
|
|
+ const charge = (await pool.query('SELECT * FROM charges WHERE id = $1 AND user_id = $2', [req.params.id, req.userId])).rows[0];
|
|
|
if (!charge) return res.status(404).json({ error: 'Charge non trouvée' });
|
|
|
|
|
|
const { category, label, amount, date, year, notes, recoverable } = req.body;
|
|
|
@@ -87,17 +87,17 @@ router.put('/:id', upload.single('invoice'), (req, res) => {
|
|
|
invoice_name = req.file.originalname;
|
|
|
}
|
|
|
|
|
|
- db.prepare(`
|
|
|
- UPDATE charges SET category=?, label=?, amount=?, date=?, year=?, invoice_path=?, invoice_name=?, notes=?, recoverable=?
|
|
|
- WHERE id=?
|
|
|
- `).run(category, label, parseFloat(amount), date, parseInt(year), invoice_path, invoice_name, notes || null, recoverable === 'false' || recoverable === '0' ? 0 : 1, req.params.id);
|
|
|
+ await pool.query(`
|
|
|
+ UPDATE charges SET category=$1, label=$2, amount=$3, date=$4, year=$5, invoice_path=$6, invoice_name=$7, notes=$8, recoverable=$9
|
|
|
+ WHERE id=$10
|
|
|
+ `, [category, label, parseFloat(amount), date, parseInt(year), invoice_path, invoice_name, notes || null, recoverable === 'false' || recoverable === '0' ? 0 : 1, req.params.id]);
|
|
|
|
|
|
res.json({ success: true });
|
|
|
});
|
|
|
|
|
|
// Delete charge
|
|
|
-router.delete('/:id', (req, res) => {
|
|
|
- const charge = db.prepare('SELECT * FROM charges WHERE id = ? AND user_id = ?').get(req.params.id, req.userId);
|
|
|
+router.delete('/:id', async (req, res) => {
|
|
|
+ const charge = (await pool.query('SELECT * FROM charges WHERE id = $1 AND user_id = $2', [req.params.id, req.userId])).rows[0];
|
|
|
if (!charge) return res.status(404).json({ error: 'Charge non trouvée' });
|
|
|
|
|
|
if (charge.invoice_path) {
|
|
|
@@ -105,13 +105,13 @@ router.delete('/:id', (req, res) => {
|
|
|
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
|
}
|
|
|
|
|
|
- db.prepare('DELETE FROM charges WHERE id = ?').run(req.params.id);
|
|
|
+ await pool.query('DELETE FROM charges WHERE id = $1', [req.params.id]);
|
|
|
res.json({ success: true });
|
|
|
});
|
|
|
|
|
|
// Download invoice
|
|
|
-router.get('/:id/invoice', (req, res) => {
|
|
|
- const charge = db.prepare('SELECT * FROM charges WHERE id = ? AND user_id = ?').get(req.params.id, req.userId);
|
|
|
+router.get('/:id/invoice', async (req, res) => {
|
|
|
+ const charge = (await pool.query('SELECT * FROM charges WHERE id = $1 AND user_id = $2', [req.params.id, req.userId])).rows[0];
|
|
|
if (!charge || !charge.invoice_path) return res.status(404).json({ error: 'Facture non trouvée' });
|
|
|
|
|
|
const filePath = path.join(uploadDir, charge.invoice_path);
|
|
|
@@ -122,58 +122,58 @@ router.get('/:id/invoice', (req, res) => {
|
|
|
});
|
|
|
|
|
|
// Annual bilan for a property
|
|
|
-router.get('/bilan/:property_id/:year', (req, res) => {
|
|
|
+router.get('/bilan/:property_id/:year', async (req, res) => {
|
|
|
const { property_id, year } = req.params;
|
|
|
|
|
|
// Verify property ownership
|
|
|
- const prop = db.prepare('SELECT * FROM properties WHERE id = ? AND user_id = ?').get(property_id, req.userId);
|
|
|
+ const prop = (await pool.query('SELECT * FROM properties WHERE id = $1 AND user_id = $2', [property_id, req.userId])).rows[0];
|
|
|
if (!prop) return res.status(403).json({ error: 'Bien non autorisé' });
|
|
|
|
|
|
// Total recoverable charges for this property/year (for tenant billing)
|
|
|
- const totalChargesRow = db.prepare(`
|
|
|
+ const totalChargesRow = (await pool.query(`
|
|
|
SELECT SUM(amount) as total, COUNT(*) as count
|
|
|
- FROM charges WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 1
|
|
|
- `).get(property_id, year, req.userId);
|
|
|
+ FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 1
|
|
|
+ `, [property_id, year, req.userId])).rows[0];
|
|
|
|
|
|
// Total non-recoverable (landlord's own charges, for info)
|
|
|
- const totalNonRecovRow = db.prepare(`
|
|
|
+ const totalNonRecovRow = (await pool.query(`
|
|
|
SELECT SUM(amount) as total, COUNT(*) as count
|
|
|
- FROM charges WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 0
|
|
|
- `).get(property_id, year, req.userId);
|
|
|
+ FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 0
|
|
|
+ `, [property_id, year, req.userId])).rows[0];
|
|
|
|
|
|
const totalChargesReelles = totalChargesRow?.total || 0;
|
|
|
const totalNonRecoverable = totalNonRecovRow?.total || 0;
|
|
|
|
|
|
// Charges by category (recoverable only)
|
|
|
- const chargesByCategory = db.prepare(`
|
|
|
+ const chargesByCategory = (await pool.query(`
|
|
|
SELECT category, SUM(amount) as total
|
|
|
- FROM charges WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 1
|
|
|
+ FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 1
|
|
|
GROUP BY category ORDER BY total DESC
|
|
|
- `).all(property_id, year, req.userId);
|
|
|
+ `, [property_id, year, req.userId])).rows;
|
|
|
|
|
|
// Non-recoverable by category (for info)
|
|
|
- const chargesNonRecovByCategory = db.prepare(`
|
|
|
+ const chargesNonRecovByCategory = (await pool.query(`
|
|
|
SELECT category, SUM(amount) as total
|
|
|
- FROM charges WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 0
|
|
|
+ FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 0
|
|
|
GROUP BY category ORDER BY total DESC
|
|
|
- `).all(property_id, year, req.userId);
|
|
|
+ `, [property_id, year, req.userId])).rows;
|
|
|
|
|
|
// All leases on this property (active or that were active during the year)
|
|
|
- const leases = db.prepare(`
|
|
|
+ const leases = (await pool.query(`
|
|
|
SELECT l.*, t.first_name, t.last_name, t.email
|
|
|
FROM leases l
|
|
|
JOIN tenants t ON l.tenant_id = t.id
|
|
|
- WHERE l.property_id = ? AND l.user_id = ?
|
|
|
- AND (l.start_date <= ? AND (l.end_date IS NULL OR l.end_date >= ?))
|
|
|
- `).all(property_id, req.userId, `${year}-12-31`, `${year}-01-01`);
|
|
|
+ WHERE l.property_id = $1 AND l.user_id = $2
|
|
|
+ AND (l.start_date <= $3 AND (l.end_date IS NULL OR l.end_date >= $4))
|
|
|
+ `, [property_id, req.userId, `${year}-12-31`, `${year}-01-01`])).rows;
|
|
|
|
|
|
// For each lease, get provisions perçues for the year
|
|
|
- const leaseBilans = leases.map(lease => {
|
|
|
- const provisions = db.prepare(`
|
|
|
+ const leaseBilans = await Promise.all(leases.map(async lease => {
|
|
|
+ const provisions = (await pool.query(`
|
|
|
SELECT SUM(charges_paid) as total
|
|
|
FROM payments
|
|
|
- WHERE lease_id = ? AND period_year = ?
|
|
|
- `).get(lease.id, year);
|
|
|
+ WHERE lease_id = $1 AND period_year = $2
|
|
|
+ `, [lease.id, year])).rows[0];
|
|
|
|
|
|
return {
|
|
|
lease_id: lease.id,
|
|
|
@@ -182,7 +182,7 @@ router.get('/bilan/:property_id/:year', (req, res) => {
|
|
|
monthly_provision: lease.charges_amount,
|
|
|
provisions_percues: provisions?.total || 0
|
|
|
};
|
|
|
- });
|
|
|
+ }));
|
|
|
|
|
|
// Calculate total provisions across all tenants for proportional split
|
|
|
const totalProvisions = leaseBilans.reduce((s, l) => s + l.provisions_percues, 0);
|
|
|
@@ -217,19 +217,19 @@ router.get('/bilan/:property_id/:year', (req, res) => {
|
|
|
router.get('/bilan/:property_id/:year/pdf', async (req, res) => {
|
|
|
const { property_id, year } = req.params;
|
|
|
|
|
|
- const prop = db.prepare('SELECT * FROM properties WHERE id = ? AND user_id = ?').get(property_id, req.userId);
|
|
|
+ const prop = (await pool.query('SELECT * FROM properties WHERE id = $1 AND user_id = $2', [property_id, req.userId])).rows[0];
|
|
|
if (!prop) return res.status(403).json({ error: 'Bien non autorisé' });
|
|
|
|
|
|
// Chercher le propriétaire lié au bail actif sur ce bien, sinon fallback profil gestionnaire
|
|
|
- const ownerRow = db.prepare(`
|
|
|
+ const ownerRow = (await pool.query(`
|
|
|
SELECT o.type as o_type, o.first_name, o.last_name, o.company_name, o.siret,
|
|
|
o.address, o.zip_code, o.city, o.email, o.phone
|
|
|
FROM leases l
|
|
|
JOIN owners o ON l.owner_id = o.id
|
|
|
- WHERE l.property_id = ? AND l.user_id = ? AND o.id IS NOT NULL
|
|
|
+ WHERE l.property_id = $1 AND l.user_id = $2 AND o.id IS NOT NULL
|
|
|
ORDER BY l.active DESC, l.start_date DESC
|
|
|
LIMIT 1
|
|
|
- `).get(property_id, req.userId);
|
|
|
+ `, [property_id, req.userId])).rows[0];
|
|
|
|
|
|
let ownerFullName, ownerAddress, ownerEmail, ownerPhone, ownerSiret;
|
|
|
if (ownerRow) {
|
|
|
@@ -241,7 +241,7 @@ router.get('/bilan/:property_id/:year/pdf', async (req, res) => {
|
|
|
ownerEmail = ownerRow.email;
|
|
|
ownerPhone = ownerRow.phone;
|
|
|
} else {
|
|
|
- const u = db.prepare('SELECT name, first_name, last_name, email, address, phone FROM users WHERE id = ?').get(req.userId);
|
|
|
+ const u = (await pool.query('SELECT name, first_name, last_name, email, address, phone FROM users WHERE id = $1', [req.userId])).rows[0];
|
|
|
ownerFullName = (u.first_name && u.last_name) ? `${u.first_name} ${u.last_name}` : u.name;
|
|
|
ownerSiret = null;
|
|
|
ownerAddress = u.address;
|
|
|
@@ -249,39 +249,39 @@ router.get('/bilan/:property_id/:year/pdf', async (req, res) => {
|
|
|
ownerPhone = u.phone;
|
|
|
}
|
|
|
|
|
|
- const totalChargesRow = db.prepare(`
|
|
|
+ const totalChargesRow = (await pool.query(`
|
|
|
SELECT SUM(amount) as total, COUNT(*) as count FROM charges
|
|
|
- WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 1
|
|
|
- `).get(property_id, year, req.userId);
|
|
|
+ WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 1
|
|
|
+ `, [property_id, year, req.userId])).rows[0];
|
|
|
const totalChargesReelles = totalChargesRow?.total || 0;
|
|
|
|
|
|
- const chargesList = db.prepare(`
|
|
|
- SELECT * FROM charges WHERE property_id = ? AND year = ? AND user_id = ?
|
|
|
+ const chargesList = (await pool.query(`
|
|
|
+ SELECT * FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3
|
|
|
ORDER BY date ASC
|
|
|
- `).all(property_id, year, req.userId);
|
|
|
+ `, [property_id, year, req.userId])).rows;
|
|
|
|
|
|
- const chargesByCategory = db.prepare(`
|
|
|
+ const chargesByCategory = (await pool.query(`
|
|
|
SELECT category, SUM(amount) as total FROM charges
|
|
|
- WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 1
|
|
|
+ WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 1
|
|
|
GROUP BY category ORDER BY total DESC
|
|
|
- `).all(property_id, year, req.userId);
|
|
|
+ `, [property_id, year, req.userId])).rows;
|
|
|
|
|
|
- const leases = db.prepare(`
|
|
|
+ const leases = (await pool.query(`
|
|
|
SELECT l.*, t.first_name, t.last_name, t.email FROM leases l
|
|
|
JOIN tenants t ON l.tenant_id = t.id
|
|
|
- WHERE l.property_id = ? AND l.user_id = ?
|
|
|
- AND (l.start_date <= ? AND (l.end_date IS NULL OR l.end_date >= ?))
|
|
|
- `).all(property_id, req.userId, `${year}-12-31`, `${year}-01-01`);
|
|
|
+ WHERE l.property_id = $1 AND l.user_id = $2
|
|
|
+ AND (l.start_date <= $3 AND (l.end_date IS NULL OR l.end_date >= $4))
|
|
|
+ `, [property_id, req.userId, `${year}-12-31`, `${year}-01-01`])).rows;
|
|
|
|
|
|
- const leaseBilans = leases.map(lease => {
|
|
|
- const provisions = db.prepare(`SELECT SUM(charges_paid) as total FROM payments WHERE lease_id = ? AND period_year = ?`).get(lease.id, year);
|
|
|
+ const leaseBilans = await Promise.all(leases.map(async lease => {
|
|
|
+ const provisions = (await pool.query(`SELECT SUM(charges_paid) as total FROM payments WHERE lease_id = $1 AND period_year = $2`, [lease.id, year])).rows[0];
|
|
|
return {
|
|
|
lease_id: lease.id,
|
|
|
tenant_name: `${lease.first_name} ${lease.last_name}`,
|
|
|
tenant_email: lease.email,
|
|
|
provisions_percues: provisions?.total || 0
|
|
|
};
|
|
|
- });
|
|
|
+ }));
|
|
|
const totalProvisions = leaseBilans.reduce((s, l) => s + l.provisions_percues, 0);
|
|
|
const bilans = leaseBilans.map(l => {
|
|
|
const ratio = totalProvisions > 0 ? l.provisions_percues / totalProvisions : (leaseBilans.length > 0 ? 1 / leaseBilans.length : 0);
|
|
|
@@ -474,45 +474,46 @@ router.get('/bilan/:property_id/:year/pdf', async (req, res) => {
|
|
|
});
|
|
|
|
|
|
// Close annual exercise — create charge_regularization for each tenant
|
|
|
-router.post('/bilan/:property_id/:year/close', (req, res) => {
|
|
|
+router.post('/bilan/:property_id/:year/close', async (req, res) => {
|
|
|
const { property_id, year } = req.params;
|
|
|
|
|
|
- const prop = db.prepare('SELECT * FROM properties WHERE id = ? AND user_id = ?').get(property_id, req.userId);
|
|
|
+ const prop = (await pool.query('SELECT * FROM properties WHERE id = $1 AND user_id = $2', [property_id, req.userId])).rows[0];
|
|
|
if (!prop) return res.status(403).json({ error: 'Bien non autorisé' });
|
|
|
|
|
|
// Check not already closed for this property/year
|
|
|
- const alreadyClosed = db.prepare(
|
|
|
- 'SELECT id FROM charge_regularizations WHERE user_id = ? AND property_id = ? AND year = ?'
|
|
|
- ).get(req.userId, property_id, parseInt(year));
|
|
|
+ const alreadyClosed = (await pool.query(
|
|
|
+ 'SELECT id FROM charge_regularizations WHERE user_id = $1 AND property_id = $2 AND year = $3',
|
|
|
+ [req.userId, property_id, parseInt(year)]
|
|
|
+ )).rows[0];
|
|
|
if (alreadyClosed) return res.status(409).json({ error: `L'exercice ${year} a déjà été clôturé pour ce bien.` });
|
|
|
|
|
|
// Recompute bilan (recoverable only)
|
|
|
- const totalRow = db.prepare(
|
|
|
- 'SELECT SUM(amount) as total FROM charges WHERE property_id = ? AND year = ? AND user_id = ? AND recoverable = 1'
|
|
|
- ).get(property_id, year, req.userId);
|
|
|
+ const totalRow = (await pool.query(
|
|
|
+ 'SELECT SUM(amount) as total FROM charges WHERE property_id = $1 AND year = $2 AND user_id = $3 AND recoverable = 1',
|
|
|
+ [property_id, year, req.userId]
|
|
|
+ )).rows[0];
|
|
|
const totalCharges = totalRow?.total || 0;
|
|
|
|
|
|
- const leases = db.prepare(`
|
|
|
+ const leases = (await pool.query(`
|
|
|
SELECT l.*, t.first_name, t.last_name FROM leases l
|
|
|
JOIN tenants t ON l.tenant_id = t.id
|
|
|
- WHERE l.property_id = ? AND l.user_id = ?
|
|
|
- AND (l.start_date <= ? AND (l.end_date IS NULL OR l.end_date >= ?))
|
|
|
- `).all(property_id, req.userId, `${year}-12-31`, `${year}-01-01`);
|
|
|
+ WHERE l.property_id = $1 AND l.user_id = $2
|
|
|
+ AND (l.start_date <= $3 AND (l.end_date IS NULL OR l.end_date >= $4))
|
|
|
+ `, [property_id, req.userId, `${year}-12-31`, `${year}-01-01`])).rows;
|
|
|
|
|
|
if (leases.length === 0) return res.status(400).json({ error: 'Aucun locataire sur cette période.' });
|
|
|
|
|
|
- const leaseBilans = leases.map(lease => {
|
|
|
- const prov = db.prepare('SELECT SUM(charges_paid) as total FROM payments WHERE lease_id = ? AND period_year = ?').get(lease.id, year);
|
|
|
+ const leaseBilans = await Promise.all(leases.map(async lease => {
|
|
|
+ const prov = (await pool.query('SELECT SUM(charges_paid) as total FROM payments WHERE lease_id = $1 AND period_year = $2', [lease.id, year])).rows[0];
|
|
|
return { lease_id: lease.id, tenant: `${lease.first_name} ${lease.last_name}`, provisions: prov?.total || 0 };
|
|
|
- });
|
|
|
+ }));
|
|
|
const totalProvisions = leaseBilans.reduce((s, l) => s + l.provisions, 0);
|
|
|
|
|
|
- const insert = db.prepare(
|
|
|
- 'INSERT INTO charge_regularizations (lease_id, user_id, property_id, year, amount, notes) VALUES (?, ?, ?, ?, ?, ?)'
|
|
|
- );
|
|
|
-
|
|
|
- const closeAll = db.transaction(() => {
|
|
|
- return leaseBilans.map(l => {
|
|
|
+ const client = await pool.connect();
|
|
|
+ try {
|
|
|
+ await client.query('BEGIN');
|
|
|
+ const results = [];
|
|
|
+ for (const l of leaseBilans) {
|
|
|
const ratio = totalProvisions > 0 ? l.provisions / totalProvisions : 1 / leaseBilans.length;
|
|
|
const quote_part = totalCharges * ratio;
|
|
|
// Positive = trop-perçu (credit tenant), Negative = complément dû (debit tenant)
|
|
|
@@ -520,13 +521,20 @@ router.post('/bilan/:property_id/:year/close', (req, res) => {
|
|
|
const label = trop_percu >= 0
|
|
|
? `Régularisation charges ${year} : trop-perçu de ${trop_percu.toFixed(2)} € à déduire`
|
|
|
: `Régularisation charges ${year} : complément de ${Math.abs(trop_percu).toFixed(2)} € à appeler`;
|
|
|
- insert.run(l.lease_id, req.userId, parseInt(property_id), parseInt(year), trop_percu, label);
|
|
|
- return { lease_id: l.lease_id, tenant: l.tenant, trop_percu };
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- const results = closeAll();
|
|
|
- res.json({ success: true, year: parseInt(year), property: prop.name, regularizations: results });
|
|
|
+ await client.query(
|
|
|
+ 'INSERT INTO charge_regularizations (lease_id, user_id, property_id, year, amount, notes) VALUES ($1, $2, $3, $4, $5, $6)',
|
|
|
+ [l.lease_id, req.userId, parseInt(property_id), parseInt(year), trop_percu, label]
|
|
|
+ );
|
|
|
+ results.push({ lease_id: l.lease_id, tenant: l.tenant, trop_percu });
|
|
|
+ }
|
|
|
+ await client.query('COMMIT');
|
|
|
+ res.json({ success: true, year: parseInt(year), property: prop.name, regularizations: results });
|
|
|
+ } catch (e) {
|
|
|
+ await client.query('ROLLBACK');
|
|
|
+ throw e;
|
|
|
+ } finally {
|
|
|
+ client.release();
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
module.exports = router;
|