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