DataMap   F
last analyzed

Complexity

Total Complexity 64

Size/Duplication

Total Lines 432
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 142
dl 0
loc 432
rs 3.28
c 0
b 0
f 0
wmc 64

56 Methods

Rating   Name   Duplication   Size   Complexity  
A getTaxableAmount() 0 3 1
A getOperationType() 0 2 1
A setDocumentSeries() 0 3 1
A setSpecificFields() 0 11 3
A getNote() 0 2 1
A getCustomerAddress() 0 2 1
A getNoteAffectedDocType() 0 2 1
A getTotalAllowances() 0 5 1
A setCustomerAddress() 0 3 1
A getNoteType() 0 2 1
A setPurchaseOrder() 0 3 1
A getISC() 0 2 1
A getTotalCharges() 0 5 1
A getDueDate() 0 2 1
A setCustomerDocNumber() 0 3 1
A setOperationType() 0 3 1
A setAllowancesAndCharges() 0 3 1
A getTaxedAmount() 0 4 1
A getPayableAmount() 0 6 1
A setCustomerDocType() 0 3 1
A getDocumentId() 0 2 1
A setDefaults() 0 5 5
A getBillableValue() 0 2 1
A getItems() 0 2 1
A getDiscrepancyResponseReason() 0 2 1
A getRawItems() 0 2 1
A getNoteDescription() 0 2 1
A getTotalTaxableOperations() 0 2 1
A setDocumentNumber() 0 3 1
A getDocumentNumber() 0 2 1
A getIGV() 0 3 1
A getTotalFreeOperations() 0 2 1
A __construct() 0 30 3
A setDueDate() 0 3 1
A getOfficialDocumentName() 0 2 1
A getNoteAffectedDocId() 0 2 1
A getBillableAmount() 0 2 1
A getCustomerDocType() 0 2 1
A getTotalUnaffectedOperations() 0 3 1
A getTotalTaxes() 0 5 1
A getRawData() 0 2 1
A setCustomerRegName() 0 3 1
A getCustomerRegName() 0 2 1
A getCurrencyCode() 0 2 1
A getDocumentSeries() 0 2 1
A getPurchaseOrder() 0 2 1
A applyAllowancesAndCharges() 0 2 1
A setIssueDate() 0 3 1
A getIVAP() 0 2 1
A getTotalItems() 0 2 1
A getTotalExemptedOperations() 0 3 1
A getDocumentName() 0 2 1
A getAllowancesAndCharges() 0 2 1
A getDocumentType() 0 2 1
A getIssueDate() 0 2 1
A getCustomerDocNumber() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like DataMap 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 DataMap, and based on these observations, apply Extract Interface, too.

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
 * DataMap
20
 * 
21
 * Esta clase es una representación interna de una factura o boleta, la cual se
22
 * encarga de aplicar toda la logica de negocio en cuanto a cálculos de tributos
23
 * y totales
24
 * 
25
 */
