Exemple #1
0
def get_previous_evidence_and_feedback(evidence_id):
    evidence = evidence_service.get_evidence_by_id(evidence_id)
    if not evidence:
        abort(404)
    if evidence.status not in ['assessed', 'rejected']:
        abort(404)
    evidence_data = evidence.serialize()
    if evidence_data:
        domain_criteria = domain_criteria_service.get_criteria_by_domain_id(evidence_data['domainId'])
        evidence_data['domain_criteria'] = [x.serialize() for x in domain_criteria]
        evidence_data['domain_price_maximum'] = evidence.domain.price_maximum
        feedback = evidence_assessment_service.find(evidence_id=evidence.id).one_or_none()
        if feedback:
            evidence_data['feedback'] = feedback.serialize()
            assessor = users.find(id=int(feedback.user_id)).one_or_none()
            evidence_data['assessor'] = assessor.name if assessor else ''
        evidence_data['domainName'] = evidence.domain.name
        supplier = suppliers.get_supplier_by_code(evidence.supplier_code)
        evidence_data['supplierName'] = supplier.name if supplier else ''
        try:
            evidence_data['criteriaNeeded'] = int(
                DomainCriteria(
                    domain_id=evidence_data.get('domainId', None),
                    rate=evidence_data.get('maxDailyRate', None)
                ).get_criteria_needed()
            )
        except DomainCriteriaInvalidRateException as e:
            abort(400, str(e))
    return jsonify(evidence=evidence_data), 200
def decline_agreement(user_info):
    supplier_code = user_info.get('supplier_code')
    email_address = user_info.get('email_address')

    supplier = suppliers.get_supplier_by_code(supplier_code)
    mandatory_supplier_checks(supplier)

    if email_address != supplier.data.get('email'):
        raise UnauthorisedError('Unauthorised to decline agreement')

    supplier_users = users.find(supplier_code=supplier_code).all()
    supplier.status = 'deleted'
    for user in supplier_users:
        user.active = False
        users.add_to_session(user)

    users.commit_changes()
    suppliers.save(supplier)

    send_decline_master_agreement_email(supplier.code)

    publish_tasks.supplier.delay(publish_tasks.compress_supplier(supplier),
                                 'declined_agreement',
                                 updated_by=email_address)

    audit_service.log_audit_event(
        audit_type=audit_types.declined_master_agreement,
        user=email_address,
        data={
            'supplierCode': supplier.code,
            'supplierData': supplier.data
        },
        db_object=supplier)
Exemple #3
0
def update_brief_add_rfx_seller(brief_id, supplier_code):
    updater_json = validate_and_return_updater_request()
    # Using the helper.py methods to get the matching brief.
    brief = briefs.get(brief_id)
    supplier = suppliers.get_supplier_by_code(supplier_code)

    if not supplier:
        raise ValidationError("No supplier found: " + supplier_code)
    sellers = brief.data['sellers']
    sellers[str(supplier_code)] = {'name': supplier.name}
    brief.data['sellers'] = sellers
    audit = AuditEvent(
        audit_type=AuditTypes.seller_added_to_rfx_opportunity_admin,
        user=updater_json['updated_by'],
        data={
            'briefId': brief.id,
            'supplier_code': supplier_code,
        },
        db_object=brief,
    )

    db.session.add(brief)
    db.session.add(audit)
    db.session.commit()

    return jsonify(briefs=brief.serialize(with_users=True)), 200
Exemple #4
0
def get_supplier_messages(code, skip_application_check):
    applications = application_service.find(
        supplier_code=code,
        type='edit'
    ).all()

    supplier = suppliers.get_supplier_by_code(code)
    validation_result = SupplierValidator(supplier).validate_all()

    if any([a for a in applications if a.status == 'saved']):
        validation_result.warnings.append({
            'message': 'You have saved updates on your profile. '
                       'You must submit these changes to the Marketplace for review. '
                       'If you did not make any changes, select \'Discard all updates\'.',
            'severity': 'warning',
            'step': 'update',
            'id': 'SB001'
        })

    if not skip_application_check:
        if any([a for a in applications if a.status == 'submitted']):
            del validation_result.warnings[:]
            del validation_result.errors[:]

    if not has_signed_current_agreement(supplier):
        if get_current_agreement():
            message = (
                'Your authorised representative {must accept the new Master Agreement} '
                'before you can apply for opportunities.'
            )
            validation_result.errors.append({
                'message': message,
                'severity': 'error',
                'step': 'representative',
                'id': 'SB002',
                'links': {
                    'must accept the new Master Agreement': '/2/seller-edit/{}/representative'.format(code)
                }
            })
    else:
        new_master_agreement = get_new_agreement()
        if new_master_agreement:
            start_date = new_master_agreement.start_date.in_tz('Australia/Canberra').date()
            message = (
                'From {}, your authorised representative must '
                'accept the new Master Agreement '
                'before you can apply for opportunities.'
            ).format(start_date.strftime('%-d %B %Y'))

            validation_result.warnings.append({
                'message': message,
                'severity': 'warning',
                'step': 'representative',
                'id': 'SB002'
            })

    return validation_result
