Passed
Push — master ( fea04c...284445 )
by Andreas
19:23
created

org_openpsa_projects_workflow::reject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 10
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package org.openpsa.projects
4
 * @author Nemein Oy http://www.nemein.com/
5
 * @copyright Nemein Oy http://www.nemein.com/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
/**
10
 * org.openpsa.projects site interface class.
11
 *
12
 * @package org.openpsa.projects
13
 */
14
class org_openpsa_projects_workflow
15
{
16
    /**
17
     * @throws midcom_error
18
     */
19 1
    public static function run(string $command, org_openpsa_projects_task_dba $task)
20
    {
21 1
        if (!method_exists(__CLASS__, $command)) {
22
            throw new midcom_error("Method not implemented");
23
        }
24 1
        return static::$command($task);
25
    }
26
27
    /**
28
     * Returns the status type of a given status
29
     */
30 32
    public static function get_status_type(int $status) : string
31
    {
32
        $map = [
33 32
            org_openpsa_projects_task_status_dba::REJECTED => 'rejected',
34
            org_openpsa_projects_task_status_dba::PROPOSED => 'not_started',
35
            org_openpsa_projects_task_status_dba::DECLINED => 'not_started',
36
            org_openpsa_projects_task_status_dba::ACCEPTED => 'not_started',
37
            org_openpsa_projects_task_status_dba::STARTED => 'ongoing',
38
            org_openpsa_projects_task_status_dba::REOPENED => 'ongoing',
39
            org_openpsa_projects_task_status_dba::COMPLETED => 'closed',
40
            org_openpsa_projects_task_status_dba::APPROVED => 'closed',
41
            org_openpsa_projects_task_status_dba::CLOSED => 'closed',
42
            org_openpsa_projects_task_status_dba::ONHOLD => 'on_hold'
43
        ];
44 32
        if (array_key_exists($status, $map)) {
45 32
            return $map[$status];
46
        }
47
        return 'on_hold';
48
    }
49
50 2
    public static function render_status_control(org_openpsa_projects_task_dba $task) : string
51
    {
52 2
        $prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX);
53 2
        if ($task->status < org_openpsa_projects_task_status_dba::COMPLETED) {
54 2
            $action = 'complete';
55 2
            $checked = '';
56
        } else {
57
            if ($task->status == org_openpsa_projects_task_status_dba::COMPLETED) {
58
                $action = 'remove_complete';
59
            } else {
60
                $action = 'reopen';
61
            }
62
            $checked = ' checked="checked"';
63
        }
64 2
        $html = '<form method="post" action="' . $prefix . 'workflow/' . $task->guid . '/">';
0 ignored issues
show
Bug introduced by
Are you sure $prefix of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

64
        $html = '<form method="post" action="' . /** @scrutinizer ignore-type */ $prefix . 'workflow/' . $task->guid . '/">';
Loading history...
65 2
        $html .= '<input type="hidden" name="org_openpsa_projects_workflow_action[' . $action . ']" value="true" />';
66 2
        $html .= '<input type="checkbox"' . $checked . ' name="org_openpsa_projects_workflow_dummy" value="true" onchange="this.form.submit()" />';
67 2
        $html .= '</form>';
68 2
        return $html;
69
    }
70
71
    /**
72
     * Shortcut for creating status object
73
     */
74 25
    public static function create_status(org_openpsa_projects_task_dba $task, int $status_type, int $target_person, string $comment = '') : bool
