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
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)
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 {}
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())
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_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
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)
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))
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
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
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