CopyModel   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 393
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 227
dl 0
loc 393
rs 3.36
c 1
b 0
f 0
wmc 63

9 Methods

Rating   Name   Duplication   Size   Complexity  
B saveAccountingEntry() 0 58 10
A loadModel() 0 11 3
A getPageData() 0 8 1
A autocompleteAction() 0 13 2
A saveDocumentEnd() 0 12 2
B savePurchaseDocument() 0 58 8
C saveProduct() 0 81 12
C privateCore() 0 53 17
B saveSalesDocument() 0 58 8

How to fix   Complexity   

Complex Class

Complex classes like CopyModel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CopyModel, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This file is part of FacturaScripts
4
 * Copyright (C) 2021-2024 Carlos Garcia Gomez <[email protected]>
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as
8
 * published by the Free Software Foundation, either version 3 of the
9
 * License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
namespace FacturaScripts\Core\Controller;
21
22
use FacturaScripts\Core\Base\Calculator;
23
use FacturaScripts\Core\Base\Controller;
24
use FacturaScripts\Core\Base\ControllerPermissions;
25
use FacturaScripts\Core\Model\Base\BusinessDocument;
26
use FacturaScripts\Core\Model\Producto;
27
use FacturaScripts\Core\Model\Variante;
28
use FacturaScripts\Core\Tools;
29
use FacturaScripts\Dinamic\Model\Asiento;
30
use FacturaScripts\Dinamic\Model\Cliente;
31
use FacturaScripts\Dinamic\Model\CodeModel;
32
use FacturaScripts\Dinamic\Model\Proveedor;
33
use FacturaScripts\Dinamic\Model\User;
34
use Symfony\Component\HttpFoundation\Response;
35
36
/**
37
 * Description of CopyModel
38
 *
39
 * @author Carlos Garcia Gomez <[email protected]>
40
 */
41
class CopyModel extends Controller
42
{
43
    const MODEL_NAMESPACE = '\\FacturaScripts\\Dinamic\\Model\\';
44
    const TEMPLATE_ASIENTO = 'CopyAsiento';
45
    const TEMPLATE_PRODUCTO = 'CopyProducto';
46
47
    /** @var CodeModel */
48
    public $codeModel;
49
50
    /** @var object */
51
    public $model;
52
53
    /** @var string */
54
    public $modelClass;
55
56
    /** @var string */
57
    public $modelCode;
58
59
    public function getPageData(): array
60
    {
61
        $data = parent::getPageData();
62
        $data['menu'] = 'sales';
63
        $data['title'] = 'copy';
64
        $data['icon'] = 'fas fa-cut';
65
        $data['showonmenu'] = false;
66
        return $data;
67
    }
68
69
    /**
70
     * @param Response $response
71
     * @param User $user
72
     * @param ControllerPermissions $permissions
73
     */
74
    public function privateCore(&$response, $user, $permissions)
75
    {
76
        parent::privateCore($response, $user, $permissions);
77
        $this->codeModel = new CodeModel();
78
79
        $action = $this->request->get('action');
80
        if ($action === 'autocomplete') {
81
            $this->autocompleteAction();
82
            return;
83
        } elseif (false === $this->loadModel()) {
84
            Tools::log()->warning('record-not-found');
85
            return;
86
        }
87
88
        // si no es un documento de compra o venta, cargamos su plantilla
89
        switch ($this->modelClass) {
90
            case 'Asiento':
91
                $this->setTemplate(self::TEMPLATE_ASIENTO);
92
                break;
93
94
            case 'Producto':
95
                $this->setTemplate(self::TEMPLATE_PRODUCTO);
96
                break;
97
        }
98
99
        if (false === $this->pipeFalse('before', $this->model)) {
0 ignored issues
show
introduced by
The condition false === $this->pipeFal...'before', $this->model) is always false.
Loading history...
100
            return;
101
        }
102
103
        $this->title .= ' ' . $this->model->primaryDescription();
104
        if ($action === 'save') {
105
            switch ($this->modelClass) {
106
                case 'AlbaranCliente':
107
                case 'FacturaCliente':
108
                case 'PedidoCliente':
109
                case 'PresupuestoCliente':
110
                    $this->saveSalesDocument();
111
                    break;
112
113
                case 'AlbaranProveedor':
114
                case 'FacturaProveedor':
115
                case 'PedidoProveedor':
116
                case 'PresupuestoProveedor':
117
                    $this->savePurchaseDocument();
118
                    break;
119
120
                case 'Asiento':
121
                    $this->saveAccountingEntry();
122
                    break;
123
124
                case 'Producto':
125
                    $this->saveProduct();
126
                    break;
127
            }
128
        }
129
    }