Exemple #5
0
    def approve_domain(self):

        supplier = suppliers.get_supplier_by_code(self.evidence.supplier_code)
        if not supplier:
            raise DomainApprovalException('Invalid suppier code in evidence')

        domain = domain_service.find(id=self.evidence.domain_id).one_or_none()
        if not domain:
            raise DomainApprovalException('Invalid domain id in evidence')

        # insert the supplier_domain as assessed for this supplier and domain
        supplier_domain_service.set_supplier_domain_status(
            supplier.id,
            domain.id,
            'assessed',
            'approved',
            do_commit=False
        )

        # set the evidence as approved
        self.evidence.approve()
        evidence_service.save_evidence(self.evidence, do_commit=False)

        # update the supplier's pricing for the evidence's domain
        supplier_data = supplier.data.copy()
        if 'pricing' not in supplier_data:
            supplier_data['pricing'] = {}
        supplier_data['pricing'][domain.name] = {'maxPrice': str(self.evidence.data['maxDailyRate'])}
        supplier.data.update({'pricing': supplier_data['pricing']})
        suppliers.save_supplier(supplier, do_commit=False)

        # create the evidence assessment outcome
        evidence_assessment = evidence_assessment_service.create_assessment(
            evidence_id=self.evidence.id,
            user_id=self.actioned_by,
            status='approved',
            do_commit=False
        )

        self.__commit()

        try:
            publish_tasks.evidence.delay(
                publish_tasks.compress_evidence(self.evidence),
                'approved',
                actioned_by=self.actioned_by,
                evidence_assessment=evidence_assessment.serialize(),
                domain=domain.name,
                supplier_code=supplier.code
            )
        except Exception as e:
            pass

        return evidence_assessment
Exemple #6
0
 def validate_sellers(self):
     if not self.data['sellers']:
         return False
     if not len(self.data['sellers']) > 0:
         return False
     for supplier_code in self.data['sellers']:
         supplier = suppliers.get_supplier_by_code(int(supplier_code))
         if not supplier:
             return False
         if suppliers.get_supplier_assessed_status(supplier.id, int(self.data['sellerCategory'])) != 'assessed':
             return False
     return True
 def validate_sellers(self):
     if not self.data['sellers']:
         return False
     if not len(self.data['sellers']) > 0:
         return False
     for supplier_code in self.data['sellers']:
         supplier = suppliers.get_supplier_by_code(int(supplier_code))
         if not supplier:
             return False
         if suppliers.get_supplier_assessed_status(supplier.id, int(self.data['sellerCategory'])) != 'assessed':
             return False
     return True
Exemple #8
0
def send_notify_auth_rep_email(supplier_code):
    from app.api.services import (
        audit_service,
        audit_types,
        suppliers,
        key_values_service
    )

    supplier = suppliers.get_supplier_by_code(supplier_code)
    to_address = supplier.data.get('email', '').encode('utf-8')

    agreement = get_new_agreement()
    if agreement is None:
        agreement = get_current_agreement()

    start_date = pendulum.now('Australia/Canberra').date()
    if agreement:
        start_date = agreement.start_date.in_tz('Australia/Canberra')

    # prepare copy
    email_body = render_email_template(
        'seller_edit_notify_auth_rep.md',
        ma_start_date=start_date.strftime('%-d %B %Y'),
        supplier_name=supplier.name,
        supplier_code=supplier.code,
        auth_rep_name=escape_markdown(supplier.data.get('representative', '')),
        frontend_url=current_app.config['FRONTEND_ADDRESS']
    )

    subject = "Accept the Master Agreement for the Digital Marketplace"

    send_or_handle_error(
        to_address,
        email_body,
        subject,
        current_app.config['DM_GENERIC_NOREPLY_EMAIL'],
        current_app.config['DM_GENERIC_SUPPORT_NAME'],
        event_description_for_errors='notify auth rep email'
    )

    audit_service.log_audit_event(
        audit_type=audit_types.notify_auth_rep_accept_master_agreement,
        user='',
        data={
            "to_address": to_address,
            "email_body": email_body,
            "subject": subject
        },
        db_object=supplier)
