misc: make form/card adjustments after status removal async (#77139) #492
|
@ -14,6 +14,7 @@ from wcs.carddef import CardDef
|
|||
from wcs.categories import WorkflowCategory
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.mail_templates import MailTemplate
|
||||
from wcs.qommon.afterjobs import AfterJob
|
||||
from wcs.qommon.errors import ConnectionError
|
||||
from wcs.qommon.form import UploadedFile
|
||||
from wcs.qommon.http_request import HTTPRequest
|
||||
|
@ -404,11 +405,13 @@ def test_workflows_delete_status(pub):
|
|||
resp = resp.follow()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'subtest', [('forms', (FormDef,)), ('cards', (CardDef,)), ('cards/forms', (FormDef, CardDef))]
|
||||
)
|
||||
def test_workflows_delete_status_reassign(pub, subtest):
|
||||
(name, formdef_classes) = subtest
|
||||
@pytest.mark.parametrize('name', ['forms', 'cards', 'cards/forms'])
|
||||
def test_workflows_delete_status_reassign(pub, name):
|
||||
formdef_classes = {
|
||||
'forms': (FormDef,),
|
||||
'cards': (CardDef,),
|
||||
'cards/forms': (FormDef, CardDef),
|
||||
}.get(name)
|
||||
create_superuser(pub)
|
||||
FormDef.wipe()
|
||||
CardDef.wipe()
|
||||
|
@ -421,37 +424,36 @@ def test_workflows_delete_status_reassign(pub, subtest):
|
|||
formdefs = []
|
||||
for i, formdef_class in enumerate(formdef_classes):
|
||||
formdef = formdef_class()
|
||||
formdef.name = 'Form titles %s' % i
|
||||
formdef.name = f'{formdef_class.xml_root_node} title {i}'
|
||||
formdef.workflow = workflow
|
||||
formdef.fields = []
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
formdefs.append(formdef)
|
||||
|
||||
formdata1 = formdefs[0].data_class()()
|
||||
formdata1.data = {}
|
||||
formdata1.status = 'wf-%s' % wf_bar.id
|
||||
formdata1.store()
|
||||
|
||||
formdata2 = formdefs[-1].data_class()()
|
||||
formdata2.data = {}
|
||||
formdata2.status = 'wf-%s' % wf_baz.id
|
||||
formdata2.store()
|
||||
|
||||
if name == 'cards':
|
||||
# add a second one, to check for plural form in message.
|
||||
formdata2b = formdefs[-1].data_class()()
|
||||
formdata2b.data = {}
|
||||
formdata2b.status = 'wf-%s' % wf_baz.id
|
||||
formdata2b.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
|
||||
for action in ('nothing', 'delete', 'reassign'):
|
||||
# restore workflow & formdata
|
||||
workflow.store()
|
||||
for action in ('nothing', 'remove', 'reassign'):
|
||||
AfterJob.wipe()
|
||||
formdefs[0].data_class().wipe()
|
||||
formdefs[-1].data_class().wipe()
|
||||
|
||||
formdata1 = formdefs[0].data_class()()
|
||||
formdata1.status = 'wf-%s' % wf_bar.id
|
||||
formdata1.store()
|
||||
|
||||
formdata2 = formdefs[-1].data_class()()
|
||||
formdata2.status = 'wf-%s' % wf_baz.id
|
||||
formdata2.store()
|
||||
|
||||
if name == 'cards':
|
||||
# add a second one, to check for plural form in message.
|
||||
formdata2b = formdefs[-1].data_class()()
|
||||
formdata2b.status = 'wf-%s' % wf_baz.id
|
||||
formdata2b.store()
|
||||
|
||||
workflow.store()
|
||||
|
||||
resp = app.get('/backoffice/workflows/1/status/%s/' % wf_baz.id)
|
||||
resp = resp.click('Delete')
|
||||
resp = resp.form.submit('submit')
|
||||
|
@ -462,18 +464,27 @@ def test_workflows_delete_status_reassign(pub, subtest):
|
|||
resp.form['action'].value = 'Do nothing'
|
||||
resp = resp.form.submit('submit')
|
||||
resp = resp.follow()
|
||||
assert len(Workflow.get(workflow.id).possible_status) == 2
|
||||
assert formdef.data_class().get(formdata2.id).status == 'wf-%s' % wf_baz.id
|
||||
elif action == 'remove':
|
||||
assert resp.request.path == f'/backoffice/workflows/{workflow.id}/status/{wf_baz.id}/'
|
||||
assert AfterJob.count() == 0
|
||||
continue
|
||||
|
||||
if action == 'remove':
|
||||
resp.form['action'].value = 'Remove these %s' % name
|
||||
resp = resp.form.submit('submit')
|
||||
resp = resp.follow()
|
||||
assert formdef.data_class().has_key(formdata1.id)
|
||||
assert not formdef.data_class().has_key(formdata2.id)
|
||||
assert formdefs[0].data_class().has_key(formdata1.id)
|
||||
assert not formdefs[-1].data_class().has_key(formdata2.id)
|
||||
elif action == 'reassign':
|
||||
resp.form['action'].value = 'Change these %s status to "bar"' % name
|
||||
resp = resp.form.submit('submit')
|
||||
resp = resp.follow()
|
||||
assert formdef.data_class().get(formdata2.id).status == 'wf-%s' % wf_bar.id
|
||||
assert formdefs[-1].data_class().get(formdata2.id).status == 'wf-%s' % wf_bar.id
|
||||
|
||||
assert AfterJob.count() == 2 # status change + rebuild_security
|
||||
resp = resp.click('Back')
|
||||
assert resp.request.path == f'/backoffice/workflows/{workflow.id}/'
|
||||
|
||||
|
||||
def test_workflows_order_status(pub):
|
||||
|
|
|
@ -35,6 +35,7 @@ from wcs.categories import WorkflowCategory
|
|||
from wcs.formdata import Evolution
|
||||
from wcs.formdef import FormDef, UpdateStatisticsDataAfterJob
|
||||
from wcs.qommon import _, errors, force_str, misc, template
|
||||
from wcs.qommon.afterjobs import AfterJob
|
||||
from wcs.qommon.form import (
|
||||
CheckboxWidget,
|
||||
ColourWidget,
|
||||
|
@ -859,43 +860,23 @@ class WorkflowStatusPage(Directory):
|
|||
r += htmltext('</div>')
|
||||
return r.getvalue()
|
||||
else:
|
||||
self.submit_reassign(form)
|
||||
del self.workflow.possible_status[self.workflow.possible_status.index(self.status)]
|
||||
self.workflow.store(comment=_('Removal of status %s') % self.status.name)
|
||||
return redirect('../..')
|
||||
|
||||
def submit_reassign(self, form):
|
||||
nb_forms = 0
|
||||
action = form.get_widget('action').parse()
|
||||
if action.startswith('reassign-'):
|
||||
new_status = 'wf-%s' % str(action)[9:]
|
||||
for formdef in itertools.chain(FormDef.select(), CardDef.select()):
|
||||
if formdef.workflow_id != self.workflow.id:
|
||||
continue
|
||||
for item in formdef.data_class().get_with_indexed_value('status', 'wf-%s' % self.status.id):
|
||||
nb_forms += 1
|
||||
if action == 'remove':
|
||||
item.remove_self()
|
||||
else:
|
||||
item.status = new_status
|
||||
evo = Evolution()
|
||||
evo.time = time.localtime()
|
||||
evo.status = new_status
|
||||
evo.comment = str(_('Administrator reassigned status'))
|
||||
if not item.evolution:
|
||||
item.evolution = []
|
||||
item.evolution.append(evo)
|
||||
item.store()
|
||||
# delete all (old) status references in evolutions
|
||||
for item in formdef.data_class().select():
|
||||
if item.evolution:
|
||||
modified = False
|
||||
for evo in item.evolution:
|
||||
if evo.status == self.status:
|
||||
evo.status = None
|
||||
modified = True
|
||||
if modified:
|
||||
item.store()
|
||||
action = form.get_widget('action').parse()
|
||||
new_status = None
|
||||
if action.startswith('reassign-'):
|
||||
new_status = 'wf-%s' % str(action)[9:]
|
||||
|
||||
job = StatusChangeJob(
|
||||
workflow_id=self.workflow.id,
|
||||
action=action,
|
||||
current_status=f'wf-{self.status.id}',
|
||||
new_status=new_status,
|
||||
)
|
||||
job.store()
|
||||
get_response().add_after_job(job)
|
||||
return redirect(job.get_processing_url())
|
||||
|
||||
def display(self):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
|
@ -2100,3 +2081,55 @@ class WorkflowsDirectory(Directory):
|
|||
workflow.store()
|
||||
get_session().message = ('info', _('This workflow has been successfully imported.'))
|
||||
return redirect('%s/' % workflow.id)
|
||||
|
||||
|
||||
class StatusChangeJob(AfterJob):
|
||||
def __init__(self, workflow_id, action, current_status, new_status):
|
||||
super().__init__(
|
||||
label=_('Updating data after workflow change'),
|
||||
workflow_id=workflow_id,
|
||||
action=action,
|
||||
current_status=current_status,
|
||||
new_status=new_status,
|
||||
)
|
||||
|
||||
def execute(self):
|
||||
workflow_id = self.kwargs['workflow_id']
|
||||
current_status = self.kwargs['current_status']
|
||||
new_status = self.kwargs['new_status']
|
||||
action = self.kwargs['action']
|
||||
|
||||
for formdef in itertools.chain(FormDef.select(), CardDef.select()):
|
||||
if formdef.workflow_id != workflow_id:
|
||||
continue
|
||||
for item in formdef.data_class().get_with_indexed_value('status', current_status):
|
||||
if action == 'remove':
|
||||
item.remove_self()
|
||||
else:
|
||||
item.status = new_status
|
||||
evo = Evolution()
|
||||
evo.time = time.localtime()
|
||||
evo.status = new_status
|
||||
evo.comment = str(_('Administrator reassigned status'))
|
||||
if not item.evolution:
|
||||
item.evolution = []
|
||||
item.evolution.append(evo)
|
||||
item.store()
|
||||
# delete all (old) status references in evolutions
|
||||
for item in formdef.data_class().select():
|
||||
if item.evolution:
|
||||
modified = False
|
||||
for evo in item.evolution:
|
||||
if evo.status == self.status:
|
||||
evo.status = None
|
||||
modified = True
|
||||
if modified:
|
||||
item._store_all_evolution = True
|
||||
item.store()
|
||||
|
||||
def done_action_url(self):
|
||||
workflow = Workflow.get(self.kwargs['workflow_id'])
|
||||
return workflow.get_admin_url()
|
||||
|
||||
def done_action_label(self):
|
||||
return _('Back')
|
||||
|
|
Loading…
Reference in New Issue