def form_valid(self, form, *args, **kwargs): """ Создаёт объект Корректировки, если есть поля с заполненными корректировками """ # Деактивируем корректировку для нашего текущего шага corrections_qs = form.instance.get_correction_active( for_step=get_task_ref(self.linked_node)) corrections_qs.update(is_active=False) # TODO MBPM-3: Вынести запрос к БД из цикла for corr_settings in self.can_create_corrections: correction_data = dict([ (name.replace(corr_settings['action_btn_name'], ''), value) for name, value in form.cleaned_data.items() if name.endswith(corr_settings['action_btn_name']) and value ]) if correction_data: Correction.objects.create( task=self.activation.task, proposal=self.activation.process, for_step=get_task_ref(corr_settings['for_step']), reviewed_version=form.cleaned_data['current_version'], data=correction_data, is_active=True, owner=self.request.user) super().form_valid(form, *args, **kwargs) return HttpResponseRedirect(self.get_success_url())
def test_get_task_ref_succeed(self): self.assertEqual( fields.get_task_ref( TestFlow.start), 'tests/test_fields.TestFlow.start') self.assertEqual( fields.get_task_ref( TestFlow.end), 'tests/test_fields.TestFlow.end')
def task_loader(flow_task, **kwargs): proposal = kwargs['proposal'] # Проверяем, есть ли у текущей заявки процесс по созданию BibServe-аккаунта if hasattr(proposal, 'bibserveprocess'): return flow_task.flow_class.task_class._default_manager.filter( flow_task=get_task_ref(flow_task), process_id=proposal.bibserveprocess.id).first()
def schedule(self, task_id): """ Async task schedule """ self.flow_task.job.apply_async( args=[get_task_ref(self.flow_task), self.task.process_id, self.task.pk], task_id=task_id, countdown=1)
def is_already_has_task(activation, task): # TODO MBPM-3: # Кажется эта функция не используется if not hasattr(task, 'flow_class'): setattr(task, 'flow_class', ProposalConfirmationFlow) return activation.process.task_set.exclude(status='DONE').filter( flow_task=get_task_ref(task)).exists()
def __init__(self, *args, **kwargs): self.linked_node = kwargs.pop('linked_node') self.show_corrections = kwargs.pop('show_corrections', []) self.can_create_corrections = kwargs.pop('can_create_corrections') self.fields_corrections = kwargs.pop('fields_corrections') super().__init__(*args, **kwargs) # Делаем каждое поле неактивным for field in self.fields.values(): if isinstance(field.widget, (CheckboxInput, Select, RadioSelect)): field.widget.attrs['disabled'] = 'disabled' else: field.widget.attrs['readonly'] = True # Добавляем поля для корректировки и комментариев согласно настройкам в self.can_create_corrections for corr_settings in self.can_create_corrections: # Если задана опция is_can_answer_only, то проверяем, есть ли корректировки, # на которые нужно отвечать. И если такие есть, то показываем поля для ответа. if 'is_can_answer_only' in corr_settings and corr_settings[ 'is_can_answer_only']: has_correction = False if '__all__' in self.fields_corrections: has_correction = bool([ corr for corr in self.fields_corrections['__all__'] if get_task_ref(corr_settings['for_step']) == get_task_ref(corr['from_step_obj']) ]) if not has_correction: continue non_field_correction = forms.CharField( max_length=255, required=False, label=corr_settings['non_field_corr_label'], widget=forms.TextInput( attrs={ 'data-correction-field': 'true', 'action_btn_label': corr_settings['action_btn_label'], 'action_btn_name': corr_settings['action_btn_name'], 'action_btn_class': corr_settings['action_btn_class'], })) self.fields[ '__all__' + corr_settings['action_btn_name']] = non_field_correction
def schedule(self, task_id): """ Async task schedule """ self.flow_task.job.apply_async(args=[ get_task_ref(self.flow_task), self.task.process_id, self.task.pk ], task_id=task_id, countdown=1)
def test_flow_job_decorator(self): act = JobTestFlow.start.run() with Context(throw_test_error=False): job_handler( get_task_ref(JobTestFlow.job), act.process.pk, act.process.get_task(JobTestFlow.job, status=[STATUS.SCHEDULED]).pk) tasks = act.process.task_set.all() self.assertEqual(3, tasks.count()) self.assertTrue(all(task.finished is not None for task in tasks))
def test_flow_job_decorator_error(self): act = JobTestFlow.start.run() with Context(throw_test_error=True): try: job_handler( get_task_ref(JobTestFlow.job), act.process.pk, act.process.get_task(JobTestFlow.job, status=[STATUS.SCHEDULED]).pk) except ValueError: """Expected test error.""" tasks = act.process.task_set.all() self.assertEqual(2, tasks.count()) job_task = act.process.get_task(JobTestFlow.job, status=[STATUS.ERROR]) self.assertIn('Expected test error', job_task.comments)
def has_active_correction(activation, for_step=None): """ Возвращает True, если у Заявки нет ни одной активной Корректировки. А это значит, что заявка на данном шаге подтверждена и можно переводить её на следующий шаг. :param activation: viewflow.activation.Activation :param for_step: viewflow.ThisObject :return: boolean """ task_qs = activation.process.task_set.filter(correction__is_active=True) if for_step: if not hasattr(for_step, 'flow_class'): setattr(for_step, 'flow_class', ProposalConfirmationFlow) for_step = get_task_ref(for_step) task_qs = task_qs.filter(correction__for_step=for_step) if task_qs.exists(): return True return False
def clean(self): self.cleaned_data = super().clean() # Проверяем, изменились ли те поля, к которым были указаны корректировки # correction_obj = self.instance.get_correction_active(for_step=get_task_ref(self.linked_node)) # need_to_be_corrected = set(correction_obj.data.keys()) corrections_qs = self.instance.get_correction_active( for_step=get_task_ref(self.linked_node)) # Для Клиента всегда должна быть одна активная Корретировка, т.к. он общается через Аккаунта, # и только Аккаунт может создавать для него Корректировки # TODO MBPM-3: Закрепить это на уровне констрейта в БД? correction_obj = corrections_qs.first() need_to_be_corrected = set(correction_obj.data.keys()) last_version = correction_obj.reviewed_version changed_fields = set( self.instance.get_diff_fields(self.cleaned_data, last_version, self.fields.keys()).keys()) if '__all__' in need_to_be_corrected: if not changed_fields: msg = l_( 'Нужно изменить хотя бы одно поле в соответствие с корретировкой: ' + correction_obj.data['__all__']) self.add_error(None, msg) need_to_be_corrected.remove('__all__') not_corrected = need_to_be_corrected - changed_fields if not_corrected: for field_name in not_corrected: msg = l_( 'Нужно изменить это поле в соответствие с корректировкой: ' + correction_obj.data[field_name]) self.add_error(field_name, msg) return self.cleaned_data
def test_get_task_ref_succeed(self): self.assertEqual(fields.get_task_ref(TestFlow.start), "tests/test_fields.TestFlow.start") self.assertEqual(fields.get_task_ref(TestFlow.end), "tests/test_fields.TestFlow.end")
def get_fields_corrections(self, instance): """ Возвращает dict с ключами с именем полей и значениями в виде Корректировок и историй изменений заявки. На основании show_corrections и полей формы. """ for_steps = [] # {'for_step': '', 'made_on_step': ''} # добавляем имя своего шага, чтобы видеть корректировки, созданные для этого шага for_steps.append({'for_step': get_task_ref(self.linked_node)}) # добавляем возможность видеть корректировки для других шагов, если это настроенно в ноде for corr_setting in self.show_corrections: for_steps.append({ 'for_step': get_task_ref(corr_setting['for_step']), 'made_on_step': get_task_ref(corr_setting['made_on_step']) if ('made_on_step' in corr_setting) else None }) corrections_qs = instance.get_corrections_all(for_steps) # Поля, которые видит пользователь в рамках этого view fields = self.fields if not fields: fields = self.form_class.base_fields.keys() fields = [ name for (name, field) in self.form_class.base_fields.items() ] fields_corrections = {} # Добавляем non_field поле for correction in corrections_qs: if '__all__' in correction.data: non_field_corr = { 'msg': correction.data['__all__'], 'from_step': str(correction.task.flow_task), 'from_step_obj': correction.task.flow_task, 'owner': str(correction.owner), 'created': correction.created, 'is_active': correction.is_active, 'changed_fieldschanged_fields': None, } if '__all__' in fields_corrections: fields_corrections['__all__'].append(non_field_corr) else: fields_corrections['__all__'] = [non_field_corr] if correction.fixed_in_version: base_instace = json.loads(correction.fixed_in_version. serialized_data)[0]['fields'] diff = ProposalProcess.get_diff_fields( base_instace, correction.reviewed_version, fields) non_field_corr['changed_fields'] = diff for (changed_field_name, changed_field_old_value) in diff.items(): field_corr = { 'msg': correction.data['__all__'], 'from_step': str(correction.task.flow_task), 'from_step_obj': correction.task.flow_task, 'owner': str(correction.owner), 'created': correction.created, 'is_active': correction.is_active, 'version_value': None } if correction.fixed_in_version: field_corr[ 'version_value'] = changed_field_old_value[ 'old_value'] if changed_field_name in fields_corrections: fields_corrections[changed_field_name].append( field_corr) else: fields_corrections[changed_field_name] = [ field_corr ] for field_name in fields: for correction in corrections_qs: if field_name in correction.data: field_corr = { 'msg': correction.data[field_name], 'from_step': str(correction.task.flow_task), 'from_step_obj': correction.task.flow_task, 'owner': str(correction.owner), 'created': correction.created, 'is_active': correction.is_active, 'version_value': None, } if correction.fixed_in_version: base_instace = json.loads(correction.fixed_in_version. serialized_data)[0]['fields'] diff = ProposalProcess.get_diff_fields( base_instace, correction.reviewed_version, [field_name]) if diff: field_corr['version_value'] = diff[field_name][ 'old_value'] if field_name in fields_corrections: fields_corrections[field_name].append(field_corr) else: fields_corrections[field_name] = [field_corr] return fields_corrections
def is_already_done(activation, task): if not hasattr(task, 'flow_class'): setattr(task, 'flow_class', ProposalConfirmationFlow) return activation.process.task_set.filter(flow_task=get_task_ref(task), status='DONE').exists()