Skip to content

Instantly share code, notes, and snippets.

@mrbarletta
Created May 14, 2018 01:45
Show Gist options
  • Save mrbarletta/fccfa6d3a125d510ed06fc430e8529c2 to your computer and use it in GitHub Desktop.
Save mrbarletta/fccfa6d3a125d510ed06fc430e8529c2 to your computer and use it in GitHub Desktop.
<?php
namespace App\Jobs;
use App\Models\ZohoInvoice;
use function \FluidXml\fluidxml;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Storage;
class createInvoiceXML implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $invoiceID;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($invoiceID)
{
//
$this->invoiceID = $invoiceID;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$invoicesToUpdate = ZohoInvoice::where('zoho_invoice_id', $this->invoiceID);
$invoiceLines = $invoicesToUpdate->get();
$factura = fluidxml(null);
$invoiceLinesArray = [];
foreach ($invoiceLines as $invoiceLineItem) {
$invoiceLinesArray[] = $invoiceLineItem;
}
$invoice = $invoiceLinesArray[0];
// file_put_contents(storage_path()."/logs/"."/lx.log", PHP_EOL. date_format(date_create(),"Y-m-d H:i:s ") .__FILE__ .":". __LINE__." -- ".print_r($invoice, 1).PHP_EOL, FILE_APPEND);
// $countr + $day + $month + year + cedula12digits + consecutivoUnico + comprobanteNormalContingencia + CodigoSeguridad
$consecutivoID = $invoice['fe_consecutivo'];
$facturaEmisiónSucursal = "001";
$facturaTerminalSucursal = "00001";
$facturaTipoDocumento = "01";
$facturaRealizadaSituacion = "1"; //1 normal - 2 contingencia - 3 internet
$facturaNumeroConsecutivo = $facturaEmisiónSucursal . $facturaTerminalSucursal . $facturaTipoDocumento . str_pad($invoice['fe_consecutivo'], 10, "0", STR_PAD_LEFT);
$codigoSeguridad = random_int(10000000, 99999999);
$facturaFechaEmision = $invoice['date_entered']->setTimezone('America/Costa_Rica')->format(DATE_ATOM);
$facturaFechaEmision = $invoice['date_entered']->format(DATE_ATOM);
$emisorNombre = "Lionix Evolve";
$emisorNombreComercial = "Lionix";
$crTimezone = new \DateTimeZone('America/Costa_Rica');
$fechaEmisionDoc = new \DateTime("now", $crTimezone);
$emisorEmail = "[email protected]";
$emisorNumeroIdentificacion = env('EMISOR_CEDULA');
$emisorTipoIdentificacion = env('EMISOR_CEDULA_TIPO');
$facturaClave = "506" . date("d") . date("m") . date("y") . str_pad($emisorNumeroIdentificacion, 12, "0", STR_PAD_LEFT) . $facturaNumeroConsecutivo . $facturaRealizadaSituacion . $codigoSeguridad;
$emisorDirProvincia = "1";
$emisorDirCanton = "15";
$emisorDirDistrito = "01";
$emisorDirBarrio = "01";
$emisorDirOtrasSenas = "Centro Colón";
$emisorTelCodigoPais = "506";
$emisorTelNumTelefono = "40001430";
$emisorFaxCodigoPais = "506";
$emisorFaxNumTelefono = "40001430";
$receptorNombre = $invoice['customer_name'];
$receptorNombreComercial = $invoice['customer_name'];
$receptorEmail = '[email protected]';
$receptorEmail = $invoice['contacts_details'][0]->email;
$receptorTipoIdentificacion = "01"; //01 cliente final - 02 empresa
if (strlen($invoice['customer_cedula']) > 9) {
$receptorTipoIdentificacion = "02"; //01 cliente final - 02 empresa
}
$receptorNumeroIdentificacion = $invoice['customer_cedula'];
$receptorDirProvincia = "1";
$receptorDirCanton = "01";
$receptorDirDistrito = "15";
$receptorDirBarrio = "01";
$receptorDirOtrasSenas = "Outlet Mall";
$receptorTelCodigoPais = "506";
$receptorTelNumTelefono = (int) str_replace("-", "", $invoice['contacts_details'][0]->email);
$receptorFaxCodigoPais = "";
$receptorFaxNumTelefono = "";
$facturaPlazoCredito = "90";
$facturaMedioPago = "01";
$facturaCodigoMoneda = 'CRC';
$facturaTotalServExentos = 0;
$facturaTotalServGravados = number_format((float) "0", 5, '.', '');
$facturaTotalMercanciasGravadas = number_format((float) "0", 5, '.', '');
$facturaTotalMercanciasExentas = number_format((float) "0", 5, '.', '');
$facturaTotalExento = $invoice['total'];
$facturaTotalGravado = number_format((float) "0", 5, '.', '');
$facturaTotalVenta = 0;
$facturaTotalDescuentos = number_format((float) $invoice['discount'], 5, '.', '');
$facturaTotalVentaNeta = number_format((float) $invoice['total'], 5, '.', '');
$facturaTotalImpuesto = number_format((float) $invoice['tax'], 5, '.', '');
$facturaTotalComprobante = number_format((float) $invoice['total'], 5, '.', '');
$facturaNumeroResolucion = "DGT-R-48-2016";
$facturaFechaResolucion = "07-10-2016 08:00:00";
$root = $factura->addChild('FacturaElectronica', true);
if ($invoice['void']) {
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns", "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/mensajeReceptor");
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xsi:schemaLocation", "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/mensajeReceptor https://tribunet.hacienda.go.cr/docs/esquemas/2016/v4.2/MensajeReceptor_4.2.xsd");
$factura->addChild('Clave', $facturaClave);
$factura->addChild('NumeroCedulaEmisor', $emisorNumeroIdentificacion);
$factura->addChild('FechaEmisionDoc', $fechaEmisionDoc->format(\DateTime::ATOM));
} else {
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns", "https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2/facturaElectronica");
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
$root[0]->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
$factura->addChild('Clave', $facturaClave);
$factura->addChild('NumeroConsecutivo', $facturaNumeroConsecutivo);
$factura->addChild('FechaEmision', $facturaFechaEmision);
$factura->addChild(['Emisor' => [
'Nombre' => $emisorNombre,
// 'NombreComercial' => $emisorNombreComercial,
['Identificacion' => [
'Tipo' => $emisorTipoIdentificacion,
'Numero' => $emisorNumeroIdentificacion,
]],
['Ubicacion' => [
'Provincia' => $emisorDirProvincia,
'Canton' => $emisorDirCanton,
'Distrito' => $emisorDirDistrito,
'Barrio' => $emisorDirBarrio,
'OtrasSenas' => $emisorDirOtrasSenas],
],
['Telefono' => [
'CodigoPais' => $emisorTelCodigoPais,
'NumTelefono' => $emisorTelNumTelefono,
]],
['Fax' => [
'CodigoPais' => $emisorFaxCodigoPais,
'NumTelefono' => $emisorFaxNumTelefono,
]],
'CorreoElectronico' => $emisorEmail,
]]);
$receptor = ['Receptor' => [
'Nombre' => $receptorNombre,
['Identificacion' => [
'Tipo' => $receptorTipoIdentificacion,
'Numero' => $receptorNumeroIdentificacion,
]],
['Ubicacion' => [
'Provincia' => $receptorDirProvincia,
'Canton' => $receptorDirCanton,
'Distrito' => $receptorDirDistrito,
'Barrio' => $receptorDirBarrio,
'OtrasSenas' => $receptorDirOtrasSenas],
]]];
if (!empty($receptorTelNumTelefono)) {
$receptor['Receptor']['Telefono'] = [
'CodigoPais' => $receptorTelCodigoPais,
'NumTelefono' => $receptorTelNumTelefono,
];
}
if (!empty($receptorTelNumTelefono)) {
$receptor['Receptor']['Fax'] = [
'CodigoPais' => $receptorFaxCodigoPais,
'NumTelefono' => $receptorFaxNumTelefono,
];
}
$receptor['Receptor']['CorreoElectronico'] = $receptorEmail;
$factura->addChild($receptor);
$factura->addChild('CondicionVenta', '02'); //01 es contado
$factura->addChild('PlazoCredito', $facturaPlazoCredito);
$factura->addChild('MedioPago', $facturaMedioPago);
$detalleServicioArray = [];
foreach ($invoiceLines as $key => $invoiceLineItem) {
$detalle=$invoiceLineItem['line_item_name'];
if(empty($detalle)){
$detalle=$invoiceLineItem['line_item_description'];
}
$detalleServicio =
['LineaDetalle' => [
'NumeroLinea' => $invoiceLineItem['line_number'],
['Codigo' => [
'Tipo' => '04', //Codigo de uso interno
'Codigo' => '1',
]],
'Cantidad' => number_format((float) $invoiceLineItem['line_item_quantity'], 5, '.', ''),
'UnidadMedida' => 'Sp',
'UnidadMedidaComercial' => '',
'Detalle' => $detalle,
'PrecioUnitario' => number_format((float) $invoiceLineItem['line_item_rate'], 5, '.', ''),
]];
$detalleServicio['LineaDetalle']['MontoTotal'] = number_format((float) $invoiceLineItem['line_item_rate'], 5, '.', '')*number_format((float) $invoiceLineItem['line_item_quantity'], 5, '.', '');
$facturaTotalVenta=$facturaTotalVenta+$detalleServicio['LineaDetalle']['MontoTotal'];
$facturaTotalServGravados =$facturaTotalVenta; //No tenemos venta de cosas ni usamos IV - podría cambiar pero habría que alterar también Zoho
if (!empty($invoiceLineItem['line_item_discount_amount']) && $invoiceLineItem['line_item_discount_amount'] > 0) {
$detalleServicio['LineaDetalle']['MontoDescuento'] = number_format((float) $invoiceLineItem['line_item_discount_amount'], 5, '.', '');
$detalleServicio['LineaDetalle']['NaturalezaDescuento'] = "Descuento por competencia";
$facturaTotalDescuentos=$facturaTotalDescuentos+$detalleServicio['LineaDetalle']['MontoDescuento'];
}
$detalleServicio['LineaDetalle']['SubTotal'] =$detalleServicio['LineaDetalle']['MontoTotal']- $detalleServicio['LineaDetalle']['MontoDescuento'];
//TODO: Cambiar cuando haya impuesto de servicios - hay q sumar el imp
$detalleServicio['LineaDetalle']['MontoTotalLinea'] = $detalleServicio['LineaDetalle']['SubTotal'] ; //+ IMPUESTOS
$detalleServicioArray[]=$detalleServicio;
}
$factura->addChild(['DetalleServicio' => $detalleServicio]);
$factura->addChild(['ResumenFactura' => [
'CodigoMoneda' => $invoiceLineItem['currency_code'],
'TipoCambio' => $invoiceLineItem['currency_rate'],
'TotalServGravados' => $facturaTotalServGravados,
'TotalServExentos' => $facturaTotalServExentos,
'TotalMercanciasGravadas' => $facturaTotalMercanciasGravadas,
'TotalMercanciasExentas' => $facturaTotalMercanciasExentas,
'TotalGravado' => $facturaTotalGravado,
'TotalExento' => $facturaTotalExento,
'TotalVenta' => $facturaTotalVenta,
'TotalDescuentos' => $facturaTotalDescuentos,
'TotalVentaNeta' => $facturaTotalVenta-$facturaTotalDescuentos,
'TotalImpuesto' => $facturaTotalImpuesto,
'TotalComprobante' => $facturaTotalComprobante,
]]);
$factura->addChild(
['Normativa' => [
'NumeroResolucion' => $facturaNumeroResolucion,
'FechaResolucion' => $facturaFechaResolucion,
]]);
}
// $factura->addChild(
// ['Otros' => [
// 'OtroTexto' => '',
// ]]);
$anoMes = date("Y") . "-" . date("m");
$anoMesDia = date("Y") . "-" . date("m") . "-" . date("d");
$invoiceXMLfile = "{$anoMesDia}-{$consecutivoID}-" . $facturaClave . ".xml";
$facturaSinFirma_ubicacion = "/facturasSinFirmar/{$anoMes}/" . $invoiceXMLfile;
$stored=Storage::disk("local")->put($facturaSinFirma_ubicacion, $factura->xml());
// file_put_contents(storage_path()."/logs/"."/lx.log", PHP_EOL . date_format(date_create(), "Y-m-d H:i:s ") . __FILE__ . ":" . __LINE__ . " -- " . print_r($stored, 1) . PHP_EOL, FILE_APPEND);
$facturaSinFirma_fullpath = storage_path() . "/app/" . $facturaSinFirma_ubicacion;
$facturaFirmada_fullpath = storage_path() . "/app/facturasFirmadas/{$anoMes}/" . $invoiceXMLfile;
$signedFileContent = $this->firmarDocumento($facturaSinFirma_fullpath, "01");
$facturaFirmada_ubicacion = "/facturasFirmadas/{$anoMes}/" . $invoiceXMLfile;
Storage::disk("s3")->put($facturaFirmada_ubicacion, $signedFileContent);
$facturaFirmadaS3_URL = "https://" . env('AWS_FQDN') . $facturaFirmada_ubicacion;
Storage::disk("local")->put($facturaFirmada_ubicacion, $signedFileContent);
$facturaXMLhash = hash_file('sha512', $facturaFirmada_fullpath);
$invoicesToUpdateArray = [
'fe_url' => $facturaFirmadaS3_URL,
'fe_xml_file' => $facturaFirmada_ubicacion,
'fe_clave' => $facturaClave,
'fe_xml_hash' => $facturaXMLhash,
];
$invoicesToUpdate->update($invoicesToUpdateArray);
$signedFile = Storage::disk("local")->get($facturaFirmada_ubicacion);
}
public function firmarDocumento($inXmlUrl, $tipoDoc)
{
require_once __DIR__ . '/firmadorCR.php';
$p12Url = config_path() . '/' . env('MH_CERTIFICATE');
$pinP12 = env('MH_KEY_PASS');
$fac = new \Firmadocr();
$outXmlUrl = $fac->firmar($p12Url, $pinP12, $inXmlUrl, $tipoDoc);
return $outXmlUrl;
}
}
<?php
namespace App\Jobs;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\ZohoInvoice;
use Monolog\Logger;
use Mailgun\Mailgun;
class getCurrentExchangeRate implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 5;
public $delayInSeconds = 5 ;
public $invoiceID;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($invoiceID)
{
$this->invoiceID = $invoiceID;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try{
$logger = new Logger('MyLog');
$logger->pushHandler(new \Monolog\Handler\StreamHandler(storage_path()."/logs/"."/lx.log"), Logger::DEBUG);
$stack = HandlerStack::create();
$stack->push(
Middleware::log(
$logger,
new MessageFormatter('{req_headers} //// {req_body} -------------------- {res_headers} ///// {res_body}')
)
);
$this->loggerStack = $stack;
$bacEndpoint = new Client([
// Base URI is used with relative requests
'base_uri' => 'https://www.baccredomatic.com/es-cr/bac/',
// You can set any number of default request options.
'timeout' => 4.0,
// 'handler' => $this->loggerStack,
]);
$resExchangeRate=$bacEndpoint->request('GET','exchange-rate-ajax/es-cr',[
'headers' => array('Accept: application/json'),
]);
$resExchangeRate = $resExchangeRate->getBody();
$currencyExchangeResult = json_decode($resExchangeRate, true);
;
$invoicesToUpdate = ZohoInvoice::where('zoho_invoice_id', $this->invoiceID);
if ($invoicesToUpdate->count() > 0) {
// file_put_contents(storage_path()."/logs/"."/lx.log", PHP_EOL. date_format(date_create(),"Y-m-d H:i:s ") .__FILE__ .":". __LINE__." -- ".print_r($currencyExchangeResult['saleRateUSD'], 1).PHP_EOL, FILE_APPEND);
$invoicesToUpdate->update(['currency_rate' => $currencyExchangeResult['saleRateUSD']]);
}else{
$this->failed(new \Exception("Zoho invoice not found"));
}
}catch (ClientException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ClientException tamo al horno');
} catch (ServerException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ServerException tamo al horno');
} catch (ConnectException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ConnectException tamo al horno');
}
}
/**
* The job failed to process.
*
* @param Exception $exception
* @return void
*/
public function failed(\Exception $exception)
{
// Send user notification of failure, etc...
$invoicesToUpdate = ZohoInvoice::whereIn('zoho_invoice_id',[ $this->invoiceID]);
$invoicesToUpdate->update(['status' => 'failed'],['status_detail' => 'getCurrentExchangeRate - Failed']);
$mailgun = Mailgun::create(env('MAILGUN_KEY'));
$mailgun->messages()->send('lionix.com', [
'from' => '[email protected]',
'to' => '[email protected]',
'subject' => "No se pudo obtener tasa de cambio para - {$this->invoiceID}",
'text' => " {$this->invoiceID}",
]);
}
}
<?php
namespace App\Jobs;
use App\Models\ZohoInvoice;
use Monolog\Logger;
use Mailgun\Mailgun;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use \Exception;
class sendSignedInvoice implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $invoiceID;
public $tries = 5;
public $delayInSeconds = 5 ;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($invoiceID)
{
$this->invoiceID = $invoiceID;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
$invoicesToUpdate = ZohoInvoice::where('zoho_invoice_id', $this->invoiceID);
$invoiceLines = $invoicesToUpdate->get();
$invoiceLinesArray = [];
foreach ($invoiceLines as $invoice) {
continue;
}
$apiHacienda = new Client([
'base_uri' => 'https://api.comprobanteselectronicos.go.cr/',
'timeout' => 4.0,
]);
$client = new Client([
'base_uri' => 'https://idp.comprobanteselectronicos.go.cr/',
'timeout' => 4.0,
]);
$form_params = [
'client_id' => env('MH_CLIENT_ID'),
'client_secret' => env('MH_CLIENT_SECRET'),
'grant_type' => 'password',
'username' => env('MH_USERNAME'),
'password' => env('MH_PASSWORD'),
];
$responseLogin = $client->request('POST', 'auth/realms/rut-stag/protocol/openid-connect/token', [
'form_params' => $form_params,
// 'debug' => fopen('/home/mrb/public_html/lx.log', "a+"),
]);
$responseLogin = json_decode($responseLogin->getBody(), true);
$headers = ['Authorization' => 'Bearer ' . $responseLogin['access_token']];
$receptorTipoIdentificacion = 01; //01 cliente final - 02 empresa
if (strlen($invoice['customer_cedula']) > 9) {
$receptorTipoIdentificacion = 02; //01 cliente final - 02 empresa
}
$receptorNumeroIdentificacion = $invoice['customer_cedula'];
$signedFile = file_get_contents(storage_path() . "/app/" . $invoice['fe_xml_file']);
$facturaParametros = [
"clave" => $invoice['fe_clave'],
"fecha" => $invoice['date_entered']->setTimezone('America/Costa_Rica')->format(DATE_ATOM),
"emisor" => ["tipoIdentificacion" => env('EMISOR_CEDULA_TIPO'), "numeroIdentificacion" => env('EMISOR_CEDULA')],
"receptor" => ["tipoIdentificacion" => $receptorTipoIdentificacion, "numeroIdentificacion" => $receptorNumeroIdentificacion],
"comprobanteXml" => base64_encode($signedFile),
];
$invoicesToUpdate->update(['fe_xml_signed_sent' => \Carbon\Carbon::now()]);
$responseRecepcion = $apiHacienda->request('POST', 'recepcion-sandbox/v1/recepcion', [
'headers' => $headers,
'json' => $facturaParametros,
]);
// file_put_contents(storage_path()."/logs/"."/lx.log", PHP_EOL . date_format(date_create(), "Y-m-d H:i:s ") . __FILE__ . ":" . __LINE__ . " -- " . print_r($responseRecepcion, 1) . PHP_EOL, FILE_APPEND);
if ($responseRecepcion->getStatusCode() != 202) {
//tamo al horno - ver q onda
}
if ($responseRecepcion->hasHeader('Location')) {
$facturaRecibidaUrl = $responseRecepcion->getHeader('Location');
$invoicesToUpdate->update(['fe_status' => 'sent', 'fe_mh_url' => $facturaRecibidaUrl[0]]);
}else{
$this->release($this->delayInSeconds);
}
} catch (ClientException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ClientException tamo al horno');
} catch (ServerException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ServerException tamo al horno');
} catch (ConnectException $e) {
$this->release($this>delayInSeconds);
throw new Exception('ConnectException tamo al horno');
}
}
/**
* The job failed to process.
*
* @param Exception $exception
* @return void
*/
public function failed(\Exception $exception)
{
// Send user notification of failure, etc...
$invoicesToUpdate = ZohoInvoice::whereIn('zoho_invoice_id',[ $this->invoiceID]);
$invoicesToUpdate->update(['status' => 'failed'],['status_detail' => 'sendSignedInvoice - Failed']);
$mailgun = Mailgun::create(env('MAILGUN_KEY'));
$mailgun->messages()->send('lionix.com', [
'from' => '[email protected]',
'to' => '[email protected]',
'subject' => "Factura no se pudo enviar a MH - {$this->invoiceID}",
'text' => " {$this->invoiceID}",
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment