from datetime import datetime from dateutil.relativedelta import relativedelta from app.util.datatypes.enum import BaseEnum from bson import json_util from app.auth.model import User, UserIDField from ..database import db, EmbeddedDocumentBase, DocumentBase from app.database.fields import QuarterDateField, QuarterYearField class MarriageStatus(BaseEnum): SINGLE = 'single' MARRIED = 'married' DIVORCED = 'divorced' WIDOWED = 'windowed' SEPARATED = 'separated' class OwnOrRent(BaseEnum): OWN = 'own' RENT = 'rent' class FilingTypes(BaseEnum): SINGLE = 'single' JOINT = 'joint' class Property(EmbeddedDocumentBase): original_cost = db.FloatField(required=False) home_price = db.FloatField(required=False) address1 = db.StringField(required=False) address2 = db.StringField(required=False) city = db.StringField(required=False) state = db.StringField(required=False) zip = db.StringField(required=False) number_of_units = db.IntField(required=False) funding_purpose = db.StringField(required=False, default='purchase') property_purpose = db.StringField(required=False) year_acquired = QuarterYearField(required=False) year_built = QuarterYearField(required=False) existing_liens = db.EmbeddedDocumentListField('AssetExpense', required=False) title_holders = db.StringField(required=False) tax_amount = db.FloatField(required=False) hoa_amount = db.FloatField(required=False) downpayment_source = db.StringField(required=False) property_type = db.StringField(required=False) class Job(EmbeddedDocumentBase): employer_info = db.StringField(required=False) self_employed = db.BooleanField(required=False) date_from = QuarterDateField(required=False) date_to = QuarterDateField(required=False, default=datetime.today()) monthly_income = db.FloatField(required=False) position_title = db.StringField(required=False) bus_phone = db.StringField(required=False) naics = db.StringField(required=False) def _get_date_delta_on_job(self, time_scale='years'): if self.date_to and self.date_from: date_from = QuarterDateField.make_datetime(self.date_to) date_to = QuarterDateField.make_datetime(self.date_from) return getattr(relativedelta(date_from, date_to), time_scale) return 0 @classmethod def ignore_from_json(cls): result = super().ignore_from_json() result.append('years_moths_on_job') return result @property def years_on_job(self): return self._get_date_delta_on_job('years') @property def months_on_job(self): return self._get_date_delta_on_job('months') @property def years_months_on_job(self): years = self.years_on_job extra_months = self.months_on_job return f'{years} Year(s), {extra_months} Month(s)' @classmethod def additional_fields(cls): res = super().additional_fields() res.append('years_months_on_job') return res class PrevAddress(EmbeddedDocumentBase): address1 = db.StringField(required=False) address2 = db.StringField(required=False) city = db.StringField(required=False) state = db.StringField(required=False) zip = db.StringField(required=False) own_or_rent = db.EnumField(OwnOrRent, required=False) years = db.IntField(required=False) class AssetBase(EmbeddedDocumentBase): meta = {'allow_inheritance': True} value = db.FloatField(required=False, default=0) class AssetExpense(AssetBase): meta = {'allow_inheritance': True} description = db.StringField(required=False, default='') class CheckingSavings(AssetBase): bank_sl_cu = db.StringField(required=False) acct_number = db.StringField(required=False) class LifeInsurance(AssetBase): face_amount = db.FloatField(required=False, default=None) class Expense(EmbeddedDocumentBase): base_emp_inc = db.FloatField(required=False) over_time = db.FloatField(required=False) bonuses = db.FloatField(required=False) commissions = db.FloatField(required=False) dividends_interest = db.FloatField(required=False) net_rental_income = db.FloatField(required=False) other = db.EmbeddedDocumentField('AssetExpense', required=False) class ScheduleOfRealEstate(EmbeddedDocumentBase): address1 = db.StringField(required=False) address2 = db.StringField(required=False) city = db.StringField(required=False) state = db.StringField(required=False) zip = db.StringField(required=False) status = db.StringField(required=False) type = db.StringField(required=False) present_market_value = db.FloatField(required=False) amount_of_mortgages = db.FloatField(required=False) gross_rental_income = db.FloatField(required=False) mortgage_payments = db.FloatField(required=False) insurance_main_taxes_misc = db.FloatField(required=False) net_rental_income = db.FloatField(required=False) class Declarations(EmbeddedDocumentBase): any_judgements = db.BooleanField(required=False) declared_bankruptcy = db.BooleanField(required=False) property_foreclosed = db.BooleanField(required=False) party_to_lawsuit = db.BooleanField(required=False) obligated_loan_foreclosure = db.BooleanField(required=False) delinquent_or_default = db.BooleanField(required=False) alimony_child_support_maintenance = db.BooleanField(required=False) down_payment_borrowed = db.BooleanField(required=False) comaker_or_endorser = db.BooleanField(required=False) intend_primary_residence = db.BooleanField(Required=False) class AcknowledgeAgree(EmbeddedDocumentBase): signature = db.StringField(required=False) date = QuarterDateField(required=False) class GovernmentInfo(EmbeddedDocumentBase): will_not_furnish = db.BooleanField(required=False) ethnicity = db.BooleanField(required=False) sex = db.StringField(required=False) race = db.StringField(required=False) class GeneralAssets(AssetExpense): deposit_held_by = db.StringField(required=False, default='') class Assets(EmbeddedDocumentBase): assets = db.EmbeddedDocumentListField('GeneralAssets', required=False, default=[GeneralAssets()]) checking_savings = db.EmbeddedDocumentListField('CheckingSavings', required=False, default=[]) stocks_bonds = db.EmbeddedDocumentListField('AssetExpense', required=False, default=[]) life_insurance = db.EmbeddedDocumentListField('LifeInsurance', required=False, default=[]) retirement_funds = db.EmbeddedDocumentListField('AssetExpense', required=False, default=[]) vehicles_owned = db.EmbeddedDocumentListField('AssetExpense', required=False, default=[]) property_owned = db.EmbeddedDocumentListField('ScheduleOfRealEstate', required=False, default=[]) owned_real_estate_value = db.FloatField(required=False, default=None) vested_interest_retirement_fund = db.FloatField(required=False, default=None) net_worth_bus_owned = db.FloatField(required=False, default=None) autos_owned_value = db.FloatField(required=False, default=None) other_assets = db.StringField(required=False, default='') class Applicant(EmbeddedDocumentBase): def __init__(self, *args, **kwargs): user = None if 'email' in kwargs: user = User.objects(email=kwargs['email']).first() elif 'user_id' in kwargs: user = User.objects(user_id=kwargs['user_id']).first() if user: kwargs['user'] = user kwargs['user_id'] = user.user_id user.date_of_birth = kwargs.get('date_of_birth') or user.date_of_birth user.first_name = kwargs.get('first_name') or user.first_name user.middle_init_or_name = kwargs.get('middle_init_or_name') or user.middle_init_or_name user.last_name = kwargs.get('last_name') or user.last_name user.address1 = kwargs.get('address1') or user.address1 user.address2 = kwargs.get('address2') or user.address2 user.city = kwargs.get('city') or user.city user.state = kwargs.get('state') or user.state user.zip = kwargs.get('zip') or user.zip user.phone_number = kwargs.get('phone_number') or user.phone_number user.save() if 'user' in kwargs: kwargs['email'] = kwargs['user'].email kwargs['first_name'] = kwargs['user'].first_name kwargs['middle_init_or_name'] = kwargs['user'].middle_init_or_name kwargs['last_name'] = kwargs['user'].last_name kwargs['address1'] = kwargs['user'].address1 kwargs['address2'] = kwargs['user'].address2 kwargs['city'] = kwargs['user'].city kwargs['state'] = kwargs['user'].state kwargs['zip'] = kwargs['user'].zip kwargs['phone_number'] = kwargs['user'].phone_number kwargs['date_of_birth'] = kwargs['user'].date_of_birth kwargs.pop('user') super().__init__(*args, **kwargs) user = db.ReferenceField('User', required=False) user_id = UserIDField(required=False) # these properties will be loaded from the user if there is one, if there isn't one, they will be saved here email = db.StringField(required=False) first_name = db.StringField(required=False) middle_init_or_name = db.StringField(required=False, db_field='middle_initial') last_name = db.StringField(required=False) address1 = db.StringField(required=False) address2 = db.StringField(required=False) city = db.StringField(required=False) state = db.StringField(required=False) zip = db.StringField(required=False) date_of_birth = QuarterDateField(required=False) phone_number = db.StringField(required=False, db_field='home_phone') # the applicant specific fields role = db.StringField(required=False) pin = db.StringField(required=False) social_security_number = db.StringField(required=False) years_school = db.IntField(required=False) degree_earned = db.StringField(required=False) school_name = db.StringField(required=False) marriage_status = db.EnumField(MarriageStatus, required=False, default=MarriageStatus.SINGLE) number_dependents = db.IntField(required=False, default=0) ages_dependents = db.ListField(db.IntField(required=False)) previous_jobs = db.EmbeddedDocumentListField('Job', required=False) previous_addresses = db.EmbeddedDocumentListField('PrevAddress', required=False) expense_info = db.EmbeddedDocumentField('Expense', required=False) other_incomes = db.EmbeddedDocumentListField('AssetExpense', required=False) assets = db.EmbeddedDocumentField('Assets', required=False, default=Assets()) declarations = db.EmbeddedDocumentField('Declarations', required=False) liabilities = db.EmbeddedDocumentListField('AssetExpense', required=False) acknowledge_and_agree = db.EmbeddedDocumentField('AcknowledgeAgree', required=False) auth_borrower = db.EmbeddedDocumentField('AcknowledgeAgree', required=False) auth_fcra = db.EmbeddedDocumentField('AcknowledgeAgree', required=False) government_info = db.EmbeddedDocumentField('GovernmentInfo') @classmethod def ignore_to_json(cls): result = super().ignore_to_json() result.append('user') result.append('user_id') return result @classmethod def ignore_from_json(cls): result = super().ignore_from_json() result.append('user_name') return result class Application(DocumentBase): filing_type = db.EnumField(FilingTypes, required=False, default=FilingTypes.SINGLE) user_id = UserIDField(required=True) applicants = db.EmbeddedDocumentListField('Applicant', required=True) deposit_held_by = db.StringField(required=False) property_info = db.EmbeddedDocumentField('Property', required=False) finalized = db.BooleanField(required=True, default=False) def to_json(self, *args, **kwargs): use_db_field = kwargs.pop('use_db_field', True) result = super().to_mongo(use_db_field=use_db_field) for applicant in result.get('applicants', [{}]): applicant.pop('user', None) return json_util.dumps(result, *args, **kwargs)