feat(FalukantService, CreateBranchDialog): implement dynamic branch cost calculation
All checks were successful
Deploy to production / deploy (push) Successful in 2m8s
All checks were successful
Deploy to production / deploy (push) Successful in 2m8s
- Added new constants and methods in FalukantService to calculate branch action costs based on owned branch types, enhancing the cost management logic. - Updated the CreateBranchDialog to utilize the new cost calculation, ensuring accurate display of branch creation costs based on user-owned branches. - Improved the handling of branch type costs, allowing for a more flexible and responsive user experience when creating and upgrading branches.
This commit is contained in:
@@ -106,6 +106,14 @@ async function getBranchOrFail(userId, branchId) {
|
||||
return branch;
|
||||
}
|
||||
|
||||
const BRANCH_EXPANSION_EXPONENT = 1.2;
|
||||
const BRANCH_TYPE_COST_PRESSURE = {
|
||||
production: { same: 1.15, other: 0.45 },
|
||||
store: { same: 1.1, other: 0.5 },
|
||||
fullstack: { same: 1.35, other: 0.7 },
|
||||
default: { same: 1.05, other: 0.5 },
|
||||
};
|
||||
|
||||
const POLITICAL_OFFICE_RANKS = {
|
||||
assessor: 1,
|
||||
councillor: 1,
|
||||
@@ -572,6 +580,22 @@ class FalukantService extends BaseService {
|
||||
{ tr: "drunkOfLife", method: "healthDrunkOfLife", cost: 5000000 }
|
||||
];
|
||||
|
||||
_getBranchCostPressure(targetLabel) {
|
||||
return BRANCH_TYPE_COST_PRESSURE[targetLabel] || BRANCH_TYPE_COST_PRESSURE.default;
|
||||
}
|
||||
|
||||
_calculateBranchActionCost(baseCost, targetLabel, ownedTypeLabels = []) {
|
||||
const normalizedTarget = String(targetLabel || '').trim().toLowerCase();
|
||||
const { same, other } = this._getBranchCostPressure(normalizedTarget);
|
||||
const weightedCount = ownedTypeLabels.reduce((sum, label) => {
|
||||
const normalizedLabel = String(label || '').trim().toLowerCase();
|
||||
return sum + (normalizedLabel === normalizedTarget ? same : other);
|
||||
}, 0);
|
||||
const exponentBase = Math.max(1, 1 + weightedCount);
|
||||
const rawCost = Number(baseCost || 0) * Math.pow(exponentBase, BRANCH_EXPANSION_EXPONENT);
|
||||
return Math.round(rawCost * 100) / 100;
|
||||
}
|
||||
|
||||
static RECURSIVE_REGION_SEARCH = `
|
||||
WITH RECURSIVE ancestors AS (
|
||||
SELECT
|
||||
@@ -1258,12 +1282,15 @@ class FalukantService extends BaseService {
|
||||
if (!branchType) {
|
||||
throw new Error(`Unknown branchTypeId ${branchTypeId}`);
|
||||
}
|
||||
const existingCount = await Branch.count({
|
||||
where: { falukantUserId: user.id }
|
||||
const existingBranches = await Branch.findAll({
|
||||
where: { falukantUserId: user.id },
|
||||
include: [{ model: BranchType, as: 'branchType', attributes: ['labelTr'] }],
|
||||
attributes: ['id']
|
||||
});
|
||||
const exponentBase = Math.max(existingCount, 1);
|
||||
const rawCost = branchType.baseCost * Math.pow(exponentBase, 1.2);
|
||||
const cost = Math.round(rawCost * 100) / 100;
|
||||
const ownedTypeLabels = existingBranches
|
||||
.map((branch) => branch.branchType?.labelTr)
|
||||
.filter(Boolean);
|
||||
const cost = this._calculateBranchActionCost(branchType.baseCost, branchType.labelTr, ownedTypeLabels);
|
||||
if (user.money < cost) {
|
||||
throw new PreconditionError('insufficientFunds');
|
||||
}
|
||||
@@ -1283,7 +1310,18 @@ class FalukantService extends BaseService {
|
||||
async getBranchTypes(hashedUserId) {
|
||||
const user = await getFalukantUserOrFail(hashedUserId);
|
||||
const branchTypes = await BranchType.findAll();
|
||||
return branchTypes;
|
||||
const ownedBranches = await Branch.findAll({
|
||||
where: { falukantUserId: user.id },
|
||||
include: [{ model: BranchType, as: 'branchType', attributes: ['labelTr'] }],
|
||||
attributes: ['id']
|
||||
});
|
||||
const ownedTypeLabels = ownedBranches
|
||||
.map((branch) => branch.branchType?.labelTr)
|
||||
.filter(Boolean);
|
||||
return branchTypes.map((branchType) => ({
|
||||
...branchType.get({ plain: true }),
|
||||
createCost: this._calculateBranchActionCost(branchType.baseCost, branchType.labelTr, ownedTypeLabels),
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
@@ -1311,7 +1349,7 @@ class FalukantService extends BaseService {
|
||||
const user = await getFalukantUserOrFail(hashedUserId);
|
||||
const branch = await Branch.findOne({
|
||||
where: { id: branchId, falukantUserId: user.id },
|
||||
include: [{ model: BranchType, as: 'branchType', attributes: ['id', 'labelTr'] }],
|
||||
include: [{ model: BranchType, as: 'branchType', attributes: ['id', 'labelTr', 'baseCost'] }],
|
||||
});
|
||||
if (!branch) {
|
||||
throw new Error('Branch not found');
|
||||
@@ -1333,8 +1371,25 @@ class FalukantService extends BaseService {
|
||||
if (!targetType) {
|
||||
throw new Error(`Target branch type '${targetLabel}' not found`);
|
||||
}
|
||||
|
||||
// Für den Moment ohne zusätzliche Kosten – kann später erweitert werden
|
||||
const ownedBranches = await Branch.findAll({
|
||||
where: { falukantUserId: user.id },
|
||||
include: [{ model: BranchType, as: 'branchType', attributes: ['labelTr'] }],
|
||||
attributes: ['id']
|
||||
});
|
||||
const ownedTypeLabels = ownedBranches
|
||||
.filter((entry) => entry.id !== branch.id)
|
||||
.map((entry) => entry.branchType?.labelTr)
|
||||
.filter(Boolean);
|
||||
const baseUpgradeCost = Math.max(targetType.baseCost - (branch.branchType?.baseCost || 0), targetType.baseCost * 0.6);
|
||||
const upgradeCost = this._calculateBranchActionCost(baseUpgradeCost, targetType.labelTr, ownedTypeLabels);
|
||||
if (user.money < upgradeCost) {
|
||||
throw new PreconditionError('insufficientFunds');
|
||||
}
|
||||
await updateFalukantUserMoney(
|
||||
user.id,
|
||||
-upgradeCost,
|
||||
'upgrade_branch'
|
||||
);
|
||||
branch.branchTypeId = targetType.id;
|
||||
await branch.save();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user