meta_payroll_type: Refactor for more code reuse.
This commit is contained in:
parent
9d41f79c52
commit
7c18bc221f
3 changed files with 79 additions and 44 deletions
|
@ -67,7 +67,12 @@ class HookRegistry:
|
||||||
'.meta_repo_links': None,
|
'.meta_repo_links': None,
|
||||||
'.meta_rt_links': ['MetaRTLinks'],
|
'.meta_rt_links': ['MetaRTLinks'],
|
||||||
'.meta_tax_implication': None,
|
'.meta_tax_implication': None,
|
||||||
'.meta_payroll_type': None,
|
'.meta_payroll_type': [
|
||||||
|
'HealthInsuranceHook',
|
||||||
|
'OtherBenefitsHook',
|
||||||
|
'SalaryHook',
|
||||||
|
'TaxHook',
|
||||||
|
],
|
||||||
'.txn_date': ['TransactionDate'],
|
'.txn_date': ['TransactionDate'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,56 +14,86 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from . import core
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from . import core
|
||||||
from .. import ranges
|
from .. import ranges
|
||||||
from .. import data
|
from .. import data
|
||||||
from .. import errors as errormod
|
from .. import errors as errormod
|
||||||
|
|
||||||
from ..beancount_types import (
|
from ..beancount_types import (
|
||||||
Transaction,
|
Transaction,
|
||||||
)
|
)
|
||||||
|
|
||||||
class MetaPayrollType(core._PostingHook):
|
METADATA_KEY = 'payroll-type'
|
||||||
"""Verify payroll-type metadata, starting on 2020-03-01 (FY 2020), is provided for the accounts:
|
|
||||||
Expenses:Payroll:Salary, Expenses:Payroll:Taxes, Expenses:Payroll:Benefits:HealthInsurance, and
|
class _PayrollTypeHook(core._NormalizePostingMetadataHook):
|
||||||
Expenses:Payroll:Benefits:Other.
|
ACCOUNT: str
|
||||||
Valid values for payroll-type are listed in the
|
VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [])
|
||||||
_SALARY_TYPES, _TAX_TYPES, _HEALTH_INSURANCE_TYPES, and _OTHER_BENEFIT_TYPES
|
TXN_DATE_RANGE = ranges.DateRange(
|
||||||
(respectively) in the class.
|
datetime.date(2020, 3, 1),
|
||||||
"""
|
core.DEFAULT_STOP_DATE,
|
||||||
METADATA_KEY = 'payroll-type'
|
)
|
||||||
HOOK_GROUPS = frozenset(['metadata', METADATA_KEY])
|
|
||||||
_TAX_TYPES = [ "CA:PP", "CA:EI",
|
|
||||||
"US:SocialSecurity", "US:Medicare",
|
|
||||||
"US:IL:Unemployment",
|
|
||||||
"US:MA:Unemployment", "US:MA:WorkTrain", "US:MA:Health",
|
|
||||||
"US:OR:Unemployment" ]
|
|
||||||
_SALARY_TYPES = [ "US:General", "US:PTO", "US:403b:Employee", "US:403b:Match",
|
|
||||||
"CA:General", "CA:PTO",
|
|
||||||
"CA:Taxes:Income", "CA:Taxes:EI", "CA:Taxes:PP",
|
|
||||||
"US:Taxes:Income", "US:Taxes:SocialSecurity", "US:Taxes:Medicare",
|
|
||||||
"US:IL:Taxes:Income",
|
|
||||||
"US:OR:Taxes:Income", "US:OR:Taxes:STT",
|
|
||||||
"US:MA:Taxes:Income", "US:MA:Disability:PML", "US:MA:Disability:PFL",
|
|
||||||
"US:NY:Taxes:Income", "US:NY:Disability:PFL", "US:NY:Disability", "US:NY:Taxes:NYC" ]
|
|
||||||
_HEALTH_INSURANCE_TYPES = [ "US:HRA:Fees", "US:HRA:Usage", "US:Premium:Main", "US:Premium:DentalVision" ]
|
|
||||||
_OTHER_BENEFIT_TYPES = [ "US:403b:Fees" ]
|
|
||||||
TXN_DATE_RANGE = ranges.DateRange(datetime.date(2020, 3, 1), core.DEFAULT_STOP_DATE)
|
|
||||||
|
|
||||||
def _run_on_post(self, txn: Transaction, post: data.Posting) -> bool:
|
def _run_on_post(self, txn: Transaction, post: data.Posting) -> bool:
|
||||||
if post.account.is_under('Expenses:Payroll:Salary') or post.account.is_under('Expenses:Payroll:Taxes') or \
|
return post.account.is_under(self.ACCOUNT) is not None
|
||||||
post.account.is_under('Expenses:Payroll:Benefits:Other') or post.account.is_under('Expenses:Payroll:Benefits:HealthInsurance'):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter:
|
|
||||||
value = post.meta.get(self.METADATA_KEY)
|
class HealthInsuranceHook(_PayrollTypeHook):
|
||||||
if value is None or \
|
ACCOUNT = 'Expenses:Payroll:Benefits:HealthInsurance'
|
||||||
(post.account.is_under('Expenses:Payroll:Salary') and (not value in self._SALARY_TYPES)) or \
|
VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [
|
||||||
(post.account.is_under('Expenses:Payroll:Taxes') and (not value in self._TAX_TYPES)) or \
|
'US:HRA:Fees',
|
||||||
(post.account.is_under('Expenses:Payroll:Benefits:HealthInsurance') and \
|
'US:HRA:Usage',
|
||||||
(not value in self._HEALTH_INSURANCE_TYPES)) or \
|
'US:Premium:DentalVision',
|
||||||
(post.account.is_under('Expenses:Payroll:Benefits:Other') and \
|
'US:Premium:Main',
|
||||||
(not value in self._OTHER_BENEFIT_TYPES)):
|
])
|
||||||
yield errormod.InvalidMetadataError(txn, self.METADATA_KEY, value, post)
|
|
||||||
|
|
||||||
|
class OtherBenefitsHook(_PayrollTypeHook):
|
||||||
|
ACCOUNT = 'Expenses:Payroll:Benefits:Other'
|
||||||
|
VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [
|
||||||
|
'US:403b:Fees',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class SalaryHook(_PayrollTypeHook):
|
||||||
|
ACCOUNT = 'Expenses:Payroll:Salary'
|
||||||
|
VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [
|
||||||
|
'CA:General',
|
||||||
|
'CA:PTO',
|
||||||
|
'CA:Taxes:EI',
|
||||||
|
'CA:Taxes:Income',
|
||||||
|
'CA:Taxes:PP',
|
||||||
|
'US:403b:Employee',
|
||||||
|
'US:403b:Match',
|
||||||
|
'US:General',
|
||||||
|
'US:IL:Taxes:Income',
|
||||||
|
'US:MA:Disability:PFL',
|
||||||
|
'US:MA:Disability:PML',
|
||||||
|
'US:MA:Taxes:Income',
|
||||||
|
'US:NY:Disability',
|
||||||
|
'US:NY:Disability:PFL',
|
||||||
|
'US:NY:Taxes:Income',
|
||||||
|
'US:NY:Taxes:NYC',
|
||||||
|
'US:OR:Taxes:Income',
|
||||||
|
'US:OR:Taxes:STT',
|
||||||
|
'US:PTO',
|
||||||
|
'US:Taxes:Income',
|
||||||
|
'US:Taxes:Medicare',
|
||||||
|
'US:Taxes:SocialSecurity',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class TaxHook(_PayrollTypeHook):
|
||||||
|
ACCOUNT = 'Expenses:Payroll:Taxes'
|
||||||
|
VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [
|
||||||
|
'CA:EI',
|
||||||
|
'CA:PP',
|
||||||
|
'US:IL:Unemployment',
|
||||||
|
'US:MA:Health',
|
||||||
|
'US:MA:Unemployment',
|
||||||
|
'US:MA:WorkTrain',
|
||||||
|
'US:Medicare',
|
||||||
|
'US:OR:Unemployment',
|
||||||
|
'US:SocialSecurity',
|
||||||
|
])
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ from setuptools import setup
|
||||||
setup(
|
setup(
|
||||||
name='conservancy_beancount',
|
name='conservancy_beancount',
|
||||||
description="Plugin, library, and reports for reading Conservancy's books",
|
description="Plugin, library, and reports for reading Conservancy's books",
|
||||||
version='1.13.1',
|
version='1.14.0',
|
||||||
author='Software Freedom Conservancy',
|
author='Software Freedom Conservancy',
|
||||||
author_email='info@sfconservancy.org',
|
author_email='info@sfconservancy.org',
|
||||||
license='GNU AGPLv3+',
|
license='GNU AGPLv3+',
|
||||||
|
|
Loading…
Reference in a new issue