InvoiceItems   C
last analyzed

Complexity

Total Complexity 54

Size/Duplication

Total Lines 395
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 140
dl 0
loc 395
rs 6.4799
c 2
b 0
f 0
wmc 54

42 Methods

Rating   Name   Duplication   Size   Complexity  
A calcUnitBillableValue() 0 2 2
A getItemValue() 0 2 1
A getTotalOperations() 0 7 3
A getTotalValue() 0 2 1
A getAllowancesAmount() 0 2 1
A getTotalAllowances() 0 2 1
A getIgvAffectationType() 0 2 1
A getItemBillableValue() 0 2 1
A getDescription() 0 2 1
A getBillableAmount() 0 2 1
A getTaxTypeCode() 0 2 1
A populate() 0 47 3
A calcItemTaxableAmount() 0 7 2
A getIgv() 0 2 1
A getTotalUnaffectedOperations() 0 2 1
A getTotalBillableValue() 0 2 1
A getUnitCode() 0 2 1
A getCount() 0 2 1
A getTotalTaxableOperations() 0 2 1
A getUNPSC() 0 2 1
A getRawData() 0 2 1
A getPriceTypeCode() 0 2 1
A getTotalTaxableAmount() 0 2 1
A getTotalBillableAmount() 0 2 1
A calcIgvAmount() 0 2 2
A getPayableAmount() 0 2 1
A getChargesAmount() 0 2 1
A calcItemBillableAmount() 0 7 2
A getTotalExemptedOperations() 0 2 1
A getTotalFreeOperations() 0 2 1
A getUnitValue() 0 2 1
A getQunatity() 0 2 1
A getTaxableAmount() 0 2 1
A getAllowancesAndCharges() 0 2 1
A getTotalIgv() 0 2 1
A getTotalCharges() 0 2 1
A calcUnitTaxedValue() 0 6 3
A getUnitTaxedValue() 0 2 1
A calcUnitValue() 0 6 3
A getUnitBillableValue() 0 2 1
A getProductCode() 0 2 1
A getCurrencyCode() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like InvoiceItems 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 InvoiceItems, 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 F72X\Tools\XMatrix;
14
15
class InvoiceItems extends XMatrix {
16
17
    const COL_PRODUCT_CODE          = 0;
18
    const COL_UNPSC                 = 1;
19
    const COL_UNIT_CODE             = 2;
20
    const COL_QUANTITY              = 3;
21
    const COL_DESCRIPTION           = 4;
22
    const COL_CURRENCY_CODE         = 5;
23
    const COL_UNIT_VALUE            = 6;
24
    const COL_UNIT_BILLABLE_VALUE   = 7;
25
    const COL_UNIT_TAXED_VALUE      = 8;
26
    // Códigos de catálogos predefinidos
27
    const COL_PRICE_TYPE            = 9;
28
    const COL_TAX_TYPE              = 10;
29
    const COL_IGV_AFFECTATION       = 11;
30
31
    const COL_ITEM_VALUE            = 12;
32
    const COL_ITEM_BILLABLE_VALUE   = 13;
33
    // Cargos y descuentos
34
    const COL_ALLOWANCES_CHARGES    = 14;
35
    const COL_ALLOWANCES_AMOUNT     = 15;
36
    const COL_CHARGES_AMOUNT        = 16;
37
38
39
    const COL_ITEM_BILLABLE_AMOUNT  = 17;
40
    const COL_ITEM_TAXABLE_AMOUNT   = 18;
41
42
    const COL_IGV                   = 19;
43
    const COL_ITEM_PAYABLE_AMOUNT   = 20;
44
45
    protected $columns = [
46
        'COL_PRODUCT_CODE',
47
        'COL_UNPSC',
48
        'COL_UNIT_CODE',
49
        'COL_QUANTITY',
50
        '============COL_DESCRIPTION============',
51
        'COL_CURRENCY_CODE',
52
        'COL_UNIT_VALUE',
53
        'COL_UNIT_BILLABLE_VALUE',
54
        'COL_UNIT_TAXED_VALUE',
55
        'COL_PRICE_TYPE[CAT#16]',
56
        'COL_TAX_TYPE[CAT#5]',
57
        'COL_IGV_AFFECTATION[CAT#7]',
58
        'COL_ITEM_VALUE [COL_UNIT_VALUE*COL_QUANTITY]',
59
        'COL_ITEM_BILLABLE_VALUE [COL_UNIT_BILLABLE_VALUE*COL_QUANTITY]',
60
        'COL_ALLOWANCES_CHARGES',
61
        'COL_ALLOWANCES_AMOUNT [COL_ITEM_BILLABLE_VALUE*k]',
62
        'COL_CHARGES_AMOUNT [COL_ITEM_BILLABLE_VALUE*k]',
63
        'COL_ITEM_BILLABLE_AMOUNT [COL_ITEM_BILLABLE_VALUE-descuentos+cargos]',
64
        'COL_ITEM_TAXABLE_AMOUNT(operacion_gravada) [COL_ITEM_VALUE-descuentos+cargos]',
65
        'COL_IGV(operacion_gravada) [COL_ITEM_BILLABLE_VALUE*IGV_PERCENT]',
66
        'COL_ITEM_PAYABLE_AMOUNT [base_imponible+IGV]'
67
    ];
68
69
    private $rawData = [];
70
    public function populate($items, $currencyCode) {
71
        $this->rawData = $items;
72
        foreach ($items as $idx => $item) {
73
            $ac             = isset($item['allowancesCharges']) ? $item['allowancesCharges'] : [];
74
            $igvAffectCode  = $item['igvAffectationType'];
75
            $priceType      = $item['priceType']; // Tipo de precio
76
            $grossUnitValue = $item['unitPrice'];
77
            $igvIncluded    = $item['igvIncluded'];
78
79
            $unitValue         = $this->calcUnitValue($igvAffectCode, $grossUnitValue, $igvIncluded);      // Valor unitario
80
            $unitTaxedValue    = $this->calcUnitTaxedValue($igvAffectCode, $grossUnitValue, $igvIncluded); // Valor unitario incluyendo impuestos si son aplicables
81
            $unitBillableValue = $this->calcUnitBillableValue($unitValue, $priceType);                     // Valor unitario facturable
82
            $quantity          = $item['quantity']; // Cantidad
83
84
            $itemValue            = $unitValue * $quantity;         // Valor de item
85
            $itemBillableValue    = $unitBillableValue * $quantity; // Valor de item
86
            $itemAllowancesAmount = Operations::getTotalAllowances($itemBillableValue, $ac); // Descuentos de item
87
            $itemChargesAmount    = Operations::getTotalCharges($itemValue, $ac);            // Cargos de item
88
            $itemBillableAmount   = $this->calcItemBillableAmount($itemValue, $priceType, $ac);         // Valor de venta del ítem = (Valor del item - Descuentos + Cargos), 0 si el valor del item es referencial!
89
            $itemTaxableAmount    = $this->calcItemTaxableAmount($itemValue, $priceType, $ac);         // Valor de venta del ítem = (Valor del item - Descuentos + Cargos), 0 si el valor del item es referencial!
90
            $igvAmount            = $this->calcIgvAmount($igvAffectCode, $itemTaxableAmount); // Afectación al IGV por item
91
92
            $itemPayableAmount    = $itemBillableValue + $igvAmount;
93
94
            $this->set(self::COL_PRODUCT_CODE,        $idx, $item['productCode']);
95
            $this->set(self::COL_UNPSC,               $idx, $item['unspsc']);
96
            $this->set(self::COL_UNIT_CODE,           $idx, $item['unitCode']);
97
            $this->set(self::COL_QUANTITY,            $idx, $quantity);
98
            $this->set(self::COL_DESCRIPTION,         $idx, trim($item['description']));
99
            $this->set(self::COL_CURRENCY_CODE,       $idx, $currencyCode);
100
            // Códigos de catálogos predefinidos
101
            $this->set(self::COL_PRICE_TYPE,          $idx, $priceType);
102
            $this->set(self::COL_TAX_TYPE,            $idx, $item['taxType']);
103
            $this->set(self::COL_IGV_AFFECTATION,     $idx, $item['igvAffectationType']);
104
105
            $this->set(self::COL_UNIT_VALUE,          $idx, $unitValue);
106
            $this->set(self::COL_UNIT_BILLABLE_VALUE, $idx, $unitBillableValue);
107
            $this->set(self::COL_UNIT_TAXED_VALUE,    $idx, $unitTaxedValue);
108
            $this->set(self::COL_ITEM_VALUE,          $idx, $itemValue);
109
            $this->set(self::COL_ITEM_BILLABLE_VALUE, $idx, $itemBillableValue);
110
            $this->set(self::COL_ALLOWANCES_CHARGES,  $idx, $ac);
111
            $this->set(self::COL_ALLOWANCES_AMOUNT,   $idx, $itemAllowancesAmount);
112
            $this->set(self::COL_CHARGES_AMOUNT,      $idx, $itemChargesAmount);
113
            $this->set(self::COL_ITEM_BILLABLE_AMOUNT,$idx, $itemBillableAmount);
114
            $this->set(self::COL_ITEM_TAXABLE_AMOUNT, $idx, $itemTaxableAmount);
115
            $this->set(self::COL_IGV,                 $idx, $igvAmount);
116
            $this->set(self::COL_ITEM_PAYABLE_AMOUNT, $idx, $itemPayableAmount);
117
        }
118
    }
119
120
    public function getRawData() {
121
        return $this->rawData;
122
    }
123
124
    /**
125
     * Valor unitario: se extrae el IGV si el valor es afectado por este y si se
126
     * encuentra incluido en el monto que se recibe como segundo parametro.
127
     *
128
     * @param string $igvAffectCode
129
     * @param float $baseAmount
130
     * @param boolean $igvIncluded
131
     * @return float
132
     */
133
    private function calcUnitValue($igvAffectCode, $baseAmount, $igvIncluded) {
134
        $amount = $baseAmount;
135
        if (Operations::isIGVAffected($igvAffectCode) && $igvIncluded) {
136
            $amount = $baseAmount / (1 + SunatVars::IGV);
137
        }
138
        return $amount;
139
    }
140
141
    /**
142
     * Valor unitario pagable: se aplica el IGV si este es aplicable y si aún no
143
     * ha sido incluido en el monto que se recibe como segundo parametro.
144
     *
145
     * @param string $igvAffectCode
146
     * @param float $baseAmount
147
     * @param boolean $igvIncluded
148
     * @return float
149
     */
150
    private function calcUnitTaxedValue($igvAffectCode, $baseAmount, $igvIncluded) {
151
        $amount = $baseAmount;
152
        if (Operations::isIGVAffected($igvAffectCode) && !$igvIncluded) {
153
            $amount = $baseAmount * (1 + SunatVars::IGV);
154
        }
155
        return $amount;
156
    }
157
158
    /**
159
     *
160
     * Valor facturable
161
     *
162
     * El valor que figurará en el comprobante como valor unitario a pagar
163
     *
164
     * @param float $baseAmount
165
     * @param boolean $priceType
166
     * @return float
167
     */
168
    private function calcUnitBillableValue($baseAmount, $priceType) {
169
        return ($priceType === Catalogo::CAT16_REF_VALUE) ? 0 : $baseAmount;
0 ignored issues
show
introduced by
The condition $priceType === F72X\Suna...talogo::CAT16_REF_VALUE is always false.
Loading history...
170
    }
171
172
    private function calcItemBillableAmount($baseAmount, $priceType, $ac) {
173
        // Valor de venta del ítem = (Valor del item - Descuentos + Cargos)
174
        if ($priceType === Catalogo::CAT16_UNITARY_PRICE) {
175
            return Operations::applyAllowancesAndCharges($baseAmount, $ac);
176
        }
177
        // 0 si el valor del item es referencial!
178
        return 0;
179
    }
180
181
    private function calcItemTaxableAmount($baseAmount, $priceType, $ac) {
182
        // Valor de venta del ítem = (Valor del item - Descuentos + Cargos)
183
        if ($priceType === Catalogo::CAT16_UNITARY_PRICE) {
184
            return Operations::applyAllowancesAndCharges($baseAmount, $ac);
185
        }
186
        // Monto base si el valor del item es referencial!
187
        return $baseAmount;
188
    }
189
190
    /**
191
     * IGV: Calcula el monto del IGV, si este es aplicable.
192
     * @param string $igvAffectCode
193
     * @param float $baseAmount
194
     * @return float
195
     */
196
    private function calcIgvAmount($igvAffectCode, $baseAmount) {
197
        return Operations::isIGVAffected($igvAffectCode) ? Operations::calcIGV($baseAmount) : 0;
198
    }
199
200
    /**
201
     * Codigo de producto
202
     *
203
     * @param int $rowIndex
204
     * @return string
205
     */
206
    public function getProductCode($rowIndex) {
207
        return $this->get(self::COL_PRODUCT_CODE, $rowIndex);
208
    }
209
210
    /**
211
     * United Nations Standard Products and Services Code
212
     * Codigo de producto SUNAT de acuerdo con UNSPSC v14_0801
213
     * @param int $rowIndex
214
     * @return string
215
     */
216
    public function getUNPSC($rowIndex) {
217
        return $this->get(self::COL_UNPSC, $rowIndex);
218
    }
219
220
    public function getUnitCode($rowIndex) {
221
        return $this->get(self::COL_UNIT_CODE, $rowIndex);
222
    }
223
224
    public function getQunatity($rowIndex) {
225
        return $this->get(self::COL_QUANTITY, $rowIndex);
226
    }
227
228
    public function getDescription($rowIndex) {
229
        return $this->get(self::COL_DESCRIPTION, $rowIndex);
230
    }
231
232
    public function getCurrencyCode($rowIndex) {
233
        return $this->get(self::COL_CURRENCY_CODE, $rowIndex);
234
    }
235
236
    public function getPriceTypeCode($rowIndex) {
237
        return $this->get(self::COL_PRICE_TYPE, $rowIndex);
238
    }
239
240
    public function getTaxTypeCode($rowIndex) {
241
        return $this->get(self::COL_TAX_TYPE, $rowIndex);
242
    }
243
244
    public function getIgvAffectationType($rowIndex) {
245
        return $this->get(self::COL_IGV_AFFECTATION, $rowIndex);
246
    }
247
248
    public function getUnitValue($rowIndex) {
249
        return $this->get(self::COL_UNIT_VALUE, $rowIndex);
250
    }
251
252
    public function getUnitBillableValue($rowIndex) {
253
        return $this->get(self::COL_UNIT_BILLABLE_VALUE, $rowIndex);
254
    }
255
256
    public function getUnitTaxedValue($rowIndex) {
257
        return $this->get(self::COL_UNIT_TAXED_VALUE, $rowIndex);
258
    }
259
260
    /**
261
     * Valor de item: Valor del item si considerar si es facturado al cliente o es transferido gratuitamente
262
     * @param int $rowIndex
263
     * @return float
264
     */
265
    public function getItemValue($rowIndex) {
266
        return $this->get(self::COL_ITEM_VALUE, $rowIndex);
267
    }
268
269
    /**
270
     * Valor facturable
271
     * Valor que figura en la factura del cliente como precio que el cliente deberá pagar
272
     * @param int $rowIndex
273
     * @return float
274
     */
275
    public function getItemBillableValue($rowIndex) {
276
        return $this->get(self::COL_ITEM_BILLABLE_VALUE, $rowIndex);
277
    }
278
279
    public function getAllowancesAndCharges($rowIndex) {
280
        return $this->get(self::COL_ALLOWANCES_CHARGES, $rowIndex);
281
    }
282
283
    public function getAllowancesAmount($rowIndex) {
284
        return $this->get(self::COL_ALLOWANCES_AMOUNT, $rowIndex);
285
    }
286
287
    public function getChargesAmount($rowIndex) {
288
        return $this->get(self::COL_CHARGES_AMOUNT, $rowIndex);
289
    }
290
    public function getBillableAmount($rowIndex) {
291
        return $this->get(self::COL_ITEM_BILLABLE_AMOUNT, $rowIndex);
292
    }
293
    public function getTaxableAmount($rowIndex) {
294
        return $this->get(self::COL_ITEM_TAXABLE_AMOUNT, $rowIndex);
295
    }
296
297
    public function getIgv($rowIndex) {
298
        return $this->get(self::COL_IGV, $rowIndex);
299
    }
300
301
    public function getPayableAmount($rowIndex) {
302
        return $this->get(self::COL_ITEM_PAYABLE_AMOUNT, $rowIndex);
303
    }
304
305
    /**
306
     * Total operaciones gravadas
307
     * @return float
308
     */
309
    public function getTotalTaxableOperations() {
310
        return $this->getTotalOperations(Catalogo::CAT5_IGV, self::COL_ITEM_TAXABLE_AMOUNT);
311
    }
312
313
    /**
314
     * Total operaciones gratuitas
315
     * @return float
316
     */
317
    public function getTotalFreeOperations() {
318
        return $this->getTotalOperations(Catalogo::CAT5_GRA, self::COL_ITEM_VALUE);
319
    }
320
321
    /**
322
     * Total operaciones exoneradas
323
     * @return float
324
     */
325
    public function getTotalExemptedOperations() {
326
        return $this->getTotalOperations(Catalogo::CAT5_EXO, self::COL_ITEM_TAXABLE_AMOUNT);
327
    }
328
329
    /**
330
     * Total operaciones inafectas
331
     * @return float
332
     */
333
    public function getTotalUnaffectedOperations() {
334
        return $this->getTotalOperations(Catalogo::CAT5_INA, self::COL_ITEM_VALUE);
335
    }
336
337
    private function getTotalOperations($taxType, $columnIndex) {
338
        $total = 0;
339
        $data = $this->getMatrix();
340
        foreach ($data as $row) {
341
            $total += ($row[self::COL_TAX_TYPE] === $taxType) ? $row[$columnIndex] : 0;
342
        }
343
        return $total;
344
    }
345
346
    /**
347
     * Todos de los descuentos.
348
     * @return float
349
     */
350
    public function getTotalAllowances() {
351
        return $this->sum(self::COL_ALLOWANCES_AMOUNT);
352
    }
353
354
    /**
355
     * Todos de los cargos.
356
     * @return float
357
     */
358
    public function getTotalCharges() {
359
        return $this->sum(self::COL_CHARGES_AMOUNT);
360
    }
361
362
    /**
363
     * Valor total
364
     * Suma los valores de cada item
365
     * = Cantidad x (Valor unitario | Valor fererencial)
366
     * @return float
367
     */
368
    public function getTotalValue() {
369
        return $this->sum(self::COL_ITEM_VALUE);
370
    }
371
372
    /**
373
     * Suma de valores de cada item sin incluir aquellos por los que no se cobra.
374
     * @return float
375
     */
376
    public function getTotalBillableValue() {
377
        return $this->sum(self::COL_ITEM_BILLABLE_VALUE);
378
    }
379
380
    /**
381
     * Total IGV
382
     * @return float
383
     */
384
    public function getTotalIgv() {
385
        return $this->sum(self::COL_IGV);
386
    }
387
388
    /**
389
     * El monto total facturable libre de impuestos
390
     * @return float
391
     */
392
    public function getTotalBillableAmount() {
393
        return $this->sum(self::COL_ITEM_BILLABLE_AMOUNT);
394
    }
395
396
    /**
397
     * Base imponible total lista para aplicar impuestos
398
     * @return float
399
     */
400
    public function getTotalTaxableAmount() {
401
        return $this->sum(self::COL_ITEM_TAXABLE_AMOUNT);
402
    }
403
404
    /**
405
     * Total de items
406
     * @return int
407
     */
408
    public function getCount() {
409
        return $this->countRows();
410
    }
411
412
}
413