26
class DataMap {
27
28
    private $_rawData;
29
    private $documentType;
30
    private $currencyCode;
31
    private $documentId;
32
    private $officialDocumentName;
33
    private $documentSeries;
34
    private $documentNumber;
35
36
    /** @var DateTime */
37
    private $issueDate;
38
39
    /** @var DateTime */
40
    private $dueDate;
41
    private $operationType;
42
    private $customerDocType;
43
    private $customerDocNumber;
44
    private $customerRegName;
45
    private $customerAddress;
46
    private $purchaseOrder;
47
48
    /** @var InvoiceItems */
49
    private $_items;
50
    private $_rawItems;
51
    private $allowancesAndCharges = [];
52
53
    /** NOTES FIELDS */
54
    private $noteType;
55
    private $discrepancyResponseReason;
56
    private $noteAffectedDocType;
57
    private $noteAffectedDocId;
58
    /**
59
     * 
60
     * @param array $data
61
     * @param string $type 01|03|07|08 The document type
62
     */
63
    public function __construct(array $data, $type) {
64
        // Type validation
65
        if (!in_array($type, ['01', '03', '07', '08'])) {
66
            throw new InvalidArgumentException("DataMap Error, el tipo de documento '$type', no es válido use 01|03|07|08");
67
        }
68
        // Items
69
        $items = new InvoiceItems();
70
        $items->populate($data['items'], $data['currencyCode']);
71
72
        $this->_rawData  = $data;
73
        $this->_rawItems = $data['items'];
74
        $this->setDefaults($data);
75
        $this->currencyCode         = $data['currencyCode'];
76
        $this->documentType         = $type;
77
        $this->documentSeries       = DocumentGenerator::buildDocumentSeries($type, $data['affectedDocType'], $data['documentSeries']);
78
        $this->documentNumber       = str_pad($data['documentNumber'], 8, '0', STR_PAD_LEFT);
79
        $this->officialDocumentName = Catalogo::getOfficialDocumentName($type);
80
        $this->documentId           = $this->documentSeries . '-' . $this->documentNumber;
81
        $this->issueDate            = new DateTime($data['issueDate']);
82
        if (isset($data['dueDate'])) {
83
            $this->dueDate            = new DateTime($data['dueDate']);
84
        }
85
        $this->customerDocType      = $data['customerDocType'];
86
        $this->customerDocNumber    = $data['customerDocNumber'];
87
        $this->customerRegName      = mb_strtoupper($data['customerRegName']);
88
        $this->customerAddress      = mb_strtoupper($data['customerAddress']);
89
        $this->_items               = $items;
90
        $this->allowancesAndCharges = $data['allowancesCharges'];
91
        $this->note                 = $data['note'];
0 ignored issues
show
Bug Best Practice introduced by
The property note does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
92
        $this->setSpecificFields($data, $type);
93
    }
94
95
    private function setSpecificFields(array $data, $type) {
96
        if (in_array($type, [Catalogo::DOCTYPE_FACTURA, Catalogo::DOCTYPE_BOLETA])) {
97
            $this->operationType = $data['operationType'];
98
            $this->purchaseOrder = $data['purchaseOrder'];
99
        } else {
100
            // Catálogo 9 tipo de nota de crédito, 10 tipo de nota de débito
101
            $catNumber = ($type == Catalogo::DOCTYPE_NOTA_CREDITO ? 9 : 10);
102
            $this->discrepancyResponseReason = Catalogo::getCatItemValue($catNumber, $data['noteType']);
103
            $this->noteType            = $data['noteType'];
104
            $this->noteAffectedDocType = $data['affectedDocType'];
105
            $this->noteAffectedDocId   = $data['affectedDocId'];
106
        }
107
    }
108
109
    private function setDefaults(array &$data) {
110
        $data['allowancesCharges'] = isset($data['allowancesCharges']) ? $data['allowancesCharges'] : [];
111
        $data['purchaseOrder'] = isset($data['purchaseOrder']) ? $data['purchaseOrder'] : null;
112
        $data['affectedDocType'] = isset($data['affectedDocType']) ? $data['affectedDocType'] : null;
113
        $data['note'] = isset($data['note']) ? $data['note'] : '';
114
    }
115
    public function getNoteType() {
116
        return $this->noteType;
117
    }
118
119
    public function getDiscrepancyResponseReason() {
120
        return $this->discrepancyResponseReason;
121
    }
122
123
    public function getNoteDescription() {
124
        return $this->note;
125
    }
126
    public function getNote() {
127
        return $this->note;
128
    }
129
    public function getNoteAffectedDocType() {
130
        return $this->noteAffectedDocType;
131
    }
132
133
    public function getNoteAffectedDocId() {
134
        return $this->noteAffectedDocId;
135
    }
136
137
    public function getDocumentId() {
138
        return $this->documentId;
139
    }
140
141
    public function getRawData() {
142
        return $this->_rawData;
143
    }
144
145
    /**
146
     * Boleta o Factura @CAT1
147
     * @return string
148
     */
149
    public function getDocumentType() {
150
        return $this->documentType;
151
    }
152
153
    public function getCurrencyCode() {
154
        return $this->currencyCode;
155
    }
156
157
    public function getOfficialDocumentName() {
158
        return $this->officialDocumentName;
159
    }
160
161
    public function getDocumentSeries() {
162
        return $this->documentSeries;
163
    }
164
165
    public function setDocumentSeries($documentSeries) {
166
        $this->documentSeries = $documentSeries;
167
        return $this;
168
    }
169
170
    public function getDocumentNumber() {
171
        return $this->documentNumber;
172
    }
173
174
    public function setDocumentNumber($documentNumber) {
175
        $this->documentNumber = $documentNumber;
176
        return $this;
177
    }
178
179
    public function getIssueDate() {
180
        return $this->issueDate;
181
    }
182
183
    public function setIssueDate(DateTime $IssueDate) {
184
        $this->issueDate = $IssueDate;
185
        return $this;
186
    }
187
188
    public function getDueDate() {
189
        return $this->dueDate;
190
    }
191
192
    public function setDueDate(DateTime $DueDate) {
193
        $this->dueDate = $DueDate;
194
        return $this;
195
    }
196
197
    public function getOperationType() {
198
        return $this->operationType;
199
    }
200
201
    public function setOperationType($operationType) {
202
        $this->operationType = $operationType;
203
        return $this;
204
    }
205
206
    public function getCustomerDocType() {
207
        return $this->customerDocType;
208
    }
209
210
    public function setCustomerDocType($customerDocType) {
211
        $this->customerDocType = $customerDocType;
212
        return $this;
213
    }
214
215
    public function getCustomerDocNumber() {
216
        return $this->customerDocNumber;
217
    }
218
219
    public function setCustomerDocNumber($customerDocNumber) {
220
        $this->customerDocNumber = $customerDocNumber;
221
        return $this;
222
    }
223
224
    public function getCustomerRegName() {
225
        return $this->customerRegName;
226
    }
227
228
    public function setCustomerRegName($customerRegName) {
229
        $this->customerRegName = $customerRegName;
230
        return $this;
231
    }
232
    public function getCustomerAddress() {
233
        return $this->customerAddress;
234
    }
235
236
    public function setCustomerAddress($customerAddress) {
237
        $this->customerAddress = $customerAddress;
238
        return $this;
239
    }
240
241
    public function getPurchaseOrder() {
242
        return $this->purchaseOrder;
243
    }
244
245
    public function setPurchaseOrder($purchaseOrder) {
246
        $this->purchaseOrder = $purchaseOrder;
247
        return $this;
248
    }
249
250
    /**
251
     * 
252
     * @return InvoiceItems
253
     */
254
    public function getItems() {
255
        return $this->_items;
256
    }
257
258
    /**
259
     * Numero de items del documento
260
     * @return int
261
     */
262
    public function getTotalItems() {
263
        return $this->_items->getCount();
264
    }
265
266
    public function getRawItems() {
267
        return $this->_rawItems;
268
    }
269
270
    public function getAllowancesAndCharges() {
271
        return $this->allowancesAndCharges;
272
    }
273
274
    public function setAllowancesAndCharges($allowancesAndCharges) {
275
        $this->allowancesAndCharges = $allowancesAndCharges;
276
        return $this;
277
    }
278
279
    /**
280
     * Monto facturable (Valor de venta)
281
     * 
282
     * Formula = SUM(BASE_FACTURABLE_X_ITEM)
283
     * 
284
     * @return float
285
     */
286
    public function getBillableAmount() {
287
        return $this->_items->getTotalBillableAmount();
288
    }
289
290
    /**
291
     * Base imponible
292
     * 
293
     * Formula = SUM(BASE_IMPONIBLE_X_ITEM) - DESCUENTOS_GLOBALES + CARGOS_GLOBALES
294
     * 
295
     * @return float
296
     */
297
    public function getTaxableAmount() {
298
        $totalItems = $this->_items->getTotalTaxableOperations();
299
        return $this->applyAllowancesAndCharges($totalItems);
300
    }
301
302
    /**
303
     * Monto con impuestos
304
     * 
305
     * Formula = BASE_IMPONIBLE + IGV
306
     * 
307
     * @return float
308
     */
309
    public function getTaxedAmount() {
310
        $totalTaxableAmount = $this->getTaxableAmount();
311
        $totalIgv = $this->getIGV();
312
        return $totalTaxableAmount + $totalIgv;
313
    }
314
315
    /**
316
     * Total operaciones gravadas
317
     * @return float
318
     */
319
    public function getTotalTaxableOperations() {
320
        return $this->getTaxableAmount();
321
    }
322
323
    /**
324
     * Total operaciones gratuitas
325
     * @return float
326
     */
327
    public function getTotalFreeOperations() {
328
        return $this->_items->getTotalFreeOperations();
329
    }
330
331
    /**
332
     * Total operationes exoneradas
333
     * 
334
     * Formula = SUM(EXEMPTED_OPERATIONS_X_ITEM) - DESCUENTOS_GLOBALES + CARGOS_GLOBALES
335
     * 
336
     * @return float
337
     */
338
    public function getTotalExemptedOperations() {
339
        $totalItems = $this->_items->getTotalExemptedOperations();
340
        return $this->applyAllowancesAndCharges($totalItems);
341
    }
342
343
    /**
344
     * Total operaciones inafectas
345
     * @return float
346
     */
347
    public function getTotalUnaffectedOperations() {
348
        $totalItems = $this->_items->getTotalUnaffectedOperations();
349
        return $this->applyAllowancesAndCharges($totalItems);
350
    }
351
352
    /**
353
     * Valor de venta
354
     * 
355
     * Valor total de la factura sin considerar descuentos impuestos u otros tributos
356
     * @return float
357
     */
358
    public function getBillableValue() {
359
        return $this->_items->getTotalBillableValue();
360
    }
361
362
    /**
363
     * Total descuentos
364
     * 
365
     * Formula: SUM(DESCUENTOS_X_ITEM) + DESCUENTOS_GLOBALES
366
     * @return float
367
     */
368
    public function getTotalAllowances() {
369
        $totalItems = $this->_items->getTotalAllowances();
370
        $totalBillableAmount = $this->getBillableAmount();
371
        $totalGlobal = Operations::getTotalAllowances($totalBillableAmount, $this->allowancesAndCharges);
372
        return $totalItems + $totalGlobal;
373
    }
374
375
    /**
376
     * Total cargos
377
     * 
378
     * Formula: SUM(CARGOS_X_ITEM) + CARGOS_GLOBALES
379
     * @return float
380
     */
381
    public function getTotalCharges() {
382
        $totalItems = $this->_items->getTotalCharges();
383
        $totalBillableAmount = $this->getBillableAmount();
384
        $totalGlobal = Operations::getTotalCharges($totalBillableAmount, $this->allowancesAndCharges);
385
        return $totalItems + $totalGlobal;
386
    }
387
388
    /**
389
     * Total a pagar
390
     * 
391
     * El importe que el usuario está obligado a pagar
392
     * 
393
     * Formula = OPERACIONES_GRAVADAS + IGV + OPERACIONES_EXONERADAS + OPERACIONES_INAFECTAS
394
     * 
395
     * @return float
396
     */
397
    public function getPayableAmount() {
398
        // Totals
399
        $totalTaxableOperations = $this->getTotalTaxableOperations();
400
        $totalIGV = $this->getIGV();
401
        $totalExemptedOperations = $this->getTotalExemptedOperations();
402
        return $totalTaxableOperations + $totalIGV + $totalExemptedOperations;
403
    }
404
405
    /**
406
     * 
407
     * Total impuestos
408
     * 
409
     * Fórmula: IGV + ISC + IVAP
410
     * 
411
     * @return float
412
     */
413
    public function getTotalTaxes() {
414
        $IGV = $this->getIGV();
415
        $ISC = $this->getISC();
416
        $IVAP = $this->getIVAP();
417
        return $IGV + $ISC + $IVAP;
418
    }
419
420
    /**
421
     * IGV
422
     * @return float
423
     */
424
    public function getIGV() {
425
        $baseAmount = $this->getTaxableAmount();
426
        return Operations::calcIGV($baseAmount);
427
    }
428
429
    /**
430
     * ISC
431
     * @IMP
432
     * @return float
433
     */
434
    public function getISC() {
435
        return Operations::calcISC();
436
    }
437
438
    /**
439
     * IVAP
440
     * @IMP
441
     * @return float
442
     */
443
    public function getIVAP() {
444
        return Operations::calcIVAP();
445
    }
446
447
    /**
448
     * 
449
     * @param float $amount
450
     * @return float
451
     */
452
    private function applyAllowancesAndCharges($amount) {
453
        return Operations::applyAllowancesAndCharges($amount, $this->allowancesAndCharges);
454
    }
455
456
    public function getDocumentName() {
457
        return Company::getRUC() . '-' . $this->documentType . '-' . $this->documentId;
458
    }
459
460
}
461