Skip to content

Commit be2ffa1

Browse files
authored
Merge pull request #3298 from unicef/ch29625-develop-fix-intervention-auto-transition
[Develop] Auto-transitions to active (via task) for PDs in the future do not work as expected.
2 parents ecc7211 + 1748a0a commit be2ffa1

File tree

2 files changed

+89
-45
lines changed

2 files changed

+89
-45
lines changed

src/etools/applications/partners/tasks.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from django.conf import settings
55
from django.contrib.auth import get_user_model
66
from django.db import connection, transaction
7-
from django.db.models import F, Sum
87

98
from celery.utils.log import get_task_logger
109
from django_tenants.utils import schema_context
@@ -119,17 +118,12 @@ def _make_intervention_status_automatic_transitions(country_name):
119118

120119
admin_user = get_user_model().objects.get(username=settings.TASK_ADMIN_USER)
121120
bad_interventions = []
122-
active_ended = Intervention.objects.filter(status=Intervention.ACTIVE,
123-
end__lt=datetime.date.today())
124-
qs = Intervention.objects\
125-
.prefetch_related('frs')\
126-
.filter(status=Intervention.ENDED)\
127-
.annotate(frs_total_outstanding=Sum('frs__outstanding_amt_local'),
128-
frs_total_actual_amt=Sum('frs__total_amt_local'),
129-
frs_intervention_amt=Sum('frs__actual_amt_local'))\
130-
.filter(frs_total_outstanding=0, frs_total_actual_amt=F('frs_intervention_amt'))
121+
# we should try all interventions except the ones in terminal statuses
122+
possible_interventions = Intervention.objects.exclude(status__in=[
123+
Intervention.DRAFT, Intervention.TERMINATED, Intervention.CLOSED, Intervention.SUSPENDED
124+
]).order_by('id')
131125
processed = 0
132-
for intervention in itertools.chain(active_ended, qs):
126+
for intervention in possible_interventions:
133127
old_status = intervention.status
134128
with transaction.atomic():
135129
validator = InterventionValid(intervention, user=admin_user, disable_rigid_check=True)
@@ -142,7 +136,7 @@ def _make_intervention_status_automatic_transitions(country_name):
142136

143137
logger.error('Bad interventions {}'.format(len(bad_interventions)))
144138
logger.error('Bad interventions ids: ' + ' '.join(str(a.id) for a in bad_interventions))
145-
logger.info('Total interventions {}'.format(active_ended.count() + qs.count()))
139+
logger.info('Total interventions {}'.format(possible_interventions.count()))
146140
logger.info("Transitioned interventions {} ".format(processed))
147141

148142

src/etools/applications/partners/tests/test_tasks.py

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,29 @@
1111
from django.utils import timezone
1212

1313
from unicef_attachments.models import Attachment
14+
from unicef_locations.tests.factories import LocationFactory
1415

1516
import etools.applications.partners.tasks
1617
from etools.applications.attachments.tests.factories import AttachmentFactory, AttachmentFileTypeFactory
1718
from etools.applications.core.tests.cases import BaseTenantTestCase
1819
from etools.applications.funds.tests.factories import FundsReservationHeaderFactory
19-
from etools.applications.partners.models import Agreement, Intervention
20+
from etools.applications.partners.models import Agreement, Intervention, InterventionBudget
21+
from etools.applications.partners.tasks import _make_intervention_status_automatic_transitions
2022
from etools.applications.partners.tests.factories import (
2123
AgreementFactory,
2224
CoreValuesAssessmentFactory,
2325
InterventionFactory,
26+
InterventionResultLinkFactory,
2427
PartnerFactory,
2528
)
26-
from etools.applications.reports.tests.factories import CountryProgrammeFactory
29+
from etools.applications.reports.models import ResultType
30+
from etools.applications.reports.tests.factories import (
31+
CountryProgrammeFactory,
32+
LowerResultFactory,
33+
OfficeFactory,
34+
ReportingRequirementFactory,
35+
SectionFactory,
36+
)
2737
from etools.applications.users.tests.factories import CountryFactory, UserFactory
2838

2939

@@ -549,23 +559,11 @@ def test_make_intervention_status_automatic_transitions_with_valid_interventions
549559
interventions.append(intervention)
550560

551561
# Create a few items that should be ignored. If they're not ignored, this test will fail.
552-
# Ignored because of end date
553-
InterventionFactory(status=Intervention.ACTIVE, end=datetime.date.today() + datetime.timedelta(days=2))
554562
# Ignored because of status
555-
InterventionFactory(status=Intervention.IMPLEMENTED, end=end_date)
556-
# Ignored because funds total outstanding != 0
557-
intervention = InterventionFactory(status=Intervention.ENDED, end=end_date)
558-
for i in range(3):
559-
FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(i),
560-
intervention_amt=_make_decimal(i),
561-
actual_amt=_make_decimal(i), total_amt=_make_decimal(i))
562-
563-
# Ignored because funds totals don't match
564-
intervention = InterventionFactory(status=Intervention.ENDED, end=end_date)
565-
for i in range(3):
566-
FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00),
567-
intervention_amt=_make_decimal(i),
568-
actual_amt=_make_decimal(i + 1), total_amt=_make_decimal(i))
563+
InterventionFactory(status=Intervention.TERMINATED)
564+
InterventionFactory(status=Intervention.CLOSED)
565+
InterventionFactory(status=Intervention.SUSPENDED)
566+
InterventionFactory(status=Intervention.DRAFT)
569567

