net-salary-calculate / functions.py
mattoofahad
adding yearly salary tax calculator
9af1696
from constants import Styles, Constants
import streamlit as st
class Functions:
@staticmethod
def calculated_current_salary_after_tax(current_salary, tax_brackets):
return current_salary - Functions.calculate_monthly_tax(
current_salary, tax_brackets
)
@staticmethod
def calculated_yearly_salary_after_tax(current_salary, tax_brackets):
return current_salary/12 - Functions.calculate_monthly_tax(
current_salary/12, tax_brackets
)
@staticmethod
def calculate_monthly_tax(monthly_income, tax_brackets):
annual_income = monthly_income * 12
total_tax = 0
remaining_income = annual_income
for lower, upper, rate in tax_brackets:
if remaining_income <= 0:
break
taxable_amount = min(remaining_income, upper - lower)
tax = taxable_amount * rate
total_tax += tax
remaining_income -= taxable_amount
monthly_tax = total_tax / 12
return round(monthly_tax, 2)
@staticmethod
def calculate_net_salary(gross_salary, tax_brackets):
return gross_salary - Functions.calculate_monthly_tax(
gross_salary, tax_brackets
)
@staticmethod
def calculated_initial_desired_net(
current_salary, desired_increment, daily_cost_of_travel, physical_days_per_week
):
return (current_salary + current_salary * desired_increment) + (
daily_cost_of_travel * physical_days_per_week * 4.5
)
@staticmethod
def calculate_additional_amount(initial_desired_net, tax_brackets):
gross_salary = initial_desired_net
max_iterations = 100
for _ in range(max_iterations):
net_salary = Functions.calculate_net_salary(gross_salary, tax_brackets)
if abs(net_salary - initial_desired_net) < 0.01:
break
gross_salary += initial_desired_net - net_salary
additional_amount = gross_salary - initial_desired_net
return {
"initial_desired_net": round(initial_desired_net, 2),
"gross_salary_needed": round(gross_salary, 2),
"additional_amount": round(additional_amount, 2),
"tax": round(
Functions.calculate_monthly_tax(gross_salary, tax_brackets), 2
),
"final_net_salary": round(
Functions.calculate_net_salary(gross_salary, tax_brackets), 2
),
}
import pandas as pd
class StreamlitFunctions:
@staticmethod
def update_initial_salary_parameter():
# if (
# st.session_state.user_initial_desired_net_state
# < st.session_state.current_salary
# ):
# st.session_state.user_initial_desired_net = (
# st.session_state.current_salary
# + st.session_state.user_initial_desired_net_state
# )
# else:
st.session_state.user_initial_desired_net = (
st.session_state.user_initial_desired_net_state
)
st.session_state.type_to_calculate = "desired_salary"
@staticmethod
def reset_initial_salary_parameter():
def reset_values():
st.session_state.user_initial_desired_net = Constants.DEFAULT_INITIAL_NET
st.session_state.valid_input = True
st.button(
"Reset Final Desired Net Salary Value",
on_click=reset_values,
use_container_width=True,
)
@staticmethod
def initial_salary_parameter():
st.header("Final Desired Net Salary")
if st.session_state.user_initial_desired_net >= st.session_state.current_salary:
minimum_value = st.session_state.current_salary
else:
minimum_value = 0.0
st.number_input(
"Final Desired Net Salary (PKR)",
min_value=minimum_value,
value=st.session_state.user_initial_desired_net,
step=1000.0,
key="user_initial_desired_net_state",
on_change=StreamlitFunctions.update_initial_salary_parameter,
)
@staticmethod
def reset_tax_brackets():
def reset_values():
st.session_state.tax_brackets = Constants.DEFAULT_TAX_BRACKETS
st.button(
"Reset Tax Brackets",
use_container_width=True,
on_click=reset_values,
)
@staticmethod
def reset_salary_parameters():
def reset_values():
st.session_state.current_salary = Constants.DEFAULT_CURRENT_SALARY
st.session_state.desired_increment_percentage = (
Constants.DEFAULT_INCREMENT_PERCENTAGE
)
st.session_state.daily_cost_of_travel = Constants.DEFAULT_DAILY_TRAVEL_COST
st.session_state.physical_days_per_week = Constants.DEFAULT_PHYSICAL_DAYS
st.button(
"Reset Salary Parameters Values",
use_container_width=True,
on_click=reset_values,
)
@staticmethod
def reset_tax_on_current_salary():
def reset_values():
st.session_state.tax_on_current_salary = (
Constants.DEFAULT_CURRENT_SALARY_WITH_TAX
)
st.button(
"Reset Current Salary",
use_container_width=True,
on_click=reset_values,
)
@staticmethod
def reset_tax_on_yearly_salary():
def reset_values():
st.session_state.tax_on_yearly_salary = (
Constants.DEFAULT_YEARLY_SALARY_WITH_TAX
)
st.button(
"Reset Yearly Salary",
use_container_width=True,
on_click=reset_values,
)
@staticmethod
def print_tax_on_current_salary():
st.header("Tax on Current Salary")
def update_tax_on_current_salary_parameter():
st.session_state.tax_on_current_salary = (
st.session_state.tax_on_current_salary_state
)
st.session_state.type_to_calculate = "tax_on_current_salary"
st.number_input(
"Current monthly Salary (PKR)",
min_value=0.0,
step=1000.0,
value=st.session_state.tax_on_current_salary,
key="tax_on_current_salary_state",
on_change=update_tax_on_current_salary_parameter,
)
@staticmethod
def print_tax_on_yearly_salary():
st.header("Tax on Yearly Salary")
def update_tax_on_yearly_salary_parameter():
st.session_state.tax_on_yearly_salary = (
st.session_state.tax_on_yearly_salary_state
)
st.session_state.type_to_calculate = "tax_on_current_salary"
st.number_input(
"Current Yearly Salary (PKR)",
min_value=0.0,
step=50000.0,
value=st.session_state.tax_on_yearly_salary,
key="tax_on_yearly_salary_state",
on_change=update_tax_on_yearly_salary_parameter,
)
@staticmethod
def print_salary_parameters():
st.header("Salary Parameters")
def update_current_salary_parameter():
st.session_state.current_salary = st.session_state.current_salary_state
st.session_state.type_to_calculate = "salary_parameters"
st.number_input(
"Current monthly salary after Tax (PKR)",
min_value=0.0,
step=1000.0,
value=st.session_state.current_salary,
key="current_salary_state",
on_change=update_current_salary_parameter,
)
def update_desired_increment_percentage_parameter():
st.session_state.desired_increment_percentage = (
st.session_state.desired_increment_percentage_state
)
st.session_state.type_to_calculate = "salary_parameters"
st.number_input(
"Desired salary increment (as a decimal)",
min_value=0.0,
step=0.05,
value=st.session_state.desired_increment_percentage,
format="%.2f",
key="desired_increment_percentage_state",
on_change=update_desired_increment_percentage_parameter,
)
def update_daily_cost_of_travel_parameter():
st.session_state.daily_cost_of_travel = (
st.session_state.daily_cost_of_travel_state
)
st.session_state.type_to_calculate = "salary_parameters"
st.number_input(
"Daily cost of travel (PKR)",
min_value=0,
step=100,
value=st.session_state.daily_cost_of_travel,
key="daily_cost_of_travel_state",
on_change=update_daily_cost_of_travel_parameter,
)
def update_physical_days_per_week_parameter():
st.session_state.physical_days_per_week = (
st.session_state.physical_days_per_week_state
)
st.session_state.type_to_calculate = "salary_parameters"
st.number_input(
"Number of On-Site days per week",
min_value=0,
max_value=7,
step=1,
value=st.session_state.physical_days_per_week,
key="physical_days_per_week_state",
on_change=update_physical_days_per_week_parameter,
)
@staticmethod
def print_tax_brackets():
st.header("Tax Brackets")
tax_brackets_df = pd.DataFrame(
st.session_state.tax_brackets,
columns=["Lower Limit", "Upper Limit", "Tax Rate"],
)
edited_tax_brackets = st.data_editor(
tax_brackets_df, num_rows="dynamic", use_container_width=True
)
st.session_state.tax_brackets = list(
edited_tax_brackets.itertuples(index=False, name=None)
)
@staticmethod
def initialize_session_values():
st.title("Net Salary Calculator")
if "tax_brackets" not in st.session_state:
st.session_state.tax_brackets = Constants.DEFAULT_TAX_BRACKETS
if "tax_on_current_salary" not in st.session_state:
st.session_state.tax_on_current_salary = (
Constants.DEFAULT_CURRENT_SALARY_WITH_TAX
)
if "tax_on_yearly_salary" not in st.session_state:
st.session_state.tax_on_yearly_salary = (
Constants.DEFAULT_YEARLY_SALARY_WITH_TAX
)
if "current_salary" not in st.session_state:
st.session_state.current_salary = Constants.DEFAULT_CURRENT_SALARY
if "desired_increment_percentage" not in st.session_state:
st.session_state.desired_increment_percentage = (
Constants.DEFAULT_INCREMENT_PERCENTAGE
)
if "daily_cost_of_travel" not in st.session_state:
st.session_state.daily_cost_of_travel = Constants.DEFAULT_DAILY_TRAVEL_COST
if "physical_days_per_week" not in st.session_state:
st.session_state.physical_days_per_week = Constants.DEFAULT_PHYSICAL_DAYS
if "user_initial_desired_net" not in st.session_state:
st.session_state.user_initial_desired_net = Constants.DEFAULT_INITIAL_NET
if "type_to_calculate" not in st.session_state:
st.session_state.type_to_calculate = None
@staticmethod
def custom_metric(label, value):
st.markdown(Styles.METRIC_STYLE, unsafe_allow_html=True)
st.markdown(
f"""
<div class="metric-container">
<div class="metric-label">{label}</div>
<div class="metric-value">PKR {value:,.2f}</div>
</div>
""",
unsafe_allow_html=True,
)