Spaces:
Sleeping
Sleeping
mattoofahaddcube
commited on
Commit
•
b398e78
1
Parent(s):
5858a75
adding individual buttons
Browse files- app.py +76 -31
- constants.py +2 -1
- functions.py +68 -35
app.py
CHANGED
@@ -3,21 +3,55 @@ import streamlit as st
|
|
3 |
from functions import Functions, StreamlitFunctions
|
4 |
import pandas as pd
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
StreamlitFunctions.initialize_session_values()
|
7 |
StreamlitFunctions.print_tax_brackets()
|
8 |
StreamlitFunctions.reset_tax_brackets()
|
9 |
|
10 |
StreamlitFunctions.print_salary_parameters()
|
11 |
StreamlitFunctions.reset_salary_parameters()
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
StreamlitFunctions.initial_salary_parameter()
|
14 |
StreamlitFunctions.reset_initial_salary_parameter()
|
15 |
-
|
|
|
|
|
|
|
|
|
16 |
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
initial_desired_net = st.session_state.user_initial_desired_net
|
20 |
-
|
21 |
initial_desired_net = Functions.calculated_initial_desired_net(
|
22 |
st.session_state.current_salary,
|
23 |
st.session_state.desired_increment_percentage,
|
@@ -28,23 +62,31 @@ if st.button("Calculate", use_container_width=True) and st.session_state.valid_i
|
|
28 |
result = Functions.calculate_additional_amount(
|
29 |
initial_desired_net, st.session_state.tax_brackets
|
30 |
)
|
31 |
-
st.header("Salary Calculation Results")
|
32 |
-
col1, col2 = st.columns(2)
|
33 |
-
with col1:
|
34 |
-
# custom_metric("Initial Desired Net Salary", result['initial_desired_net'])
|
35 |
-
StreamlitFunctions.custom_metric("Final Net Salary", result["final_net_salary"])
|
36 |
-
StreamlitFunctions.custom_metric("Tax", result["tax"])
|
37 |
-
|
38 |
-
with col2:
|
39 |
-
# custom_metric("Additional Amount Needed", result['additional_amount'])
|
40 |
-
StreamlitFunctions.custom_metric(
|
41 |
-
"Gross Salary Needed", result["gross_salary_needed"]
|
42 |
-
)
|
43 |
|
44 |
# Display how initial_desired_net was determined
|
45 |
st.markdown("---")
|
46 |
-
if st.session_state.
|
47 |
-
st.success(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
summary_df = pd.DataFrame(
|
49 |
{
|
50 |
"Parameter": [
|
@@ -59,9 +101,9 @@ if st.button("Calculate", use_container_width=True) and st.session_state.valid_i
|
|
59 |
],
|
60 |
}
|
61 |
)
|
62 |
-
|
63 |
-
st.
|
64 |
-
"
|
65 |
)
|
66 |
summary_df = pd.DataFrame(
|
67 |
{
|
@@ -85,16 +127,19 @@ if st.button("Calculate", use_container_width=True) and st.session_state.valid_i
|
|
85 |
],
|
86 |
}
|
87 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
|
|
|
|
|
|
|
|
|
|
89 |
# Display a summary of the calculation
|
90 |
st.subheader("Calculation Summary")
|
91 |
-
|
92 |
-
st.
|
93 |
-
|
94 |
-
st.subheader("Salary Breakdown")
|
95 |
-
breakdown_data = {
|
96 |
-
"Component": ["Net Salary", "Tax"],
|
97 |
-
"Amount": [result["final_net_salary"], result["tax"]],
|
98 |
-
}
|
99 |
-
breakdown_df = pd.DataFrame(breakdown_data)
|
100 |
-
st.bar_chart(breakdown_df.set_index("Component"))
|
|
|
3 |
from functions import Functions, StreamlitFunctions
|
4 |
import pandas as pd
|
5 |
|
6 |
+
|
7 |
+
def calculate_salary_parameters():
|
8 |
+
st.session_state.type_to_calculate = "salary_parameters"
|
9 |
+
|
10 |
+
|
11 |
+
def calculate_initial_salary_parameter():
|
12 |
+
st.session_state.type_to_calculate = "desired_salary"
|
13 |
+
|
14 |
+
|
15 |
+
def calculate_tax_on_current_salary():
|
16 |
+
st.session_state.type_to_calculate = "tax_on_current_salary"
|
17 |
+
|
18 |
+
|
19 |
StreamlitFunctions.initialize_session_values()
|
20 |
StreamlitFunctions.print_tax_brackets()
|
21 |
StreamlitFunctions.reset_tax_brackets()
|
22 |
|
23 |
StreamlitFunctions.print_salary_parameters()
|
24 |
StreamlitFunctions.reset_salary_parameters()
|
25 |
+
st.button(
|
26 |
+
"Calculate Based on Salary Parameters",
|
27 |
+
use_container_width=True,
|
28 |
+
on_click=calculate_salary_parameters,
|
29 |
+
)
|
30 |
|
31 |
StreamlitFunctions.initial_salary_parameter()
|
32 |
StreamlitFunctions.reset_initial_salary_parameter()
|
33 |
+
st.button(
|
34 |
+
"Calculate Based on Desired Net Salary",
|
35 |
+
use_container_width=True,
|
36 |
+
on_click=calculate_initial_salary_parameter,
|
37 |
+
)
|
38 |
|
39 |
+
StreamlitFunctions.print_tax_on_current_salary()
|
40 |
+
StreamlitFunctions.reset_tax_on_current_salary()
|
41 |
+
st.button(
|
42 |
+
"Calculate Tax on Current Salary",
|
43 |
+
use_container_width=True,
|
44 |
+
on_click=calculate_tax_on_current_salary,
|
45 |
+
)
|
46 |
+
|
47 |
+
if st.session_state.type_to_calculate is not None:
|
48 |
+
if st.session_state.type_to_calculate == "tax_on_current_salary":
|
49 |
+
initial_desired_net = Functions.calculated_current_salary_after_tax(
|
50 |
+
st.session_state.tax_on_current_salary, st.session_state.tax_brackets
|
51 |
+
)
|
52 |
+
elif st.session_state.type_to_calculate == "desired_salary":
|
53 |
initial_desired_net = st.session_state.user_initial_desired_net
|
54 |
+
elif st.session_state.type_to_calculate == "salary_parameters":
|
55 |
initial_desired_net = Functions.calculated_initial_desired_net(
|
56 |
st.session_state.current_salary,
|
57 |
st.session_state.desired_increment_percentage,
|
|
|
62 |
result = Functions.calculate_additional_amount(
|
63 |
initial_desired_net, st.session_state.tax_brackets
|
64 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
# Display how initial_desired_net was determined
|
67 |
st.markdown("---")
|
68 |
+
if st.session_state.type_to_calculate == "tax_on_current_salary":
|
69 |
+
st.success(
|
70 |
+
"✅ Calculation was done based on the selected value of 'Tax on Current Salary'"
|
71 |
+
)
|
72 |
+
summary_df = pd.DataFrame(
|
73 |
+
{
|
74 |
+
"Parameter": [
|
75 |
+
"Current Salary",
|
76 |
+
"Tax",
|
77 |
+
"Gross Salary",
|
78 |
+
],
|
79 |
+
"Value": [
|
80 |
+
f"PKR {result['final_net_salary']:,.2f}",
|
81 |
+
f"PKR {result['tax']:,.2f}",
|
82 |
+
f"PKR {result['gross_salary_needed']:,.2f}",
|
83 |
+
],
|
84 |
+
}
|
85 |
+
)
|
86 |
+
elif st.session_state.type_to_calculate == "desired_salary":
|
87 |
+
st.success(
|
88 |
+
"✅ Calculation was done based on the selected value of 'Final Desired Net Salary'"
|
89 |
+
)
|
90 |
summary_df = pd.DataFrame(
|
91 |
{
|
92 |
"Parameter": [
|
|
|
101 |
],
|
102 |
}
|
103 |
)
|
104 |
+
elif st.session_state.type_to_calculate == "salary_parameters":
|
105 |
+
st.success(
|
106 |
+
"✅ Calculation was done based on the selected values of 'Salary Parameters'"
|
107 |
)
|
108 |
summary_df = pd.DataFrame(
|
109 |
{
|
|
|
127 |
],
|
128 |
}
|
129 |
)
|
130 |
+
st.header("Salary Calculation Results")
|
131 |
+
col1, col2 = st.columns(2)
|
132 |
+
with col1:
|
133 |
+
# custom_metric("Initial Desired Net Salary", result['initial_desired_net'])
|
134 |
+
StreamlitFunctions.custom_metric("Final Net Salary", result["final_net_salary"])
|
135 |
+
StreamlitFunctions.custom_metric("Tax", result["tax"])
|
136 |
|
137 |
+
with col2:
|
138 |
+
# custom_metric("Additional Amount Needed", result['additional_amount'])
|
139 |
+
StreamlitFunctions.custom_metric(
|
140 |
+
"Gross Salary Needed", result["gross_salary_needed"]
|
141 |
+
)
|
142 |
# Display a summary of the calculation
|
143 |
st.subheader("Calculation Summary")
|
144 |
+
st.data_editor(summary_df, use_container_width=True, hide_index=True)
|
145 |
+
st.session_state.type_to_calculate = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constants.py
CHANGED
@@ -3,7 +3,8 @@ class Constants:
|
|
3 |
DEFAULT_INCREMENT_PERCENTAGE = 0.3
|
4 |
DEFAULT_DAILY_TRAVEL_COST = 1500
|
5 |
DEFAULT_PHYSICAL_DAYS = 5
|
6 |
-
DEFAULT_INITIAL_NET =
|
|
|
7 |
|
8 |
DEFAULT_TAX_BRACKETS = [
|
9 |
(0, 600000, 0),
|
|
|
3 |
DEFAULT_INCREMENT_PERCENTAGE = 0.3
|
4 |
DEFAULT_DAILY_TRAVEL_COST = 1500
|
5 |
DEFAULT_PHYSICAL_DAYS = 5
|
6 |
+
DEFAULT_INITIAL_NET = 212500.0
|
7 |
+
DEFAULT_CURRENT_SALARY_WITH_TAX = 200000.0
|
8 |
|
9 |
DEFAULT_TAX_BRACKETS = [
|
10 |
(0, 600000, 0),
|
functions.py
CHANGED
@@ -3,6 +3,12 @@ import streamlit as st
|
|
3 |
|
4 |
|
5 |
class Functions:
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
@staticmethod
|
7 |
def calculate_monthly_tax(monthly_income, tax_brackets):
|
8 |
annual_income = monthly_income * 12
|
@@ -60,34 +66,20 @@ import pandas as pd
|
|
60 |
|
61 |
|
62 |
class StreamlitFunctions:
|
63 |
-
@staticmethod
|
64 |
-
def check_initial_salary_parameter():
|
65 |
-
if (
|
66 |
-
st.session_state.user_initial_desired_net > 0
|
67 |
-
and st.session_state.user_initial_desired_net
|
68 |
-
<= st.session_state.current_salary
|
69 |
-
):
|
70 |
-
st.warning(
|
71 |
-
"⚠️ The Initial Desired Net Salary should be greater than your Current Salary. Please adjust your input or leave it at 0 to calculate automatically."
|
72 |
-
)
|
73 |
-
st.session_state.valid_input = False
|
74 |
-
else:
|
75 |
-
st.session_state.valid_input = True
|
76 |
-
|
77 |
@staticmethod
|
78 |
def update_initial_salary_parameter():
|
79 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
st.session_state.user_initial_desired_net_state
|
81 |
-
|
82 |
-
):
|
83 |
-
st.session_state.user_initial_desired_net = (
|
84 |
-
st.session_state.current_salary
|
85 |
-
+ st.session_state.user_initial_desired_net_state
|
86 |
-
)
|
87 |
-
else:
|
88 |
-
st.session_state.user_initial_desired_net = (
|
89 |
-
st.session_state.user_initial_desired_net_state
|
90 |
-
)
|
91 |
|
92 |
@staticmethod
|
93 |
def reset_initial_salary_parameter():
|
@@ -103,13 +95,13 @@ class StreamlitFunctions:
|
|
103 |
|
104 |
@staticmethod
|
105 |
def initial_salary_parameter():
|
106 |
-
st.header("
|
107 |
if st.session_state.user_initial_desired_net >= st.session_state.current_salary:
|
108 |
minimum_value = st.session_state.current_salary
|
109 |
else:
|
110 |
minimum_value = 0.0
|
111 |
st.number_input(
|
112 |
-
"Final Desired Net Salary (PKR
|
113 |
min_value=minimum_value,
|
114 |
value=st.session_state.user_initial_desired_net,
|
115 |
step=1000.0,
|
@@ -144,15 +136,46 @@ class StreamlitFunctions:
|
|
144 |
on_click=reset_values,
|
145 |
)
|
146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
@staticmethod
|
148 |
def print_salary_parameters():
|
149 |
-
st.header("
|
150 |
|
151 |
def update_current_salary_parameter():
|
152 |
st.session_state.current_salary = st.session_state.current_salary_state
|
153 |
|
154 |
-
st.
|
155 |
-
"Current monthly salary (PKR)",
|
156 |
min_value=0.0,
|
157 |
step=1000.0,
|
158 |
value=st.session_state.current_salary,
|
@@ -165,7 +188,7 @@ class StreamlitFunctions:
|
|
165 |
st.session_state.desired_increment_percentage_state
|
166 |
)
|
167 |
|
168 |
-
st.
|
169 |
"Desired salary increment (as a decimal)",
|
170 |
min_value=0.0,
|
171 |
step=0.05,
|
@@ -180,7 +203,7 @@ class StreamlitFunctions:
|
|
180 |
st.session_state.daily_cost_of_travel_state
|
181 |
)
|
182 |
|
183 |
-
st.
|
184 |
"Daily cost of travel (PKR)",
|
185 |
min_value=0,
|
186 |
step=100,
|
@@ -194,7 +217,7 @@ class StreamlitFunctions:
|
|
194 |
st.session_state.physical_days_per_week_state
|
195 |
)
|
196 |
|
197 |
-
st.
|
198 |
"Number of On-Site days per week",
|
199 |
min_value=0,
|
200 |
max_value=7,
|
@@ -211,7 +234,10 @@ class StreamlitFunctions:
|
|
211 |
st.session_state.tax_brackets,
|
212 |
columns=["Lower Limit", "Upper Limit", "Tax Rate"],
|
213 |
)
|
214 |
-
|
|
|
|
|
|
|
215 |
st.session_state.tax_brackets = list(
|
216 |
edited_tax_brackets.itertuples(index=False, name=None)
|
217 |
)
|
@@ -221,6 +247,10 @@ class StreamlitFunctions:
|
|
221 |
st.title("Net Salary Calculator")
|
222 |
if "tax_brackets" not in st.session_state:
|
223 |
st.session_state.tax_brackets = Constants.DEFAULT_TAX_BRACKETS
|
|
|
|
|
|
|
|
|
224 |
if "current_salary" not in st.session_state:
|
225 |
st.session_state.current_salary = Constants.DEFAULT_CURRENT_SALARY
|
226 |
if "desired_increment_percentage" not in st.session_state:
|
@@ -233,7 +263,10 @@ class StreamlitFunctions:
|
|
233 |
st.session_state.physical_days_per_week = Constants.DEFAULT_PHYSICAL_DAYS
|
234 |
if "user_initial_desired_net" not in st.session_state:
|
235 |
st.session_state.user_initial_desired_net = Constants.DEFAULT_INITIAL_NET
|
236 |
-
|
|
|
|
|
|
|
237 |
@staticmethod
|
238 |
def custom_metric(label, value):
|
239 |
st.markdown(Styles.METRIC_STYLE, unsafe_allow_html=True)
|
|
|
3 |
|
4 |
|
5 |
class Functions:
|
6 |
+
@staticmethod
|
7 |
+
def calculated_current_salary_after_tax(current_salary, tax_brackets):
|
8 |
+
return current_salary - Functions.calculate_monthly_tax(
|
9 |
+
current_salary, tax_brackets
|
10 |
+
)
|
11 |
+
|
12 |
@staticmethod
|
13 |
def calculate_monthly_tax(monthly_income, tax_brackets):
|
14 |
annual_income = monthly_income * 12
|
|
|
66 |
|
67 |
|
68 |
class StreamlitFunctions:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
@staticmethod
|
70 |
def update_initial_salary_parameter():
|
71 |
+
# if (
|
72 |
+
# st.session_state.user_initial_desired_net_state
|
73 |
+
# < st.session_state.current_salary
|
74 |
+
# ):
|
75 |
+
# st.session_state.user_initial_desired_net = (
|
76 |
+
# st.session_state.current_salary
|
77 |
+
# + st.session_state.user_initial_desired_net_state
|
78 |
+
# )
|
79 |
+
# else:
|
80 |
+
st.session_state.user_initial_desired_net = (
|
81 |
st.session_state.user_initial_desired_net_state
|
82 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
84 |
@staticmethod
|
85 |
def reset_initial_salary_parameter():
|
|
|
95 |
|
96 |
@staticmethod
|
97 |
def initial_salary_parameter():
|
98 |
+
st.header("Final Desired Net Salary")
|
99 |
if st.session_state.user_initial_desired_net >= st.session_state.current_salary:
|
100 |
minimum_value = st.session_state.current_salary
|
101 |
else:
|
102 |
minimum_value = 0.0
|
103 |
st.number_input(
|
104 |
+
"Final Desired Net Salary (PKR)",
|
105 |
min_value=minimum_value,
|
106 |
value=st.session_state.user_initial_desired_net,
|
107 |
step=1000.0,
|
|
|
136 |
on_click=reset_values,
|
137 |
)
|
138 |
|
139 |
+
@staticmethod
|
140 |
+
def reset_tax_on_current_salary():
|
141 |
+
def reset_values():
|
142 |
+
st.session_state.tax_on_current_salary = (
|
143 |
+
Constants.DEFAULT_CURRENT_SALARY_WITH_TAX
|
144 |
+
)
|
145 |
+
|
146 |
+
st.button(
|
147 |
+
"Reset Current Salary",
|
148 |
+
use_container_width=True,
|
149 |
+
on_click=reset_values,
|
150 |
+
)
|
151 |
+
|
152 |
+
@staticmethod
|
153 |
+
def print_tax_on_current_salary():
|
154 |
+
st.header("Tax on Current Salary")
|
155 |
+
|
156 |
+
def update_tax_on_current_salary_parameter():
|
157 |
+
st.session_state.tax_on_current_salary = (
|
158 |
+
st.session_state.tax_on_current_salary_state
|
159 |
+
)
|
160 |
+
|
161 |
+
st.number_input(
|
162 |
+
"Current monthly Salary (PKR)",
|
163 |
+
min_value=0.0,
|
164 |
+
step=1000.0,
|
165 |
+
value=st.session_state.tax_on_current_salary,
|
166 |
+
key="tax_on_current_salary_state",
|
167 |
+
on_change=update_tax_on_current_salary_parameter,
|
168 |
+
)
|
169 |
+
|
170 |
@staticmethod
|
171 |
def print_salary_parameters():
|
172 |
+
st.header("Salary Parameters")
|
173 |
|
174 |
def update_current_salary_parameter():
|
175 |
st.session_state.current_salary = st.session_state.current_salary_state
|
176 |
|
177 |
+
st.number_input(
|
178 |
+
"Current monthly salary after Tax (PKR)",
|
179 |
min_value=0.0,
|
180 |
step=1000.0,
|
181 |
value=st.session_state.current_salary,
|
|
|
188 |
st.session_state.desired_increment_percentage_state
|
189 |
)
|
190 |
|
191 |
+
st.number_input(
|
192 |
"Desired salary increment (as a decimal)",
|
193 |
min_value=0.0,
|
194 |
step=0.05,
|
|
|
203 |
st.session_state.daily_cost_of_travel_state
|
204 |
)
|
205 |
|
206 |
+
st.number_input(
|
207 |
"Daily cost of travel (PKR)",
|
208 |
min_value=0,
|
209 |
step=100,
|
|
|
217 |
st.session_state.physical_days_per_week_state
|
218 |
)
|
219 |
|
220 |
+
st.number_input(
|
221 |
"Number of On-Site days per week",
|
222 |
min_value=0,
|
223 |
max_value=7,
|
|
|
234 |
st.session_state.tax_brackets,
|
235 |
columns=["Lower Limit", "Upper Limit", "Tax Rate"],
|
236 |
)
|
237 |
+
|
238 |
+
edited_tax_brackets = st.data_editor(
|
239 |
+
tax_brackets_df, num_rows="dynamic", use_container_width=True
|
240 |
+
)
|
241 |
st.session_state.tax_brackets = list(
|
242 |
edited_tax_brackets.itertuples(index=False, name=None)
|
243 |
)
|
|
|
247 |
st.title("Net Salary Calculator")
|
248 |
if "tax_brackets" not in st.session_state:
|
249 |
st.session_state.tax_brackets = Constants.DEFAULT_TAX_BRACKETS
|
250 |
+
if "tax_on_current_salary" not in st.session_state:
|
251 |
+
st.session_state.tax_on_current_salary = (
|
252 |
+
Constants.DEFAULT_CURRENT_SALARY_WITH_TAX
|
253 |
+
)
|
254 |
if "current_salary" not in st.session_state:
|
255 |
st.session_state.current_salary = Constants.DEFAULT_CURRENT_SALARY
|
256 |
if "desired_increment_percentage" not in st.session_state:
|
|
|
263 |
st.session_state.physical_days_per_week = Constants.DEFAULT_PHYSICAL_DAYS
|
264 |
if "user_initial_desired_net" not in st.session_state:
|
265 |
st.session_state.user_initial_desired_net = Constants.DEFAULT_INITIAL_NET
|
266 |
+
|
267 |
+
if "type_to_calculate" not in st.session_state:
|
268 |
+
st.session_state.type_to_calculate = None
|
269 |
+
|
270 |
@staticmethod
|
271 |
def custom_metric(label, value):
|
272 |
st.markdown(Styles.METRIC_STYLE, unsafe_allow_html=True)
|