Ejemplo n.º 1
0
    def test_brief_response_can_be_serialized(self):
        with self.app.app_context():
            brief_response = BriefResponse(data={'foo': 'bar'},
                                           brief=self.brief,
                                           supplier=self.supplier)
            db.session.add(brief_response)
            db.session.commit()

            with mock.patch('app.models.url_for') as url_for:
                url_for.side_effect = lambda *args, **kwargs: (args, kwargs)
                assert brief_response.serialize() == {
                    'id': brief_response.id,
                    'briefId': self.brief.id,
                    'supplierId': 0,
                    'supplierName': 'Supplier 0',
                    'createdAt': mock.ANY,
                    'foo': 'bar',
                    'links': {
                        'self': (('.get_brief_response', ), {
                            'brief_response_id': brief_response.id
                        }),
                        'brief': (('.get_brief', ), {
                            'brief_id': self.brief.id
                        }),
                        'supplier': (('.get_supplier', ), {
                            'supplier_id': 0
                        }),
                    }
                }
Ejemplo n.º 2
0
    def brief_responses(self, app, brief, suppliers):
        now = pendulum.now('utc')

        with app.app_context():
            db.session.add(
                BriefResponse(
                    id=1,
                    brief_id=1,
                    created_at=now,
                    data={
                        'respondToEmailAddress': '*****@*****.**'
                    },
                    submitted_at=now,
                    supplier_code=123,
                    updated_at=now
                )
            )

            db.session.add(
                BriefResponse(
                    id=2,
                    brief_id=1,
                    created_at=now,
                    data={},
                    supplier_code=456,
                    updated_at=now
                )
            )

            db.session.commit()
            yield db.session.query(BriefResponse).all()
    def setup_dummy_brief_response(self, brief_id=None, supplier_code=0):
        with self.app.app_context():
            brief_response = BriefResponse(
                data=example_listings.brief_response_data().example(),
                supplier_code=supplier_code, brief_id=brief_id or self.brief_id
            )

            db.session.add(brief_response)
            db.session.commit()

            return brief_response.id
Ejemplo n.º 4
0
def brief_response(app):
    with app.app_context():
        db.session.add(
            BriefResponse(id=1,
                          brief_id=1,
                          supplier_code=1,
                          submitted_at=pendulum.now(),
                          data={}))

        db.session.commit()
        yield BriefResponse.query.get(1)
Ejemplo n.º 5
0
def brief_responses(app, overview_briefs, suppliers):
    with app.app_context():
        now = pendulum.now('utc')

        db.session.add(
            BriefResponse(id=1,
                          brief_id=7,
                          data={},
                          submitted_at=now,
                          supplier_code=2))

        db.session.add(
            BriefResponse(id=2,
                          brief_id=8,
                          data={},
                          submitted_at=now,
                          supplier_code=2))

        db.session.add(
            BriefResponse(id=3,
                          brief_id=9,
                          data={},
                          submitted_at=now,
                          supplier_code=2))

        db.session.add(
            BriefResponse(id=4,
                          brief_id=9,
                          data={},
                          submitted_at=now,
                          supplier_code=2))

        db.session.add(
            BriefResponse(id=5,
                          brief_id=9,
                          data={},
                          submitted_at=now,
                          supplier_code=2))

        db.session.commit()
        yield db.session.query(BriefResponse).all()
    def test_can_not_close_published_opportunity_early_with_multiple_seller_responses(
            self, overview_briefs, suppliers, lot_slug):
        lot = lots_service.find(slug=lot_slug).one_or_none()
        brief = briefs_service.find(lot=lot, status='live').one_or_none()

        db.session.add(
            BriefResponse(id=6, brief_id=brief.id, data={}, supplier_code=3))

        db.session.commit()

        can_close = can_close_opportunity_early(brief)
        assert can_close is False
Ejemplo n.º 7
0
def brief_responses(app, request, briefs, supplier_user):
    params = request.param if hasattr(request, 'param') else {}
    data = params['data'] if 'data' in params else {}
    with app.app_context():
        db.session.add(
            BriefResponse(id=1,
                          brief_id=1,
                          supplier_code=supplier_user.supplier_code,
                          data=data))

        db.session.commit()
        yield BriefResponse.query.all()
Ejemplo n.º 8
0
    def test_create_a_new_brief_response(self):
        with self.app.app_context():
            brief_response = BriefResponse(data={},
                                           brief=self.brief,
                                           supplier=self.supplier)
            db.session.add(brief_response)
            db.session.commit()

            assert brief_response.id is not None
            assert brief_response.supplier_id == 0
            assert brief_response.brief_id == self.brief.id
            assert isinstance(brief_response.created_at, datetime)
            assert brief_response.data == {}