130
131
    protected function autocompleteAction(): void
132
    {
133
        $this->setTemplate(false);
134
        $results = [];
135
        $data = $this->request->request->all();
136
        foreach ($this->codeModel->search($data['source'], $data['fieldcode'], $data['fieldtitle'], $data['term']) as $value) {
137
            $results[] = [
138
                'key' => Tools::fixHtml($value->code),
139
                'value' => Tools::fixHtml($value->description)
140
            ];
141
        }
142
143
        $this->response->setContent(json_encode($results));
144
    }
145
146
    protected function loadModel(): bool
147
    {
148
        $this->modelClass = $this->request->get('model');
149
        $this->modelCode = $this->request->get('code');
150
        if (empty($this->modelClass) || empty($this->modelCode)) {
151
            return false;
152
        }
153
154
        $className = self::MODEL_NAMESPACE . $this->modelClass;
155
        $this->model = new $className();
156
        return $this->model->loadFromCode($this->modelCode);
157
    }
158
159
    protected function saveDocumentEnd(BusinessDocument $newDoc): void
160
    {
161
        $lines = $newDoc->getLines();
162
        if (false === Calculator::calculate($newDoc, $lines, true)) {
163
            Tools::log()->warning('record-save-error');
164
            $this->dataBase->rollback();
165
            return;
166
        }
167
168
        $this->dataBase->commit();
169
        Tools::log()->notice('record-updated-correctly');
170
        $this->redirect($newDoc->url() . '&action=save-ok');
171
    }
172
173
    protected function saveAccountingEntry(): void
174
    {
175
        if (false === $this->validateFormToken()) {
176
            return;
177
        }
178
179
        $this->dataBase->beginTransaction();
180
181
        // creamos el nuevo asiento
182
        $newEntry = new Asiento();
183
        $newEntry->canal = $this->request->request->get('canal');
184
        $newEntry->concepto = $this->request->request->get('concepto');
185
186
        $company = $this->request->request->get('idempresa');
187
        $newEntry->idempresa = empty($company) ? $newEntry->idempresa : $company;
188
189
        $diario = $this->request->request->get('iddiario');
190
        $newEntry->iddiario = empty($diario) ? null : $diario;
191
        $newEntry->importe = $this->model->importe;
192
193
        $fecha = $this->request->request->get('fecha');
194
        if (false === $newEntry->setDate($fecha)) {
195
            Tools::log()->warning('error-set-date');
196
            $this->dataBase->rollback();
197
            return;
198
        }
199
200
        if (false === $this->pipeFalse('beforeSaveAccounting', $newEntry)) {
0 ignored issues
show
introduced by
The condition false === $this->pipeFal...Accounting', $newEntry) is always false.
Loading history...
201
            $this->dataBase->rollback();
202
            return;
203
        }
204
205
        if (false === $newEntry->save()) {
206
            Tools::log()->warning('record-save-error');
207
            $this->dataBase->rollback();
208
            return;
209
        }
210
211
        // copiamos las líneas del asiento
212
        foreach ($this->model->getLines() as $line) {
213
            $newLine = $newEntry->getNewLine();
214
            $newLine->loadFromData($line->toArray(), ['idasiento', 'idpartida', 'idsubcuenta']);
215
216
            if (false === $this->pipeFalse('beforeSaveAccountingLine', $newLine)) {
217
                $this->dataBase->rollback();
218
                return;
219
            }
220
221
            if (false === $newLine->save()) {
222
                Tools::log()->warning('record-save-error');
223
                $this->dataBase->rollback();
224
                return;
225
            }
226
        }
227
228
        $this->dataBase->commit();
229
        Tools::log()->notice('record-updated-correctly');
230
        $this->redirect($newEntry->url() . '&action=save-ok');
231
    }
