DataMap::setFormOfPaymentField()   B
last analyzed

Complexity

Conditions 10
Paths 6

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 13
nc 6
nop 1
dl 0
loc 20
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * MÓDULO DE EMISIÓN ELECTRÓNICA F72X
5
 * UBL 2.1
6
 * Version 1.0
7
 *
8
 * Copyright 2019, Jaime Cruz
9
 */
10
11
namespace F72X\Sunat;
12
13
use DateTime;
14
use InvalidArgumentException;
15
use F72X\Company;
16
use F72X\Sunat\Catalogo;
17
use F72X\Sunat\DocumentGenerator;
18
19
/**
20
 * DataMap
21
 *
22
 * Esta clase es una representación interna de una factura o boleta, la cual se
23
 * encarga de aplicar toda la logica de negocio en cuanto a cálculos de tributos
24
 * y totales
25
 *
26
 */
27
class DataMap
28
{
29
30
    private $_rawData;
31
    private $documentType;
32
    private $currencyCode;
33
    private $documentId;
34
    private $officialDocumentName;
35
    private $documentSeries;
36
    private $documentNumber;
37
38
    /** @var DateTime */
39
    private $issueDate;
40
41
    /** @var DateTime */
42
    private $dueDate;
43
    private $operationType;
44
    private $customerDocType;
45
    private $customerDocNumber;
46
    private $customerRegName;
47
    private $customerAddress;
48
    private $purchaseOrder;
49
50
    private $formOfPayment;
51
    private $installments = [];
52
    private $pendingAmount = 0;
53
54
    /** @var InvoiceItems */
55
    private $_items;
56
    private $_rawItems;
57
    private $allowancesAndCharges = [];
58
59
    /** NOTES FIELDS */
60
    private $note;
61
    private $noteType;
62
    private $discrepancyResponseReason;
63
    private $noteAffectedDocType;
64
    private $noteAffectedDocId;
65
    /**
66
     *
67
     * @param array $data
68
     * @param string $type 01|03|07|08 The document type
69
     */
70
    public function __construct(array $data, $type)
71
    {
72
        // Type validation
73
        if (!in_array($type, ['01', '03', '07', '08'])) {
74
            throw new InvalidArgumentException("DataMap Error, el tipo de documento '$type', no es válido use 01|03|07|08");
75
        }
76
77
        // Items
78
        $items = new InvoiceItems();
79
        $items->populate($data['items'], $data['currencyCode']);
80
81
        $this->_rawData  = $data;
82
        $this->_rawItems = $data['items'];
83
        $this->setDefaults($data);
84
        $this->currencyCode         = $data['currencyCode'];
85
        $this->documentType         = $type;
86
        $this->documentSeries       = DocumentGenerator::buildDocumentSeries($type, $data['affectedDocType'], $data['documentSeries']);
87
        $this->documentNumber       = str_pad($data['documentNumber'], 8, '0', STR_PAD_LEFT);
88
        $this->officialDocumentName = Catalogo::getOfficialDocumentName($type);
89
        $this->documentId           = $this->documentSeries . '-' . $this->documentNumber;
90
        $this->issueDate            = new DateTime($data['issueDate']);
91
        if (isset($data['dueDate'])) {
92
            $this->dueDate            = new DateTime($data['dueDate']);
93
        }
94
        $this->customerDocType      = $data['customerDocType'];
95
        $this->customerDocNumber    = $data['customerDocNumber'];
96
        $this->customerRegName      = mb_strtoupper($data['customerRegName']);
97
        $this->customerAddress      = mb_strtoupper($data['customerAddress']);
98
        $this->_items               = $items;
99
        $this->allowancesAndCharges = $data['allowancesCharges'];
100
        // Facturas y notas de crédito deben establecer explicitamnte la forma de pago.
101
        if ($type == Catalogo::DOCTYPE_FACTURA || $type == Catalogo::DOCTYPE_NOTA_CREDITO) {
102
            $this->setFormOfPaymentField($data);
103
        }
104
        // Note
105
        $this->note = $data['note'];
106
        $this->setSpecificFields($data, $type);
107
    }
108
    private function setFormOfPaymentField(&$data)
109
    {
110
        if (!isset($data['formOfPayment'])) {
111
            throw new InvalidArgumentException("El campo 'formOfPayment', es obligatorio para facturas y notas de crédito");
112
        }
113
        $formOfPayment = $data['formOfPayment'];
114
        if (!in_array($formOfPayment, Catalogo::$FAC_FORMS_OF_PAYMENT)) {
115
            throw new InvalidArgumentException("El campo 'formOfPayment', no es válido use " . implode(', ', Catalogo::$FAC_FORMS_OF_PAYMENT));
116
        }
117
        $this->formOfPayment = $formOfPayment;
118
        // Caso crédito
119
        if ($formOfPayment == Catalogo::FAC_FORM_OF_PAYMENT_CREDITO) {
120
            if (!isset($data['pendingAmount']) || is_nan($data['pendingAmount']) || $data['pendingAmount'] <= 0) {
121
                throw new InvalidArgumentException("El campo 'pendingAmount', es obligatorio y debe ser mayor que cero para facturas y notas de crédito con forma de pago '" . Catalogo::FAC_FORM_OF_PAYMENT_CREDITO . "'");
122
            }
123
            if (!isset($data['installments']) || !is_array($data['installments']) || count($data['installments']) == 0) {
124
                throw new InvalidArgumentException("El campo 'installments', es obligatorio para facturas y notas de crédito con forma de pago '" . Catalogo::FAC_FORM_OF_PAYMENT_CREDITO . "'");
125
            }
126
            $this->pendingAmount = $data['pendingAmount'];
127
            $this->installments = $this->parseInstallments($data['installments']);
128
        }
129
    }
130
    private function parseInstallments($data)
131
    {
132
        $out = [];
133
        foreach ($data as $key => $item) {
134
            $inst = new CreditInstallment();
135
            $id = "Cuota" . str_pad($key + 1, 3, '0', STR_PAD_LEFT);
136
            $inst
137
                ->setId($id)
138
                ->setAmount($item['amount'])
139
                ->setPaymentDueDate(new DateTime($item['paymentDueDate']));
140
            $out[] = $inst;
141
        }
142
        return $out;
143
    }
144
145
    private function setSpecificFields(array $data, $type)
146
    {
147
        if (in_array($type, [Catalogo::DOCTYPE_FACTURA, Catalogo::DOCTYPE_BOLETA])) {
148
            $this->operationType = $data['operationType'];
149
            $this->purchaseOrder = $data['purchaseOrder'];
150
        } else {
151
            // Catálogo 9 tipo de nota de crédito, 10 tipo de nota de débito
152
            $catNumber = ($type == Catalogo::DOCTYPE_NOTA_CREDITO ? 9 : 10);
153
            $this->discrepancyResponseReason = Catalogo::getCatItemValue($catNumber, $data['noteType']);
154
            $this->noteType            = $data['noteType'];
155
            $this->noteAffectedDocType = $data['affectedDocType'];
156
            $this->noteAffectedDocId   = $data['affectedDocId'];
157
        }
158
    }
159
160
    private function setDefaults(array &$data)
161
    {
162
        $data['allowancesCharges'] = isset($data['allowancesCharges']) ? $data['allowancesCharges'] : [];
163
        $data['purchaseOrder'] = isset($data['purchaseOrder']) ? $data['purchaseOrder'] : null;
164
        $data['affectedDocType'] = isset($data['affectedDocType']) ? $data['affectedDocType'] : null;
165
        $data['note'] = isset($data['note']) ? $data['note'] : '';
166
    }
167
    public function getNoteType()
168
    {
169
        return $this->noteType;
170
    }
171
172
    public function getDiscrepancyResponseReason()
173
    {
174
        return $this->discrepancyResponseReason;
175
    }
176
177
    public function getNoteDescription()
178
    {
179
        return $this->note;
180
    }
181
    public function getNote()
182
    {
183
        return $this->note;
184
    }
185
    public function getNoteAffectedDocType()
186
    {
187
        return $this->noteAffectedDocType;
188
    }
189
190
    public function getNoteAffectedDocId()
191
    {
192
        return $this->noteAffectedDocId;
193
    }
194
195
    public function getDocumentId()
196
    {
197
        return $this->documentId;
198
    }
199
200
    public function getRawData()
201
    {
202
        return $this->_rawData;
203
    }
204
205
    /**
206
     * Boleta o Factura @CAT1
207
     * @return string
208
     */
209
    public function getDocumentType()
210
    {
211
        return $this->documentType;
212
    }
213
214
    public function getCurrencyCode()
215
    {
216
        return $this->currencyCode;
217
    }
218
219
    public function getOfficialDocumentName()
220
    {
221
        return $this->officialDocumentName;
222
    }
223
224
    public function getDocumentSeries()
225
    {
226
        return $this->documentSeries;
227
    }
228
229
    public function setDocumentSeries($documentSeries)
230
    {
231
        $this->documentSeries = $documentSeries;
232
        return $this;
233
    }
234
235
    public function getDocumentNumber()
236
    {
237
        return $this->documentNumber;
238
    }
239
240
    public function setDocumentNumber($documentNumber)
241
    {
242
        $this->documentNumber = $documentNumber;
243
        return $this;
244
    }
245
246
    public function getIssueDate()
247
    {
248
        return $this->issueDate;
249
    }
250
251
    public function setIssueDate(DateTime $IssueDate)
252
    {
253
        $this->issueDate = $IssueDate;
254
        return $this;
255
    }
256
257
    public function getDueDate()
258
    {
259
        return $this->dueDate;
260
    }
261
262
    public function setDueDate(DateTime $DueDate)
263
    {
264
        $this->dueDate = $DueDate;
265
        return $this;
266
    }
267
268
    public function getOperationType()
269
    {
270
        return $this->operationType;
271
    }
272
273
    public function setOperationType($operationType)
274
    {
275
        $this->operationType = $operationType;
276
        return $this;
277
    }
278
279
    public function getCustomerDocType()
280
    {
281
        return $this->customerDocType;
282
    }
283
284
    public function setCustomerDocType($customerDocType)
285
    {
286
        $this->customerDocType = $customerDocType;
287
        return $this;
288
    }
289
290
    public function getCustomerDocNumber()
291
    {
292
        return $this->customerDocNumber;
293
    }
294
295
    public function setCustomerDocNumber($customerDocNumber)
296
    {
297
        $this->customerDocNumber = $customerDocNumber;
298
        return $this;
299
    }
300
301
    public function getCustomerRegName()
302
    {
303
        return $this->customerRegName;
304
    }
305
306
    public function setCustomerRegName($customerRegName)
307
    {
308
        $this->customerRegName = $customerRegName;
309
        return $this;
310
    }
311
    public function getCustomerAddress()
312
    {
313
        return $this->customerAddress;
314
    }
315
316
    public function setCustomerAddress($customerAddress)
317
    {
318
        $this->customerAddress = $customerAddress;
319
        return $this;
320
    }
321
322
    public function getPurchaseOrder()
323
    {
324
        return $this->purchaseOrder;
325
    }
326
327
    public function setPurchaseOrder($purchaseOrder)
328
    {
329
        $this->purchaseOrder = $purchaseOrder;
330
        return $this;
331
    }
332
333
    public function getFormOfPayment()
334
    {
335
        return $this->formOfPayment;
336
    }
337
338
    /**
339
     *
340
     * @return InvoiceItems
341
     */
342
    public function getItems()
343
    {
344
        return $this->_items;
345
    }
346
    /**
347
     *
348
     * @return CreditInstallment[]
349
     */
350
    public function getInstallments()
351
    {
352
        return $this->installments;
353
    }
354
    public function getPendingAmount()
355
    {
356
        return $this->pendingAmount;
357
    }
358
    /**
359
     * Numero de items del documento
360
     * @return int
361
     */
362
    public function getTotalItems()
363
    {
364
        return $this->_items->getCount();
365
    }
366
367
    public function getRawItems()
368
    {
369
        return $this->_rawItems;
370
    }
371
372
    public function getAllowancesAndCharges()
373
    {
374
        return $this->allowancesAndCharges;
375
    }
376
377
    public function setAllowancesAndCharges($allowancesAndCharges)
378
    {
379
        $this->allowancesAndCharges = $allowancesAndCharges;
380
        return $this;
381
    }
382
383
    /**
384
     * Monto facturable (Valor de venta)
385
     *
386
     * Formula = SUM(BASE_FACTURABLE_X_ITEM)
387
     *
388
     * @return float
389
     */
390
    public function getBillableAmount()
391
    {
392
        return $this->_items->getTotalBillableAmount();
393
    }
394
395
    /**
396
     * Base imponible
397
     *
398
     * Formula = SUM(BASE_IMPONIBLE_X_ITEM) - DESCUENTOS_GLOBALES + CARGOS_GLOBALES
399
     *
400
     * @return float
401
     */
402
    public function getTaxableAmount()
403
    {
404
        $totalItems = $this->_items->getTotalTaxableOperations();
405
        return $this->applyAllowancesAndCharges($totalItems);
406
    }
407
408
    /**
409
     * Monto con impuestos
410
     *
411
     * Formula = BASE_IMPONIBLE + IGV
412
     *
413
     * @return float
414
     */
415
    public function getTaxedAmount()
416
    {
417
        $totalTaxableAmount = $this->getTaxableAmount();
418
        $totalIgv = $this->getIGV();
419
        return $totalTaxableAmount + $totalIgv;
420
    }
421
422
    /**
423
     * Total operaciones gravadas
424
     * @return float
425
     */
426
    public function getTotalTaxableOperations()
427
    {
428
        return $this->getTaxableAmount();
429
    }
430
431
    /**
432
     * Total operaciones gratuitas
433
     * @return float
434
     */
435
    public function getTotalFreeOperations()
436
    {
437
        return $this->_items->getTotalFreeOperations();
438
    }
439
440
    /**
441
     * Total operationes exoneradas
442
     *
443
     * Formula = SUM(EXEMPTED_OPERATIONS_X_ITEM) - DESCUENTOS_GLOBALES + CARGOS_GLOBALES
444
     *
445
     * @return float
446
     */
447
    public function getTotalExemptedOperations()
448
    {
449
        $totalItems = $this->_items->getTotalExemptedOperations();
450
        return $this->applyAllowancesAndCharges($totalItems);
451
    }
452
453
    /**
454
     * Total operaciones inafectas
455
     * @return float
456
     */
457
    public function getTotalUnaffectedOperations()
458
    {
459
        $totalItems = $this->_items->getTotalUnaffectedOperations();
460
        return $this->applyAllowancesAndCharges($totalItems);
461
    }
462
463
    /**
464
     * Valor de venta
465
     *
466
     * Valor total de la factura sin considerar descuentos impuestos u otros tributos
467
     * @return float
468
     */
469
    public function getBillableValue()
470
    {
471
        return $this->_items->getTotalBillableValue();
472
    }
473
474
    /**
475
     * Total descuentos
476
     *
477
     * Formula: SUM(DESCUENTOS_X_ITEM) + DESCUENTOS_GLOBALES
478
     * @return float
479
     */
480
    public function getTotalAllowances()
481
    {
482
        $totalItems = $this->_items->getTotalAllowances();
483
        $totalBillableAmount = $this->getBillableAmount();
484
        $totalGlobal = Operations::getTotalAllowances($totalBillableAmount, $this->allowancesAndCharges);
485
        return $totalItems + $totalGlobal;
486
    }
487
488
    /**
489
     * Total cargos
490
     *
491
     * Formula: SUM(CARGOS_X_ITEM) + CARGOS_GLOBALES
492
     * @return float
493
     */
494
    public function getTotalCharges()
495
    {
496
        $totalItems = $this->_items->getTotalCharges();
497
        $totalBillableAmount = $this->getBillableAmount();
498
        $totalGlobal = Operations::getTotalCharges($totalBillableAmount, $this->allowancesAndCharges);
499
        return $totalItems + $totalGlobal;
500
    }
501
502
    /**
503
     * Total a pagar
504
     *
505
     * El importe que el usuario está obligado a pagar
506
     *
507
     * Formula = OPERACIONES_GRAVADAS + IGV + OPERACIONES_EXONERADAS + OPERACIONES_INAFECTAS
508
     *
509
     * @return float
510
     */
511
    public function getPayableAmount()
512
    {
513
        // Totals
514
        $totalTaxableOperations = $this->getTotalTaxableOperations();
515
        $totalIGV = $this->getIGV();
516
        $totalExemptedOperations = $this->getTotalExemptedOperations();
517
        return $totalTaxableOperations + $totalIGV + $totalExemptedOperations;
518
    }
519
520
    /**
521
     *
522
     * Total impuestos
523
     *
524
     * Fórmula: IGV + ISC + IVAP
525
     *
526
     * @return float
527
     */
528
    public function getTotalTaxes()
529
    {
530
        $IGV = $this->getIGV();
531
        $ISC = $this->getISC();
532
        $IVAP = $this->getIVAP();
533
        return $IGV + $ISC + $IVAP;
534
    }
535
536
    /**
537
     * IGV
538
     * @return float
539
     */
540
    public function getIGV()
541
    {
542
        $baseAmount = $this->getTaxableAmount();
543
        return Operations::calcIGV($baseAmount);
544
    }
545
546
    /**
547
     * ISC
548
     * @IMP
549
     * @return float
550
     */
551
    public function getISC()
552
    {
553
        return Operations::calcISC();
554
    }
555
556
    /**
557
     * IVAP
558
     * @IMP
559
     * @return float
560
     */
561
    public function getIVAP()
562
    {
563
        return Operations::calcIVAP();
564
    }
565
566
    /**
567
     *
568
     * @param float $amount
569
     * @return float
570
     */
571
    private function applyAllowancesAndCharges($amount)
572
    {
573
        return Operations::applyAllowancesAndCharges($amount, $this->allowancesAndCharges);
574
    }
575
576
    public function getDocumentName()
577
    {
578
        return Company::getRUC() . '-' . $this->documentType . '-' . $this->documentId;
579
    }
580
}
581