petri_flow 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +34 -0
- data/app/assets/config/wf_manifest.js +2 -0
- data/app/assets/javascripts/wf/application.js +4 -0
- data/app/assets/stylesheets/wf/application.scss +2 -0
- data/app/assets/stylesheets/wf/arcs.css +4 -0
- data/app/assets/stylesheets/wf/cases.css +4 -0
- data/app/assets/stylesheets/wf/comments.css +4 -0
- data/app/assets/stylesheets/wf/fields.css +4 -0
- data/app/assets/stylesheets/wf/forms.css +4 -0
- data/app/assets/stylesheets/wf/guards.css +4 -0
- data/app/assets/stylesheets/wf/places.css +4 -0
- data/app/assets/stylesheets/wf/transitions.css +4 -0
- data/app/assets/stylesheets/wf/workflows.css +4 -0
- data/app/assets/stylesheets/wf/workitem_assignments.css +4 -0
- data/app/assets/stylesheets/wf/workitems.css +4 -0
- data/app/controllers/wf/application_controller.rb +14 -0
- data/app/controllers/wf/arcs_controller.rb +61 -0
- data/app/controllers/wf/cases_controller.rb +48 -0
- data/app/controllers/wf/comments_controller.rb +30 -0
- data/app/controllers/wf/fields_controller.rb +54 -0
- data/app/controllers/wf/forms_controller.rb +59 -0
- data/app/controllers/wf/guards_controller.rb +58 -0
- data/app/controllers/wf/places_controller.rb +53 -0
- data/app/controllers/wf/transitions_controller.rb +69 -0
- data/app/controllers/wf/workflows_controller.rb +59 -0
- data/app/controllers/wf/workitem_assignments_controller.rb +30 -0
- data/app/controllers/wf/workitems_controller.rb +79 -0
- data/app/helpers/wf/application_helper.rb +6 -0
- data/app/helpers/wf/arcs_helper.rb +6 -0
- data/app/helpers/wf/cases_helper.rb +6 -0
- data/app/helpers/wf/comments_helper.rb +6 -0
- data/app/helpers/wf/fields_helper.rb +6 -0
- data/app/helpers/wf/forms_helper.rb +6 -0
- data/app/helpers/wf/guards_helper.rb +6 -0
- data/app/helpers/wf/places_helper.rb +6 -0
- data/app/helpers/wf/transitions_helper.rb +6 -0
- data/app/helpers/wf/workflows_helper.rb +6 -0
- data/app/helpers/wf/workitem_assignments_helper.rb +6 -0
- data/app/helpers/wf/workitems_helper.rb +6 -0
- data/app/jobs/wf/application_job.rb +6 -0
- data/app/jobs/wf/fire_timed_workitem_job.rb +15 -0
- data/app/mailers/wf/application_mailer.rb +8 -0
- data/app/models/wf/application_record.rb +7 -0
- data/app/models/wf/arc.rb +42 -0
- data/app/models/wf/callbacks/assignment_default.rb +12 -0
- data/app/models/wf/callbacks/deadline_default.rb +11 -0
- data/app/models/wf/callbacks/enable_default.rb +11 -0
- data/app/models/wf/callbacks/fire_default.rb +11 -0
- data/app/models/wf/callbacks/hold_timeout_default.rb +11 -0
- data/app/models/wf/callbacks/notification_default.rb +11 -0
- data/app/models/wf/callbacks/time_default.rb +11 -0
- data/app/models/wf/callbacks/unassignment_default.rb +11 -0
- data/app/models/wf/case.rb +44 -0
- data/app/models/wf/case_assignment.rb +22 -0
- data/app/models/wf/case_command/add_comment.rb +17 -0
- data/app/models/wf/case_command/add_manual_assignment.rb +17 -0
- data/app/models/wf/case_command/add_token.rb +20 -0
- data/app/models/wf/case_command/add_workitem_assignment.rb +35 -0
- data/app/models/wf/case_command/begin_workitem_action.rb +33 -0
- data/app/models/wf/case_command/cancel.rb +17 -0
- data/app/models/wf/case_command/cancel_workitem.rb +20 -0
- data/app/models/wf/case_command/clear_manual_assignments.rb +16 -0
- data/app/models/wf/case_command/clear_workitem_assignments.rb +20 -0
- data/app/models/wf/case_command/consume_token.rb +23 -0
- data/app/models/wf/case_command/enable_transitions.rb +33 -0
- data/app/models/wf/case_command/end_workitem_action.rb +25 -0
- data/app/models/wf/case_command/finish_workitem.rb +18 -0
- data/app/models/wf/case_command/finished_p.rb +28 -0
- data/app/models/wf/case_command/fire_message_transition.rb +20 -0
- data/app/models/wf/case_command/fire_transition_internal.rb +41 -0
- data/app/models/wf/case_command/lock_token.rb +21 -0
- data/app/models/wf/case_command/new.rb +17 -0
- data/app/models/wf/case_command/release_token.rb +20 -0
- data/app/models/wf/case_command/remove_manual_assignment.rb +17 -0
- data/app/models/wf/case_command/remove_workitem_assignment.rb +24 -0
- data/app/models/wf/case_command/resume.rb +17 -0
- data/app/models/wf/case_command/set_workitem_assignments.rb +32 -0
- data/app/models/wf/case_command/start_case.rb +19 -0
- data/app/models/wf/case_command/start_workitem.rb +26 -0
- data/app/models/wf/case_command/suspend.rb +17 -0
- data/app/models/wf/case_command/sweep_automatic_transitions.rb +31 -0
- data/app/models/wf/case_command/sweep_timed_transitions.rb +16 -0
- data/app/models/wf/case_command/workitem_action.rb +20 -0
- data/app/models/wf/comment.rb +21 -0
- data/app/models/wf/demo_target.rb +18 -0
- data/app/models/wf/entry.rb +33 -0
- data/app/models/wf/field.rb +53 -0
- data/app/models/wf/field_value.rb +30 -0
- data/app/models/wf/form.rb +18 -0
- data/app/models/wf/group.rb +21 -0
- data/app/models/wf/guard.rb +73 -0
- data/app/models/wf/party.rb +22 -0
- data/app/models/wf/place.rb +28 -0
- data/app/models/wf/token.rb +37 -0
- data/app/models/wf/transition.rb +49 -0
- data/app/models/wf/transition_static_assignment.rb +21 -0
- data/app/models/wf/user.rb +26 -0
- data/app/models/wf/workflow.rb +182 -0
- data/app/models/wf/workitem.rb +78 -0
- data/app/models/wf/workitem_assignment.rb +19 -0
- data/app/views/layouts/wf/_alert.html.erb +4 -0
- data/app/views/layouts/wf/_footer.html.erb +13 -0
- data/app/views/layouts/wf/_nav.html.erb +13 -0
- data/app/views/layouts/wf/_notice.html.erb +4 -0
- data/app/views/layouts/wf/application.html.erb +34 -0
- data/app/views/wf/arcs/_form.html.erb +40 -0
- data/app/views/wf/arcs/edit.html.erb +1 -0
- data/app/views/wf/arcs/new.html.erb +1 -0
- data/app/views/wf/arcs/show.html.erb +67 -0
- data/app/views/wf/cases/_form.html.erb +27 -0
- data/app/views/wf/cases/index.html.erb +35 -0
- data/app/views/wf/cases/new.html.erb +1 -0
- data/app/views/wf/cases/show.html.erb +113 -0
- data/app/views/wf/comments/new.html.erb +27 -0
- data/app/views/wf/fields/_form.html.erb +42 -0
- data/app/views/wf/fields/edit.html.erb +1 -0
- data/app/views/wf/fields/new.html.erb +1 -0
- data/app/views/wf/forms/_form.html.erb +32 -0
- data/app/views/wf/forms/edit.html.erb +1 -0
- data/app/views/wf/forms/index.html.erb +32 -0
- data/app/views/wf/forms/new.html.erb +1 -0
- data/app/views/wf/forms/show.html.erb +53 -0
- data/app/views/wf/guards/_form.html.erb +43 -0
- data/app/views/wf/guards/edit.html.erb +1 -0
- data/app/views/wf/guards/new.html.erb +1 -0
- data/app/views/wf/places/_form.html.erb +43 -0
- data/app/views/wf/places/edit.html.erb +1 -0
- data/app/views/wf/places/new.html.erb +1 -0
- data/app/views/wf/transitions/_form.html.erb +92 -0
- data/app/views/wf/transitions/edit.html.erb +1 -0
- data/app/views/wf/transitions/new.html.erb +1 -0
- data/app/views/wf/workflows/_form.html.erb +32 -0
- data/app/views/wf/workflows/edit.html.erb +1 -0
- data/app/views/wf/workflows/index.html.erb +38 -0
- data/app/views/wf/workflows/new.html.erb +1 -0
- data/app/views/wf/workflows/show.html.erb +177 -0
- data/app/views/wf/workitem_assignments/new.html.erb +27 -0
- data/app/views/wf/workitems/index.html.erb +68 -0
- data/app/views/wf/workitems/pre_finish.html.erb +33 -0
- data/app/views/wf/workitems/show.html.erb +211 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20200130201043_init.rb +226 -0
- data/db/migrate/20200130201641_init_some_data.rb +15 -0
- data/db/migrate/20200131200455_create_wf_entries.rb +19 -0
- data/db/migrate/20200201001543_add_target_field_name_for_guard.rb +7 -0
- data/lib/tasks/wf_tasks.rake +5 -0
- data/lib/wf/engine.rb +10 -0
- data/lib/wf/version.rb +5 -0
- data/lib/wf.rb +7 -0
- metadata +312 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class CancelWorkitem
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise("The workitem is not in state #{workitem.state}") unless workitem.started?
|
13
|
+
Wf::ApplicationRecord.transaction do
|
14
|
+
workitem.update!(state: :canceled, :canceled_at: Time.zone.now)
|
15
|
+
ReleaseToken.call(workitem)
|
16
|
+
SweepAutomaticTransitions.call(workitem.case)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class ClearManualAssignments
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case, :transition
|
7
|
+
def initialize(wf_case, transition)
|
8
|
+
@wf_case = wf_case
|
9
|
+
@transition = transition
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
wf_case.case_assignments.where(transition: transition).find_each(&:destroy)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class ClearWorkitemAssignments
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem, :permanent
|
7
|
+
def initialize(workitem, permanent = true)
|
8
|
+
@workitem = workitem
|
9
|
+
@permanent = permanent
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
Wf::ApplicationRecord.transaction do
|
14
|
+
ClearManualAssignments.call(workitem.case, workitem.transition) if permanent
|
15
|
+
workitem.workitem_assignments.delete_all
|
16
|
+
workitem.transition.unassignment_callback.constantize.new(workitem.id).perform
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class ConsumeToken
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case, :place, :locked_item
|
7
|
+
def initialize(wf_case, place, locked_item = nil)
|
8
|
+
@wf_case = wf_case
|
9
|
+
@place = place
|
10
|
+
@locked_item = locked_item
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
Wf::ApplicationRecord.transaction do
|
15
|
+
if locked_item
|
16
|
+
wf_case.tokens.where(place: place, state: :locked, locked_workitem_id: locked_item.id).update(consumed_at: Time.zone.now, state: :consumed)
|
17
|
+
else
|
18
|
+
wf_case.tokens.where(id: wf_case.tokens.where(place: place, state: :free).first&.id).update(consumed_at: Time.zone.now, state: :consumed)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class EnableTransitions
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
wf_case.workitems.enabled.each do |workitem|
|
14
|
+
workitem.update!(state: :overridden, overridden_at: Time.zone.now) unless wf_case.can_fire?(workitem.transition)
|
15
|
+
end
|
16
|
+
wf_case.workflow.transitions.each do |transition|
|
17
|
+
next unless wf_case.can_fire?(transition) && !transition.workitems.where(case: wf_case, state: %i[enabled started]).exists?
|
18
|
+
|
19
|
+
trigger_time = Time.zone.now + transition.trigger_limit.minutes if transition.trigger_limit && transition.time?
|
20
|
+
workitem = wf_case.workitems.create!(
|
21
|
+
workflow: wf_case.workflow,
|
22
|
+
transition: transition,
|
23
|
+
state: :enabled,
|
24
|
+
trigger_time: trigger_time
|
25
|
+
)
|
26
|
+
Wf::FireTimedWorkitemJob.set(wait: transition.trigger_limit.minutes).perform_later(workitem.id) if trigger_time
|
27
|
+
SetWorkitemAssignments.call(workitem)
|
28
|
+
workitem.transition.unassignment_callback.constantize.new(workitem.id).perform_now if workitem.workitem_assignments.count == 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class EndWorkitemAction
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem, :action, :user
|
7
|
+
def initialize(workitem, user, action = :start)
|
8
|
+
@workitem = workitem
|
9
|
+
@action = action
|
10
|
+
@user = user
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
if action == :start
|
15
|
+
StartWorkitem.call(workitem, user)
|
16
|
+
elsif action == :finish
|
17
|
+
FinishWorkitem.call(workitem, user)
|
18
|
+
elsif action == :cancel
|
19
|
+
CancelWorkitem.call(workitem, user)
|
20
|
+
elsif action == :comment
|
21
|
+
raise("Unknown action #{action}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class FinishWorkitem
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
FireTransitionInternal.call(workitem)
|
14
|
+
SweepAutomaticTransitions.call(workitem.case)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class FinishedP
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return true if wf_case.finished?
|
13
|
+
|
14
|
+
end_place = wf_case.workflow.places.end.first
|
15
|
+
end_place_token_num = Wf::ApplicationRecord.uncached { wf_case.tokens.where(place: end_place).count }
|
16
|
+
if end_place_token_num == 0
|
17
|
+
false
|
18
|
+
else
|
19
|
+
free_and_locked_token_num = wf_case.tokens.where(place: end_place).where(state: %i[free locked]).count
|
20
|
+
raise("The workflow net is misconstructed: Some parallel executions have not finished.") if free_and_locked_token_num > 1
|
21
|
+
|
22
|
+
ConsumeToken.call(wf_case, end_place)
|
23
|
+
wf_case.finished!
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class FireMessageTransition
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise("Transition #{workitem.transition.name} is not message triggered") unless workitem.transition.message?
|
13
|
+
|
14
|
+
Wf::ApplicationRecord.transaction do
|
15
|
+
FireTransitionInternal.call(workitem)
|
16
|
+
SweepAutomaticTransitions.call(workitem.case)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class FireTransitionInternal
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
if workitem.enabled?
|
13
|
+
locked_item = nil
|
14
|
+
elsif workitem.started?
|
15
|
+
locked_item = workitem
|
16
|
+
else
|
17
|
+
raise("can not fire the transition if it is not in state enabled or started.")
|
18
|
+
end
|
19
|
+
Wf::ApplicationRecord.transaction do
|
20
|
+
workitem.update!(finished_at: Time.zone.now, state: :finished)
|
21
|
+
# TODO: only in?
|
22
|
+
workitem.transition.arcs.each do |arc|
|
23
|
+
ConsumeToken.call(workitem.case, arc.place, locked_item)
|
24
|
+
end
|
25
|
+
# last arc without guard -> pass
|
26
|
+
has_passed = false
|
27
|
+
workitem.transition.arcs.out.order("guards_count DESC").each do |arc|
|
28
|
+
if workitem.transition.explicit_or_split?
|
29
|
+
if workitem.pass_guard?(arc, has_passed)
|
30
|
+
has_passed = true
|
31
|
+
AddToken.call(workitem.case, arc.place)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
AddToken.call(workitem.case, arc.place)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
workitem.transition.fire_callback.constantize.new(workitem.id).perform_now
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class LockToken
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case, :place, :workitem
|
7
|
+
def initialize(wf_case, place, workitem)
|
8
|
+
@wf_case = wf_case
|
9
|
+
@place = place
|
10
|
+
@workitem = workitem
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
wf_case.tokens.free.where(place: place).limit(1).update_all(
|
15
|
+
state: :locked,
|
16
|
+
locked_at: Time.zone.now,
|
17
|
+
locked_workitem_id: workitem.id
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class New
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workflow, :target
|
7
|
+
def initialize(workflow, target = nil)
|
8
|
+
@workflow = workflow
|
9
|
+
@target = target
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
wf_case = workflow.cases.create!(targetable: target, state: :created)
|
14
|
+
wf_case
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class ReleaseToken
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
Wf::Token.where(locked_workitem_id: workitem.id).locked.each do |token|
|
14
|
+
AddToken.call(token.case, token.place)
|
15
|
+
token.update!(state: :canceled, canceled_at: Time.zone.now)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class RemoveManualAssignment
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case, :transition, :party
|
7
|
+
def initialize(wf_case, transition, party)
|
8
|
+
@wf_case = wf_case
|
9
|
+
@transition = transition
|
10
|
+
@party = party
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
wf_case.case_assignments.where(transition: transition, party: party).find_each(&:destroy)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class RemoveWorkitemAssignment
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem, :party, :permanent
|
7
|
+
def initialize(workitem, party, permanent = true)
|
8
|
+
@workitem = workitem
|
9
|
+
@party = party
|
10
|
+
@permanent = permanent
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
return if party.nil?
|
15
|
+
|
16
|
+
Wf::ApplicationRecord.transaction do
|
17
|
+
RemoveManualAssignment.call(workitem.case, workitem.transition, party) if permanent
|
18
|
+
workitem.workitem_assignments.where(party: party).first&.destroy
|
19
|
+
|
20
|
+
workitem.transition.unassignment_callback.constantize.new(workitem.id).perform_now if workitem.workitem_assignments.count == 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class Resume
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise("Only suspended or canceled cases can be resumed") unless wf_case.suspended? || wf_case.canceled?
|
13
|
+
|
14
|
+
wf_case.active!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class SetWorkitemAssignments
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem
|
7
|
+
def initialize(workitem)
|
8
|
+
@workitem = workitem
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
has_case_ass = false
|
14
|
+
workitem.case.case_assignments.where(transition: workitem.transition).find_each do |case_ass|
|
15
|
+
AddWorkitemAssignment.call(workitem, case_ass.party, false)
|
16
|
+
has_case_ass = true
|
17
|
+
end
|
18
|
+
|
19
|
+
unless has_case_ass
|
20
|
+
callback_values = workitem.transition.assignment_callback.constantize.new(workitem.id).perform
|
21
|
+
if callback_values.present?
|
22
|
+
# TODO: do assignment for callback.
|
23
|
+
else
|
24
|
+
workitem.transition.transition_static_assignments.each do |static_assignment|
|
25
|
+
AddWorkitemAssignment.call(workitem, static_assignment.party, false)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class StartCase
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
wf_case.active!
|
14
|
+
AddToken.call(wf_case, wf_case.workflow.places.start.first)
|
15
|
+
SweepAutomaticTransitions.call(wf_case)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class StartWorkitem
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem, :user
|
7
|
+
def initialize(workitem, user)
|
8
|
+
@workitem = workitem
|
9
|
+
@user = user
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
raise("The workitem is not in state #{workitem.state}") unless workitem.enabled?
|
14
|
+
|
15
|
+
# TODO: holding timeout
|
16
|
+
Wf::ApplicationRecord.transaction do
|
17
|
+
workitem.update!(state: :started, holding_user: user)
|
18
|
+
|
19
|
+
workitem.transition.arcs.in.each do |arc|
|
20
|
+
LockToken.call(workitem.case, arc.place, workitem)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
workitem
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class Suspend
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
raise("Only active or suspended cases can be canceled") unless wf_case.active?
|
13
|
+
|
14
|
+
wf_case.suspended!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class SweepAutomaticTransitions
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :wf_case
|
7
|
+
def initialize(wf_case)
|
8
|
+
@wf_case = wf_case
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Wf::ApplicationRecord.transaction do
|
13
|
+
EnableTransitions.call(wf_case)
|
14
|
+
done = false
|
15
|
+
until done
|
16
|
+
done = true
|
17
|
+
finished = FinishedP.call(wf_case).result
|
18
|
+
next if finished
|
19
|
+
|
20
|
+
Wf::ApplicationRecord.uncached do
|
21
|
+
wf_case.workitems.joins(:transition).where(state: :enabled).where(Wf::Transition.table_name => { trigger_type: Wf::Transition.trigger_types[:automatic] }).find_each do |item|
|
22
|
+
FireTransitionInternal.call(item)
|
23
|
+
done = false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
EnableTransitions.call(wf_case)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class SweepTimedTransitions
|
5
|
+
prepend SimpleCommand
|
6
|
+
|
7
|
+
def call
|
8
|
+
Wf::ApplicationRecord.transaction do
|
9
|
+
Wf::Workitem.enabled.where("trigger_time <= ?", Time.zone.now).find_each do |item|
|
10
|
+
FireTransitionInternal.call(item)
|
11
|
+
SweepAutomaticTransitions.call(item.case)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Wf::CaseCommand
|
4
|
+
class WorkitemAction
|
5
|
+
prepend SimpleCommand
|
6
|
+
attr_reader :workitem, :action, :user
|
7
|
+
def initialize(workitem, user, action = :start)
|
8
|
+
@workitem = workitem
|
9
|
+
@action = action
|
10
|
+
@user = user
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
Wf::ApplicationRecord.transaction do
|
15
|
+
BeginWorkitemAction.call(workitem, user, action)
|
16
|
+
EndWorkitemAction.call(workitem, user, action)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# == Schema Information
|
3
|
+
#
|
4
|
+
# Table name: wf_comments
|
5
|
+
#
|
6
|
+
# id :integer not null, primary key
|
7
|
+
# workitem_id :integer
|
8
|
+
# user_id :string
|
9
|
+
# body :text
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
#
|
13
|
+
|
14
|
+
# frozen_string_literal: true
|
15
|
+
|
16
|
+
module Wf
|
17
|
+
class Comment < ApplicationRecord
|
18
|
+
belongs_to :workitem
|
19
|
+
belongs_to :user, class_name: Wf::Workflow.user_class.to_s
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_demo_targets
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# description :string
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
#
|
13
|
+
|
14
|
+
module Wf
|
15
|
+
class DemoTarget < ApplicationRecord
|
16
|
+
has_many :cases, as: :targetable
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_entries
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# user_id :string
|
9
|
+
# workitem_id :integer
|
10
|
+
# payload :json default("{}")
|
11
|
+
# created_at :datetime not null
|
12
|
+
# updated_at :datetime not null
|
13
|
+
#
|
14
|
+
|
15
|
+
module Wf
|
16
|
+
class Entry < ApplicationRecord
|
17
|
+
belongs_to :user, class_name: Wf::Workflow.user_class.to_s
|
18
|
+
belongs_to :workitem
|
19
|
+
has_many :field_values
|
20
|
+
|
21
|
+
after_initialize do
|
22
|
+
self.payload = {} if payload.blank?
|
23
|
+
end
|
24
|
+
|
25
|
+
def json
|
26
|
+
field_values.includes(:field).map { |x| [x.field_id.to_i, { field_id: x.id.to_i, field_name: x.field.name, value: x.value_after_cast }] }.to_h
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_payload!
|
30
|
+
update(payload: json)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_fields
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# form_id :integer
|
10
|
+
# position :integer default("0")
|
11
|
+
# field_type :integer default("0")
|
12
|
+
# field_type_name :string
|
13
|
+
# default_value :string
|
14
|
+
# created_at :datetime not null
|
15
|
+
# updated_at :datetime not null
|
16
|
+
#
|
17
|
+
|
18
|
+
module Wf
|
19
|
+
class Field < ApplicationRecord
|
20
|
+
belongs_to :form, touch: true
|
21
|
+
|
22
|
+
enum field_type: {
|
23
|
+
string: 0,
|
24
|
+
integer: 1,
|
25
|
+
boolean: 2,
|
26
|
+
date: 3,
|
27
|
+
datetime: 4,
|
28
|
+
decimal: 5,
|
29
|
+
float: 6,
|
30
|
+
json: 7,
|
31
|
+
text: 8,
|
32
|
+
|
33
|
+
"string[]": 20,
|
34
|
+
"integer[]": 21,
|
35
|
+
"date[]": 23,
|
36
|
+
"datetime[]": 24,
|
37
|
+
"decimal[]": 25,
|
38
|
+
"float[]": 26,
|
39
|
+
"json[]": 27,
|
40
|
+
"text[]": 28
|
41
|
+
}
|
42
|
+
|
43
|
+
def type_for_cast
|
44
|
+
type = field_type.to_s.match(/^(\w+)(\[\])?$/)[1]
|
45
|
+
is_array = field_type.to_s.match(/^(\w+)(\[\])?$/)[2] == "[]"
|
46
|
+
if is_array
|
47
|
+
ActiveRecord::Type.lookup(type.to_sym, array: true)
|
48
|
+
else
|
49
|
+
ActiveRecord::Type.lookup(type.to_sym)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|