Passed
Push — 1.0 ( 07b100...83f8df )
by Morven
05:31
created

OrdersDetailForm_ItemRequest::doDuplicate()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 20
nc 3
nop 2
dl 0
loc 34
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace SilverCommerce\OrdersAdmin\Forms\GridField;
4
5
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
6
use SilverStripe\Security\Member;
7
use SilverStripe\Security\Permission;
8
use SilverStripe\Security\Security;
9
use SilverStripe\Forms\Form;
10
use SilverStripe\Forms\FormAction;
11
use SilverStripe\Forms\LiteralField;
12
use SilverStripe\Forms\DropdownField;
13
use SilverStripe\View\Requirements;
14
use SilverStripe\Versioned\Versioned;
15
use SilverStripe\Versioned\DataDifferencer;
16
use SilverStripe\Core\Convert;
17
use SilverStripe\Admin\LeftAndMain;
18
use SilverStripe\Control\PjaxResponseNegotiator;
19
use SilverStripe\ORM\ValidationException;
20
use SilverStripe\ORM\ValidationResult;
21
use SilverCommerce\OrdersAdmin\Model\Invoice;
22
use SilverCommerce\OrdersAdmin\Model\Estimate;
23
24
class OrdersDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest
25
{
26
27
    private static $allowed_actions = [
28
        'edit',
29
        'view',
30
        'ItemEditForm'
31
    ];
32
    
33
    public function edit($request)
34
    {
35
        $controller = $this->getToplevelController();
36
        $form = $this->ItemEditForm();
37
38
        // If this is a new record, we need to save it first
39
        if ($this->record->ID == 0) {
40
            // ensure we populate any foreign keys first
41
            $list = $this->gridField->getList();
42
            if ($list instanceof HasManyList && !$this->record->isInDB()) {
43
                $key = $list->getForeignKey();
44
                $id = $list->getForeignID();
45
                $this->record->$key = $id;
46
            }
47
48
            $this->record->write();
49
            
50
            $controller
51
                ->getRequest()
52
                ->addHeader('X-Pjax', 'Content');
53
            
54
            return $controller->redirect($this->Link("edit"));
55
        }
56
57
        $return = $this->customise(array(
58
            'Backlink' => $controller->hasMethod('Backlink') ? $controller->Backlink() : $controller->Link(),
59
            'ItemEditForm' => $form,
60
        ))->renderWith($this->getTemplates());
61
        
62
        if ($request->isAjax()) {
63
            return $return;
64
        } else {
65
            // If not requested by ajax, we need to render it within the controller context+template
66
            return $controller->customise(array(
67
                // TODO CMS coupling
68
                'Content' => $return,
69
            ));
70
        }
71
    }
72
73
    public function ItemEditForm()
74
    {        
75
        $form = parent::ItemEditForm();
76
        $fields = $form->Fields();
77
        $actions = $form->Actions();
78
        $record = $this->record;
79
        $member = Member::currentUser();
80
        
81
        $can_view = $this->record->canView();
82
        $can_edit = $this->record->canEdit();
83
        $can_delete = $this->record->canDelete();
84
        $can_create = $this->record->canCreate();
85
        
86
        // First cache and remove the delete button
87
        $delete_action = $actions->dataFieldByName("action_doDelete");
88
        $actions->removeByName("action_doDelete");
89
        
90
        // Deal with Estimate objects
91
        if ($record->ClassName == Estimate::class) {            
92
            if ($record->ID && $can_edit) {
93
                $actions->insertAfter(
94
                    FormAction::create(
95
                        'doConvert',
96
                        _t('OrdersAdmin.ConvertToInvoice', 'Convert To Invoice')
97
                    )->setUseButtonTag(true)
98
                    ->addExtraClass('btn-outline-primary btn-hide-outline font-icon-sync'),
99
                    "action_doSave"
100
                );
101
            }
102
        }
103
104
        // Deal with Order objects
105
        if ($record->ClassName == Invoice::class) {
106
            $can_change_status = $this->record->canChangeStatus();
107
            
108
            // Set our status field as a dropdown (has to be here to
109
            // ignore canedit)
110
            // Allow users to change status (as long as they have permission)
111
            if ($can_edit || $can_change_status) {
112
                $status_field = DropdownField::create(
113
                    'Status',
114
                    null,
115
                    $record->config()->statuses
116
                );
117
                
118
                // Set default status if we can
119
                if (!$record->Status && !$record->config()->default_status) {
120
                    $status_field
121
                        ->setValue($record->config()->default_status);
122
                } else {
123
                    $status_field
124
                        ->setValue($record->Status);
125
                }
126
                
127
                $fields->replaceField("Status", $status_field);
128
            }
129
            
130
            // Setup order history
131
            if (Permission::check(array('ORDERS_EDIT_INVOICES', 'ADMIN'), 'any', $member)) {
132
                $versions = $record->AllVersions();
133
                $first_version = $versions->First();
134
                $curr_version = ($first_version) ? $versions->First() : null;
135
                $message = "";
136
137
                foreach ($versions as $version) {
138
                    $i = $version->Version;
139
                    $name = "History_{$i}";
140
141
                    if ($i > 1) {
142
                        $frm = Versioned::get_version($record->ClassName, $record->ID, $i - 1);
143
                        $to = Versioned::get_version($record->ClassName, $record->ID, $i);
144
                        $diff = new DataDifferencer($frm, $to);
145
146
                        if ($version->Author()) {
147
                            $message = "<p>{$version->Author()->FirstName} ({$version->LastEdited})</p>";
148
                        } else {
149
                            $message = "<p>Unknown ({$version->LastEdited})</p>";
150
                        }
151
152
                        if ($diff->ChangedFields()->exists()) {
153
                            $message .= "<ul>";
154
155
                            // Now loop through all changed fields and track as message
156
                            foreach ($diff->ChangedFields() as $change) {
157
                                if ($change->Name != "LastEdited") {
158
                                    $message .= "<li>{$change->Title}: {$change->Diff}</li>";
159
                                }
160
                            }
161
162
                            $message .= "</ul>";
163
                        }
164
                        
165
                        $fields->addFieldToTab("Root.History", LiteralField::create(
166
                            $name,
167
                            "<div class=\"field\">{$message}</div>"
168
                        ));
169
                    }
170
                }
171
            }
172
            
173
            // Is user cannot edit, but can change status, add change
174
            // status button
175
            if ($record->ID && !$can_edit && $can_change_status) {
176
                $actions->push(
177
                    FormAction::create('doChangeStatus', _t('OrdersAdmin.Save', 'Save'))
178
                        ->setUseButtonTag(true)
179
                        ->addExtraClass('btn-primary font-icon-save')
180
                );
181
            }
182
        }
183
        
184
        // Add a duplicate button, either after the save button or
185
        // the change status "save" button.
186
        if ($record->ID) {
187
            $duplicate_button = FormAction::create(
188
                'doDuplicate',
189
                _t('OrdersAdmin.Duplicate', 'Duplicate')
190
            )->setUseButtonTag(true)
191
            ->addExtraClass('btn-outline-primary  btn-hide-outline font-icon-switch');
192
            
193
            if ($actions->find("Name", "action_doSave")) {
194
                $actions->insertAfter($duplicate_button, "action_doSave");
195
            }
196
            
197
            if ($actions->find("Name", "action_doChangeStatus")) {
198
                $actions->insertAfter($duplicate_button, "action_doChangeStatus");
199
            }
200
        }
201
202
        if ($record->ID) {
203
            $html = '<a href="' . $record->DisplayLink() . '" ';
204
            $html .= 'target="_blank" class="btn btn-outline-primary  btn-hide-outline font-icon-eye"';
205
            $html .= '>' . _t('OrdersAdmin.View', 'View') . '</a>';
206
            
207
            $view_field = LiteralField::create('ViewButton', $html);
208
209
            $html = '<a href="' . $record->PDFLink() . '" ';
210
            $html .= 'target="_blank" class="btn btn-outline-primary  btn-hide-outline font-icon-down-circled"';
211
            $html .= '>' . _t('OrdersAdmin.Download', 'Download') . '</a>';
212
            
213
            $download_field = LiteralField::create('DownloadButton', $html);
214
            
215
            $actions->push($view_field, "action_doSave");
216
            $actions->push($download_field, "action_doSave");
217
        }
218
        
219
        // Finally, if allowed, re-add the delete button (so it is last)
220
        if ($record->ID && $can_delete) {
221
            $actions->push($delete_action);
222
        }
223
224
        $this->extend("updateItemEditForm", $form);
225
        
226
        return $form;
227
    }
228
    
229
    public function doDuplicate($data, $form)
230
    {
231
        $record = $this->record;
232
233
        if ($record && !$record->canEdit()) {
234
            return Security::permissionFailure($this);
235
        }
236
237
        $form->saveInto($record);
238
        
239
        $record->write();
240
        
241
        $new_record = $record->duplicate();
242
        
243
        $this->gridField->getList()->add($new_record);
244
245
        $message = sprintf(
246
            _t('OrdersAdmin.Duplicated', 'Duplicated %s %s'),
247
            $this->record->singular_name(),
248
            '"'.Convert::raw2xml($this->record->Title).'"'
249
        );
250
        
251
        $toplevelController = $this->getToplevelController();
252
        if ($toplevelController && $toplevelController instanceof LeftAndMain) {
253
            $backForm = $toplevelController->getEditForm();
254
            $backForm->sessionMessage($message, 'good', ValidationResult::CAST_HTML);
255
        } else {
256
            $form->sessionMessage($message, 'good', ValidationResult::CAST_HTML);
257
        }
258
        
259
        $toplevelController = $this->getToplevelController();
260
        $toplevelController->getRequest()->addHeader('X-Pjax', 'Content');
261
262
        return $toplevelController->redirect($this->getBacklink(), 302);
263
    }
264
    
265
    public function doConvert($data, $form)
266
    {
267
        $record = $this->record;
268
269
        if ($record && !$record->canEdit()) {
270
            return Security::permissionFailure($this);
271
        }
272
273
        $form->saveInto($record);
274
        
275
        $record = $record->convertToInvoice();
276
        $this->record = $record;
277
        
278
        $this->gridField->getList()->add($record);
279
280
        $message = sprintf(
281
            _t('OrdersAdmin.ConvertedToOrder', 'Converted %s %s'),
282
            $this->record->singular_name(),
283
            '"'.Convert::raw2xml($this->record->Title).'"'
284
        );
285
        
286
        $toplevelController = $this->getToplevelController();
287
        if ($toplevelController && $toplevelController instanceof LeftAndMain) {
288
            $backForm = $toplevelController->getEditForm();
289
            $backForm->sessionMessage($message, 'good', ValidationResult::CAST_HTML);
290
        } else {
291
            $form->sessionMessage($message, 'good', ValidationResult::CAST_HTML);
292
        }
293
        
294
        $toplevelController = $this->getToplevelController();
295
        $toplevelController->getRequest()->addHeader('X-Pjax', 'Content');
296
297
        return $toplevelController->redirect($this->getBacklink(), 302);
298
    }
299
    
300
    public function doChangeStatus($data, $form)
301
    {
302
        $new_record = $this->record->ID == 0;
303
        $controller = $this->getToplevelController();
304
        $list = $this->gridField->getList();
305
306
        try {
307
            $this->record->Status = $data["Status"];
308
            $this->record->write();
309
        } catch (ValidationException $e) {
310
            $form->sessionMessage($e->getResult()->message(), 'bad', ValidationResult::CAST_HTML);
311
            
312
            $responseNegotiator = new PjaxResponseNegotiator(array(
313
                'CurrentForm' => function () use (&$form) {
314
                    return $form->forTemplate();
315
                },
316
                'default' => function () use (&$controller) {
317
                    return $controller->redirectBack();
318
                }
319
            ));
320
            
321
            if ($controller->getRequest()->isAjax()) {
322
                $controller->getRequest()->addHeader('X-Pjax', 'CurrentForm');
323
            }
324
            
325
            return $responseNegotiator->respond($controller->getRequest());
326
        }
327
328
        $link = '<a href="' . $this->Link('edit') . '">"'
329
            . htmlspecialchars($this->record->Title, ENT_QUOTES)
330
            . '"</a>';
331
332
        $message = _t(
333
            'OrdersAdmin.StatusChanged',
334
            'Status Changed {name} {link}',
335
            array(
336
                'name' => $this->record->i18n_singular_name(),
337
                'link' => $link
338
            )
339
        );
340
        
341
        $form->sessionMessage($message, 'good', ValidationResult::CAST_HTML);
342
343
        if ($this->gridField->getList()->byId($this->record->ID)) {
344
            // Return new view, as we can't do a "virtual redirect" via the CMS Ajax
345
            // to the same URL (it assumes that its content is already current, and doesn't reload)
346
            return $this->edit($controller->getRequest());
347
        } else {
348
            // Changes to the record properties might've excluded the record from
349
            // a filtered list, so return back to the main view if it can't be found
350
            $noActionURL = $controller->removeAction($data['url']);
351
            $controller->getRequest()->addHeader('X-Pjax', 'Content');
352
            return $controller->redirect($noActionURL, 302);
353
        }
354
    }
355
}
356