def notify_auth_rep(user_info):
    supplier_code = user_info.get('supplier_code')
    email_address = user_info.get('email_address')

    supplier = suppliers.get_supplier_by_code(supplier_code)
    mandatory_supplier_checks(supplier)

    send_notify_auth_rep_email(supplier.code)

    audit_service.log_audit_event(
        audit_type=audit_types.notify_auth_rep_accept_master_agreement,
        user=email_address,
        data={
            'supplierCode': supplier.code,
            'supplierData': supplier.data
        },
        db_object=supplier)
 def __init__(self, brief, current_user):
     self.brief = brief
     self.current_user = current_user
     self.supplier = None
     self.supplier_code = None
     self.user_role = current_user.role if hasattr(current_user, 'role') else None
     self.brief_category = None
     self.brief_domain = None
     self.invited_sellers = {}
     if self.user_role == 'supplier' and hasattr(current_user, 'supplier_code'):
         self.supplier_code = current_user.supplier_code
         self.supplier = suppliers.get_supplier_by_code(self.supplier_code)
     if brief:
         self.brief_category = self.brief.data.get('sellerCategory', '')
         self.brief_domain = (
             domain_service.get_by_name_or_id(int(self.brief_category)) if self.brief_category else None
         )
         self.invited_sellers = self.brief.data['sellers'] if 'sellers' in self.brief.data else {}
def get_supplier_edit_info(user_info):
    supplier_code = user_info.get('supplier_code')
    email_address = user_info.get('email_address')

    supplier = suppliers.get_supplier_by_code(supplier_code)

    agreementStatus = get_agreement_status(supplier, user_info)
    return {
        'supplier': {
            'name': supplier.name,
            'code': supplier.code,
            'abn': supplier.abn,
            'data': {
                'representative': supplier.data.get('representative'),
                'email': supplier.data.get('email'),
                'phone': supplier.data.get('phone')
            }
        },
        'agreementStatus': agreementStatus
    }
Exemple #12
0
 def __init__(self, brief, current_user):
     self.brief = brief
     self.current_user = current_user
     self.supplier = None
     self.supplier_code = None
     self.user_role = current_user.role if hasattr(current_user,
                                                   'role') else None
     self.brief_category = None
     self.brief_domain = None
     self.invited_sellers = {}
     if self.user_role == 'supplier' and hasattr(current_user,
                                                 'supplier_code'):
         self.supplier_code = current_user.supplier_code
         self.supplier = suppliers.get_supplier_by_code(self.supplier_code)
     if brief:
         self.brief_category = self.brief.data.get('sellerCategory', '')
         self.brief_domain = (domain_service.get_by_name_or_id(
             int(self.brief_category)) if self.brief_category else None)
         self.invited_sellers = self.brief.data[
             'sellers'] if 'sellers' in self.brief.data else {}
def accept_agreement(user_info):
    supplier_code = user_info.get('supplier_code')
    email_address = user_info.get('email_address')
    user_id = user_info.get('user_id')

    supplier = suppliers.get_supplier_by_code(supplier_code)
    mandatory_supplier_checks(supplier)

    if email_address != supplier.data.get('email'):
        raise UnauthorisedError('Unauthorised to accept agreement')

    agreement = get_current_agreement()
    if agreement is None:
        raise NotFoundError('Current master agreement not found')

    already_signed = signed_agreement_service.first(
        agreement_id=agreement.id, supplier_code=supplier_code)
    if already_signed:
        raise ValidationError('Already signed agreement')

    signed_agreement = SignedAgreement(
        agreement_id=agreement.id,
        user_id=user_id,
        signed_at=pendulum.now('Australia/Canberra'),
        supplier_code=supplier_code)
    signed_agreement_service.save(signed_agreement)

    publish_tasks.supplier.delay(publish_tasks.compress_supplier(supplier),
                                 'accepted_agreement',
                                 updated_by=email_address)

    audit_service.log_audit_event(
        audit_type=audit_types.accepted_master_agreement,
        user=email_address,
        data={
            'supplierCode': supplier.code,
            'supplierData': supplier.data
        },
        db_object=supplier)
