def test_calculate_portfolio_complete(self): # tickers for testing portfolio calculations in goals endpoint # otherwise, No valid instruments found TickerFactory.create(symbol='IAGG', asset_class=self.bonds_asset_class) TickerFactory.create(symbol='ITOT', asset_class=self.stocks_asset_class) TickerFactory.create(symbol='IPO') fund = TickerFactory.create(symbol='rest') self.portfolio_set.asset_classes.add(fund.asset_class) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) account = ClientAccountFactory.create(primary_owner=Fixture1.client1()) # setup some inclusive goal settings goal_settings = GoalSettingFactory.create() # Create a risk score metric for the settings GoalMetricFactory.create(group=goal_settings.metric_group, type=GoalMetric.METRIC_TYPE_RISK_SCORE) goal = GoalFactory.create(account=account, selected_settings=goal_settings, portfolio_set=self.portfolio_set, active_settings=goal_settings) goal_settings.completion_date = timezone.now().date() - timedelta(days=365) serializer = GoalSettingSerializer(goal_settings) url = '/api/v1/goals/{}/calculate-all-portfolios?setting={}'.format(goal.id, json.dumps(serializer.data)) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.client.force_authenticate(user=Fixture1.client1().user) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_add_goal_complete(self): # tickers for testing portfolio calculations in goals endpoint # otherwise, No valid instruments found self.bonds_index = MarketIndexFactory.create() self.stocks_index = MarketIndexFactory.create() self.bonds_ticker = TickerFactory.create( asset_class=self.bonds_asset_class, benchmark=self.bonds_index) self.stocks_ticker = TickerFactory.create( asset_class=self.stocks_asset_class, benchmark=self.stocks_index) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) self.portfolio_provider = PortfolioProvider.objects.create( name='Krane', type=PORTFOLIO_PROVIDER_TYPE_KRANE) url = '/api/v1/goals' self.client.force_authenticate(user=Fixture1.client1().user) account = ClientAccountFactory.create(primary_owner=Fixture1.client1()) goal_settings = GoalSettingFactory.create() goal_metric = GoalMetricFactory.create( group=goal_settings.metric_group) ser = GoalCreateSerializer( data={ 'account': account.id, 'name': 'Zero Goal Target', 'type': GoalTypeFactory().id, 'target': 500, 'completion': timezone.now().date(), 'initial_deposit': 0, 'ethical': True, 'portfolio_provider': self.portfolio_provider.id }) self.assertEqual(ser.is_valid(), True, msg="Serializer has errors %s" % ser.errors) response = self.client.post(url, ser.data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data['selected_settings']['target'], 500) # "OnTrack" is false because the 500 deposit is still pending self.assertEqual(response.data['on_track'], False) goal = Goal.objects.get(pk=response.data['id']) goal.cash_balance += 500 goal.save() response = self.client.get('%s/%s' % (url, goal.id)) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['selected_settings']['target'], 500) self.assertEqual(response.data['on_track'], True)
def test_create_goal(self): self.bonds_index = MarketIndexFactory.create() self.stocks_index = MarketIndexFactory.create() self.bonds_asset_class = AssetClassFactory.create( investment_type=InvestmentType.Standard.BONDS.get()) self.stocks_asset_class = AssetClassFactory.create( investment_type=InvestmentType.Standard.STOCKS.get()) # Add the asset classes to the portfolio set self.portfolio_set = PortfolioSetFactory.create() self.portfolio_set.asset_classes.add(self.bonds_asset_class, self.stocks_asset_class) self.bonds_ticker = TickerFactory.create( asset_class=self.bonds_asset_class, benchmark=self.bonds_index) self.stocks_ticker = TickerFactory.create( asset_class=self.stocks_asset_class, benchmark=self.stocks_index) self.portfolio_provider = PortfolioProvider.objects.create( name='Krane', type=PORTFOLIO_PROVIDER_TYPE_KRANE) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) account = ClientAccountFactory.create(primary_owner=Fixture1.client1()) # setup some inclusive goal settings goal_settings = GoalSettingFactory.create() goal_type = GoalTypeFactory.create() url = '/api/v1/goals' data = { 'account': account.id, 'name': 'Fancy new goal', 'type': goal_type.id, 'target': 15000.0, 'completion': "2016-01-01", 'initial_deposit': 5000, 'ethical': True, 'portfolio_provider': self.portfolio_provider.id } # unauthenticated 403 response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # authenticated 200 self.client.force_authenticate(account.primary_owner.user) response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertDictEqual( response.data['portfolio_provider'], { 'id': self.portfolio_provider.id, 'name': self.portfolio_provider.name, 'type': PORTFOLIO_PROVIDER_TYPE_KRANE })
def test_calculate_portfolio(self): """ expects the setting parameter to be a json dump of the goal settings to use for the portfolio calculation """ # tickers for testing portfolio calculations in goals endpoint # otherwise, No valid instruments found TickerFactory.create(symbol='IAGG', asset_class=self.bonds_asset_class) TickerFactory.create(symbol='AGG', asset_class=self.bonds_asset_class) TickerFactory.create(symbol='ITOT', asset_class=self.stocks_asset_class) TickerFactory.create(symbol='GRFXX', asset_class=self.stocks_asset_class) TickerFactory.create(symbol='IPO') fund = TickerFactory.create(symbol='rest') self.portfolio_set.asset_classes.add(fund.asset_class) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) account = ClientAccountFactory.create(primary_owner=Fixture1.client1()) # setup some inclusive goal settings goal_settings = GoalSettingFactory.create() # Create a risk score metric for the settings GoalMetricFactory.create(group=goal_settings.metric_group, type=GoalMetric.METRIC_TYPE_RISK_SCORE) portfolio_provider = PortfolioProvider( type=constants.PORTFOLIO_PROVIDER_TYPE_KRANE) portfolio_provider.save() goal = GoalFactory.create(account=account, portfolio_provider=portfolio_provider, selected_settings=goal_settings, portfolio_set=self.portfolio_set) serializer = GoalSettingSerializer(goal_settings) url = '/api/v1/goals/{}/calculate-portfolio?setting={}'.format( goal.id, json.dumps(serializer.data)) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.client.force_authenticate(user=Fixture1.client1().user) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_calculate_portfolio_old(self): fund0 = TickerFactory.create(symbol='IAGG') fund1 = TickerFactory.create(symbol='ITOT') fund5 = TickerFactory.create(symbol='GRFXX') fund2 = TickerFactory.create(symbol='VEA') fund0 = TickerFactory.create(symbol='IPO') fund3 = TickerFactory.create(symbol='EEM') fund4 = TickerFactory.create(symbol='AGG') AssetFeatureValueFactory.create( assets=[fund1, fund2, fund3, fund4, fund5]) ps1 = PortfolioSetFactory \ .create(asset_classes=[fund1.asset_class, fund2.asset_class, fund3.asset_class, fund4.asset_class, fund5.asset_class]) # Create a settings object with a metric for a feature with no instruments in the current portfolio set. feature = AssetFeatureValueFactory.create() settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create(group=settings.metric_group) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MAXIMUM, configured_val=.3) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # The below fund has the desired feature, but is not in the goal's portfolio set. feature.assets.add(fund1) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the prediction # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() idata = build_instruments(data_provider) result = calculate_portfolio_old(settings=settings, data_provider=data_provider, execution_provider=execution_provider, idata=idata) self.assertTrue(True)
def test_calculate_portfolio(self): # TODO # constraints -> limit them -> maximum minimum value of 5%, maximum max value of 95% asset_class1 = AssetClassFactory.create(name='US_TOTAL_BOND_MARKET') asset_class2 = AssetClassFactory.create(name='HEDGE_FUNDS') fund0 = TickerFactory.create(symbol='IAGG', asset_class=asset_class1) fund0 = TickerFactory.create(symbol='GRFXX', asset_class=asset_class1) fund1 = TickerFactory.create(symbol='ITOT', asset_class=asset_class2) fund0 = TickerFactory.create(symbol='IPO') fund0 = TickerFactory.create(symbol='AGG', asset_class=asset_class1) fund6 = TickerFactory.create(symbol='rest') ps1 = PortfolioSetFactory \ .create(asset_classes=[asset_class1, asset_class2, fund6.asset_class]) feature = AssetFeatureValueFactory.create() feature.assets.add(fund6) settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_RISK_SCORE) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MINIMUM, configured_val=0.5) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() idata = build_instruments(data_provider) result = calculate_portfolio(settings=settings, data_provider=data_provider, execution_provider=execution_provider, idata=idata) self.assertTrue(True)
def test_add_goal_0_target(self): # tickers for testing portfolio calculations in goals endpoint # otherwise, No valid instruments found self.bonds_index = MarketIndexFactory.create() self.stocks_index = MarketIndexFactory.create() self.bonds_ticker = TickerFactory.create(asset_class=self.bonds_asset_class, benchmark=self.bonds_index) self.stocks_ticker = TickerFactory.create(asset_class=self.stocks_asset_class, benchmark=self.stocks_index) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) url = '/api/v1/goals' self.client.force_authenticate(user=Fixture1.client1().user) account = ClientAccountFactory.create(primary_owner=Fixture1.client1()) goal_settings = GoalSettingFactory.create() goal_metric = GoalMetricFactory.create(group=goal_settings.metric_group) ser = GoalCreateSerializer(data={ 'account': account.id, 'name': 'Zero Goal Target', 'type': GoalTypeFactory().id, 'target': 0, 'completion': timezone.now().date() + timedelta(days=7), 'initial_deposit': 0, 'ethical': True, }) self.assertEqual(ser.is_valid(), True, msg="Serializer has errors %s"%ser.errors) response = self.client.post(url, ser.data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data['selected_settings']['target'], 0) self.assertEqual(response.data['on_track'], True)
def test_calc_opt_inputs_no_assets_for_constraint(self): """ Makes sure when we have no assets filling a constraint, we behave appropriately. """ # This fund has a different feature to the one in the mix metric, but it is in the correct portfolio set. fund1 = TickerFactory.create() AssetFeatureValueFactory.create(assets=[fund1]) ps1 = PortfolioSetFactory.create(asset_classes=[fund1.asset_class]) # Create a settings object with a metric for a feature with no instruments in the current portfolio set. feature = AssetFeatureValueFactory.create() settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create(group=settings.metric_group) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MAXIMUM, configured_val=.3) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # The below fund has the desired feature, but is not in the goal's portfolio set. fund2 = TickerFactory.create() feature.assets.add(fund2) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the prediction # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() idata = build_instruments(data_provider) execution_provider = ExecutionProviderDjango() # Get the opt inputs, there should be no constraint for the max for the feature with no funds. result = calc_opt_inputs(settings=settings, idata=idata, data_provider=data_provider, execution_provider=execution_provider) xs, lam, constraints, settings_instruments, settings_symbol_ixs, lcovars = result self.assertEqual(len(constraints), 3) # All positive, and sum to 1 # Then create a fund in the portfolio I want. We should get a constraint for the maximum for the feature. fund3 = TickerFactory.create(asset_class=fund1.asset_class) feature.assets.add(fund3) delete_data() populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) idata = build_instruments(data_provider) result = calc_opt_inputs(settings=settings, idata=idata, data_provider=data_provider, execution_provider=execution_provider) xs, lam, constraints, settings_instruments, settings_symbol_ixs, lcovars = result self.assertEqual(len(constraints), 4) # All positive, sum to 1, and the max constraint
def test_retirement_plan_calculate(self): plan = RetirementPlanFactory.create(income=100000, desired_income=81000, btc=4000, retirement_home_price=250000, paid_days=1, retirement_age=67, selected_life_expectancy=85) # some tickers for portfolio bonds_asset_class = AssetClassFactory.create( name='US_TOTAL_BOND_MARKET') stocks_asset_class = AssetClassFactory.create(name='HEDGE_FUNDS') TickerFactory.create(symbol='IAGG', asset_class=bonds_asset_class) TickerFactory.create(symbol='ITOT', asset_class=stocks_asset_class) TickerFactory.create(symbol='IPO') fund = TickerFactory.create(symbol='rest') # Add the asset classes to the advisor's default portfolio set plan.client.advisor.default_portfolio_set.asset_classes.add( bonds_asset_class, stocks_asset_class, fund.asset_class) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) populate_inflation(asof=mocked_now.date()) self.assertIsNone(plan.goal_setting) old_settings = GoalSetting.objects.all().count() old_mgroups = GoalMetricGroup.objects.all().count() old_metrics = GoalMetric.objects.all().count() url = '/api/v1/clients/{}/retirement-plans/{}/calculate'.format( plan.client.id, plan.id) self.client.force_authenticate(user=plan.client.user) # First try and calculate without a client date of birth. Make sure we get the correct 400 old_dob = plan.client.date_of_birth plan.client.date_of_birth = None plan.client.save() response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Now set the date of birth plan.client.date_of_birth = old_dob plan.client.save() # We should be ready to calculate properly response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue('portfolio' in response.data) self.assertTrue('projection' in response.data) self.assertEqual(len(response.data['projection']), 50) # Make sure the goal_setting is now populated. plan.refresh_from_db() self.assertIsNotNone(plan.goal_setting.portfolio) self.assertEqual(old_settings + 1, GoalSetting.objects.all().count()) self.assertEqual(old_mgroups + 1, GoalMetricGroup.objects.all().count()) self.assertEqual(old_metrics + 1, GoalMetric.objects.all().count()) old_id = plan.goal_setting.id # Recalculate and make sure the number of settings, metric groups and metrics in the system is the same # Also make sure the setting object is different response = self.client.get(url) plan.refresh_from_db() self.assertEqual(old_settings + 1, GoalSetting.objects.all().count()) self.assertEqual(old_mgroups + 1, GoalMetricGroup.objects.all().count()) self.assertEqual(old_metrics + 1, GoalMetric.objects.all().count()) self.assertNotEqual(old_id, plan.goal_setting.id)
def setup_performance_history(self): populate_prices(400, asof=mocked_now) populate_cycle_obs(400, asof=mocked_now) populate_cycle_prediction(asof=mocked_now)
def test_transactions_check(self): """ Create an Goal with RecurringTransaction Execute transactions_check and make sure Transactions are created for the Recurring Transactions. """ # Bring an invite key, get logged in as a new user invite = EmailInviteFactory.create(status=EmailInvite.STATUS_SENT) url = reverse('api:v1:client-user-register') data = { 'first_name': invite.first_name, 'last_name': invite.last_name, 'invite_key': invite.invite_key, 'password': '******', 'question_one': 'what is the first answer?', 'question_one_answer': 'answer one', 'question_two': 'what is the second answer?', 'question_two_answer': 'answer two', } # Accept an invitation and create a user response = self.client.post(url, data) lookup_invite = EmailInvite.objects.get(pk=invite.pk) invite_detail_url = reverse('api:v1:invite-detail', kwargs={'invite_key': invite.invite_key}) self.assertEqual(EmailInvite.STATUS_ACCEPTED, lookup_invite.status) # New user must be logged in too self.assertIn('sessionid', response.cookies) # GET: /api/v1/invites/:key # If a session is logged in, return 200 with data response = self.client.get(invite_detail_url) self.assertEqual( response.status_code, status.HTTP_200_OK, msg='/api/v1/invites/:key should be valid during invitation') self.assertEqual( response.data['invite_key'], invite.invite_key, msg='/api/v1/invites/:key should have invitation data') self.assertEqual( response.data['status'], EmailInvite.STATUS_ACCEPTED, msg='/api/v1/invites/:key should have invitation status ACCEPTED') self.assertEqual( 'onboarding_data' in response.data, True, msg='/api/v1/invites/:key should show onboarding_data to user') self.assertEqual(response.data['risk_profile_group'], self.risk_group.id) # Make sure the user now has access to the risk-profile-groups endpoint rpg_url = reverse('api:v1:settings-risk-profile-groups-list') response = self.client.get(rpg_url) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data[0]['id'], self.risk_group.id) # PUT: /api/v1/invites/:key # Submit with onboarding_data onboarding = {'onboarding_data': {'foo': 'bar'}} response = self.client.put(invite_detail_url, data=onboarding) lookup_invite = EmailInvite.objects.get(pk=invite.pk) self.assertEqual(response.status_code, status.HTTP_200_OK, msg='Onboarding must accept json objects') self.assertEqual(response.data['status'], EmailInvite.STATUS_ACCEPTED, msg='invitation status ACCEPTED') self.assertEqual(lookup_invite.onboarding_data['foo'], 'bar', msg='should save onboarding_file') # PUT: /api/v1/invites/:key # Tax transcript upload and parsing with open(os.path.join(settings.BASE_DIR, 'pdf_parsers', 'samples', 'sample_2006.pdf'), mode="rb") as tax_transcript: data = {'tax_transcript': tax_transcript} response = self.client.put(invite_detail_url, data, format='multipart') self.assertEqual( response.status_code, status.HTTP_200_OK, msg='Updating onboarding with tax_transcript PDF returns OK') self.assertNotEqual( response.data['tax_transcript_data'], None, msg='tax_transcript_data is in the response and not None') self.assertEqual(response.data['tax_transcript_data'], self.expected_tax_transcript_data, msg='Parsed tax_transcript_data matches expected') with open(os.path.join(settings.BASE_DIR, 'pdf_parsers', 'samples', 'ssa-7005-sm-si_wanda_worker_young.pdf'), mode="rb") as ss_statement: data = {'social_security_statement': ss_statement} response = self.client.put(invite_detail_url, data, format='multipart') self.assertEqual( response.status_code, status.HTTP_200_OK, msg='Updating onboarding with tax_transcript PDF returns OK') self.assertNotEqual( response.data['social_security_statement'], None, msg='social_security_statement_data is in the response and not None' ) self.assertEqual( response.data['social_security_statement_data'], self.expected_social_security_statement_data, msg='Parsed social_security_statement_data matches expected') with open(os.path.join(settings.BASE_DIR, 'pdf_parsers', 'samples', 'ssa-7005-sm-si_wanda_worker_young.pdf'), mode="rb") as ss_statement: data = {'partner_social_security_statement': ss_statement} response = self.client.put(invite_detail_url, data, format='multipart') self.assertEqual( response.status_code, status.HTTP_200_OK, msg='Updating onboarding with tax_transcript PDF returns OK') self.assertNotEqual( response.data['partner_social_security_statement'], None, msg= 'partner_social_security_statement_data is in the response and not None' ) self.assertEqual( response.data['partner_social_security_statement_data'], self.expected_social_security_statement_data, msg='Parsed partner_social_security_statement_data matches expected' ) self.assertEqual( response._headers['content-type'], ('Content-Type', 'application/json'), msg='Response content type is application/json after upload') lookup_invite = EmailInvite.objects.get(pk=invite.pk) self.assertEqual(response.data['status'], EmailInvite.STATUS_ACCEPTED, msg='invitation status ACCEPTED') # re-upload tax transcript with open(os.path.join(settings.BASE_DIR, 'pdf_parsers', 'samples', 'sample_2006.pdf'), mode="rb") as tax_transcript: data = {'tax_transcript': tax_transcript} response = self.client.put(invite_detail_url, data, format='multipart') self.assertEqual( response.status_code, status.HTTP_200_OK, msg='Updating onboarding with tax_transcript PDF returns OK') self.assertNotEqual( response.data['tax_transcript_data'], None, msg='tax_transcript_data is in the response and not None') self.assertEqual(response.data['tax_transcript_data'], self.expected_tax_transcript_data, msg='Parsed tax_transcript_data matches expected') # test stripe photo_verification upload goes through ok with open(os.path.join(settings.BASE_DIR, 'tests', 'success.png'), mode="rb") as photo_verification: data = {'photo_verification': photo_verification} response = self.client.put(invite_detail_url, data, format='multipart') self.assertEqual( response.status_code, status.HTTP_200_OK, msg='Updating onboarding with photo verification returns OK') self.assertNotEqual( response.data['photo_verification'], None, msg='photo_verification is in the response and not None') # create client and make sure tax_transcript data is carried over properly url = reverse('api:v1:client-list') address = { "address": "123 My Street\nSome City", "post_code": "112233", "region": { "name": "New South Wales", "country": "AU", "code": "NSW", } } regional_data = { 'ssn': '555-55-5555', } data = { "advisor_agreement": True, "betasmartz_agreement": True, "date_of_birth": date(2016, 9, 21), "employment_status": EMPLOYMENT_STATUS_EMMPLOYED, "gender": GENDER_MALE, "income": 1234, "politically_exposed": True, "phone_num": "+1-234-234-2342", "residential_address": address, "regional_data": json.dumps(regional_data) } response = self.client.post(url, data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) regional_data_load = json.loads(response.data['regional_data']) self.assertNotEqual(regional_data_load['tax_transcript'], None) self.assertEqual( regional_data_load['tax_transcript_data']['filing_status'], self.expected_tax_transcript_data['filing_status'], msg='Parsed tax_transcript_data filing_status parsed successfully') lookup_invite = EmailInvite.objects.get(pk=invite.pk) # create goal self.bonds_index = MarketIndexFactory.create() self.stocks_index = MarketIndexFactory.create() self.bonds_asset_class = AssetClassFactory.create( investment_type=InvestmentType.Standard.BONDS.get()) self.stocks_asset_class = AssetClassFactory.create( investment_type=InvestmentType.Standard.STOCKS.get()) # Add the asset classes to the portfolio set self.portfolio_set = PortfolioSetFactory.create() self.portfolio_set.asset_classes.add(self.bonds_asset_class, self.stocks_asset_class) self.bonds_ticker = TickerFactory.create( asset_class=self.bonds_asset_class, benchmark=self.bonds_index) self.stocks_ticker = TickerFactory.create( asset_class=self.stocks_asset_class, benchmark=self.stocks_index) # Set the markowitz bounds for today self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the optimisation # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) account = ClientAccount.objects.get( primary_owner=lookup_invite.user.client) # setup some inclusive goal settings goal_settings = GoalSettingFactory.create() goal = GoalFactory.create(selected_settings=goal_settings) # plaid user with access_token needed for deposits plaid_user = PlaidUserFactory.create(user=account.primary_owner.user) resp = create_public_token() plaid_user.access_token = resp['access_token'] plaid_user.save() accounts = get_accounts(plaid_user.user) tx1 = self.rt = RecurringTransactionFactory.create( setting=goal_settings, begin_date=timezone.now().date(), amount=10, growth=0.0005, schedule='RRULE:FREQ=DAILY;INTERVAL=1', account_id=accounts[0]['account_id'], enabled=True, ) lookup_transactions = Transaction.objects.all() self.assertEqual(len(lookup_transactions), 0) tx1.setting.goal.approve_selected() execute_recurring_transactions_today() lookup_transactions = Transaction.objects.all() self.assertEqual(len(lookup_transactions), 1) trans = Transaction.objects.first() self.assertEqual(trans.to_goal.state, Goal.State.ACTIVE.value) self.assertEqual(trans.status, Transaction.STATUS_PENDING)