taxforge 0.9.15__py3-none-any.whl → 0.9.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aitax/__init__.py +1 -1
- aitax/aitax.py +63 -0
- aitax/cli.py +1 -1
- aitax/state.py +124 -4
- {taxforge-0.9.15.dist-info → taxforge-0.9.16.dist-info}/METADATA +1 -1
- taxforge-0.9.16.dist-info/RECORD +11 -0
- taxforge-0.9.15.dist-info/RECORD +0 -11
- {taxforge-0.9.15.dist-info → taxforge-0.9.16.dist-info}/WHEEL +0 -0
- {taxforge-0.9.15.dist-info → taxforge-0.9.16.dist-info}/entry_points.txt +0 -0
- {taxforge-0.9.15.dist-info → taxforge-0.9.16.dist-info}/top_level.txt +0 -0
aitax/__init__.py
CHANGED
aitax/aitax.py
CHANGED
|
@@ -847,6 +847,69 @@ def review_page() -> rx.Component:
|
|
|
847
847
|
background=COLORS["bg_hover"], border_radius="8px",
|
|
848
848
|
),
|
|
849
849
|
|
|
850
|
+
# Dependents & Child Tax Credit
|
|
851
|
+
rx.vstack(
|
|
852
|
+
rx.hstack(
|
|
853
|
+
rx.text("👨👩👧👦 Dependents", color=COLORS["text_primary"], font_weight="600"),
|
|
854
|
+
rx.spacer(),
|
|
855
|
+
rx.button("+ Add", size="sm", on_click=TaxAppState.toggle_dependent_form),
|
|
856
|
+
),
|
|
857
|
+
rx.cond(
|
|
858
|
+
TaxAppState.dependents.length() > 0,
|
|
859
|
+
rx.foreach(
|
|
860
|
+
TaxAppState.dependents,
|
|
861
|
+
lambda d, idx: rx.hstack(
|
|
862
|
+
rx.text(d["name"], flex="1"),
|
|
863
|
+
rx.text(f"{d['relationship']}, Age {d['age']}"),
|
|
864
|
+
rx.badge(
|
|
865
|
+
rx.cond(d["is_child"], "CTC $2,000", "Credit $500"),
|
|
866
|
+
color_scheme=rx.cond(d["is_child"], "green", "blue"),
|
|
867
|
+
),
|
|
868
|
+
rx.icon("x", size=14, cursor="pointer",
|
|
869
|
+
on_click=lambda: TaxAppState.remove_dependent(idx)),
|
|
870
|
+
width="100%", padding="8px",
|
|
871
|
+
),
|
|
872
|
+
),
|
|
873
|
+
rx.text("No dependents added", color=COLORS["text_muted"], font_style="italic"),
|
|
874
|
+
),
|
|
875
|
+
# Dependent Form
|
|
876
|
+
rx.cond(
|
|
877
|
+
TaxAppState.show_dependent_form,
|
|
878
|
+
rx.vstack(
|
|
879
|
+
rx.hstack(
|
|
880
|
+
rx.input(placeholder="Name", value=TaxAppState.dependent_form_name, on_change=TaxAppState.set_dependent_name, flex="1"),
|
|
881
|
+
rx.input(placeholder="Relationship", value=TaxAppState.dependent_form_relationship, on_change=TaxAppState.set_dependent_relationship, width="120px"),
|
|
882
|
+
rx.input(placeholder="Age", value=TaxAppState.dependent_form_age, on_change=TaxAppState.set_dependent_age, type="number", width="80px"),
|
|
883
|
+
width="100%",
|
|
884
|
+
),
|
|
885
|
+
rx.text("Under 17 = $2,000 Child Tax Credit | 17+ = $500 Other Dependent Credit",
|
|
886
|
+
color=COLORS["text_muted"], font_size="12px"),
|
|
887
|
+
rx.hstack(
|
|
888
|
+
rx.button("Cancel", variant="outline", on_click=TaxAppState.toggle_dependent_form),
|
|
889
|
+
rx.button("Add Dependent", on_click=TaxAppState.submit_dependent_form),
|
|
890
|
+
width="100%", justify="end",
|
|
891
|
+
),
|
|
892
|
+
width="100%", spacing="2", padding="12px",
|
|
893
|
+
background="white", border_radius="8px", border=f"1px solid {COLORS['border']}",
|
|
894
|
+
),
|
|
895
|
+
),
|
|
896
|
+
# Credits Summary
|
|
897
|
+
rx.cond(
|
|
898
|
+
TaxAppState.child_tax_credit > 0,
|
|
899
|
+
rx.text(f"Child Tax Credit: ${TaxAppState.child_tax_credit:,.2f}",
|
|
900
|
+
color=COLORS["success"], font_size="13px"),
|
|
901
|
+
),
|
|
902
|
+
rx.cond(
|
|
903
|
+
TaxAppState.other_dependent_credit > 0,
|
|
904
|
+
rx.text(f"Other Dependent Credit: ${TaxAppState.other_dependent_credit:,.2f}",
|
|
905
|
+
color=COLORS["success"], font_size="13px"),
|
|
906
|
+
),
|
|
907
|
+
rx.text(f"Total Tax Credits: ${TaxAppState.total_credits:,.2f}",
|
|
908
|
+
color=COLORS["success"], font_size="13px", font_weight="600"),
|
|
909
|
+
width="100%", spacing="2", padding="12px",
|
|
910
|
+
background=COLORS["bg_hover"], border_radius="8px",
|
|
911
|
+
),
|
|
912
|
+
|
|
850
913
|
spacing="4",
|
|
851
914
|
width="100%",
|
|
852
915
|
),
|
aitax/cli.py
CHANGED
aitax/state.py
CHANGED
|
@@ -136,11 +136,18 @@ class TaxAppState(rx.State):
|
|
|
136
136
|
other_deduction_form_desc: str = ""
|
|
137
137
|
other_deduction_form_amount: str = ""
|
|
138
138
|
|
|
139
|
+
# Dependent form
|
|
140
|
+
dependent_form_name: str = ""
|
|
141
|
+
dependent_form_relationship: str = ""
|
|
142
|
+
dependent_form_age: str = ""
|
|
143
|
+
child_care_form_amount: str = ""
|
|
144
|
+
|
|
139
145
|
# Form visibility
|
|
140
146
|
show_rental_form: bool = False
|
|
141
147
|
show_business_form: bool = False
|
|
142
148
|
show_other_income_form: bool = False
|
|
143
149
|
show_other_deduction_form: bool = False
|
|
150
|
+
show_dependent_form: bool = False
|
|
144
151
|
|
|
145
152
|
# ===== Document State =====
|
|
146
153
|
uploaded_files: List[str] = []
|
|
@@ -168,6 +175,12 @@ class TaxAppState(rx.State):
|
|
|
168
175
|
other_income: List[Dict] = [] # {description, amount, tax_type}
|
|
169
176
|
other_deductions: List[Dict] = [] # {description, amount, deduction_type}
|
|
170
177
|
|
|
178
|
+
# Dependents
|
|
179
|
+
dependents: List[Dict] = [] # {name, relationship, age, ssn_last4, is_child}
|
|
180
|
+
|
|
181
|
+
# Child and Dependent Care
|
|
182
|
+
child_care_expenses: float = 0.0 # Expenses for dependent care while working
|
|
183
|
+
|
|
171
184
|
# ===== Calculated Values =====
|
|
172
185
|
total_wages: float = 0.0
|
|
173
186
|
total_interest: float = 0.0
|
|
@@ -186,6 +199,12 @@ class TaxAppState(rx.State):
|
|
|
186
199
|
capital_gains_tax: float = 0.0 # Separate tax on capital gains
|
|
187
200
|
additional_medicare_tax: float = 0.0 # 0.9% on wages > $250k (MFJ)
|
|
188
201
|
niit: float = 0.0 # Net Investment Income Tax 3.8%
|
|
202
|
+
|
|
203
|
+
# Tax Credits
|
|
204
|
+
child_tax_credit: float = 0.0 # $2,000 per child under 17
|
|
205
|
+
other_dependent_credit: float = 0.0 # $500 per other dependent
|
|
206
|
+
child_care_credit: float = 0.0 # Credit for child/dependent care
|
|
207
|
+
total_credits: float = 0.0
|
|
189
208
|
taxable_income: float = 0.0
|
|
190
209
|
total_tax: float = 0.0
|
|
191
210
|
total_withholding: float = 0.0
|
|
@@ -555,6 +574,28 @@ class TaxAppState(rx.State):
|
|
|
555
574
|
self.other_deductions.pop(index)
|
|
556
575
|
self._recalculate()
|
|
557
576
|
|
|
577
|
+
# ===== Dependent Methods =====
|
|
578
|
+
def add_dependent(self, name: str, relationship: str, age: int, is_child: bool = True):
|
|
579
|
+
"""Add a dependent (child or other)."""
|
|
580
|
+
self.dependents.append({
|
|
581
|
+
"name": name,
|
|
582
|
+
"relationship": relationship,
|
|
583
|
+
"age": age,
|
|
584
|
+
"is_child": is_child and age < 17, # Child Tax Credit requires under 17
|
|
585
|
+
})
|
|
586
|
+
self._recalculate()
|
|
587
|
+
|
|
588
|
+
def remove_dependent(self, index: int):
|
|
589
|
+
"""Remove a dependent."""
|
|
590
|
+
if 0 <= index < len(self.dependents):
|
|
591
|
+
self.dependents.pop(index)
|
|
592
|
+
self._recalculate()
|
|
593
|
+
|
|
594
|
+
def set_child_care_expenses(self, amount: float):
|
|
595
|
+
"""Set child/dependent care expenses."""
|
|
596
|
+
self.child_care_expenses = amount
|
|
597
|
+
self._recalculate()
|
|
598
|
+
|
|
558
599
|
# ===== Form Toggle Methods =====
|
|
559
600
|
def toggle_rental_form(self):
|
|
560
601
|
self.show_rental_form = not self.show_rental_form
|
|
@@ -568,6 +609,9 @@ class TaxAppState(rx.State):
|
|
|
568
609
|
def toggle_other_deduction_form(self):
|
|
569
610
|
self.show_other_deduction_form = not self.show_other_deduction_form
|
|
570
611
|
|
|
612
|
+
def toggle_dependent_form(self):
|
|
613
|
+
self.show_dependent_form = not self.show_dependent_form
|
|
614
|
+
|
|
571
615
|
# ===== Form Input Setters =====
|
|
572
616
|
def set_rental_address(self, val): self.rental_form_address = val
|
|
573
617
|
def set_rental_income(self, val): self.rental_form_income = val
|
|
@@ -587,6 +631,11 @@ class TaxAppState(rx.State):
|
|
|
587
631
|
def set_other_deduction_desc(self, val): self.other_deduction_form_desc = val
|
|
588
632
|
def set_other_deduction_amount(self, val): self.other_deduction_form_amount = val
|
|
589
633
|
|
|
634
|
+
def set_dependent_name(self, val): self.dependent_form_name = val
|
|
635
|
+
def set_dependent_relationship(self, val): self.dependent_form_relationship = val
|
|
636
|
+
def set_dependent_age(self, val): self.dependent_form_age = val
|
|
637
|
+
def set_child_care_amount(self, val): self.child_care_form_amount = val
|
|
638
|
+
|
|
590
639
|
# ===== Form Submit Methods =====
|
|
591
640
|
def submit_rental_form(self):
|
|
592
641
|
"""Submit rental property form."""
|
|
@@ -659,6 +708,34 @@ class TaxAppState(rx.State):
|
|
|
659
708
|
except ValueError:
|
|
660
709
|
self.error_message = "Invalid amount"
|
|
661
710
|
|
|
711
|
+
def submit_dependent_form(self):
|
|
712
|
+
"""Submit dependent form."""
|
|
713
|
+
try:
|
|
714
|
+
age = int(self.dependent_form_age or 0)
|
|
715
|
+
self.add_dependent(
|
|
716
|
+
name=self.dependent_form_name or "Dependent",
|
|
717
|
+
relationship=self.dependent_form_relationship or "Child",
|
|
718
|
+
age=age,
|
|
719
|
+
is_child=(age < 17),
|
|
720
|
+
)
|
|
721
|
+
self.dependent_form_name = ""
|
|
722
|
+
self.dependent_form_relationship = ""
|
|
723
|
+
self.dependent_form_age = ""
|
|
724
|
+
self.show_dependent_form = False
|
|
725
|
+
self.success_message = "Dependent added!"
|
|
726
|
+
except ValueError:
|
|
727
|
+
self.error_message = "Invalid age"
|
|
728
|
+
|
|
729
|
+
def submit_child_care_expenses(self):
|
|
730
|
+
"""Submit child care expenses."""
|
|
731
|
+
try:
|
|
732
|
+
self.child_care_expenses = float(self.child_care_form_amount or 0)
|
|
733
|
+
self.child_care_form_amount = ""
|
|
734
|
+
self._recalculate()
|
|
735
|
+
self.success_message = "Child care expenses updated!"
|
|
736
|
+
except ValueError:
|
|
737
|
+
self.error_message = "Invalid amount"
|
|
738
|
+
|
|
662
739
|
def remove_file(self, filename: str):
|
|
663
740
|
"""Remove an uploaded file and its extracted data."""
|
|
664
741
|
if filename in self.uploaded_files:
|
|
@@ -871,10 +948,51 @@ class TaxAppState(rx.State):
|
|
|
871
948
|
niit_base = min(investment_income, max(0, self.adjusted_gross_income - niit_threshold))
|
|
872
949
|
self.niit = niit_base * 0.038
|
|
873
950
|
|
|
874
|
-
#
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
951
|
+
# Gross tax before credits
|
|
952
|
+
gross_tax = (ordinary_tax + self.capital_gains_tax +
|
|
953
|
+
self.additional_medicare_tax + self.niit +
|
|
954
|
+
self.self_employment_tax)
|
|
955
|
+
|
|
956
|
+
# ===== TAX CREDITS =====
|
|
957
|
+
|
|
958
|
+
# Child Tax Credit ($2,000 per qualifying child under 17)
|
|
959
|
+
# Phase out: MFJ $400k, others $200k
|
|
960
|
+
ctc_phaseout = 400000 if self.filing_status == "married_filing_jointly" else 200000
|
|
961
|
+
qualifying_children = sum(1 for d in self.dependents if d.get("is_child", False))
|
|
962
|
+
base_ctc = qualifying_children * 2000
|
|
963
|
+
|
|
964
|
+
# Phase out: reduce by $50 for each $1,000 over threshold
|
|
965
|
+
if self.adjusted_gross_income > ctc_phaseout:
|
|
966
|
+
reduction = ((self.adjusted_gross_income - ctc_phaseout) // 1000) * 50
|
|
967
|
+
self.child_tax_credit = max(0, base_ctc - reduction)
|
|
968
|
+
else:
|
|
969
|
+
self.child_tax_credit = base_ctc
|
|
970
|
+
|
|
971
|
+
# Credit for Other Dependents ($500 per dependent not qualifying for CTC)
|
|
972
|
+
other_dependents = sum(1 for d in self.dependents if not d.get("is_child", False))
|
|
973
|
+
self.other_dependent_credit = other_dependents * 500
|
|
974
|
+
|
|
975
|
+
# Child and Dependent Care Credit (20-35% of expenses, max $3,000/1 or $6,000/2+)
|
|
976
|
+
if self.child_care_expenses > 0 and qualifying_children > 0:
|
|
977
|
+
max_expenses = 3000 if qualifying_children == 1 else 6000
|
|
978
|
+
eligible_expenses = min(self.child_care_expenses, max_expenses)
|
|
979
|
+
# Credit rate: 35% if AGI <= $15,000, phases down to 20% at $43,000+
|
|
980
|
+
if self.adjusted_gross_income <= 15000:
|
|
981
|
+
rate = 0.35
|
|
982
|
+
elif self.adjusted_gross_income >= 43000:
|
|
983
|
+
rate = 0.20
|
|
984
|
+
else:
|
|
985
|
+
rate = 0.35 - ((self.adjusted_gross_income - 15000) // 2000) * 0.01
|
|
986
|
+
rate = max(0.20, rate)
|
|
987
|
+
self.child_care_credit = eligible_expenses * rate
|
|
988
|
+
else:
|
|
989
|
+
self.child_care_credit = 0.0
|
|
990
|
+
|
|
991
|
+
# Total credits (nonrefundable - can't exceed tax)
|
|
992
|
+
self.total_credits = self.child_tax_credit + self.other_dependent_credit + self.child_care_credit
|
|
993
|
+
|
|
994
|
+
# Total tax after credits
|
|
995
|
+
self.total_tax = max(0, gross_tax - self.total_credits)
|
|
878
996
|
|
|
879
997
|
# ===== REFUND OR AMOUNT OWED =====
|
|
880
998
|
self.refund_or_owed = self.total_withholding - self.total_tax
|
|
@@ -919,6 +1037,8 @@ class TaxAppState(rx.State):
|
|
|
919
1037
|
self.business_income = []
|
|
920
1038
|
self.other_income = []
|
|
921
1039
|
self.other_deductions = []
|
|
1040
|
+
self.dependents = []
|
|
1041
|
+
self.child_care_expenses = 0.0
|
|
922
1042
|
self.form_1099_list = []
|
|
923
1043
|
self.total_wages = 0.0
|
|
924
1044
|
self.total_interest = 0.0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
aitax/__init__.py,sha256=l2Os-WDmdC962LQuemEbe_NvuUInlH7r3pkudOaV_cI,68
|
|
2
|
+
aitax/aitax.py,sha256=3V3LdjT5q64eZoFgdsiTqWV9aZLgWD3NUtKzBPCfQ2w,63630
|
|
3
|
+
aitax/cli.py,sha256=2HlOOXVh1rJixJbGhVGKOPtiLlLD_NzsAhrun5FLHyU,2651
|
|
4
|
+
aitax/components.py,sha256=pi4wKOtNsw0ju1cN3ivY7UWF0Q32rshijeklFnxVt5U,21056
|
|
5
|
+
aitax/document_extractor.py,sha256=l2bMajEwK382lH57eiHOn5E1ohgijezgldiBURiV4_s,10459
|
|
6
|
+
aitax/state.py,sha256=Kra1XJnlaTn8QccpVW5MlDwFtiFzBeJ679UWzSZ2zWc,42086
|
|
7
|
+
taxforge-0.9.16.dist-info/METADATA,sha256=JXe6pV9rHDxCyHjleg1XDiJKiaE8FZ7xMnww5Ropav8,4874
|
|
8
|
+
taxforge-0.9.16.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
+
taxforge-0.9.16.dist-info/entry_points.txt,sha256=2dG4U_m3yvQaVeD8LeEGm1v8szyNGQtXUZOvbwH75Gg,44
|
|
10
|
+
taxforge-0.9.16.dist-info/top_level.txt,sha256=H7DuLZSRzSwHT5STc7uQa0oTOsKcNYUz2Pn4a4C5Q0Y,6
|
|
11
|
+
taxforge-0.9.16.dist-info/RECORD,,
|
taxforge-0.9.15.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
aitax/__init__.py,sha256=JncLlRPr8j0rLn9Z0IqBYPMdBa-gb059WY-BvS1oRyU,68
|
|
2
|
-
aitax/aitax.py,sha256=e4DitXQwj61BtgVTaV-so8U00P6EKkec6LKVxbkFdHE,59433
|
|
3
|
-
aitax/cli.py,sha256=bbkhzRJyrne-0p3aImWuQCUDbzOOBV-4aEg-cviVxIg,2651
|
|
4
|
-
aitax/components.py,sha256=pi4wKOtNsw0ju1cN3ivY7UWF0Q32rshijeklFnxVt5U,21056
|
|
5
|
-
aitax/document_extractor.py,sha256=l2bMajEwK382lH57eiHOn5E1ohgijezgldiBURiV4_s,10459
|
|
6
|
-
aitax/state.py,sha256=Xj9NU237CT6eOHAT91NPDJeNOZESa9yqtc8Q7SfTerg,37016
|
|
7
|
-
taxforge-0.9.15.dist-info/METADATA,sha256=AzyV0f1f_erkAHyllM3Wx_N_4WVYHO_qGh0_I2ENeek,4874
|
|
8
|
-
taxforge-0.9.15.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
-
taxforge-0.9.15.dist-info/entry_points.txt,sha256=2dG4U_m3yvQaVeD8LeEGm1v8szyNGQtXUZOvbwH75Gg,44
|
|
10
|
-
taxforge-0.9.15.dist-info/top_level.txt,sha256=H7DuLZSRzSwHT5STc7uQa0oTOsKcNYUz2Pn4a4C5Q0Y,6
|
|
11
|
-
taxforge-0.9.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|