BillMixin   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 364
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 218
dl 0
loc 364
rs 9.92
c 0
b 0
f 0
wmc 31

13 Methods

Rating   Name   Duplication   Size   Complexity  
A addInvoiceOrderReference() 0 9 2
B addDocumentItem() 0 106 4
A addDocumentLine() 0 12 4
A addInvoiceLegalMonetaryTotal() 0 17 1
A addInvoiceAccountingCustomerParty() 0 29 1
A setDocumentLineQuantity() 0 12 4
A addPaymentTerms() 0 23 4
A addDocumentTaxes() 0 37 5
A addInvoiceAccountingSupplierParty() 0 40 1
A getDocumentName() 0 3 1
A addDocumentItems() 0 6 2
A getItems() 0 3 1
A getDataMap() 0 3 1
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\Document;
12
13
use F72X\Company;
14
use F72X\Sunat\DataMap;
15
use F72X\Sunat\InvoiceItems;
16
use F72X\Sunat\Catalogo;
17
use F72X\Sunat\SunatVars;
18
use F72X\Tools\UblHelper;
19
use F72X\UblComponent\OrderReference;
20
use F72X\UblComponent\Party;
21
use F72X\UblComponent\PartyIdentification;
22
use F72X\UblComponent\PartyTaxScheme;
23
use F72X\UblComponent\RegistrationAddress;
24
use F72X\UblComponent\PartyName;
25
use F72X\UblComponent\AccountingSupplierParty;
26
use F72X\UblComponent\AccountingCustomerParty;
27
use F72X\UblComponent\PartyLegalEntity;
28
use F72X\UblComponent\TaxTotal;
29
use F72X\UblComponent\TaxSubTotal;
30
use F72X\UblComponent\TaxCategory;
31
use F72X\UblComponent\TaxScheme;
32
use F72X\UblComponent\LegalMonetaryTotal;
33
use F72X\UblComponent\InvoiceLine;
34
use F72X\UblComponent\CreditNoteLine;
35
use F72X\UblComponent\DebitNoteLine;
36
use F72X\UblComponent\PricingReference;
37
use F72X\UblComponent\AlternativeConditionPrice;
38
use F72X\UblComponent\Amount;
39
use F72X\UblComponent\Item;
40
use F72X\UblComponent\SellersItemIdentification;
41
use F72X\UblComponent\CommodityClassification;
42
use F72X\UblComponent\PaymentTerms;
43
use F72X\UblComponent\Price;
44
45
trait BillMixin
46
{
47
48
49
50
    /** @var DataMap */
51
    private $dataMap;
52
53
    public function getDataMap()
54
    {
55
        return $this->dataMap;
56
    }
57
58
    /**
59
     *
60
     * @return InvoiceItems
61
     */
62
    public function getItems()
63
    {
64
        return $this->dataMap->getItems();
65
    }
66
67
    public function addPaymentTerms()
68
    {
69
        $invoice = $this->getDataMap();
70
        $currencyCode = $invoice->getCurrencyCode();
71
        $formOfPayment = $invoice->getFormOfPayment();
72
        $terms = [];
73
        // Contado
74
        if ($formOfPayment == 'Contado') {
75
            $terms[] = new PaymentTerms('FormaPago', 'Contado');
76
        }
77
        // Crédito
78
        elseif ($formOfPayment == 'Credito') {
79
            $paymentTerms = new PaymentTerms('FormaPago', 'Credito');
80
            $paymentTerms->setAmount(new Amount($invoice->getPendingAmount(), $currencyCode));
81
            $terms[] = $paymentTerms;
82
            foreach ($invoice->getInstallments() as $installement) {
83
                $paymentTerms = new PaymentTerms('FormaPago', $installement->getId());
84
                $paymentTerms->setAmount(new Amount($installement->getAmmount(), $currencyCode));
85
                $paymentTerms->setPaymentDueDate($installement->getPaymentDueDate());
86
                $terms[] = $paymentTerms;
87
            }
88
        }
89
        parent::setPaymentTerms($terms);
90
    }
91
    /**
92
     *
93
     * @param string $lineType InvoiceLine|CreditNoteLine|DebitNoteLine
94
     */
95
    private function addDocumentItems($lineType)
96
    {
97
        $ln = $this->dataMap->getTotalItems();
98
        // Loop
99
        for ($i = 0; $i < $ln; $i++) {
100
            $this->addDocumentItem($i, $lineType);
101
        }
102
    }
103
104
    private function addInvoiceOrderReference()
105
    {
106
        $orderNumer = $this->dataMap->getPurchaseOrder();
107
        if ($orderNumer) {
108
            // Xml Node
109
            $orderRef = new OrderReference();
110
            $orderRef->setID($orderNumer);
111
            // Añadir al documento
112
            parent::setOrderReference($orderRef);
113
        }
114
    }
115
116
    private function addDocumentTaxes()
117
    {
118
        $Invoice                   = $this->dataMap;
119
        $currencyID                = $Invoice->getCurrencyCode();              // Tipo de moneda
120
        $totalTaxableOperations    = $Invoice->getTotalTaxableOperations();    // Total operaciones gravadas
121
        $totalTaxes                = $Invoice->getTotalTaxes();                // Total operaciones gravadas
122
        $Igv                       = $Invoice->getIGV();                       // Total IGV
123
        $totalExemptedOperations   = $Invoice->getTotalExemptedOperations();   // Total operaciones exoneradas
124
        $totalUnaffectedOperations = $Invoice->getTotalUnaffectedOperations(); // Total operaciones inafectas
125
        $totalFreeOpertions        = $Invoice->getTotalFreeOperations();       // Total operaciones gratuitas
126
127
        // XML nodes
128
        $TaxTotal = new TaxTotal();
129
130
        // Operaciones gravadas
131
        if ($Igv) {
132
            UblHelper::addTaxSubtotal($TaxTotal, $currencyID, $Igv, $totalTaxableOperations, Catalogo::CAT5_IGV);
133
        }
134
        // Total operaciones exoneradas
135
        if ($totalExemptedOperations) {
136
            UblHelper::addTaxSubtotal($TaxTotal, $currencyID, 0, $totalExemptedOperations,   Catalogo::CAT5_EXO);
137
        }
138
        // Total operaciones inafectas
139
        if ($totalUnaffectedOperations) {
140
            UblHelper::addTaxSubtotal($TaxTotal, $currencyID, 0, $totalUnaffectedOperations, Catalogo::CAT5_INA);
141
        }
142
        // Total operaciones gratuitas
143
        if ($totalFreeOpertions) {
144
            UblHelper::addTaxSubtotal($TaxTotal, $currencyID, 0, $totalFreeOpertions,        Catalogo::CAT5_GRA);
145
        }
146
147
        // Total impuestos
148
        $TaxTotal
149
            ->setCurrencyID($currencyID)
150
            ->setTaxAmount($totalTaxes);
151
        // Anadir al documento
152
        parent::setTaxTotal($TaxTotal);
153
    }
154
155
    /**
156
     *
157
     * @param int $itemIndex Index del item
158
     * @param string $lineType InvoiceLine|CreditNoteLine|DebitNoteLine
159
     */
160
161
    private function addDocumentItem($itemIndex, $lineType)
162
    {
163
        $docLineClassName = "\F72X\UblComponent\\$lineType";
164
        // XML Nodes
165
        $DocumentLine     = new $docLineClassName();
166
        $PricingReference = new PricingReference();
167
        $TaxTotal         = new TaxTotal();
168
        $TaxSubTotal      = new TaxSubTotal();
169
        $TaxCategory      = new TaxCategory();
170
        $TaxCategory
171
            ->setElementAttributes('ID', [
172
                'schemeID'         => 'UN/ECE 5305',
173
                'schemeName'       => 'Tax Category Identifier',
174
                'schemeAgencyName' => 'United Nations Economic Commission for Europe'
175
            ])
176
            ->setElementAttributes('TaxExemptionReasonCode', [
177
                'listAgencyName'   => 'PE:SUNAT',
178
                'listName'         => 'SUNAT:Codigo de Tipo de Afectación del IGV',
179
                'listURI'          => 'urn:pe:gob:sunat:cpe:see:gem:catalogos:catalogo07'
180
            ]);
181
182
        $TaxScheme = new TaxScheme();
183
        $TaxScheme
184
            ->setElementAttributes('ID', [
185
                'schemeID'         => 'UN/ECE 5153',
186
                'schemeName'       => 'Tax Scheme Identifier',
187
                'schemeAgencyName' => 'United Nations Economic Commission for Europe'
188
            ]);
189
190
        $AlternativeConditionPrice  = new AlternativeConditionPrice();
191
        $Item                       = new Item();
192
        $SellersItemIdentification  = new SellersItemIdentification();
193
        $CommodityClassification    = new CommodityClassification();
194
        $Price                      = new Price();
195
        // Detail Operation Matrix
196
        $Items = $this->dataMap->getItems();
197
        // Vars
198
        $productCode        = $Items->getProductCode($itemIndex);
199
        $sunatProductCode   = $Items->getUNPSC($itemIndex);
200
        $unitCode           = $Items->getUnitCode($itemIndex);
201
        $quantity           = $Items->getQunatity($itemIndex);
202
        $description        = $Items->getDescription($itemIndex);
203
        $currencyCode       = $Items->getCurrencyCode($itemIndex);
204
        $unitBillableValue  = $Items->getUnitBillableValue($itemIndex);
205
        $priceTypeCode      = $Items->getPriceTypeCode($itemIndex);
206
        $taxTypeCode        = $Items->getTaxTypeCode($itemIndex);
207
        $igvAffectationType = $Items->getIgvAffectationType($itemIndex);
208
        $taxCategoryPercent = $igvAffectationType === '10' ? SunatVars::IGV_PERCENT : '0.00';
209
210
        $itemValue          = $Items->getItemValue($itemIndex);
211
        $ac                 = $Items->getAllowancesAndCharges($itemIndex);
212
        $itemTaxableAmount  = $Items->getTaxableAmount($itemIndex);
213
        $itemTaxAmount      = $Items->getIgv($itemIndex);
214
        $unitPrice          = $Items->getUnitTaxedValue($itemIndex);
215
216
        // Catálogo 5 Ipuesto aplicable
217
        $cat5Item = Catalogo::getCatItem(5, $taxTypeCode);
218
219
        // Descuentos y cargos
220
        UblHelper::addAllowancesCharges($DocumentLine, $ac, $itemValue, $currencyCode);
221
222
        // Config Item
223
        $Item->setDescription($description); // Descripción
224
        // Código de producto
225
        if ($productCode) {
226
            $Item->setSellersItemIdentification($SellersItemIdentification->setID($productCode));
227
        }
228
        // Código de producto SUNAT
229
        if ($sunatProductCode) {
230
            $Item->setCommodityClassification($CommodityClassification->setItemClassificationCode($sunatProductCode));
231
        }
232
        $DocumentLine
233
            ->setCurrencyID($currencyCode)                    // Tipo de moneda
234
            ->setID($itemIndex + 1)                         // Número de orden
235
            ->setUnitCode($unitCode)                        // Codigo de unidad de medida
236
            ->setLineExtensionAmount($itemTaxableAmount)    // Valor de venta del ítem, sin impuestos
237
            ->setPricingReference($PricingReference
238
                ->setAlternativeConditionPrice($AlternativeConditionPrice
239
                    ->setCurrencyID($currencyCode)            // Tipo de moneda
240
                    ->setPriceAmount($unitPrice)            // Precio de venta unitario
241
                    ->setPriceTypeCode($priceTypeCode)))    // Price
242
            ->setTaxTotal($TaxTotal
243
                ->setCurrencyID($currencyCode)
244
                ->setTaxAmount($itemTaxAmount)
245
                ->addTaxSubTotal($TaxSubTotal
246
                    ->setCurrencyID($currencyCode)          // Tipo de moneda
247
                    ->setTaxableAmount($itemTaxableAmount)  // Valor de venta del item sin impuestos
248
                    ->setTaxAmount($itemTaxAmount)          // IGV
249
                    ->setTaxCategory($TaxCategory
250
                        ->setID($cat5Item['categoria'])                     // Codigo de categoria de immpuestos @CAT5
251
                        ->setPercent($taxCategoryPercent)                // Porcentaje de IGV (18.00)
252
                        ->setTaxExemptionReasonCode($igvAffectationType)    // Código de afectación del IGV
253
                        ->setTaxScheme($TaxScheme
254
                            ->setID($taxTypeCode)                       // Codigo de categoria de impuesto
255
                            ->setName($cat5Item['name'])
256
                            ->setTaxTypeCode($cat5Item['UN_ECE_5153'])))))
257
            ->setItem($Item)
258
            ->setPrice(
259
                $Price
260
                    ->setCurrencyID($currencyCode)    // Tipo de moneda
261
                    ->setPriceAmount($unitBillableValue)    // Precio unitario del item
262
            );
263
        // Set Quantity
264
        $this->setDocumentLineQuantity($DocumentLine, $lineType, $quantity);
265
        // Añade item
266
        $this->addDocumentLine($DocumentLine, $lineType);
267
    }
268
269
    /**
270
     *
271
     * @param InvoiceLine|CreditNoteLine|DebitNoteLine $DocumentLine
272
     * @param string $lineType InvoiceLine|CreditNoteLine|DebitNoteLine
273
     * @param int $quantity
274
     */
275
    private function addDocumentLine($DocumentLine, $lineType)
276
    {
277
        switch ($lineType) {
278
            case 'InvoiceLine':
279
                parent::addInvoiceLine($DocumentLine);
280
                break;
281
            case 'CreditNoteLine':
282
                parent::addCreditNoteLine($DocumentLine);
283
                break;
284
            case 'DebitNoteLine':
285
                parent::addDebitNoteLine($DocumentLine);
286
                break;
287
        }
288
    }
289
    /**
290
     *
291
     * @param InvoiceLine|CreditNoteLine|DebitNoteLine $DocumentLine
292
     * @param string $lineType InvoiceLine|CreditNoteLine|DebitNoteLine
293
     * @param int $quantity
294
     */
295
    private function setDocumentLineQuantity($DocumentLine, $lineType, $quantity)
296
    {
297
        switch ($lineType) {
298
            case 'InvoiceLine':
299
                $DocumentLine->setInvoicedQuantity($quantity);
0 ignored issues
show
Bug introduced by
The method setInvoicedQuantity() does not exist on F72X\UblComponent\CreditNoteLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

299
                $DocumentLine->/** @scrutinizer ignore-call */ 
300
                               setInvoicedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method setInvoicedQuantity() does not exist on F72X\UblComponent\DebitNoteLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

299
                $DocumentLine->/** @scrutinizer ignore-call */ 
300
                               setInvoicedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
300
                break;
301
            case 'CreditNoteLine':
302
                $DocumentLine->setCreditedQuantity($quantity);
0 ignored issues
show
Bug introduced by
The method setCreditedQuantity() does not exist on F72X\UblComponent\DebitNoteLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

302
                $DocumentLine->/** @scrutinizer ignore-call */ 
303
                               setCreditedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method setCreditedQuantity() does not exist on F72X\UblComponent\InvoiceLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

302
                $DocumentLine->/** @scrutinizer ignore-call */ 
303
                               setCreditedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
303
                break;
304
            case 'DebitNoteLine':
305
                $DocumentLine->setDebitedQuantity($quantity);
0 ignored issues
show
Bug introduced by
The method setDebitedQuantity() does not exist on F72X\UblComponent\InvoiceLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

305
                $DocumentLine->/** @scrutinizer ignore-call */ 
306
                               setDebitedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method setDebitedQuantity() does not exist on F72X\UblComponent\CreditNoteLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

305
                $DocumentLine->/** @scrutinizer ignore-call */ 
306
                               setDebitedQuantity($quantity);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
306
                break;
307
        }
308
    }
309
310
    private function addInvoiceLegalMonetaryTotal()
311
    {
312
        $Invoice            = $this->dataMap;
313
        $currencyID         = $this->getDocumentCurrencyCode(); // Tipo de moneda
0 ignored issues
show
Bug introduced by
It seems like getDocumentCurrencyCode() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

313
        /** @scrutinizer ignore-call */ 
314
        $currencyID         = $this->getDocumentCurrencyCode(); // Tipo de moneda
Loading history...
314
        $totalAllowances    = $Invoice->getTotalAllowances();   // Total descuentos
315
        $payableAmount      = $Invoice->getPayableAmount();     // Total a pagar
316
        $billableAmount     = $Invoice->getBillableValue();
317
        // LegalMonetaryTotal
318
        $LegalMonetaryTotal = new LegalMonetaryTotal();
319
        $LegalMonetaryTotal
320
            ->setCurrencyID($currencyID)
321
            ->setLineExtensionAmount($billableAmount)
322
            ->setTaxInclusiveAmount($payableAmount)
323
            ->setAllowanceTotalAmount($totalAllowances)
324
            ->setPayableAmount($payableAmount);
325
326
        parent::setLegalMonetaryTotal($LegalMonetaryTotal);
327
    }
328
329
    private function addInvoiceAccountingSupplierParty()
330
    {
331
        // Info
332
        $partyName  = Company::getBusinessName();
333
        $regName    = Company::getCompanyName();
334
        $docNumber  = Company::getRUC();
335
        $addressRegCode = Company::getRegAddressCode(); // Código de domicilio fiscal o anexo
336
        $docType    = Catalogo::IDENTIFICATION_DOC_RUC;
337
338
        // XML nodes
339
        $AccountingSupplierParty    = new AccountingSupplierParty();
340
        $Party                      = new Party();
341
        $PartyIdentification        = new PartyIdentification();
342
        $PartyTaxScheme             = new PartyTaxScheme();
343
        $RegistrationAddress        = new RegistrationAddress();
344
        $PartyIdentification
345
            ->setElementAttributes('ID', [
346
                'schemeAgencyName'  => 'PE:SUNAT',
347
                'schemeID'          => $docType,
348
                'schemeName'        => 'Documento de Identidad',
349
                'schemeURI'         => 'urn:pe:gob:sunat:cpe:see:gem:catalogos:catalogo06'
350
            ]);
351
        $PartyName                  = new PartyName();
352
        $PartyLegalEntity           = new PartyLegalEntity();
353
354
        $AccountingSupplierParty
355
            ->setParty($Party
356
                ->setPartyIdentification($PartyIdentification
357
                    ->setID($docNumber))
358
                ->setPartyName($PartyName
359
                    ->setName($partyName))
360
                ->setPartyTaxScheme($PartyTaxScheme
361
                    ->setRegistrationAddress($RegistrationAddress
362
                        ->setAddressTypeCode($addressRegCode)))
363
                ->setPartyLegalEntity($PartyLegalEntity
364
                    ->setRegistrationName($regName)
365
                    ->setRegistrationAddress($RegistrationAddress
366
                        ->setAddressTypeCode($addressRegCode))));
367
        // Add to Document
368
        parent::setAccountingSupplierParty($AccountingSupplierParty);
369
    }
370
371
    private function addInvoiceAccountingCustomerParty()
372
    {
373
        $Invoice   = $this->dataMap;
374
        // Info
375
        $regName   = $Invoice->getCustomerRegName();
376
        $docNumber = $Invoice->getCustomerDocNumber();
377
        $docType   = $Invoice->getCustomerDocType();
378
379
        // XML nodes
380
        $AccountingCustomerParty    = new AccountingCustomerParty();
381
        $Party                      = new Party();
382
        $PartyIdentification        = new PartyIdentification();
383
        $PartyLegalEntity           = new PartyLegalEntity();
384
        $PartyIdentification
385
            ->setElementAttributes('ID', [
386
                'schemeAgencyName'  => 'PE:SUNAT',
387
                'schemeID'          => $docType,
388
                'schemeName'        => 'Documento de Identidad',
389
                'schemeURI'         => 'urn:pe:gob:sunat:cpe:see:gem:catalogos:catalogo06'
390
            ]);
391
392
        $AccountingCustomerParty
393
            ->setParty($Party
394
                ->setPartyIdentification($PartyIdentification
395
                    ->setID($docNumber))
396
                ->setPartyLegalEntity($PartyLegalEntity
397
                    ->setRegistrationName($regName)));
398
        // Add to Document
399
        parent::setAccountingCustomerParty($AccountingCustomerParty);
400
    }
401
402
    /**
403
     *
404
     * @return string Nombre del comprobante de acuerdo con las especificaciones de la SUNAT
405
     */
406
    public function getDocumentName()
407
    {
408
        return $this->dataMap->getDocumentName();
409
    }
410
}
411