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