Exemple #14
0
def send_decline_master_agreement_email(supplier_code):
    from app.api.services import (
        audit_service,
        audit_types,
        suppliers
    )

    supplier = suppliers.get_supplier_by_code(supplier_code)
    to_addresses = [
        e['email_address']
        for e in suppliers.get_supplier_contacts(supplier_code)
    ]

    # prepare copy
    email_body = render_email_template(
        'seller_edit_decline.md',
        frontend_url=current_app.config['FRONTEND_ADDRESS']
    )

    subject = "You declined the new Master Agreement"

    send_or_handle_error(
        to_addresses,
        email_body,
        subject,
        current_app.config['DM_GENERIC_NOREPLY_EMAIL'],
        current_app.config['DM_GENERIC_SUPPORT_NAME'],
        event_description_for_errors='declined master agreement email'
    )

    audit_service.log_audit_event(
        audit_type=audit_types.declined_master_agreement_email,
        user='',
        data={
            "to_address": to_addresses,
            "email_body": email_body,
            "subject": subject
        },
        db_object=supplier)
Exemple #15
0
def get_categories():
    """Supplier dashboard (Categories) (role=supplier)
    ---
    tags:
      - dashboard
    definitions:
      SellerDashboardCategoryItems:
        type: object
        properties:
            categories:
              type: array
              items:
                $ref: '#/definitions/SellerDashboardCategoryItem'
      SellerDashboardCategoryItem:
        type: object
        properties:
          id:
            type: number
          name:
            type: string
          status:
            type: string
          is_approved:
            type: boolean
          evidence_id:
            type: number
    responses:
      200:
        description: Seller dashboard data for the 'Categories' tab
        schema:
          $ref: '#/definitions/SellerDashboardCategoryItems'
    """
    categories = []
    supplier = suppliers.get_supplier_by_code(current_user.supplier_code)
    for domain in domain_service.get_active_domains():
        is_approved = True if domain.name in supplier.assessed_domains else False
        data = {
            "id": domain.id,
            "name": domain.name,
            "previous_evidence_id": None,
            "evidence_id": None,
            "is_approved": is_approved
        }
        domain_evidence = evidence_service.get_latest_evidence_for_supplier_and_domain(
            domain.id,
            current_user.supplier_code,
        )
        if domain_evidence:
            previous_evidence = evidence_service.get_previous_submitted_evidence_for_supplier_and_domain(
                domain_evidence.id, domain.id, current_user.supplier_code)
            if previous_evidence and previous_evidence.status == 'rejected':
                data['previous_evidence_id'] = previous_evidence.id
            data['status'] = domain_evidence.status
            data['evidence_id'] = domain_evidence.id
        else:
            # is there a submitted case study assessment in progress?
            open_assessment = assessments.get_open_assessments(
                domain_id=domain.id, supplier_code=supplier.code)
            if open_assessment:
                data['status'] = 'submitted'
            else:
                assessed_status = suppliers.get_supplier_assessed_status(
                    supplier.id, domain.id)
                data[
                    'status'] = assessed_status if assessed_status else 'unassessed'

        # override the status as unassessed if the domain is not in the assessed domains
        if data['status'] == 'assessed' and not is_approved:
            data['status'] = 'unassessed'

        data['rate'] = suppliers.get_supplier_max_price_for_domain(
            current_user.supplier_code, domain.name)

        categories.append(data)

        # sort by status
        categories_sorted = []
        categories_sorted += [
            x for x in categories if x['status'] == 'rejected'
        ]
        categories_sorted += [x for x in categories if x['status'] == 'draft']
        categories_sorted += [
            x for x in categories if x['status'] == 'submitted'
        ]
        categories_sorted += [
            x for x in categories if x['status'] == 'assessed'
        ]
        categories_sorted += [
            x for x in categories if x['status'] == 'unassessed'
        ]

    return jsonify(categories={'items': categories_sorted}), 200
