CentralBackend/repositories/tax/taxRepository.js
2025-12-06 11:14:55 +01:00

131 lines
4.2 KiB
JavaScript

const Country = require('../../models/Country');
const { VatRate, VatRateHistory, VAT_FIELDS } = require('../../models/Tax');
class TaxRepository {
constructor(uow) {
this.uow = uow;
this.conn = uow.getConnection();
}
async upsertCountries(countries, actorUserId) {
let created = 0;
let updated = 0;
for (const c of countries) {
const [res] = await this.conn.query(
`INSERT INTO countries (country_code, country_name, created_by, updated_by)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE country_name=VALUES(country_name), updated_by=VALUES(updated_by), updated_at=CURRENT_TIMESTAMP`,
[c.code, c.name, actorUserId || null, actorUserId || null]
);
if (res.affectedRows === 1) created += 1;
if (res.affectedRows === 2) updated += 1;
}
return { created, updated };
}
async getCountriesByCodes(codes) {
if (!codes.length) return {};
const [rows] = await this.conn.query(
`SELECT * FROM countries WHERE country_code IN (${codes.map(() => '?').join(',')})`,
codes
);
const map = {};
rows.forEach((r) => { map[r.country_code] = new Country(r); });
return map;
}
async getCountryByCode(code) {
const [rows] = await this.conn.query(`SELECT * FROM countries WHERE country_code = ? LIMIT 1`, [code]);
return rows[0] ? new Country(rows[0]) : null;
}
async getAllCurrentVatRates() {
const [rows] = await this.conn.query(
`SELECT c.*, vr.id AS vat_id, vr.standard_rate, vr.reduced_rate, vr.super_reduced_rate, vr.parking_rate, vr.effective_from
FROM countries c
LEFT JOIN vat_rates vr ON vr.country_id = c.id AND vr.effective_to IS NULL
ORDER BY c.country_name ASC`
);
return rows;
}
async getVatHistory(countryId) {
const [rows] = await this.conn.query(
`SELECT * FROM vat_rate_history WHERE country_id = ? ORDER BY effective_from DESC`,
[countryId]
);
return rows.map((r) => new VatRateHistory(r));
}
async setCurrentVatRate(countryId, rates, actorUserId) {
const [currentRows] = await this.conn.query(
`SELECT * FROM vat_rates WHERE country_id = ? AND effective_to IS NULL LIMIT 1`,
[countryId]
);
const now = new Date();
const current = currentRows[0] ? new VatRate(currentRows[0]) : null;
const areEqual =
current &&
VAT_FIELDS.every((k) => {
const a = current[k] == null ? null : Number(current[k]);
const b = rates[k] == null ? null : Number(rates[k]);
return (a === null && b === null) || a === b;
});
if (areEqual) return { changed: false, skipped: true };
if (current) {
await this.conn.query(
`INSERT INTO vat_rate_history (country_id, standard_rate, reduced_rate, super_reduced_rate, parking_rate, effective_from, effective_to, created_by, updated_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
countryId,
current.standard_rate,
current.reduced_rate,
current.super_reduced_rate,
current.parking_rate,
current.effective_from,
now,
actorUserId || current.created_by || null,
actorUserId || current.updated_by || null
]
);
await this.conn.query(
`UPDATE vat_rates SET effective_to = ?, updated_by = ? WHERE id = ?`,
[now, actorUserId || null, current.id]
);
}
await this.conn.query(
`INSERT INTO vat_rates (country_id, standard_rate, reduced_rate, super_reduced_rate, parking_rate, effective_from, effective_to, created_by, updated_by)
VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`,
[
countryId,
rates.standard_rate,
rates.reduced_rate,
rates.super_reduced_rate,
rates.parking_rate,
now,
actorUserId || null,
actorUserId || null
]
);
return { changed: true, skipped: false };
}
async bulkImportVatRates(entries, actorUserId) {
let ratesUpdated = 0;
let ratesSkipped = 0;
for (const entry of entries) {
const res = await this.setCurrentVatRate(entry.country_id, entry.rates, actorUserId);
if (res.changed) ratesUpdated += 1;
if (res.skipped) ratesSkipped += 1;
}
return { ratesUpdated, ratesSkipped };
}
}
module.exports = TaxRepository;