saldo
Version:
Portuguese salary calculator library
211 lines (210 loc) • 8.48 kB
JavaScript
export const Situations = {
SOLCAS2: {
code: "SOLCAS2",
description: "Trabalho dependente - Não casado sem dependentes ou casado dois titulares",
conditions: [
{
description: "Não Casado sem dependentes",
married: false,
dependents: false,
disabled: false,
},
{
description: "Casado, 2 titulares, sem dependentes",
married: true,
numberOfHolders: 2,
dependents: false,
disabled: false,
},
{
description: "Casado, 2 titulares, com dependentes",
married: true,
numberOfHolders: 2,
dependents: true,
disabled: false,
},
],
},
SOLD: {
code: "SOLD",
description: "Trabalho dependente - Não casado com um ou mais dependentes",
conditions: [
{
description: "Não casado com um ou mais dependentes",
married: false,
dependents: true,
disabled: false,
},
],
},
CAS1: {
code: "CAS1",
description: "Trabalho dependente - Casado único titular",
conditions: [
{
description: "Casado único titular sem dependentes",
married: true,
numberOfHolders: 1,
dependents: false,
disabled: false,
},
{
description: "Casado único titular com dependentes",
married: true,
numberOfHolders: 1,
dependents: true,
disabled: false,
},
],
},
SOLCAS2_DEF: {
code: "SOLCAS2+DEF",
description: "Trabalho dependente - Não casado ou casado dois titulares sem dependentes - deficiente",
conditions: [
{
description: "Não Casado sem dependentes - deficiente",
married: false,
dependents: false,
disabled: true,
},
{
description: "Casado, 2 titulares, sem dependentes - deficiente",
married: true,
numberOfHolders: 2,
dependents: false,
disabled: true,
},
],
},
SOLD_DEF: {
code: "SOLD+DEF",
description: "Trabalho dependente - Não casado, com um ou mais dependentes - deficiente",
conditions: [
{
description: "Não casado com um ou mais dependentes - deficiente",
married: false,
dependents: true,
disabled: true,
},
],
},
CAS2D_DEF: {
code: "CAS2D+DEF",
description: "Trabalho dependente - Casado dois titulares, com um ou mais dependentes - deficiente",
conditions: [
{
description: "Casado, 2 titulares, com dependentes - deficiente",
married: true,
numberOfHolders: 2,
dependents: true,
disabled: true,
},
],
},
CAS1_DEF: {
code: "CAS1+DEF",
description: "Trabalho dependente - Casado único titular - deficiente",
conditions: [
{
description: "Casado único titular sem dependentes - deficiente",
married: true,
numberOfHolders: 1,
dependents: false, // Python had None, translated to false based on Condition.__init__
disabled: true,
},
{
description: "Casado único titular com dependentes - deficiente",
married: true,
numberOfHolders: 1,
dependents: true,
disabled: true,
},
],
},
};
// Utility functions for Situations
export class SituationUtils {
static getSituationFromCode(code) {
return Object.keys(Situations)
.map((key) => Situations[key])
.find((situation) => situation.code === code);
}
static getSituation(married, disabled, numberOfHolders, numberOfDependents) {
const inputCondition = {
married,
numberOfHolders: numberOfHolders,
dependents: numberOfDependents !== undefined ? numberOfDependents > 0 : false,
disabled,
};
return SituationUtils.getSituationFromCondition(inputCondition);
}
static getSituationFromCondition(condition) {
for (const key in Situations) {
if (Object.prototype.hasOwnProperty.call(Situations, key)) {
const situation = Situations[key];
for (const situationCondition of situation.conditions) {
const marriedMatch = situationCondition.married === condition.married;
let holdersMatch = true;
if (situationCondition.numberOfHolders !== undefined &&
situationCondition.numberOfHolders !== null) {
holdersMatch =
situationCondition.numberOfHolders === condition.numberOfHolders;
}
// In Python, if situation_condition.number_of_holders is None, it implies a match.
// Here, if situationCondition.numberOfHolders is undefined/null, we consider it a match only if condition.numberOfHolders is also undefined/null.
// This might need adjustment based on exact Python None semantics vs TypeScript undefined/null.
// For now, if schema has no numberOfHolders, it matches any.
// If schema *has* numberOfHolders, it must match.
let dependentsMatch = true;
if (situationCondition.dependents !== undefined) {
// Python code treated None for dependents as a wildcard / match
dependentsMatch =
situationCondition.dependents === condition.dependents;
}
const disabledMatch = situationCondition.disabled === condition.disabled;
if (marriedMatch && holdersMatch && dependentsMatch && disabledMatch) {
return situation;
}
}
}
}
// In Python, this raised ValueError. In TS, we return undefined.
// console.error(`Situation with condition ${JSON.stringify(condition)} not found.`);
return undefined;
}
}
export class RetentionPathsSchema {
identifier; // Renamed from yearPath, locationPath, etc. to a single identifier
constructor(dateStart, dateEnd, location, situationCode, // This is the code like "SOLD", "CAS1"
year) {
const yearStr = String(year);
const customPadStart = (str, targetLength, padString) => {
targetLength = targetLength >> 0; // floor if number or convert non-number to 0
padString = String(typeof padString !== 'undefined' ? padString : ' ');
if (str.length > targetLength) {
return String(str);
}
else {
targetLength = targetLength - str.length;
if (targetLength > padString.length) {
padString += padString.repeat(targetLength / padString.length); // append to original to ensure we are longer than needed
}
return padString.slice(0, targetLength) + String(str);
}
};
const formatDate = (date) => {
const y = date.getFullYear();
const m = customPadStart(String(date.getMonth() + 1), 2, "0");
const d = customPadStart(String(date.getDate()), 2, "0");
return `${y}-${m}-${d}`;
};
// Construct the identifier string matching the keys in taxTablesData
// e.g., "2024/continente/2024-01-01_2024-12-31/SOLD"
// Note: situationCode already comes without .json
this.identifier = `${yearStr}/${location}/${formatDate(dateStart)}_${formatDate(dateEnd)}/${situationCode}`;
}
get path() {
// but it now returns the identifier.
return this.identifier;
}
}