def validate_seller_category(self):
     if not self.validate_open_to():
         return False
     if self.data['openTo'] == 'all' and self.data['sellerCategory'] == '':
         return True
     if (self.data['openTo'] == 'category' and self.data['sellerCategory']
             and domain_service.get_by_name_or_id(
                 int(self.data['sellerCategory']))):
         return True
     return False
Exemplo n.º 2
0
def get_domain(domain_id):
    domain = domain_service.get_by_name_or_id(domain_id, show_legacy=False)
    if not domain:
        return not_found('Domain does not exist')

    data = domain.serialize()

    data['criteriaEnforcementCutoffDate'] = None
    key_value = key_values_service.get_by_key('criteria_enforcement_cutoff_date')
    if key_value:
        data['criteriaEnforcementCutoffDate'] = (
            pendulum.parse(key_value['data']['value'], tz='Australia/Canberra').isoformat()
        )

    return jsonify(data)
Exemplo n.º 3
0
    def __init__(self, data, evidence=None):
        self.data = data
        self.evidence = evidence
        self.max_criteria = 2
        if self.evidence:
            self.domain = domain_service.get_by_name_or_id(evidence.domain.id)
            self.domain_criteria = domain_criteria_service.get_criteria_by_domain_id(
                evidence.domain.id)

        self.criteria_enforcement_cutoff_date = None
        key_value = key_values_service.get_by_key(
            'criteria_enforcement_cutoff_date')
        if key_value:
            self.criteria_enforcement_cutoff_date = (pendulum.parse(
                key_value['data']['value'], tz='Australia/Canberra').date())
 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 {}
Exemplo n.º 5
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 get_domain(domain_id):
    domain = domain_service.get_by_name_or_id(domain_id, show_legacy=False)
    if not domain:
        return not_found('Domain does not exist')
    return jsonify(domain.serialize())
Exemplo n.º 7
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())
Exemplo n.º 8
0
def get_suppliers():
    """Suppliers search names by keyword
    ---
    tags:
        - suppliers
    definitions:
        SupplierMinimal:
            type: object
            properties:
                name:
                    type: string
                code:
                    type: integer
                panel:
                    type: boolean
                sme:
                    type: boolean
        Suppliers:
            type: object
            properties:
                sellers:
                    type: array
                    items:
                        $ref: '#/definitions/SupplierMinimal'
    parameters:
        - name: keyword
          in: query
          type: string
          required: true
          description: the keyword to search on
        - name: category
          in: query
          type: string
          required: false
          description: the seller category to filter on
    responses:
        200:
            description: a list of matching suppliers
            schema:
                $ref: '#/definitions/Suppliers'
        400:
            description: invalid request data, such as a missing keyword param
    """
    keyword = request.args.get('keyword') or ''
    category = request.args.get('category') or ''
    all_suppliers = request.args.get('all') or ''
    if keyword:
        results = suppliers.get_suppliers_by_name_keyword(keyword,
                                                          framework_slug='digital-marketplace',
                                                          category=category)
        supplier_results = []
        for result in results:
            if all_suppliers:
                supplier = {}
                supplier['name'] = result.name
                supplier['code'] = result.code
                supplier_results.append(supplier)
            elif len(result.assessed_domains) > 0:
                if category:
                    domain = domain_service.get_by_name_or_id(int(category))
                    if not domain or domain.name not in result.assessed_domains:
                        continue
                supplier = {}
                supplier['name'] = result.name
                supplier['code'] = result.code
                supplier_results.append(supplier)

        return jsonify(sellers=supplier_results), 200
    else:
        return jsonify(message='You must provide a keyword param.'), 400
Exemplo n.º 9
0
 def __init__(self, data, evidence=None):
     self.data = data
     self.evidence = evidence
     if self.evidence:
         self.domain = domain_service.get_by_name_or_id(evidence.domain.id)
         self.domain_criteria = domain_criteria_service.get_criteria_by_domain_id(evidence.domain.id)