570568
# Mock InterventionValid() to always return True.
571569
mock_validator = mock.Mock(spec=['is_valid'])
@@ -619,22 +617,11 @@ def test_make_intervention_status_automatic_transitions_with_mixed_interventions
619617
interventions.append(intervention)
620618

621619
# Create a few items that should be ignored. If they're not ignored, this test will fail.
622-
# Ignored because of end date
623-
InterventionFactory(status=Intervention.ACTIVE, end=datetime.date.today() + datetime.timedelta(days=2))
624620
# Ignored because of status
625-
InterventionFactory(status=Intervention.IMPLEMENTED, end=end_date)
626-
# Ignored because funds total outstanding != 0
627-
intervention = InterventionFactory(status=Intervention.ENDED, end=end_date)
628-
for i in range(3):
629-
FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(i),
630-
intervention_amt=_make_decimal(i),
631-
actual_amt=_make_decimal(i), total_amt=_make_decimal(i))
632-
# Ignored because funds totals don't match
633-
intervention = InterventionFactory(status=Intervention.ENDED, end=end_date)
634-
for i in range(3):
635-
FundsReservationHeaderFactory(intervention=intervention, outstanding_amt=Decimal(0.00),
636-
intervention_amt=_make_decimal(i),
637-
actual_amt=_make_decimal(i + 1), total_amt=_make_decimal(i))
621+
InterventionFactory(status=Intervention.TERMINATED)
622+
InterventionFactory(status=Intervention.CLOSED)
623+
InterventionFactory(status=Intervention.SUSPENDED)
624+
InterventionFactory(status=Intervention.DRAFT)
638625

639626
def mock_intervention_valid_class_side_effect(*args, **kwargs):
640627
"""Side effect for my mock InterventionValid() that gets called each time my mock InterventionValid() class
@@ -680,6 +667,69 @@ def mock_intervention_valid_class_side_effect(*args, **kwargs):
680667
]
681668
self._assertCalls(mock_logger.error, expected_call_args)
682669

670+
def test_activate_intervention_with_task(self, _mock_db_connection, _mock_logger):
671+
today = datetime.date.today()
672+
unicef_staff = UserFactory(is_staff=True, groups__data=['UNICEF User'])
673+
674+
partner = PartnerFactory(name='Partner 2')
675+
active_agreement = AgreementFactory(
676+
partner=partner,
677+
status=Agreement.SIGNED,
678+
signed_by_unicef_date=today - datetime.timedelta(days=2),
679+
signed_by_partner_date=today - datetime.timedelta(days=2),
680+
start=today - datetime.timedelta(days=2),
681+
)
682+
683+
active_intervention = InterventionFactory(
684+
agreement=active_agreement,
685+
title='Active Intervention',
686+
document_type=Intervention.PD,
687+
start=today - datetime.timedelta(days=1),
688+
end=today + datetime.timedelta(days=365),
689+
status=Intervention.SIGNED,
690+
country_programme=active_agreement.country_programme,
691+
# budget_owner=unicef_staff,
692+
# date_sent_to_partner=today - datetime.timedelta(days=1),
693+
signed_by_unicef_date=today - datetime.timedelta(days=1),
694+
signed_by_partner_date=today - datetime.timedelta(days=1),
695+
unicef_signatory=unicef_staff,
696+
partner_authorized_officer_signatory=partner.staff_members.all().first(),
697+
# cash_transfer_modalities=[Intervention.CASH_TRANSFER_DIRECT],
698+
)
699+
InterventionBudget.objects.get_or_create(
700+
intervention=active_intervention,
701+
defaults={
702+
'unicef_cash': 100,
703+
'unicef_cash_local': 10,
704+
'partner_contribution': 200,
705+
'partner_contribution_local': 20,
706+
'in_kind_amount_local': 10,
707+
}
708+
)
709+
active_intervention.flat_locations.add(LocationFactory())
710+
active_intervention.partner_focal_points.add(partner.staff_members.all().first())
711+
active_intervention.unicef_focal_points.add(unicef_staff)
712+
active_intervention.offices.add(OfficeFactory())
713+
active_intervention.sections.add(SectionFactory())
714+
ReportingRequirementFactory(intervention=active_intervention)
715+
AttachmentFactory(
716+
code='partners_intervention_signed_pd',
717+
content_object=active_intervention,
718+
)
719+
FundsReservationHeaderFactory(intervention=active_intervention)
720+
721+
result_link = InterventionResultLinkFactory(
722+
intervention=active_intervention,
723+
cp_output__result_type__name=ResultType.OUTPUT,
724+
)
725+
LowerResultFactory(result_link=result_link)
726+
# activity = InterventionActivityFactory(result=pd_output) # epd related stuff
727+
# activity.time_frames.add(active_intervention.quarters.first())
728+
729+
_make_intervention_status_automatic_transitions(self.country_name)
730+
active_intervention.refresh_from_db()
731+
self.assertEqual(active_intervention.status, Intervention.ACTIVE)
732+
683733

684734
@mock.patch('etools.applications.partners.tasks.logger', spec=['info'])
685735
@mock.patch('etools.applications.partners.tasks.connection', spec=['set_tenant'])

0 commit comments

Comments
 (0)