def edit_opportunity(user_id, brief_id, edits):
    brief = brief_service.get(brief_id)
    if not brief:
        raise NotFoundError('Opportunity {} does not exist'.format(brief_id))

    if not brief_service.has_permission_to_brief(user_id, brief_id):
        raise UnauthorisedError(
            'Not authorised to edit opportunity {}'.format(brief_id))

    if brief.status != 'live':
        raise BriefError('Unable to edit opportunity {}'.format(brief_id))

    user = user_service.get(user_id)
    if not user:
        raise NotFoundError('User {} does not exist'.format(user_id))

    previous_data = copy.deepcopy(brief.data)
    previous_data['closed_at'] = brief.closed_at.to_iso8601_string(
        extended=True)

    edit_title(brief, edits['title'])
    edit_summary(brief, edits['summary'])
    edit_closing_date(brief, edits['closingDate'])

    if 'documentsEdited' in edits and edits['documentsEdited']:
        if 'attachments' in edits:
            edit_attachments(brief, edits['attachments'])
        if 'requirementsDocument' in edits and 'requirementsDocument' in brief.data:
            edit_requirements_document(brief, edits['requirementsDocument'])
        if 'responseTemplate' in edits and 'responseTemplate' in brief.data:
            edit_response_template(brief, edits['responseTemplate'])

    organisation = None
    sellers_to_contact = []
    if (title_was_edited(brief.data['title'], previous_data['title']) or
            summary_was_edited(brief.data['summary'], previous_data['summary'])
            or closing_date_was_edited(
                brief.closed_at.to_iso8601_string(extended=True),
                previous_data['closed_at'])
            or documents_were_edited(brief.data.get('attachments', []),
                                     previous_data.get('attachments', []))
            or documents_were_edited(
                brief.data.get('requirementsDocument', []),
                previous_data.get('requirementsDocument', [])) or
            documents_were_edited(brief.data.get('responseTemplate', []),
                                  previous_data.get('responseTemplate', []))):
        organisation = agency_service.get_agency_name(user.agency_id)
        # We need to find sellers to contact about the current incoming edits before sellers are edited as we're
        # not sending additional sellers emails about the current edits that have been made.
        sellers_to_contact = brief_service.get_sellers_to_notify(
            brief, brief_business.is_open_to_all(brief))

    sellers_to_invite = {}
    if 'sellers' in edits and sellers_were_edited(
            edits['sellers'], brief.data.get('sellers', {})):
        sellers_to_invite = get_sellers_to_invite(brief, edits['sellers'])
        edit_sellers(brief, sellers_to_invite)
        edit_seller_selector(brief, sellers_to_invite)

    # strip out any data keys not whitelisted
    brief = brief_business.remove_keys_not_whitelisted(brief)

    data_to_validate = copy.deepcopy(brief.data)
    # only validate the sellers being added in the edit
    if 'sellers' in edits and len(edits['sellers'].keys()) > 0:
        data_to_validate['sellers'] = copy.deepcopy(edits.get('sellers', {}))

    validator = None
    if brief.lot.slug == 'rfx':
        validator = RFXDataValidator(data_to_validate)
    elif brief.lot.slug == 'training2':
        validator = TrainingDataValidator(data_to_validate)
    elif brief.lot.slug == 'atm':
        validator = ATMDataValidator(data_to_validate)
    elif brief.lot.slug == 'specialist':
        validator = SpecialistDataValidator(data_to_validate)

    if validator is None:
        raise ValidationError('Validator not found for {}'.format(
            brief.lot.slug))

    errors = []
    if (title_was_edited(brief.data['title'], previous_data['title'])
            and not validator.validate_title()):
        errors.append('You must add a title')

    if (summary_was_edited(brief.data['summary'], previous_data['summary'])
            and not validator.validate_summary()):
        message = ('You must add what the specialist will do'
                   if brief.lot.slug == 'specialist' else
                   'You must add a summary of work to be done')

        errors.append(message)

    if (brief.lot.slug != 'atm' and 'sellers' in edits and sellers_were_edited(
            edits['sellers'], brief.data.get('sellers', {}))
            and not validator.validate_sellers()):
        message = (
            'You must select some sellers'
            if brief.lot.slug == 'specialist' else
            'You must select at least one seller and each seller must be assessed for the chosen category'
        )

        errors.append(message)

    if (closing_date_was_edited(
            brief.closed_at.to_iso8601_string(extended=True),
            previous_data['closed_at'])
            and not validator.validate_closed_at(minimum_days=1)):
        message = (
            'The closing date must be at least 1 day into the future or not more than one year long'
            if brief.lot.slug == 'specialist' else
            'The closing date must be at least 1 day into the future')

        errors.append(message)

    if len(errors) > 0:
        raise ValidationError(', '.join(errors))

    brief_service.save(brief, do_commit=False)

    edit = BriefHistory(brief_id=brief.id, user_id=user_id, data=previous_data)

    brief_history_service.save(edit, do_commit=False)
    brief_service.commit_changes()

    if len(sellers_to_contact) > 0 and organisation:
        for email_address in sellers_to_contact:
            send_opportunity_edited_email_to_seller(brief, email_address,
                                                    organisation)

    for code, data in sellers_to_invite.items():
        supplier = supplier_service.get_supplier_by_code(code)
        if supplier:
            if brief.lot.slug == 'rfx':
                send_seller_invited_to_rfx_email(brief, supplier)
            elif brief.lot.slug == 'specialist':
                send_specialist_brief_seller_invited_email(brief, supplier)
            elif brief.lot.slug == 'training':
                send_seller_invited_to_training_email(brief, supplier)

    send_opportunity_edited_email_to_buyers(brief, user, edit)

    try:
        audit_service.log_audit_event(
            audit_type=audit_types.opportunity_edited,
            data={'briefId': brief.id},
            db_object=brief,
            user=user.email_address)

        publish_tasks.brief.delay(publish_tasks.compress_brief(brief),
                                  'edited',
                                  email_address=user.email_address,
                                  name=user.name)
    except Exception as e:
        rollbar.report_exc_info()

    return brief
