· 5 years ago · Oct 30, 2020, 11:14 PM
1<?php
2use PrestaShop\PrestaShop\Adapter\Entity\Customer;
3
4if ( ! defined( '_PS_VERSION_' ) ) {
5 exit;
6}
7
8require_once dirname( __FILE__ ) . '/classes/Customer.php';
9require_once dirname( __FILE__ ) . '/classes/Invoice.php';
10require_once dirname( __FILE__ ) . '/classes/NubeFact.php';
11
12class Vex_Nubefact extends Module {
13 protected $checkoutProcess;
14 private $VEX_GET_ID_ORDER;
15 private $VEX_SET_DATE_INVOICE;
16
17 // config
18 const CONFIG_LIVEMODE = 'VEX_NUBEFACT_LIVEMODE';
19 const CONFIG_LICENSE = 'VEX_NUBEFACT_LICENSE';
20 const CONFIG_TEST_URL = 'VEX_NUBEFACT_TEST_URL';
21 const CONFIG_TEST_TOKEN = 'VEX_NUBEFACT_TEST_TOKEN';
22 const CONFIG_LIVE_URL = 'VEX_NUBEFACT_LIVE_URL';
23 const CONFIG_LIVE_TOKEN = 'VEX_NUBEFACT_LIVE_TOKEN';
24 const CONFIG_BUSINESS_RUC = 'VEX_NUBEFACT_BUSINESS_RUC';
25 const CONFIG_BUSINESS_NAME = 'VEX_NUBEFACT_BUSINESS_NAME';
26 const CONFIG_BUSINESS_ADDRESS = 'VEX_NUBEFACT_BUSINESS_ADDRESS';
27 const CONFIG_RECEIPT_SERIE = 'VEX_NUBEFACT_RECEIPT_SERIE';
28 const CONFIG_RECEIPT_NUM = 'VEX_NUBEFACT_RECEIPT_NUM';
29 const CONFIG_INVOICE_SERIE = 'VEX_NUBEFACT_INVOICE_SERIE';
30 const CONFIG_INVOICE_NUM = 'VEX_NUBEFACT_INVOICE_NUM';
31 const CONFIG_INVOICE_STATE = 'VEX_NUBEFACT_INVOICE_STATE';
32 const CONFIG_INVOICE_SUNAT_CODE = 'VEX_NUBEFACT_INVOICE_SUNAT_CODE';
33 const CONFIG_API_APPNAME = 'VEX_API_APPNAME';
34 const CONFIG_API_FE_BILLING_NAME = 'VEX_API_FE_BILLING_NAME';
35 const CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE = 'VEX_FE_TOKEN_AUTO_INCREMENT_INVOICE';
36 const CONFIG_FE_URL_AUTO_INCREMENT_INVOICE = 'VEX_FE_URL_AUTO_INCREMENT_INVOICE';
37 const CONFIG_FE_F_SUFFIX = 'VEX_FE_F_SUFFIX';
38 const CONFIG_FE_B_SUFFIX = 'VEX_FE_B_SUFFIX';
39
40 const TIPOCOMPROBANTE_FACTURA = 1;
41 const TIPODOCUMENTO_RUC = 6;
42
43 const NUBEFACT_PATH_LOG = _PS_ROOT_DIR_ . "/../logs/modules/vex_nubefact/log";
44
45 public function __construct(){
46 $this->name = 'vex_nubefact';
47 // $this->tab = 'administration';
48 $this->tab = 'billing_invoicing';
49 $this->version = '1.2.0';
50 $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
51 $this->author = 'Vex Soluciones - Modified by Alekuoshu & German';
52 // $this->controllers = array('validation', 'payment', 'transaction', 'error');
53 $this->bootstrap = true;
54
55
56
57 $this->displayName = 'NubeFact';
58 $this->description = $this->l('Electronic invoicing management module for Peru');
59 $this->confirmUninstall = $this->l('Are you sure about removing NubeFact?');
60 $this->VEX_GET_ID_ORDER = Tools::getValue('VEX_GET_ID_ORDER');
61 $this->VEX_SET_DATE_INVOICE = Tools::getValue('VEX_SET_DATE_INVOICE');
62 parent::__construct();
63
64 // init this function
65 $this->sendMasiveInvoices();
66 }
67
68 public function install()
69 {
70 return (parent::install()
71 && $this->createTabs()
72 && $this->registerHook('header')
73 && $this->registerHook('displayPaymentTop')
74 && $this->registerHook('termsAndConditions')
75 && $this->registerHook('backOfficeHeader')
76 && $this->registerHook('actionOrderStatusPostUpdate')
77 && $this->registerHook('displayOrderDetail')
78 && $this->registerHook('actionObjectCustomerAddAfter')
79 && $this->registerHook('displayAdminCustomersForm')
80 && $this->installDb());
81 }
82
83 public function uninstall(){
84 return (
85 parent::uninstall()
86 );
87 }
88
89 public function installDb()
90 {
91 return (Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'vex_nubefact_customer` (
92 `id` int(11) NOT NULL AUTO_INCREMENT,
93 `customer_id` int(11) NOT NULL,
94 `cart_id` int(11) NOT NULL,
95 `tipo_de_comprobante` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
96 `cliente_tipo_de_documento` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
97 `cliente_numero_de_documento` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
98 `cliente_denominacion` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
99 `cliente_direccion` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
100 `date_add` DATETIME NOT NULL,
101 PRIMARY KEY (`id`)
102 ) ENGINE=' . _MYSQL_ENGINE_ . ' AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;') &&
103 Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'vex_nubefact_invoice` (
104 `comprobante_id` int(11) NOT NULL AUTO_INCREMENT,
105 `id_customer` int(11) NOT NULL,
106 `id_order` int(11) NOT NULL,
107 `url_pdf` text COLLATE utf8mb4_unicode_ci,
108 `tipo_de_comprobante` char(2) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
109 `serie` char(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
110 `numero` int(11) DEFAULT NULL,
111 `cliente_tipo_de_documento` varchar(6) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
112 `cliente_numero_de_documento` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
113 `cliente_denominacion` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
114 `cliente_direccion` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
115 `cliente_email` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
116 `fecha_de_emision` date DEFAULT NULL,
117 `porcentaje_de_igv` double DEFAULT NULL,
118 `descuento_global` double DEFAULT NULL,
119 `total_descuento` double DEFAULT NULL,
120 `total_gravada` double DEFAULT NULL,
121 `total_igv` double DEFAULT NULL,
122 `total_gratuita` double DEFAULT NULL,
123 `total` double DEFAULT NULL,
124 `wp_data` text COLLATE utf8mb4_unicode_ci,
125 `sunat_estado` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT "",
126 `sunat_respuesta_envio` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
127 `sunat_fecha_envio` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
128 `sys_estado` smallint(6) DEFAULT "1",
129 `date_add` DATETIME NOT NULL,
130 PRIMARY KEY (`comprobante_id`,`sunat_estado`)
131 ) ENGINE=' . _MYSQL_ENGINE_ . ' AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;'));
132 }
133
134 private function createTabs()
135 {
136 $tab = new Tab();
137 $tab->active = 1;
138 $tab->class_name = "AdminNubeFact";
139 $tab->id_parent = Tab::getIdFromClassName('AdminParentOrders');
140 $tab->module = $this->name;
141 $tab->name = array();
142
143 foreach (Language::getLanguages() as $lang) {
144 $tab->name[$lang['id_lang']] = "NubeFact";
145 }
146
147 return $tab->add();
148 }
149
150 private function canBeUsed($params)
151 {
152 if (! $this->active) {
153 return false;
154 }
155
156 return true;
157 }
158
159 /**
160 * Add the CSS & JavaScript files in the module's backoffice.
161 *
162 * @return void
163 */
164 public function hookBackOfficeHeader($params)
165 {
166 $controller = Tools::getValue('controller');
167 $submitAddcustomer = Tools::getValue('submitAddcustomer');
168 $tipoDeDocumentoCliente = Tools::getValue('tipo_de_documento_cliente');
169 $id_customer = (int) Tools::getValue('id_customer');
170
171 if (! empty($id_customer) && $controller == 'AdminCustomers' && (bool) $submitAddcustomer && ! empty($tipoDeDocumentoCliente)) {
172
173 $customer = new Customer($id_customer);
174 if (Validate::isLoadedObject($customer))
175 self::updateDataInvoice($customer);
176 }
177
178
179 if (! $this->canBeUsed($params)) {
180 return false;
181 }
182
183 if (Tools::getValue('configure') == $this->name) {
184 $this->context->controller->addCSS($this->_path . 'views/css/backend.css');
185 // if (version_compare(_PS_VERSION_, '1.6', '<') == true) {
186 // $this->context->controller->addCSS($this->_path.'views/css/bootstrap.min.css');
187 // $this->context->controller->addCSS($this->_path.'views/css/configure-ps-15.css');
188 // } else {
189 // $this->context->controller->addCSS($this->_path.'views/css/configure-ps-16.css');
190 // }
191 }
192 }
193
194
195 /**
196 * Add the CSS & JavaScript files on the frontoffice.
197 *
198 * @return void
199 */
200 public function hookHeader($params)
201 {
202 if (! $this->canBeUsed($params)) {
203 return false;
204 }
205
206 // print_r( [$params, $this->context]);
207 $this->context->controller->addJS($this->_path . '/views/js/front.js');
208 // $this->context->controller->addCSS($this->_path.'/views/css/front.css');
209 }
210
211 public function hookDisplayPaymentTop($params)
212 {
213 if (! $this->canBeUsed($params)) {
214 return false;
215 }
216
217 $this->getDataInvoiceForm();
218
219 return $this->display(__FILE__, 'vex_facturacion.tpl');
220 }
221
222 /*
223 * Hook que se acciona al pasar estado depende del valor de la variable CONFIG_INVOICE_STATE
224 */
225 public function hookActionOrderStatusPostUpdate($params)
226 {
227 if (! $this->canBeUsed($params)) {
228 return false;
229 }
230
231 $stateID = trim(Configuration::get(self::CONFIG_INVOICE_STATE));
232
233 // value if state changed is equal to (CONFIG_INVOICE_STATE)
234 if ($params['newOrderStatus']->id == $stateID) {
235
236 $order = new Order($params['id_order']);
237 $customer_id = $order->id_customer;
238 $id_cart = $order->id_cart;
239
240 // evalua si es gratuita o no
241 if ($order->total_paid_tax_incl == 0) {
242 $incluido_impuestos = 0; // total incluido impuesto
243 $sin_impuestos = 0; // total sin impuesto
244 } else {
245 // $incluido_impuestos = $order->total_products_wt; // total incluido impuesto
246 // $sin_impuestos = $order->total_products; // total sin impuesto
247 $incluido_impuestos = $order->total_paid_tax_incl; // total incluido impuesto
248 $sin_impuestos = $order->total_paid_tax_excl; // total sin impuesto
249 }
250
251 $totalGratis = 0;
252 $sumaDescuentoItems = 0;
253 // load saved values
254 // $nubeFactValues = array();
255 if ($nubeFactCustomer = Vex_Nubefact_Customer::getByCustomerId($customer_id)) {
256 // $nubeFactValues = $nubeFactCustomer;
257 // unset( $nubeFactValues['date_add'], $nubeFactValues['cart_id'] );
258 // unset( $nubeFactValues['customer_id'], $nubeFactValues['id'] );
259 $customer = new Customer($customer_id);
260
261 $url = $this->get_url();
262 $token = $this->get_token();
263
264 $nubeFact = new Vex_PrestaShop_NubeFact($url, $token);
265
266 if ($nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA) {
267 require_once dirname(__FILE__) . '/classes/NubeFact/FacturaElectronica.php';
268 $document = new Vex_FacturaElectronica();
269
270 $serie = 'F' . Configuration::get( self::CONFIG_INVOICE_SERIE );
271 // $numero = Configuration::get( self::CONFIG_INVOICE_NUM );
272
273 // consulta consecutivo en api
274 $AutoIncrementInvoice = new stdClass();
275 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
276 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
277 $AutoIncrementInvoice->idCart = $id_cart;
278 $AutoIncrementInvoice->idOrder = $params['id_order'];
279 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
280 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_F_SUFFIX);
281 $AutoIncrementInvoice->production = true;
282
283 $data_string = json_encode($AutoIncrementInvoice);
284
285 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
286 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
287 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
288 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
289 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
290 'Content-Type: application/json',
291 'Content-Length: ' . strlen($data_string)
292 ));
293
294 $response = curl_exec($ch);
295
296 $responseArray = json_decode($response, true);
297 $numero = $responseArray['invoiceNumber'];
298
299 } else {
300 require_once dirname( __FILE__ ) . '/classes/NubeFact/BoletaElectronica.php';
301 $document = new Vex_BoletaElectronica();
302
303 $serie = 'B' . Configuration::get( self::CONFIG_RECEIPT_SERIE );
304 // $numero = Configuration::get( self::CONFIG_RECEIPT_NUM );
305
306 // consulta consecutivo en api
307 $AutoIncrementInvoice = new stdClass();
308 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
309 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
310 $AutoIncrementInvoice->idCart = $id_cart;
311 $AutoIncrementInvoice->idOrder = $params['id_order'];
312 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
313 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_B_SUFFIX);
314 $AutoIncrementInvoice->production = true;
315
316 $data_string = json_encode($AutoIncrementInvoice);
317
318 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
319 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
320 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
321 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
322 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
323 'Content-Type: application/json',
324 'Content-Length: ' . strlen($data_string)
325 ));
326
327 $response = curl_exec($ch);
328
329 $responseArray = json_decode($response, true);
330 $numero = $responseArray['invoiceNumber'];
331 }
332
333 $document->setSunatEnvioAutomatico( true );
334 $document->setSerie( $serie );
335 $document->setNumero( $numero );
336
337 $document->setCliente( array(
338 'cliente_tipo_de_documento' => $nubeFactCustomer['cliente_tipo_de_documento'],
339 'cliente_numero_de_documento' => trim($nubeFactCustomer['cliente_numero_de_documento']),
340 'cliente_denominacion' => $nubeFactCustomer['cliente_denominacion'],
341 'cliente_direccion' => $nubeFactCustomer['cliente_direccion']
342 ) );
343
344 $document->addClienteEmail( $customer->email );
345
346 // $currency = new Currency($order->id_currency);
347 // $currencies = array(
348 // 'PEN' => Vex_DocumentContract::$SOL,
349 // 'USD' => Vex_DocumentContract::$DOLAR,
350 // 'EUR' => Vex_DocumentContract::$EURO,
351 // );
352
353 // var_export( [$currency, $nubeFactCustomer] );
354
355
356 // $document->setMoneda( $currencies[ $currency->iso_code ] );
357
358 // $document->setTipoCambio();
359 $document->setPorcentajeIGV( $this->get_percent_igv() );
360 $document->setTotal( $incluido_impuestos );
361 // $document->setDetraccion();
362 // $document->setObservaciones();
363
364 $features = $this->getFeaturesProductOrder($order->id);
365
366 $giftFlag = false;
367 $dproductFlag = false;
368 $totalInafecta = 0;
369
370 foreach ( $order->getProducts() as $productDetail ) {
371 $TotalConImpuesto = $productDetail['total_price_tax_incl'];
372 $TotalSinImpuesto = $productDetail['total_price_tax_excl'];
373 $discounts = $productDetail['reduction_percent'];
374 $discountAmount = $productDetail['reduction_amount_tax_excl'];
375 $valorUnitario = $productDetail['original_product_price'];
376 $includeTax = $productDetail['id_tax_rules_group'];
377 $impuestoUnitario = ($valorUnitario * (int) $this->get_percent_igv()) / 100;
378 $precioUnitario = round($valorUnitario + $impuestoUnitario, 2);
379 $tipoIGV = '1';
380 $IGV = $TotalConImpuesto - $TotalSinImpuesto;
381 $total = $TotalConImpuesto;
382 $descuento = 0;
383 $subtotal = ($valorUnitario * $productDetail['product_quantity']) - $descuento;
384
385
386 // evalua si el producto es inafecto
387 if($includeTax == 0){
388 self::logtxt("Producto Inafecto de IGV");
389 $precioUnitario = $valorUnitario;
390 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
391 $tipoIGV = '9';
392 $IGV = 0;
393 $total = $subtotal;
394 $totalInafecta += $total;
395 $dproductFlag = true;
396
397 // descuento por producto
398 if($discounts > 0) {
399 self::logtxt("Descuento por producto! - Percent");
400 $descuento = ($valorUnitario * $discounts / 100);
401 $sumaDescuentoItems += $descuento;
402 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
403 $total = $subtotal;
404 $totalInafecta += $total;
405
406 if($discounts == 100) {
407 // Si el producto es gratuito
408 self::logtxt("Producto gratuito");
409 $giftFlag = true;
410 $precioUnitario = $valorUnitario;
411 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
412 $tipoIGV = '9';
413 $IGV = 0;
414 $total = $subtotal;
415 $totalGratis += $subtotal;
416 $descuento = 0;
417 $totalInafecta += $total;
418 }
419
420 }elseif($discountAmount > 0){
421 self::logtxt("Descuento por producto! - Amount");
422 $descuento = $discountAmount;
423 $sumaDescuentoItems += $discountAmount;
424 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
425 $total = $subtotal;
426 $totalInafecta += $total;
427 $dproductFlag = true;
428
429 }
430
431 }else{
432 self::logtxt("Producto Con IGV");
433
434 // descuento por producto
435 if($discounts > 0) {
436 self::logtxt("Descuento por producto! - Percent");
437 $descuento = ($valorUnitario * $discounts / 100);
438 $sumaDescuentoItems += $descuento;
439 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
440 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
441 $dproductFlag = true;
442
443 if($discounts == 100) {
444 // Si el producto es gratuito
445 self::logtxt("Producto gratuito");
446 $giftFlag = true;
447 $precioUnitario = $valorUnitario;
448 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
449 $tipoIGV = '6';
450 $IGV = 0;
451 $total = $subtotal;
452 $totalGratis += $subtotal;
453 $descuento = 0;
454 }
455
456 }elseif($discountAmount > 0){
457 self::logtxt("Descuento por producto! - Amount");
458 $descuento = $discountAmount;
459 $sumaDescuentoItems += $discountAmount;
460 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
461 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
462 $dproductFlag = true;
463
464 }
465
466 }//fin producto es inafecto de IGV
467
468 if(!empty($features[$productDetail['product_id']]['value']))
469 $codigo_producto_sunat = $features[$productDetail['product_id']]['value'];
470 else
471 $codigo_producto_sunat = Configuration::get( self::CONFIG_INVOICE_SUNAT_CODE );
472
473
474 // evalua si es gratuito o no
475 if($order->total_paid_tax_incl == 0){
476 $precioUnitario = $valorUnitario;
477 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
478 $totalGratis += $subtotal;
479 $tipoIGV = '6';
480 $IGV = 0;
481 $total = $subtotal;
482 }
483
484 $document->addItem( array(
485 'unidad_de_medida' => 'NIU',
486 'codigo' => $productDetail['product_id'],
487 'descripcion' => $productDetail['product_name'],
488 'cantidad' => $productDetail['product_quantity'],
489 'valor_unitario' => $valorUnitario, // unitario sin impuesto
490 'precio_unitario' => $precioUnitario, // unitario con impuesto
491 'descuento' => $descuento,
492 'subtotal' => $subtotal,
493 'tipo_de_igv' => $tipoIGV,
494 'igv' => $IGV,
495 'total' => $total,
496 'anticipo_regularizacion' => 'false',
497 'anticipo_documento_serie' => '',
498 'anticipo_documento_numero' => '',
499 'codigo_producto_sunat' => $codigo_producto_sunat //Fórmulas y productos para apoyo nutritivo
500 ) );
501 }
502
503 // transporte
504 $shipping_sin_impuestos = $order->total_shipping_tax_excl; // total transporte sin impuesto
505 $shipping_con_impuestos = $order->total_shipping_tax_incl; // total transporte sin impuesto
506 $precioUnitario = round($shipping_con_impuestos, 2);
507 $tipoIGV = '1';
508 $IGV = $shipping_con_impuestos - $shipping_sin_impuestos;
509 $total = $shipping_con_impuestos;
510 if ($shipping_sin_impuestos > 0) {
511 // evalua si es gratuito o no
512 if($order->total_paid_tax_incl == 0){
513 $precioUnitario = $shipping_sin_impuestos;
514 $tipoIGV = '6';
515 $IGV = 0;
516 $total = $shipping_sin_impuestos;
517 }
518
519 $document->addItem( array(
520 'unidad_de_medida' => 'ZZ',
521 'codigo' => '001',
522 'descripcion' => 'Costo de envío',
523 'cantidad' => '1',
524 'valor_unitario' => $shipping_sin_impuestos, // unitario sin impuesto
525 'precio_unitario' => $precioUnitario, // unitario con impuesto
526 'descuento' => '',
527 'subtotal' => $shipping_sin_impuestos,
528 'tipo_de_igv' => $tipoIGV,
529 'igv' => $IGV,
530 'total' => $total,
531 'anticipo_regularizacion' => 'false',
532 'anticipo_documento_serie' => '',
533 'anticipo_documento_numero' => '',
534 'codigo_producto_sunat' => '78140000' //Servicios de transporte
535 ) );
536 }
537
538 // $document->setCodigoUnico();
539
540 // var_export( $document->getArray() );
541
542 // descuento general
543 $total_descuentos = 0;
544 $descuento_general = 0;
545 if($order->total_discounts > 0){
546 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
547 }
548 $total_descuentos = $descuento_general + $sumaDescuentoItems;
549
550 // si hay descuento general y por item
551 if($order->total_discounts > 0 && $dproductFlag == true){
552 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
553 $total_descuentos = $sumaDescuentoItems;
554 }
555 $document->setDescuentoGlobal( $descuento_general );
556 $document->setTotalDescuento( $total_descuentos );
557
558 // si es gratuita o no
559 if($order->total_paid_tax_incl == 0){
560 $document->setTotalGratis( $totalGratis );
561 }
562
563 // si existe un producto gratuito
564 if($giftFlag == true){
565 $document->setTotalGratis( $totalGratis );
566 }
567
568 // Evalua el tipo de documento para saber el tipo de transacción (segun sunat) - By Alekuoshu
569 if((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 4 || (int) $nubeFactCustomer['cliente_tipo_de_documento'] == 7){
570 $document->setSunatTransaction( 29 ); // Venta no domiciliados que no califican como exportación
571 }elseif((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 0){
572 $document->setSunatTransaction( 2 ); // Exportanción
573 }else{
574 $document->setSunatTransaction( 1 ); // Venta Interna
575 }
576
577 // si existe un producto inefacto de IGV
578 if($totalInafecta > 0){
579 $document->setTotalInafecta( $totalInafecta );
580 $total_igv = '';
581 $document->setTotalIGV( $total_igv );
582 $tota_gravada = '';
583 $document->setTotalGravada( $tota_gravada );
584 }else{
585 $total_igv = round( $incluido_impuestos - $sin_impuestos, 2 );
586 $document->setTotalIGV( $total_igv );
587 $tota_gravada = $sin_impuestos;
588 $document->setTotalGravada( $tota_gravada );
589 }
590
591 //create invoice
592 $invoice = new Vex_Nubefact_Invoice();
593
594 $invoice->id_customer = $customer->id;
595 $invoice->id_order = $order->id;
596 $invoice->tipo_de_comprobante = $nubeFactCustomer['tipo_de_comprobante'];
597 $invoice->serie = $serie;
598 $invoice->numero = (int) $numero;
599 $invoice->cliente_tipo_de_documento = $nubeFactCustomer['cliente_tipo_de_documento'];
600 $invoice->cliente_numero_de_documento = trim($nubeFactCustomer['cliente_numero_de_documento']);
601 $invoice->cliente_denominacion = $nubeFactCustomer['cliente_denominacion'];
602 $invoice->cliente_direccion = $nubeFactCustomer['cliente_direccion'];
603 $invoice->cliente_email = $customer->email;
604 $invoice->fecha_de_emision = date( 'Y-m-d' );
605 $invoice->moneda = 1;
606 $invoice->porcentaje_de_igv = $this->get_percent_igv();
607 $invoice->descuento_global = $descuento_general;
608 $invoice->total_descuento = $total_descuentos;
609 $invoice->total_gravada = $tota_gravada;
610 $invoice->total_igv = $total_igv;
611 $invoice->total_gratuita = $totalGratis;
612 $invoice->total = $incluido_impuestos;
613
614
615 // Get json for sent to log
616 $jsonEnviado = json_encode($document->getArray());
617 self::logtxt("Json_enviado: ".$jsonEnviado);
618
619
620 // validar que no existe ya la factura en nubefact y no este aceptada a la sunat
621 $query = new DbQuery();
622 $query->select('*');
623 $query->from('vex_nubefact_invoice');
624 $query->where('id_order = "'.$order->id.'" AND sunat_estado = 1');
625 $valueR = Db::getInstance()->executeS($query);
626
627 // si no existe en el registro la factura se envia a nubefact
628 if(empty($valueR)){
629 if( $response = $nubeFact->sendDocument( $document ) ){
630 // incrementar numero
631 // if( $nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA ){
632 // Configuration::updateValue( self::CONFIG_INVOICE_NUM, $numero+1 );
633 // } else {
634 // Configuration::updateValue( self::CONFIG_RECEIPT_NUM, $numero+1 );
635 // }
636
637 $data = @json_decode( $response );
638
639 // guardar pdf url
640 $invoice->url_pdf = $data->enlace_del_pdf;
641 // respuesta sunat
642 $sunat = $data->aceptada_por_sunat;
643 if($sunat === true){
644 $invoice->sunat_estado = '1';
645 $invoice->sunat_respuesta_envio = $data->sunat_description;
646
647 // Insertamos data en ps_vex_invoices_sent tabla
648 $result = Db::getInstance()->insert('vex_invoices_sent', array(
649 'id_order' => $params['id_order'],
650 'date_add' => date("Y-m-d H:i:s"),
651 ));
652 $error = Db::getInstance()->getMsgError();
653
654 if ($result == true) {
655 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
656 } else {
657 if ($error != '') {
658 self::logtxt($error);
659 }
660 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
661 }
662
663 }else{
664 $invoice->sunat_estado = '0';
665 $invoice->sunat_respuesta_envio = $data->sunat_description;
666
667 // Insertamos data en ps_vex_invoices_sent tabla
668 $result = Db::getInstance()->insert('vex_invoices_sent', array(
669 'id_order' => $params['id_order'],
670 'date_add' => date("Y-m-d H:i:s"),
671 ));
672 $error = Db::getInstance()->getMsgError();
673
674 if ($result == true) {
675 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
676 } else {
677 if ($error != '') {
678 self::logtxt($error);
679 }
680 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
681 }
682
683 }
684 } else {
685 // var_export( [ $nubeFact->getClient(), $document->getArray() ] );
686 // exit();
687 }
688
689 $invoice->wp_data = $nubeFact->getClient()->response;
690 $invoice->add();
691 }
692
693 }
694 // $customer = new Customer($customer_id);
695
696 // $clientParams = array(
697 // 'cliente_email' => $customer->email,
698 // 'cliente_tipo_de_documento' => '',
699 // 'cliente_numero_de_documento' => '',
700 // 'cliente_denominacion' => '',
701 // 'cliente_direccion' => ''
702 // );
703
704 // $clientParams = array_merge( $clientParams, $nubeFactValues );
705
706 // var_export( [$params['id_order'], $order->id] );
707 // exit();
708
709 }//fin cambio de estado
710
711 }
712
713 // public function hookDisplayCustomerAccount(){
714 // $data = array();
715 // $this->context->smarty->assign( $data );
716
717 // return $this->display(__FILE__, 'customer-account.tpl');
718 // }
719
720 public function hookDisplayOrderDetail( $params ){
721 if( $invoice = Vex_Nubefact_Invoice::getByOrderId( $params['order']->id ) ){
722 $url_pdf = '';
723
724 if( empty( $invoice['url_pdf'] ) ){
725 $data = @json_decode( $invoice['wp_data'] );
726
727 if( isset( $data->enlace_del_pdf ) ){
728 $url_pdf = $data->enlace_del_pdf;
729 }
730 } else {
731 $url_pdf = $invoice['url_pdf'];
732 }
733
734 $this->context->smarty->assign( array(
735 'serie' => $invoice['serie'],
736 'numero' => str_pad( $invoice['numero'], 4, '0', STR_PAD_LEFT ),
737 'url_pdf' => $url_pdf
738 ) );
739
740 return $this->display(__FILE__, 'order-detail.tpl');
741 }
742 }
743
744 public function getContent(){
745 if( Tools::isSubmit( 'submit' . $this->name ) ){
746 $this->postProcess();
747
748 $id_orderM = $this->VEX_GET_ID_ORDER;
749 if($id_orderM){
750 // self::logtxt("Entered in manually mode... ID_Order: $id_orderM");
751 $this->sendDataManually($id_orderM);
752
753 }
754 }
755
756 return $this->displayForm();
757 }
758
759 protected function postProcess(){
760 $test_url = Configuration::get( self::CONFIG_TEST_URL, null, null, null, '' );
761 $test_token = Configuration::get( self::CONFIG_TEST_TOKEN, null, null, null, '' );
762
763 $live_url = Configuration::get( self::CONFIG_LIVE_URL, null, null, null, '' );
764 $live_token = Configuration::get( self::CONFIG_LIVE_TOKEN, null, null, null, '' );
765
766 // save credentials
767 if( Tools::getValue( self::CONFIG_LIVEMODE ) == 0 ){
768 if( ! Tools::getValue( self::CONFIG_TEST_URL ) ){
769 $this->context->controller->errors[] = $this->l('TEST URL required!');
770 } else {
771 $test_url = Tools::getValue( self::CONFIG_TEST_URL, '' );
772 }
773
774 if( ! Tools::getValue( self::CONFIG_TEST_TOKEN ) ){
775 $this->context->controller->errors[] = $this->l('TEST Token required!');
776 } else {
777 $test_token = Tools::getValue( self::CONFIG_TEST_TOKEN, '' );
778 }
779 } else {
780 if( ! Tools::getValue( self::CONFIG_LIVE_URL ) ){
781 $this->context->controller->errors[] = $this->l('LIVE URL required!');
782 } else {
783 $live_url = Tools::getValue( self::CONFIG_LIVE_URL, '' );
784 }
785
786 if( ! Tools::getValue( self::CONFIG_LIVE_TOKEN ) ){
787 $this->context->controller->errors[] = $this->l('LIVE Token required!');
788 } else {
789 $live_token = Tools::getValue( self::CONFIG_LIVE_TOKEN, '' );
790 }
791 }
792
793 // validate business ruc
794 if( ! Tools::getValue( self::CONFIG_BUSINESS_RUC ) ){
795 $this->context->controller->errors[] = $this->l('Business ruc required!');
796 }
797
798 // validate business name
799 if( ! Tools::getValue( self::CONFIG_BUSINESS_NAME ) ){
800 $this->context->controller->errors[] = $this->l('Business name required!');
801 }
802
803 // validate business address
804 if( ! Tools::getValue( self::CONFIG_BUSINESS_ADDRESS ) ){
805 $this->context->controller->errors[] = $this->l('Business address required!');
806 }
807
808 // validate receipt serie
809 if( ! Tools::getValue( self::CONFIG_RECEIPT_SERIE ) ){
810 $this->context->controller->errors[] = $this->l('Receipt serie required!');
811 }
812
813 // validate receipt num
814 if( ! Tools::getValue( self::CONFIG_RECEIPT_NUM ) ){
815 $this->context->controller->errors[] = $this->l('Receipt number required!');
816 }
817
818 // validate invoice serie
819 if( ! Tools::getValue( self::CONFIG_INVOICE_SERIE ) ){
820 $this->context->controller->errors[] = $this->l('Invoice serie required!');
821 }
822
823 // validate invoice num
824 if( ! Tools::getValue( self::CONFIG_INVOICE_NUM ) ){
825 $this->context->controller->errors[] = $this->l('Invoice number required!');
826 }
827
828 // validate invoice state
829 if( ! Tools::getValue( self::CONFIG_INVOICE_STATE ) ){
830 $this->context->controller->errors[] = $this->l('State number required!');
831 }
832
833 // validate api name
834 if( ! Tools::getValue( self::CONFIG_API_APPNAME ) ){
835 $this->context->controller->errors[] = $this->l('Api name required!');
836 }
837
838 // validate billing name
839 if( ! Tools::getValue( self::CONFIG_API_FE_BILLING_NAME ) ){
840 $this->context->controller->errors[] = $this->l('Billing name required!');
841 }
842
843 // validate token
844 if( ! Tools::getValue( self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE ) ){
845 $this->context->controller->errors[] = $this->l('Token required!');
846 }
847
848 // validate api url
849 if( ! Tools::getValue( self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE ) ){
850 $this->context->controller->errors[] = $this->l('URL required!');
851 }
852
853 // validate factura suffix
854 if( ! Tools::getValue( self::CONFIG_FE_F_SUFFIX ) ){
855 $this->context->controller->errors[] = $this->l('Factura suffix required!');
856 }
857
858 // validate boleta suffix
859 if( ! Tools::getValue( self::CONFIG_FE_B_SUFFIX ) ){
860 $this->context->controller->errors[] = $this->l('Boleta suffix required!');
861 }
862
863
864
865 // save other fields
866 Configuration::updateValue( self::CONFIG_LIVEMODE, ( int ) Tools::getValue( self::CONFIG_LIVEMODE ) );
867 Configuration::updateValue( self::CONFIG_TEST_URL, $test_url );
868 Configuration::updateValue( self::CONFIG_TEST_TOKEN, $test_token );
869
870 Configuration::updateValue( self::CONFIG_LIVE_URL, $live_url );
871 Configuration::updateValue( self::CONFIG_LIVE_TOKEN, $live_token );
872 Configuration::updateValue( self::CONFIG_BUSINESS_RUC, Tools::getValue( self::CONFIG_BUSINESS_RUC ) );
873 Configuration::updateValue( self::CONFIG_BUSINESS_NAME, Tools::getValue( self::CONFIG_BUSINESS_NAME ) );
874 Configuration::updateValue( self::CONFIG_BUSINESS_ADDRESS, Tools::getValue( self::CONFIG_BUSINESS_ADDRESS ) );
875 Configuration::updateValue( self::CONFIG_RECEIPT_SERIE, Tools::getValue( self::CONFIG_RECEIPT_SERIE ) );
876 Configuration::updateValue( self::CONFIG_RECEIPT_NUM, Tools::getValue( self::CONFIG_RECEIPT_NUM ) );
877 Configuration::updateValue( self::CONFIG_INVOICE_SERIE, Tools::getValue( self::CONFIG_INVOICE_SERIE ) );
878 Configuration::updateValue( self::CONFIG_INVOICE_NUM, Tools::getValue( self::CONFIG_INVOICE_NUM ) );
879 Configuration::updateValue( self::CONFIG_INVOICE_STATE, Tools::getValue( self::CONFIG_INVOICE_STATE ) );
880 Configuration::updateValue( self::CONFIG_INVOICE_SUNAT_CODE, Tools::getValue( self::CONFIG_INVOICE_SUNAT_CODE ) );
881 Configuration::updateValue( self::CONFIG_API_APPNAME, Tools::getValue( self::CONFIG_API_APPNAME ) );
882 Configuration::updateValue( self::CONFIG_API_FE_BILLING_NAME, Tools::getValue( self::CONFIG_API_FE_BILLING_NAME ) );
883 Configuration::updateValue( self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE, Tools::getValue( self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE ) );
884 Configuration::updateValue( self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE, Tools::getValue( self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE ) );
885 Configuration::updateValue( self::CONFIG_FE_F_SUFFIX, Tools::getValue( self::CONFIG_FE_F_SUFFIX ) );
886 Configuration::updateValue( self::CONFIG_FE_B_SUFFIX, Tools::getValue( self::CONFIG_FE_B_SUFFIX ) );
887
888 if ( ! count( $this->context->controller->errors ) ) {
889 $this->context->controller->confirmations[] = $this->l('Settings saved successfully');
890 }
891 }
892
893 protected function displayForm(){
894 $default_lang = new Language( ( int ) Configuration::get( 'PS_LANG_DEFAULT' ) );
895
896 $helper = new HelperForm();
897 $helper->show_toolbar = true;
898 $helper->table = $this->table;
899 $helper->name_controller = $this->name;
900 $helper->default_form_language = $default_lang->id;
901 $helper->submit_action = 'submit' . $this->name;
902 $helper->currentIndex = $this->context->link->getAdminLink( 'AdminModules', false ) . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
903 $helper->token = Tools::getAdminTokenLite( 'AdminModules' );
904
905 $helper->tpl_vars = array(
906 'fields_value' => $this->getConfigFieldsValues(),
907 'languages' => $this->context->controller->getLanguages(),
908 'id_language' => $this->context->language->id
909 );
910
911 $this->context->controller->addJS( $this->_path . 'views/js/backoffice.js' );
912
913 return $helper->generateForm( $this->getConfigForm() );
914 }
915
916 public function getConfigFieldsValues(){
917 return array(
918 self::CONFIG_LIVEMODE => Configuration::get( self::CONFIG_LIVEMODE ),
919 self::CONFIG_TEST_URL => Configuration::get( self::CONFIG_TEST_URL ),
920 self::CONFIG_TEST_TOKEN => Configuration::get( self::CONFIG_TEST_TOKEN ),
921 self::CONFIG_LIVE_URL => Configuration::get( self::CONFIG_LIVE_URL ),
922 self::CONFIG_LIVE_TOKEN => Configuration::get( self::CONFIG_LIVE_TOKEN ),
923 self::CONFIG_BUSINESS_RUC => Configuration::get( self::CONFIG_BUSINESS_RUC ),
924 self::CONFIG_BUSINESS_NAME => Configuration::get( self::CONFIG_BUSINESS_NAME ),
925 self::CONFIG_BUSINESS_ADDRESS => Configuration::get( self::CONFIG_BUSINESS_ADDRESS ),
926 self::CONFIG_INVOICE_STATE => Configuration::get( self::CONFIG_INVOICE_STATE ),
927 self::CONFIG_INVOICE_SUNAT_CODE => Configuration::get( self::CONFIG_INVOICE_SUNAT_CODE ),
928 self::CONFIG_API_APPNAME => Configuration::get( self::CONFIG_API_APPNAME ),
929 self::CONFIG_API_FE_BILLING_NAME => Configuration::get( self::CONFIG_API_FE_BILLING_NAME ),
930 self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE => Configuration::get( self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE ),
931 self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE => Configuration::get( self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE ),
932 self::CONFIG_FE_F_SUFFIX => Configuration::get( self::CONFIG_FE_F_SUFFIX ),
933 self::CONFIG_FE_B_SUFFIX => Configuration::get( self::CONFIG_FE_B_SUFFIX ),
934 'VEX_GET_ID_ORDER' => Tools::getValue('VEX_GET_ID_ORDER'),
935 'VEX_SET_DATE_INVOICE' => Tools::getValue('VEX_SET_DATE_INVOICE'),
936 );
937 }
938
939 protected function getConfigForm(){
940 $testmode_form = array(
941 'form' => array(
942 'legend' => array(
943 'title' => $this->l('Environment'),
944 'icon' => 'icon-wrench'
945 ),
946 'input' => array(
947 array(
948 'type' => 'switch',
949 'label' => $this->l('Live mode'),
950 'name' => self::CONFIG_LIVEMODE,
951 'is_bool' => true,
952 'desc' => $this->l('Choose between live or test mode'),
953 'values' => array(
954 array(
955 'id' => 'active_on',
956 'value' => 1,
957 'label' => $this->l('Live')
958 ),
959 array(
960 'id' => 'active_off',
961 'value' => 0,
962 'label' => $this->l('Test')
963 )
964 )
965 )
966 ),
967 'submit' => array(
968 'title' => $this->l('Save')
969 )
970 )
971 );
972
973 $credentials_form = array(
974 'form' => array(
975 'legend' => array(
976 'title' => $this->l('API credentials'),
977 'icon' => 'icon-user'
978 ),
979 'input' => array(
980 array(
981 'type' => 'text',
982 'label' => $this->l('TEST URL'),
983 'name' => self::CONFIG_TEST_URL,
984 'placeholder' => 'https://api.nubefact.com/api/v1/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
985 'class' => 'test-field',
986 'required' => true
987 ),
988 array(
989 'type' => 'text',
990 'label' => $this->l('TEST Token'),
991 'name' => self::CONFIG_TEST_TOKEN,
992 'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
993 'class' => 'test-field',
994 'required' => true
995 ),
996 array(
997 'type' => 'text',
998 'label' => $this->l('LIVE URL'),
999 'name' => self::CONFIG_LIVE_URL,
1000 'placeholder' => 'https://api.nubefact.com/api/v1/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
1001 'class' => 'live-field',
1002 'required' => true
1003 ),
1004 array(
1005 'type' => 'text',
1006 'label' => $this->l('LIVE Token'),
1007 'name' => self::CONFIG_LIVE_TOKEN,
1008 'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
1009 'class' => 'live-field',
1010 'required' => true
1011 )
1012 ),
1013 'submit' => array(
1014 'title' => $this->l('Save')
1015 )
1016 )
1017 );
1018
1019 $business_data_form = array(
1020 'form' => array(
1021 'legend' => array(
1022 'title' => $this->l('Business data'),
1023 'icon' => 'icon-wrench'
1024 ),
1025 'input' => array(
1026 array(
1027 'type' => 'text',
1028 'label' => $this->l('RUC'),
1029 'name' => self::CONFIG_BUSINESS_RUC,
1030 'placeholder' => '20xxxxxxxxx',
1031 'class' => 'fixed-width-xxl',
1032 'required' => true
1033 ),
1034 array(
1035 'type' => 'text',
1036 'label' => $this->l('Business name'),
1037 'name' => self::CONFIG_BUSINESS_NAME,
1038 'placeholder' => 'My little shop',
1039 'required' => true
1040 ),
1041 array(
1042 'type' => 'text',
1043 'label' => $this->l('Business address'),
1044 'name' => self::CONFIG_BUSINESS_ADDRESS,
1045 'placeholder' => 'Av. xxxxxx #9999',
1046 'required' => true
1047 ),
1048 ),
1049 'submit' => array(
1050 'title' => $this->l('Save')
1051 )
1052 )
1053 );
1054
1055 $general_parameters_form = array(
1056 'form' => array(
1057 'legend' => array(
1058 'title' => $this->l('General parameters'),
1059 'icon' => 'icon-wrench'
1060 ),
1061 'input' => array(
1062 array(
1063 'type' => 'html',
1064 'html_content' => $this->billFields( array(
1065 'prefix' => 'B',
1066 'serie' => array(
1067 'name' => self::CONFIG_RECEIPT_SERIE,
1068 'value' => Configuration::get( self::CONFIG_RECEIPT_SERIE ),
1069 'placeholder' => '001'
1070 ),
1071 'num' => array(
1072 'name' => self::CONFIG_RECEIPT_NUM,
1073 'value' => Configuration::get( self::CONFIG_RECEIPT_NUM ),
1074 'placeholder' => '0001'
1075 )
1076 ) ),
1077 'label' => $this->l('Receipt series'),
1078 'name' => self::CONFIG_RECEIPT_SERIE,
1079 'required' => true
1080 ),
1081 array(
1082 'type' => 'html',
1083 'html_content' => $this->billFields( array(
1084 'prefix' => 'F',
1085 'serie' => array(
1086 'name' => self::CONFIG_INVOICE_SERIE,
1087 'value' => Configuration::get( self::CONFIG_INVOICE_SERIE ),
1088 'placeholder' => '001'
1089 ),
1090 'num' => array(
1091 'name' => self::CONFIG_INVOICE_NUM,
1092 'value' => Configuration::get( self::CONFIG_INVOICE_NUM ),
1093 'placeholder' => '0001'
1094 )
1095 ) ),
1096 'label' => $this->l('Invoice series'),
1097 'name' => self::CONFIG_INVOICE_SERIE,
1098 'required' => true
1099 ),
1100 array(
1101 'type' => 'text',
1102 'label' => $this->l('State Number'),
1103 'name' => self::CONFIG_INVOICE_STATE,
1104 'placeholder' => 'Set the state number id here',
1105 'class' => 'fixed-width-xxl',
1106 'required' => true
1107 ),
1108 array(
1109 'type' => 'text',
1110 'label' => $this->l('Sunat Product Code'),
1111 'name' => self::CONFIG_INVOICE_SUNAT_CODE,
1112 'placeholder' => 'Set the sunat product code here',
1113 'class' => 'fixed-width-xxl',
1114 'required' => true
1115 ),
1116 array(
1117 'type' => 'text',
1118 'label' => $this->l('API Name'),
1119 'name' => self::CONFIG_API_APPNAME,
1120 'placeholder' => 'Api name for invoice number consecutive',
1121 'class' => 'fixed-width-xxl',
1122 'required' => true
1123 ),
1124 array(
1125 'type' => 'text',
1126 'label' => $this->l('Billing Name'),
1127 'name' => self::CONFIG_API_FE_BILLING_NAME,
1128 'placeholder' => 'Ej: FARMALATAM',
1129 'class' => 'fixed-width-xxl',
1130 'required' => true
1131 ),
1132 array(
1133 'type' => 'text',
1134 'label' => $this->l('API Token'),
1135 'name' => self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE,
1136 'placeholder' => '',
1137 'class' => 'fixed-width-xxl',
1138 'required' => true
1139 ),
1140 array(
1141 'type' => 'text',
1142 'label' => $this->l('URL API'),
1143 'name' => self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE,
1144 'placeholder' => '',
1145 'class' => 'fixed-width-xxl',
1146 'required' => true
1147 ),
1148 array(
1149 'type' => 'text',
1150 'label' => $this->l('Factura Suffix'),
1151 'name' => self::CONFIG_FE_F_SUFFIX,
1152 'placeholder' => '',
1153 'class' => 'fixed-width-xxl',
1154 'required' => true
1155 ),
1156 array(
1157 'type' => 'text',
1158 'label' => $this->l('Boleta Suffix'),
1159 'name' => self::CONFIG_FE_B_SUFFIX,
1160 'placeholder' => '',
1161 'class' => 'fixed-width-xxl',
1162 'required' => true
1163 ),
1164
1165
1166 ),
1167 'submit' => array(
1168 'title' => $this->l('Save')
1169 )
1170 )
1171 );
1172
1173 $sendManualInvoice = array(
1174 // Send manually data
1175 'form' => array(
1176 'legend' => array(
1177 'title' => $this->l('Send Manual Invoice'),
1178 'icon' => 'icon-terminal',
1179 ),
1180 'input' => array(
1181 array(
1182 'col' => 3,
1183 'type' => 'text',
1184 'prefix' => '<i class="icon icon-gears"></i>',
1185 'desc' => $this->l('Enter order id'),
1186 'name' => 'VEX_GET_ID_ORDER',
1187 'label' => $this->l('Order ID'),
1188 ),
1189 array(
1190 'col' => 9,
1191 'type' => 'date',
1192 'prefix' => '<i class="icon icon-calendar"></i>',
1193 'desc' => $this->l('Enter invoice date'),
1194 'name' => 'VEX_SET_DATE_INVOICE',
1195 'label' => $this->l('Invoice Date'),
1196 ),
1197 ),
1198 'submit' => array(
1199 'title' => $this->l('Send'),
1200 ),
1201 ),
1202 );
1203
1204 return array( $testmode_form, $credentials_form, $business_data_form, $general_parameters_form, $sendManualInvoice );
1205 }
1206
1207 private function billFields( $params ){
1208 $serie_value = isset($params['serie']['value']) ? $params['serie']['value'] : '';
1209 $num_value = isset($params['num']['value']) ? $params['num']['value'] : '';
1210
1211 return <<<EOF
1212<div class="form-inline">
1213 <div class="form-group">
1214 <div class="input-group">
1215 <div class="input-group-addon">{$params['prefix']}</div>
1216 <input type="text" class="form-control" name="{$params['serie']['name']}" id="{$params['serie']['name']}" value="{$serie_value}" placeholder="{$params['serie']['placeholder']}">
1217 </div>
1218 </div>
1219 <div class="form-group hidden-xs"> - </div>
1220 <div class="form-group">
1221 <input type="text" class="form-control" name="{$params['num']['name']}" id="{$params['num']['name']}" value="{$num_value}" placeholder="{$params['num']['placeholder']}">
1222 </div>
1223</div>
1224EOF;
1225 }
1226
1227 // methods
1228 public function is_test_mode(){
1229 return '0' == Configuration::get( self::CONFIG_LIVEMODE, null, null, null, '0' );
1230 }
1231
1232 public function get_url(){
1233 if( $this->is_test_mode() ){
1234 return Configuration::get( self::CONFIG_TEST_URL, null, null, null, '' );
1235 } else {
1236 return Configuration::get( self::CONFIG_LIVE_URL, null, null, null, '' );
1237 }
1238 }
1239
1240 public function get_token(){
1241 if( $this->is_test_mode() ){
1242 return Configuration::get( self::CONFIG_TEST_TOKEN, null, null, null, '' );
1243 } else {
1244 return Configuration::get( self::CONFIG_LIVE_TOKEN, null, null, null, '' );
1245 }
1246 }
1247
1248 public function get_percent_igv(){
1249 return '18.00';
1250 // return Configuration::get( self::CONFIG_TEST_TOKEN, null, null, null, '' );
1251 }
1252
1253 private function getFeaturesProductOrder($id_otrder = 0)
1254 {
1255 $return = array();
1256 $query = new DbQuery();
1257 $query->select('psfp.id_product, psfl.name, psfv.value');
1258 $query->from('feature_product', 'psfp');
1259 $query->join('INNER JOIN`' . _DB_PREFIX_ . 'feature_lang` psfl ON psfl.`id_feature` = psfp.`id_feature` AND psfl.`name` = "codigo_producto_sunat"');
1260 $query->join('INNER JOIN`' . _DB_PREFIX_ . 'feature_value_lang` psfv ON psfv.`id_feature_value` = psfp.`id_feature_value`');
1261 $query->join('INNER JOIN`' . _DB_PREFIX_ . 'order_detail` psod ON psfp.`id_product` = psod.`product_id`');
1262 $query->where('psod.`id_order` = "' . (int) $id_otrder . '"');
1263 $query->groupBy('psfl.name');
1264
1265 if ($result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query)) {
1266
1267 foreach ($result as $value) {
1268 $return[$value['id_product']] = $value;
1269 unset($return[$value['id_product']]['id_product']);
1270 }
1271 }
1272 return $return;
1273 }
1274
1275 public function hookActionObjectCustomerAddAfter($params)
1276 {
1277 $customer = $params['object'];
1278 self::updateDataInvoice($customer);
1279 }
1280
1281 public function hookActionCustomerAccountUpdate($params)
1282 {
1283
1284 }
1285
1286 public function hookActionDispatcherBefore()
1287 {
1288 // error_log('<< hookActionDispatcherBefore >>');
1289 }
1290
1291 public function hookDisplayAdminCustomersForm($params)
1292 {
1293 $this->context->controller->addJS($this->_path . '/views/js/backoffice.js');
1294
1295 // https://api.sunat.cloud/ruc/10403322097
1296 // https://cors-anywhere.herokuapp.com/wmtechnology.org/Consultar-RUC/?modo=1&btnBuscar=Buscar&nruc=10403322097
1297 $this->getDataInvoiceForm();
1298 return $this->display(__FILE__, 'views/templates/hook/customer_invoice.tpl');
1299 }
1300
1301 private function getDataInvoiceForm()
1302 {
1303
1304 // load saved values
1305 $values = array();
1306 $id_customer = (int) (! empty($this->context->customer->id) ? $this->context->customer->id : Tools::getValue('id_customer'));
1307
1308 if (! empty($id_customer) && $nubeFactCustomer = Vex_Nubefact_Customer::getByCustomerId($id_customer)) {
1309 $values = $nubeFactCustomer;
1310 unset($values['date_add'], $values['cart_id'], $values['customer_id'], $values['id']);
1311 }
1312
1313 $staticData = array(
1314 'tiposDeComprobantes' => array(
1315 '1' => 'Factura',
1316 '2' => 'Boleta'
1317 ),
1318 'tiposDeDocumentosCliente' => array(
1319 '1' => 'DNI',
1320 '4' => 'Carnet de extranjeria',
1321 // '6' => 'RUC',
1322 '7' => 'Pasaporte'
1323 ),
1324 'tipo_de_comprobante' => '',
1325 'cliente_tipo_de_documento' => '',
1326 'cliente_numero_de_documento' => '',
1327 'cliente_denominacion' => '',
1328 'cliente_direccion' => ''
1329 );
1330
1331 $data = array_merge($staticData, $values);
1332
1333 $this->context->smarty->assign($data);
1334 }
1335
1336 public static function updateDataInvoice($customer = null)
1337 {
1338 $tipo_de_comprobante = pSQL(Tools::getValue('tipo_comprobante'));
1339
1340 if ($tipo_de_comprobante == Vex_Nubefact::TIPOCOMPROBANTE_FACTURA) {
1341 $tipo_documento_cliente = Vex_Nubefact::TIPODOCUMENTO_RUC;
1342 } else {
1343 $tipo_documento_cliente = pSQL(Tools::getValue('tipo_de_documento_cliente'));
1344 }
1345
1346 $context = Context::getContext();
1347
1348 if (empty($customer))
1349 $customer = $context->customer;
1350
1351 $tipo_de_comprobante = $tipo_documento_cliente == 6 ? 1 : 2;
1352
1353 $data = array(
1354 'customer_id' => (int) $customer->id,
1355 'cart_id' => (int) $context->cart->id,
1356 'tipo_de_comprobante' => $tipo_de_comprobante,
1357 'cliente_tipo_de_documento' => $tipo_documento_cliente,
1358 'cliente_numero_de_documento' => pSQL(Tools::getValue('numero_documento')),
1359 'cliente_denominacion' => pSQL(Tools::getValue('cliente_denominacion')),
1360 'cliente_direccion' => pSQL(Tools::getValue('domicilio_facturacion'))
1361 );
1362
1363 $nubeFactCustomerId = 0;
1364 if ($nubeFactCustomer = Vex_Nubefact_Customer::getByCustomerId($data['customer_id'])) {
1365 $nubeFactCustomerId = $nubeFactCustomer['id'];
1366 }
1367
1368 $nubeFactCustomer = new Vex_Nubefact_Customer($nubeFactCustomerId);
1369
1370 $nubeFactCustomer->customer_id = (int) $customer->id;
1371 $nubeFactCustomer->cart_id = (int) $context->cart->id;
1372 $nubeFactCustomer->tipo_de_comprobante = (string) $tipo_de_comprobante;
1373 $nubeFactCustomer->cliente_tipo_de_documento = (string) $tipo_documento_cliente;
1374 $nubeFactCustomer->cliente_numero_de_documento = pSQL(Tools::getValue('numero_documento'));
1375 $nubeFactCustomer->cliente_denominacion = pSQL(Tools::getValue('cliente_denominacion'));
1376 $nubeFactCustomer->cliente_direccion = pSQL(Tools::getValue('domicilio_facturacion'));
1377
1378 try {
1379 return $nubeFactCustomer->save();
1380 } catch (Exception $e) {
1381 error_log('"vex_nubefact" mssage: ' . $e->getMessage());
1382 return false;
1383 }
1384 }
1385
1386 /**
1387 * Function for send data manually
1388 * getting id_order.
1389 */
1390 public function sendDataManually($id_order)
1391 {
1392 self::logtxt("Entro a: sendDataManually");
1393 $stateID = trim(Configuration::get( self::CONFIG_INVOICE_STATE ));
1394
1395 // value if state changed is equal to (CONFIG_INVOICE_STATE)
1396 $order = new Order($id_order);
1397 if($order->current_state == $stateID) {
1398
1399 $customer_id = $order->id_customer;
1400 $id_cart = $order->id_cart;
1401
1402 // evalua si es gratuita o no
1403 if($order->total_paid_tax_incl == 0){
1404 $incluido_impuestos = 0; // total incluido impuesto
1405 $sin_impuestos = 0; // total sin impuesto
1406 }else{
1407 // $incluido_impuestos = $order->total_products_wt; // total incluido impuesto
1408 // $sin_impuestos = $order->total_products; // total sin impuesto
1409 $incluido_impuestos = $order->total_paid_tax_incl; // total incluido impuesto
1410 $sin_impuestos = $order->total_paid_tax_excl; // total sin impuesto
1411 }
1412
1413 $totalGratis = 0;
1414 $sumaDescuentoItems = 0;
1415 // load saved values
1416 // $nubeFactValues = array();
1417 if( $nubeFactCustomer = Vex_Nubefact_Customer::getByCustomerId( $customer_id ) ) {
1418 // $nubeFactValues = $nubeFactCustomer;
1419 // unset( $nubeFactValues['date_add'], $nubeFactValues['cart_id'] );
1420 // unset( $nubeFactValues['customer_id'], $nubeFactValues['id'] );
1421 $customer = new Customer($customer_id);
1422
1423 $url = $this->get_url();
1424 $token = $this->get_token();
1425
1426 $nubeFact = new Vex_PrestaShop_NubeFact( $url, $token );
1427
1428 if( $nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA ){
1429 require_once dirname( __FILE__ ) . '/classes/NubeFact/FacturaElectronica.php';
1430 $document = new Vex_FacturaElectronica();
1431
1432 $serie = 'F' . Configuration::get( self::CONFIG_INVOICE_SERIE );
1433 // $numero = Configuration::get( self::CONFIG_INVOICE_NUM );
1434
1435 // consulta consecutivo en api
1436 $AutoIncrementInvoice = new stdClass();
1437 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
1438 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
1439 $AutoIncrementInvoice->idCart = $id_cart;
1440 $AutoIncrementInvoice->idOrder = $id_order;
1441 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
1442 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_F_SUFFIX);
1443 $AutoIncrementInvoice->production = true;
1444
1445 $data_string = json_encode($AutoIncrementInvoice);
1446
1447 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
1448 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
1449 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
1450 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1451 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
1452 'Content-Type: application/json',
1453 'Content-Length: ' . strlen($data_string)
1454 ));
1455
1456 $response = curl_exec($ch);
1457
1458 $responseArray = json_decode($response, true);
1459 $numero = $responseArray['invoiceNumber'];
1460
1461 } else {
1462 require_once dirname( __FILE__ ) . '/classes/NubeFact/BoletaElectronica.php';
1463 $document = new Vex_BoletaElectronica();
1464
1465 $serie = 'B' . Configuration::get( self::CONFIG_RECEIPT_SERIE );
1466 // $numero = Configuration::get( self::CONFIG_RECEIPT_NUM );
1467
1468 // consulta consecutivo en api
1469 $AutoIncrementInvoice = new stdClass();
1470 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
1471 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
1472 $AutoIncrementInvoice->idCart = $id_cart;
1473 $AutoIncrementInvoice->idOrder = $id_order;
1474 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
1475 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_B_SUFFIX);
1476 $AutoIncrementInvoice->production = true;
1477
1478 $data_string = json_encode($AutoIncrementInvoice);
1479
1480 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
1481 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
1482 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
1483 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1484 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
1485 'Content-Type: application/json',
1486 'Content-Length: ' . strlen($data_string)
1487 ));
1488
1489 $response = curl_exec($ch);
1490
1491 $responseArray = json_decode($response, true);
1492 $numero = $responseArray['invoiceNumber'];
1493 }
1494
1495 $document->setSunatEnvioAutomatico( true );
1496 $document->setSerie( $serie );
1497 $document->setNumero( $numero );
1498
1499 $document->setCliente( array(
1500 'cliente_tipo_de_documento' => $nubeFactCustomer['cliente_tipo_de_documento'],
1501 'cliente_numero_de_documento' => trim($nubeFactCustomer['cliente_numero_de_documento']),
1502 'cliente_denominacion' => $nubeFactCustomer['cliente_denominacion'],
1503 'cliente_direccion' => $nubeFactCustomer['cliente_direccion']
1504 ) );
1505
1506 $document->addClienteEmail( $customer->email );
1507
1508 // $currency = new Currency($order->id_currency);
1509 // $currencies = array(
1510 // 'PEN' => Vex_DocumentContract::$SOL,
1511 // 'USD' => Vex_DocumentContract::$DOLAR,
1512 // 'EUR' => Vex_DocumentContract::$EURO,
1513 // );
1514
1515 // var_export( [$currency, $nubeFactCustomer] );
1516
1517
1518 // $document->setMoneda( $currencies[ $currency->iso_code ] );
1519
1520 // $document->setTipoCambio();
1521 $document->setPorcentajeIGV( $this->get_percent_igv() );
1522 $document->setTotal( $incluido_impuestos );
1523 // $document->setDetraccion();
1524 // $document->setObservaciones();
1525
1526 $features = $this->getFeaturesProductOrder($order->id);
1527
1528 $giftFlag = false;
1529 $dproductFlag = false;
1530 $totalInafecta = 0;
1531
1532 foreach ( $order->getProducts() as $productDetail ) {
1533 $TotalConImpuesto = $productDetail['total_price_tax_incl'];
1534 $TotalSinImpuesto = $productDetail['total_price_tax_excl'];
1535 $discounts = $productDetail['reduction_percent'];
1536 $discountAmount = $productDetail['reduction_amount_tax_excl'];
1537 $valorUnitario = $productDetail['original_product_price'];
1538 $includeTax = $productDetail['id_tax_rules_group'];
1539 $impuestoUnitario = ($valorUnitario * (int) $this->get_percent_igv()) / 100;
1540 $precioUnitario = round($valorUnitario + $impuestoUnitario, 2);
1541 $tipoIGV = '1';
1542 $IGV = $TotalConImpuesto - $TotalSinImpuesto;
1543 $total = $TotalConImpuesto;
1544 $descuento = 0;
1545 $subtotal = ($valorUnitario * $productDetail['product_quantity']) - $descuento;
1546
1547
1548 // evalua si el producto es inafecto
1549 if($includeTax == 0){
1550 self::logtxt("Producto Inafecto de IGV");
1551 $precioUnitario = $valorUnitario;
1552 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
1553 $tipoIGV = '9';
1554 $IGV = 0;
1555 $total = $subtotal;
1556 $totalInafecta += $total;
1557 $dproductFlag = true;
1558
1559 // descuento por producto
1560 if($discounts > 0) {
1561 self::logtxt("Descuento por producto! - Percent");
1562 $descuento = ($valorUnitario * $discounts / 100);
1563 $sumaDescuentoItems += $descuento;
1564 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
1565 $total = $subtotal;
1566 $totalInafecta += $total;
1567
1568 if($discounts == 100) {
1569 // Si el producto es gratuito
1570 self::logtxt("Producto gratuito");
1571 $giftFlag = true;
1572 $precioUnitario = $valorUnitario;
1573 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
1574 $tipoIGV = '9';
1575 $IGV = 0;
1576 $total = $subtotal;
1577 $totalGratis += $subtotal;
1578 $descuento = 0;
1579 $totalInafecta += $total;
1580 }
1581
1582 }elseif($discountAmount > 0){
1583 self::logtxt("Descuento por producto! - Amount");
1584 $descuento = $discountAmount;
1585 $sumaDescuentoItems += $discountAmount;
1586 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
1587 $total = $subtotal;
1588 $totalInafecta += $total;
1589 $dproductFlag = true;
1590
1591 }
1592
1593 }else{
1594 self::logtxt("Producto Con IGV");
1595
1596 // descuento por producto
1597 if($discounts > 0) {
1598 self::logtxt("Descuento por producto! - Percent");
1599 $descuento = ($valorUnitario * $discounts / 100);
1600 $sumaDescuentoItems += $descuento;
1601 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
1602 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
1603 $dproductFlag = true;
1604
1605 if($discounts == 100) {
1606 // Si el producto es gratuito
1607 self::logtxt("Producto gratuito");
1608 $giftFlag = true;
1609 $precioUnitario = $valorUnitario;
1610 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
1611 $tipoIGV = '6';
1612 $IGV = 0;
1613 $total = $subtotal;
1614 $totalGratis += $subtotal;
1615 $descuento = 0;
1616 }
1617
1618 }elseif($discountAmount > 0){
1619 self::logtxt("Descuento por producto! - Amount");
1620 $descuento = $discountAmount;
1621 $sumaDescuentoItems += $discountAmount;
1622 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
1623 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
1624 $dproductFlag = true;
1625
1626 }
1627
1628 }//fin producto es inafecto de IGV
1629
1630 if(!empty($features[$productDetail['product_id']]['value']))
1631 $codigo_producto_sunat = $features[$productDetail['product_id']]['value'];
1632 else
1633 $codigo_producto_sunat = Configuration::get( self::CONFIG_INVOICE_SUNAT_CODE );
1634
1635
1636 // evalua si es gratuito o no
1637 if($order->total_paid_tax_incl == 0){
1638 $precioUnitario = $valorUnitario;
1639 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
1640 $totalGratis += $subtotal;
1641 $tipoIGV = '6';
1642 $IGV = 0;
1643 $total = $subtotal;
1644 }
1645
1646 $document->addItem( array(
1647 'unidad_de_medida' => 'NIU',
1648 'codigo' => $productDetail['product_id'],
1649 'descripcion' => $productDetail['product_name'],
1650 'cantidad' => $productDetail['product_quantity'],
1651 'valor_unitario' => $valorUnitario, // unitario sin impuesto
1652 'precio_unitario' => $precioUnitario, // unitario con impuesto
1653 'descuento' => $descuento,
1654 'subtotal' => $subtotal,
1655 'tipo_de_igv' => $tipoIGV,
1656 'igv' => $IGV,
1657 'total' => $total,
1658 'anticipo_regularizacion' => 'false',
1659 'anticipo_documento_serie' => '',
1660 'anticipo_documento_numero' => '',
1661 'codigo_producto_sunat' => $codigo_producto_sunat //Fórmulas y productos para apoyo nutritivo
1662 ) );
1663 }
1664
1665 // transporte
1666 $shipping_sin_impuestos = $order->total_shipping_tax_excl; // total transporte sin impuesto
1667 $shipping_con_impuestos = $order->total_shipping_tax_incl; // total transporte sin impuesto
1668 $precioUnitario = round($shipping_con_impuestos, 2);
1669 $tipoIGV = '1';
1670 $IGV = $shipping_con_impuestos - $shipping_sin_impuestos;
1671 $total = $shipping_con_impuestos;
1672 if ($shipping_sin_impuestos > 0) {
1673 // evalua si es gratuito o no
1674 if($order->total_paid_tax_incl == 0){
1675 $precioUnitario = $shipping_sin_impuestos;
1676 $tipoIGV = '6';
1677 $IGV = 0;
1678 $total = $shipping_sin_impuestos;
1679 }
1680
1681 $document->addItem( array(
1682 'unidad_de_medida' => 'ZZ',
1683 'codigo' => '001',
1684 'descripcion' => 'Costo de envío',
1685 'cantidad' => '1',
1686 'valor_unitario' => $shipping_sin_impuestos, // unitario sin impuesto
1687 'precio_unitario' => $precioUnitario, // unitario con impuesto
1688 'descuento' => '',
1689 'subtotal' => $shipping_sin_impuestos,
1690 'tipo_de_igv' => $tipoIGV,
1691 'igv' => $IGV,
1692 'total' => $total,
1693 'anticipo_regularizacion' => 'false',
1694 'anticipo_documento_serie' => '',
1695 'anticipo_documento_numero' => '',
1696 'codigo_producto_sunat' => '78140000' //Servicios de transporte
1697 ) );
1698 }
1699
1700 // $document->setCodigoUnico();
1701
1702 // var_export( $document->getArray() );
1703
1704 // descuento general
1705 $total_descuentos = 0;
1706 $descuento_general = 0;
1707 if($order->total_discounts > 0){
1708 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
1709 }
1710 $total_descuentos = $descuento_general + $sumaDescuentoItems;
1711
1712 // si hay descuento general y por item
1713 if($order->total_discounts > 0 && $dproductFlag == true){
1714 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
1715 $total_descuentos = $sumaDescuentoItems;
1716 }
1717 $document->setDescuentoGlobal( $descuento_general );
1718 $document->setTotalDescuento( $total_descuentos );
1719
1720 // si es gratuita o no
1721 if($order->total_paid_tax_incl == 0){
1722 $document->setTotalGratis( $totalGratis );
1723 }
1724
1725 // si existe un producto gratuito
1726 if($giftFlag == true){
1727 $document->setTotalGratis( $totalGratis );
1728 }
1729
1730 // si por configuración no se obtiene la fecha de emisión se toma la actual
1731 if($this->VEX_SET_DATE_INVOICE){
1732 $fechaEmision = $this->VEX_SET_DATE_INVOICE;
1733 $date = date_create($fechaEmision);
1734 $document->setFechaEmision( date_format($date,"d-m-Y") );
1735 }else{
1736 $fechaEmision = date( 'd-m-Y' );
1737 $document->setFechaEmision( $fechaEmision );
1738 }
1739
1740 // Evalua el tipo de documento para saber el tipo de transacción (segun sunat) - By Alekuoshu
1741 if((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 4 || (int) $nubeFactCustomer['cliente_tipo_de_documento'] == 7){
1742 $document->setSunatTransaction( 29 ); // Venta no domiciliados que no califican como exportación
1743 }elseif((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 0){
1744 $document->setSunatTransaction( 2 ); // Exportanción
1745 }else{
1746 $document->setSunatTransaction( 1 ); // Venta Interna
1747 }
1748
1749 // si existe un producto inefacto de IGV
1750 if($totalInafecta > 0){
1751 $document->setTotalInafecta( $totalInafecta );
1752 $total_igv = '';
1753 $document->setTotalIGV( $total_igv );
1754 $tota_gravada = '';
1755 $document->setTotalGravada( $tota_gravada );
1756 }else{
1757 $total_igv = round( $incluido_impuestos - $sin_impuestos, 2 );
1758 $document->setTotalIGV( $total_igv );
1759 $tota_gravada = $sin_impuestos;
1760 $document->setTotalGravada( $tota_gravada );
1761 }
1762
1763 //create invoice
1764 $invoice = new Vex_Nubefact_Invoice();
1765
1766 $invoice->id_customer = $customer->id;
1767 $invoice->id_order = $order->id;
1768 $invoice->tipo_de_comprobante = $nubeFactCustomer['tipo_de_comprobante'];
1769 $invoice->serie = $serie;
1770 $invoice->numero = (int) $numero;
1771 $invoice->cliente_tipo_de_documento = $nubeFactCustomer['cliente_tipo_de_documento'];
1772 $invoice->cliente_numero_de_documento = trim($nubeFactCustomer['cliente_numero_de_documento']);
1773 $invoice->cliente_denominacion = $nubeFactCustomer['cliente_denominacion'];
1774 $invoice->cliente_direccion = $nubeFactCustomer['cliente_direccion'];
1775 $invoice->cliente_email = $customer->email;
1776 $invoice->fecha_de_emision = $fechaEmision;
1777 $invoice->moneda = 1;
1778 $invoice->porcentaje_de_igv = $this->get_percent_igv();
1779 $invoice->descuento_global = $descuento_general;
1780 $invoice->total_descuento = $total_descuentos;
1781 $invoice->total_gravada = $tota_gravada;
1782 $invoice->total_igv = $total_igv;
1783 $invoice->total_gratuita = $totalGratis;
1784 $invoice->total = $incluido_impuestos;
1785
1786 // Get json for sent to log
1787 $jsonEnviado = json_encode($document->getArray());
1788 self::logtxt("Json_enviado: ".$jsonEnviado);
1789
1790
1791 // validar que no existe ya la factura en nubefact y no este aceptada a la sunat
1792 $query = new DbQuery();
1793 $query->select('*');
1794 $query->from('vex_nubefact_invoice');
1795 $query->where('id_order = "'.$order->id.'" AND sunat_estado = 1');
1796 $valueR = Db::getInstance()->executeS($query);
1797
1798 // si no existe en el registro la factura se envia a nubefact
1799 if(empty($valueR)){
1800 if( $response = $nubeFact->sendDocument( $document ) ){
1801 // incrementar numero
1802 // if( $nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA ){
1803 // Configuration::updateValue( self::CONFIG_INVOICE_NUM, $numero+1 );
1804 // } else {
1805 // Configuration::updateValue( self::CONFIG_RECEIPT_NUM, $numero+1 );
1806 // }
1807
1808 $data = @json_decode( $response );
1809
1810 // guardar pdf url
1811 $invoice->url_pdf = $data->enlace_del_pdf;
1812 // respuesta sunat
1813 $sunat = $data->aceptada_por_sunat;
1814 if($sunat === true){
1815 $invoice->sunat_estado = '1';
1816 $invoice->sunat_respuesta_envio = $data->sunat_description;
1817
1818 // Insertamos data en ps_vex_invoices_sent tabla
1819 $result = Db::getInstance()->insert('vex_invoices_sent', array(
1820 'id_order' => $id_order,
1821 'date_add' => date("Y-m-d H:i:s"),
1822 ));
1823 $error = Db::getInstance()->getMsgError();
1824
1825 if ($result == true) {
1826 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
1827 } else {
1828 if ($error != '') {
1829 self::logtxt($error);
1830 }
1831 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
1832 }
1833
1834 }else{
1835 $invoice->sunat_estado = '0';
1836 $invoice->sunat_respuesta_envio = $data->sunat_description;
1837
1838 // Insertamos data en ps_vex_invoices_sent tabla
1839 $result = Db::getInstance()->insert('vex_invoices_sent', array(
1840 'id_order' => $id_order,
1841 'date_add' => date("Y-m-d H:i:s"),
1842 ));
1843 $error = Db::getInstance()->getMsgError();
1844
1845 if ($result == true) {
1846 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
1847 } else {
1848 if ($error != '') {
1849 self::logtxt($error);
1850 }
1851 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
1852 }
1853
1854 }
1855 } else {
1856 // var_export( [ $nubeFact->getClient(), $document->getArray() ] );
1857 // exit();
1858 }
1859
1860 $invoice->wp_data = $nubeFact->getClient()->response;
1861 $invoice->add();
1862 }
1863
1864 }
1865 // $customer = new Customer($customer_id);
1866
1867 // $clientParams = array(
1868 // 'cliente_email' => $customer->email,
1869 // 'cliente_tipo_de_documento' => '',
1870 // 'cliente_numero_de_documento' => '',
1871 // 'cliente_denominacion' => '',
1872 // 'cliente_direccion' => ''
1873 // );
1874
1875 // $clientParams = array_merge( $clientParams, $nubeFactValues );
1876
1877 // var_export( [$params['id_order'], $order->id] );
1878 // exit();
1879
1880 }//fin cambio de estado
1881 }
1882
1883
1884 /**
1885 * Function for send masive invoices
1886 * getting id_order.
1887 */
1888 public function sendMasiveInvoices()
1889 {
1890 $key = 'sendInvoice@2020';
1891 // set by post: date like 2020-07
1892 // Example: curl -s 'https://tienda.ensure.abbott/pe?k=sendInvoice@2020&date=2020-07' > /dev/null
1893 // curl --silent --output /dev/null http://example.com
1894
1895 $date = Tools::getValue('date');
1896
1897 if (Tools::getValue('k') == $key) {
1898
1899 self::logtxt("---- Envio masivo de Facturas ----");
1900 self::logtxt("---- Fecha insertada: $date ----");
1901
1902 // get orders ids
1903 $sql = new DbQuery();
1904 $sql->select('*');
1905 $sql->from('orders', 'A');
1906 $sql->where('A.current_state = 5 AND A.date_add >= "'.$date.'-01 00:00:00" AND A.date_add <= "'.$date.'-31 23:59:59" AND NOT EXISTS (SELECT id_order FROM ps_vex_invoices_sent WHERE id_order = A.id_order)');
1907
1908 $resOrders = Db::getInstance()->executeS($sql);
1909
1910 // if results
1911 if (!empty($resOrders)) {
1912 $numData = count($resOrders);
1913 self::logtxt("sendMasiveInvoices: Hay ".$numData." registros para enviar!");
1914
1915 // iterate all id orders that we need
1916 foreach ($resOrders as $key => $Order) {
1917
1918 // get values request
1919 $id_order = $Order['id_order'];
1920 self::logtxt("id_order: $id_order");
1921
1922 $stateID = trim(Configuration::get( self::CONFIG_INVOICE_STATE ));
1923
1924 // value if state changed is equal to (CONFIG_INVOICE_STATE)
1925 $order = new Order($id_order);
1926 if($order->current_state == $stateID) {
1927
1928 $customer_id = $order->id_customer;
1929 $id_cart = $order->id_cart;
1930
1931 // evalua si es gratuita o no
1932 if($order->total_paid_tax_incl == 0){
1933 $incluido_impuestos = 0; // total incluido impuesto
1934 $sin_impuestos = 0; // total sin impuesto
1935 }else{
1936 // $incluido_impuestos = $order->total_products_wt; // total incluido impuesto
1937 // $sin_impuestos = $order->total_products; // total sin impuesto
1938 $incluido_impuestos = $order->total_paid_tax_incl; // total incluido impuesto
1939 $sin_impuestos = $order->total_paid_tax_excl; // total sin impuesto
1940 }
1941
1942 $totalGratis = 0;
1943 $sumaDescuentoItems = 0;
1944 // load saved values
1945 // $nubeFactValues = array();
1946 if( $nubeFactCustomer = Vex_Nubefact_Customer::getByCustomerId( $customer_id ) ) {
1947 // $nubeFactValues = $nubeFactCustomer;
1948 // unset( $nubeFactValues['date_add'], $nubeFactValues['cart_id'] );
1949 // unset( $nubeFactValues['customer_id'], $nubeFactValues['id'] );
1950 $customer = new Customer($customer_id);
1951
1952 $url = $this->get_url();
1953 $token = $this->get_token();
1954
1955 $nubeFact = new Vex_PrestaShop_NubeFact( $url, $token );
1956
1957 if( $nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA ){
1958 require_once dirname( __FILE__ ) . '/classes/NubeFact/FacturaElectronica.php';
1959 $document = new Vex_FacturaElectronica();
1960
1961 $serie = 'F' . Configuration::get( self::CONFIG_INVOICE_SERIE );
1962 // $numero = Configuration::get( self::CONFIG_INVOICE_NUM );
1963
1964 // consulta consecutivo en api
1965 $AutoIncrementInvoice = new stdClass();
1966 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
1967 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
1968 $AutoIncrementInvoice->idCart = $id_cart;
1969 $AutoIncrementInvoice->idOrder = $id_order;
1970 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
1971 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_F_SUFFIX);
1972 $AutoIncrementInvoice->production = true;
1973
1974 $data_string = json_encode($AutoIncrementInvoice);
1975
1976 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
1977 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
1978 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
1979 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1980 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
1981 'Content-Type: application/json',
1982 'Content-Length: ' . strlen($data_string)
1983 ));
1984
1985 $response = curl_exec($ch);
1986
1987 $responseArray = json_decode($response, true);
1988 $numero = $responseArray['invoiceNumber'];
1989
1990 } else {
1991 require_once dirname( __FILE__ ) . '/classes/NubeFact/BoletaElectronica.php';
1992 $document = new Vex_BoletaElectronica();
1993
1994 $serie = 'B' . Configuration::get( self::CONFIG_RECEIPT_SERIE );
1995 // $numero = Configuration::get( self::CONFIG_RECEIPT_NUM );
1996
1997 // consulta consecutivo en api
1998 $AutoIncrementInvoice = new stdClass();
1999 $AutoIncrementInvoice->aplicationName = Configuration::get(self::CONFIG_API_APPNAME);
2000 $AutoIncrementInvoice->billingName = Configuration::get(self::CONFIG_API_FE_BILLING_NAME);
2001 $AutoIncrementInvoice->idCart = $id_cart;
2002 $AutoIncrementInvoice->idOrder = $id_order;
2003 $AutoIncrementInvoice->token = Configuration::get(self::CONFIG_FE_TOKEN_AUTO_INCREMENT_INVOICE);
2004 $AutoIncrementInvoice->suffix = Configuration::get(self::CONFIG_FE_B_SUFFIX);
2005 $AutoIncrementInvoice->production = true;
2006
2007 $data_string = json_encode($AutoIncrementInvoice);
2008
2009 $ch = curl_init(Configuration::get(self::CONFIG_FE_URL_AUTO_INCREMENT_INVOICE));
2010 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
2011 curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
2012 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
2013 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
2014 'Content-Type: application/json',
2015 'Content-Length: ' . strlen($data_string)
2016 ));
2017
2018 $response = curl_exec($ch);
2019
2020 $responseArray = json_decode($response, true);
2021 $numero = $responseArray['invoiceNumber'];
2022 }
2023
2024 $document->setSunatEnvioAutomatico( true );
2025 $document->setSerie( $serie );
2026 $document->setNumero( $numero );
2027
2028 $document->setCliente( array(
2029 'cliente_tipo_de_documento' => $nubeFactCustomer['cliente_tipo_de_documento'],
2030 'cliente_numero_de_documento' => trim($nubeFactCustomer['cliente_numero_de_documento']),
2031 'cliente_denominacion' => $nubeFactCustomer['cliente_denominacion'],
2032 'cliente_direccion' => $nubeFactCustomer['cliente_direccion']
2033 ) );
2034
2035 $document->addClienteEmail( $customer->email );
2036
2037 // $currency = new Currency($order->id_currency);
2038 // $currencies = array(
2039 // 'PEN' => Vex_DocumentContract::$SOL,
2040 // 'USD' => Vex_DocumentContract::$DOLAR,
2041 // 'EUR' => Vex_DocumentContract::$EURO,
2042 // );
2043
2044 // var_export( [$currency, $nubeFactCustomer] );
2045
2046
2047 // $document->setMoneda( $currencies[ $currency->iso_code ] );
2048
2049 // $document->setTipoCambio();
2050 $document->setPorcentajeIGV( $this->get_percent_igv() );
2051 $document->setTotal( $incluido_impuestos );
2052 // $document->setDetraccion();
2053 // $document->setObservaciones();
2054
2055 $features = $this->getFeaturesProductOrder($order->id);
2056
2057 $giftFlag = false;
2058 $dproductFlag = false;
2059 $totalInafecta = 0;
2060
2061 foreach ( $order->getProducts() as $productDetail ) {
2062 $TotalConImpuesto = $productDetail['total_price_tax_incl'];
2063 $TotalSinImpuesto = $productDetail['total_price_tax_excl'];
2064 $discounts = $productDetail['reduction_percent'];
2065 $discountAmount = $productDetail['reduction_amount_tax_excl'];
2066 $valorUnitario = $productDetail['original_product_price'];
2067 $includeTax = $productDetail['id_tax_rules_group'];
2068 $impuestoUnitario = ($valorUnitario * (int) $this->get_percent_igv()) / 100;
2069 $precioUnitario = round($valorUnitario + $impuestoUnitario, 2);
2070 $tipoIGV = '1';
2071 $IGV = $TotalConImpuesto - $TotalSinImpuesto;
2072 $total = $TotalConImpuesto;
2073 $descuento = 0;
2074 $subtotal = ($valorUnitario * $productDetail['product_quantity']) - $descuento;
2075
2076
2077 // evalua si el producto es inafecto
2078 if($includeTax == 0){
2079 self::logtxt("Producto Inafecto de IGV");
2080 $precioUnitario = $valorUnitario;
2081 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
2082 $tipoIGV = '9';
2083 $IGV = 0;
2084 $total = $subtotal;
2085 $totalInafecta += $total;
2086 $dproductFlag = true;
2087
2088 // descuento por producto
2089 if($discounts > 0) {
2090 self::logtxt("Descuento por producto! - Percent");
2091 $descuento = ($valorUnitario * $discounts / 100);
2092 $sumaDescuentoItems += $descuento;
2093 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
2094 $total = $subtotal;
2095 $totalInafecta += $total;
2096
2097 if($discounts == 100) {
2098 // Si el producto es gratuito
2099 self::logtxt("Producto gratuito");
2100 $giftFlag = true;
2101 $precioUnitario = $valorUnitario;
2102 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
2103 $tipoIGV = '9';
2104 $IGV = 0;
2105 $total = $subtotal;
2106 $totalGratis += $subtotal;
2107 $descuento = 0;
2108 $totalInafecta += $total;
2109 }
2110
2111 }elseif($discountAmount > 0){
2112 self::logtxt("Descuento por producto! - Amount");
2113 $descuento = $discountAmount;
2114 $sumaDescuentoItems += $discountAmount;
2115 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
2116 $total = $subtotal;
2117 $totalInafecta += $total;
2118 $dproductFlag = true;
2119
2120 }
2121
2122 }else{
2123 self::logtxt("Producto Con IGV");
2124
2125 // descuento por producto
2126 if($discounts > 0) {
2127 self::logtxt("Descuento por producto! - Percent");
2128 $descuento = ($valorUnitario * $discounts / 100);
2129 $sumaDescuentoItems += $descuento;
2130 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
2131 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
2132 $dproductFlag = true;
2133
2134 if($discounts == 100) {
2135 // Si el producto es gratuito
2136 self::logtxt("Producto gratuito");
2137 $giftFlag = true;
2138 $precioUnitario = $valorUnitario;
2139 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
2140 $tipoIGV = '6';
2141 $IGV = 0;
2142 $total = $subtotal;
2143 $totalGratis += $subtotal;
2144 $descuento = 0;
2145 }
2146
2147 }elseif($discountAmount > 0){
2148 self::logtxt("Descuento por producto! - Amount");
2149 $descuento = $discountAmount;
2150 $sumaDescuentoItems += $discountAmount;
2151 $subtotal = ($valorUnitario - $descuento) * ($productDetail['product_quantity']);
2152 $IGV = ($subtotal * (int) $this->get_percent_igv()) / 100;
2153 $dproductFlag = true;
2154
2155 }
2156
2157 }//fin producto es inafecto de IGV
2158
2159 if(!empty($features[$productDetail['product_id']]['value']))
2160 $codigo_producto_sunat = $features[$productDetail['product_id']]['value'];
2161 else
2162 $codigo_producto_sunat = Configuration::get( self::CONFIG_INVOICE_SUNAT_CODE );
2163
2164
2165 // evalua si es gratuito o no
2166 if($order->total_paid_tax_incl == 0){
2167 $precioUnitario = $valorUnitario;
2168 $subtotal = ($valorUnitario * $productDetail['product_quantity']);
2169 $totalGratis += $subtotal;
2170 $tipoIGV = '6';
2171 $IGV = 0;
2172 $total = $subtotal;
2173 }
2174
2175 $document->addItem( array(
2176 'unidad_de_medida' => 'NIU',
2177 'codigo' => $productDetail['product_id'],
2178 'descripcion' => $productDetail['product_name'],
2179 'cantidad' => $productDetail['product_quantity'],
2180 'valor_unitario' => $valorUnitario, // unitario sin impuesto
2181 'precio_unitario' => $precioUnitario, // unitario con impuesto
2182 'descuento' => $descuento,
2183 'subtotal' => $subtotal,
2184 'tipo_de_igv' => $tipoIGV,
2185 'igv' => $IGV,
2186 'total' => $total,
2187 'anticipo_regularizacion' => 'false',
2188 'anticipo_documento_serie' => '',
2189 'anticipo_documento_numero' => '',
2190 'codigo_producto_sunat' => $codigo_producto_sunat //Fórmulas y productos para apoyo nutritivo
2191 ) );
2192 }
2193
2194 // transporte
2195 $shipping_sin_impuestos = $order->total_shipping_tax_excl; // total transporte sin impuesto
2196 $shipping_con_impuestos = $order->total_shipping_tax_incl; // total transporte sin impuesto
2197 $precioUnitario = round($shipping_con_impuestos, 2);
2198 $tipoIGV = '1';
2199 $IGV = $shipping_con_impuestos - $shipping_sin_impuestos;
2200 $total = $shipping_con_impuestos;
2201 if ($shipping_sin_impuestos > 0) {
2202 // evalua si es gratuito o no
2203 if($order->total_paid_tax_incl == 0){
2204 $precioUnitario = $shipping_sin_impuestos;
2205 $tipoIGV = '6';
2206 $IGV = 0;
2207 $total = $shipping_sin_impuestos;
2208 }
2209
2210 $document->addItem( array(
2211 'unidad_de_medida' => 'ZZ',
2212 'codigo' => '001',
2213 'descripcion' => 'Costo de envío',
2214 'cantidad' => '1',
2215 'valor_unitario' => $shipping_sin_impuestos, // unitario sin impuesto
2216 'precio_unitario' => $precioUnitario, // unitario con impuesto
2217 'descuento' => '',
2218 'subtotal' => $shipping_sin_impuestos,
2219 'tipo_de_igv' => $tipoIGV,
2220 'igv' => $IGV,
2221 'total' => $total,
2222 'anticipo_regularizacion' => 'false',
2223 'anticipo_documento_serie' => '',
2224 'anticipo_documento_numero' => '',
2225 'codigo_producto_sunat' => '78140000' //Servicios de transporte
2226 ) );
2227 }
2228
2229 // $document->setCodigoUnico();
2230
2231 // var_export( $document->getArray() );
2232
2233 // descuento general
2234 $total_descuentos = 0;
2235 $descuento_general = 0;
2236 if($order->total_discounts > 0){
2237 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
2238 }
2239 $total_descuentos = $descuento_general + $sumaDescuentoItems;
2240
2241 // si hay descuento general y por item
2242 if($order->total_discounts > 0 && $dproductFlag == true){
2243 $descuento_general = $order->total_discounts_tax_excl; // total descuento orden
2244 $total_descuentos = $sumaDescuentoItems;
2245 }
2246 $document->setDescuentoGlobal( $descuento_general );
2247 $document->setTotalDescuento( $total_descuentos );
2248
2249 // si es gratuita o no
2250 if($order->total_paid_tax_incl == 0){
2251 $document->setTotalGratis( $totalGratis );
2252 }
2253
2254 // si existe un producto gratuito
2255 if($giftFlag == true){
2256 $document->setTotalGratis( $totalGratis );
2257 }
2258
2259 // Evalua el tipo de documento para saber el tipo de transacción (segun sunat) - By Alekuoshu
2260 if((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 4 || (int) $nubeFactCustomer['cliente_tipo_de_documento'] == 7){
2261 $document->setSunatTransaction( 29 ); // Venta no domiciliados que no califican como exportación
2262 }elseif((int) $nubeFactCustomer['cliente_tipo_de_documento'] == 0){
2263 $document->setSunatTransaction( 2 ); // Exportanción
2264 }else{
2265 $document->setSunatTransaction( 1 ); // Venta Interna
2266 }
2267
2268 // si existe un producto inefacto de IGV
2269 if($totalInafecta > 0){
2270 $document->setTotalInafecta( $totalInafecta );
2271 $total_igv = '';
2272 $document->setTotalIGV( $total_igv );
2273 $tota_gravada = '';
2274 $document->setTotalGravada( $tota_gravada );
2275 }else{
2276 $total_igv = round( $incluido_impuestos - $sin_impuestos, 2 );
2277 $document->setTotalIGV( $total_igv );
2278 $tota_gravada = $sin_impuestos;
2279 $document->setTotalGravada( $tota_gravada );
2280 }
2281
2282 //create invoice
2283 $invoice = new Vex_Nubefact_Invoice();
2284
2285 $invoice->id_customer = $customer->id;
2286 $invoice->id_order = $order->id;
2287 $invoice->tipo_de_comprobante = $nubeFactCustomer['tipo_de_comprobante'];
2288 $invoice->serie = $serie;
2289 $invoice->numero = (int) $numero;
2290 $invoice->cliente_tipo_de_documento = $nubeFactCustomer['cliente_tipo_de_documento'];
2291 $invoice->cliente_numero_de_documento = trim($nubeFactCustomer['cliente_numero_de_documento']);
2292 $invoice->cliente_denominacion = $nubeFactCustomer['cliente_denominacion'];
2293 $invoice->cliente_direccion = $nubeFactCustomer['cliente_direccion'];
2294 $invoice->cliente_email = $customer->email;
2295 $invoice->fecha_de_emision = date( 'Y-m-d' );
2296 $invoice->moneda = 1;
2297 $invoice->porcentaje_de_igv = $this->get_percent_igv();
2298 $invoice->descuento_global = $descuento_general;
2299 $invoice->total_descuento = $total_descuentos;
2300 $invoice->total_gravada = $tota_gravada;
2301 $invoice->total_igv = $total_igv;
2302 $invoice->total_gratuita = $totalGratis;
2303 $invoice->total = $incluido_impuestos;
2304
2305
2306 // validar que no existe ya la factura en nubefact y no este aceptada a la sunat
2307 $query = new DbQuery();
2308 $query->select('*');
2309 $query->from('vex_nubefact_invoice');
2310 $query->where('id_order = "'.$order->id.'" AND sunat_estado = 1');
2311 $valueR = Db::getInstance()->executeS($query);
2312
2313 // si no existe en el registro la factura se envia a nubefact
2314 if(empty($valueR)){
2315 if( $response = $nubeFact->sendDocument( $document ) ){
2316 // incrementar numero
2317 // if( $nubeFactCustomer['tipo_de_comprobante'] == self::TIPOCOMPROBANTE_FACTURA ){
2318 // Configuration::updateValue( self::CONFIG_INVOICE_NUM, $numero+1 );
2319 // } else {
2320 // Configuration::updateValue( self::CONFIG_RECEIPT_NUM, $numero+1 );
2321 // }
2322
2323 $data = @json_decode( $response );
2324
2325 // guardar pdf url
2326 $invoice->url_pdf = $data->enlace_del_pdf;
2327 // respuesta sunat
2328 $sunat = $data->aceptada_por_sunat;
2329 if($sunat === true){
2330 $invoice->sunat_estado = '1';
2331 $invoice->sunat_respuesta_envio = $data->sunat_description;
2332
2333 // Insertamos data en ps_vex_invoices_sent tabla
2334 $result = Db::getInstance()->insert('vex_invoices_sent', array(
2335 'id_order' => $id_order,
2336 'date_add' => date("Y-m-d H:i:s"),
2337 ));
2338 $error = Db::getInstance()->getMsgError();
2339
2340 if ($result == true) {
2341 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
2342 self::logtxt("sendMasiveInvoices: #Orden: $id_order Enviada!");
2343 } else {
2344 if ($error != '') {
2345 self::logtxt($error);
2346 }
2347 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
2348 }
2349
2350 }else{
2351 $invoice->sunat_estado = '0';
2352 $invoice->sunat_respuesta_envio = $data->sunat_description;
2353
2354 // Insertamos data en ps_vex_invoices_sent tabla
2355 $result = Db::getInstance()->insert('vex_invoices_sent', array(
2356 'id_order' => $id_order,
2357 'date_add' => date("Y-m-d H:i:s"),
2358 ));
2359 $error = Db::getInstance()->getMsgError();
2360
2361 if ($result == true) {
2362 self::logtxt("Registro guardado al ps_vex_invoices_sent con exito");
2363 self::logtxt("sendMasiveInvoices: #Orden: $id_order Enviada!");
2364 } else {
2365 if ($error != '') {
2366 self::logtxt($error);
2367 }
2368 self::logtxt("Hubo un error al intentar guardar en vex_invoices_sent");
2369 }
2370
2371 }
2372 } else {
2373 // var_export( [ $nubeFact->getClient(), $document->getArray() ] );
2374 // exit();
2375 }
2376
2377 $invoice->wp_data = $nubeFact->getClient()->response;
2378 $invoice->add();
2379 }
2380
2381 }
2382 // $customer = new Customer($customer_id);
2383
2384 // $clientParams = array(
2385 // 'cliente_email' => $customer->email,
2386 // 'cliente_tipo_de_documento' => '',
2387 // 'cliente_numero_de_documento' => '',
2388 // 'cliente_denominacion' => '',
2389 // 'cliente_direccion' => ''
2390 // );
2391
2392 // $clientParams = array_merge( $clientParams, $nubeFactValues );
2393
2394 // var_export( [$params['id_order'], $order->id] );
2395 // exit();
2396
2397 }//fin cambio de estado
2398
2399 } //end foreach iterate items
2400
2401 }else{
2402 self::logtxt("sendMasiveInvoices: No hay registros para enviar!");
2403
2404 }// end if results sql statement
2405
2406
2407 }//end value key for consume
2408
2409
2410 }//end sendMasiveInvoices
2411
2412 /**
2413 * Error log
2414 *
2415 * @param string $text text that will be saved in the file
2416 * @return void Error record in file "errors.log"
2417 */
2418 public static function logtxt($text = "") {
2419
2420 if (file_exists(self::NUBEFACT_PATH_LOG)) {
2421
2422 $fp = fopen(self::NUBEFACT_PATH_LOG . "/errors.log", "a+");
2423 fwrite($fp, date('l jS \of F Y h:i:s A') . ", " . $text . "\r\n");
2424 fclose($fp);
2425 return true;
2426 } else {
2427 self::createPath(self::NUBEFACT_PATH_LOG);
2428 }
2429 }
2430
2431 /**
2432 * Recursively create a string of directories
2433 */
2434 public static function createPath($path) {
2435
2436 if (is_dir($path))
2437 return true;
2438
2439 $prev_path = substr($path, 0, strrpos($path, '/', -2) + 1);
2440 $return = self::createPath($prev_path);
2441 return ($return && is_writable($prev_path)) ? mkdir($path) : false;
2442 }
2443}
2444