1602 lines
46 KiB
PHP
Executable File
1602 lines
46 KiB
PHP
Executable File
<?php
|
|
|
|
class Comprobante extends Main
|
|
{
|
|
public $sucursalId;
|
|
|
|
public function setSucursalId($value)
|
|
{
|
|
$this->Util()->ValidateInteger($value);
|
|
$this->sucursalId = $value;
|
|
}
|
|
|
|
|
|
function GenerarComprobante($data, $notaCredito = false)
|
|
{
|
|
global $empresa;
|
|
global $rfc;
|
|
global $cliente;
|
|
global $util;
|
|
global $venta;
|
|
|
|
$myData = urlencode(serialize($data));
|
|
$infEmp = $empresa->InfoAll();
|
|
|
|
$values = explode("&", $data["datosFacturacion"]);
|
|
unset($data["datosFacturacion"]);
|
|
foreach($values as $key => $val)
|
|
{
|
|
$array = explode("=", $values[$key]);
|
|
$data[$array[0]] = $array[1];
|
|
}
|
|
|
|
//Datos de la Nota de Venta
|
|
$tickets = array();
|
|
if($data['ventaId'] != ""){
|
|
|
|
$ventaId = $data['ventaId'];
|
|
|
|
$venta->setVentaId($ventaId);
|
|
$infV = $venta->Info();
|
|
|
|
if($infV["status"] == 'Facturada'){
|
|
$vs->Util()->setError('', "error", "La nota de venta ya ha sido facturada previamente.");
|
|
$vs->Util()->PrintErrors();
|
|
return false;
|
|
}
|
|
|
|
}elseif($data['tickets'] != ''){
|
|
|
|
$tickets = explode('-', $data['tickets']);
|
|
|
|
//Checar si alguna nota ya se facturo
|
|
foreach($tickets as $idVenta){
|
|
$venta->setVentaId($idVenta);
|
|
$infV = $venta->Info();
|
|
|
|
if($infV["status"] == 'Facturada'){
|
|
$util->setError('', 'error', 'La nota de venta No. '.$infV['folio'].' ya ha sido facturada <br> previamente.');
|
|
$util->PrintErrors();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}//elseif
|
|
|
|
$tipoSerie = explode("-", $data["tiposComprobanteId"]);
|
|
$data["tiposComprobanteId"] = $tipoSerie[0];
|
|
$data["tiposSerieId"] = $tipoSerie[1];
|
|
|
|
$empresa->setRFC($data["rfc"]);
|
|
$empresa->setCalle($data["calle"]);
|
|
$empresa->setPais($data["pais"]);
|
|
|
|
if(strlen($data["formaDePago"]) <= 0)
|
|
{
|
|
$empresa->Util()->setError(10041, "error", "");
|
|
}
|
|
|
|
if(count($_SESSION["conceptos"]) < 1)
|
|
{
|
|
$empresa->Util()->setError(10040, "error", "");
|
|
}
|
|
|
|
$myConceptos = urlencode(serialize($_SESSION["conceptos"]));
|
|
$myImpuestos = urlencode(serialize($_SESSION["impuestos"]));
|
|
|
|
$userId = $data["userId"];
|
|
|
|
$totales = $this->GetTotalDesglosado($data);
|
|
|
|
/*** AJUSTAMOS TOTALES ***/
|
|
|
|
$ventaId = $data['ventaId'];
|
|
|
|
if($ventaId){
|
|
|
|
$venta->setVentaId($ventaId);
|
|
$infV = $venta->Info();
|
|
|
|
$difCents = $infV['total'] - $totales['total'];
|
|
$difCents = number_format($difCents,2,'.','');
|
|
|
|
if($difCents == 0.01 || $difCents == -0.01){
|
|
$totales['iva'] += $difCents;
|
|
$totales['ivaThis'] += $difCents;
|
|
$totales['total'] += $difCents;
|
|
}
|
|
|
|
$totales['iva'] = number_format($totales['iva'],2,'.','');
|
|
$totales['ivaThis'] = number_format($totales['ivaThis'],2,'.','');
|
|
|
|
}
|
|
|
|
/*** FIN AJUSTAR TOTALES ***/
|
|
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
|
|
if(!$data["tipoDeCambio"])
|
|
{
|
|
$data["tipoDeCambio"] = "1.00";
|
|
}
|
|
|
|
if(!$data["porcentajeDescuento"])
|
|
{
|
|
$data["porcentajeDescuento"] = "0";
|
|
}
|
|
|
|
if(!$data["porcentajeIEPS"])
|
|
{
|
|
$data["porcentajeIEPS"] = "0";
|
|
}
|
|
|
|
//get active rfc
|
|
$activeRfc = $rfc->getRfcActive();
|
|
|
|
//get datos serie de acuerdo al tipo de comprobabte expedido.
|
|
|
|
if(!$data["metodoDePago"])
|
|
{
|
|
$empresa->Util()->setError(10047, "error", "El método de pago no puede ser vacío.");
|
|
}
|
|
|
|
if($data["numCtaPago"])
|
|
{
|
|
if(strlen($data["numCtaPago"]) < 4)
|
|
{
|
|
$empresa->Util()->setError(10047, "error", "El número de cuenta debe de tener 4 dígitos.");
|
|
}
|
|
}
|
|
|
|
if(!$data["tiposComprobanteId"])
|
|
{
|
|
$empresa->Util()->setError(10047, "error");
|
|
}
|
|
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
|
|
if($notaCredito)
|
|
{
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT * FROM serie WHERE tiposComprobanteId = '2' AND empresaId = ".$_SESSION["empresaId"]." AND rfcId = '".$activeRfc."' AND consecutivo != folioFinal AND serieId = ".$data["tiposSerieId"]." ORDER BY serieId DESC LIMIT 1");
|
|
}
|
|
else
|
|
{
|
|
$sql = "SELECT
|
|
*
|
|
FROM
|
|
serie
|
|
WHERE
|
|
tiposComprobanteId = ".$data["tiposComprobanteId"]."
|
|
AND
|
|
empresaId = ".$_SESSION["empresaId"]."
|
|
AND
|
|
rfcId = '".$activeRfc."'
|
|
AND
|
|
consecutivo != folioFinal
|
|
AND
|
|
serieId = ".$data["tiposSerieId"]."
|
|
ORDER BY
|
|
serieId DESC
|
|
LIMIT
|
|
1";
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
}
|
|
|
|
$serie = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
|
|
|
|
if(!$serie)
|
|
{
|
|
$empresa->Util()->setError(10047, "error");
|
|
}
|
|
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
|
|
$folio = $serie["consecutivo"];
|
|
$fecha = $this->Util()->FormatDateAndTime(time()-600);
|
|
//$fecha = "2012-02-07 14:55:52";
|
|
|
|
//el tipo de comprobante lo determina tiposComprobanteId
|
|
$tipoDeComprobante = $this->GetTipoComprobante($data["tiposComprobanteId"]);
|
|
$data["comprobante"] = $this->InfoComprobante($data["tiposComprobanteId"]);
|
|
|
|
$data["serie"] = $serie;
|
|
$data["folio"] = $folio;
|
|
$data["fecha"] = $fecha;
|
|
$data["tipoDeComprobante"] = $tipoDeComprobante;
|
|
$data["certificado"] = $serie["noCertificado"];
|
|
|
|
//Build informacion nodo emisor
|
|
$sucursal = new Sucursal;
|
|
$sucursal->setSucursalId($data["sucursalId"]);
|
|
$nodoEmisor = $sucursal->Info();
|
|
$nodoEmisor['identificador'] = $nodoEmisor['nombre'];
|
|
|
|
$rfc->setRfcId($activeRfc);
|
|
$nodoEmisorRfc = $rfc->Info();
|
|
|
|
$data["nodoEmisor"]["sucursal"] = $nodoEmisor;
|
|
$data["nodoEmisor"]["rfc"] = $nodoEmisorRfc;
|
|
|
|
if(!$data["nodoEmisor"]["rfc"]["regimenFiscal"])
|
|
{
|
|
$empresa->Util()->setError(10047, "error", "Necesitas el Régimen Fiscal. Esto se actualiza en Catálogos <br> Mi Empresa, en la opción de edición.");
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
}
|
|
|
|
if($_SESSION["version"] == "auto")
|
|
{
|
|
$rootQr = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/qrs/";
|
|
$qrRfc = strtoupper($nodoEmisorRfc["rfc"]);
|
|
$nufa = $serie["serieId"]."_".$serie["noAprobacion"]."_".$qrRfc.".png";
|
|
|
|
if(!file_exists($rootQr.$nufa))
|
|
{
|
|
$nufa = $serie["serieId"]."_".$serie["noAprobacion"]."_".$qrRfc."_.png";
|
|
if(!file_exists($rootQr.$nufa))
|
|
{
|
|
$nufa = $serie["serieId"].".png";
|
|
if(!file_exists($rootQr.$nufa))
|
|
{
|
|
$empresa->Util()->setError(10048, "error");
|
|
}
|
|
}
|
|
}
|
|
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
|
|
}
|
|
|
|
$userId = $data["userId"];
|
|
|
|
//Build informacion Nodo Receptor
|
|
|
|
if($_SESSION['tipoComp'] == 'Publico'){
|
|
|
|
$rfc->setRfcId($activeRfc);
|
|
$nodoReceptor = $rfc->Info();
|
|
$nodoReceptor['nombre'] = $nodoReceptor['razonSocial'];
|
|
$data["nodoReceptor"] = $nodoReceptor;
|
|
$facturaGlobal = 1;
|
|
$fechaIni = $_SESSION['compFI'];
|
|
$fechaFin = $_SESSION['compFF'];
|
|
|
|
}else{
|
|
|
|
$userId = $data["userId"];
|
|
$cliente->setClienteId($userId);
|
|
$nodoReceptor = $cliente->Info();
|
|
$nodoReceptor = $util->EncodeRow($nodoReceptor);
|
|
$data["nodoReceptor"] = $nodoReceptor;
|
|
$facturaGlobal = 0;
|
|
$fechaIni = '';
|
|
$fechaFin = '';
|
|
}
|
|
|
|
//Checar si nos falta unidad en alguno
|
|
foreach($_SESSION["conceptos"] as $concepto)
|
|
{
|
|
if($concepto["unidad"] == "")
|
|
{
|
|
$empresa->Util()->setError(10048, "error", "El campo de Unidad no puede ser vacío.");
|
|
}
|
|
}
|
|
|
|
if($empresa->Util()->PrintErrors()){ return false; }
|
|
|
|
switch($_SESSION["version"])
|
|
{
|
|
case "auto":
|
|
case "v3":
|
|
case "construc":
|
|
include_once(DOC_ROOT.'/classes/cadena_original_v3.class.php');break;
|
|
case "2":
|
|
include_once(DOC_ROOT.'/classes/cadena_original_v2.class.php');break;
|
|
}
|
|
$cadena = new Cadena;
|
|
$cadenaOriginal = $cadena->BuildCadenaOriginal($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"]);
|
|
|
|
$data["cadenaOriginal"] = utf8_encode($cadenaOriginal);
|
|
$data["cadenaOriginal"] = $cadenaOriginal;
|
|
$md5Cadena = utf8_decode($cadenaOriginal);
|
|
|
|
if(date("Y") > 2010)
|
|
{
|
|
$md5 = sha1($md5Cadena);
|
|
}
|
|
|
|
$sello = $this->GenerarSello($cadenaOriginal, $md5);
|
|
$data["sello"] = $sello["sello"];
|
|
$data["certificado"] = $sello["certificado"];
|
|
|
|
switch($_SESSION["version"])
|
|
{
|
|
case "auto":
|
|
case "v3":
|
|
case "construc":
|
|
include_once(DOC_ROOT.'/classes/generate_xml_default.class.php');break;
|
|
case "2":
|
|
include_once(DOC_ROOT.'/classes/generate_xml_v2.class.php');break;
|
|
}
|
|
|
|
$xml = $infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
|
|
|
|
/*** CHECAR ERROR DE FACTURACION**/
|
|
|
|
$xmlGen = new XmlGen;
|
|
$xml = $xmlGen->GenerateXML($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"],$infEmp);
|
|
|
|
//despues de la generacion del xml, viene el timbrado.
|
|
if($_SESSION["version"] == "v3" || $_SESSION["version"] == "construc")
|
|
{
|
|
$nufa = $infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
|
|
$rfcActivo = $rfc->getRfcActive();
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/";
|
|
$root_dos = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/timbres/";
|
|
|
|
$nufa_dos = "SIGN_".$infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
|
|
$xmlFile = $root.$nufa.".xml";
|
|
$zipFile = $root.$nufa.".zip";
|
|
$signedFile = $root.$nufa."_signed.zip";
|
|
$timbreFile = $root.$nufa."_timbre.zip";
|
|
$timbradoFile = $root.$nufa_dos.".xml";
|
|
|
|
$this->Util()->Zip($root, $nufa);
|
|
|
|
$user = USER_PAC;
|
|
$pw = PW_PAC;
|
|
$pac = new Pac;
|
|
$response = $pac->GetCfdi($user, $pw, $zipFile, $root, $signedFile, $infEmp["empresaId"]);
|
|
|
|
$resp = explode('#',$response);
|
|
|
|
if($resp[0] == "fault")
|
|
{
|
|
//echo "<b><br><br>Has encontrado un error al Sellar tu Comprobante. Favor de reportarnos este error con todos los detalles posibles. Gracias!!</b>";
|
|
$util->setError(20113,'error','Error al Sellar',$resp[1]);
|
|
$util->PrintErrors();
|
|
return false;
|
|
}
|
|
|
|
$fileTimbreXml = $pac->GetTimbreCfdi($user, $pw, $zipFile, $root, $timbreFile, $infEmp["empresaId"]);
|
|
$timbreXml = $pac->ParseTimbre($timbradoFile);
|
|
|
|
$cadenaOriginalTimbre = $pac->GenerateCadenaOriginalTimbre($timbreXml);
|
|
$cadenaOriginalTimbreSerialized = serialize($cadenaOriginalTimbre);
|
|
|
|
$data["timbreFiscal"] = $cadenaOriginalTimbre;
|
|
}
|
|
/*
|
|
//GeneratePDF
|
|
//cambios 29 junio 2011
|
|
switch($infEmp["empresaId"])
|
|
{
|
|
default:
|
|
switch($_SESSION["version"])
|
|
{
|
|
case "v3":
|
|
case "construc": include_once(DOC_ROOT."/classes/override_generate_pdf_default.php"); break;
|
|
case "auto": include_once(DOC_ROOT."/classes/override_generate_pdf_default_auto.php");break;
|
|
case "2": include_once(DOC_ROOT."/classes/override_generate_pdf_default_2.php");break;
|
|
}
|
|
|
|
$override = new Override;
|
|
$pdf = $override->GeneratePDF($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"],$infEmp);
|
|
}
|
|
*/
|
|
//cambios 29 junio 2011
|
|
//insert new comprobante
|
|
switch($data["tiposDeMoneda"])
|
|
{
|
|
case "MXN": $data["tiposDeMoneda"] = "peso"; break;
|
|
case "USD": $data["tiposDeMoneda"] = "dolar"; break;
|
|
case "EUR": $data["tiposDeMoneda"] = "euro"; break;
|
|
}
|
|
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("
|
|
INSERT INTO `comprobante` (
|
|
`comprobanteId`,
|
|
`userId`,
|
|
`formaDePago`,
|
|
`condicionesDePago`,
|
|
`metodoDePago`,
|
|
`tasaIva`,
|
|
`tipoDeMoneda`,
|
|
`tipoDeCambio`,
|
|
`porcentajeRetIva`,
|
|
`porcentajeRetIsr`,
|
|
`tiposComprobanteId`,
|
|
`porcentajeIEPS`,
|
|
`porcentajeDescuento`,
|
|
`empresaId`,
|
|
`sucursalId`,
|
|
`observaciones`,
|
|
`serie`,
|
|
`folio`,
|
|
`fecha`,
|
|
`sello`,
|
|
`noAprobacion`,
|
|
`anoAprobacion`,
|
|
`noCertificado`,
|
|
`certificado`,
|
|
`subtotal`,
|
|
`descuento`,
|
|
`motivoDescuento`,
|
|
`total`,
|
|
`tipoDeComprobante`,
|
|
`xml`,
|
|
`rfcId`,
|
|
`ivaTotal`,
|
|
`data`,
|
|
`conceptos`,
|
|
`impuestos`,
|
|
`cadenaOriginal`,
|
|
`timbreFiscal`,
|
|
`facturaGlobal`,
|
|
`fechaIni`,
|
|
`fechaFin`
|
|
) VALUES
|
|
(
|
|
NULL,
|
|
'".$userId."',
|
|
'".$data["formaDePago"]."',
|
|
'".$data["condicionesDePago"]."',
|
|
'".$data["metodoDePago"]."',
|
|
'".$data["tasaIva"]."',
|
|
'".$data["tiposDeMoneda"]."',
|
|
'".$data["tipoDeCambio"]."',
|
|
'".$data["porcentajeRetIva"]."',
|
|
'".$data["porcentajeRetIsr"]."',
|
|
'".$data["tiposComprobanteId"]."',
|
|
'".$data["porcentajeIEPS"]."',
|
|
'".$data["porcentajeDescuento"]."',
|
|
'".$infEmp["empresaId"]."',
|
|
'".$data["sucursalId"]."',
|
|
'".$data["observaciones"]."',
|
|
'".$serie["serie"]."',
|
|
'".$folio."',
|
|
'".$fecha."',
|
|
'".$data["sello"]."',
|
|
'".$serie["noAprobacion"]."',
|
|
'".$serie["anoAprobacion"]."',
|
|
'".$serie["noCertificado"]."',
|
|
'".$data["certificado"]."',
|
|
'".$totales["subtotal"]."',
|
|
'".$totales["descuento"]."',
|
|
'".$data["motivoDescuento"]."',
|
|
'".$totales["total"]."',
|
|
'".$tipoDeComprobante."',
|
|
'".$xml."',
|
|
'".$data["nodoEmisor"]["rfc"]["rfcId"]."',
|
|
'".$totales["iva"]."',
|
|
'".$myData."',
|
|
'".$myConceptos."',
|
|
'".$myImpuestos."',
|
|
'".htmlspecialchars($data["cadenaOriginal"], ENT_QUOTES)."',
|
|
'".$cadenaOriginalTimbreSerialized."',
|
|
'".$facturaGlobal."',
|
|
'".$fechaIni."',
|
|
'".$fechaFin."'
|
|
)");
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->InsertData();
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT comprobanteId FROM comprobante ORDER BY comprobanteId DESC LIMIT 1");
|
|
$comprobanteId = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
|
|
|
|
if($data['ventaId'] != ""){
|
|
|
|
$sql = "UPDATE
|
|
venta
|
|
SET
|
|
comprobanteId = '".$comprobanteId."',
|
|
status = 'Facturada'
|
|
WHERE
|
|
ventaId = '".$data["ventaId"]."'";
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
|
|
|
|
}elseif(count($tickets) > 0){
|
|
|
|
//Actualizamos los tickets a facturado
|
|
|
|
foreach($tickets as $ventaId){
|
|
$sql = "UPDATE venta
|
|
SET comprobanteId = '".$comprobanteId."',
|
|
status = 'Facturada'
|
|
WHERE
|
|
ventaId = '".$ventaId."'";
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
|
|
}
|
|
|
|
}//elseif
|
|
|
|
//Insert Conceptos
|
|
foreach($_SESSION["conceptos"] as $concepto)
|
|
{
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("
|
|
INSERT INTO `concepto` (
|
|
`comprobanteId`,
|
|
`cantidad`,
|
|
`unidad`,
|
|
`noIdentificacion`,
|
|
`descripcion`,
|
|
`valorUnitario`,
|
|
`excentoIva`,
|
|
`importe`,
|
|
`userId`,
|
|
`empresaId`
|
|
) VALUES (
|
|
".$comprobanteId.",
|
|
".$concepto["cantidad"].",
|
|
'".$concepto["unidad"]."',
|
|
'".htmlspecialchars($concepto["noIdentificacion"], ENT_QUOTES)."',
|
|
'".htmlspecialchars($concepto["descripcion"], ENT_QUOTES)."',
|
|
".$concepto["valorUnitario"].",
|
|
'".$concepto["excentoIva"]."',
|
|
".$concepto["importe"].",
|
|
'".$userId."',
|
|
".$infEmp["empresaId"]."
|
|
)");
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->InsertData();
|
|
}//foreach
|
|
|
|
|
|
|
|
unset($_SESSION["notasPorFacturar"]);
|
|
unset($_SESSION["conceptos"]);
|
|
|
|
//Finally we update the consecutivo
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("UPDATE serie SET consecutivo = consecutivo + 1 WHERE serieId = ".$serie["serieId"]);
|
|
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
|
|
|
|
return true;
|
|
|
|
}//GenerarComprobante
|
|
|
|
function CancelarComprobante($data, $comprobanteId, $notaCredito = false, $recipient)
|
|
{
|
|
global $rfc;
|
|
|
|
$sql = "SELECT noCertificado, xml, rfc FROM comprobante
|
|
LEFT JOIN cliente ON cliente.clienteId = comprobante.userId
|
|
WHERE comprobanteId = ".$comprobanteId;
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
|
|
$xml = $row["xml"];
|
|
|
|
$info = $this->GetInfoComprobante($comprobanteId);
|
|
|
|
/*
|
|
if($info["version"] == "v3" || $info["version"] == "construc")
|
|
{
|
|
$rfcActivo = $rfc->getRfcActive();
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/SIGN_".$xml.".xml";
|
|
|
|
$fh = fopen($root, 'r');
|
|
$theData = fread($fh, filesize($root));
|
|
fclose($fh);
|
|
|
|
$theData = explode("UUID", $theData);
|
|
$theData = $theData[1];
|
|
$theData = explode("FechaTimbrado", $theData);
|
|
$theData = $theData[0];
|
|
$uuid = str_replace("\"", "", $theData);
|
|
$uuid = str_replace("=", "", $uuid);
|
|
$uuid = str_replace(" ", "", $uuid);
|
|
|
|
$path = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/".$row["noCertificado"].".cer.pfx";
|
|
|
|
$user = USER_PAC;
|
|
$pw = PW_PAC;
|
|
$pac = new Pac;
|
|
|
|
//get password
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/password.txt";
|
|
$fh = fopen($root, 'r');
|
|
$password = fread($fh, filesize($root));
|
|
|
|
fclose($fh);
|
|
|
|
if(!$password)
|
|
{
|
|
$this->Util()->setError('', "error", "Tienes que actualizar tu certificado para que podamos obtener el password");
|
|
$this->Util()->PrintErrors();
|
|
return false;
|
|
}
|
|
$rfc->setRfcId($rfcActivo);
|
|
$nodoEmisorRfc = $rfc->InfoRfc();
|
|
$response = $pac->CancelaCfdi($user, $pw, $nodoEmisorRfc["rfc"], $uuid, $path, $password);
|
|
|
|
}
|
|
*/
|
|
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("UPDATE comprobante SET status = '0' WHERE comprobanteId = ".$comprobanteId);
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
|
|
|
|
$fileName = $xml.".pdf";
|
|
|
|
$path = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/1/facturas/pdf/".$fileName;
|
|
|
|
//$pdf =& new FPDI();
|
|
$pdf = new FPDI();
|
|
|
|
$pagecount = $pdf->setSourceFile($path);
|
|
$tplidx = $pdf->importPage(1, '/MediaBox');
|
|
|
|
$pdf->addPage();
|
|
$pdf->useTemplate($tplidx, 0, 0, 210);
|
|
|
|
$pdf->AddFont('verdana','','verdana.php');
|
|
$pdf->SetFont('verdana','',72);
|
|
|
|
$pdf->SetY(100);
|
|
$pdf->SetX(10);
|
|
$pdf->SetTextColor(200, 0, 0);
|
|
$pdf->Cell(20,10,"CANCELADO",0,0,'L');
|
|
$pdf->Output($path, 'F');
|
|
|
|
$this->Util()->setError('', "complete", "El folio ha sido cancelado correctamente.");
|
|
$this->Util()->PrintErrors();
|
|
|
|
return true;
|
|
|
|
}//CancelarComprobante
|
|
|
|
|
|
function GetTotalDesglosado($data)
|
|
{
|
|
if(!$_SESSION["conceptos"])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
$data["subtotal"] = 0;
|
|
$data["descuento"] = 0;
|
|
$data["iva"] = 0;
|
|
$data["ieps"] = 0;
|
|
$data["retIva"] = 0;
|
|
$data["retIsr"] = 0;
|
|
$data["total"] = 0;
|
|
|
|
foreach($data as $key => $value)
|
|
{
|
|
$data[$key] = $this->Util()->RoundNumber($data[$key]);
|
|
}
|
|
|
|
foreach($_SESSION["conceptos"] as $key => $concepto)
|
|
{
|
|
|
|
//cada concepto correrle los impuestos extra.
|
|
if($_SESSION["impuestos"])
|
|
{
|
|
$importe = $concepto["importe"];
|
|
foreach($_SESSION["impuestos"] as $keyImpuesto => $impuesto)
|
|
{
|
|
// print_r($impuesto);
|
|
//impuesto extra, suma
|
|
if($_SESSION["impuestos"][$keyImpuesto]["importe"] != 0)
|
|
{
|
|
// echo $_SESSION["impuestos"][$keyImpuesto]["importe"];
|
|
if($impuesto["tipo"] == "impuesto")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] + $_SESSION["impuestos"][$keyImpuesto]["importe"];
|
|
}
|
|
elseif($impuesto["tipo"] == "retencion")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
|
|
}
|
|
elseif($impuesto["tipo"] == "deduccion")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
|
|
}
|
|
elseif($impuesto["tipo"] == "amortizacion")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if($impuesto["tipo"] == "impuesto")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] + ($importe * ($impuesto["tasa"] / 100));
|
|
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
|
|
}
|
|
elseif($impuesto["tipo"] == "retencion")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] - ($importe * ($impuesto["tasa"] / 100));
|
|
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
|
|
}
|
|
elseif($impuesto["tipo"] == "deduccion")
|
|
{
|
|
$concepto["importe"] = $concepto["importe"] - ($importe * ($impuesto["tasa"] / 100));
|
|
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
|
|
}
|
|
|
|
}//foreach
|
|
}//impuestos
|
|
|
|
$data["subtotal"] = $this->Util()->RoundNumber($data["subtotal"] + $concepto["importe"]);
|
|
if($concepto["excentoIva"] == "si")
|
|
{
|
|
$_SESSION["conceptos"][$key]["tasaIva"] = 0;
|
|
}
|
|
else
|
|
{
|
|
$_SESSION["conceptos"][$key]["tasaIva"] = $data["tasaIva"];
|
|
}
|
|
//porcentaje de descuento
|
|
if($data["porcentajeDescuento"])
|
|
{
|
|
$data["porcentajeDescuento"];
|
|
}
|
|
|
|
$data["descuentoThis"] = $this->Util()->RoundNumber($_SESSION["conceptos"][$key]["importe"] * ($data["porcentajeDescuento"] / 100));
|
|
$data["descuento"] += $data["descuentoThis"];
|
|
|
|
$afterDescuento = $_SESSION["conceptos"][$key]["importe"] - $data["descuentoThis"];
|
|
if($concepto["excentoIva"] == "si")
|
|
{
|
|
$_SESSION["conceptos"][$key]["tasaIva"] = 0;
|
|
}
|
|
else
|
|
{
|
|
$_SESSION["conceptos"][$key]["tasaIva"] = $data["tasaIva"];
|
|
}
|
|
|
|
$data["ivaThis"] = $this->Util()->RoundNumber($afterDescuento * ($_SESSION["conceptos"][$key]["tasaIva"] / 100));
|
|
$data["iva"] += $data["ivaThis"];
|
|
$data["valorUnitario"] = $concepto["valorUnitario"];
|
|
$concepto["importe"] = $importe;
|
|
|
|
}
|
|
|
|
$afterDescuento = $data["subtotal"] - $data["descuento"];
|
|
//ieps de descuento
|
|
if(!$data["porcentajeIEPS"])
|
|
{
|
|
$data["porcentajeIEPS"] = 0;
|
|
}
|
|
$data["ieps"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeIEPS"] / 100));
|
|
$afterImpuestos = $afterDescuento + $data["iva"] + $data["ieps"];
|
|
|
|
$data["retIva"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeRetIva"] / 100));
|
|
$data["retIsr"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeRetIsr"] / 100));
|
|
$data["total"] = $this->Util()->RoundNumber($data["subtotal"] - $data["descuento"] + $data["iva"] + $data["ieps"] - $data["retIva"] - $data["retIsr"]);
|
|
|
|
return $data;
|
|
}
|
|
|
|
protected function GetTipoComprobante($value)
|
|
{
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT tipoDeComprobante FROM tiposComprobante WHERE tiposComprobanteId = ".$value." LIMIT 1");
|
|
return $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
|
|
}
|
|
|
|
|
|
function GenerarSello($cadenaOriginal, $md5)
|
|
{
|
|
global $rfc;
|
|
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/";
|
|
|
|
if(!is_dir($root))
|
|
{
|
|
mkdir($root, 0777);
|
|
}
|
|
|
|
|
|
$data["certificado"] = $arr['noCertificado'];
|
|
$rfcActivo = $rfc->getRfcActive();
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/";
|
|
|
|
if(!is_dir($root))
|
|
{
|
|
mkdir($root, 0777);
|
|
}
|
|
|
|
if ($handle = opendir($root))
|
|
{
|
|
while (false !== ($file = readdir($handle)))
|
|
{
|
|
$ext = substr($file, -7);
|
|
if($ext == "cer.pem")
|
|
{
|
|
$cert = $file;
|
|
}
|
|
|
|
if($ext == "key.pem")
|
|
{
|
|
$key = $file;
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir($handle);
|
|
|
|
$file=$root.$key; // Ruta al archivo
|
|
|
|
//write md5 to txt
|
|
$fp = fopen ($root."/md5.txt", "w+");
|
|
fwrite($fp, $md5);
|
|
fclose($fp);
|
|
|
|
|
|
//sign the original md5 with private key
|
|
exec("openssl dgst -sha1 -sign ".$file." -out ".$root."/md5sha1.txt ".$root."/md5.txt");
|
|
|
|
$myFile = $root."/md5sha1.txt";
|
|
$fh = fopen($myFile, 'r');
|
|
$theData = fread($fh, filesize($myFile));
|
|
fclose($fh);
|
|
//generate public
|
|
exec("openssl rsa -in ".$file." -pubout -out ".$root."/publickey.txt");
|
|
|
|
//verify
|
|
exec("openssl dgst -sha1 -verify ".$root."/publickey.txt -out ".$root."/verified.txt -signature ".$root."/md5sha1.txt ".$root."/md5.txt");
|
|
|
|
$cadenaOriginalDecoded = utf8_decode($cadenaOriginal);
|
|
|
|
$file = $root.$cert; // Ruta al archivo
|
|
$datos = file($file);
|
|
$data["certificado"] = "";
|
|
$carga=false;
|
|
for ($i=0; $i<sizeof($datos); $i++)
|
|
{
|
|
if (strstr($datos[$i],"END CERTIFICATE")) $carga=false;
|
|
if ($carga)
|
|
{
|
|
$data["certificado"] .= trim($datos[$i]);
|
|
|
|
}
|
|
if (strstr($datos[$i],"BEGIN CERTIFICATE")) $carga=true;
|
|
}
|
|
$keyFile = $root.$key;
|
|
$pkeyid = openssl_get_privatekey(file_get_contents($root.$key));
|
|
// openssl_sign($cadenaOriginal, $crypttext, $pkeyid, OPENSSL_ALGO_SHA1);
|
|
openssl_sign($cadenaOriginalDecoded, $crypttext, $pkeyid, OPENSSL_ALGO_SHA1);
|
|
|
|
$data["sello"] = base64_encode($crypttext);
|
|
|
|
return $data;
|
|
}
|
|
|
|
function GenerarSelloGral($cadenaOriginal, $md5, $certificado, $llave, $pass, $id_rfc)
|
|
{
|
|
$id_empresa = $_SESSION['empresaId'];
|
|
|
|
$file = DOC_ROOT.'/empresas/'.$id_empresa.'/certificados/'.$id_rfc.'/'.$certificado.'.pem'; // Ruta al archivo
|
|
$root = DOC_ROOT.'/empresas/'.$id_empresa.'/certificados/'.$id_rfc;
|
|
|
|
//write md5 to txt
|
|
$fp = fopen ($root."/md5.txt", "w+");
|
|
fwrite($fp, $md5);
|
|
fclose($fp);
|
|
|
|
//generate .key.pem file
|
|
exec('openssl pkcs8 -inform DER -in '.$root.'/'.$certificado.' -out '.$root.'/'.$certificado.'.pem -passin pass:'.$pass);
|
|
|
|
//generate .cer.pem file
|
|
exec('openssl x509 -inform DER -outform PEM -in '.$root.'/'.$llave.' -out '.$root.'/'.$llave.'.pem');
|
|
|
|
//sign the original md5 with private key
|
|
exec("openssl dgst -sha1 -sign ".$file." -out ".$root."/md5sha1.txt ".$root."/md5.txt");
|
|
|
|
//generate public
|
|
exec("openssl rsa -in ".$file." -pubout -out ".$root."/publickey.txt");
|
|
|
|
//verify
|
|
exec("openssl dgst -sha1 -verify ".$root."/publickey.txt -out ".$root."/verified.txt -signature ".$root."/md5sha1.txt ".$root."/md5.txt");
|
|
|
|
//changed 02 agosto
|
|
//generate merge
|
|
exec('openssl pkcs12 -export -out '.$root.'/'.$llave.'.pfx -inkey '.$root.'/'.$certificado.'.pem -in '.$root.'/'.$llave.'.pem -passout pass:'.$pass);
|
|
//changed 02 agosto
|
|
|
|
|
|
}//GenerarSelloGral
|
|
|
|
function GetLastComprobante()
|
|
{
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT * FROM comprobante ORDER BY comprobanteId DESC");
|
|
|
|
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
|
|
|
|
$row["path"] = urlencode(DOC_ROOT."/empresas/".$row["empresaId"]."/certificados/".$row["rfcId"]."/facturas/");
|
|
|
|
return $row;
|
|
}
|
|
|
|
function GetInfoComprobante($comprobanteId){
|
|
|
|
$sqlQuery = 'SELECT * FROM comprobante WHERE comprobanteId = "'.$comprobanteId.'"';
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sqlQuery);
|
|
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
|
|
|
|
return $row;
|
|
|
|
}//GetInfoComprobante
|
|
|
|
function GetComprobantesBySuc(){
|
|
|
|
global $rfc;
|
|
global $user;
|
|
|
|
$rfcId = $rfc->getRfcActive();
|
|
|
|
$sql = 'SELECT COUNT(*) FROM comprobante
|
|
WHERE rfcId = "'.$rfcId.'"
|
|
AND sucursalId = "'.$this->sucursalId.'"
|
|
AND facturaGlobal = "0"
|
|
ORDER BY fecha DESC';
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
$total = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
|
|
|
|
$pages = $this->Util->HandleMultipages($this->page, $total ,WEB_ROOT."/facturacion");
|
|
|
|
$sqlAdd = "LIMIT ".$pages["start"].", ".$pages["items_per_page"];
|
|
|
|
$sql = 'SELECT * FROM comprobante
|
|
WHERE rfcId = "'.$rfcId.'"
|
|
AND sucursalId = "'.$this->sucursalId.'"
|
|
AND facturaGlobal = "0"
|
|
ORDER BY fecha DESC '.$sqlAdd;
|
|
$this->Util()->DBSelect($_SESSION['empresaId'])->setQuery($sql);
|
|
$comprobantes = $this->Util()->DBSelect($_SESSION['empresaId'])->GetResult();
|
|
|
|
$data["items"] = $comprobantes;
|
|
$data["pages"] = $pages;
|
|
|
|
return $data;
|
|
|
|
}//GetComprobantesBySuc
|
|
|
|
function GetCompMensBySuc(){
|
|
|
|
global $rfc;
|
|
global $user;
|
|
|
|
$rfcId = $rfc->getRfcActive();
|
|
|
|
$sql = 'SELECT COUNT(*) FROM comprobante
|
|
WHERE rfcId = "'.$rfcId.'"
|
|
AND sucursalId = "'.$this->sucursalId.'"
|
|
AND facturaGlobal = "1"
|
|
ORDER BY fecha DESC';
|
|
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
|
|
$total = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
|
|
|
|
$pages = $this->Util->HandleMultipages($this->page, $total ,WEB_ROOT."/facturacion");
|
|
|
|
$sqlAdd = "LIMIT ".$pages["start"].", ".$pages["items_per_page"];
|
|
|
|
$sql = 'SELECT * FROM comprobante
|
|
WHERE rfcId = "'.$rfcId.'"
|
|
AND sucursalId = "'.$this->sucursalId.'"
|
|
AND facturaGlobal = "1"
|
|
ORDER BY fecha DESC '.$sqlAdd;
|
|
$this->Util()->DBSelect($_SESSION['empresaId'])->setQuery($sql);
|
|
$comprobantes = $this->Util()->DBSelect($_SESSION['empresaId'])->GetResult();
|
|
|
|
$data["items"] = $comprobantes;
|
|
$data["pages"] = $pages;
|
|
|
|
return $data;
|
|
|
|
}//GetCompMensBySuc
|
|
|
|
function SearchComprobantesByRfc($values){
|
|
|
|
global $user;
|
|
|
|
$sqlSearch = '';
|
|
|
|
if($values['rfc']){
|
|
$sqlSearch .= ' AND u.rfc LIKE "%'.$values['rfc'].'%"';
|
|
}//if
|
|
|
|
if($values['nombre']){
|
|
$sqlSearch .= ' AND u.nombre LIKE "%'.$values['nombre'].'%"';
|
|
}//if
|
|
|
|
if($values['mes']){
|
|
$sqlSearch .= ' AND EXTRACT(MONTH FROM c.fecha) = '.$values['mes'];
|
|
}//if
|
|
|
|
if($values['anio'])
|
|
$sqlSearch .= ' AND EXTRACT(YEAR FROM c.fecha) = '.intval($values['anio']);
|
|
|
|
if($values['status_activo'] != '')
|
|
$sqlSearch .= ' AND c.status = "'.$values['status_activo'].'"';
|
|
|
|
if($values['comprobante'])
|
|
$sqlSearch .= ' AND c.tiposComprobanteId = '.$values['comprobante'];
|
|
|
|
if($values['sucursal'])
|
|
$sqlSearch .= ' AND c.sucursalId = '.$values['sucursal'];
|
|
|
|
|
|
$id_rfc = $this->getRfcActive();
|
|
|
|
$sqlQuery = 'SELECT
|
|
c.*
|
|
FROM
|
|
comprobante AS c,
|
|
cliente AS u
|
|
WHERE
|
|
c.userId = u.userId
|
|
AND c.rfcId = '.$id_rfc.$sqlSearch.'
|
|
ORDER BY
|
|
c.fecha DESC';
|
|
|
|
$id_empresa = $_SESSION['empresaId'];
|
|
|
|
$this->Util()->DBSelect($id_empresa)->setQuery($sqlQuery);
|
|
$comprobantes = $this->Util()->DBSelect($id_empresa)->GetResult();
|
|
|
|
$info = array();
|
|
foreach($comprobantes as $key => $val){
|
|
|
|
$user->setUserId($val['userId'],1);
|
|
$usr = $user->GetUserInfo();
|
|
$card['serie'] = $val['serie'];
|
|
$card['folio'] = $val['folio'];
|
|
$card['rfc'] = $usr['rfc'];
|
|
$card['nombre'] = $usr['nombre'];
|
|
$card['fecha'] = date('d/m/Y',strtotime($val['fecha']));
|
|
$card['subTotal'] = $val['subTotal'];
|
|
$card['porcentajeDescuento'] = $val['porcentajeDescuento'];
|
|
$card['descuento'] = $val['descuento'];
|
|
$card['ivaTotal'] = $val['ivaTotal'];
|
|
$card['total'] = $val['total'];
|
|
$card['total_formato'] = number_format($val['total'],2,'.',',');
|
|
$card['tipoDeMoneda'] = $val['tipoDeMoneda'];
|
|
$card['tipoDeCambio'] = $val['tipoDeCambio'];
|
|
$card['porcentajeRetIva'] = $val['porcentajeRetIva'];
|
|
$card['porcentajeRetIsr'] = $val['porcentajeRetIsr'];
|
|
$card['porcentajeIEPS'] = $val['porcentajeIEPS'];
|
|
$card['comprobanteId'] = $val['comprobanteId'];
|
|
$card['status'] = $val['status'];
|
|
|
|
$card['tickets'] = $this->GetRangeTicketsByComp($val['comprobanteId']);
|
|
|
|
$info[$key] = $card;
|
|
|
|
}//foreach
|
|
|
|
$data["items"] = $info;
|
|
$data["pages"] = $pages;
|
|
|
|
return $data;
|
|
|
|
}//SearchComprobantesByRfc
|
|
|
|
function GenerateQR($data, $totales, $nodoEmisor, $nodoReceptor, $empresa, $serie)
|
|
{
|
|
global $rfc;
|
|
|
|
$total = $this->Util()->RoundNumber($totales["total"], 6);
|
|
$total = $this->Util()->PadStringLeft(number_format($total, 6, ".", ""), 14, "0");
|
|
$cadenaCodigoBarras = "?re=".$data["nodoEmisor"]["rfc"]["rfc"]."&rr=".$nodoReceptor["rfc"]."&tt=".$total."&id=".$data["timbreFiscal"]["UUID"];
|
|
|
|
$nufa = $empresa["empresaId"]."_".$serie["serie"]."_".$data["folio"];
|
|
|
|
$rfcActivo = $rfc->getRfcActive();
|
|
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/qr/";
|
|
$rootFacturas = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/";
|
|
|
|
if(!is_dir($rootFacturas))
|
|
{
|
|
mkdir($rootFacturas, 0777);
|
|
}
|
|
|
|
if(!is_dir($root))
|
|
{
|
|
mkdir($root, 0777);
|
|
}
|
|
|
|
//$pdf->Output($root.$nufa.".pdf", "F");
|
|
QRcode::png($cadenaCodigoBarras, $root.$nufa.".png", 'L', 4, 2);
|
|
|
|
}
|
|
|
|
}//Comprobante
|
|
|
|
|
|
require(DOC_ROOT.'/pdf/fpdf.php');
|
|
require(DOC_ROOT.'/pdf/fpdi.php');
|
|
|
|
class PDF extends FPDF
|
|
{
|
|
|
|
var $widths;
|
|
var $aligns;
|
|
//Page header
|
|
function Header()
|
|
{
|
|
//Logo
|
|
//Arial bold 15
|
|
$this->SetFont('Arial','B',10);
|
|
$this->SetY(0);
|
|
$this->SetX(0);
|
|
$this->Cell(70,10,'http://novomoda.ddns.net',0,0,'C');
|
|
//Line break
|
|
$this->Ln(20);
|
|
}
|
|
|
|
//Page footer
|
|
function Footer()
|
|
{
|
|
//Position at 1.5 cm from bottom
|
|
$this->SetY(-8);
|
|
//Arial italic 8
|
|
$this->SetFont('Arial','I',8);
|
|
//Page number
|
|
$this->Cell(0,10,$this->PageNo().'/{nb}',0,0,'C');
|
|
|
|
}
|
|
|
|
function RoundedRect($x, $y, $w, $h, $r, $style = '', $angle = '1234')
|
|
{
|
|
$k = $this->k;
|
|
$hp = $this->h;
|
|
if($style=='F')
|
|
$op='f';
|
|
elseif($style=='FD' or $style=='DF')
|
|
$op='B';
|
|
else
|
|
$op='S';
|
|
$MyArc = 4/3 * (sqrt(2) - 1);
|
|
$this->_out(sprintf('%.2f %.2f m', ($x+$r)*$k, ($hp-$y)*$k ));
|
|
|
|
$xc = $x+$w-$r;
|
|
$yc = $y+$r;
|
|
$this->_out(sprintf('%.2f %.2f l', $xc*$k, ($hp-$y)*$k ));
|
|
if (strpos($angle, '2')===false)
|
|
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-$y)*$k ));
|
|
else
|
|
$this->_Arc($xc + $r*$MyArc, $yc - $r, $xc + $r, $yc - $r*$MyArc, $xc + $r, $yc);
|
|
|
|
$xc = $x+$w-$r;
|
|
$yc = $y+$h-$r;
|
|
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-$yc)*$k));
|
|
if (strpos($angle, '3')===false)
|
|
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-($y+$h))*$k));
|
|
else
|
|
$this->_Arc($xc + $r, $yc + $r*$MyArc, $xc + $r*$MyArc, $yc + $r, $xc, $yc + $r);
|
|
|
|
$xc = $x+$r;
|
|
$yc = $y+$h-$r;
|
|
$this->_out(sprintf('%.2f %.2f l', $xc*$k, ($hp-($y+$h))*$k));
|
|
if (strpos($angle, '4')===false)
|
|
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-($y+$h))*$k));
|
|
else
|
|
$this->_Arc($xc - $r*$MyArc, $yc + $r, $xc - $r, $yc + $r*$MyArc, $xc - $r, $yc);
|
|
|
|
$xc = $x+$r ;
|
|
$yc = $y+$r;
|
|
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-$yc)*$k ));
|
|
if (strpos($angle, '1')===false)
|
|
{
|
|
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-$y)*$k ));
|
|
$this->_out(sprintf('%.2f %.2f l', ($x+$r)*$k, ($hp-$y)*$k ));
|
|
}
|
|
else
|
|
$this->_Arc($xc - $r, $yc - $r*$MyArc, $xc - $r*$MyArc, $yc - $r, $xc, $yc - $r);
|
|
$this->_out($op);
|
|
}
|
|
|
|
function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
|
|
{
|
|
$h = $this->h;
|
|
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c ', $x1*$this->k, ($h-$y1)*$this->k,
|
|
$x2*$this->k, ($h-$y2)*$this->k, $x3*$this->k, ($h-$y3)*$this->k));
|
|
}
|
|
|
|
function WordWrap(&$text, $maxwidth)
|
|
{
|
|
$text = trim($text);
|
|
if ($text==='')
|
|
return 0;
|
|
$space = $this->GetStringWidth(' ');
|
|
$lines = explode("\n", $text);
|
|
$text = '';
|
|
$count = 0;
|
|
|
|
foreach ($lines as $line)
|
|
{
|
|
$words = preg_split('/ +/', $line);
|
|
$width = 0;
|
|
|
|
foreach ($words as $word)
|
|
{
|
|
$wordwidth = $this->GetStringWidth($word);
|
|
if ($width + $wordwidth <= $maxwidth)
|
|
{
|
|
$width += $wordwidth + $space;
|
|
$text .= $word.' ';
|
|
}
|
|
else
|
|
{
|
|
$width = $wordwidth + $space;
|
|
$text = rtrim($text)."\n".$word.' ';
|
|
$count++;
|
|
}
|
|
}
|
|
$text = rtrim($text)."\n";
|
|
$count++;
|
|
}
|
|
$text = rtrim($text);
|
|
return $count;
|
|
}
|
|
|
|
function SetWidths($w)
|
|
{
|
|
//Set the array of column widths
|
|
$this->widths=$w;
|
|
}
|
|
|
|
function SetAligns($a)
|
|
{
|
|
//Set the array of column alignments
|
|
$this->aligns=$a;
|
|
}
|
|
|
|
function Row($data, $pixelHeight = 5)
|
|
{
|
|
//Calculate the height of the row
|
|
$nb=0;
|
|
for($i=0;$i<count($data);$i++)
|
|
$nb=max($nb, $this->NbLines($this->widths[$i], $data[$i]));
|
|
$h=$pixelHeight * $nb;
|
|
//Issue a page break first if needed
|
|
$this->CheckPageBreak($h);
|
|
//Draw the cells of the row
|
|
for($i=0;$i<count($data);$i++)
|
|
{
|
|
$w=$this->widths[$i];
|
|
$a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
|
|
// print_r($a);
|
|
//Save the current position
|
|
$x=$this->GetX();
|
|
$y=$this->GetY();
|
|
//Draw the border
|
|
//$this->Rect($x, $y, $w, $h);
|
|
//Print the text
|
|
$this->MultiCell($w, $pixelHeight, $data[$i], 0, $a);
|
|
//Put the position to the right of the cell
|
|
$this->SetXY($x+$w, $y);
|
|
}
|
|
//Go to the next line
|
|
$this->Ln($h);
|
|
}
|
|
|
|
function CheckPageBreak($h)
|
|
{
|
|
//If the height h would cause an overflow, add a new page immediately
|
|
if($this->GetY()+$h>$this->PageBreakTrigger)
|
|
$this->AddPage($this->CurOrientation);
|
|
}
|
|
|
|
function NbLines($w, $txt)
|
|
{
|
|
//Computes the number of lines a MultiCell of width w will take
|
|
$cw=&$this->CurrentFont['cw'];
|
|
if($w==0)
|
|
$w=$this->w-$this->rMargin-$this->x;
|
|
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
|
|
$s=str_replace("\r", '', $txt);
|
|
$nb=strlen($s);
|
|
if($nb>0 and $s[$nb-1]=="\n")
|
|
$nb--;
|
|
$sep=-1;
|
|
$i=0;
|
|
$j=0;
|
|
$l=0;
|
|
$nl=1;
|
|
while($i<$nb)
|
|
{
|
|
$c=$s[$i];
|
|
if($c=="\n")
|
|
{
|
|
$i++;
|
|
$sep=-1;
|
|
$j=$i;
|
|
$l=0;
|
|
$nl++;
|
|
continue;
|
|
}
|
|
if($c==' ')
|
|
$sep=$i;
|
|
$l+=$cw[$c];
|
|
if($l>$wmax)
|
|
{
|
|
if($sep==-1)
|
|
{
|
|
if($i==$j)
|
|
$i++;
|
|
}
|
|
else
|
|
$i=$sep+1;
|
|
$sep=-1;
|
|
$j=$i;
|
|
$l=0;
|
|
$nl++;
|
|
}
|
|
else
|
|
$i++;
|
|
}
|
|
return $nl;
|
|
}
|
|
}
|
|
|
|
class PDF_ImageAlpha extends PDF{
|
|
|
|
//Private properties
|
|
var $tmpFiles = array();
|
|
|
|
/*******************************************************************************
|
|
* *
|
|
* Public methods *
|
|
* *
|
|
*******************************************************************************/
|
|
function ImageX($file,$x,$y,$w=0,$h=0,$type='',$link='', $isMask=false, $maskImg=0)
|
|
{
|
|
//Put an image on the page
|
|
if(!isset($this->images[$file]))
|
|
{
|
|
//First use of image, get info
|
|
if($type=='')
|
|
{
|
|
$pos=strrpos($file,'.');
|
|
if(!$pos)
|
|
$this->Error('Image file has no extension and no type was specified: '.$file);
|
|
$type=substr($file,$pos+1);
|
|
}
|
|
$type=strtolower($type);
|
|
$mqr=@get_magic_quotes_runtime();
|
|
@set_magic_quotes_runtime(0);
|
|
if($type=='jpg' || $type=='jpeg')
|
|
$info=$this->_parsejpg($file);
|
|
elseif($type=='png'){
|
|
$info=$this->_parsepng($file);
|
|
if ($info=='alpha') return $this->ImagePngWithAlpha($file,$x,$y,$w,$h,$link);
|
|
}
|
|
else
|
|
{
|
|
//Allow for additional formats
|
|
$mtd='_parse'.$type;
|
|
if(!method_exists($this,$mtd))
|
|
$this->Error('Unsupported image type: '.$type);
|
|
$info=$this->$mtd($file);
|
|
}
|
|
@set_magic_quotes_runtime($mqr);
|
|
|
|
if ($isMask){
|
|
$info['cs']="DeviceGray"; // try to force grayscale (instead of indexed)
|
|
}
|
|
$info['i']=count($this->images)+1;
|
|
if ($maskImg>0) $info['masked'] = $maskImg;###
|
|
$this->images[$file]=$info;
|
|
}
|
|
else
|
|
$info=$this->images[$file];
|
|
//Automatic width and height calculation if needed
|
|
if($w==0 && $h==0)
|
|
{
|
|
//Put image at 72 dpi
|
|
$w=$info['w']/$this->k;
|
|
$h=$info['h']/$this->k;
|
|
}
|
|
if($w==0)
|
|
$w=$h*$info['w']/$info['h'];
|
|
if($h==0)
|
|
$h=$w*$info['h']/$info['w'];
|
|
|
|
if ($isMask) $x = ($this->CurOrientation=='P'?$this->CurPageFormat[0]:$this->CurPageFormat[1]) + 10; // embed hidden, ouside the canvas
|
|
$this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i']));
|
|
if($link)
|
|
$this->Link($x,$y,$w,$h,$link);
|
|
|
|
return $info['i'];
|
|
}
|
|
|
|
// needs GD 2.x extension
|
|
// pixel-wise operation, not very fast
|
|
function ImagePngWithAlpha($file,$x,$y,$w=0,$h=0,$link='')
|
|
{
|
|
$tmp_alpha = tempnam('.', 'mska');
|
|
$this->tmpFiles[] = $tmp_alpha;
|
|
$tmp_plain = tempnam('.', 'mskp');
|
|
$this->tmpFiles[] = $tmp_plain;
|
|
|
|
list($wpx, $hpx) = getimagesize($file);
|
|
$img = imagecreatefrompng($file);
|
|
$alpha_img = imagecreate( $wpx, $hpx );
|
|
|
|
// generate gray scale pallete
|
|
for($c=0;$c<256;$c++) ImageColorAllocate($alpha_img, $c, $c, $c);
|
|
|
|
// extract alpha channel
|
|
$xpx=0;
|
|
while ($xpx<$wpx){
|
|
$ypx = 0;
|
|
while ($ypx<$hpx){
|
|
$color_index = imagecolorat($img, $xpx, $ypx);
|
|
$alpha = 255-($color_index>>24)*255/127; // GD alpha component: 7 bit only, 0..127!
|
|
imagesetpixel($alpha_img, $xpx, $ypx, $alpha);
|
|
++$ypx;
|
|
}
|
|
++$xpx;
|
|
}
|
|
|
|
imagepng($alpha_img, $tmp_alpha);
|
|
imagedestroy($alpha_img);
|
|
|
|
// extract image without alpha channel
|
|
$plain_img = imagecreatetruecolor ( $wpx, $hpx );
|
|
imagecopy ($plain_img, $img, 0, 0, 0, 0, $wpx, $hpx );
|
|
imagepng($plain_img, $tmp_plain);
|
|
imagedestroy($plain_img);
|
|
|
|
//first embed mask image (w, h, x, will be ignored)
|
|
$maskImg = $this->ImageX($tmp_alpha, 0,0,0,0, 'PNG', '', true);
|
|
|
|
//embed image, masked with previously embedded mask
|
|
$this->ImageX($tmp_plain,$x,$y,$w,$h,'PNG',$link, false, $maskImg);
|
|
}
|
|
|
|
function Close()
|
|
{
|
|
parent::Close();
|
|
// clean up tmp files
|
|
foreach($this->tmpFiles as $tmp) @unlink($tmp);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* *
|
|
* Private methods *
|
|
* *
|
|
*******************************************************************************/
|
|
function _putimages()
|
|
{
|
|
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
|
|
reset($this->images);
|
|
foreach($this->images as $file => $info)
|
|
{
|
|
$this->_newobj();
|
|
$this->images[$file]['n']=$this->n;
|
|
$this->_out('<</Type /XObject');
|
|
$this->_out('/Subtype /Image');
|
|
$this->_out('/Width '.$info['w']);
|
|
$this->_out('/Height '.$info['h']);
|
|
|
|
if (isset($info["masked"])) $this->_out('/SMask '.($this->n-1).' 0 R'); ###
|
|
|
|
if($info['cs']=='Indexed')
|
|
$this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
|
|
else
|
|
{
|
|
$this->_out('/ColorSpace /'.$info['cs']);
|
|
if($info['cs']=='DeviceCMYK')
|
|
$this->_out('/Decode [1 0 1 0 1 0 1 0]');
|
|
}
|
|
$this->_out('/BitsPerComponent '.$info['bpc']);
|
|
if(isset($info['f']))
|
|
$this->_out('/Filter /'.$info['f']);
|
|
if(isset($info['parms']))
|
|
$this->_out($info['parms']);
|
|
if(isset($info['trns']) && is_array($info['trns']))
|
|
{
|
|
$trns='';
|
|
for($i=0;$i<count($info['trns']);$i++)
|
|
$trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
|
|
$this->_out('/Mask ['.$trns.']');
|
|
}
|
|
$this->_out('/Length '.strlen($info['data']).'>>');
|
|
$this->_putstream($info['data']);
|
|
unset($this->images[$file]['data']);
|
|
$this->_out('endobj');
|
|
//Palette
|
|
if($info['cs']=='Indexed')
|
|
{
|
|
$this->_newobj();
|
|
$pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
|
|
$this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
|
|
$this->_putstream($pal);
|
|
$this->_out('endobj');
|
|
}
|
|
}
|
|
}
|
|
|
|
// this method overwriing the original version is only needed to make the Image method support PNGs with alpha channels.
|
|
// if you only use the ImagePngWithAlpha method for such PNGs, you can remove it from this script.
|
|
function _parsepng($file)
|
|
{
|
|
//Extract info from a PNG file
|
|
$f=fopen($file,'rb');
|
|
if(!$f)
|
|
$this->Error('Can\'t open image file: '.$file);
|
|
//Check signature
|
|
if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
|
|
$this->Error('Not a PNG file: '.$file);
|
|
//Read header chunk
|
|
fread($f,4);
|
|
if(fread($f,4)!='IHDR')
|
|
$this->Error('Incorrect PNG file: '.$file);
|
|
$w=$this->_readint($f);
|
|
$h=$this->_readint($f);
|
|
$bpc=ord(fread($f,1));
|
|
if($bpc>8)
|
|
$this->Error('16-bit depth not supported: '.$file);
|
|
$ct=ord(fread($f,1));
|
|
if($ct==0)
|
|
$colspace='DeviceGray';
|
|
elseif($ct==2)
|
|
$colspace='DeviceRGB';
|
|
elseif($ct==3)
|
|
$colspace='Indexed';
|
|
else {
|
|
fclose($f); // the only changes are
|
|
return 'alpha'; // made in those 2 lines
|
|
}
|
|
if(ord(fread($f,1))!=0)
|
|
$this->Error('Unknown compression method: '.$file);
|
|
if(ord(fread($f,1))!=0)
|
|
$this->Error('Unknown filter method: '.$file);
|
|
if(ord(fread($f,1))!=0)
|
|
$this->Error('Interlacing not supported: '.$file);
|
|
fread($f,4);
|
|
$parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>';
|
|
//Scan chunks looking for palette, transparency and image data
|
|
$pal='';
|
|
$trns='';
|
|
$data='';
|
|
do
|
|
{
|
|
$n=$this->_readint($f);
|
|
$type=fread($f,4);
|
|
if($type=='PLTE')
|
|
{
|
|
//Read palette
|
|
$pal=fread($f,$n);
|
|
fread($f,4);
|
|
}
|
|
elseif($type=='tRNS')
|
|
{
|
|
//Read transparency info
|
|
$t=fread($f,$n);
|
|
if($ct==0)
|
|
$trns=array(ord(substr($t,1,1)));
|
|
elseif($ct==2)
|
|
$trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
|
|
else
|
|
{
|
|
$pos=strpos($t,chr(0));
|
|
if($pos!==false)
|
|
$trns=array($pos);
|
|
}
|
|
fread($f,4);
|
|
}
|
|
elseif($type=='IDAT')
|
|
{
|
|
//Read image data block
|
|
$data.=fread($f,$n);
|
|
fread($f,4);
|
|
}
|
|
elseif($type=='IEND')
|
|
break;
|
|
else
|
|
fread($f,$n+4);
|
|
}
|
|
while($n);
|
|
if($colspace=='Indexed' && empty($pal))
|
|
$this->Error('Missing palette in '.$file);
|
|
fclose($f);
|
|
return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data);
|
|
}
|
|
}
|
|
|
|
|
|
?>
|