def buyer_dashboard_briefs(app, request, buyer_dashboard_users, supplier_user):
    with app.app_context():
        for user in buyer_dashboard_users:
            for status in ['draft', 'live', 'closed']:
                brief = Brief(
                    data=COMPLETE_DIGITAL_SPECIALISTS_BRIEF.copy(),
                    framework=Framework.query.filter(Framework.slug == "digital-outcomes-and-specialists").first(),
                    lot=Lot.query.filter(Lot.slug == 'digital-specialists').first(),
                    published_at=None,
                    closed_at=None,
                    questions_closed_at=None,
                    withdrawn_at=None
                )
                db.session.add(brief)
                db.session.flush()

                if status == 'live':
                    brief.published_at = utcnow()
                    brief.questions_closed_at = utcnow().add(days=1)
                    brief.closed_at = utcnow().add(days=2)
                elif status == 'closed':
                    brief.published_at = utcnow().subtract(weeks=1)
                    brief.questions_closed_at = utcnow().subtract(days=2)
                    brief.closed_at = utcnow().subtract(days=1)

                brief_user = BriefUser(
                    brief_id=brief.id,
                    user_id=user.id
                )
                db.session.add(brief_user)
                db.session.flush()

                # Link briefs with responses and work orders when they're live or closed
                if status == 'live' or status == 'closed':
                    db.session.add(BriefResponse(
                        brief_id=brief.id,
                        supplier_code=supplier_user.supplier_code,
                        data={}
                    ))

                    db.session.add(WorkOrder(
                        brief_id=brief.id,
                        supplier_code=supplier_user.supplier_code,
                        created_at=utcnow(),
                        data={}
                    ))

        db.session.commit()

        yield Brief.query.all()
    def setup_dummy_brief_response(self,
                                   brief_id=None,
                                   supplier_id=0,
                                   submitted_at=datetime(2016, 1, 2),
                                   award_details=None):

        brief_response = BriefResponse(
            data=example_listings.brief_response_data().example(),
            supplier_id=supplier_id,
            brief_id=brief_id or self.brief_id,
            submitted_at=submitted_at,
            award_details=award_details if award_details else {})

        db.session.add(brief_response)
        db.session.commit()

        return brief_response.id
