def create_submission(self, survey, user): session = object_session(survey) program = survey.program submission = model.Submission(program=program, organisation=user.organisation, survey=survey, title="First submission", approval='draft') session.add(submission) for m in program.measures: # Preload response type to avoid autoflush response_type = m.response_type qnode_measure = m.get_qnode_measure(survey) if not qnode_measure: continue response = model.Response(qnode_measure=qnode_measure, submission=submission, user=user) response.attachments = [] response.not_relevant = False response.modified = datetime.datetime.utcnow() response.approval = 'final' response.comment = "Response for %s" % m.title session.add(response) if response_type.name == 'Yes / No': response.response_parts = [{'index': 1, 'note': "Yes"}] elif response_type.name in { 'Numerical', 'External Numerical', 'Planned', 'Actual' }: response.response_parts = [{'value': 1}] else: raise ValueError("Unknown response type") response.attachments.append( model.Attachment(file_name="File %s 1" % m.title, url="Bar", storage='external', organisation=user.organisation)) response.attachments.append( model.Attachment(file_name="File %s 2" % m.title, url="Baz", storage='external', organisation=user.organisation)) response.attachments.append( model.Attachment(file_name="File %s 3" % m.title, blob=b'A blob', storage='external', organisation=user.organisation)) session.flush() calculator = Calculator.scoring(submission) calculator.mark_entire_survey_dirty(submission.survey) calculator.execute() submission.approval = 'final' session.flush() return submission
def create_submission(self): # Respond to a survey with model.session_scope() as session: program = session.query(model.Program).one() user = (session.query( model.AppUser).filter_by(email='clerk').one()) organisation = (session.query( model.Organisation).filter_by(name='Utility').one()) survey = (session.query( model.Survey).filter_by(title='Survey 1').one()) submission = model.Submission(program_id=program.id, organisation_id=organisation.id, survey_id=survey.id, title="Submission", approval='draft') session.add(submission) for m in program.measures: # Preload response type to avoid autoflush response_type = m.response_type qnode_measure = m.get_qnode_measure(survey) if not qnode_measure: continue response = model.Response(submission=submission, qnode_measure=qnode_measure, user=user) response.attachments = [] response.not_relevant = False response.modified = sa.func.now() response.approval = 'final' response.comment = "Response for %s" % m.title session.add(response) if response_type.name == 'Yes / No': response.response_parts = [{'index': 1, 'note': "Yes"}] else: response.response_parts = [{'value': 1}] calculator = Calculator.scoring(submission) calculator.mark_entire_survey_dirty(submission.survey) calculator.execute() functions = list(submission.rnodes) self.assertAlmostEqual(functions[0].score, 33) self.assertAlmostEqual(functions[1].score, 0) self.assertAlmostEqual(functions[0].qnode.total_weight, 33) self.assertAlmostEqual(functions[1].qnode.total_weight, 0) return submission.id
def background_task(self, program_id, survey_id, organisation_id, title): with tempfile.NamedTemporaryFile() as fd: fileinfo = self.request.files['file'][0] fd.write(fileinfo['body']) all_rows = self.read_sheet(fd.name) with model.session_scope() as session: user_session = self.get_user_session(session) org = session.query(model.Organisation).get(organisation_id) if not org: raise errors.ModelError("No such organisation") survey = (session.query(model.Survey).get((survey_id, program_id))) if not survey: raise errors.ModelError("No such survey") submission = model.Submission() submission.program = survey.program submission.survey = survey submission.organisation = org submission.title = title submission.approval = 'draft' session.add(submission) session.flush() submission_id = submission.id policy = user_session.policy.derive({ 'org': org, 'survey': survey, 'surveygroups': submission.surveygroups, }) policy.verify('surveygroup_interact') policy.verify('submission_add') self.process_submission_file(all_rows, session, submission, user_session.user) return submission_id
def post(self, submission_id): '''Create new.''' if submission_id: raise errors.MethodError("Can't use POST for existing object") program_id = self.get_argument('programId', '') if not program_id: raise errors.ModelError("Program ID is required") survey_id = self.get_argument('surveyId', '') if not survey_id: raise errors.ModelError("Survey ID is required") organisation_id = self.get_argument('organisationId', '') if not organisation_id: raise errors.ModelError("Organisation ID is required") # Source submission ID duplicate_id = self.get_argument('duplicateId', '') with model.session_scope() as session: user_session = self.get_user_session(session) org = session.query(model.Organisation).get(organisation_id) if not org: raise errors.ModelError("No such organisation") survey = session.query(model.Survey).get((survey_id, program_id)) if not survey: raise errors.ModelError("No such survey") if duplicate_id: source_submission = (session.query( model.Submission).get(duplicate_id)) if not source_submission: raise errors.MissingDocError( "Source submission (for duplication) not found") if source_submission.organisation != org: raise errors.ModelError( "Can't duplicate a submission across two " "organisations: '%s' and '%s'" % (source_submission.organisation.name, org.name)) else: source_submission = None submission = model.Submission(program=survey.program, survey=survey, organisation=org, approval='draft') self._update(submission, self.request_son) session.add(submission) surveygroups = submission.surveygroups if source_submission: surveygroups &= source_submission.surveygroups policy = user_session.policy.derive({ 'org': org, 'survey': survey, 'surveygroups': surveygroups, }) policy.verify('surveygroup_interact') policy.verify('submission_add') session.flush() submission_id = str(submission.id) if source_submission: yield SubmissionHandler.executor.submit( self.duplicate, submission, source_submission, session) act = Activities(session) act.record(user_session.user, submission, ['create']) act.ensure_subscription(user_session.user, submission, submission.organisation, self.reason) self.get(submission_id)
def test_extern(self): '''Check that variables can depend on each other''' with model.session_scope() as session: user = (session.query( model.AppUser).filter_by(email='clerk').one()) survey = (session.query( model.Survey).filter_by(title='Survey 1').one()) program = survey.program # Add a response type that has an extenal variable rt = next(rt for rt in TEST_RESPONSE_TYPES if rt['id'] == 'external-var') ext_response_type = model.ResponseType(program=program, name=rt['name'], parts=rt['parts'], formula=rt['formula']) session.add(ext_response_type) # Attach response type to a measure target_qm = survey.qnodes[0].children[0].qnode_measures[1] target_qm.measure.response_type = ext_response_type self.assertEqual(1, len(ext_response_type.measures)) # Bind variable to link measures source_qm = survey.qnodes[0].children[0].qnode_measures[0] session.add( model.MeasureVariable(program=program, survey=survey, source_qnode_measure=source_qm, source_field='_score', target_qnode_measure=target_qm, target_field='ext')) submission = model.Submission(program=program, organisation=user.organisation, survey=survey, title="Intermeasure Variables Test", approval='draft') session.add(submission) session.flush() submission_id = str(submission.id) mid_111 = str( survey.qnodes[0].children[0].qnode_measures[0].measure_id) mid_112 = str( survey.qnodes[0].children[0].qnode_measures[1].measure_id) # Put dependant response with errors. Check that the error refers to # missing dependency. with base.mock_user('clerk'): response_son = { 'notRelevant': False, 'responseParts': [], 'comment': "Incomplete dependant response", 'approval': 'draft', } response_son = self.fetch("/submission/%s/response/%s.json" % (submission_id, mid_112), method='PUT', body=response_son, expected=200, decode=True) with model.session_scope() as session: response = (session.query(model.Response).get( (submission_id, mid_112))) self.assertIn('depends on', response.error) self.assertIn('measure has an error', response.parent.error) self.assertIn('sub-category has an error', response.parent.parent.error) self.assertIn('category has an error', response.submission.error) # Put dependency, and check that error of dependant has changed. with base.mock_user('clerk'): response_son = { 'notRelevant': False, 'responseParts': [{ 'note': 'Yes', 'index': 1 }], 'comment': "Dependency", 'approval': 'draft', } response_son = self.fetch("/submission/%s/response/%s.json" % (submission_id, mid_111), method='PUT', body=response_son, expected=200, decode=True) with model.session_scope() as session: response = (session.query(model.Response).get( (submission_id, mid_111))) self.assertIs(response.error, None) # Parent still has an error due to sibling self.assertIn('measure has an error', response.parent.error) response = (session.query(model.Response).get( (submission_id, mid_112))) # Error has changed: dependency has been provided, but response # is still incomplete self.assertIn('undefined variable', response.error) # Fix dependant response and check that errors are resolved. with base.mock_user('clerk'): response_son = self.fetch("/submission/%s/response/%s.json" % (submission_id, mid_112), method='GET', expected=200, decode=True) response_son['response_parts'] = [{'value': 1}] response_son['comment'] = "Complete dependant response" response_son = self.fetch("/submission/%s/response/%s.json" % (submission_id, mid_112), method='PUT', body=response_son, expected=200, decode=True) with model.session_scope() as session: response = (session.query(model.Response).get( (submission_id, mid_112))) # Error has been resolved. self.assertIs(response.error, None) self.assertIs(response.error, response.parent.error) self.assertIs(response.error, response.parent.parent.error) self.assertIs(response.error, response.submission.error)