python-taxes 0.1.0__tar.gz

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.
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.3
2
+ Name: python-taxes
3
+ Version: 0.1.0
4
+ Summary: Development in progress - please come back later.
5
+ Author: Stacy Noland
6
+ Author-email: 46572585+stacynoland@users.noreply.github.com
7
+ Requires-Python: >=3.13
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Requires-Dist: pydantic (>=2.10.6,<3.0.0)
11
+ Description-Content-Type: text/markdown
12
+
13
+
File without changes
@@ -0,0 +1,23 @@
1
+ [project]
2
+ name = "python-taxes"
3
+ version = "0.1.0"
4
+ description = "Development in progress - please come back later."
5
+ authors = [
6
+ {name = "Stacy Noland", email = "46572585+stacynoland@users.noreply.github.com"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.13"
10
+ dependencies = [
11
+ "pydantic (>=2.10.6,<3.0.0)"
12
+ ]
13
+
14
+ [tool.poetry]
15
+ packages = [{include = "python_taxes", from = "src"}]
16
+
17
+
18
+ [tool.poetry.group.dev.dependencies]
19
+ pytest = "^8.3.5"
20
+
21
+ [build-system]
22
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
23
+ build-backend = "poetry.core.masonry.api"
File without changes
@@ -0,0 +1,13 @@
1
+ from decimal import Decimal, getcontext, ROUND_HALF_UP
2
+
3
+
4
+ getcontext().rounding = ROUND_HALF_UP
5
+
6
+ ROUNDED = Decimal('1.')
7
+
8
+ NOT_ROUNDED = Decimal('0.01')
9
+
10
+ rounding = {
11
+ True: ROUNDED,
12
+ False: NOT_ROUNDED,
13
+ }
@@ -0,0 +1,88 @@
1
+ from decimal import Decimal
2
+ from typing import Annotated, Literal, Optional
3
+
4
+ from pydantic import Field, StrictBool, validate_call
5
+
6
+ from . import rounding
7
+
8
+
9
+ STANDARD_PERCENT = Decimal("1.45") / 100
10
+
11
+ SELF_EMPLOYED_PERCENT = Decimal("2.9") / 100
12
+
13
+ ADDITIONAL_PERCENT = Decimal("0.9") / 100
14
+
15
+ DEFAULT_THRESHOLD = Decimal("200000")
16
+
17
+ status_threshold = {
18
+ 'single': DEFAULT_THRESHOLD,
19
+ 'married': Decimal("250000"),
20
+ 'separate': Decimal("125000"),
21
+ 'hoh': DEFAULT_THRESHOLD,
22
+ }
23
+
24
+
25
+ @validate_call
26
+ def withholding(
27
+ taxable_wages: Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)],
28
+ taxable_wages_ytd: Optional[
29
+ Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)]] = None,
30
+ self_employed: StrictBool = False,
31
+ rounded: StrictBool = False,
32
+ ) -> Decimal:
33
+ """Required amount to withhold regardless of filing status
34
+
35
+ Parameters:
36
+ taxable_wages -- Earned this period
37
+ taxable_wages_ytd -- Earned this year
38
+ self_employed -- Person/employee is self-employed (default False)
39
+ round -- Round response to nearest whole dollar amount (default False)
40
+ """
41
+
42
+ if not taxable_wages_ytd:
43
+ taxable_wages_ytd = 0
44
+
45
+ if self_employed:
46
+ tax_rate = SELF_EMPLOYED_PERCENT
47
+ else:
48
+ tax_rate = STANDARD_PERCENT
49
+
50
+ if (taxable_wages > DEFAULT_THRESHOLD
51
+ or (taxable_wages_ytd + taxable_wages) > DEFAULT_THRESHOLD):
52
+ tax_rate = tax_rate + ADDITIONAL_PERCENT
53
+
54
+ return (taxable_wages * tax_rate).quantize(rounding[rounded])
55
+
56
+
57
+ @validate_call
58
+ def additional_withholding(
59
+ taxable_wages_ytd: Annotated[Decimal, Field(ge=Decimal("0.01"), decimal_places=2)],
60
+ self_employed: StrictBool = False,
61
+ status: Optional[Literal['single', 'married', 'separate' 'hoh']] = 'single',
62
+ rounded: StrictBool = False,
63
+ ) -> Decimal:
64
+ """Additional withholding based on status
65
+
66
+ Parameters:
67
+ taxable_wages_ytd -- Earned this year
68
+ self_employed -- Person/employee is self-employed (default False)
69
+ status -- Filing status of person (default 'single')
70
+ round -- Round response to nearest whole dollar amount (default False)
71
+ """
72
+
73
+ if self_employed:
74
+ tax_rate = SELF_EMPLOYED_PERCENT
75
+ else:
76
+ tax_rate = STANDARD_PERCENT
77
+
78
+ threshold = status_threshold[status]
79
+
80
+ if taxable_wages_ytd > threshold:
81
+ wages_over_threshold = taxable_wages_ytd - threshold
82
+ med_taxes = (taxable_wages_ytd - wages_over_threshold) * tax_rate
83
+ tax_rate = tax_rate + ADDITIONAL_PERCENT
84
+ med_taxes = med_taxes + (wages_over_threshold * tax_rate)
85
+ else:
86
+ med_taxes = taxable_wages_ytd * tax_rate
87
+
88
+ return med_taxes.quantize(rounding[rounded])
@@ -0,0 +1,32 @@
1
+ from decimal import Decimal
2
+ from typing import Annotated, Literal, Optional
3
+
4
+ from pydantic import Field, StrictBool, validate_call
5
+
6
+ from . import rounding
7
+
8
+ STANDARD_TAX = Decimal('6.200') / 100
9
+
10
+ SELF_EMPLOYED_TAX = Decimal('12.400') / 100
11
+
12
+
13
+ @validate_call
14
+ def withholding(
15
+ taxable_wages: Annotated[Decimal, Field(ge=0.01, decimal_places=2)],
16
+ self_employed: StrictBool = False,
17
+ rounded: StrictBool = False,
18
+ ) -> Decimal:
19
+ """Social security tax withholding.
20
+
21
+ Parameters:
22
+ taxable_wages -- Total wages to be taxed
23
+ self_employed -- Person/employee is self-employed (default False)
24
+ round -- Round response to nearest whole dollar amount (default False)
25
+ """
26
+
27
+ if self_employed:
28
+ tax_rate = SELF_EMPLOYED_TAX
29
+ else:
30
+ tax_rate = STANDARD_TAX
31
+
32
+ return (taxable_wages * tax_rate).quantize(rounding[rounded])