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