Ejemplo n.º 11
0
    def test_update_outcome_scenarios(
        self,
        other_oc_brief_based,
        initial_brief_based,
        other_oc_data,
        initial_data,
        put_values,
        expected_status_code,
        expected_response_data,
    ):
        """
        A number of arguments control the background context this test is run in and the parameters PUT to the endpoint.
        Not all of the combinations make sense together and a caller should not expect a test to pass with a nonsensical
        combination of arguments

        :param other_oc_brief_based:   whether the "other", existing Outcome should be Brief-based as opposed to
                                       Direct Award-based
        :param initial_brief_based:    whether the target Outcome should initially be set up to be Brief-based as
                                       opposed to Direct Award-based
        :param other_oc_data:          field values to set up the "other" Outcome with, ``None`` for no "other"
                                       Outcome to be created
        :param initial_data:           field values to initially set up the target Outcome with
        :param put_values:             payload dictionary to be PUT to the target endpoint (without the
                                       ``outcome`` wrapper)
        :param expected_status_code:
        :param expected_response_data:
        """
        user_id = self.setup_dummy_user(id=1, role='buyer')
        self.setup_dummy_suppliers(3)

        project = None
        search = None
        chosen_archived_service = other_archived_service = None
        if not (other_oc_brief_based and initial_brief_based):
            # create required objects for direct award-based Outcome
            self.setup_dummy_services(3, model=ArchivedService)

            project = DirectAwardProject(
                name="Lambay Island",
                users=[User.query.get(user_id)],
            )
            db.session.add(project)

            search = DirectAwardSearch(
                project=project,
                created_by=user_id,
                active=True,
                search_url="http://nothing.nowhere",
            )
            db.session.add(search)

            for archived_service in db.session.query(ArchivedService).filter(
                    ArchivedService.service_id.in_((
                        "2000000000",
                        "2000000001",
                    ))).all():
                search.archived_services.append(archived_service)

            chosen_archived_service, other_archived_service = search.archived_services[:
                                                                                       2]
        # else skip creating these to save time

        brief = None
        chosen_brief_response = other_brief_response = None
        if other_oc_brief_based or initial_brief_based:
            # create required objects for brief-based Outcome
            brief = self.setup_dummy_brief(status="closed",
                                           user_id=user_id,
                                           data={})
            chosen_brief_response, other_brief_response = (BriefResponse(
                brief=brief,
                supplier_id=i,
                submitted_at=datetime.datetime.utcnow(),
                data={},
            ) for i in (
                1,
                2,
            ))
            db.session.add(chosen_brief_response)
            db.session.add(other_brief_response)
        # else skip creating these to save time

        other_outcome = None
        if other_oc_data is not None:
            # create "other" Outcome for our target one to potentially clash with
            other_outcome = Outcome(
                **({
                    "brief": brief
                } if other_oc_brief_based else {
                    "direct_award_project": project
                }),
                **(
                    {
                        "result":
                        other_oc_data.get("result", "awarded"),
                        **({
                            "brief_response": other_brief_response,
                        } if other_oc_brief_based else {
                               "direct_award_search":
                               search,
                               "direct_award_archived_service":
                               other_archived_service,
                           }),
                    } if other_oc_data.get(
                        "result", "awarded") == "awarded" else {
                            "result": other_oc_data["result"]
                        }),
                **{
                    k: v
                    for k, v in (other_oc_data or {}).items() if k not in (
                        "completed_at",
                        "result",
                    )
                },
            )
            if "completed_at" in other_oc_data:
                other_outcome.completed_at = other_oc_data["completed_at"]
            db.session.add(other_outcome)

        # create our target Outcome in its initial state
        outcome = Outcome(
            **({
                "brief": brief
            } if initial_brief_based else {
                "direct_award_project": project
            }),
            **(
                {
                    "result":
                    initial_data.get("result", "awarded"),
                    **({
                        "brief_response": chosen_brief_response,
                    } if initial_brief_based else {
                           "direct_award_search":
                           search,
                           "direct_award_archived_service":
                           chosen_archived_service,
                       }),
                } if initial_data.get("result", "awarded") == "awarded" else {
                    "result": initial_data["result"]
                }),
            **{
                k: v
                for k, v in (initial_data or {}).items() if k not in (
                    "completed_at",
                    "result",
                )
            },
        )
        if "completed_at" in initial_data:
            # can only set completed_at after other fields have been set
            outcome.completed_at = initial_data["completed_at"]
        db.session.add(outcome)

        # must assign ids before we can lock project
        db.session.flush()
        if project:
            project.locked_at = datetime.datetime.now()

        # make a concrete note of these so we don't have to fetch them back from the database after the request,
        # potentially getting back values which have been inadvertantly changed
        outcome_external_id = outcome.external_id
        project_external_id = project and project.external_id
        search_id = search and search.id
        chosen_archived_service_id = chosen_archived_service and chosen_archived_service.id
        chosen_archived_service_service_id = chosen_archived_service and chosen_archived_service.service_id
        brief_id = brief and brief.id
        chosen_brief_response_id = chosen_brief_response and chosen_brief_response.id
        audit_event_count = AuditEvent.query.count()
        db.session.commit()

        # keep an nice concrete representation for later comparison
        outcome_serialization_before = outcome.serialize()

        res = self.client.put(
            f"/outcomes/{outcome.external_id}",
            data=json.dumps({
                "updated_by": "*****@*****.**",
                "outcome": put_values,
            }),
            content_type="application/json",
        )
        assert res.status_code == expected_status_code
        response_data = json.loads(res.get_data())
        assert response_data == expected_response_data

        # allow these to be re-used in this session, "refreshed"
        db.session.add_all(x for x in (
            outcome,
            project,
            search,
            chosen_archived_service,
        ) if x is not None)
        db.session.expire_all()

        if res.status_code != 200:
            # assert change wasn't made, audit event wasn't added
            assert outcome.serialize() == outcome_serialization_before
            assert AuditEvent.query.count() == audit_event_count
        else:
            # an additional check of values we should be able to figure out the "correct" values for
            assert response_data == {
                "outcome": {
                    "id": outcome_external_id,
                    "result": initial_data.get("result", "awarded"),
                    "completed": (
                        bool(outcome_serialization_before.get("completedAt"))
                        or put_values.get("completed") is True
                    ),
                    "completedAt": (
                        outcome_serialization_before.get("completedAt")
                        or (
                            AnyStringMatching(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z")
                            if put_values.get("completed") else None
                        )
                    ),
                    **({
                        "resultOfFurtherCompetition": {
                            "brief": {
                                "id": brief_id,
                            },
                            **({
                                "briefResponse": {
                                    "id": chosen_brief_response_id,
                                },
                            } if initial_data.get("result", "awarded") == "awarded" else {}),
                        },
                    } if initial_brief_based else {
                        "resultOfDirectAward": {
                            "project": {
                                "id": project_external_id,
                            },
                            **({
                                "search": {
                                    "id": search_id,
                                },
                                "archivedService": {
                                    "id": chosen_archived_service_id,
                                    "service": {
                                        "id": chosen_archived_service_service_id,
                                    },
                                },
                            } if initial_data.get("result", "awarded") == "awarded" else {})
                        },
                    }),
                    **({"award": AnySupersetOf({})} if initial_data.get("result", "awarded") == "awarded" else {}),
                }
            }

            # check changes actually got committed
            assert response_data == {
                "outcome": outcome.serialize(),
            }

            # check audit event(s) were saved
            expect_complete_audit_event = put_values.get(
                "completed") is True and not initial_data.get("completed_at")
            n_expected_new_audit_events = 2 if expect_complete_audit_event else 1

            assert AuditEvent.query.count(
            ) == audit_event_count + n_expected_new_audit_events
            # grab those most recent (1 or) 2 audit events from the db, re-sorting them to be in a predictable order -
            # we don't care whether the complete_outcome or update_outcome comes out of the db first
            audit_events = sorted(
                db.session.query(AuditEvent).order_by(
                    desc(AuditEvent.created_at),
                    desc(AuditEvent.id),
                )[:n_expected_new_audit_events],
                key=lambda ae: ae.type,
                reverse=True,
            )

            assert audit_events[0].type == "update_outcome"
            assert audit_events[0].object is outcome
            assert audit_events[0].acknowledged is False
            assert audit_events[0].acknowledged_at is None
            assert not audit_events[0].acknowledged_by
            assert audit_events[0].user == "*****@*****.**"
            assert audit_events[0].data == put_values

            if expect_complete_audit_event:
                assert audit_events[1].type == "complete_outcome"
                assert audit_events[1].created_at == audit_events[
                    0].created_at == outcome.completed_at
                assert audit_events[1].object is outcome
                assert audit_events[1].acknowledged is False
                assert audit_events[1].acknowledged_at is None
                assert not audit_events[1].acknowledged_by
                assert audit_events[1].user == "*****@*****.**"
                assert audit_events[1].data == {}
Ejemplo n.º 12
0
    def test_whitespace_is_stripped_from_brief_response_data(self):
        brief_response = BriefResponse(data={})
        brief_response.data = {'foo': ' bar ', 'bar': ['', '  foo']}

        assert brief_response.data == {'foo': 'bar', 'bar': ['foo']}
Ejemplo n.º 13
0
    def test_nulls_are_removed_from_brief_response_data(self):
        brief_response = BriefResponse(data={})
        brief_response.data = {'foo': 'bar', 'bar': None}

        assert brief_response.data == {'foo': 'bar'}
Ejemplo n.º 14
0
    def test_foreign_fields_are_removed_from_brief_response_data(self):
        brief_response = BriefResponse(data={})
        brief_response.data = {'foo': 'bar', 'briefId': 5, 'supplierId': 100}

        assert brief_response.data == {'foo': 'bar'}
    def setup_outcomes(self):
        user_id = self.setup_dummy_user(id=1, role='buyer')
        self.setup_dummy_suppliers(5)

        # create required objects for direct award-based Outcome
        self.setup_dummy_services(5, model=ArchivedService)

        #
        # create required objects for direct-award-related Outcomes
        #

        projects = tuple(
            DirectAwardProject(
                name=name,
                users=[User.query.get(user_id)],
            ) for name in ("alumno optimo", "palmam ferenti", "vere dignum et iustum est",)
        )
        db.session.add_all(projects)

        searches = tuple(
            DirectAwardSearch(
                project=project,
                created_by=user_id,
                active=True,
                search_url="http://nothing.nowhere",
            ) for project in projects
        )
        db.session.add_all(searches)

        for i, search in enumerate(searches):
            for archived_service in db.session.query(ArchivedService).filter(
                ArchivedService.service_id.in_([str(j) for j in range(2000000000 + i, 2000000000 + i + 3)])
            ).all():
                search.archived_services.append(archived_service)

        #
        # create required objects for Brief-related Outcomes
        #

        briefs = tuple(
            self.setup_dummy_brief(status="closed", user_id=user_id, data={})
            for _ in range(4)
        )
        db.session.add_all(briefs)
        # increasingly many BriefResponses for each Brief in `briefs`
        brief_responses = tuple(BriefResponse(
            brief=brief,
            supplier_id=j,
            submitted_at=datetime.datetime.utcnow(),
            data={},
        ) for j in range(i) for i, brief in enumerate(briefs))
        db.session.add_all(brief_responses)

        outcomes = (
            Outcome(
                external_id=100000000,
                direct_award_project=searches[0].project,
                direct_award_search=searches[0],
                direct_award_archived_service=searches[0].archived_services[0],
                result="awarded",
                start_date=datetime.date(2006, 2, 2),
                end_date=datetime.date(2006, 3, 3),
                awarding_organisation_name="Omnium Gatherum",
                award_value=81396,
                completed_at=datetime.datetime(2005, 10, 10, 10, 10, 10),
            ),
            Outcome(
                external_id=100000005,
                direct_award_project=searches[0].project,
                direct_award_search=searches[0],
                direct_award_archived_service=searches[0].archived_services[1],
                result="awarded",
                start_date=datetime.date(2006, 4, 4),
                awarding_organisation_name="Nisus Formativus",
            ),
            Outcome(
                external_id=100000002,
                direct_award_project=searches[0].project,
                result="none-suitable",
            ),
            Outcome(
                external_id=100000011,
                direct_award_project=searches[1].project,
                result="none-suitable",
            ),
            Outcome(
                external_id=100000004,
                direct_award_project=searches[2].project,
                result="cancelled",
                completed_at=datetime.datetime(2005, 10, 9, 9, 9, 9),
            ),
            Outcome(
                external_id=100000001,
                brief=briefs[0],
                result="cancelled",
                completed_at=datetime.datetime(2005, 5, 5, 5, 5, 5),
            ),
            Outcome(
                external_id=100000008,
                brief=briefs[0],
                result="cancelled",
            ),
            Outcome(
                external_id=100000012,
                brief=briefs[1],
                brief_response=briefs[1].brief_responses[0],
                result="awarded",
                start_date=datetime.date(2010, 1, 1),
                end_date=datetime.date(2011, 8, 8),
                awarding_organisation_name="Viridum Toxicum",
                award_value=81396,
                completed_at=datetime.datetime(2005, 11, 11, 11, 11, 11),
            ),
            Outcome(
                external_id=100000006,
                brief=briefs[1],
                brief_response=briefs[1].brief_responses[0],
                result="awarded",
                award_value=83300,
            ),
            Outcome(
                external_id=100000009,
                brief=briefs[2],
                result="none-suitable",
                completed_at=datetime.datetime(2005, 10, 10, 10, 11, 11),
            ),
            Outcome(
                external_id=100000013,
                brief=briefs[2],
                brief_response=briefs[2].brief_responses[0],
                result="awarded",
                start_date=datetime.date(2011, 1, 1),
                end_date=datetime.date(2011, 1, 2),
                award_value=3072,
            ),
            Outcome(
                external_id=100000003,
                brief=briefs[2],
                brief_response=briefs[2].brief_responses[1],
                result="awarded",
            ),
            Outcome(
                external_id=100000007,
                brief=briefs[3],
                result="none-suitable",
            ),
            Outcome(
                external_id=100000010,
                brief=briefs[3],
                brief_response=briefs[3].brief_responses[0],
                result="awarded",
                start_date=datetime.date(2006, 1, 1),
                end_date=datetime.date(2008, 1, 1),
                awarding_organisation_name="Lacus Mortis",
                award_value=4386035,
                completed_at=datetime.datetime(2006, 1, 1, 1, 1, 1),
            ),
        )
        db.session.add_all(outcomes)

        db.session.commit()
    def digital_professional_responses(self, app, briefs, brief_response_data,
                                       suppliers):
        with app.app_context():
            brief_response = BriefResponse(id=1,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=1)

            brief_response.data['specialistName'] = 'Klay Thompson'
            db.session.add(brief_response)

            brief_response = BriefResponse(id=2,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=1)

            brief_response.data['specialistName'] = 'steph curry'
            db.session.add(brief_response)

            brief_response = BriefResponse(id=3,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=1)

            brief_response.data['specialistName'] = 'kevin durant'
            db.session.add(brief_response)

            brief_response = BriefResponse(id=4,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=2)

            db.session.add(brief_response)

            brief_response = BriefResponse(id=5,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=3)

            db.session.add(brief_response)

            brief_response = BriefResponse(id=6,
                                           brief_id=1,
                                           data=brief_response_data,
                                           submitted_at=pendulum.now(),
                                           supplier_code=4)

            db.session.add(brief_response)

            db.session.commit()
            yield db.session.query(BriefResponse).all()