Changeset - 7c18bc221f5f
[Not reviewed]
0 3 0
Brett Smith - 3 years ago 2020-12-23 22:27:30
brettcsmith@brettcsmith.org
meta_payroll_type: Refactor for more code reuse.
3 files changed with 79 insertions and 44 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/plugin/__init__.py
Show inline comments
...
 
@@ -67,7 +67,12 @@ class HookRegistry:
 
        '.meta_repo_links': None,
 
        '.meta_rt_links': ['MetaRTLinks'],
 
        '.meta_tax_implication': None,
 
        '.meta_payroll_type': None,
 
        '.meta_payroll_type': [
 
            'HealthInsuranceHook',
 
            'OtherBenefitsHook',
 
            'SalaryHook',
 
            'TaxHook',
 
        ],
 
        '.txn_date': ['TransactionDate'],
 
    }
 

	
conservancy_beancount/plugin/meta_payroll_type.py
Show inline comments
...
 
@@ -14,56 +14,86 @@
 
# 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/>.
 

	
 
from . import core
 
import datetime
 

	
 
from . import core
 
from .. import ranges
 
from .. import data
 
from .. import errors as errormod
 

	
 
from ..beancount_types import (
 
    Transaction,
 
)
 

	
 
class MetaPayrollType(core._PostingHook):
 
    """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
 
       Expenses:Payroll:Benefits:Other.
 
       Valid values for payroll-type are listed in the
 
       _SALARY_TYPES, _TAX_TYPES, _HEALTH_INSURANCE_TYPES, and _OTHER_BENEFIT_TYPES
 
       (respectively) in the class.
 
    """
 
    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)
 
METADATA_KEY = 'payroll-type'
 

	
 
class _PayrollTypeHook(core._NormalizePostingMetadataHook):
 
    ACCOUNT: str
 
    VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [])
 
    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:
 
        if post.account.is_under('Expenses:Payroll:Salary') or post.account.is_under('Expenses:Payroll:Taxes') or \
 
            post.account.is_under('Expenses:Payroll:Benefits:Other') or post.account.is_under('Expenses:Payroll:Benefits:HealthInsurance'):
 
            return True
 
        else:
 
            return False
 
        return post.account.is_under(self.ACCOUNT) is not None
 

	
 

	
 
class HealthInsuranceHook(_PayrollTypeHook):
 
    ACCOUNT = 'Expenses:Payroll:Benefits:HealthInsurance'
 
    VALUES_ENUM = core.MetadataEnum(METADATA_KEY, [
 
        'US:HRA:Fees',
 
        'US:HRA:Usage',
 
        'US:Premium:DentalVision',
 
        'US:Premium:Main',
 
    ])
 

	
 

	
 
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',
 
    ])
 

	
 

	
 
    def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter:
 
        value = post.meta.get(self.METADATA_KEY)
 
        if value is None or \
 
           (post.account.is_under('Expenses:Payroll:Salary') and (not value in self._SALARY_TYPES)) or \
 
           (post.account.is_under('Expenses:Payroll:Taxes') and (not value in self._TAX_TYPES)) or \
 
           (post.account.is_under('Expenses:Payroll:Benefits:HealthInsurance') and \
 
            (not value in self._HEALTH_INSURANCE_TYPES)) or \
 
           (post.account.is_under('Expenses:Payroll:Benefits:Other') and \
 
            (not value in self._OTHER_BENEFIT_TYPES)):
 
            yield errormod.InvalidMetadataError(txn, self.METADATA_KEY, value, post)
 
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',
 
    ])
setup.py
Show inline comments
...
 
@@ -5,7 +5,7 @@ from setuptools import setup
 
setup(
 
    name='conservancy_beancount',
 
    description="Plugin, library, and reports for reading Conservancy's books",
 
    version='1.13.1',
 
    version='1.14.0',
 
    author='Software Freedom Conservancy',
 
    author_email='info@sfconservancy.org',
 
    license='GNU AGPLv3+',
0 comments (0 inline, 0 general)