232
233
    protected function savePurchaseDocument(): void
234
    {
235
        if (false === $this->validateFormToken()) {
236
            return;
237
        }
238
239
        // buscamos el proveedor
240
        $subject = new Proveedor();
241
        if (false === $subject->loadFromCode($this->request->request->get('codproveedor'))) {
242
            Tools::log()->warning('record-not-found');
243
            return;
244
        }
245
246
        $this->dataBase->beginTransaction();
247
248
        // creamos el nuevo documento
249
        $className = self::MODEL_NAMESPACE . $this->modelClass;
250
        $newDoc = new $className();
251
        $newDoc->setAuthor($this->user);
252
        $newDoc->setSubject($subject);
253
        $newDoc->codalmacen = $this->request->request->get('codalmacen');
254
        $newDoc->setCurrency($this->model->coddivisa);
255
        $newDoc->codpago = $this->request->request->get('codpago');
256
        $newDoc->codserie = $this->request->request->get('codserie');
257
        $newDoc->dtopor1 = (float)$this->request->request->get('dtopor1', 0);
258
        $newDoc->dtopor2 = (float)$this->request->request->get('dtopor2', 0);
259
        $newDoc->setDate($this->request->request->get('fecha'), $this->request->request->get('hora'));
260
        $newDoc->numproveedor = $this->request->request->get('numproveedor');
261
        $newDoc->observaciones = $this->request->request->get('observaciones');
262
263
        if (false === $this->pipeFalse('beforeSavePurchase', $newDoc)) {
0 ignored issues
show
introduced by
The condition false === $this->pipeFal...SavePurchase', $newDoc) is always false.
Loading history...
264
            $this->dataBase->rollback();
265
            return;
266
        }
267
268
        if (false === $newDoc->save()) {
269
            Tools::log()->warning('record-save-error');
270
            $this->dataBase->rollback();
271
            return;
272
        }
273
274
        // copiamos las líneas del documento
275
        foreach ($this->model->getLines() as $line) {
276
            $newLine = $newDoc->getNewLine($line->toArray());
277
278
            if (false === $this->pipeFalse('beforeSavePurchaseLine', $newLine)) {
279
                $this->dataBase->rollback();
280
                return;
281
            }
282
283
            if (false === $newLine->save()) {
284
                Tools::log()->warning('record-save-error');
285
                $this->dataBase->rollback();
286
                return;
287
            }
288
        }
289
290
        $this->saveDocumentEnd($newDoc);
291
    }
292
293
    protected function saveSalesDocument(): void
294
    {
295
        if (false === $this->validateFormToken()) {
296
            return;
297
        }
298
299
        // buscamos el cliente
300
        $subject = new Cliente();
301
        if (false === $subject->loadFromCode($this->request->request->get('codcliente'))) {
302
            Tools::log()->warning('record-not-found');
303
            return;
304
        }
305
306
        $this->dataBase->beginTransaction();
307
308
        // creamos el nuevo documento
309
        $className = self::MODEL_NAMESPACE . $this->modelClass;
310
        $newDoc = new $className();
311
        $newDoc->setAuthor($this->user);
312
        $newDoc->setSubject($subject);
313
        $newDoc->codalmacen = $this->request->request->get('codalmacen');
314
        $newDoc->setCurrency($this->model->coddivisa);
315
        $newDoc->codpago = $this->request->request->get('codpago');
316
        $newDoc->codserie = $this->request->request->get('codserie');
317
        $newDoc->dtopor1 = (float)$this->request->request->get('dtopor1', 0);
318
        $newDoc->dtopor2 = (float)$this->request->request->get('dtopor2', 0);
319
        $newDoc->setDate($this->request->request->get('fecha'), $this->request->request->get('hora'));
320
        $newDoc->numero2 = $this->request->request->get('numero2');
321
        $newDoc->observaciones = $this->request->request->get('observaciones');
322
323
        if (false === $this->pipeFalse('beforeSaveSales', $newDoc)) {
0 ignored issues
show
introduced by
The condition false === $this->pipeFal...oreSaveSales', $newDoc) is always false.
Loading history...
324
            $this->dataBase->rollback();
325
            return;
326
        }
327
328
        if (false === $newDoc->save()) {
329
            Tools::log()->warning('record-save-error');
330
            $this->dataBase->rollback();
331
            return;
332
        }
333
334
        // copiamos las líneas del documento
335
        foreach ($this->model->getLines() as $line) {
336
            $newLine = $newDoc->getNewLine($line->toArray());
337
338
            if (false === $this->pipeFalse('beforeSaveSalesLine', $newLine)) {
339
                $this->dataBase->rollback();
340
                return;
341
            }
342
343
            if (false === $newLine->save()) {
344
                Tools::log()->warning('record-save-error');
345
                $this->dataBase->rollback();
346
                return;
347
            }
348
        }
349
350
        $this->saveDocumentEnd($newDoc);
351
    }
