131 lines
4.2 KiB
JavaScript
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;
|