def test_count_unanswered_questions(self): brief = { 'status': 'draft', 'frameworkSlug': 'dos', 'lotSlug': 'digital-specialists', 'required1': True } content = content_loader.get_manifest('dos', 'edit_brief').filter( {'lot': 'digital-specialists'}) sections = content.summary(brief) unanswered_required, unanswered_optional = buyers_helpers.count_unanswered_questions( sections) assert unanswered_required == 2 assert unanswered_optional == 2
def view_brief_overview(framework_slug, lot_slug, brief_id): if lot_slug == 'digital-professionals' or lot_slug == 'training': return redirect('/2/brief/{}/overview'.format(brief_id)) if lot_slug in ['rfx', 'atm', 'specialist', 'training2']: return redirect('/2/brief/{}/overview/{}'.format(brief_id, lot_slug)) framework, lot = get_framework_and_lot(framework_slug, lot_slug, data_api_client, status='live', must_allow_brief=True) brief = data_api_client.get_brief(brief_id)["briefs"] if not is_brief_correct(brief, framework_slug, lot_slug, current_user.id, data_api_client) and not allowed_email_domain( current_user.id, brief, data_api_client): abort(404) content = content_loader.get_manifest( brief['frameworkSlug'], 'edit_brief').filter({'lot': brief['lotSlug']}) sections = content.summary(brief) delete_requested = True if request.args.get('delete_requested') else False completed_sections = {} for section in sections: required, optional = count_unanswered_questions([section]) if section_has_at_least_one_required_question(section): completed_sections[section.slug] = True if required == 0 else False else: completed_sections[section.slug] = True if optional == 0 else False brief['clarificationQuestions'] = [ dict(question, number=index + 1) for index, question in enumerate(brief['clarificationQuestions']) ] return render_template_with_csrf( "buyers/brief_overview.html", framework=framework, confirm_remove=request.args.get("confirm_remove", None), brief=brief, sections=sections, completed_sections=completed_sections, step_sections=[ section.step for section in sections if hasattr(section, 'step') ], delete_requested=delete_requested, )
def view_brief_overview(framework_slug, lot_slug, brief_id): if lot_slug == 'digital-professionals' or lot_slug == 'training': return redirect('/2/brief/{}/overview'.format(brief_id)) if lot_slug in ['rfx', 'atm']: return redirect('/2/brief/{}/overview/{}'.format(brief_id, lot_slug)) framework, lot = get_framework_and_lot( framework_slug, lot_slug, data_api_client, status='live', must_allow_brief=True) brief = data_api_client.get_brief(brief_id)["briefs"] if not is_brief_correct( brief, framework_slug, lot_slug, current_user.id ) and not allowed_email_domain(current_user.id, brief, data_api_client): abort(404) content = content_loader.get_manifest(brief['frameworkSlug'], 'edit_brief').filter({'lot': brief['lotSlug']}) sections = content.summary(brief) delete_requested = True if request.args.get('delete_requested') else False completed_sections = {} for section in sections: required, optional = count_unanswered_questions([section]) if section_has_at_least_one_required_question(section): completed_sections[section.slug] = True if required == 0 else False else: completed_sections[section.slug] = True if optional == 0 else False brief['clarificationQuestions'] = [ dict(question, number=index+1) for index, question in enumerate(brief['clarificationQuestions']) ] return render_template_with_csrf( "buyers/brief_overview.html", framework=framework, confirm_remove=request.args.get("confirm_remove", None), brief=brief, sections=sections, completed_sections=completed_sections, step_sections=[section.step for section in sections if hasattr(section, 'step')], delete_requested=delete_requested, )
def publish_brief(framework_slug, lot_slug, brief_id): if lot_slug in ['digital-outcome', 'digital-professionals', 'training']: abort(404) TZ = current_app.config['DM_TIMEZONE'] get_framework_and_lot(framework_slug, lot_slug, data_api_client, status='live', must_allow_brief=True) brief = data_api_client.get_brief(brief_id)["briefs"] if not is_brief_correct( brief, framework_slug, lot_slug, current_user.id, data_api_client ) or not brief_can_be_edited(brief): abort(404) if not has_permission_to_edit_brief(brief): return redirect('/2/request-access/publish_opportunities') content = content_loader.get_manifest(brief['frameworkSlug'], 'edit_brief').filter({'lot': brief['lotSlug']}) sections = content.summary(brief) question_and_answers = {} question_and_answers_content = sections.get_question('questionAndAnswerSessionDetails') question_and_answers['id'] = question_and_answers_content['id'] for section in sections: if section.get_question('questionAndAnswerSessionDetails') == question_and_answers_content: question_and_answers['slug'] = section['id'] for question_id in section.get_section_question_ids(): remove_non_cascade_fields(brief, section, question_id) unanswered_required, unanswered_optional = count_unanswered_questions(sections) if request.method == 'POST': if unanswered_required > 0: abort(400, 'There are still unanswered required questions') if not current_user.has_permission('publish_opportunities'): return redirect('/2/request-access/publish_opportunities') data_api_client.publish_brief(brief_id, current_user.name) brief_url = '/2/brief/{}/published'.format(brief_id) brief_url_external = url_for('main.get_brief_by_id', framework_slug=brief['frameworkSlug'], brief_id=brief['id'], _external=True) send_new_opportunity_email_to_sellers(brief, brief_url_external) notification_message = '{}\n{}\nBy: {} ({})'.format( brief['title'], brief['organisation'], current_user.name, current_user.email_address ) notify_team('A buyer has published a new opportunity', notification_message, brief_url_external) return redirect(brief_url) else: email_address = current_user.email_address return render_template_with_csrf( "buyers/brief_publish_confirmation.html", email_address=email_address, question_and_answers=question_and_answers, unanswered_required=unanswered_required, sections=sections, brief=brief, current_date=pendulum.now(TZ) )
def get_brief_by_id(framework_slug, brief_id): briefs = data_api_client.get_brief(brief_id) brief = briefs.get('briefs') if brief['lotSlug'] in ['rfx', 'atm', 'specialist', 'training2']: return redirect('/2/%s/opportunities/%s' % (framework_slug, brief_id), 301) if brief['status'] not in ['live', 'closed']: if ( not current_user.is_authenticated or (brief['users'] and brief['users'][0]['id'] != current_user.id) or current_user.id not in [tb.get('userId') for tb in brief.get('teamBriefs', [])] ): abort(404, "Opportunity '{}' can not be found".format(brief_id)) if current_user.is_authenticated and current_user.role == 'supplier': brief_responses = data_api_client.find_brief_responses( brief_id, current_user.supplier_code)["briefResponses"] selected_for_brief = _is_supplier_selected_for_brief(brief) else: brief_responses = None selected_for_brief = False brief['clarificationQuestions'] = [ dict(question, number=index+1) for index, question in enumerate(brief['clarificationQuestions']) ] brief_content = content_loader.get_builder(framework_slug, 'display_brief').filter( brief ) sections = brief_content.summary(brief) unanswered_required, unanswered_optional = count_unanswered_questions(sections) brief_of_current_user = False if not current_user.is_anonymous and len(brief.get('users')) > 0: brief_of_current_user = brief['users'][0]['id'] == current_user.id is_restricted_brief = brief.get('sellerSelector', '') in ('someSellers', 'oneSeller') brief_published_date = brief['dates'].get('published_date', None) feature_date = current_app.config['MULTI_CANDIDATE_PUBLISHED_DATE'] published_date = pendulum.parse(brief_published_date) if brief_published_date else feature_date.subtract(days=1) application_url = "/2/brief/{}/respond".format(brief['id']) application_specialist_url = application_url application_specialist_submitted_url = None if published_date >= feature_date: application_specialist_url = "/2/brief/{}/specialist/respond".format(brief['id']) application_specialist_submitted_url = "/2/brief/{}/specialist/respond/submitted".format(brief['id']) application_training_url = "/2/brief/{}/training/respond".format(brief['id']) add_case_study_url = None profile_application_status = None supplier = None unassessed_domains = {} assessed_domains = {} profile_url = None supplier_assessments = {} supplier_framework = None if current_user.is_authenticated: if current_user.supplier_code is not None: supplier = data_api_client.get_supplier( current_user.supplier_code ).get('supplier', None) profile_application_id = current_user.application_id if supplier is not None: profile_url = '/supplier/{}'.format(supplier.get('code')) assessed_domains = supplier.get('domains').get('assessed', None) unassessed_domains = supplier.get('domains').get('unassessed', None) legacy_domains = supplier.get('domains').get('legacy', None) if profile_application_id is None: profile_application_id = supplier.get('application_id', None) supplier_code = supplier.get('code') supplier_assessments = data_api_client.req.assessments().supplier(supplier_code).get() if len(legacy_domains) != 0: for i in range(len(legacy_domains)): supplier_assessments['assessed'].append(legacy_domains[i]) supplier_framework_ids = supplier.get('frameworks') for i in range(len(supplier_framework_ids)): if supplier.get('frameworks')[i].get('framework_id') == 7: supplier_framework = 'digital-marketplace' if supplier_framework is None: supplier_framework = 'digital-service-professionals' if profile_application_id is not None: try: profile_application = data_api_client.req.applications(profile_application_id).get() if unassessed_domains is None: unassessed_domains = profile_application.get( 'application').get('supplier').get('domains', None).get('unassessed', None) if assessed_domains is None: assessed_domains = profile_application.get( 'application').get('supplier').get('domains', None).get('assessed', None) profile_application_status = profile_application.get('application').get('status', None) if profile_application.get('application').get('type') == 'edit': profile_application_status = 'approved' except APIError: pass except HTTPError: pass domain_id = None if brief.get('areaOfExpertise'): current_domain = data_api_client.req.domain(brief['areaOfExpertise']).get() domain_id = current_domain['domain']['id'] elif brief['lotSlug'] == 'training': domain_id = 15 # training return render_template_with_csrf( 'brief.html', add_case_study_url=add_case_study_url, application_url=application_url, application_specialist_url=application_specialist_url, application_specialist_submitted_url=application_specialist_submitted_url, application_training_url=application_training_url, assessed_domains=assessed_domains, brief=brief, brief_responses=brief_responses, brief_of_current_user=brief_of_current_user, content=brief_content, domain_id=domain_id, is_restricted_brief=is_restricted_brief, selected_for_brief=selected_for_brief, profile_application_status=profile_application_status, profile_url=profile_url, unassessed_domains=unassessed_domains, supplier_assessments=supplier_assessments, supplier_framework=supplier_framework, unanswered_required=unanswered_required, training_domain_name='Training, Learning and Development' )
def get_brief_by_id(framework_slug, brief_id): briefs = data_api_client.get_brief(brief_id) brief = briefs.get('briefs') if brief['lotSlug'] in ['rfx', 'atm']: return redirect('/2/%s/opportunities/%s' % (framework_slug, brief_id), 301) if brief['status'] not in ['live', 'closed']: if not current_user.is_authenticated or brief['users'][0]['id'] != current_user.id: abort(404, "Opportunity '{}' can not be found".format(brief_id)) if current_user.is_authenticated and current_user.role == 'supplier': brief_responses = data_api_client.find_brief_responses( brief_id, current_user.supplier_code)["briefResponses"] selected_for_brief = _is_supplier_selected_for_brief(brief) else: brief_responses = None selected_for_brief = False brief['clarificationQuestions'] = [ dict(question, number=index+1) for index, question in enumerate(brief['clarificationQuestions']) ] brief_content = content_loader.get_builder(framework_slug, 'display_brief').filter( brief ) sections = brief_content.summary(brief) unanswered_required, unanswered_optional = count_unanswered_questions(sections) brief_of_current_user = False if not current_user.is_anonymous and len(brief.get('users')) > 0: brief_of_current_user = brief['users'][0]['id'] == current_user.id is_restricted_brief = brief.get('sellerSelector', '') in ('someSellers', 'oneSeller') brief_published_date = brief['dates'].get('published_date', None) feature_date = current_app.config['MULTI_CANDIDATE_PUBLISHED_DATE'] published_date = pendulum.parse(brief_published_date) if brief_published_date else feature_date.subtract(days=1) application_url = "/2/brief/{}/respond".format(brief['id']) application_specialist_url = application_url application_specialist_submitted_url = None if published_date >= feature_date: application_specialist_url = "/2/brief/{}/specialist/respond".format(brief['id']) application_specialist_submitted_url = "/2/brief/{}/specialist/respond/submitted".format(brief['id']) application_training_url = "/2/brief/{}/training/respond".format(brief['id']) add_case_study_url = None profile_application_status = None supplier = None unassessed_domains = {} assessed_domains = {} profile_url = None supplier_assessments = {} supplier_framework = None if current_user.is_authenticated: if current_user.supplier_code is not None: supplier = data_api_client.get_supplier( current_user.supplier_code ).get('supplier', None) profile_application_id = current_user.application_id if supplier is not None: profile_url = '/supplier/{}'.format(supplier.get('code')) assessed_domains = supplier.get('domains').get('assessed', None) unassessed_domains = supplier.get('domains').get('unassessed', None) legacy_domains = supplier.get('domains').get('legacy', None) if profile_application_id is None: profile_application_id = supplier.get('application_id', None) supplier_code = supplier.get('code') supplier_assessments = data_api_client.req.assessments().supplier(supplier_code).get() if len(legacy_domains) != 0: for i in range(len(legacy_domains)): supplier_assessments['assessed'].append(legacy_domains[i]) supplier_framework_ids = supplier.get('frameworks') for i in range(len(supplier_framework_ids)): if supplier.get('frameworks')[i].get('framework_id') == 7: supplier_framework = 'digital-marketplace' if supplier_framework is None: supplier_framework = 'digital-service-professionals' if profile_application_id is not None: try: profile_application = data_api_client.req.applications(profile_application_id).get() if unassessed_domains is None: unassessed_domains = profile_application.get( 'application').get('supplier').get('domains', None).get('unassessed', None) if assessed_domains is None: assessed_domains = profile_application.get( 'application').get('supplier').get('domains', None).get('assessed', None) profile_application_status = profile_application.get('application').get('status', None) if profile_application.get('application').get('type') == 'edit': profile_application_status = 'approved' except APIError: pass except HTTPError: pass domain_id = None if brief.get('areaOfExpertise'): current_domain = data_api_client.req.domain(brief['areaOfExpertise']).get() domain_id = current_domain['domain']['id'] elif brief['lotSlug'] == 'training': domain_id = 15 # training return render_template_with_csrf( 'brief.html', add_case_study_url=add_case_study_url, application_url=application_url, application_specialist_url=application_specialist_url, application_specialist_submitted_url=application_specialist_submitted_url, application_training_url=application_training_url, assessed_domains=assessed_domains, brief=brief, brief_responses=brief_responses, brief_of_current_user=brief_of_current_user, content=brief_content, domain_id=domain_id, is_restricted_brief=is_restricted_brief, selected_for_brief=selected_for_brief, profile_application_status=profile_application_status, profile_url=profile_url, unassessed_domains=unassessed_domains, supplier_assessments=supplier_assessments, supplier_framework=supplier_framework, unanswered_required=unanswered_required, training_domain_name='Training, Learning and Development' )
def publish_brief(framework_slug, lot_slug, brief_id): if lot_slug == 'digital-outcome': abort(404) TZ = current_app.config['DM_TIMEZONE'] get_framework_and_lot(framework_slug, lot_slug, data_api_client, status='live', must_allow_brief=True) brief = data_api_client.get_brief(brief_id)["briefs"] if not is_brief_correct( brief, framework_slug, lot_slug, current_user.id ) or not brief_can_be_edited(brief): abort(404) content = content_loader.get_manifest(brief['frameworkSlug'], 'edit_brief').filter({'lot': brief['lotSlug']}) brief_users = brief['users'][0] brief_user_name = brief_users['name'] sections = content.summary(brief) question_and_answers = {} question_and_answers_content = sections.get_question('questionAndAnswerSessionDetails') question_and_answers['id'] = question_and_answers_content['id'] for section in sections: if section.get_question('questionAndAnswerSessionDetails') == question_and_answers_content: question_and_answers['slug'] = section['id'] for question_id in section.get_section_question_ids(): remove_non_cascade_fields(brief, section, question_id) unanswered_required, unanswered_optional = count_unanswered_questions(sections) if request.method == 'POST': if unanswered_required > 0: abort(400, 'There are still unanswered required questions') data_api_client.publish_brief(brief_id, brief_user_name) brief_url = '/2/brief/{}/published'.format(brief_id) brief_url_external = url_for('main.get_brief_by_id', framework_slug=brief['frameworkSlug'], brief_id=brief['id'], _external=True) send_new_opportunity_email_to_sellers(brief, brief_url_external) notification_message = '{}\n{}\nBy: {} ({})'.format( brief['title'], brief['organisation'], current_user.name, current_user.email_address ) notify_team('A buyer has published a new opportunity', notification_message, brief_url_external) return redirect(brief_url) else: email_address = brief_users['emailAddress'] return render_template_with_csrf( "buyers/brief_publish_confirmation.html", email_address=email_address, question_and_answers=question_and_answers, unanswered_required=unanswered_required, sections=sections, brief=brief, current_date=pendulum.now(TZ) )