352
353
    protected function saveProduct(): void
354
    {
355
        if (false === $this->validateFormToken()) {
356
            return;
357
        }
358
359
        $this->dataBase->beginTransaction();
360
361
        // obtenemos el producto origen
362
        /** @var Producto $productoOrigen */
363
        $productoOrigen = $this->model;
364
365
        // obtenemos las variantes del producto origen
366
        $variantesProductoOrigen = $productoOrigen->getVariants();
367
368
        // creamos el nuevo producto y copiamos los campos del producto origen
369
        $productoDestino = new Producto();
370
371
        $camposProducto = array_keys((new Producto())->getModelFields());
372
        $camposExcluidos = ['actualizado', 'descripcion', 'fechaalta', 'idproducto', 'referencia', 'stockfis'];
373
374
        foreach ($camposProducto as $campo) {
375
            if (false === in_array($campo, $camposExcluidos)) {
376
                $productoDestino->{$campo} = $productoOrigen->{$campo};
377
            }
378
        }
379
380
        $productoDestino->descripcion = $this->request->request->get('descripcion');
381
        $productoDestino->referencia = $this->request->request->get('referencia');
382
383
        if (false === $this->pipeFalse('beforeSaveProduct', $productoDestino)) {
0 ignored issues
show
introduced by
The condition false === $this->pipeFal...uct', $productoDestino) is always false.
Loading history...
384
            $this->dataBase->rollback();
385
            return;
386
        }
387
388
        if (false === $productoDestino->save()) {
389
            Tools::log()->warning('record-save-error');
390
            $this->dataBase->rollback();
391
            return;
392
        }
393
394
        // creamos las nuevas variantes
395
        $camposVariante = array_keys((new Variante())->getModelFields());
396
        $camposExcluidos = ['idvariante', 'idproducto', 'referencia', 'stockfis'];
397
398
        foreach ($variantesProductoOrigen as $variante) {
399
            // Como al crear un producto siempre se crea
400
            // una variante principal aprovechamos esta
401
            // y la modificamos para que el producto destino
402
            // no tenga una variante más que el producto origen
403
            if ($variante === reset($variantesProductoOrigen)) {
404
                // si es el primer elemento del array, modificamos la variante existente
405
                $varianteDestino = $productoDestino->getVariants()[0];
406
            } else {
407
                $varianteDestino = new Variante();
408
            }
409
410
            foreach ($camposVariante as $campo) {
411
                if (false === in_array($campo, $camposExcluidos)) {
412
                    $varianteDestino->{$campo} = $variante->{$campo};
413
                }
414
            }
415
416
            // asignamos variantes al producto nuevo
417
            $varianteDestino->idproducto = $productoDestino->idproducto;
418
419
            if (false === $this->pipeFalse('beforeSaveVariant', $varianteDestino)) {
420
                $this->dataBase->rollback();
421
                return;
422
            }
423
424
            if (false === $varianteDestino->save()) {
425
                Tools::log()->warning('record-save-error');
426
                $this->dataBase->rollback();
427
                return;
428
            }
429
        }
430
431
        $this->dataBase->commit();
432
        Tools::log()->notice('record-updated-correctly');
433
        $this->redirect($productoDestino->url() . '&action=save-ok');
434
    }
435
}
436