Exemplo n.º 10
0
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))
Exemplo n.º 11
0
def _can_do_brief_response(brief_id):
    try:
        brief = Brief.query.get(brief_id)
    except DataError:
        brief = None

    if brief is None:
        abort("Invalid brief ID '{}'".format(brief_id))

    if brief.status != 'live':
        abort("Brief must be live")

    if brief.framework.status != 'live':
        abort("Brief framework must be live")

    if not hasattr(current_user, 'role') or current_user.role != 'supplier':
        forbidden("Only supplier role users can respond to briefs")

    try:
        supplier = Supplier.query.filter(
            Supplier.code == current_user.supplier_code
        ).first()
    except DataError:
        supplier = None

    if not supplier:
        forbidden("Invalid supplier Code '{}'".format(current_user.supplier_code))

    validation_result = SupplierValidator(supplier).validate_all()
    if len(validation_result.errors) > 0:
        abort(validation_result.errors)

    def domain(email):
        return email.split('@')[-1]

    current_user_domain = domain(current_user.email_address) \
        if domain(current_user.email_address) not in current_app.config.get('GENERIC_EMAIL_DOMAINS') \
        else None

    rfx_lot = lots_service.find(slug='rfx').one_or_none()
    rfx_lot_id = rfx_lot.id if rfx_lot else None

    atm_lot = lots_service.find(slug='atm').one_or_none()
    atm_lot_id = atm_lot.id if atm_lot else None

    is_selected = False
    seller_selector = brief.data.get('sellerSelector', '')
    open_to = brief.data.get('openTo', '')
    brief_category = brief.data.get('sellerCategory', '')
    brief_domain = domain_service.get_by_name_or_id(int(brief_category)) if brief_category else None

    if brief.lot_id == rfx_lot_id:
        if str(current_user.supplier_code) in brief.data['sellers'].keys():
            is_selected = True

    elif brief.lot_id == atm_lot_id:
        if seller_selector == 'allSellers' and len(supplier.assessed_domains) > 0:
            is_selected = True
        elif seller_selector == 'someSellers' and open_to == 'category' and brief_domain and\
                                brief_domain.name in supplier.assessed_domains:
            is_selected = True

    else:
        if not seller_selector or seller_selector == 'allSellers':
            is_selected = True
        elif seller_selector == 'someSellers':
            seller_domain_list = [domain(x).lower() for x in brief.data['sellerEmailList']]
            if current_user.email_address in brief.data['sellerEmailList'] \
               or (current_user_domain and current_user_domain.lower() in seller_domain_list):
                is_selected = True
        elif seller_selector == 'oneSeller':
            if current_user.email_address.lower() == brief.data['sellerEmail'].lower() \
               or (current_user_domain and current_user_domain.lower() == domain(brief.data['sellerEmail'].lower())):
                is_selected = True
    if not is_selected:
        forbidden("Supplier not selected for this brief")

    if (len(supplier.frameworks) == 0 or
            'digital-marketplace' != supplier.frameworks[0].framework.slug):

        abort("Supplier does not have Digital Marketplace framework")

    if len(supplier.assessed_domains) == 0:
        abort("Supplier does not have at least one assessed domain")
    else:
        training_lot = lots_service.find(slug='training').one_or_none()
        if brief.lot_id == training_lot.id:
            if 'Training, Learning and Development' not in supplier.assessed_domains:
                abort("Supplier needs to be assessed in 'Training, Learning and Development'")

    lot = lots_service.first(slug='digital-professionals')
    if brief.lot_id == lot.id:
        # Check the supplier can respond to the category
        brief_category = brief.data.get('areaOfExpertise', None)
        if brief_category and brief_category not in supplier.assessed_domains:
            abort("Supplier needs to be assessed in '{}'".format(brief_category))
        # Check if there are more than 3 brief response already from this supplier when professional aka specialists
        brief_response_count = brief_responses_service.find(supplier_code=supplier.code,
                                                            brief_id=brief.id,
                                                            withdrawn_at=None).count()
        if (brief_response_count > 2):  # TODO magic number
            abort("There are already 3 brief responses for supplier '{}'".format(supplier.code))
    else:
        # Check if brief response already exists from this supplier when outcome for all other types
        if brief_responses_service.find(supplier_code=supplier.code,
                                        brief_id=brief.id,
                                        withdrawn_at=None).one_or_none():
            abort("Brief response already exists for supplier '{}'".format(supplier.code))

    return supplier, brief