Exemple #17
0
def create_evidence(domain_id, brief_id=None):
    """Create evidence (role=supplier)
    ---
    tags:
        - evidence
    definitions:
        EvidenceCreated:
            type: object
            properties:
                id:
                    type: number
                domain_id:
                    type: number
                supplier_code:
                    type: number
    responses:
        200:
            description: Evidence created successfully.
            schema:
                $ref: '#/definitions/EvidenceCreated'
        400:
            description: Bad request.
        403:
            description: Unauthorised to create evidence.
        500:
            description: Unexpected error.
    """
    domain = domain_service.get_by_name_or_id(domain_id, show_legacy=False)
    if not domain:
        abort('Unknown domain id')

    supplier = suppliers.get_supplier_by_code(current_user.supplier_code)
    if supplier.data.get('recruiter', '') == 'yes':
        abort('Assessment can\'t be started against a recruiter only supplier')

    existing_evidence = evidence_service.get_latest_evidence_for_supplier_and_domain(
        domain_id, current_user.supplier_code)
    if domain.name in supplier.assessed_domains:
        abort('This supplier is already assessed for this domain')

    open_assessment = assessments.get_open_assessments(
        domain_id=domain_id, supplier_code=current_user.supplier_code)
    if open_assessment or (existing_evidence and existing_evidence.status
                           in ['draft', 'submitted']):
        abort(
            'This supplier already has a draft assessment or is awaiting assessment for this domain'
        )

    if brief_id:
        brief = briefs.find(id=brief_id).one_or_none()
        if not brief or brief.status != 'live':
            abort('Brief id does not exist or is not open for responses')

    try:
        data = {}

        if existing_evidence and existing_evidence.status == 'rejected':
            data = existing_evidence.data.copy()
        else:
            # does this supplier already have a max price for this domain set? if so, pre-populate
            current_max_price = suppliers.get_supplier_max_price_for_domain(
                current_user.supplier_code, domain.name)
            if current_max_price:
                data['maxDailyRate'] = int(current_max_price)

        evidence = evidence_service.create_evidence(domain_id,
                                                    current_user.supplier_code,
                                                    current_user.id,
                                                    brief_id=brief_id,
                                                    data=data)

    except Exception as e:
        rollbar.report_exc_info()
        abort(e.message)

    publish_tasks.evidence.delay(publish_tasks.compress_evidence(evidence),
                                 'created',
                                 name=current_user.name,
                                 domain=domain.name,
                                 supplier_code=current_user.supplier_code)

    return jsonify(evidence.serialize())