75
    {
76 25
        debug_print_function_stack('create_status called from: ');
77 25
        $status = new org_openpsa_projects_task_status_dba();
78 25
        $status->targetPerson = $target_person;
79 25
        $status->task = $task->id;
80 25
        $status->type = $status_type;
81 25
        $status->comment = $comment;
82
83 25
        $ret = $status->create();
84
85 25
        if (!$ret) {
86
            debug_add('failed to create status object, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_WARN);
87
        }
88 25
        return $ret;
89
    }
90
91
    /**
92
     * Propose task to a resource
93
     */
94 7
    public static function propose(org_openpsa_projects_task_dba $task, int $pid, string $comment = '') : bool
95
    {
96 7
        debug_add("saving proposed status for person {$pid}");
97 7
        return self::create_status($task, org_openpsa_projects_task_status_dba::PROPOSED, $pid, $comment);
98
    }
99
100
    /**
101
     * Accept the proposal
102
     */
103 5
    public static function accept(org_openpsa_projects_task_dba $task, int $pid = -1, string $comment = '') : bool
104
    {
105 5
        if ($pid < 0) {
106 1
            $pid = midcom_connection::get_user();
107
        }
108 5
        debug_add("task->accept() called with user #" . $pid);
109
110 5
        return self::create_status($task, org_openpsa_projects_task_status_dba::ACCEPTED, $pid, $comment);
111
    }
112
113
    /**
114
     * Decline the proposal
115
     */
116 1
    static function decline(org_openpsa_projects_task_dba $task, string $comment = '') : bool
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
117
    {
118 1
        debug_add("task->decline() called with user #" . midcom_connection::get_user());
119
120 1
        return self::create_status($task, org_openpsa_projects_task_status_dba::DECLINED, midcom_connection::get_user(), $comment);
121
    }
122
123
    /**
124
     * Mark task as started (in case it's not already done)
125
     */
126 14
    public static function start(org_openpsa_projects_task_dba $task, int $started_by = 0) : bool
127
    {
128 14
        debug_add("task->start() called with user #" . midcom_connection::get_user());
129
        //PONDER: Check actual status objects for more accurate logic ?
130 14
        if (   $task->status >= org_openpsa_projects_task_status_dba::STARTED
131 14
            && $task->status <= org_openpsa_projects_task_status_dba::APPROVED) {
132
            //We already have started status
133
            debug_add('Task has already been started');
134
            return true;
135
        }
136 14
        return self::create_status($task, org_openpsa_projects_task_status_dba::STARTED, $started_by);
137
    }
138
139
    /**
140
     * Mark task as completed
141
     */
142 5
    public static function complete(org_openpsa_projects_task_dba $task, string $comment = '') : bool
143
    {
144 5
        debug_add("task->complete() called with user #" . midcom_connection::get_user());
145
        //TODO: Check deliverables
146 5
        if (!self::create_status($task, org_openpsa_projects_task_status_dba::COMPLETED, 0, $comment)) {
147
            return false;
148
        }
149
        //PONDER: Check ACL instead ?
150 5
        if (self::is_manager($task)) {
151
            //Manager marking task completed also approves it at the same time
152 4
            debug_add('We\'re the manager of this task (or it is orphaned), approving straight away');
153 4
            return self::approve($task, $comment);
154
        }
155
156 1
        return true;
157
    }
158
159
    /**
160
     * Drops a completed task to started status
161
     */
162
    static function remove_complete(org_openpsa_projects_task_dba $task, $comment = '') : bool
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
163
    {
164
        debug_add("task->remove_complete() called with user #" . midcom_connection::get_user());
165
        if ($task->status != org_openpsa_projects_task_status_dba::COMPLETED) {
166
            //Status is not completed, we can't remove that status.
167
            debug_add('status != completed, aborting');
168
            return false;
169
        }
170
        return self::_drop_to_started($task, $comment);
171
    }
172
173
    /**
174
     * Drops tasks status to started
175
     */
176
    private static function _drop_to_started(org_openpsa_projects_task_dba $task, string $comment = '') : bool
177
    {
178
        if ($task->status <= org_openpsa_projects_task_status_dba::STARTED) {
179
            debug_add('Task has not been started, aborting');
180
            return false;
181
        }
182
        return self::create_status($task, org_openpsa_projects_task_status_dba::STARTED, 0, $comment);
183
    }
184
185
    /**
186
     * Mark task as approved
187
     */
188 6
    static function approve(org_openpsa_projects_task_dba $task, string $comment = '') : bool
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
189
    {
190 6
        debug_add("task->approve() called with user #" . midcom_connection::get_user());
191
        //TODO: Check deliverables / Require to be completed first
192
        //PONDER: Check ACL instead ?
193 6
        if (!self::is_manager($task)) {
194 1
            debug_add("Current user #" . midcom_connection::get_user() . " is not manager of task, thus cannot approve", MIDCOM_LOG_ERROR);
195 1
            return false;
196
        }
197
198 5
        if (!self::create_status($task, org_openpsa_projects_task_status_dba::APPROVED, 0, $comment)) {
199
            return false;
200
        }
201 5
        debug_add('approved tasks get closed at the same time, calling this->close()');
202 5
        return self::close($task, $comment);
203
    }
204
205
    static function reject(org_openpsa_projects_task_dba $task, string $comment = '') : bool
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
206
    {
207
        debug_add("task->reject() called with user #" . midcom_connection::get_user());
208
        //TODO: Check deliverables / Require to be completed first
209
        //PONDER: Check ACL instead ?
210
        if (!self::is_manager($task)) {
211
            debug_add("Current user #" . midcom_connection::get_user() . " is not manager of task, thus cannot reject", MIDCOM_LOG_ERROR);
212
            return false;
213
        }
214
        return self::create_status($task, org_openpsa_projects_task_status_dba::REJECTED, 0, $comment);
215
    }
216
217
    /**
218
     * Drops an approved task to started status
219
     */
220
    static function remove_approve(org_openpsa_projects_task_dba $task, string $comment = '') : bool
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
221
    {
222
        debug_add("task->remove_approve() called with user #" . midcom_connection::get_user());
223
        if ($task->status != org_openpsa_projects_task_status_dba::APPROVED) {
224
            debug_add('Task is not approved, aborting');
225
            return false;
226
        }
227
        return self::_drop_to_started($task, $comment);
228
    }
229
230
    /**
231
     * Mark task as closed
232
     */
233 5
    public static function close(org_openpsa_projects_task_dba $task, string $comment = '') : bool
234
    {
235 5
        debug_add("task->close() called with user #" . midcom_connection::get_user());
236
        //TODO: Check deliverables / require to be approved first
237
        //PONDER: Check ACL instead?
238 5
        if (!self::is_manager($task)) {
239
            debug_add("Current user #" . midcom_connection::get_user() . " is not manager of task, thus cannot close", MIDCOM_LOG_ERROR);
240
            return false;
241
        }
242
243 5
        if (self::create_status($task, org_openpsa_projects_task_status_dba::CLOSED, 0, $comment)) {
244 5
            midcom::get()->uimessages->add(midcom::get()->i18n->get_string('org.openpsa.projects', 'org.openpsa.projects'), sprintf(midcom::get()->i18n->get_string('marked task "%s" closed', 'org.openpsa.projects'), $task->title));
245 5
            if ($task->agreement) {
246 2
                $agreement = new org_openpsa_sales_salesproject_deliverable_dba($task->agreement);
247
248
                // Set agreement delivered if this is the only open task for it
249 2
                $task_qb = org_openpsa_projects_task_dba::new_query_builder();
250 2
                $task_qb->add_constraint('agreement', '=', $task->agreement);
251 2
                $task_qb->add_constraint('status', '<', org_openpsa_projects_task_status_dba::CLOSED);
252 2
                $task_qb->add_constraint('id', '<>', $task->id);
253 2
                if ($task_qb->count() == 0) {
254
                    // No other open tasks, mark as delivered
255 2
                    $agreement->deliver(false);
256
                } else {
257
                    midcom::get()->uimessages->add(midcom::get()->i18n->get_string('org.openpsa.projects', 'org.openpsa.projects'), sprintf(midcom::get()->i18n->get_string('did not mark deliverable "%s" delivered due to other tasks', 'org.openpsa.sales'), $agreement->title), 'info');
258
                }
259
            }
260 5
            return true;
261
        }
262
        return false;
263
    }
264
265
    /**
266
     * Reopen a closed task
267
     */
268
    public static function reopen(org_openpsa_projects_task_dba $task, string $comment = '') : bool
269
    {
270
        debug_add("task->reopen() called with user #" . midcom_connection::get_user());
271
        if ($task->status != org_openpsa_projects_task_status_dba::CLOSED) {
272
            debug_add('Task is not closed, aborting');
273
            return false;
274
        }
275
        return self::create_status($task, org_openpsa_projects_task_status_dba::REOPENED, 0, $comment);
276
    }
277
278 7
    private static function is_manager(org_openpsa_projects_task_dba $task) : bool
279
    {
280 7
        return (   $task->manager == 0
281 7
                || midcom_connection::get_user() == $task->manager);
282
    }
283
}
284