Exemplo n.º 12
0
def get_suppliers():
    """Suppliers search names by keyword
    ---
    tags:
        - suppliers
    definitions:
        SupplierMinimal:
            type: object
            properties:
                name:
                    type: string
                code:
                    type: integer
                panel:
                    type: boolean
                sme:
                    type: boolean
        Suppliers:
            type: object
            properties:
                sellers:
                    type: array
                    items:
                        $ref: '#/definitions/SupplierMinimal'
    parameters:
        - name: keyword
          in: query
          type: string
          required: true
          description: the keyword to search on
        - name: category
          in: query
          type: string
          required: false
          description: the seller category to filter on
    responses:
        200:
            description: a list of matching suppliers
            schema:
                $ref: '#/definitions/Suppliers'
        400:
            description: invalid request data, such as a missing keyword param
    """
    keyword = request.args.get('keyword') or ''
    category = request.args.get('category') or ''
    if keyword:
        results = suppliers.get_suppliers_by_name_keyword(keyword,
                                                          framework_slug='digital-marketplace',
                                                          category=category)
        supplier_results = []
        for result in results:
            if len(result.assessed_domains) > 0:
                if category:
                    domain = domain_service.get_by_name_or_id(int(category))
                    if not domain or domain.name not in result.assessed_domains:
                        continue
                supplier = {}
                supplier['name'] = result.name
                supplier['code'] = result.code
                supplier_results.append(supplier)

        return jsonify(sellers=supplier_results), 200
    else:
        return jsonify(message='You must provide a keyword param.'), 400
Exemplo n.º 13
0
def get_suppliers():
    """Suppliers search names by keyword
    ---
    tags:
        - suppliers
    definitions:
        SupplierMinimal:
            type: object
            properties:
                name:
                    type: string
                code:
                    type: integer
                panel:
                    type: boolean
                sme:
                    type: boolean
        Suppliers:
            type: object
            properties:
                sellers:
                    type: array
                    items:
                        $ref: '#/definitions/SupplierMinimal'
    parameters:
        - name: keyword
          in: query
          type: string
          required: true
          description: the keyword to search on
        - name: category
          in: query
          type: string
          required: false
          description: the seller category to filter on
    responses:
        200:
            description: a list of matching suppliers
            schema:
                $ref: '#/definitions/Suppliers'
        400:
            description: invalid request data, such as a missing keyword param
    """
    keyword = request.args.get('keyword') or ''
    category = request.args.get('category') or ''
    all_suppliers = request.args.get('all') or ''
    brief_id = request.args.get('briefId', None)

    brief = None
    if brief_id:
        brief = briefs.get(brief_id)

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

    exclude = json.loads(
        request.args.get('exclude')) if request.args.get('exclude') else []
    exclude_recruiters = True if brief and brief.lot.slug != 'specialist' else False
    supplier_codes_to_exclude = [int(code) for code in exclude]

    if keyword:
        results = suppliers.get_suppliers_by_name_keyword(
            keyword,
            framework_slug='digital-marketplace',
            category=category,
            exclude=supplier_codes_to_exclude,
            exclude_recruiters=exclude_recruiters)

        supplier_results = []
        for result in results:
            if all_suppliers:
                supplier = {}
                supplier['name'] = result.name
                supplier['code'] = result.code
                supplier_results.append(supplier)
            elif len(result.assessed_domains) > 0:
                if category:
                    domain = domain_service.get_by_name_or_id(int(category))
                    if not domain or domain.name not in result.assessed_domains:
                        continue
                supplier = {}
                supplier['name'] = result.name
                supplier['code'] = result.code
                supplier_results.append(supplier)

        return jsonify(sellers=supplier_results), 200
    else:
        return jsonify(message='You must provide a keyword param.'), 400