133 if wftr is None: |
133 if wftr is None: |
134 # inconsistency detected |
134 # inconsistency detected |
135 qname = role_name('to_state', 'subject') |
135 qname = role_name('to_state', 'subject') |
136 msg = session._("state doesn't belong to entity's current workflow") |
136 msg = session._("state doesn't belong to entity's current workflow") |
137 raise ValidationError(self.trinfo.eid, {'to_state': msg}) |
137 raise ValidationError(self.trinfo.eid, {'to_state': msg}) |
138 tostate = wftr.get_exit_point(forentity, trinfo['to_state']) |
138 tostate = wftr.get_exit_point(forentity, trinfo.cw_attr_cache['to_state']) |
139 if tostate is not None: |
139 if tostate is not None: |
140 # reached an exit point |
140 # reached an exit point |
141 msg = session._('exiting from subworkflow %s') |
141 msg = session._('exiting from subworkflow %s') |
142 msg %= session._(iworkflowable.current_workflow.name) |
142 msg %= session._(iworkflowable.current_workflow.name) |
143 session.transaction_data[(forentity.eid, 'subwfentrytr')] = True |
143 session.transaction_data[(forentity.eid, 'subwfentrytr')] = True |
183 def __call__(self): |
183 def __call__(self): |
184 session = self._cw |
184 session = self._cw |
185 entity = self.entity |
185 entity = self.entity |
186 # first retreive entity to which the state change apply |
186 # first retreive entity to which the state change apply |
187 try: |
187 try: |
188 foreid = entity['wf_info_for'] |
188 foreid = entity.cw_attr_cache['wf_info_for'] |
189 except KeyError: |
189 except KeyError: |
190 qname = role_name('wf_info_for', 'subject') |
190 qname = role_name('wf_info_for', 'subject') |
191 msg = session._('mandatory relation') |
191 msg = session._('mandatory relation') |
192 raise ValidationError(entity.eid, {qname: msg}) |
192 raise ValidationError(entity.eid, {qname: msg}) |
193 forentity = session.entity_from_eid(foreid) |
193 forentity = session.entity_from_eid(foreid) |
|
194 # see comment in the TrInfo entity definition |
|
195 entity.cw_edited['tr_count']=len(forentity.reverse_wf_info_for) |
194 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
196 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
195 # then check it has a workflow set, unless we're in the process of changing |
197 # then check it has a workflow set, unless we're in the process of changing |
196 # entity's workflow |
198 # entity's workflow |
197 if session.transaction_data.get((forentity.eid, 'customwf')): |
199 if session.transaction_data.get((forentity.eid, 'customwf')): |
198 wfeid = session.transaction_data[(forentity.eid, 'customwf')] |
200 wfeid = session.transaction_data[(forentity.eid, 'customwf')] |
211 swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None) |
213 swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None) |
212 cowpowers = (session.user.is_in_group('managers') |
214 cowpowers = (session.user.is_in_group('managers') |
213 or not session.write_security) |
215 or not session.write_security) |
214 # no investigate the requested state change... |
216 # no investigate the requested state change... |
215 try: |
217 try: |
216 treid = entity['by_transition'] |
218 treid = entity.cw_attr_cache['by_transition'] |
217 except KeyError: |
219 except KeyError: |
218 # no transition set, check user is a manager and destination state |
220 # no transition set, check user is a manager and destination state |
219 # is specified (and valid) |
221 # is specified (and valid) |
220 if not cowpowers: |
222 if not cowpowers: |
221 qname = role_name('by_transition', 'subject') |
223 qname = role_name('by_transition', 'subject') |
222 msg = session._('mandatory relation') |
224 msg = session._('mandatory relation') |
223 raise ValidationError(entity.eid, {qname: msg}) |
225 raise ValidationError(entity.eid, {qname: msg}) |
224 deststateeid = entity.get('to_state') |
226 deststateeid = entity.cw_attr_cache.get('to_state') |
225 if not deststateeid: |
227 if not deststateeid: |
226 qname = role_name('by_transition', 'subject') |
228 qname = role_name('by_transition', 'subject') |
227 msg = session._('mandatory relation') |
229 msg = session._('mandatory relation') |
228 raise ValidationError(entity.eid, {qname: msg}) |
230 raise ValidationError(entity.eid, {qname: msg}) |
229 deststate = wf.state_by_eid(deststateeid) |
231 deststate = wf.state_by_eid(deststateeid) |
245 'tr': session._(tr.name), 'st': session._(fromstate.name)} |
247 'tr': session._(tr.name), 'st': session._(fromstate.name)} |
246 raise ValidationError(entity.eid, {qname: msg}) |
248 raise ValidationError(entity.eid, {qname: msg}) |
247 if not tr.may_be_fired(foreid): |
249 if not tr.may_be_fired(foreid): |
248 msg = session._("transition may not be fired") |
250 msg = session._("transition may not be fired") |
249 raise ValidationError(entity.eid, {qname: msg}) |
251 raise ValidationError(entity.eid, {qname: msg}) |
250 if entity.get('to_state'): |
252 deststateeid = entity.cw_attr_cache.get('to_state') |
251 deststateeid = entity['to_state'] |
253 if deststateeid is not None: |
252 if not cowpowers and deststateeid != tr.destination(forentity).eid: |
254 if not cowpowers and deststateeid != tr.destination(forentity).eid: |
253 qname = role_name('by_transition', 'subject') |
255 qname = role_name('by_transition', 'subject') |
254 msg = session._("transition isn't allowed") |
256 msg = session._("transition isn't allowed") |
255 raise ValidationError(entity.eid, {qname: msg}) |
257 raise ValidationError(entity.eid, {qname: msg}) |
256 if swtr is None: |
258 if swtr is None: |
260 msg = session._("state doesn't belong to entity's workflow") |
262 msg = session._("state doesn't belong to entity's workflow") |
261 raise ValidationError(entity.eid, {qname: msg}) |
263 raise ValidationError(entity.eid, {qname: msg}) |
262 else: |
264 else: |
263 deststateeid = tr.destination(forentity).eid |
265 deststateeid = tr.destination(forentity).eid |
264 # everything is ok, add missing information on the trinfo entity |
266 # everything is ok, add missing information on the trinfo entity |
265 entity['from_state'] = fromstate.eid |
267 entity.cw_edited['from_state'] = fromstate.eid |
266 entity['to_state'] = deststateeid |
268 entity.cw_edited['to_state'] = deststateeid |
267 nocheck = session.transaction_data.setdefault('skip-security', set()) |
269 nocheck = session.transaction_data.setdefault('skip-security', set()) |
268 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
270 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
269 nocheck.add((entity.eid, 'to_state', deststateeid)) |
271 nocheck.add((entity.eid, 'to_state', deststateeid)) |
270 _FireAutotransitionOp(session, entity=forentity) |
272 _FireAutotransitionOp(session, entity=forentity) |
271 |
273 |
276 __select__ = WorkflowHook.__select__ & is_instance('TrInfo') |
278 __select__ = WorkflowHook.__select__ & is_instance('TrInfo') |
277 events = ('after_add_entity',) |
279 events = ('after_add_entity',) |
278 |
280 |
279 def __call__(self): |
281 def __call__(self): |
280 trinfo = self.entity |
282 trinfo = self.entity |
281 _change_state(self._cw, trinfo['wf_info_for'], |
283 rcache = trinfo.cw_attr_cache |
282 trinfo['from_state'], trinfo['to_state']) |
284 _change_state(self._cw, rcache['wf_info_for'], rcache['from_state'], |
283 forentity = self._cw.entity_from_eid(trinfo['wf_info_for']) |
285 rcache['to_state']) |
|
286 forentity = self._cw.entity_from_eid(rcache['wf_info_for']) |
284 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
287 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
285 assert iworkflowable.current_state.eid == trinfo['to_state'] |
288 assert iworkflowable.current_state.eid == rcache['to_state'] |
286 if iworkflowable.main_workflow.eid != iworkflowable.current_workflow.eid: |
289 if iworkflowable.main_workflow.eid != iworkflowable.current_workflow.eid: |
287 _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo) |
290 _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo) |
288 |
291 |
289 |
292 |
290 class CheckInStateChangeAllowed(WorkflowHook): |
293 class CheckInStateChangeAllowed(WorkflowHook): |