def get_categories():
    categories = []
    supplier = suppliers.get_supplier_by_code(current_user.supplier_code)
    for domain in domain_service.get_active_domains():
        is_approved = True if domain.name in supplier.assessed_domains else False
        data = {
            "id": domain.id,
            "name": domain.name,
            "previous_evidence_id": None,
            "evidence_id": None,
            "is_approved": is_approved
        }
        domain_evidence = evidence_service.get_latest_evidence_for_supplier_and_domain(
            domain.id,
            current_user.supplier_code,
        )
        if domain_evidence:
            previous_evidence = evidence_service.get_previous_submitted_evidence_for_supplier_and_domain(
                domain_evidence.id, domain.id, current_user.supplier_code)
            if previous_evidence and previous_evidence.status == 'rejected':
                data['previous_evidence_id'] = previous_evidence.id
            data['status'] = domain_evidence.status
            data['evidence_id'] = domain_evidence.id
        else:
            # is there a submitted case study assessment in progress?
            open_assessment = assessments.get_open_assessments(
                domain_id=domain.id, supplier_code=supplier.code)
            if open_assessment:
                data['status'] = 'submitted'
            else:
                assessed_status = suppliers.get_supplier_assessed_status(
                    supplier.id, domain.id)
                data[
                    'status'] = assessed_status if assessed_status else 'unassessed'

        # override the status as unassessed if the domain is not in the assessed domains
        if data['status'] == 'assessed' and not is_approved:
            data['status'] = 'unassessed'

        data['rate'] = suppliers.get_supplier_max_price_for_domain(
            current_user.supplier_code, domain.name)

        categories.append(data)

        # sort by status
        categories_sorted = []
        categories_sorted += [
            x for x in categories if x['status'] == 'rejected'
        ]
        categories_sorted += [x for x in categories if x['status'] == 'draft']
        categories_sorted += [
            x for x in categories if x['status'] == 'submitted'
        ]
        categories_sorted += [
            x for x in categories if x['status'] == 'assessed'
        ]
        categories_sorted += [
            x for x in categories if x['status'] == 'unassessed'
        ]

    return jsonify(categories={'items': categories_sorted}), 200
def update_brief(brief_id):
    """Update RFX brief (role=buyer)
    ---
    tags:
        - brief
    definitions:
        RFXBrief:
            type: object
            properties:
                title:
                    type: string
                organisation:
                    type: string
                location:
                    type: array
                    items:
                        type: string
                summary:
                    type: string
                industryBriefing:
                    type: string
                sellerCategory:
                    type: string
                sellers:
                    type: object
                attachments:
                    type: array
                    items:
                        type: string
                requirementsDocument:
                    type: array
                    items:
                        type: string
                responseTemplate:
                    type: array
                    items:
                        type: string
                evaluationType:
                    type: array
                    items:
                        type: string
                proposalType:
                    type: array
                    items:
                        type: string
                evaluationCriteria:
                    type: array
                    items:
                        type: object
                includeWeightings:
                    type: boolean
                closedAt:
                    type: string
                contactNumber:
                    type: string
                startDate:
                    type: string
                contractLength:
                    type: string
                contractExtensions:
                    type: string
                budgetRange:
                    type: string
                workingArrangements:
                    type: string
                securityClearance:
                    type: string
    parameters:
      - name: brief_id
        in: path
        type: number
        required: true
      - name: body
        in: body
        required: true
        schema:
            $ref: '#/definitions/RFXBrief'
    responses:
        200:
            description: Brief updated successfully.
            schema:
                $ref: '#/definitions/RFXBrief'
        400:
            description: Bad request.
        403:
            description: Unauthorised to update RFX brief.
        404:
            description: Brief not found.
        500:
            description: Unexpected error.
    """
    brief = briefs.get(brief_id)

    if not brief:
        not_found("Invalid brief id '{}'".format(brief_id))

    if brief.status != 'draft':
        abort('Cannot edit a {} brief'.format(brief.status))

    if brief.lot.slug not in ['rfx', 'atm']:
        abort('Brief lot not supported for editing')

    if current_user.role == 'buyer':
        brief_user_ids = [user.id for user in brief.users]
        if current_user.id not in brief_user_ids:
            return forbidden('Unauthorised to update brief')

    data = get_json_from_request()

    publish = False
    if 'publish' in data and data['publish']:
        del data['publish']
        publish = True

    if brief.lot.slug == 'rfx':
        # validate the RFX JSON request data
        errors = RFXDataValidator(data).validate(publish=publish)
        if len(errors) > 0:
            abort(', '.join(errors))

    if brief.lot.slug == 'atm':
        # validate the ATM JSON request data
        errors = ATMDataValidator(data).validate(publish=publish)
        if len(errors) > 0:
            abort(', '.join(errors))

    if brief.lot.slug == 'rfx' and 'evaluationType' in data:
        if 'Written proposal' not in data['evaluationType']:
            data['proposalType'] = []
        if 'Response template' not in data['evaluationType']:
            data['responseTemplate'] = []

    if brief.lot.slug == 'rfx' and 'sellers' in data and len(data['sellers']) > 0:
        data['sellerSelector'] = 'someSellers' if len(data['sellers']) > 1 else 'oneSeller'

    data['areaOfExpertise'] = ''
    if brief.lot.slug == 'atm' and 'openTo' in data:
        if data['openTo'] == 'all':
            data['sellerSelector'] = 'allSellers'
            data['sellerCategory'] = ''
        elif data['openTo'] == 'category':
            data['sellerSelector'] = 'someSellers'
            brief_domain = (
                domain_service.get_by_name_or_id(int(data['sellerCategory'])) if data['sellerCategory'] else None
            )
            if brief_domain:
                data['areaOfExpertise'] = brief_domain.name

    previous_status = brief.status
    if publish:
        brief.publish(closed_at=data['closedAt'])
        if 'sellers' in brief.data and data['sellerSelector'] != 'allSellers':
            for seller_code, seller in brief.data['sellers'].iteritems():
                supplier = suppliers.get_supplier_by_code(seller_code)
                if brief.lot.slug == 'rfx':
                    send_seller_invited_to_rfx_email(brief, supplier)
        try:
            brief_url_external = '{}/2/digital-marketplace/opportunities/{}'.format(
                current_app.config['FRONTEND_ADDRESS'],
                brief_id
            )
            _notify_team_brief_published(
                brief.data['title'],
                brief.data['organisation'],
                current_user.name,
                current_user.email_address,
                brief_url_external
            )
        except Exception as e:
            pass

    brief.data = data
    briefs.save_brief(brief)

    if publish:
        brief_url_external = '{}/2/digital-marketplace/opportunities/{}'.format(
            current_app.config['FRONTEND_ADDRESS'],
            brief_id
        )
        publish_tasks.brief.delay(
            publish_tasks.compress_brief(brief),
            'published',
            previous_status=previous_status,
            name=current_user.name,
            email_address=current_user.email_address,
            url=brief_url_external
        )
    try:
        audit_service.log_audit_event(
            audit_type=AuditTypes.update_brief,
            user=current_user.email_address,
            data={
                'briefId': brief.id,
                'briefData': brief.data
            },
            db_object=brief)
    except Exception as e:
        rollbar.report_exc_info()

    return jsonify(brief.serialize(with_users=False))
