def publish_answer(current_user, brief_id, data): brief = briefs.get(brief_id) if not brief: raise NotFoundError("Invalid brief id '{}'".format(brief_id)) if not briefs.has_permission_to_brief(current_user.id, brief.id): raise UnauthorisedError('Unauthorised to publish answer') publish_question = data.get('question') if not publish_question: raise ValidationError('Question is required') answer = data.get('answer') if not answer: raise ValidationError('Answer is required') brief_clarification_question = brief_clarification_question_service.save( BriefClarificationQuestion(_brief_id=brief.id, question=publish_question, answer=answer, user_id=current_user.id)) question_id = data.get('questionId') if question_id: question = brief_question_service.get(question_id) if question.brief_id == brief.id: question.answered = True brief_question_service.save(question) audit_service.log_audit_event( audit_type=audit_types.create_brief_clarification_question, user=current_user.email_address, data={'briefId': brief.id}, db_object=brief_clarification_question)
def get_question(current_user, brief_id, question_id): brief = briefs.find(id=brief_id).one_or_none() if not brief: raise NotFoundError("Invalid brief id '{}'".format(brief_id)) if not briefs.has_permission_to_brief(current_user.id, brief.id): raise UnauthorisedError('Unauthorised to publish answer') question = brief_question_service.find(id=question_id, brief_id=brief.id).one_or_none() question_result = None if question: question_result = {"id": question.id, "data": question.data} return { "question": question_result, "brief": { "title": brief.data.get('title'), "id": brief.id, "lot": brief.lot.slug, "questionsCloseAt": brief.questions_closed_at, "closedAt": brief.closed_at, "internalReference": brief.data.get('internalReference'), "isOpenToAll": brief_business.is_open_to_all(brief), "status": brief.status } }
def close_opportunity_early(user_id, brief_id): 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 close opportunity {}'.format(brief_id)) if not can_close_opportunity_early(brief): raise BriefError('Unable to close opportunity {}'.format(brief_id)) user = users.get(user_id) if not user: raise NotFoundError('User {} does not exist'.format(user_id)) brief = brief_service.close_opportunity_early(brief) create_responses_zip(brief.id) send_opportunity_closed_early_email(brief, user) try: audit_service.log_audit_event( audit_type=audit_types.close_opportunity_early, data={'briefId': brief.id}, db_object=brief, user=user.email_address) publish_tasks.brief.delay(publish_tasks.compress_brief(brief), 'closed_early', email_address=user.email_address, name=user.name) except Exception as e: rollbar.report_exc_info() return brief
def withdraw_opportunity(user_id, brief_id, withdrawal_reason): 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 withdraw opportunity {}'.format(brief_id)) if brief.status != 'live': raise BriefError('Unable to withdraw opportunity {}'.format(brief_id)) if not withdrawal_reason: raise ValidationError( 'Withdrawal reason is required for opportunity {}'.format( brief_id)) user = users.get(user_id) if not user: raise NotFoundError('User {} does not exist'.format(user_id)) brief = brief_service.withdraw_opportunity(brief, withdrawal_reason) organisation = agency_service.get_agency_name(user.agency_id) sellers_to_contact = brief_service.get_sellers_to_notify( brief, brief_business.is_open_to_all(brief)) for email_address in sellers_to_contact: send_opportunity_withdrawn_email_to_seller(brief, email_address, organisation) send_opportunity_withdrawn_email_to_buyers(brief, user) try: audit_service.log_audit_event( audit_type=audit_types.withdraw_opportunity, data={'briefId': brief.id}, db_object=brief, user=user.email_address) publish_tasks.brief.delay(publish_tasks.compress_brief(brief), 'withdrawn', email_address=user.email_address, name=user.name) except Exception as e: rollbar.report_exc_info() return brief
def get_suppliers_responded(brief_id): """Get suppliers responded (role=buyer) --- tags: - "Brief Response" security: - basicAuth: [] parameters: - name: brief_response_id in: path type: number required: true definitions: BriefResponse: type: object properties: id: type: number data: type: object brief_id: type: number supplier_code: type: number responses: 200: description: Suppliers that have responded to brief_id schema: id: BriefResponse 404: description: brief_response_id not found """ brief = briefs.get(brief_id) if not brief: return not_found('brief {} not found'.format(brief_id)) if not briefs.has_permission_to_brief(current_user.id, brief.id): return forbidden('Unauthorised to get suppliers responded') suppliers = brief_responses_service.get_suppliers_responded(brief_id) work_order = work_order_service.find(brief_id=brief_id).one_or_none() return jsonify(brief=brief.serialize(with_users=False), suppliers=suppliers, workOrderCreated=True if work_order else False)
def get_questions(current_user, brief_id): brief = briefs.find(id=brief_id).one_or_none() if not brief: raise NotFoundError("Invalid brief id '{}'".format(brief_id)) if not briefs.has_permission_to_brief(current_user.id, brief.id): raise UnauthorisedError('Unauthorised to publish answer') questions = brief_question_service.get_questions(brief_id) return { "questions": questions, "brief": { "title": brief.data.get('title'), "id": brief.id, "closedAt": brief.closed_at, "internalReference": brief.data.get('internalReference') }, "questionCount": get_counts(brief_id, questions=questions) }
def get_opportunity_to_edit(user_id, brief_id): 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)) domains = [] for domain in domain_service.get_active_domains(): domains.append({'id': str(domain.id), 'name': domain.name}) return { 'brief': brief.serialize(with_users=False), 'domains': domains, 'isOpenToAll': brief_business.is_open_to_all(brief) }
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