Füge Spalte product_quality zur Tabelle stock hinzu und erstelle Migration für weather_type_id in production
This commit is contained in:
@@ -133,6 +133,64 @@ async function calcRegionalSellPrice(product, knowledgeFactor, regionId, worthPe
|
||||
return parseFloat(val) || 0;
|
||||
}
|
||||
|
||||
// Returns cumulative tax percent for a region, but excludes regions where the user holds
|
||||
// a political office that grants tax exemption according to the rules.
|
||||
// exemptionsMap maps political office.name -> array of regionType labelTr that are exempted
|
||||
const POLITICAL_TAX_EXEMPTIONS = {
|
||||
'council': ['city'],
|
||||
'taxman': ['city', 'county'],
|
||||
'treasurerer': ['city', 'county', 'shire'],
|
||||
'super-state-administrator': ['city', 'county', 'shire', 'markgrave', 'duchy'],
|
||||
'chancellor': ['city','county','shire','markgrave','duchy','duchy'] // chancellor = all types; we'll handle as wildcard
|
||||
};
|
||||
|
||||
async function getCumulativeTaxPercentWithExemptions(userId, regionId) {
|
||||
if (!regionId) return 0;
|
||||
// fetch user's political offices (active) and their region types
|
||||
const offices = await PoliticalOffice.findAll({
|
||||
where: { userId },
|
||||
include: [{ model: PoliticalOfficeType, as: 'type', attributes: ['name'] }, { model: RegionData, as: 'region', include: [{ model: RegionType, as: 'regionType', attributes: ['labelTr'] }] }]
|
||||
});
|
||||
|
||||
// build set of exempt region type labels from user's offices
|
||||
const exemptTypes = new Set();
|
||||
let hasChancellor = false;
|
||||
for (const o of offices) {
|
||||
const name = o.type?.name;
|
||||
if (!name) continue;
|
||||
if (name === 'chancellor') { hasChancellor = true; break; }
|
||||
const allowed = POLITICAL_TAX_EXEMPTIONS[name];
|
||||
if (allowed && Array.isArray(allowed)) {
|
||||
for (const t of allowed) exemptTypes.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
// If chancellor, exempt all region types -> tax = 0
|
||||
if (hasChancellor) return 0;
|
||||
|
||||
// Now compute cumulative tax but exclude regions whose regionType.labelTr is in exemptTypes
|
||||
const rows = await sequelize.query(
|
||||
`WITH RECURSIVE ancestors AS (
|
||||
SELECT r.id, r.parent_id, r.tax_percent, rt.label_tr as region_type
|
||||
FROM falukant_data.region r
|
||||
JOIN falukant_type.region_type rt ON rt.id = r.region_type_id
|
||||
WHERE r.id = :id
|
||||
UNION ALL
|
||||
SELECT reg.id, reg.parent_id, reg.tax_percent, rt2.label_tr
|
||||
FROM falukant_data.region reg
|
||||
JOIN falukant_type.region_type rt2 ON rt2.id = reg.region_type_id
|
||||
JOIN ancestors a ON reg.id = a.parent_id
|
||||
)
|
||||
SELECT COALESCE(SUM(CASE WHEN :exempt_types::text[] && ARRAY[region_type] THEN 0 ELSE tax_percent END),0) AS total FROM ancestors;`,
|
||||
{
|
||||
replacements: { id: regionId, exempt_types: Array.from(exemptTypes) },
|
||||
type: sequelize.QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
const val = rows?.[0]?.total ?? 0;
|
||||
return parseFloat(val) || 0;
|
||||
}
|
||||
|
||||
function calculateMarriageCost(titleOfNobility, age) {
|
||||
const minTitle = 1;
|
||||
const adjustedTitle = titleOfNobility - minTitle + 1;
|
||||
@@ -1527,8 +1585,8 @@ class FalukantService extends BaseService {
|
||||
const knowledgeVal = item.knowledges?.[0]?.knowledge || 0;
|
||||
const pricePerUnit = await calcRegionalSellPrice(item, knowledgeVal, branch.regionId);
|
||||
|
||||
// compute cumulative tax (region + ancestors) and inflate price so seller net is unchanged
|
||||
const cumulativeTax = await getCumulativeTaxPercent(branch.regionId);
|
||||
// compute cumulative tax (region + ancestors) with political exemptions and inflate price so seller net is unchanged
|
||||
const cumulativeTax = await getCumulativeTaxPercentWithExemptions(user.id, branch.regionId);
|
||||
const inflationFactor = cumulativeTax >= 100 ? 1 : (1 / (1 - cumulativeTax / 100));
|
||||
const adjustedPricePerUnit = Math.round(pricePerUnit * inflationFactor * 100) / 100;
|
||||
const revenue = quantity * adjustedPricePerUnit;
|
||||
@@ -1614,7 +1672,7 @@ class FalukantService extends BaseService {
|
||||
const knowledgeVal = item.productType.knowledges[0]?.knowledge || 0;
|
||||
const regionId = item.stock.branch.regionId;
|
||||
const pricePerUnit = await calcRegionalSellPrice(item.productType, knowledgeVal, regionId);
|
||||
const cumulativeTax = await getCumulativeTaxPercent(regionId);
|
||||
const cumulativeTax = await getCumulativeTaxPercentWithExemptions(user.id, regionId);
|
||||
const inflationFactor = cumulativeTax >= 100 ? 1 : (1 / (1 - cumulativeTax / 100));
|
||||
const adjustedPricePerUnit = Math.round(pricePerUnit * inflationFactor * 100) / 100;
|
||||
total += item.quantity * adjustedPricePerUnit;
|
||||
@@ -4363,15 +4421,26 @@ class FalukantService extends BaseService {
|
||||
|
||||
// Unikate nach character.id
|
||||
const map = new Map();
|
||||
const POLITICAL_TAX_EXEMPTIONS = {
|
||||
'council': ['city'],
|
||||
'taxman': ['city','county'],
|
||||
'treasurerer': ['city','county','shire'],
|
||||
'super-state-administrator': ['city','county','shire','markgrave','duchy'],
|
||||
'chancellor': ['*']
|
||||
};
|
||||
|
||||
histories.forEach(h => {
|
||||
const c = h.holder;
|
||||
if (c && c.id && !map.has(c.id)) {
|
||||
const officeName = h.type?.name;
|
||||
const benefit = POLITICAL_TAX_EXEMPTIONS[officeName] || [];
|
||||
map.set(c.id, {
|
||||
id: c.id,
|
||||
name: `${c.definedFirstName.name} ${c.definedLastName.name}`,
|
||||
title: c.nobleTitle.labelTr,
|
||||
officeType: h.type.name,
|
||||
gender: c.gender
|
||||
officeType: officeName,
|
||||
gender: c.gender,
|
||||
benefit
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user