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)