348 lines
19 KiB
Python
348 lines
19 KiB
Python
import model
|
|
from fields import *
|
|
import enums
|
|
|
|
__all__ = RECORD_TYPES = ['SubmitterRecord', 'EmployerRecord',
|
|
'EmployeeWageRecord', 'OptionalEmployeeWageRecord',
|
|
'TotalRecord', 'OptionalTotalRecord',
|
|
'StateTotalRecord', 'FinalRecord',]
|
|
|
|
class SubmitterRecord(model.Model):
|
|
record_identifier = 'RA'
|
|
required = True
|
|
|
|
submitter_ein = NumericField(max_length=9)
|
|
user_id = TextField(max_length=8)
|
|
software_vendor = TextField(max_length=4, required=False)
|
|
blank1 = BlankField(max_length=5)
|
|
resub_indictator = BooleanField(required=False)
|
|
resub_identifier = TextField(max_length=6, required=False)
|
|
software_code = StaticField(value='98') # In-house program
|
|
company_name = TextField(max_length=57)
|
|
company_address = TextField(max_length=22)
|
|
company_delivery_address = TextField(max_length=22)
|
|
company_city = TextField(max_length=22)
|
|
company_state = StateField()
|
|
company_zipcode = TextField(max_length=5)
|
|
company_zipcode_ext = TextField(max_length=4, required=False)
|
|
blank2 = BlankField(max_length=5)
|
|
company_foreign_state_province= TextField(max_length=23, required=False)
|
|
company_foreign_postal_code = TextField(max_length=15, required=False)
|
|
company_country_code = TextField(max_length=2, required=False)
|
|
submitter_name = TextField(max_length=57)
|
|
submitter_address = TextField(max_length=22)
|
|
submitter_delivery_address = TextField(max_length=22)
|
|
submitter_city = TextField(max_length=22)
|
|
submitter_state = StateField()
|
|
submitter_zipcode = TextField(max_length=5)
|
|
submitter_zipcode_ext = TextField(max_length=4, required=False)
|
|
blank3 = BlankField(max_length=5)
|
|
submitter_foreign_state_province = TextField(max_length=23, required=False)
|
|
submitter_foreign_postal_code = TextField(max_length=15, required=False)
|
|
submitter_country_code = TextField(max_length=2, required=False)
|
|
contact_name = TextField(max_length=27)
|
|
contact_phone = TextField(max_length=15)
|
|
contact_phone_ext = TextField(max_length=5, required=False)
|
|
blank4 = BlankField(max_length=3)
|
|
contact_email = EmailField(max_length=40)
|
|
blank5 = BlankField(max_length=3)
|
|
contact_fax = TextField(max_length=10, required=False)
|
|
preferred_notification = TextField(max_length=1)
|
|
preparer_code = TextField(max_length=1)
|
|
blank6 = BlankField(max_length=12)
|
|
|
|
def validate_submitter_ein(self, f):
|
|
f.value = f.value.replace('-','')
|
|
excluded_values = ('07','08','09','17','18','19','28','29','49','69', '70', '78', '79', '89')
|
|
if f.value[0:2] in excluded_values:
|
|
raise ValidationError("%s not one of %s" % (f.value, excluded_values), field=f)
|
|
try:
|
|
int(f.value)
|
|
except ValueError:
|
|
raise ValidationError("%s must be numeric values only" % f.value, field=f)
|
|
|
|
def validate_resub_identifier(self, f):
|
|
if self.resub_indicator.value == True:
|
|
if not f.value:
|
|
raise ValidationError("resub_identifier must be set because resub_indicator is True", field=f)
|
|
|
|
def validate_preferred_notification(self, f):
|
|
if self.preferred_notification.value == '1':
|
|
if not self.contact_email.value:
|
|
raise ValidationError("contact_email must be set if preferred notification method is email (1)", field=f)
|
|
|
|
def validate_preparer_code(self, f):
|
|
valid_options = ('A','L','S','P','O')
|
|
if self.preparer_code.value.upper() not in valid_options:
|
|
raise ValidationError("preparer_code %s not one of %s" % (self.preparer_code.value, valid_options), field=f)
|
|
|
|
|
|
|
|
class EmployerRecord(model.Model):
|
|
record_identifier = 'RE'
|
|
required = True
|
|
|
|
tax_year = NumericField(max_length=4)
|
|
agent_indicator = NumericField(max_length=1, required=False)
|
|
employer_ein = TextField(max_length=9)
|
|
agent_for_ein = TextField(max_length=9, required=False)
|
|
terminating_business_indicator = BooleanField()
|
|
establishment_number = TextField(max_length=4, required=False)
|
|
other_ein = TextField(max_length=9, required=False)
|
|
employer_name = TextField(max_length=57)
|
|
location_address = TextField(max_length=22)
|
|
delivery_address = TextField(max_length=22)
|
|
city = TextField(max_length=22)
|
|
state = StateField()
|
|
zipcode = TextField(max_length=5)
|
|
zipcode_ext = TextField(max_length=4, required=False)
|
|
kind_of_employer = TextField(max_length=1)
|
|
blank1 = BlankField(max_length=4)
|
|
foreign_state_province = TextField(max_length=23)
|
|
foreign_postal_code = TextField(max_length=15)
|
|
country_code = TextField(max_length=2, required=False)
|
|
employment_code = TextField(max_length=1)
|
|
tax_jurisdiction_code = TextField(max_length=1, required=False)
|
|
third_party_sick_pay = BooleanField()
|
|
blank2 = BlankField(max_length=291)
|
|
|
|
def validate_agent_indicator(self, f):
|
|
v = f.value
|
|
if v and v not in (1,2,3):
|
|
raise ValidationError("%s not in one of (1,2,3)" % v, field=f)
|
|
|
|
def validate_employer_ein(self, f):
|
|
excluded_values = ('00','07','08','09','17','18','19','28','29','49','69','70','78','79','89')
|
|
if f.value[0:2] in excluded_values:
|
|
raise ValidationError("%s not one of %s" % (f.value, excluded_values), field=f)
|
|
|
|
def validate_agent_for_ein(self, f):
|
|
if self.agent_indicator.value == 1 and not f.value:
|
|
raise ValidationError("agent_for_ein must be provided with agent_indicator=1", field=f)
|
|
|
|
def validate_kind_of_employer(self, f):
|
|
choices = [k for k,v in enums.employer_types]
|
|
if f.value.upper() not in choices:
|
|
raise ValidationError("%s not in one of %s" % (f.value, choices), field=f)
|
|
|
|
def validate_employment_code(self, f):
|
|
choices = [k for k,v in enums.employment_codes]
|
|
if f.value.upper() not in choices:
|
|
raise ValidationError("%s not in one of %s" % (f.value, choices), field=f)
|
|
|
|
def validate_tax_jurisdiction_code(self, f):
|
|
choices = [k for k,v in enums.tax_jurisdiction_codes]
|
|
if f.value and f.value.upper() not in choices:
|
|
raise ValidationError("%s not in one of %s" % (f.value, choices), field=f)
|
|
|
|
|
|
class EmployeeWageRecord(model.Model):
|
|
record_identifier = 'RW'
|
|
required = True
|
|
|
|
ssn = NumericField(max_length=9, required=False)
|
|
employee_first_name = TextField(max_length=15)
|
|
employee_middle_name = TextField(max_length=15)
|
|
employee_last_name = TextField(max_length=20)
|
|
employee_suffix = TextField(max_length=4, required=False)
|
|
location_address = TextField(max_length=22)
|
|
delivery_address = TextField(max_length=22)
|
|
city = TextField(max_length=22)
|
|
state = StateField()
|
|
zipcode = TextField(max_length=5, required=False)
|
|
zipcode_ext = TextField(max_length=4, required=False)
|
|
blank1 = BlankField(max_length=5)
|
|
foreign_state = TextField(max_length=23, required=False)
|
|
foreign_postal_code = TextField(max_length=15, required=False)
|
|
country = TextField(max_length=2)
|
|
wages_tips = MoneyField(max_length=11)
|
|
federal_income_tax_withheld = MoneyField(max_length=11)
|
|
social_security_wages = MoneyField(max_length=11)
|
|
social_security_tax_withheld = MoneyField(max_length=11)
|
|
medicare_wages_and_tips = MoneyField(max_length=11)
|
|
medicare_tax_withheld = MoneyField(max_length=11)
|
|
social_security_tips = MoneyField(max_length=11)
|
|
advance_eic = MoneyField(max_length=11)
|
|
dependent_care_benefits = MoneyField(max_length=11)
|
|
deferred_compensation_401k = MoneyField(max_length=11)
|
|
deferred_compensation_403b = MoneyField(max_length=11)
|
|
deferred_compensation_408k = MoneyField(max_length=11)
|
|
deferred_compensation_457b = MoneyField(max_length=11)
|
|
deferred_compensation_501c = MoneyField(max_length=11)
|
|
military_pay = MoneyField(max_length=11)
|
|
non_qualified_457 = MoneyField(max_length=11)
|
|
employer_contrib_to_hsa = MoneyField(max_length=11)
|
|
non_qualified_not_457 = MoneyField(max_length=11)
|
|
nontaxable_combat_pay = MoneyField(max_length=11)
|
|
blank2 = BlankField(max_length=11)
|
|
cost_of_premiums_for_insurance = MoneyField(max_length=11)
|
|
income_nonstatutory_stock_opts = MoneyField(max_length=11)
|
|
deferred_compensation_409a = MoneyField(max_length=11)
|
|
designated_roth_contrib_401k = MoneyField(max_length=11)
|
|
designated_roth_contrib_403b = MoneyField(max_length=11)
|
|
blank3 = BlankField(max_length=23)
|
|
statutory_employee_indicator = BooleanField()
|
|
blank4 = BlankField(max_length=1)
|
|
retirement_plan_indicator = BooleanField()
|
|
third_party_sick_pay = BooleanField()
|
|
blank5 = BlankField(max_length=23)
|
|
|
|
def validate_ssn(self, f):
|
|
if str(f.value).startswith('666','9'):
|
|
raise ValidationError("ssn cannot start with 666 or 9", field=f)
|
|
|
|
|
|
|
|
class OptionalEmployeeWageRecord(model.Model):
|
|
record_identifier = 'RO'
|
|
required = False
|
|
|
|
blank1 = BlankField(max_length=9)
|
|
allocated_tips = MoneyField(max_length=11)
|
|
uncollected_tax_on_tips = MoneyField(max_length=11)
|
|
medical_savings_account = MoneyField(max_length=11)
|
|
simple_retirement_account = MoneyField(max_length=11)
|
|
qualified_adoption_expenses = MoneyField(max_length=11)
|
|
uncollected_ss_life_ins = MoneyField(max_length=11)
|
|
uncollected_medicare_life_ins = MoneyField(max_length=11)
|
|
income_under_409a = MoneyField(max_length=11)
|
|
hire_exempt_wages_and_tips = MoneyField(max_length=11)
|
|
blank2 = BlankField(max_length=164)
|
|
wages_subject_to_puerto_rico_tax = MoneyField(max_length=11, required=False)
|
|
commissions_subject_to_puerto_rico_tax = MoneyField(max_length=11, required=False)
|
|
allowances_subject_to_puerto_rico_tax = MoneyField(max_length=11, required=False)
|
|
tips_subject_to_puerto_rico_tax = MoneyField(max_length=11, required=False)
|
|
total_wages_subject_to_puerto_rico_tax = MoneyField(max_length=11, required=False)
|
|
puerto_rico_tax_withheld = MoneyField(max_length=11, required=False)
|
|
retirement_fund_contrib = MoneyField(max_length=11, required=False)
|
|
blank3 = BlankField(max_length=11)
|
|
total_wages_tips_virgin_islands = MoneyField(max_length=11, required=False)
|
|
virgin_islands_income_tax_withheld = MoneyField(max_length=11, required=False)
|
|
blank4 = BlankField(max_length=128)
|
|
|
|
|
|
|
|
|
|
class StateWageRecord(model.Model):
|
|
record_identifier = 'RS'
|
|
required = False
|
|
|
|
state_code = StateField(use_numeric=True)
|
|
taxing_entity_code = TextField(max_length=5, required=False)
|
|
ssn = NumericField(max_length=9, required=False)
|
|
employee_first_name = TextField(max_length=15)
|
|
employee_middle_name = TextField(max_length=15)
|
|
employee_last_name = TextField(max_length=20)
|
|
employee_suffix = TextField(max_length=4, required=False)
|
|
location_address = TextField(max_length=22)
|
|
delivery_address = TextField(max_length=22)
|
|
city = TextField(max_length=22)
|
|
state = StateField()
|
|
zipcode = TextField(max_length=5, required=False)
|
|
zipcode_ext = TextField(max_length=4, required=False)
|
|
blank1 = BlankField(max_length=5)
|
|
foreign_state_province = TextField(max_length=23, required=False)
|
|
foreign_postal_code = TextField(max_length=15, required=False)
|
|
country_code = TextField(max_length=2, required=False)
|
|
optional_code = TextField(max_length=2, required=False)
|
|
reporting_period = MonthYearField()
|
|
quarterly_unemp_ins_wages = MoneyField(max_length=11)
|
|
quarterly_unemp_ins_taxable_wages = MoneyField(max_length=11)
|
|
number_of_weeks_worked = NumericField(max_length=2)
|
|
date_first_employed = DateField(required=False)
|
|
date_of_separation = DateField(required=False)
|
|
blank2 = BlankField(max_length=5)
|
|
state_employer_account_num = NumericField(max_length=20)
|
|
blank3 = BlankField(max_length=6)
|
|
state_code_2 = StateField(use_numeric=True)
|
|
state_taxable_wages = MoneyField(max_length=11)
|
|
state_income_tax_wh = MoneyField(max_length=11)
|
|
other_state_data = TextField(max_length=10, required=False)
|
|
tax_type_code = TextField(max_length=1) # VALIDATE C, D, E, or F
|
|
local_taxable_wages = MoneyField(max_length=11)
|
|
local_income_tax_wh = MoneyField(max_length=11)
|
|
state_control_number = NumericField(max_length=7, required=False)
|
|
supplemental_data1 = TextField(max_length=75, required=False)
|
|
supplemental_data2 = TextField(max_length=75, required=False)
|
|
blank4 = BlankField(max_length=25)
|
|
|
|
def validate_tax_type_code(self, field):
|
|
choices = [x for x,y in enums.tax_type_codes]
|
|
if field.value.upper() not in choices:
|
|
raise ValidationError("%s not one of %s" % (field.value,choices), field=f)
|
|
|
|
|
|
class TotalRecord(model.Model):
|
|
record_identifier = 'RT'
|
|
required = True
|
|
|
|
number_of_rw_records = NumericField(max_length=7)
|
|
wages_tips = NumericField(max_length=15)
|
|
federal_income_tax_withheld = NumericField(max_length=15)
|
|
social_security_wages = NumericField(max_length=15)
|
|
social_security_tax_withheld = NumericField(max_length=15)
|
|
medicare_wages_and_tips = NumericField(max_length=15)
|
|
medicare_tax_withheld = NumericField(max_length=15)
|
|
social_security_tips = NumericField(max_length=15)
|
|
advance_eic = NumericField(max_length=15)
|
|
dependent_care_benefits = NumericField(max_length=15)
|
|
deferred_compensation_401k = NumericField(max_length=15)
|
|
deferred_compensation_403b = NumericField(max_length=15)
|
|
deferred_compensation_408k = NumericField(max_length=15)
|
|
deferred_compensation_457b = NumericField(max_length=15)
|
|
deferred_compensation_501c = NumericField(max_length=15)
|
|
military_pay = NumericField(max_length=15)
|
|
non_qualified_457 = NumericField(max_length=15)
|
|
employer_contrib_to_hsa = NumericField(max_length=15)
|
|
non_qualified_not_457 = NumericField(max_length=15)
|
|
nontaxable_combat_pay = NumericField(max_length=15)
|
|
blank1 = BlankField(max_length=15)
|
|
employer_cost_term_life_ins = NumericField(max_length=15)
|
|
income_tax_wh_sick_pay = NumericField(max_length=15)
|
|
income_exercise_nonstat_stock_opts = NumericField(max_length=15)
|
|
deferred_409a_compensation_plan = NumericField(max_length=15)
|
|
designated_roth_contribs_401k = NumericField(max_length=15)
|
|
disignated_roth_contribs_403b = NumericField(max_length=15)
|
|
blank2 = BlankField(max_length=113)
|
|
|
|
|
|
class OptionalTotalRecord(model.Model):
|
|
record_identifier = 'RU'
|
|
required = False
|
|
|
|
number_of_ro_records = NumericField(max_length=7)
|
|
allocated_tips = NumericField(max_length=15)
|
|
uncollected_tax_on_tips = NumericField(max_length=15)
|
|
medical_savings_account = NumericField(max_length=15)
|
|
simple_retirement_account = NumericField(max_length=15)
|
|
qualified_adoption_expenses = NumericField(max_length=15)
|
|
uncollected_ss_life_ins = NumericField(max_length=15)
|
|
uncollected_medicare_life_ins = NumericField(max_length=15)
|
|
income_under_409a = NumericField(max_length=15)
|
|
hire_exempt_wages_and_tips = NumericField(max_length=15)
|
|
blank1 = BlankField(max_length=210)
|
|
wages_subject_to_puerto_rico_tax = NumericField(max_length=15, required=False)
|
|
commissions_subject_to_puerto_rico_tax = NumericField(max_length=15, required=False)
|
|
allowances_subject_to_puerto_rico_tax = NumericField(max_length=15, required=False)
|
|
tips_subject_to_puerto_rico_tax = NumericField(max_length=15, required=False)
|
|
total_wages_subject_to_puerto_rico_tax = NumericField(max_length=15, required=False)
|
|
puerto_rico_tax_withheld = NumericField(max_length=15, required=False)
|
|
retirement_fund_contrib = NumericField(max_length=15, required=False)
|
|
total_wages_tips_virgin_islands = NumericField(max_length=15, required=False)
|
|
virgin_islands_income_tax_withheld = NumericField(max_length=15, required=False)
|
|
blank2 = BlankField(max_length=23)
|
|
|
|
|
|
class StateTotalRecord(model.Model):
|
|
record_identifier = 'RV'
|
|
required = False
|
|
|
|
supplemental_data = TextField(max_length=510)
|
|
|
|
class FinalRecord(model.Model):
|
|
record_identifier = 'RF'
|
|
required = True
|
|
|
|
blank1 = BlankField(max_length=5)
|
|
number_of_rw_records = NumericField(max_length=9)
|
|
blank2 = BlankField(max_length=496)
|