def setUp(self): vendor_code = self.intervention.agreement.partner.vendor_number self.fr_1 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_2 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_3 = FundsReservationHeaderFactory(intervention=None, currency="RON")
def test_attachment(self): """If Total actual amount > 100,000 need attachment with type Final Partnership Review """ file_type = self.file_parnership_file_type InterventionAttachmentFactory( intervention=self.intervention, type=file_type ) frs = FundsReservationHeaderFactory( intervention=self.intervention, total_amt=0.00, total_amt_local=120000.00, actual_amt_local=120000.00, actual_amt=0, outstanding_amt_local=0.00, outstanding_amt=0.00, intervention_amt=0.00, ) self.assertTrue(transition_to_closed(self.intervention)) self.expected["total_actual_amt"] = 120000.00 self.expected["total_frs_amt"] = 120000.00 self.expected["earliest_start_date"] = frs.start_date self.expected["latest_end_date"] = frs.end_date self.assertFundamentals(self.intervention.total_frs)
def test_attachment_invalid(self): """If Total actual amount > 100,000 need attachment with type Final Partnership Review """ frs = FundsReservationHeaderFactory( intervention=self.intervention, total_amt=0.00, total_amt_local=120000.00, actual_amt_local=120000.00, actual_amt=120000.00, outstanding_amt_local=0.00, outstanding_amt=0.00, intervention_amt=0.00, ) with self.assertRaisesRegexp( TransitionError, 'Total amount transferred greater than 100,000 and no ' 'Final Partnership Review was attached'): transition_to_closed(self.intervention) self.expected["total_actual_amt"] = 120000.00 self.expected["total_actual_amt_usd"] = 120000.00 self.expected["total_frs_amt"] = 120000.00 self.expected["earliest_start_date"] = frs.start_date self.expected["latest_end_date"] = frs.end_date self.assertFundamentals(self.intervention.total_frs)
def test_donors_many_filter(self): """Check that filtering on multiple donors returns expected result""" donor_1 = DonorFactory() donor_2 = DonorFactory() grant_number_1 = "G123" grant_number_2 = "G124" GrantFactory( donor=donor_1, name=grant_number_1, ) GrantFactory( donor=donor_2, name=grant_number_2, ) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number_1) FundsReservationItemFactory(fund_reservation=self.fr_2, grant_number=grant_number_2) FundsReservationHeaderFactory() data = { "values": ",".join([self.fr_1.fr_number, self.fr_2.fr_number]), "donors": ",".join([str(donor_1.pk), str(donor_2.pk)]), } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2)
def test_api_partners_retreive_same_fr_amounts(self): self.intervention.status = Intervention.ACTIVE self.intervention.save() fr_header_1 = FundsReservationHeaderFactory( intervention=self.intervention, total_amt=Decimal("300.00"), actual_amt=Decimal("250.00"), outstanding_amt=Decimal("200.00"), total_amt_local=Decimal("100.00"), actual_amt_local=Decimal("50.00"), outstanding_amt_local=Decimal("20.00"), intervention_amt=Decimal("10.00"), ) fr_header_2 = FundsReservationHeaderFactory( intervention=self.intervention, total_amt=Decimal("300.00"), actual_amt=Decimal("250.00"), outstanding_amt=Decimal("200.00"), total_amt_local=Decimal("100.00"), actual_amt_local=Decimal("50.00"), outstanding_amt_local=Decimal("20.00"), intervention_amt=Decimal("10.00"), ) response = self.forced_auth_req( 'get', reverse('partners_api:partner-detail', args=[self.partner.pk]), user=self.unicef_staff, ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( Decimal(response.data["interventions"][0]["actual_amount"]), Decimal(fr_header_1.actual_amt_local + fr_header_2.actual_amt_local)) self.assertEqual( Decimal(response.data["interventions"][0]["frs_total_frs_amt"]), Decimal(fr_header_1.total_amt_local + fr_header_2.total_amt_local)) self.assertEqual( Decimal(response.data["interventions"][0] ["frs_total_intervention_amt"]), Decimal(fr_header_1.intervention_amt + fr_header_2.intervention_amt)) self.assertEqual( Decimal(response.data["interventions"][0] ["frs_total_outstanding_amt"]), Decimal(fr_header_1.outstanding_amt_local + fr_header_2.outstanding_amt_local))
def test_dates(self): """Ensure earliest and latest dates set correctly""" FundsReservationHeaderFactory( intervention=self.intervention, fr_number=1, total_amt=0.00, total_amt_local=100.00, start_date=datetime.date(2001, 1, 1), end_date=datetime.date(2001, 2, 1), actual_amt=0.00, actual_amt_local=100.00, intervention_amt=0.00, outstanding_amt_local=0.00, outstanding_amt=0.00, ) FundsReservationHeaderFactory( intervention=self.intervention, fr_number=2, total_amt=0.00, total_amt_local=100.00, start_date=datetime.date(2000, 1, 1), end_date=datetime.date(2000, 2, 1), actual_amt=0.00, actual_amt_local=100.00, intervention_amt=0.00, outstanding_amt_local=0.00, outstanding_amt=0.00, ) FundsReservationHeaderFactory( intervention=self.intervention, fr_number=3, total_amt=0.00, total_amt_local=100.00, start_date=datetime.date(2002, 1, 1), end_date=datetime.date(2002, 2, 1), actual_amt_local=100.00, actual_amt=0.00, intervention_amt=0.00, outstanding_amt_local=0.00, outstanding_amt=0.00, ) self.assertTrue(transition_to_closed(self.intervention)) self.expected["earliest_start_date"] = datetime.date(2000, 1, 1) self.expected["latest_end_date"] = datetime.date(2002, 2, 1) self.expected["total_actual_amt"] = 300.00 self.expected["total_frs_amt"] = 300.00 self.assertFundamentals(self.intervention.total_frs)
def test_api_partners_retreive_actual_fr_amounts(self): self.intervention.status = Intervention.ACTIVE self.intervention.save() fr_header_1 = FundsReservationHeaderFactory( intervention=self.intervention) fr_header_2 = FundsReservationHeaderFactory( intervention=self.intervention) response = self.forced_auth_req( 'get', reverse('partners_api:partner-detail', args=[self.partner.pk]), user=self.unicef_staff, ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( Decimal(response.data["interventions"][0]["actual_amount"]), Decimal(fr_header_1.actual_amt_local + fr_header_2.actual_amt_local))
def test_send_not_signed(self): intervention = InterventionFactory( status=Intervention.DRAFT, start=datetime.date.today() - datetime.timedelta(days=2), ) FundsReservationHeaderFactory(intervention=intervention) mock_send = Mock() with patch(self.send_path, mock_send): utils.send_intervention_past_start_notification() self.assertEqual(mock_send.call_count, 0)
def test_task(self): send_path = "etools.applications.partners.utils.send_notification_with_template" intervention = InterventionFactory( status=Intervention.SIGNED, start=datetime.date.today() - datetime.timedelta(days=2), ) FundsReservationHeaderFactory(intervention=intervention) mock_send = Mock() with patch(send_path, mock_send): call_command("send_intervention_past_start_notification") self.assertEqual(mock_send.call_count, 1)
def test_get_fail_with_intervention_id(self): other_intervention = InterventionFactory() fth_value = 'im a bad value' FundsReservationHeaderFactory(fr_number=fth_value, intervention=other_intervention, currency="USD") data = { 'values': ','.join([fth_value, self.fr_1.fr_number]), 'intervention': self.intervention.pk } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( result['error'], 'FR #{} is already being used by PD/SSFA ref [{}]'.format( fth_value, other_intervention))
def test_update(self): user = UserFactory() intervention = InterventionFactory() obj_dict = utils.create_dict_with_relations(intervention) fr = FundsReservationHeaderFactory(intervention=intervention) activity = utils.create_snapshot(intervention, obj_dict, user) self.assertEqual(activity.target, intervention) self.assertEqual(activity.action, activity.UPDATE) self.assertEqual(activity.by_user, user) self.assertEqual(activity.data["title"], intervention.title) self.assertEqual(activity.change, { "frs": { "before": [], "after": [fr.pk] } })
def test_total_amounts_valid(self): """Total amounts must equal and total outstanding must be zero""" frs = FundsReservationHeaderFactory(intervention=self.intervention, total_amt=0.00, total_amt_local=10.00, intervention_amt=0.00, actual_amt=0.00, actual_amt_local=10.00, outstanding_amt=0.00, outstanding_amt_local=0.00) self.assertTrue(transition_to_closed(self.intervention)) self.expected["total_frs_amt"] = 10.00 self.expected["total_actual_amt"] = 10.00 self.expected["earliest_start_date"] = frs.start_date self.expected["latest_end_date"] = frs.end_date self.assertFundamentals(self.intervention.total_frs)
def test_total_frs_amount(self): """Ensure total_frs_amt set correctly""" frs = FundsReservationHeaderFactory( intervention=self.intervention, total_amt=0.00, total_amt_local=100.00, actual_amt=0.00, actual_amt_local=100.00, intervention_amt=0.00, outstanding_amt=0.00, outstanding_amt_local=0.00, ) self.assertTrue(transition_to_closed(self.intervention)) self.expected["total_frs_amt"] = 100.00 self.expected["total_actual_amt"] = 100.00 self.expected["earliest_start_date"] = frs.start_date self.expected["latest_end_date"] = frs.end_date self.assertFundamentals(self.intervention.total_frs)
def test_total_amounts_not_equal(self): """Total amounts must equal and total outstanding must be zero""" frs = FundsReservationHeaderFactory(intervention=self.intervention, total_amt=0.00, total_amt_local=0.00, intervention_amt=10.00, actual_amt_local=20.00, actual_amt=0.00, outstanding_amt_local=0.00, outstanding_amt=0.00) with self.assertRaisesRegexp( TransitionError, 'Total FR amount needs to equal total actual amount, and ' 'Total Outstanding DCTs need to equal to 0'): transition_to_closed(self.intervention) self.expected["total_intervention_amt"] = 10.00 self.expected["total_actual_amt"] = 20.00 self.expected["earliest_start_date"] = frs.start_date self.expected["latest_end_date"] = frs.end_date self.assertFundamentals(self.intervention.total_frs)
def test_make_intervention_status_automatic_transitions_with_valid_interventions( self, MockInterventionValid, mock_db_connection, mock_logger): '''Exercise _make_intervention_status_automatic_transitions() when all interventions are valid''' # Make some interventions that are active that ended yesterday. (The task looks for such interventions.) end_date = datetime.date.today() - datetime.timedelta(days=1) # Interventions sort by oldest last, so I make sure my list here is ordered in the same way as they'll be # pulled out of the database. interventions = [ InterventionFactory(status=Intervention.ACTIVE, end=end_date, created=_make_past_datetime(i)) for i in range(3) ] # Make an intervention with some associated funds reservation headers that the task should find. intervention = InterventionFactory(status=Intervention.ENDED) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i), total_amt=_make_decimal(i)) interventions.append(intervention) # Create a few items that should be ignored. If they're not ignored, this test will fail. # Ignored because of end date InterventionFactory(status=Intervention.ACTIVE, end=datetime.date.today() + datetime.timedelta(days=2)) # Ignored because of status InterventionFactory(status=Intervention.IMPLEMENTED, end=end_date) # Ignored because funds total outstanding != 0 intervention = InterventionFactory(status=Intervention.ENDED, end=end_date) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(i), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i), total_amt=_make_decimal(i)) # Ignored because funds totals don't match intervention = InterventionFactory(status=Intervention.ENDED, end=end_date) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i + 1), total_amt=_make_decimal(i)) # Mock InterventionValid() to always return True. mock_validator = mock.Mock(spec=['is_valid']) mock_validator.is_valid = True MockInterventionValid.return_value = mock_validator # I'm done mocking, it's time to call the function. etools.applications.partners.tasks._make_intervention_status_automatic_transitions( self.country_name) expected_call_args = [((intervention_, ), { 'user': self.admin_user, 'disable_rigid_check': True }) for intervention_ in interventions] self._assertCalls(MockInterventionValid, expected_call_args) # Verify logged messages. expected_call_args = [ (('Starting intervention auto status transition for country {}'. format(self.country_name), ), {}), (('Total interventions 4', ), {}), (('Transitioned interventions 0 ', ), {}) ] self._assertCalls(mock_logger.info, expected_call_args) expected_call_args = [ (('Bad interventions 0', ), {}), (('Bad interventions ids: ', ), {}), ] self._assertCalls(mock_logger.error, expected_call_args)
class TestFRHeaderView(BaseTenantTestCase): @classmethod def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) partner = PartnerFactory(vendor_number="PVN") agreement = AgreementFactory(partner=partner) cls.intervention = InterventionFactory(agreement=agreement) def setUp(self): vendor_code = self.intervention.agreement.partner.vendor_number self.fr_1 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_2 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_3 = FundsReservationHeaderFactory(intervention=None, currency="RON") def run_request(self, data): response = self.forced_auth_req( 'get', reverse('funds:frs'), user=self.unicef_staff, data=data ) return response.status_code, json.loads(response.rendered_content) def test_get_one_fr(self): data = {'values': self.fr_1.fr_number} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) self.assertEqual(result['total_actual_amt'], float(self.fr_1.actual_amt_local)) self.assertEqual(result['total_outstanding_amt'], float(self.fr_1.outstanding_amt_local)) self.assertEqual(result['total_frs_amt'], float(self.fr_1.total_amt_local)) self.assertEqual(result['total_intervention_amt'], float(self.fr_1.intervention_amt)) def test_get_two_frs(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) # Make sure result numbers match up # float the Decimal sum self.assertEqual(result['total_actual_amt'], float(sum([self.fr_1.actual_amt_local, self.fr_2.actual_amt_local]))) self.assertEqual(result['total_outstanding_amt'], float(sum([self.fr_1.outstanding_amt_local, self.fr_2.outstanding_amt_local]))) self.assertEqual(result['total_frs_amt'], float(sum([self.fr_1.total_amt_local, self.fr_2.total_amt_local]))) self.assertEqual(result['total_intervention_amt'], float(sum([self.fr_1.intervention_amt, self.fr_2.intervention_amt]))) def test_get_earliest_start_date_from_two_frs(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) self.assertEqual(datetime.strptime(result['earliest_start_date'], '%Y-%m-%d').date(), min([self.fr_1.start_date, self.fr_2.start_date])) self.assertEqual(datetime.strptime(result['latest_end_date'], '%Y-%m-%d').date(), max([self.fr_1.end_date, self.fr_2.end_date])) def test_get_earliest_start_date_from_one_fr(self): data = {'values': ','.join([self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) self.assertEqual(datetime.strptime(result['earliest_start_date'], '%Y-%m-%d').date(), self.fr_1.start_date) self.assertEqual(datetime.strptime(result['latest_end_date'], '%Y-%m-%d').date(), self.fr_1.end_date) def test_get_fail_with_no_values(self): data = {} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(result['error'], 'Values are required') def test_get_fail_with_nonexistant_values(self): data = {'values': ','.join(['im a bad value', 'another bad value'])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(result['error'], 'The FR another bad value, im a bad value could not be found on eTools') def test_get_fail_with_intervention_id(self): other_intervention = InterventionFactory() fth_value = 'im a bad value' FundsReservationHeaderFactory(fr_number=fth_value, intervention=other_intervention, currency="USD") data = {'values': ','.join([fth_value, self.fr_1.fr_number]), 'intervention': self.intervention.pk} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(result['error'], 'FR #{} is already being used by PD/SSFA ref [{}]'.format(fth_value, other_intervention)) def test_get_success_with_expired_fr(self): self.fr_1.end_date = timezone.now().date() - timedelta(days=1) self.fr_1.save() data = {'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) def test_get_fail_with_intervention_fr(self): self.fr_1.intervention = self.intervention self.fr_1.save() data = {'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(result['error'], 'One or more of the FRs are used by another PD/SSFA ' 'or could not be found in eTools.') def test_get_with_intervention_fr(self): self.fr_1.intervention = self.intervention self.fr_1.save() data = {'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number]), 'intervention': self.intervention.id} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) self.assertEqual(result['total_actual_amt'], float(sum([self.fr_1.actual_amt_local, self.fr_2.actual_amt_local]))) self.assertEqual(result['total_outstanding_amt'], float(sum([self.fr_1.outstanding_amt_local, self.fr_2.outstanding_amt_local]))) self.assertEqual(result['total_frs_amt'], float(sum([self.fr_1.total_amt_local, self.fr_2.total_amt_local]))) self.assertEqual(result['total_intervention_amt'], float(sum([self.fr_1.intervention_amt, self.fr_2.intervention_amt]))) def test_grants_filter(self): """Check that filtering on grant returns expected result""" grant_number = "G123" grant = GrantFactory(name=grant_number) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number ) data = { "values": self.fr_1.fr_number, "grants": grant.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) def test_grants_many_filter(self): """Check that filtering on multiple grants returns expected result""" grant_number_1 = "G123" grant_number_2 = "G124" grant_1 = GrantFactory(name=grant_number_1) grant_2 = GrantFactory(name=grant_number_2) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number_1 ) FundsReservationItemFactory( fund_reservation=self.fr_2, grant_number=grant_number_2 ) FundsReservationHeaderFactory() data = { "values": ",".join([self.fr_1.fr_number, self.fr_2.fr_number]), "grants": ",".join([str(grant_1.pk), str(grant_2.pk)]), } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) def test_grants_filter_invalid(self): """Check that filtering on invalid grant returns 400""" grant_number = "G123" GrantFactory(name=grant_number) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number ) data = { "values": self.fr_1.fr_number, "grants": "404", } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error'] ) def test_donors_filter(self): """Check that filtering on donor returns expected result""" donor = DonorFactory() grant_number = "G123" GrantFactory( donor=donor, name=grant_number, ) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number ) data = { "values": self.fr_1.fr_number, "donors": donor.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) def test_donors_many_filter(self): """Check that filtering on multiple donors returns expected result""" donor_1 = DonorFactory() donor_2 = DonorFactory() grant_number_1 = "G123" grant_number_2 = "G124" GrantFactory( donor=donor_1, name=grant_number_1, ) GrantFactory( donor=donor_2, name=grant_number_2, ) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number_1 ) FundsReservationItemFactory( fund_reservation=self.fr_2, grant_number=grant_number_2 ) FundsReservationHeaderFactory() data = { "values": ",".join([self.fr_1.fr_number, self.fr_2.fr_number]), "donors": ",".join([str(donor_1.pk), str(donor_2.pk)]), } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) def test_donors_filter_invalid(self): """Check that filtering on invalid donors returns 400""" donor = DonorFactory() grant_number = "G123" GrantFactory( donor=donor, name=grant_number, ) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number ) data = { "values": self.fr_1.fr_number, "donors": "404", } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error'] ) def test_grant_donors_mismatch(self): """Check that filtering on donors and grant not related to donor, returns 400 """ donor = DonorFactory() GrantFactory( donor=donor, ) grant_number = "G123" grant = GrantFactory( name=grant_number, ) FundsReservationItemFactory( fund_reservation=self.fr_1, grant_number=grant_number ) data = { "values": self.fr_1.fr_number, "grants": grant.pk, "donors": donor.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error'] ) def test_frs_vendor_code_mismatch(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_3.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('FRs selected relate to various partners', result['error']) def test_frs_partner_vendor_code_mismatch(self): data = {'values': ','.join([self.fr_3.fr_number]), 'intervention': self.intervention.pk} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('vendor number of the selected implementing partner in eTools does not ' 'match the vendor number entered in the FR in VISION', result['error']) def test_frs_partner_vendor_code_ok(self): data = {'values': ','.join([self.fr_1.fr_number]), 'intervention': self.intervention.pk} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) def test_frs_currencies_match_ok(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(result['currencies_match'], True) self.assertNotEqual(result['total_intervention_amt'], 0) def test_frs_currencies_mismatch_ok(self): self.fr_2.currency = 'LBP' self.fr_2.save() data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(result['currencies_match'], False) self.assertEqual(result['total_intervention_amt'], 0)
def test_make_intervention_status_automatic_transitions_with_mixed_interventions( self, MockInterventionValid, mock_db_connection, mock_logger): '''Exercise _make_intervention_status_automatic_transitions() when only some interventions are valid, but not all of them. ''' # Make some interventions that are active that ended yesterday. (The task looks for such interventions.) end_date = datetime.date.today() - datetime.timedelta(days=1) # Interventions sort by oldest last, so I make sure my list here is ordered in the same way as they'll be # pulled out of the database. interventions = [ InterventionFactory(status=Intervention.ACTIVE, end=end_date, created=_make_past_datetime(i)) for i in range(3) ] # Make an intervention with some associated funds reservation headers that the task should find. intervention = InterventionFactory(status=Intervention.ENDED) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i), total_amt=_make_decimal(i)) interventions.append(intervention) # Create a few items that should be ignored. If they're not ignored, this test will fail. # Ignored because of end date InterventionFactory(status=Intervention.ACTIVE, end=datetime.date.today() + datetime.timedelta(days=2)) # Ignored because of status InterventionFactory(status=Intervention.IMPLEMENTED, end=end_date) # Ignored because funds total outstanding != 0 intervention = InterventionFactory(status=Intervention.ENDED, end=end_date) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(i), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i), total_amt=_make_decimal(i)) # Ignored because funds totals don't match intervention = InterventionFactory(status=Intervention.ENDED, end=end_date) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00), intervention_amt=_make_decimal(i), actual_amt=_make_decimal(i + 1), total_amt=_make_decimal(i)) def mock_intervention_valid_class_side_effect(*args, **kwargs): '''Side effect for my mock InterventionValid() that gets called each time my mock InterventionValid() class is instantiated. It gives me the opportunity to modify one of the agreements passed. ''' if args and hasattr(args[0], 'id'): if args[0].id == interventions[1].id: # We'll pretend the second intervention made a status transition args[0].status = Intervention.CLOSED args[0].save() # else: # This is a test failure; we always expect (mock) InterventionValid to be called (instantiated) with # an agreement passed as the first arg. However the args with which InterventionValid is called are # explicitly checked in this test so we don't need to react here. return mock.DEFAULT # (Mock) InterventionValid() returns a (mock) validator; set up is_valid to return False for the first # intervention and True for the others. mock_validator = mock.Mock(spec=['is_valid'], name='mock_validator') type(mock_validator).is_valid = mock.PropertyMock( side_effect=[False, True, True, True]) MockInterventionValid.side_effect = mock_intervention_valid_class_side_effect MockInterventionValid.return_value = mock_validator # I'm done mocking, it's time to call the function. etools.applications.partners.tasks._make_intervention_status_automatic_transitions( self.country_name) expected_call_args = [((intervention_, ), { 'user': self.admin_user, 'disable_rigid_check': True }) for intervention_ in interventions] self._assertCalls(MockInterventionValid, expected_call_args) # Verify logged messages. expected_call_args = [ (('Starting intervention auto status transition for country {}'. format(self.country_name), ), {}), (('Total interventions 4', ), {}), (('Transitioned interventions 1 ', ), {}) ] self._assertCalls(mock_logger.info, expected_call_args) expected_call_args = [ (('Bad interventions 1', ), {}), (('Bad interventions ids: {}'.format(interventions[0].id), ), {}), ] self._assertCalls(mock_logger.error, expected_call_args)
def setup_intervention_test_data(test_case, include_results_and_indicators=False): today = datetime.date.today() test_case.unicef_staff = UserFactory(is_staff=True) test_case.partnership_manager_user = UserFactory(is_staff=True) test_case.partnership_manager_user.groups.add(GroupFactory()) test_case.partner = PartnerFactory(name='Partner 1', vendor_number="VP1") test_case.partner1 = PartnerFactory(name='Partner 2') test_case.agreement = AgreementFactory( partner=test_case.partner, signed_by_unicef_date=datetime.date.today()) test_case.active_agreement = AgreementFactory( partner=test_case.partner1, status='active', signed_by_unicef_date=datetime.date.today(), signed_by_partner_date=datetime.date.today()) test_case.intervention = InterventionFactory(agreement=test_case.agreement, title='Intervention 1') test_case.intervention_2 = InterventionFactory( agreement=test_case.agreement, title='Intervention 2', document_type=Intervention.PD, ) test_case.active_intervention = InterventionFactory( agreement=test_case.active_agreement, title='Active Intervention', document_type=Intervention.PD, start=today - datetime.timedelta(days=1), end=today + datetime.timedelta(days=90), status='active', signed_by_unicef_date=today - datetime.timedelta(days=1), signed_by_partner_date=today - datetime.timedelta(days=1), unicef_signatory=test_case.unicef_staff, partner_authorized_officer_signatory=test_case.partner1.staff_members. all().first()) test_case.result_type = ResultType.objects.get_or_create( name=ResultType.OUTPUT)[0] test_case.result = ResultFactory(result_type=test_case.result_type) test_case.partnership_budget = InterventionBudget.objects.create( intervention=test_case.intervention, unicef_cash=10, unicef_cash_local=100, partner_contribution=20, partner_contribution_local=200, in_kind_amount_local=10, ) # set up two frs not connected to any interventions test_case.fr_1 = FundsReservationHeaderFactory(intervention=None, currency='USD') test_case.fr_2 = FundsReservationHeaderFactory(intervention=None, currency='USD') if include_results_and_indicators: # setup additional inicator/results test_case.result = ResultFactory(name='A Result') test_case.result_link = InterventionResultLink.objects.create( intervention=test_case.active_intervention, cp_output=test_case.result) test_case.lower_result = LowerResult.objects.create( result_link=test_case.result_link, name='Lower Result 1') test_case.indicator_blueprint = IndicatorBlueprint.objects.create( title='The Blueprint') test_case.applied_indicator = AppliedIndicator.objects.create( indicator=test_case.indicator_blueprint, lower_result=test_case.lower_result, ) test_case.applied_indicator.locations.add( LocationFactory(name='A Location', gateway=GatewayTypeFactory(name='A Gateway'), p_code='a-p-code')) test_case.disaggregation = test_case.applied_indicator.disaggregation.create( name='A Disaggregation') test_case.file_type_attachment = AttachmentFileTypeFactory( code="partners_intervention_attachment") test_case.file_type_prc = AttachmentFileTypeFactory( code="partners_intervention_prc_review") test_case.file_type_pd = AttachmentFileTypeFactory( code="partners_intervention_signed_pd")
def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) cls.frs = FundsReservationHeaderFactory()
def setUpTestData(cls): cls.fr_header = FundsReservationHeaderFactory(fr_number='23')
def test_funds_reservation_header(self): funds_reservation_header = FundsReservationHeaderFactory.build( fr_number='R\xe4dda Barnen') self.assertEqual(str(funds_reservation_header), 'R\xe4dda Barnen')
def test_relation(self): intervention = InterventionFactory() fr = FundsReservationHeaderFactory(intervention=intervention) obj_dict = utils.create_dict_with_relations(intervention) self.assertEqual(obj_dict["frs"], [fr.pk])
def test_notify_of_ended_interventions_with_some_interventions( self, mock_notification_model, mock_db_connection, mock_logger): '''Exercise _notify_of_ended_interventions_with_mismatched_frs() when it has some interventions to work on''' # Create some interventions to work with. Interventions sort by oldest last, so I make sure my list here is # ordered in the same way as they'll be pulled out of the database. interventions = [ InterventionFactory(status=Intervention.ENDED, created=_make_past_datetime(i)) for i in range(3) ] # Add mismatched funds values to each intervention. for intervention in interventions: for i in range(3): FundsReservationHeaderFactory( intervention=intervention, actual_amt_local=_make_decimal(i + 1), total_amt_local=_make_decimal(i)) # Create a few items that should be ignored. If they're not ignored, this test will fail. # Should be ignored because of status even though FRS values are mismatched intervention = InterventionFactory(status=Intervention.DRAFT) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, actual_amt_local=_make_decimal(i + 1), total_amt_local=_make_decimal(i)) # Should be ignored because FRS values are not mismatched intervention = InterventionFactory(status=Intervention.ENDED) for i in range(3): FundsReservationHeaderFactory(intervention=intervention, actual_amt_local=_make_decimal(i), total_amt_local=_make_decimal(i)) # Mock Notifications.objects.create() to return a Mock. In order to *truly* mimic create(), my # mock_notification_objects.create() should return a new (mock) object every time, but the lazy way or # returning the same object is good enough and still allows me to count calls to .send_notification(). mock_notification = mock.Mock( spec=['send_notification', 'save', 'full_clean']) mock_notification_model.return_value = mock_notification # I'm done mocking, it's time to call the function. etools.applications.partners.tasks._notify_of_ended_interventions_with_mismatched_frs( self.country_name) # Verify that Notification.objects.create() was called as expected. expected_call_args = [((), { 'method_type': mock_notification_model.TYPE_EMAIL, 'sender': intervention_, 'recipients': [], 'cc': [], 'from_address': '', 'template_name': 'partners/partnership/ended/frs/outstanding', 'template_data': etools.applications.partners.tasks.get_intervention_context( intervention_), }) for intervention_ in interventions] self._assertCalls(mock_notification_model, expected_call_args) # Verify that each created notification object had send_notification() called. expected_call_args = [((), {})] * len(interventions) self._assertCalls(mock_notification.send_notification, expected_call_args)
class TestFundReservationsSynchronizer(BaseTenantTestCase): maxDiff = None @classmethod def setUpTestData(cls): cls.country = Country.objects.first() def setUp(self): self.data = { "VENDOR_CODE": "Code123", "FR_NUMBER": "123", "FR_DOC_DATE": "14-Jan-15", "FR_TYPE": "Type", "CURRENCY": "USD", "FR_DOCUMENT_TEXT": "Random Text", "FR_START_DATE": "13-Jan-15", "FR_END_DATE": "20-Dec-15", "LINE_ITEM": "987", "WBS_ELEMENT": "WBS", "GRANT_NBR": "456", "FUND": "Fund", "OVERALL_AMOUNT": "20.00", "OVERALL_AMOUNT_DC": "5.00", "FR_LINE_ITEM_TEXT": "Line item text", "DUE_DATE": "18-May-15", "FR_OVERALL_AMOUNT": "15.00", "CURRENT_FR_AMOUNT": "17.00", "ACTUAL_CASH_TRANSFER": "18.00", "OUTSTANDING_DCT": "19.00", "ACTUAL_CASH_TRANSFER_DC": "13.00", "OUTSTANDING_DCT_DC": "14.00", "MULTI_CURR_FLAG": "N" } self.expected_headers = { "vendor_code": "Code123", "fr_number": "123", "document_date": datetime.date(2015, 1, 14), "fr_type": "Type", "currency": "USD", "document_text": "Random Text", "start_date": datetime.date(2015, 1, 13), "end_date": datetime.date(2015, 12, 20), "total_amt": "15.00", "intervention_amt": "17.00", "actual_amt": "18.00", "actual_amt_local": "13.00", "outstanding_amt": "19.00", "outstanding_amt_local": "14.00", "multi_curr_flag": False } self.expected_line_item = { "line_item": "987", "fr_number": "123", "donor": None, "donor_code": None, "wbs": "WBS", "grant_number": "456", "fund": "Fund", "overall_amount": "20.00", "overall_amount_dc": "5.00", "due_date": datetime.date(2015, 5, 18), "line_item_text": "Line item text", "fr_ref_number": "123-987" } self.fund_item = FundsReservationItemFactory( fr_ref_number="123-987", line_item=self.data["LINE_ITEM"], wbs=self.data["WBS_ELEMENT"], grant_number=self.data["GRANT_NBR"], fund=self.data["FUND"], overall_amount=self.data["OVERALL_AMOUNT"], overall_amount_dc=self.data["OVERALL_AMOUNT_DC"], due_date=datetime.date(2015, 5, 18), line_item_text=self.data["FR_LINE_ITEM_TEXT"], ) self.fund_header = FundsReservationHeaderFactory( vendor_code=self.data["VENDOR_CODE"], fr_number=self.data["FR_NUMBER"], document_date=datetime.date(2015, 1, 14), fr_type=self.data["FR_TYPE"], currency=self.data["CURRENCY"], document_text=self.data["FR_DOCUMENT_TEXT"], intervention_amt=self.data["CURRENT_FR_AMOUNT"], total_amt=self.data["FR_OVERALL_AMOUNT"], actual_amt=self.data["ACTUAL_CASH_TRANSFER"], outstanding_amt=self.data["OUTSTANDING_DCT"], outstanding_amt_local=self.data["OUTSTANDING_DCT_DC"], start_date=datetime.date(2015, 1, 13), end_date=datetime.date(2015, 12, 20), ) self.adapter = synchronizers.FundReservationsSynchronizer(self.country) def test_init(self): a = synchronizers.FundReservationsSynchronizer(self.country) self.assertEqual(a.header_records, {}) self.assertEqual(a.item_records, {}) self.assertEqual(a.fr_headers, {}) def test_convert_records(self): self.assertEqual( self.adapter._convert_records(json.dumps({"ROWSET": {"ROW": [self.data]}})), [self.data] ) def test_update_fr_totals_no_fr_items__overall_amount_dc(self): # Test for https://app.clubhouse.io/unicefetools/story/4978/fr-handler-none-values-failing-on-frs # We were throwing an exception because we expected Sum() to always # return a value, but if there's nothing to sum, it returns None. self.adapter.update_fr_totals() def test_filter_records_no_overall_amount(self): """If no overall amount then ignore record""" self.data["OVERALL_AMOUNT"] = "" records = {"ROWSET": {"ROW": [self.data]}} response = self.adapter._filter_records(records) self.assertEqual(response, []) def test_filter_records_no_fr_number(self): """If no fr number then ignore record""" self.data["FR_NUMBER"] = "" records = {"ROWSET": {"ROW": [self.data]}} response = self.adapter._filter_records(records) self.assertEqual(response, []) def test_filter_records(self): """If have both overall number and fr number then keep record""" records = [self.data] response = self.adapter._filter_records(records) self.assertEqual(response, [self.data]) def test_get_value_for_field_date(self): """If a set field (date) then convert to datetime date type""" fields = ["start_date", "end_date", "document_date", "due_date"] for field in fields: response = self.adapter.get_value_for_field(field, "15-Jan-14") self.assertEqual(response, datetime.date(2014, 1, 15)) def test_get_value_for_field(self): """If NOT a set field (date) then return value""" response = self.adapter.get_value_for_field("random", "val") self.assertEqual(response, "val") def test_get_fr_item_number(self): response = self.adapter.get_fr_item_number(self.data) self.assertEqual(response, "123-987") def test_map_header_from_record(self): response = self.adapter.map_header_from_record(self.data) self.assertEqual(response, self.expected_headers) def test_map_line_item_record(self): response = self.adapter.map_line_item_record(self.data) self.assertEqual(response, self.expected_line_item) def test_set_mapping(self): self.assertEqual(self.adapter.header_records, {}) self.assertEqual(self.adapter.item_records, {}) self.adapter.set_mapping([self.data]) self.assertEqual( self.adapter.header_records, {"123": self.expected_headers} ) self.assertEqual( self.adapter.item_records, {"123-987": self.expected_line_item} ) def test_equal_fields_decimal(self): """If field is amt field then do comp_decimal comparison""" self.assertTrue( self.adapter.equal_fields("total_amt", "20.00", "20.00") ) self.assertFalse( self.adapter.equal_fields("total_amt", "20.00", "20.01") ) def test_equal_fields_line_item(self): """If field is line item then convert obj field to str prior to comparison """ self.assertTrue(self.adapter.equal_fields("line_item", 20, "20")) self.assertFalse(self.adapter.equal_fields("line_item", 21, "22")) def test_equal_fields(self): """If field is not special do normal comparison""" self.assertTrue(self.adapter.equal_fields("fr_number", "123", "123")) self.assertFalse(self.adapter.equal_fields("fr_number", "124", "123")) def test_update_object(self): """Check that if a value does not match object then return True""" self.fund_item.fr_ref_number = "321-123", record = self.adapter.map_line_item_record(self.data) del record["fr_number"] self.assertTrue(self.adapter.update_obj(self.fund_item, record)) self.assertEqual(self.fund_item.fr_ref_number, "123-987") def test_update_object_no_change(self): """Check that if all values match object then return False""" record = self.adapter.map_line_item_record(self.data) del record["fr_number"] self.assertFalse(self.adapter.update_obj(self.fund_item, record)) def test_header_sync_update(self): """Check that FundsReservationHeader record updated if values differ """ self.fund_header.vendor_code = "Code321" self.fund_header.save() self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.header_sync() self.assertEqual(updated, 1) self.assertEqual(to_create, 0) fund_header_updated = FundsReservationHeader.objects.get( pk=self.fund_header.pk ) self.assertEqual( fund_header_updated.vendor_code, self.data["VENDOR_CODE"] ) def test_header_sync_create(self): """Check that FundsReservationHeader record created if fr_number does not exist """ self.data["FR_NUMBER"] = "333" fund_qs = FundsReservationHeader.objects.filter(fr_number="333") self.assertFalse(fund_qs.exists()) self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.header_sync() self.assertEqual(updated, 0) self.assertEqual(to_create, 1) self.assertTrue(fund_qs.exists()) def test_li_sync_update(self): """Check that FundsReservationItem record updated if values differ """ self.fund_item.overall_amount = "30.00" self.fund_item.save() self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.li_sync() self.assertEqual(updated, 1) self.assertEqual(to_create, 0) fund_item_updated = FundsReservationItem.objects.get( pk=self.fund_item.pk ) self.assertEqual( fund_item_updated.overall_amount, Decimal(self.data["OVERALL_AMOUNT"]) ) def test_li_sync_create(self): """Check that FundsReservationItem record created if fr_ref_number does not exist """ self.data["LINE_ITEM"] = "333" fund_qs = FundsReservationItem.objects.filter( fr_ref_number="123-333" ) self.assertFalse(fund_qs.exists()) self.adapter.set_mapping([self.data]) self.adapter.map_header_objects([self.fund_header]) updated, to_create = self.adapter.li_sync() self.assertEqual(updated, 0) self.assertEqual(to_create, 1) self.assertTrue(fund_qs.exists()) def test_save_records(self): self.data["LINE_ITEM"] = "333" response = self.adapter._save_records([self.data]) self.assertEqual(response, 2)
class TestFundReservationsSynchronizer(BaseTenantTestCase): maxDiff = None @classmethod def setUpTestData(cls): cls.country = Country.objects.first() def setUp(self): self.data = { "VENDOR_CODE": "Code123", "FR_NUMBER": "123", "FR_DOC_DATE": "14-Jan-15", "FR_TYPE": "Type", "CURRENCY": "USD", "FR_DOCUMENT_TEXT": "Random Text", "FR_START_DATE": "13-Jan-15", "FR_END_DATE": "20-Dec-15", "LINE_ITEM": "987", "WBS_ELEMENT": "WBS", "GRANT_NBR": "456", "FUND": "Fund", "OVERALL_AMOUNT": "20.00", "OVERALL_AMOUNT_DC": "5.00", "FR_LINE_ITEM_TEXT": "Line item text", "DUE_DATE": "18-May-15", "FR_OVERALL_AMOUNT": "15.00", "CURRENT_FR_AMOUNT": "17.00", "ACTUAL_CASH_TRANSFER": "18.00", "OUTSTANDING_DCT": "19.00", "ACTUAL_CASH_TRANSFER_DC": "13.00", "OUTSTANDING_DCT_DC": "14.00", "MULTI_CURR_FLAG": "N" } self.expected_headers = { "vendor_code": "Code123", "fr_number": "123", "document_date": datetime.date(2015, 1, 14), "fr_type": "Type", "currency": "USD", "document_text": "Random Text", "start_date": datetime.date(2015, 1, 13), "end_date": datetime.date(2015, 12, 20), "total_amt": "15.00", "intervention_amt": "17.00", "actual_amt": "18.00", "actual_amt_local": "13.00", "outstanding_amt": "19.00", "outstanding_amt_local": "14.00", "multi_curr_flag": False } self.expected_line_item = { "line_item": "987", "fr_number": "123", "donor": None, "donor_code": None, "wbs": "WBS", "grant_number": "456", "fund": "Fund", "overall_amount": "20.00", "overall_amount_dc": "5.00", "due_date": datetime.date(2015, 5, 18), "line_item_text": "Line item text", "fr_ref_number": "123-987" } self.fund_item = FundsReservationItemFactory( fr_ref_number="123-987", line_item=self.data["LINE_ITEM"], wbs=self.data["WBS_ELEMENT"], grant_number=self.data["GRANT_NBR"], fund=self.data["FUND"], overall_amount=self.data["OVERALL_AMOUNT"], overall_amount_dc=self.data["OVERALL_AMOUNT_DC"], due_date=datetime.date(2015, 5, 18), line_item_text=self.data["FR_LINE_ITEM_TEXT"], ) self.fund_header = FundsReservationHeaderFactory( vendor_code=self.data["VENDOR_CODE"], fr_number=self.data["FR_NUMBER"], document_date=datetime.date(2015, 1, 14), fr_type=self.data["FR_TYPE"], currency=self.data["CURRENCY"], document_text=self.data["FR_DOCUMENT_TEXT"], intervention_amt=self.data["CURRENT_FR_AMOUNT"], total_amt=self.data["FR_OVERALL_AMOUNT"], actual_amt=self.data["ACTUAL_CASH_TRANSFER"], outstanding_amt=self.data["OUTSTANDING_DCT"], outstanding_amt_local=self.data["OUTSTANDING_DCT_DC"], start_date=datetime.date(2015, 1, 13), end_date=datetime.date(2015, 12, 20), ) self.adapter = adapter.FundReservationsSynchronizer(self.country) def test_init(self): a = adapter.FundReservationsSynchronizer(self.country) self.assertEqual(a.header_records, {}) self.assertEqual(a.item_records, {}) self.assertEqual(a.fr_headers, {}) def test_convert_records(self): self.assertEqual( self.adapter._convert_records( json.dumps({"ROWSET": { "ROW": [self.data] }})), [self.data]) def test_update_fr_totals_no_fr_items__overall_amount_dc(self): # Test for https://app.clubhouse.io/unicefetools/story/4978/fr-handler-none-values-failing-on-frs # We were throwing an exception because we expected Sum() to always # return a value, but if there's nothing to sum, it returns None. self.adapter.update_fr_totals() def test_filter_records_no_overall_amount(self): """If no overall amount then ignore record""" self.data["OVERALL_AMOUNT"] = "" records = {"ROWSET": {"ROW": [self.data]}} response = self.adapter._filter_records(records) self.assertEqual(response, []) def test_filter_records_no_fr_number(self): """If no fr number then ignore record""" self.data["FR_NUMBER"] = "" records = {"ROWSET": {"ROW": [self.data]}} response = self.adapter._filter_records(records) self.assertEqual(response, []) def test_filter_records(self): """If have both overall number and fr number then keep record""" records = [self.data] response = self.adapter._filter_records(records) self.assertEqual(response, [self.data]) def test_get_value_for_field_date(self): """If a set field (date) then convert to datetime date type""" fields = ["start_date", "end_date", "document_date", "due_date"] for field in fields: response = self.adapter.get_value_for_field(field, "15-Jan-14") self.assertEqual(response, datetime.date(2014, 1, 15)) def test_get_value_for_field(self): """If NOT a set field (date) then return value""" response = self.adapter.get_value_for_field("random", "val") self.assertEqual(response, "val") def test_get_fr_item_number(self): response = self.adapter.get_fr_item_number(self.data) self.assertEqual(response, "123-987") def test_map_header_from_record(self): response = self.adapter.map_header_from_record(self.data) self.assertEqual(response, self.expected_headers) def test_map_line_item_record(self): response = self.adapter.map_line_item_record(self.data) self.assertEqual(response, self.expected_line_item) def test_set_mapping(self): self.assertEqual(self.adapter.header_records, {}) self.assertEqual(self.adapter.item_records, {}) self.adapter.set_mapping([self.data]) self.assertEqual(self.adapter.header_records, {"123": self.expected_headers}) self.assertEqual(self.adapter.item_records, {"123-987": self.expected_line_item}) def test_equal_fields_decimal(self): """If field is amt field then do comp_decimal comparison""" self.assertTrue( self.adapter.equal_fields("total_amt", "20.00", "20.00")) self.assertFalse( self.adapter.equal_fields("total_amt", "20.00", "20.01")) def test_equal_fields_line_item(self): """If field is line item then convert obj field to str prior to comparison """ self.assertTrue(self.adapter.equal_fields("line_item", 20, "20")) self.assertFalse(self.adapter.equal_fields("line_item", 21, "22")) def test_equal_fields(self): """If field is not special do normal comparison""" self.assertTrue(self.adapter.equal_fields("fr_number", "123", "123")) self.assertFalse(self.adapter.equal_fields("fr_number", "124", "123")) def test_update_object(self): """Check that if a value does not match object then return True""" self.fund_item.fr_ref_number = "321-123", record = self.adapter.map_line_item_record(self.data) del record["fr_number"] self.assertTrue(self.adapter.update_obj(self.fund_item, record)) self.assertEqual(self.fund_item.fr_ref_number, "123-987") def test_update_object_no_change(self): """Check that if all values match object then return False""" record = self.adapter.map_line_item_record(self.data) del record["fr_number"] self.assertFalse(self.adapter.update_obj(self.fund_item, record)) def test_header_sync_update(self): """Check that FundsReservationHeader record updated if values differ """ self.fund_header.vendor_code = "Code321" self.fund_header.save() self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.header_sync() self.assertEqual(updated, 1) self.assertEqual(to_create, 0) fund_header_updated = FundsReservationHeader.objects.get( pk=self.fund_header.pk) self.assertEqual(fund_header_updated.vendor_code, self.data["VENDOR_CODE"]) def test_header_sync_create(self): """Check that FundsReservationHeader record created if fr_number does not exist """ self.data["FR_NUMBER"] = "333" fund_qs = FundsReservationHeader.objects.filter(fr_number="333") self.assertFalse(fund_qs.exists()) self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.header_sync() self.assertEqual(updated, 0) self.assertEqual(to_create, 1) self.assertTrue(fund_qs.exists()) def test_li_sync_update(self): """Check that FundsReservationItem record updated if values differ """ self.fund_item.overall_amount = "30.00" self.fund_item.save() self.adapter.set_mapping([self.data]) updated, to_create = self.adapter.li_sync() self.assertEqual(updated, 1) self.assertEqual(to_create, 0) fund_item_updated = FundsReservationItem.objects.get( pk=self.fund_item.pk) self.assertEqual(fund_item_updated.overall_amount, Decimal(self.data["OVERALL_AMOUNT"])) def test_li_sync_create(self): """Check that FundsReservationItem record created if fr_ref_number does not exist """ self.data["LINE_ITEM"] = "333" fund_qs = FundsReservationItem.objects.filter(fr_ref_number="123-333") self.assertFalse(fund_qs.exists()) self.adapter.set_mapping([self.data]) self.adapter.map_header_objects([self.fund_header]) updated, to_create = self.adapter.li_sync() self.assertEqual(updated, 0) self.assertEqual(to_create, 1) self.assertTrue(fund_qs.exists()) def test_save_records(self): self.data["LINE_ITEM"] = "333" response = self.adapter._save_records([self.data]) self.assertEqual(response, 2)
def setUp(self): super().setUp() self.unicef_staff = UserFactory(is_staff=True) self.frs = FundsReservationHeaderFactory() self.item = FundsReservationItemFactory(fund_reservation=self.frs)
def setUp(self): self.data = { "VENDOR_CODE": "Code123", "FR_NUMBER": "123", "FR_DOC_DATE": "14-Jan-15", "FR_TYPE": "Type", "CURRENCY": "USD", "FR_DOCUMENT_TEXT": "Random Text", "FR_START_DATE": "13-Jan-15", "FR_END_DATE": "20-Dec-15", "LINE_ITEM": "987", "WBS_ELEMENT": "WBS", "GRANT_NBR": "456", "FUND": "Fund", "OVERALL_AMOUNT": "20.00", "OVERALL_AMOUNT_DC": "5.00", "FR_LINE_ITEM_TEXT": "Line item text", "DUE_DATE": "18-May-15", "FR_OVERALL_AMOUNT": "15.00", "CURRENT_FR_AMOUNT": "17.00", "ACTUAL_CASH_TRANSFER": "18.00", "OUTSTANDING_DCT": "19.00", "ACTUAL_CASH_TRANSFER_DC": "13.00", "OUTSTANDING_DCT_DC": "14.00", "MULTI_CURR_FLAG": "N" } self.expected_headers = { "vendor_code": "Code123", "fr_number": "123", "document_date": datetime.date(2015, 1, 14), "fr_type": "Type", "currency": "USD", "document_text": "Random Text", "start_date": datetime.date(2015, 1, 13), "end_date": datetime.date(2015, 12, 20), "total_amt": "15.00", "intervention_amt": "17.00", "actual_amt": "18.00", "actual_amt_local": "13.00", "outstanding_amt": "19.00", "outstanding_amt_local": "14.00", "multi_curr_flag": False } self.expected_line_item = { "line_item": "987", "fr_number": "123", "donor": None, "donor_code": None, "wbs": "WBS", "grant_number": "456", "fund": "Fund", "overall_amount": "20.00", "overall_amount_dc": "5.00", "due_date": datetime.date(2015, 5, 18), "line_item_text": "Line item text", "fr_ref_number": "123-987" } self.fund_item = FundsReservationItemFactory( fr_ref_number="123-987", line_item=self.data["LINE_ITEM"], wbs=self.data["WBS_ELEMENT"], grant_number=self.data["GRANT_NBR"], fund=self.data["FUND"], overall_amount=self.data["OVERALL_AMOUNT"], overall_amount_dc=self.data["OVERALL_AMOUNT_DC"], due_date=datetime.date(2015, 5, 18), line_item_text=self.data["FR_LINE_ITEM_TEXT"], ) self.fund_header = FundsReservationHeaderFactory( vendor_code=self.data["VENDOR_CODE"], fr_number=self.data["FR_NUMBER"], document_date=datetime.date(2015, 1, 14), fr_type=self.data["FR_TYPE"], currency=self.data["CURRENCY"], document_text=self.data["FR_DOCUMENT_TEXT"], intervention_amt=self.data["CURRENT_FR_AMOUNT"], total_amt=self.data["FR_OVERALL_AMOUNT"], actual_amt=self.data["ACTUAL_CASH_TRANSFER"], outstanding_amt=self.data["OUTSTANDING_DCT"], outstanding_amt_local=self.data["OUTSTANDING_DCT_DC"], start_date=datetime.date(2015, 1, 13), end_date=datetime.date(2015, 12, 20), ) self.adapter = adapter.FundReservationsSynchronizer(self.country)
class TestFRHeaderView(BaseTenantTestCase): @classmethod def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) partner = PartnerFactory(vendor_number="PVN") agreement = AgreementFactory(partner=partner) cls.intervention = InterventionFactory(agreement=agreement) def setUp(self): vendor_code = self.intervention.agreement.partner.vendor_number self.fr_1 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_2 = FundsReservationHeaderFactory(intervention=None, currency="USD", vendor_code=vendor_code) self.fr_3 = FundsReservationHeaderFactory(intervention=None, currency="RON") def run_request(self, data): response = self.forced_auth_req('get', reverse('funds:frs'), user=self.unicef_staff, data=data) return response.status_code, json.loads(response.rendered_content) def test_get_one_fr(self): data = {'values': self.fr_1.fr_number} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) self.assertEqual(result['total_actual_amt'], float(self.fr_1.actual_amt_local)) self.assertEqual(result['total_outstanding_amt'], float(self.fr_1.outstanding_amt_local)) self.assertEqual(result['total_frs_amt'], float(self.fr_1.total_amt_local)) self.assertEqual(result['total_intervention_amt'], float(self.fr_1.intervention_amt)) def test_get_two_frs(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) # Make sure result numbers match up # float the Decimal sum self.assertEqual( result['total_actual_amt'], float(sum([self.fr_1.actual_amt_local, self.fr_2.actual_amt_local]))) self.assertEqual( result['total_outstanding_amt'], float( sum([ self.fr_1.outstanding_amt_local, self.fr_2.outstanding_amt_local ]))) self.assertEqual( result['total_frs_amt'], float(sum([self.fr_1.total_amt_local, self.fr_2.total_amt_local]))) self.assertEqual( result['total_intervention_amt'], float(sum([self.fr_1.intervention_amt, self.fr_2.intervention_amt]))) def test_get_earliest_start_date_from_two_frs(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) self.assertEqual( datetime.strptime(result['earliest_start_date'], '%Y-%m-%d').date(), min([self.fr_1.start_date, self.fr_2.start_date])) self.assertEqual( datetime.strptime(result['latest_end_date'], '%Y-%m-%d').date(), max([self.fr_1.end_date, self.fr_2.end_date])) def test_get_earliest_start_date_from_one_fr(self): data = {'values': ','.join([self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) self.assertEqual( datetime.strptime(result['earliest_start_date'], '%Y-%m-%d').date(), self.fr_1.start_date) self.assertEqual( datetime.strptime(result['latest_end_date'], '%Y-%m-%d').date(), self.fr_1.end_date) def test_get_fail_with_no_values(self): data = {} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(result['error'], 'Values are required') def test_get_fail_with_nonexistant_values(self): data = {'values': ','.join(['im a bad value', 'another bad value'])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( result['error'], 'The FR another bad value, im a bad value could not be found on eTools' ) def test_get_fail_with_intervention_id(self): other_intervention = InterventionFactory() fth_value = 'im a bad value' FundsReservationHeaderFactory(fr_number=fth_value, intervention=other_intervention, currency="USD") data = { 'values': ','.join([fth_value, self.fr_1.fr_number]), 'intervention': self.intervention.pk } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( result['error'], 'FR #{} is already being used by PD/SSFA ref [{}]'.format( fth_value, other_intervention)) def test_get_success_with_expired_fr(self): self.fr_1.end_date = timezone.now().date() - timedelta(days=1) self.fr_1.save() data = {'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) def test_get_fail_with_intervention_fr(self): self.fr_1.intervention = self.intervention self.fr_1.save() data = {'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( result['error'], 'One or more of the FRs are used by another PD/SSFA ' 'or could not be found in eTools.') def test_get_with_intervention_fr(self): self.fr_1.intervention = self.intervention self.fr_1.save() data = { 'values': ','.join([self.fr_2.fr_number, self.fr_1.fr_number]), 'intervention': self.intervention.id } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) self.assertEqual( result['total_actual_amt'], float(sum([self.fr_1.actual_amt_local, self.fr_2.actual_amt_local]))) self.assertEqual( result['total_outstanding_amt'], float( sum([ self.fr_1.outstanding_amt_local, self.fr_2.outstanding_amt_local ]))) self.assertEqual( result['total_frs_amt'], float(sum([self.fr_1.total_amt_local, self.fr_2.total_amt_local]))) self.assertEqual( result['total_intervention_amt'], float(sum([self.fr_1.intervention_amt, self.fr_2.intervention_amt]))) def test_grants_filter(self): """Check that filtering on grant returns expected result""" grant_number = "G123" grant = GrantFactory(name=grant_number) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number) data = { "values": self.fr_1.fr_number, "grants": grant.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) def test_grants_many_filter(self): """Check that filtering on multiple grants returns expected result""" grant_number_1 = "G123" grant_number_2 = "G124" grant_1 = GrantFactory(name=grant_number_1) grant_2 = GrantFactory(name=grant_number_2) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number_1) FundsReservationItemFactory(fund_reservation=self.fr_2, grant_number=grant_number_2) FundsReservationHeaderFactory() data = { "values": ",".join([self.fr_1.fr_number, self.fr_2.fr_number]), "grants": ",".join([str(grant_1.pk), str(grant_2.pk)]), } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) def test_grants_filter_invalid(self): """Check that filtering on invalid grant returns 400""" grant_number = "G123" GrantFactory(name=grant_number) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number) data = { "values": self.fr_1.fr_number, "grants": "404", } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error']) def test_donors_filter(self): """Check that filtering on donor returns expected result""" donor = DonorFactory() grant_number = "G123" GrantFactory( donor=donor, name=grant_number, ) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number) data = { "values": self.fr_1.fr_number, "donors": donor.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 1) def test_donors_many_filter(self): """Check that filtering on multiple donors returns expected result""" donor_1 = DonorFactory() donor_2 = DonorFactory() grant_number_1 = "G123" grant_number_2 = "G124" GrantFactory( donor=donor_1, name=grant_number_1, ) GrantFactory( donor=donor_2, name=grant_number_2, ) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number_1) FundsReservationItemFactory(fund_reservation=self.fr_2, grant_number=grant_number_2) FundsReservationHeaderFactory() data = { "values": ",".join([self.fr_1.fr_number, self.fr_2.fr_number]), "donors": ",".join([str(donor_1.pk), str(donor_2.pk)]), } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(len(result['frs']), 2) def test_donors_filter_invalid(self): """Check that filtering on invalid donors returns 400""" donor = DonorFactory() grant_number = "G123" GrantFactory( donor=donor, name=grant_number, ) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number) data = { "values": self.fr_1.fr_number, "donors": "404", } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error']) def test_grant_donors_mismatch(self): """Check that filtering on donors and grant not related to donor, returns 400 """ donor = DonorFactory() GrantFactory(donor=donor, ) grant_number = "G123" grant = GrantFactory(name=grant_number, ) FundsReservationItemFactory(fund_reservation=self.fr_1, grant_number=grant_number) data = { "values": self.fr_1.fr_number, "grants": grant.pk, "donors": donor.pk, } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'please make sure to select FRs that relate to the PD/SSFA Partner', result['error']) def test_frs_vendor_code_mismatch(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_3.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('FRs selected relate to various partners', result['error']) def test_frs_partner_vendor_code_mismatch(self): data = { 'values': ','.join([self.fr_3.fr_number]), 'intervention': self.intervention.pk } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_400_BAD_REQUEST) self.assertIn( 'vendor number of the selected implementing partner in eTools does not ' 'match the vendor number entered in the FR in VISION', result['error']) def test_frs_partner_vendor_code_ok(self): data = { 'values': ','.join([self.fr_1.fr_number]), 'intervention': self.intervention.pk } status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) def test_frs_currencies_match_ok(self): data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(result['currencies_match'], True) self.assertNotEqual(result['total_intervention_amt'], 0) def test_frs_currencies_mismatch_ok(self): self.fr_2.currency = 'LBP' self.fr_2.save() data = {'values': ','.join([self.fr_1.fr_number, self.fr_2.fr_number])} status_code, result = self.run_request(data) self.assertEqual(status_code, status.HTTP_200_OK) self.assertEqual(result['currencies_match'], False) self.assertEqual(result['total_intervention_amt'], 0)
def setUp(self): self.data = { "VENDOR_CODE": "Code123", "FR_NUMBER": "123", "FR_DOC_DATE": "14-Jan-15", "FR_TYPE": "Type", "CURRENCY": "USD", "FR_DOCUMENT_TEXT": "Random Text", "FR_START_DATE": "13-Jan-15", "FR_END_DATE": "20-Dec-15", "LINE_ITEM": "987", "WBS_ELEMENT": "WBS", "GRANT_NBR": "456", "FUND": "Fund", "OVERALL_AMOUNT": "20.00", "OVERALL_AMOUNT_DC": "5.00", "FR_LINE_ITEM_TEXT": "Line item text", "DUE_DATE": "18-May-15", "FR_OVERALL_AMOUNT": "15.00", "CURRENT_FR_AMOUNT": "17.00", "ACTUAL_CASH_TRANSFER": "18.00", "OUTSTANDING_DCT": "19.00", "ACTUAL_CASH_TRANSFER_DC": "13.00", "OUTSTANDING_DCT_DC": "14.00", "MULTI_CURR_FLAG": "N" } self.expected_headers = { "vendor_code": "Code123", "fr_number": "123", "document_date": datetime.date(2015, 1, 14), "fr_type": "Type", "currency": "USD", "document_text": "Random Text", "start_date": datetime.date(2015, 1, 13), "end_date": datetime.date(2015, 12, 20), "total_amt": "15.00", "intervention_amt": "17.00", "actual_amt": "18.00", "actual_amt_local": "13.00", "outstanding_amt": "19.00", "outstanding_amt_local": "14.00", "multi_curr_flag": False } self.expected_line_item = { "line_item": "987", "fr_number": "123", "donor": None, "donor_code": None, "wbs": "WBS", "grant_number": "456", "fund": "Fund", "overall_amount": "20.00", "overall_amount_dc": "5.00", "due_date": datetime.date(2015, 5, 18), "line_item_text": "Line item text", "fr_ref_number": "123-987" } self.fund_item = FundsReservationItemFactory( fr_ref_number="123-987", line_item=self.data["LINE_ITEM"], wbs=self.data["WBS_ELEMENT"], grant_number=self.data["GRANT_NBR"], fund=self.data["FUND"], overall_amount=self.data["OVERALL_AMOUNT"], overall_amount_dc=self.data["OVERALL_AMOUNT_DC"], due_date=datetime.date(2015, 5, 18), line_item_text=self.data["FR_LINE_ITEM_TEXT"], ) self.fund_header = FundsReservationHeaderFactory( vendor_code=self.data["VENDOR_CODE"], fr_number=self.data["FR_NUMBER"], document_date=datetime.date(2015, 1, 14), fr_type=self.data["FR_TYPE"], currency=self.data["CURRENCY"], document_text=self.data["FR_DOCUMENT_TEXT"], intervention_amt=self.data["CURRENT_FR_AMOUNT"], total_amt=self.data["FR_OVERALL_AMOUNT"], actual_amt=self.data["ACTUAL_CASH_TRANSFER"], outstanding_amt=self.data["OUTSTANDING_DCT"], outstanding_amt_local=self.data["OUTSTANDING_DCT_DC"], start_date=datetime.date(2015, 1, 13), end_date=datetime.date(2015, 12, 20), ) self.adapter = synchronizers.FundReservationsSynchronizer(self.country)
def test_funds_reservation_header(self): funds_reservation_header = FundsReservationHeaderFactory.build(fr_number='R\xe4dda Barnen') self.assertEqual(str(funds_reservation_header), 'R\xe4dda Barnen')