Exemple #20
0
def withdraw_brief_response(brief_response_id):
    """Withdraw brief responses (role=supplier)
    ---
    tags:
      - "Brief Response"
    security:
      - basicAuth: []
    parameters:
      - name: brief_response_id
        in: path
        type: number
        required: true
    responses:
      200:
        description: Successfully withdrawn a candidate
        schema:
          id: BriefResponse
      400:
        description: brief_response_id not found
    """
    brief_response = (brief_responses_service.find(
        id=brief_response_id,
        supplier_code=current_user.supplier_code).one_or_none())

    if brief_response:
        if brief_response.withdrawn_at is None:
            status_before_withdrawn = brief_response.status
            brief_response.withdrawn_at = utcnow()
            brief_responses_service.save(brief_response)

            try:
                audit = AuditEvent(
                    audit_type=audit_types.update_brief_response,
                    user=current_user.email_address,
                    data={
                        'briefResponseId': brief_response.id,
                        'withdrawn': True
                    },
                    db_object=brief_response)
                audit_service.save(audit)
            except Exception as e:
                extra_data = {
                    'audit_type': audit_types.update_brief_response,
                    'briefResponseId': brief_response.id
                }
                rollbar.report_exc_info(extra_data=extra_data)

            if status_before_withdrawn == 'submitted':
                brief = briefs.get(id=brief_response.brief_id)
                supplier = suppliers.get_supplier_by_code(
                    brief_response.supplier_code)
                if brief and supplier:
                    if brief.lot.slug == 'specialist':
                        send_specialist_brief_response_withdrawn_email(
                            supplier,
                            brief,
                            brief_response,
                            supplier_user=current_user.name)
                    else:
                        send_brief_response_withdrawn_email(
                            supplier,
                            brief,
                            brief_response,
                            supplier_user=current_user.name)

            publish_tasks.brief_response.delay(
                publish_tasks.compress_brief_response(brief_response),
                'withdrawn',
                user=current_user.email_address)
        else:
            abort(
                'Brief response with brief_response_id "{}" is already withdrawn'
                .format(brief_response_id))
    else:
        not_found(
            'Cannot find brief response with brief_response_id :{} and supplier_code: {}'
            .format(brief_response_id, current_user.supplier_code))

    return jsonify(briefResponses=brief_response.serialize()), 200