unit FacturaEv40;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, StrUtils, DateUtils, xmldom, XMLIntf, msxmldom,
  XMLDoc, DB, FIBDataSet, pFIBDataSet, cfdv40, FIBQuery, pFIBQuery,
  pFIBStoredProc, SBEncoding, SBPublicKeyCrypto, SBConstants, SBX509,
  SBTypes,  SBUtils, SBCryptoProv, FIBDatabase, pFIBDatabase, AES, base64,
  SBCertValidator, SBSimpleSSL, SBHTTPSClient,
  SBHTTPCRL, SBHTTPOCSPClient, SBHTTPCertRetriever, SBSSLClient, SBSSLCommon, Math,
  SBSocket, frxClass, frxExportPDF, IdBaseComponent, IdCoder, IdCoder3to4,
  IdCoderMIME, frxFIBComponents, pCore2D, pBarcode2D, pQRCode, frxBarcode, CHILKATMAILLib2_TLB,
  ExtCtrls, Vcl.StdCtrls;

type
TFacturaEFormV40 = class(TForm)
	OpenDialog: TOpenDialog;
    dsInformacion: TpFIBDataSet;
    dsConceptos: TpFIBDataSet;
    dsQuery1: TpFIBDataSet;
    dsQuery2: TpFIBDataSet;
    dsLugExpDoctosPV: TpFIBDataSet;
    dsFormasCobro: TpFIBDataSet;
    dsFormasCobroNOMBRE: TFIBStringField;
    dsFormasCobroCLAVE_FISCAL: TFIBStringField;
    spGenDoctoId: TpFIBStoredProc;
    dsLugExpRegistry: TpFIBDataSet;
    dsLugExpDoctosPVCODIGO_POSTAL: TFIBStringField;
    dsLugExpRegistryVALOR: TFIBStringField;
    dsConceptosARTICULO_ID: TFIBIntegerField;
    dsConceptosNOMBRE: TFIBStringField;
    dsConceptosUNIDAD_VENTA: TFIBStringField;
    dsConceptosCLAVE_ARTICULO: TFIBStringField;
    dsConceptosPRECIO_TOTAL_NETO: TFIBBCDField;
    dsConceptosUNIDADES: TFIBFloatField;
    dsConceptosNOTAS: TFIBMemoField;
    dsConceptosPRECIO_UNITARIO: TFIBFloatField;
    dsConceptosPOSICION: TFIBIntegerField;
    dsConceptosDOCTO_PV_DET_ID: TFIBIntegerField;
    dsConceptosDSCTO_ART: TFIBBCDField;
    dsConceptosCLAVE_ART_SAT: TFIBStringField;
    dsConceptosCLAVE_MEDIDA_SAT: TFIBStringField;
    XMLDoc: TXMLDocument;
    XMLDocCopy: TXMLDocument;
    xmlFac: TXMLDocument;
    dsDoctoPv: TpFIBDataSet;
    dsDoctoPvDet: TpFIBDataSet;
    dsFormasCobroCC40: TpFIBDataSet;
    spCalcTotalesPV: TpFIBStoredProc;
    spCopiaFteDestPV: TpFIBStoredProc;
    IBQuery2: TpFIBDataSet;
    dsDatosAlmacen40: TpFIBDataSet;
    dsPedimentosPv: TpFIBDataSet;
    dsEmpresa: TpFIBDataSet;
    IBQuery: TpFIBDataSet;
    IBDatabase1: TpFIBDatabase;
    trTrans: TpFIBTransaction;
    IBQuery4: TpFIBDataSet;
    IBQuery3: TpFIBDataSet;
    xmlFacCopy: TXMLDocument;
    xmlTimbre: TXMLDocument;
    HTTPSClient: TElHTTPSClient;
    CertificateValidator: TElX509CertificateValidator;
    IdEncoderMIME1: TIdEncoderMIME;
    frxFIBComponents1: TfrxFIBComponents;
    frxReport1: TfrxReport;
    ExportPDF: TfrxPDFExport;
    frxBarCodeObject1: TfrxBarCodeObject;
    xmlWebservice: TXMLDocument;
    spGenCatId: TpFIBStoredProc;
    dsDoctosVe: TpFIBDataSet;
    dsDoctosVeDet: TpFIBDataSet;
    dsFormasCobroCC: TpFIBDataSet;
    dsLugExpDoctosVe: TpFIBDataSet;
    spCalcTotVe: TpFIBStoredProc;
    spAplicaVe: TpFIBStoredProc;
    dsPedimentosVE: TpFIBDataSet;
    FIBIntegerField1: TFIBIntegerField;
    FIBStringField1: TFIBStringField;
    FIBDateField1: TFIBDateField;
    FIBStringField2: TFIBStringField;
    dsDoctoPvDet40_IEPS_Inc: TpFIBDataSet;
    spCalcTotalesPVIEPS: TpFIBStoredProc;
    spRoundProd: TpFIBStoredProc;
    dsDoctoFte: TpFIBDataSet;
    dsIEPS_VE: TpFIBDataSet;
    dsIEPS_VE_P: TpFIBDataSet;
    dsDoctoVeDet40_IEPS_Inc: TpFIBDataSet;
    spCalcTotalesVEIEPS: TpFIBStoredProc;
    dsIEPS_PV: TpFIBDataSet;
    dsIEPS: TpFIBDataSet;
    dsDatosEmisor: TpFIBDataSet;
    procedure HTTPSClientCertificateValidate(Sender: TObject;
            Certificate: TElX509Certificate; var Validity: TSBCertificateValidity;
            var Reason: TSBCertificateValidityReason);
    procedure HTTPSClientCloseConnection(Sender: TObject;
      CloseReason: TSBCloseReason);
    procedure HTTPSClientData(Sender: TObject; Buffer: Pointer; Size: Integer);
    procedure HTTPSClientRedirection(Sender: TObject; const OldURL: string;
      var NewURL: string; var AllowRedirection: Boolean);
    procedure HTTPSClientDocumentBegin(Sender: TObject);
    procedure HTTPSClientDocumentEnd(Sender: TObject);
    procedure HTTPSClientPreparedHeaders(Sender: TObject;
      Headers: TElStringList);
    procedure HTTPSClientReceivingHeaders(Sender: TObject;
      Headers: TElStringList);
private
public
  const   CLAVE = 'MICROSIP4856';
  var gCertVerif : TElX509Certificate;
  gCertificado, gCadenaOriginal, gNoCertificado, gSello, gNoAprobacion, gAnoAprobacion:String;


  gPathCertificado,gPathLlave,gContrasena,gVERCFDI:String;
  gUrlTimbre,gUsuarioTimbre,gPassTimbre:String;

  //Crea PDF
  gSelloDigital, gFechaXml,gRfcEmisor,gRfcReceptor, gCadenaOriginalTimbre,gUUID,gSelloSat,
  gCertificadoSAT,gFechaTimbrado,gSelloCFD,gAnoAprob,gmetodoPagoSat:String;
  CFDI40: IXMLComprobante;

	CFD : IXMLComprobante; //CFD *solo* representa el Nodo <Comprobante>; para operaciones de in/out usar el objeto XMLDoc
  CFDAux : IXMLComprobante;
	CadOriginal : WideString;
  gFechaDocumento:TDatetime;

  gXml40:AnsiString;
  FolioFacVENuew, gEmailEnvio :String;

  function AbrirSellos(PathCert,PathKey,Password:String; Var Error:String):Boolean;
  function ValidaCadena(Cadena:String):String;
  function InsertaAdd(DoctoId:Integer; Modulo:String):String;
  function SellaFactura(Cert:TElX509Certificate; CadOriginal:WideString):String;
  procedure GeneraCadenaOriginalCFDI40(CFDIxml:TXMLDocument);

  function InsertFacturaElectronica(DoctoVeId:Integer; xmlFactura:TXMLDocument; Modulo:String; Var Error:String ):Boolean;

  function CreaDoctoVe(DoctoPedID, LugarExp, ConsigId, FormaCobroId :Integer; serie, UsoCFDI, lDescripcion:String; Var Error:String ):Integer;
  function NuevoDoctoVe(pedId, LugarExp, dirCliId:Integer; tipoDocto, folio, UsoCFDI, lDescripcion:String; Var Error:String):Integer;
  function RenglonDoctoVe(pedId, pedDetId, doctoVeId, articuloId:Integer; unidades, precio, importe, pctjeDscto, dsctoArt,
          pctjeDsctoCli, dsctoExtra, pctjeDsctoVol, pctjeDsctoPromo, pctjeComis:Double; rol, notas, claArt:String; Var Error:String):Boolean;
  function ObtenerDoctoId():Integer;
  function ModificaFoliosSiguientes(consecutivo:Double; serieId:Integer; Var Error:String):Boolean;
  function GeneraXmlVe40(DoctoVeId:Integer; TipoComp:String; {F,D} Var Error:String ):WideString;
  function NumPed(CadNumPed:String):String;
  function GeneraXmlPv40(DoctoPvId:Integer; TipoComp:String; Var Error:String ):WideString;

  function Conexion(StringConexion:String; Var Error:String):Boolean;
  function LeerParams(Parametro:String; NoParam:Integer):String;
  function ValidacionesTicket(Folio, SistemaOrigen :String; Var Error:String; var FolDoc, TipoDoc, OCompra:String):Integer;
  function GetPrefer(Nombre:String):String;
  function descifrarTexto(Str : String): String;

  function Rellena(cadena:String; Var SerieVnta:String):string;
  function AgregaConsig(ConsigId,ClienteId:Integer; Var Error:String ):Integer;
  function GetDoctoId():Integer;
  function ValidarDatosCliente(ConsigId:Integer):String;
  procedure GetDatosFac();
  function ValidarRFC(RFC:String):String;
  function ContieneNumeros(Cadena:String):Boolean;
  function NuevaFacturaPv(MetodoPagoSAT,Serie,dDescripcion,ClaveCli,TipoDscto,ImpuestoIncluido,VUsoCFDI:String;
         TipoCambio,DsctoImpte,DsctoPctje:Double; ClienteId,ConsigId,CajaId,MonedaId,LugarExp:Integer; Fecha:TDateTime;
         Var Error:String):Integer;
  function AsignaFolioFactura(DoctoId:Integer; Serie,TipoDocto,Modulo:String; Var Error:String ):String;
  function AplicaDoctoPv(DoctoPvId:Integer; SoloLectura,ImptoIncluido:String; Var Error:String):Boolean;
  function FormasCobroPV(IdTicket,DoctoPvId:Integer; Var Error:String):Boolean;
  function CopiarDetallePv(DoctoOrigen,DoctoDest:Integer; ModifEncab : String; Var Error:String):Boolean;
  function TimbrarFac40(DoctoId:Integer; SisOrigen, Url,Usuario,Pass,Serie:String; Var Error:String):boolean;
  function CodigosError(Codigo:String):String;
  function InsertaRepositorio40(sXML:TXMLDocument; ConceptoId:Integer; var Error:String):Integer;
  function NumLet(mNum: Currency; iIdioma, iModo: Smallint):string;
  function VensionXML(XML:String):String;
  procedure ObtenerDatosFact40();
  function GeneraPDF(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;
  function CodificaPDF(PdfPath:String):widestring;
  function EnviaFacturas(DoctoPvId:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
  function ReemplazaPalabrasReservadas(Cadena,Cliente,Contrasena,Empresa,Factura:String):String;
  function EnvioMail(Smtp,Usuario,Pass,EnviadoPor,PuertoMail,Asunto,Mensaje,Mail,PDF,XML,SSL,TLS:String; Var ErrorEnvio:String):Boolean;
  function GeneraPDFEmail(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;
  function EnviaNotasCredito(DoctoPvId:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
  function EnviaPago(DoctoCCID:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
  function ProcesaFactura(CadenaXML:String; Var Error:String ):WideString;

  procedure GeneraJSonMongo(CFDIxml:TXMLDocument);

  function GetCatalogoId():Integer;
  function ValidarImporte(IdTicket:Integer;TipoDoc:String;TotalPagar:Double):String;
  function ValidarSucursales(SistemaOrigen, SistemaOrigen1, FolDoc:String; var ClientePublicoId:Integer; var Error:String):String;

  procedure ObtenerDatosFact40Pago();

  function InsertRFCS_LCO(RFC, NOMBRE_FISCAL, DOMICILIO_FISCAL:String; Var Error:String ):Boolean;
  function UpdateDIRS_CLIENTES(DIR_CLI_ID:Integer; TIPO_PERSONA, CLAVE_REGIMEN_FISCAL:String; Var Error:String ):Boolean;


end;

var
  FacturaEFormV40: TFacturaEFormV40;

implementation

uses Utils, Sello;

{$R *.dfm}
function TFacturaEFormV40.EnviaPago(DoctoCCID:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
var PathArchivos,TOTAL_LETRA,Smtp,Usuario,Pass,EnviadoPor,PuertoMail,
    Mensaje,Asunto,NombreEmpresa,Email,NombreCli,TipoFac,SSL,TLS:String;
    PDF,XML,ErrorEnvio:String;
    TotalPagar:Double;

    CfdiVe : IXMLComprobante;
    VersionXML:string;
begin

try
  begin
   sysutils.decimalseparator:='.';
   Result := False;
   Error := '';
   PathArchivos := GetPrefer('CarpetaArchivos');

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT NOMBRE FROM DATOS_EMPRESA ');
   IBQuery.Open;
   NombreEmpresa := IBQuery.FieldByName('NOMBRE').AsString;

{$REGION 'PV'}
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT D.NOMBRE AS CLIENTE ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_CC A ');
   IBQuery.SelectSQL.Add('INNER JOIN CLIENTES D ON (A.CLIENTE_ID = D.CLIENTE_ID) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES E ON (D.CLIENTE_ID = E.CLIENTE_ID) ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_CC_ID = :DOCTO_ID ');
   IBQuery.SelectSQL.Add('AND E.ES_DIR_PPAL = ''S'' ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoCCID;
   IBQuery.Open;
   NombreCli := IBQuery.FieldByName('CLIENTE').AsString;
   TipoFac := 'CFDI';

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT IMPORTE, IMPUESTO, IVA_RETENIDO, ISR_RETENIDO, DSCTO_PPAG, PCTJE_COMIS_COB ');
   IBQuery.SelectSQL.Add('FROM IMPORTES_DOCTOS_CC ');
   IBQuery.SelectSQL.Add('WHERE DOCTO_CC_ID = :DOCTO_CC_ID ');
   IBQuery.ParamByName('DOCTO_CC_ID').ASINTEGER := DoctoCCID;
   IBQuery.Open;
   TotalPagar := IBQuery.FieldByName('IMPORTE').asfloat;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.FOLIO, B.IMPORTE, C.SISTEMA, C.XML, E.EMAIL ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_CC A ');
   IBQuery.SelectSQL.Add('INNER JOIN IMPORTES_DOCTOS_CC B ON (A.DOCTO_CC_ID = B.DOCTO_CC_ID) ');
   IBQuery.SelectSQL.Add('INNER JOIN USOS_FOLIOS_FISCALES C ON (A.DOCTO_CC_ID = C.DOCTO_ID) ');
   IBQuery.SelectSQL.Add('INNER JOIN CLIENTES D ON (A.CLIENTE_ID = D.CLIENTE_ID) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES E ON (D.CLIENTE_ID = E.CLIENTE_ID) ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_CC_ID = :DOCTO_ID ');
   IBQuery.SelectSQL.Add('AND E.ES_DIR_PPAL = ''S'' ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoCCID;
   IBQuery.Open;

   if EmailAlterno = '' then
   begin
     Email := IBQuery.FieldByName('EMAIL').AsString;
     if Email = '' then
        raise Exception.Create('El cliente no tiene correo configurado.');
   end else
   begin
     Email := EmailAlterno;
   end;
{$ENDREGION}


   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.XML,A.FOLIOS_FISCALES_ID,A.USO_FOLIO_ID ');
   IBQuery.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = :SISTEMA ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoCCID;
   IBQuery.ParamByName('SISTEMA').AsString := 'CC';
   IBQuery.Open;

   xmlFac.XML.Text := IBQuery.FieldByName('XML').AsString;
   XML := PathArchivos+'\Pago_'+Folio+'.xml';
   xmlFac.Active := True;
   xmlFac.SaveToFile(XML);

   CfdiVe := GetComprobante(xmlFac);
   VersionXML := CfdiVe.Version;

   xmlTimbre.xml.Text := IBQuery.FieldByName('XML').AsString;

   TOTAL_LETRA := NUMLET(TotalPagar,1,1);

  if VersionXML = '4.0' then
      ObtenerDatosFact40Pago();

  GeneraPDFEmail(Folio,TOTAL_LETRA,MODULO,TipoFac,TotalPagar,DoctoCCID);

  PDF := PathArchivos+'\Pago'+Folio+'.pdf';

  Smtp := GetPrefer('SMPT');
  Usuario := GetPrefer('UsuarioMail');
  Pass := GetPrefer('PassMail'); //'Pruebas246';
  EnviadoPor := GetPrefer('EnviadoPorMail');
  PuertoMail := GetPrefer('PuertoMail');
  Mensaje := GetPrefer('MensajeMailPago');
  Asunto := GetPrefer('AsuntoMailPago');
  SSL := GetPrefer('SslMail');
  TLS := GetPrefer('TlsMail');

  Asunto := ReemplazaPalabrasReservadas(Asunto,NombreCli,'',NombreEmpresa,Folio);
  Mensaje := ReemplazaPalabrasReservadas(Mensaje,NombreCli,'',NombreEmpresa,Folio);

  if NOT FileExists(XML) then
      raise Exception.Create('No existe el XML.');
  if NOT FileExists(PDF) then
      raise Exception.Create('No existe el PDF');

  Error := '';

  ErrorEnvio := '';


  if not EnvioMail(Smtp,Usuario,Pass,EnviadoPor,PuertoMail,Asunto,Mensaje,Email,PDF,XML,SSL,TLS,ErrorEnvio) then
  begin
    Error := ErrorEnvio;
    Result := False;
  end else
  begin
    Error := '';
    Result := True;
  end;

  if ErrorEnvio <> '' then
      Error := ErrorEnvio;

  DeleteFile(PAnsiChar(XML));
  DeleteFile(PAnsiChar(PDF));
 end;
except on e : exception do
  begin
     Error := e.Message;
     Result := False;
  end;
end;

end;

function TFacturaEFormV40.EnviaNotasCredito(DoctoPvId:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
var PathArchivos,TOTAL_LETRA,Smtp,Usuario,Pass,EnviadoPor,PuertoMail,
    Mensaje,Asunto,NombreEmpresa,Email,NombreCli,TipoFac,SSL,TLS:String;
    PDF,XML,ErrorEnvio:String;
    TotalPagar:Double;

    CfdiVe : IXMLComprobante;
    VersionXML:string;
    SerieSC:String;
begin
   sysutils.decimalseparator:='.';
   Result := False;
   Error := '';
   PathArchivos := GetPrefer('CarpetaArchivos');

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT NOMBRE FROM DATOS_EMPRESA ');
   IBQuery.Open;
   NombreEmpresa := IBQuery.FieldByName('NOMBRE').AsString;

if Modulo = 'PV' then
begin
{$REGION 'PV'}
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT IIF (C.ES_DIR_PPAL = ''S'',B.NOMBRE,C.NOMBRE_CONSIG) NOMBRE_CLI ');
   IBQuery.SelectSQL.Add(', A.MODALIDAD_FACTURACION ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_PV A ');
   IBQuery.SelectSQL.Add('INNER JOIN CLIENTES B ON ( A.CLIENTE_ID = B.CLIENTE_ID ) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON ( C.DIR_CLI_ID = A.DIR_CLI_ID  ) ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID ');
   IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
   IBQuery.Open;
   NombreCli := IBQuery.FieldByName('NOMBRE_CLI').AsString;
   TipoFac := IBQuery.FieldByName('MODALIDAD_FACTURACION').AsString;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT TOTAL_A_PAGAR FROM CALC_TOTALES_DOCTO_PV(:DOCTO_PV_ID, ''S'',''N'',0 ) ');
   IBQuery.ParamByName('DOCTO_PV_ID').ASINTEGER := DoctoPvId;
   IBQuery.Open;
   TotalPagar := IBQuery.FieldByName('TOTAL_A_PAGAR').asfloat;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.DOCTO_PV_ID,B.XML,A.FOLIO,C.EMAIL ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_PV A ');
   IBQuery.SelectSQL.Add('INNER JOIN USOS_FOLIOS_FISCALES B ON ( A.DOCTO_PV_ID = B.DOCTO_ID ) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON (C.DIR_CLI_ID = A.DIR_CLI_ID) ');
   IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''C'' AND A.DOCTO_PV_ID = :DOCTO_PV_ID ');
   IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
   IBQuery.Open;

   if EmailAlterno = '' then
   begin
     Email := IBQuery.FieldByName('EMAIL').AsString;
     if Email = '' then
        raise Exception.Create('El cliente no tiene correo configurado.');
   end else
   begin
      Email := EmailAlterno;
   end;

{$ENDREGION}
end;
if Modulo = 'VE' then
begin
{$REGION 'VE'}
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT IIF (C.ES_DIR_PPAL = ''S'',B.NOMBRE,C.NOMBRE_CONSIG) NOMBRE_CLI ');
   IBQuery.SelectSQL.Add(', A.MODALIDAD_FACTURACION ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
   IBQuery.SelectSQL.Add('INNER JOIN CLIENTES B ON ( A.CLIENTE_ID = B.CLIENTE_ID ) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON ( C.DIR_CLI_ID = A.DIR_CLI_ID  ) ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
   IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPvId;
   IBQuery.Open;
   NombreCli := IBQuery.FieldByName('NOMBRE_CLI').AsString;
   TipoFac := IBQuery.FieldByName('MODALIDAD_FACTURACION').AsString;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT TOTAL_A_PAGAR FROM CALC_TOTALES_DOCTO_VE(:DOCTO_VE_ID, ''S'') ');
   IBQuery.ParamByName('DOCTO_VE_ID').ASINTEGER := DoctoPvId;
   IBQuery.Open;
   TotalPagar := IBQuery.FieldByName('TOTAL_A_PAGAR').asfloat;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID,B.XML,A.FOLIO,C.EMAIL ');
   IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
   IBQuery.SelectSQL.Add('INNER JOIN USOS_FOLIOS_FISCALES B ON ( A.DOCTO_VE_ID = B.DOCTO_ID ) ');
   IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON (C.DIR_CLI_ID = A.DIR_CLI_ID) ');
   IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''D'' AND A.DOCTO_VE_ID = :DOCTO_VE_ID ');
   IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPvId;
   IBQuery.Open;

   if EmailAlterno = '' then
   begin
     Email := IBQuery.FieldByName('EMAIL').AsString;
     if Email = '' then
        raise Exception.Create('El cliente no tiene correo configurado.');
   end else
   begin
      Email := EmailAlterno;
   end;
{$ENDREGION}
end;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.XML,A.FOLIOS_FISCALES_ID,A.USO_FOLIO_ID ');
   IBQuery.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = :SISTEMA ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoPvId;
   IBQuery.ParamByName('SISTEMA').AsString := MODULO;
   IBQuery.Open;

   xmlFac.XML.Text := IBQuery.FieldByName('XML').AsString;
   XML := PathArchivos+'\NotaCredito_'+Folio+'.xml';
   xmlFac.Active := True;
   xmlFac.SaveToFile(XML);

   CfdiVe := GetComprobante(xmlFac);
   VersionXML := CfdiVe.Version;

   xmlTimbre.xml.Text := IBQuery.FieldByName('XML').AsString;

   TOTAL_LETRA := NUMLET(TotalPagar,1,1);

  if VersionXML = '4.0' then
      ObtenerDatosFact40();

  GeneraPDFEmail(Folio,TOTAL_LETRA,MODULO,TipoFac,TotalPagar,DoctoPvId);

  Folio := Rellena(Folio, SerieSC);
  PDF := PathArchivos+'\NotaCredito_'+Folio+'.pdf';

  Smtp := GetPrefer('SMPT');
  Usuario := GetPrefer('UsuarioMail');
  Pass := GetPrefer('PassMail'); //'Pruebas246';
  EnviadoPor := GetPrefer('EnviadoPorMail');
  PuertoMail := GetPrefer('PuertoMail');
  Mensaje := GetPrefer('MensajeMailNC');
  Asunto := GetPrefer('AsuntoMailNC');
  SSL := GetPrefer('SslMail');
  TLS := GetPrefer('TlsMail');


  Asunto := ReemplazaPalabrasReservadas(Asunto,NombreCli,'',NombreEmpresa,Folio);
  Mensaje := ReemplazaPalabrasReservadas(Mensaje,NombreCli,'',NombreEmpresa,Folio);

  if NOT FileExists(XML) then
      raise Exception.Create('No existe el XML.');
  if NOT FileExists(PDF) then
      raise Exception.Create('No existe el archivo .rf3 para generar PDF del documento [1]'+PDF);

  Error := '';

  ErrorEnvio := '';

  gEmailEnvio := Email;
  if not EnvioMail(Smtp,Usuario,Pass,EnviadoPor,PuertoMail,Asunto,Mensaje,Email,PDF,XML,SSL,TLS,ErrorEnvio) then
  begin
    Error := ErrorEnvio;
    Result := False;
  end else
  begin
    Error := '';
    Result := True;
  end;


  if ErrorEnvio <> '' then
      Error := ErrorEnvio;

  DeleteFile(PAnsiChar(XML));
  DeleteFile(PAnsiChar(PDF));

end;

function TFacturaEFormV40.GeneraPDFEmail(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;
Var Image1: TImage;
Qrcode,str_qrcode:String;
ReportStream,ImagenStream:TStream;
PathGen,PathPdf,PathXml,Caracter, pdfpath:String;
Documento:String;
LengthSello, PosInicial :Integer;
SerieSC:String;
begin
    Result := '';
    sysutils.decimalseparator:='.';

    try
    begin
        image1 := TImage.Create(nil);
        Image1.Width := 132;
        Image1.Height := 144;
        PathGen := GetPrefer('CarpetaArchivos');

        // se agrego cosnulta para ver el tipo de documento Credito o Factura
        Documento := '';
        if Modulo = 'PV' then
        begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT TIPO_DOCTO FROM DOCTOS_PV WHERE DOCTO_PV_ID = :DOCTO_PV_ID ');
            IBQuery.ParamByName('DOCTO_PV_ID').ASINTEGER := IdDocto;
            IBQuery.Open;
            Documento := IBQuery.FieldByName('TIPO_DOCTO').AsString;
        end;

        if Modulo = 'VE' then
        begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT TIPO_DOCTO FROM DOCTOS_VE WHERE DOCTO_VE_ID = :DOCTO_VE_ID ');
            IBQuery.ParamByName('DOCTO_VE_ID').ASINTEGER := IdDocto;
            IBQuery.Open;
            Documento := IBQuery.FieldByName('TIPO_DOCTO').AsString;
        end;

        if Modulo = 'PA' then
        begin
            Documento := 'PA';
        end;

        if Documento = 'F' then
        begin
            if ((Modulo = 'VE') and (TipoFact='CFDI')) then
            begin
                ReportStream := TFileStream.Create(PathGen+'\Factura_VE_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
            end;
            if ((Modulo = 'VE') and (TipoFact='CFD')) then
            begin
                ReportStream := TFileStream.Create(PathGen+'\Factura_VE_CFD.fr3', fmOpenReadWrite or fmShareDenyWrite);
            end;

            if ((Modulo = 'PV') and (TipoFact = 'CFDI')) then
            begin
                ReportStream := TFileStream.Create(PathGen+'\Factura_PV_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
            end;
            if ((Modulo = 'PV') and (TipoFact='CFD')) then
            begin
                ReportStream := TFileStream.Create(PathGen+'\Factura_PV_CFD.fr3', fmOpenReadWrite or fmShareDenyWrite);
            end;
        end;

        if Documento = 'C' then
        begin
          if ((Modulo = 'PV') and (TipoFact = 'CFDI')) then
          begin
              ReportStream := TFileStream.Create(PathGen+'\Credito_PV_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
          end;
        end;

        if Documento = 'D' then
        begin
            if ((Modulo = 'VE') and (TipoFact='CFDI')) then
            begin
                ReportStream := TFileStream.Create(PathGen+'\Credito_VE_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
            end;
        end;

        if Documento = 'PA' then
        begin
            ReportStream := TFileStream.Create(PathGen+'\Pago_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
        end;

        frxReport1.LoadFromStream(ReportStream);

        if TipoFact = 'CFDI' then
        begin
          LengthSello := Length(gSelloDigital);
          PosInicial := LengthSello - 8;
          str_qrcode := 'https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?&id='+gUUID+'&re='+gRfcEmisor+'&rr='+gRfcReceptor+
          '&tt='+FormatFloat('#.00',TotalPagar )+'&fe='+Copy(gSelloDigital, PosInicial, 8);
          Qrcode := str_qrcode;
        end;

        frxReport1.Variables['DOCTO_ID'] := IdDocto;
        frxReport1.Variables['TT_LETRA'] := ''''+TotalLetra+'''';
        frxReport1.Variables['SELLO_DIGITAL'] := ''''+gSelloDigital+'''';
        frxReport1.Variables['CERTIFICADO'] := ''''+gNoCertificado+'''';


        if TipoFact = 'CFDI' then
        begin
            frxReport1.Variables['SELLO_SAT'] := ''''+gSelloSat+'''';
            frxReport1.Variables['QRCODE'] := ''''+Qrcode+'''';
            frxReport1.Variables['UUID'] := ''''+gUUID+'''';
            frxReport1.Variables['CERTIFICADO_SAT'] := ''''+gCertificadoSAT+'''';
            frxReport1.Variables['FECHA_TIMBRADO'] := ''''+gFechaTimbrado+'''';
            frxReport1.Variables['SELLO_CFD'] := ''''+gSelloCFD+'''';
            frxReport1.Variables['CADENA_ORIGINAL'] := ''''+gCadenaOriginalTimbre+'''';
        end;

        if TipoFact = 'CFD' then
        begin
            frxReport1.Variables['ANO_APROBACION'] := ''''+gANOAPROB+'''';
            frxReport1.Variables['NO_APROBACION'] := ''''+gnoaprobacion+'''';
            Caracter := '''';
            gCadenaOriginal := StringReplace(gCadenaOriginal,Caracter,'',[rfReplaceAll, rfIgnoreCase]);;
            frxReport1.Variables['CADENA_ORIGINAL'] := ''''+gCadenaOriginal+'''';
        end;

        frxReport1.PrepareReport(True);
        ExportPDF.DefaultPath := PathGen;

        if Documento = 'F' then
            ExportPDF.FileName := 'Factura_' + Rellena(Folio, SerieSC) + '.pdf';

        if Documento = 'C' then
            ExportPDF.FileName := 'NotaCredito_' + Rellena(Folio, SerieSC) + '.pdf';

        if Documento = 'D' then
            ExportPDF.FileName := 'NotaCredito_' + Rellena(Folio, SerieSC) + '.pdf';

        if Documento = 'PA' then
            ExportPDF.FileName := 'Pago' + Rellena(Folio, SerieSC) + '.pdf';

        ExportPDF.ShowDialog := false;
        frxReport1.Export(ExportPDF);

        FreeAndNil(ReportStream);
        pdfpath := PathGen+'\'+ExportPDF.FileName;

        if FileExists(pdfpath) then
            Result := CodificaPDF(pdfpath);

       end
       except on e : exception do
         begin
            ExportPDF.Free;
            FreeAndNil(ReportStream);
            if FileExists(Qrcode) then
                DeleteFile(PAnsiChar(Qrcode));
            raise Exception.Create('Ocurrió un error al generar el PDF. Error: '+e.Message);
         end;
       end;
end;

function TFacturaEFormV40.EnvioMail(Smtp,Usuario,Pass,EnviadoPor,PuertoMail,Asunto,Mensaje,Mail,PDF,XML,SSL,TLS:String; Var ErrorEnvio:String):Boolean;
Var mailman: TChilkatMailMan2;
email: CHILKATMAILLib2_TLB.IChilkatEmail2;
success : Integer;
contentType:String;
begin

  //  The mailman object is used for sending and receiving email.
  mailman := TChilkatMailMan2.Create(mailman);
  //  Any string argument automatically begins the 30-day trial.
  success := mailman.UnlockComponent('MICROSMAILQ_PdeCmWdwnL2G');
  if (success <> 1) then
  begin
    ErrorEnvio := 'Error de componente.';
    Result := False;
    Exit;
  end;

  mailman.SmtpHost := Smtp;
  mailman.SmtpUsername := Usuario;
  mailman.SmtpPassword := Pass;
  mailman.SmtpAuthMethod := 'LOGIN';
  mailman.SmtpSsl := StrToInt(SSL);
  mailman.SmtpPort := StrToInt(PuertoMail);
  mailman.StartTLS := StrToInt(TLS);

  email := CoChilkatEmail2.Create();

  email.From := Usuario;
  email.fromName := EnviadoPor;

  email.Subject := Asunto;
  email.Body := Mensaje;

  email.ClearTo;
  email.AddTo(Mail,Mail);
  email.Subject := Asunto;

  if PDF <> '' then
  begin
    if not FileExists(PDF) then
    begin
       ErrorEnvio := 'No existe el archivo .rf3 para generar PDF del documento';
       Result := False;
       exit;
    end;
    contentType := email.AddFileAttachment(PDF);
    if (contentType = NULL ) then
    begin
        Raise Exception.create(email.LastErrorText);
    end;
  end;

  if XML <> '' then
  begin
    if not FileExists(XML) then
    begin
       ErrorEnvio := 'Error: No Existe el documento XML.';
       Result := False;
       exit;
    end;
    contentType := email.AddFileAttachment(XML);
    if (contentType = NULL ) then
    begin
        Raise Exception.create(email.LastErrorText);
    end;
  end;


  success := mailman.SendEmail(email As CHILKATMAILLib2_TLB.IChilkatEmail2);
   if (success <> 1) then
   begin
      ErrorEnvio := 'Error: '+mailman.LastErrorText;
      Result := False;
      ExportPDF.Free;
      exit;
   end
   ELSE
   begin
      Result := True;
   end;


   FreeAndNil(mailman);

   Result := True;

end;

function TFacturaEFormV40.ReemplazaPalabrasReservadas(Cadena,Cliente,Contrasena,Empresa,Factura:String):String;
Var NuevaCad:String;
begin
  NuevaCad := Cadena;
  if Pos('[CONTRASENA]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[CONTRASENA]',Contrasena,[rfReplaceAll, rfIgnoreCase]);
  end;
  if Pos('[CLIENTE]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[CLIENTE]',Cliente,[rfReplaceAll, rfIgnoreCase]);
  end;
  if Pos('[EMPRESA]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[EMPRESA]',Empresa,[rfReplaceAll, rfIgnoreCase]);
  end;
  if Pos('[FACTURA]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[FACTURA]',Factura,[rfReplaceAll, rfIgnoreCase]);
  end;

  if Pos('[NOTA_CREDITO]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[NOTA_CREDITO]',Factura,[rfReplaceAll, rfIgnoreCase]);
  end;

  if Pos('[PAGO]',Cadena) > 0 then
  begin
    NuevaCad := StringReplace(NuevaCad,'[PAGO]',Factura,[rfReplaceAll, rfIgnoreCase]);
  end;

  Result := NuevaCad;
end;

function TFacturaEFormV40.EnviaFacturas(DoctoPvId:Integer;Folio,Modulo, EmailAlterno:String; Var Error : String):Boolean;
var PathArchivos,TOTAL_LETRA,Smtp,Usuario,Pass,EnviadoPor,PuertoMail,
    Mensaje,Asunto,NombreEmpresa,Email,NombreCli,TipoFac,SSL,TLS:String;
    PDF,XML,ErrorEnvio:String;
    TotalPagar:Double;

    CfdiVe : IXMLComprobante;
    VersionXML:string;
    SerieSC:String;
begin

try
  begin



   sysutils.decimalseparator:='.';
   Result := False;
   Error := ''; gEmailEnvio := '';
   PathArchivos := GetPrefer('CarpetaArchivos');

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT NOMBRE FROM DATOS_EMPRESA ');
   IBQuery.Open;
   NombreEmpresa := IBQuery.FieldByName('NOMBRE').AsString;

if Modulo = 'PV' then
begin
    {$REGION 'PV'}
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT IIF (C.ES_DIR_PPAL = ''S'',B.NOMBRE,C.NOMBRE_CONSIG) NOMBRE_CLI ');
    IBQuery.SelectSQL.Add(', A.MODALIDAD_FACTURACION ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_PV A ');
    IBQuery.SelectSQL.Add('INNER JOIN CLIENTES B ON ( A.CLIENTE_ID = B.CLIENTE_ID ) ');
    IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON ( C.DIR_CLI_ID = A.DIR_CLI_ID  ) ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID ');
    IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
    IBQuery.Open;
    NombreCli := IBQuery.FieldByName('NOMBRE_CLI').AsString;
    TipoFac := IBQuery.FieldByName('MODALIDAD_FACTURACION').AsString;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT TOTAL_A_PAGAR FROM CALC_TOTALES_DOCTO_PV(:DOCTO_PV_ID, ''S'',''N'',0 ) ');
    IBQuery.ParamByName('DOCTO_PV_ID').ASINTEGER := DoctoPvId;
    IBQuery.Open;
    TotalPagar := IBQuery.FieldByName('TOTAL_A_PAGAR').asfloat;



    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.DOCTO_PV_ID,B.XML,A.FOLIO,C.EMAIL ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_PV A ');
    IBQuery.SelectSQL.Add('INNER JOIN USOS_FOLIOS_FISCALES B ON ( A.DOCTO_PV_ID = B.DOCTO_ID ) ');
    IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON (C.DIR_CLI_ID = A.DIR_CLI_ID) ');
    IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''F'' AND A.DOCTO_PV_ID = :DOCTO_PV_ID ');
    IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
    IBQuery.Open;

    if EmailAlterno = '' then
    begin
     Email := IBQuery.FieldByName('EMAIL').AsString;
     if Email = '' then
        raise Exception.Create('El cliente no tiene correo configurado.');
    end else
    begin
      Email := EmailAlterno;
    end;

    {$ENDREGION}
end;
if Modulo = 'VE' then
begin
    {$REGION 'VE'}
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT IIF (C.ES_DIR_PPAL = ''S'',B.NOMBRE,C.NOMBRE_CONSIG) NOMBRE_CLI ');
    IBQuery.SelectSQL.Add(', A.MODALIDAD_FACTURACION ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('INNER JOIN CLIENTES B ON ( A.CLIENTE_ID = B.CLIENTE_ID ) ');
    IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON ( C.DIR_CLI_ID = A.DIR_CLI_ID  ) ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPvId;
    IBQuery.Open;
    NombreCli := IBQuery.FieldByName('NOMBRE_CLI').AsString;
    TipoFac := IBQuery.FieldByName('MODALIDAD_FACTURACION').AsString;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT TOTAL_A_PAGAR FROM CALC_TOTALES_DOCTO_VE(:DOCTO_VE_ID, ''S'') ');
    IBQuery.ParamByName('DOCTO_VE_ID').ASINTEGER := DoctoPvId;
    IBQuery.Open;
    TotalPagar := IBQuery.FieldByName('TOTAL_A_PAGAR').asfloat;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID,B.XML,A.FOLIO,C.EMAIL ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('INNER JOIN USOS_FOLIOS_FISCALES B ON ( A.DOCTO_VE_ID = B.DOCTO_ID ) ');
    IBQuery.SelectSQL.Add('INNER JOIN DIRS_CLIENTES C ON (C.DIR_CLI_ID = A.DIR_CLI_ID) ');
    IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''F'' AND A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPvId;
    IBQuery.Open;

    if EmailAlterno = '' then
    begin
     Email := IBQuery.FieldByName('EMAIL').AsString;
     if Email = '' then
        raise Exception.Create('El cliente no tiene correo configurado.');
    end else
    begin
      Email := EmailAlterno;
    end;
    {$ENDREGION}
end;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.XML,A.FOLIOS_FISCALES_ID,A.USO_FOLIO_ID ');
   IBQuery.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A ');
   IBQuery.SelectSQL.Add('WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = :SISTEMA ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoPvId;
   IBQuery.ParamByName('SISTEMA').AsString := MODULO;
   IBQuery.Open;

   xmlFac.XML.Text := IBQuery.FieldByName('XML').AsString;
   XML := PathArchivos+'\Factura_'+Rellena(Folio, SerieSC)+'.xml';

   xmlFac.Active := True;
   xmlFac.SaveToFile(XML);

   CfdiVe := GetComprobante(xmlFac);
   VersionXML := CfdiVe.Version;

   xmlTimbre.xml.Text := IBQuery.FieldByName('XML').AsString;

   TOTAL_LETRA := NUMLET(TotalPagar,1,1);

  if VersionXML = '3.3' then
      ObtenerDatosFact40();

  GeneraPDFEmail(Rellena(Folio, SerieSC),TOTAL_LETRA,MODULO,TipoFac,TotalPagar,DoctoPvId);

  PDF := PathArchivos+'\Factura_'+Rellena(Folio, SerieSC)+'.pdf';

  Smtp := GetPrefer('SMPT');
  Usuario := GetPrefer('UsuarioMail');
  Pass := GetPrefer('PassMail'); //'Pruebas246';
  EnviadoPor := GetPrefer('EnviadoPorMail');
  PuertoMail := GetPrefer('PuertoMail');
  Mensaje := GetPrefer('MensajeMail');
  Asunto := GetPrefer('AsuntoMail');
  SSL := GetPrefer('SslMail');
  TLS := GetPrefer('TlsMail');

  Asunto := ReemplazaPalabrasReservadas(Asunto,NombreCli,'',NombreEmpresa,Folio);
  Mensaje := ReemplazaPalabrasReservadas(Mensaje,NombreCli,'',NombreEmpresa,Folio);

  if NOT FileExists(XML) then
      raise Exception.Create('No existe el XML.');
  if NOT FileExists(PDF) then
      raise Exception.Create('No existe el archivo .rf3 para generar PDF del documento');

  Error := '';

  ErrorEnvio := '';


  if not EnvioMail(Smtp,Usuario,Pass,EnviadoPor,PuertoMail,Asunto,Mensaje,Email,PDF,XML,SSL,TLS,ErrorEnvio) then
  begin
    Error := 'Envio: '+Pass+'--'+ErrorEnvio;
    Result := False;
  end else
  begin
    Error := '';
    FolioFacVENuew := Rellena(Folio, SerieSC);
    Result := True;
    gEmailEnvio := Email;
    ExportPDF.Free;
  end;


  if ErrorEnvio <> '' then
      Error := 'Envio: '+Pass+'--'+ErrorEnvio; //Error := ErrorEnvio;

  DeleteFile(PAnsiChar(XML));
  DeleteFile(PAnsiChar(PDF));


  end;
except on e : exception do
  begin
      Error := 'XML: '+e.Message;
  end;
end;

end;

function TFacturaEFormV40.CodificaPDF(PdfPath:String):widestring;
var
source : TFileStream;
encoded : widestring;
cad:String;
begin

source := TFileStream.Create(PdfPath, fmOpenRead);

encoded := IdEncoderMIME1.Encode(source, source.Size);

result := encoded;

FreeAndNil(source);


end;

function TFacturaEFormV40.GeneraPDF(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;
Var
Qrcode,str_qrcode:String;
ReportStream,ImagenStream:TStream;
PathGen,PathPdf,PathXml,Caracter, pdfpath:String;
Documento:String;
LengthSello, PosInicial :Integer;
begin
  Result := '';
  sysutils.decimalseparator:='.';

try
 begin


  PathGen := GetPrefer('CarpetaArchivos');

  Documento := '';
  if Modulo = 'PV' then
  begin
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT TIPO_DOCTO FROM DOCTOS_PV WHERE DOCTO_PV_ID = :DOCTO_PV_ID ');
    IBQuery.ParamByName('DOCTO_PV_ID').ASINTEGER := IdDocto;
    IBQuery.Open;
    Documento := IBQuery.FieldByName('TIPO_DOCTO').AsString;
  end;

  if Modulo = 'VE' then
  begin
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT TIPO_DOCTO FROM DOCTOS_VE WHERE DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').ASINTEGER := IdDocto;
    IBQuery.Open;
    Documento := IBQuery.FieldByName('TIPO_DOCTO').AsString;
  end;

  if Modulo = 'PA' then
  begin
    Documento := 'PA';
  end;

  if Documento = 'F' then
    begin
    if ((Modulo = 'VE') and (TipoFact='CFDI')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Factura_VE_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;
    if ((Modulo = 'VE') and (TipoFact='CFD')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Factura_VE_CFD.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;

    if ((Modulo = 'PV') and (TipoFact = 'CFDI')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Factura_PV_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;
    if ((Modulo = 'PV') and (TipoFact='CFD')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Factura_PV_CFD.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;
  end;

  if Documento = 'C' then
  begin
    if ((Modulo = 'PV') and (TipoFact = 'CFDI')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Credito_PV_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;
  end;

  if Documento = 'D' then
  begin
    if ((Modulo = 'VE') and (TipoFact='CFDI')) then
    begin
        ReportStream := TFileStream.Create(PathGen+'\Credito_VE_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
    end;
  end;

  if Documento = 'PA' then
  begin
     ReportStream := TFileStream.Create(PathGen+'\Pago_CFDI.fr3', fmOpenReadWrite or fmShareDenyWrite);
  end;


  frxReport1.LoadFromStream(ReportStream);
  if TipoFact = 'CFDI' then
  begin
    LengthSello := Length(gSelloDigital);
    PosInicial := LengthSello - 8;
    str_qrcode := 'https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?&id='+gUUID+'&re='+gRfcEmisor+'&rr='+gRfcReceptor+
    '&tt='+FormatFloat('#.00',TotalPagar )+'&fe='+Copy(gSelloDigital, PosInicial, 8);
    Qrcode := str_qrcode;
  end;

  frxReport1.Variables['DOCTO_ID'] := IdDocto;
  frxReport1.Variables['TT_LETRA'] := ''''+TotalLetra+'''';
  frxReport1.Variables['SELLO_DIGITAL'] := ''''+gSelloDigital+'''';
  frxReport1.Variables['CERTIFICADO'] := ''''+gNoCertificado+'''';

  if TipoFact = 'CFDI' then
  begin
    frxReport1.Variables['SELLO_SAT'] := ''''+gSelloSat+'''';
    frxReport1.Variables['QRCODE'] := ''''+Qrcode+'''';
    frxReport1.Variables['UUID'] := ''''+gUUID+'''';
    frxReport1.Variables['CERTIFICADO_SAT'] := ''''+gCertificadoSAT+'''';
    frxReport1.Variables['FECHA_TIMBRADO'] := ''''+gFechaTimbrado+'''';
    frxReport1.Variables['SELLO_CFD'] := ''''+gSelloCFD+'''';
    frxReport1.Variables['CADENA_ORIGINAL'] := ''''+gCadenaOriginalTimbre+'''';
  end;

  if TipoFact = 'CFD' then
  begin
    frxReport1.Variables['ANO_APROBACION'] := ''''+gANOAPROB+'''';
    frxReport1.Variables['NO_APROBACION'] := ''''+gnoaprobacion+'''';
    Caracter := '''';
    gCadenaOriginal := StringReplace(gCadenaOriginal,Caracter,'',[rfReplaceAll, rfIgnoreCase]);;
    frxReport1.Variables['CADENA_ORIGINAL'] := ''''+gCadenaOriginal+'''';
  end;

  frxReport1.PrepareReport(True);
  ExportPDF.DefaultPath := GetPrefer('CarpetaArchivos');
  ExportPDF.FileName := 'Factura_' + Folio + '.pdf';
  ExportPDF.ShowDialog := false;
  frxReport1.Export(ExportPDF);
  FreeAndNil(ReportStream);
  pdfpath := PathGen+'\'+'Factura_' + Folio + '.pdf';
  if FileExists(pdfpath) then
      Result := CodificaPDF(pdfpath);

 end
except on e : exception do
 begin
   ExportPDF.Free;
   FreeAndNil(ReportStream);
   if FileExists(Qrcode) then
       DeleteFile(PAnsiChar(Qrcode));
   Raise Exception.Create('Ocurrió un error al generar el PDF. Error: '+e.Message);
 end;

end;
end;

procedure TFacturaEFormV40.ObtenerDatosFact40();
var NodoListXML,NodoListOrigXML,NodoList,NodoListTimbre: IXMLNodeList;
AtribList: IXMLNodeList;
AtributoNombre,AtributoValor : String;
i,n : Integer;
begin
   xmlTimbre.Active := True;

   NodoListOrigXML:= xmlTimbre.ChildNodes;

   For i := 0 to NodoListOrigXML.Count - 1 do
   begin
    if (NodoListOrigXML.Nodes[i].NodeName = 'cfdi:Comprobante') then
    begin
    {$REGION 'CFDI'}
         xmlTimbre.Active := True;

         XMLfac.XML.Text := xmlTimbre.XML.Text;
         xmlFacCopy.XML.Text := xmlTimbre.XML.Text;
         GeneraCadenaOriginalCFDI40(xmlTimbre);

         XMLfac.XML.Text := xmlFacCopy.XML.Text;

         XMLfac.Active := True;

         CFDI40 := GetComprobante(XMLfac);
         gCERTIFICADO := '';

         with CFDI40 do
         begin
             gSelloDigital := CFDI40.Sello;
             gCERTIFICADO := trim(CFDI40.Certificado);
             gNoCertificado := Trim(CFDI40.NoCertificado);
             gFECHAXML := CFDI40.Fecha;
           with CFDI40.Emisor do
           begin
            with CFDI40.Emisor.AttributeNodes do
             begin
               gRfcEmisor := CFDI40.Emisor.Attributes['Rfc'];
             end;
           end;

           with CFDI40.Receptor do
           begin
             with CFDI40.Receptor.AttributeNodes do
             begin
               gRfcReceptor := CFDI40.Receptor.Attributes['Rfc'];
             end;
           end;

            try
             begin
                with CFDI40.Complemento do
                begin
                   gCadenaOriginalTimbre := '';
                   NodoListTimbre := CFDI40.Complemento.ChildNodes;
                   gUUID := NodoListTimbre.Nodes[0].Attributes['UUID'];
                   gSelloSAT := NodoListTimbre.Nodes[0].Attributes['selloSAT'];
                   gCertificadoSAT := NodoListTimbre.Nodes[0].Attributes['noCertificadoSAT'];
                   gFechaTimbrado := NodoListTimbre.Nodes[0].Attributes['FechaTimbrado'];
                   gSelloCFD := NodoListTimbre.Nodes[0].Attributes['selloCFD'];

                   gCadenaOriginalTimbre := '||';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['version']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['UUID']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['FechaTimbrado']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['selloCFD']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['noCertificadoSAT']+'||';
                end;
             end;
           except
             begin
                with CFDI40.Complemento do
                begin

                   gCadenaOriginalTimbre := '';
                   NodoListTimbre := CFDI40.Complemento.ChildNodes;
                   gUUID := NodoListTimbre.Nodes[0].Attributes['UUID'];
                   gSelloSAT := NodoListTimbre.Nodes[0].Attributes['SelloSAT'];
                   gCertificadoSAT := NodoListTimbre.Nodes[0].Attributes['NoCertificadoSAT'];
                   gFechaTimbrado := NodoListTimbre.Nodes[0].Attributes['FechaTimbrado'];
                   gSelloCFD := NodoListTimbre.Nodes[0].Attributes['SelloCFD'];

                   gCadenaOriginalTimbre := '||';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['Version']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['UUID']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['FechaTimbrado']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['SelloCFD']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       NodoListTimbre.Nodes[0].Attributes['NoCertificadoSAT']+'||';

                end;
             end;
           end;

         end;
         gAnoAprob := '';
         gNOAPROBACION := '';

         {$ENDREGION}
    end;

   end;

end;

function TFacturaEFormV40.VensionXML(XML:String):String;
var CfdiVe : IXMLComprobante;
    VersionXML:string;
begin
   CfdiVe := GetComprobante(xmlTimbre);
   VersionXML := CfdiVe.Version;

   Result:= VersionXML;
end;

function TFacturaEFormV40.NumLet(mNum: Currency; iIdioma, iModo: Smallint):string;
 const
   a:integer=1;
   iTopFil: Smallint = 6;
   iTopCol: Smallint = 10;
   aCastellano: array[0..5, 0..9] of PChar =
   ( ('UNA ','DOS ','TRES ','CUATRO ','CINCO ',
     'SEIS ','SIETE ','OCHO ','NUEVE ','UN '),
     ('ONCE ','DOCE ','TRECE ','CATORCE ','QUINCE ',
     'DIECISEIS ','DIECISIETE ','DIECIOCHO ','DIECINUEVE ',''),
     ('DIEZ ','VEINTE ','TREINTA ','CUARENTA ','CINCUENTA ',
     'SESENTA ','SETENTA ','OCHENTA ','NOVENTA ','VEINTI'),
     ('CIEN ','DOSCIENTAS ','TRESCIENTAS ','CUATROCIENTAS ','QUINIENTAS ',
     'SEISCIENTAS ','SETECIENTAS ','OCHOCIENTAS ','NOVECIENTAS ','CIENTO '),
     ('CIEN ','DOSCIENTOS ','TRESCIENTOS ','CUATROCIENTOS ','QUINIENTOS ',
     'SEISCIENTOS ','SETECIENTOS ','OCHOCIENTOS ','NOVECIENTOS ','CIENTO '),
     ('MIL ','MILLON ','MILLONES ','CERO ','Y ',
     'UNO ','DOS ','CON ','','') );
   aCatalan: array[0..5, 0..9] of PChar =
   ( ( 'UNA ','DUES ','TRES ','QUATRE ','CINC ',
     'SIS ','SET ','VUIT ','NOU ','UN '),
     ( 'ONZE ','DOTZE ','TRETZE ','CATORZE ','QUINZE ',
     'SETZE ','DISSET ','DIVUIT ','DINOU ',''),
     ( 'DEU ','VINT ','TRENTA ','QUARANTA ','CINQUANTA ',
     'SEIXANTA ','SETANTA ','VUITANTA ','NORANTA ','VINT-I-'),
     ( 'CENT ','DOS-CENTES ','TRES-CENTES ','QUATRE-CENTES ','CINC-CENTES ',
     'SIS-CENTES ','SET-CENTES ','VUIT-CENTES ','NOU-CENTES ','CENT '),
     ( 'CENT ','DOS-CENTS ','TRES-CENTS ','QUATRE-CENTS ','CINC-CENTS ',
     'SIS-CENTS ','SET-CENTS ','VUIT-CENTS ','NOU-CENTS ','CENT '),
     ( 'MIL ','MILIO ','MILIONS ','ZERO ','-',
     'UN ','DOS ','AMB ','','') );
 var
   aTexto: array[0..5, 0..9] of PChar;
   cTexto, cNumero: String;
   iCentimos, iPos: Smallint;
   bHayCentimos, bHaySigni: Boolean;

   (*************************************)
   (* Cargar Textos según Idioma / Modo *)
   (*************************************)

   procedure NumLetra_CarTxt;
   var
     i, j: Smallint;
   begin
(* Asignación según Idioma *)

     for i := 0 to iTopFil - 1 do
       for j := 0 to iTopCol - 1 do
         case iIdioma of
           1: aTexto[i, j] := aCastellano[i, j];
           2: aTexto[i, j] := aCatalan[i, j];
           else
           aTexto[i, j] := aCastellano[i, j];
         end;

(* Asignación si Modo Masculino *)

     if (iModo = 1) then
     begin
       for j := 0 to 1 do
       aTexto[0, j] := aTexto[5, j + 5];

       for j := 0 to 9 do
         aTexto[3, j] := aTexto[4, j];
     end;
end;

   (****************************)
   (* Traducir Dígito -Unidad- *)
   (****************************)

   procedure NumLetra_Unidad;
   begin
   if not( (cNumero[iPos] = '0') or (cNumero[iPos - 1] = '1')
      or ((Copy(cNumero, iPos - 2, 3) = '001') and ((iPos = 3) or (iPos = 9))) ) then
      if (cNumero[iPos] = '1') and (iPos <= 6) then
        cTexto := cTexto + aTexto[0, 9]
      else
        cTexto := cTexto + aTexto[0, StrToInt(cNumero[iPos]) - 1];

     if ((iPos = 3) or (iPos = 9)) and (Copy(cNumero, iPos - 2, 3) <> '000') then
       cTexto := cTexto + aTexto[5, 0];

     if (iPos = 6) then
       if (Copy(cNumero, 1, 6) = '000001') then
         cTexto := cTexto + aTexto[5, 1]
       else
         cTexto := cTexto + aTexto[5, 2];
   end;

   (****************************)
   (* Traducir Dígito -Decena- *)
   (****************************)

   procedure NumLetra_Decena;
   begin
     if (cNumero[iPos] = '0') then
       Exit
     else if (cNumero[iPos + 1] = '0') then
       cTexto := cTexto + aTexto[2, StrToInt(cNumero[iPos]) - 1]
       else if (cNumero[iPos] = '1') then
         cTexto := cTexto + aTexto[1, StrToInt(cNumero[iPos + 1]) - 1]
         else if (cNumero[iPos] = '2') then
           cTexto := cTexto + aTexto[2, 9]
         else
           cTexto := cTexto + aTexto[2, StrToInt(cNumero[iPos]) - 1]+ aTexto[5, 4];
   end;

   (*****************************)
   (* Traducir Dígito -Centena- *)
   (*****************************)

   procedure NumLetra_Centena;
   var
     iPos2: Smallint;
   begin
     if (cNumero[iPos] = '0') then
     Exit;

     iPos2 := 4 - Ord(iPos > 6);

     if (cNumero[iPos] = '1') and (Copy(cNumero, iPos + 1, 2) <> '00') then
       cTexto := cTexto + aTexto[iPos2, 9]
     else
       cTexto := cTexto + aTexto[iPos2, StrToInt(cNumero[iPos]) - 1];
   end;

   (**************************************)
   (* Eliminar Blancos previos a guiones *)
   (**************************************)

   procedure NumLetra_BorBla;
   var
     i: Smallint;
   begin
     i := Pos(' -', cTexto);

     while (i > 0) do
     begin
       Delete(cTexto, i, 1);
       i := Pos(' -', cTexto);
     end;
end;

begin
(* Control de Argumentos *)

   if (mNum < 0.00) or (mNum > 999999999999.99) or (iIdioma < 1) or (iIdioma > 2)
     or (iModo < 1) or (iModo > 2) then
     begin
        Result := 'ERROR EN ARGUMENTOS';
     Abort;
   end;

(* Cargar Textos según Idioma / Modo *)

   NumLetra_CarTxt;

   (* Bucle Exterior -Tratamiento Céntimos-     *)
   (* NOTA: Se redondea a dos dígitos decimales *)

   cNumero := Trim(Format('%12.0f', [Int(mNum)]));
   cNumero := StringOfChar('0', 12 - Length(cNumero)) + cNumero;
   iCentimos := Trunc((Frac(mNum) * 100) + 0.5);

   repeat
(* Detectar existencia de Céntimos *)

     if (iCentimos <> 0) then
        bHayCentimos := True
     else
        bHayCentimos := False;

     (* Bucle Interior -Traducción- *)

     bHaySigni := False;

     for iPos := 1 to 12 do
     begin
(* Control existencia Dígito significativo *)

       if not(bHaySigni) and (cNumero[iPos] = '0') then
         Continue
       else
         bHaySigni := True;

       (* Detectar Tipo de Dígito *)

       case ((iPos - 1) mod 3) of
         0: NumLetra_Centena;
         1: NumLetra_Decena;
         2: NumLetra_Unidad;
       end;
end;

(* Detectar caso 0 *)

     if (cTexto = '') then
       cTexto := aTexto[5, 3];

     (* Traducir Céntimos -si procede- *)

     if (iCentimos <> 0) then
     begin
       {cTexto := cTexto + aTexto[5, 7];
       cNumero := Trim(Format('%.12d', [iCentimos]));
       iCentimos := 0;}
       cTexto := cTexto + ' PESOS ' + inttostr(icentimos)+ '/100 MN';
     end
     else begin
          cTexto := cTexto + ' PESOS ' + '00/100 MN';
          end;
     until a=1;

   (* Eliminar Blancos innecesarios -sólo Catalán- *)

   if (iIdioma = 2) then
      NumLetra_BorBla;

   (* Retornar Resultado *)

   Result := Trim(cTexto);


end;

function TFacturaEFormV40.CopiarDetallePv(DoctoOrigen,DoctoDest:Integer; ModifEncab : String; Var Error:String):Boolean;
begin
Result := False;
try
 begin
  spCopiaFteDestPV.ParamByName('FTE_ID').AsInteger := DoctoOrigen;
  spCopiaFteDestPV.ParamByName('DEST_ID').AsInteger := DoctoDest;
  spCopiaFteDestPV.ParamByName('MODIF_ENCAB').AsString := ModifEncab;
  spCopiaFteDestPV.ExecProc;
  Result := True;
 end
except
 begin
   Error := 'Al generar los detalles de la factura.';
   Result := False;
 end;
end;
end;

function TFacturaEFormV40.FormasCobroPV(IdTicket,DoctoPvId:Integer; Var Error:String):Boolean;
var FORMA_COBRO_REFER_ID:Integer;
REFERENCIA:String;
begin
  Result := False;

  try
   begin
     IBQuery.Close;
     IBQuery.SelectSQL.Clear;
     IBQuery.SelectSQL.Add('SELECT DOCTO_PV_COBRO_ID, DOCTO_PV_ID, TIPO, FORMA_COBRO_ID, IMPORTE, TIPO_CAMBIO, IMPORTE_MON_DOC ');
     IBQuery.SelectSQL.Add('FROM DOCTOS_PV_COBROS ');
     IBQuery.SelectSQL.Add('WHERE DOCTO_PV_ID = :DOCTO_PV_ID AND TIPO = ''C'' ');
     IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := IdTicket;
     IBQuery.Open;

     while not IBQuery.Eof do
     begin

          IBQuery3.Close;
          IBQuery3.SelectSQL.Clear;
          IBQuery3.SelectSQL.Add('SELECT FORMA_COBRO_REFER_ID ');
          IBQuery3.SelectSQL.Add('FROM FORMAS_COBRO_REFER ');
          IBQuery3.SelectSQL.Add('WHERE UPPER(NOMBRE) = UPPER(''Banco/Cheque'') ');
          IBQuery3.SelectSQL.Add('AND FORMA_COBRO_ID = :FORMA_COBRO_ID ');
          IBQuery3.ParamByName('FORMA_COBRO_ID').AsInteger := IBQuery.FieldByName('FORMA_COBRO_ID').AsInteger;
          IBQuery3.Open;
          FORMA_COBRO_REFER_ID := IBQuery3.FieldByName('FORMA_COBRO_REFER_ID').AsInteger;

          IBQuery3.Close;
          IBQuery3.SelectSQL.Clear;
          IBQuery3.SelectSQL.Add('SELECT REFERENCIA ');
          IBQuery3.SelectSQL.Add('FROM DOCTOS_PV_COBROS_REFER ');
          IBQuery3.SelectSQL.Add('WHERE DOCTO_PV_COBRO_ID = :DOCTO_PV_COBRO_ID ');
          IBQuery3.SelectSQL.Add('AND FORMA_COBRO_REFER_ID = :FORMA_COBRO_REFER_ID ');
          IBQuery3.ParamByName('DOCTO_PV_COBRO_ID').AsInteger := IBQuery.FieldByName('DOCTO_PV_COBRO_ID').AsInteger;
          IBQuery3.ParamByName('FORMA_COBRO_REFER_ID').AsInteger := FORMA_COBRO_REFER_ID;
          IBQuery3.Open;
          REFERENCIA := IBQuery3.FieldByName('REFERENCIA').AsString;

          IBQuery2.Close;
          IBQuery2.SelectSQL.Clear;
          IBQuery2.SelectSQL.Add('INSERT INTO FORMAS_COBRO_DOCTOS (FORMA_COBRO_DOC_ID, NOM_TABLA_DOCTOS, DOCTO_ID, FORMA_COBRO_ID, NUM_CTA_PAGO, CLAVE_SIS_FORMA_COB, REFERENCIA, IMPORTE) ');
          IBQuery2.SelectSQL.Add('VALUES (-1, ''DOCTOS_PV'', :DOCTO_ID, :FORMA_COBRO_ID, :NUM_CTA_PAGO, ''PV'', :REFERENCIA, :IMPORTE); ');
          IBQuery2.ParamByName('DOCTO_ID').AsInteger := DoctoPvId;
          IBQuery2.ParamByName('FORMA_COBRO_ID').AsInteger := IBQuery.FieldByName('FORMA_COBRO_ID').AsInteger;
          if REFERENCIA <> '' then
              IBQuery2.ParamByName('NUM_CTA_PAGO').AsString := Copy(REFERENCIA, 1, 4)
          else
            IBQuery2.ParamByName('NUM_CTA_PAGO').AsString := '';
          IBQuery2.ParamByName('REFERENCIA').AsString := '';
          IBQuery2.ParamByName('IMPORTE').AsFloat := IBQuery.FieldByName('IMPORTE_MON_DOC').AsFloat;;
          IBQuery2.Open;


          IBQuery.Next;
     end;


     Result := True;
   end
  except on e : exception do
   begin
     Error := 'Al agregar formas de pago: '+e.Message;
     Result := False;
   end;
  end;
end;

function TFacturaEFormV40.AplicaDoctoPv(DoctoPvId:Integer; SoloLectura,ImptoIncluido:String; Var Error:String):Boolean;
begin
  Result := False;

  try
   begin
     spCalcTotalesPV.Close;
     spCalcTotalesPV.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
     spCalcTotalesPV.ParamByName('SOLO_LECTURA').AsString := SoloLectura;
     spCalcTotalesPV.ParamByName('IMPTO_INCLUIDO').AsString := ImptoIncluido;
     spCalcTotalesPV.ExecProc;

     IBQuery.Close;
     IBQuery.SelectSQL.Clear;
     IBQuery.SelectSQL.Add('UPDATE DOCTOS_PV SET APLICADO = ''S'' WHERE ( DOCTO_PV_ID = :DOCTO_PV_ID ) ');
     IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
     IBQuery.Open;
     Result := True;
   end
  except on e : exception do
   begin
     Error := 'Al aplicar el documento 40.'+e.Message;
     Result := False;
   end;
  end;
end;

function TFacturaEFormV40.AsignaFolioFactura(DoctoId:Integer; Serie,TipoDocto,Modulo:String; Var Error:String ):String;
Var FolioVentasId,FoliosFiscalesId,UsoFolioId : Integer;
    FolioSig,Folio:Integer;
    Evento : String;
begin
try
 begin
  FolioVentasId := 0;
  FoliosFiscalesId := 0;

  IBQuery3.Close;
  IBQuery3.SelectSQL.Clear;
  IBQuery3.SelectSQL.Add('SELECT A.FOLIO_VENTAS_ID,A.CONSECUTIVO ');
  IBQuery3.SelectSQL.Add('FROM FOLIOS_VENTAS A ');
  IBQuery3.SelectSQL.Add('WHERE A.SERIE = :SERIE AND A.TIPO_DOCTO = :TIPO_DOCTO AND MODALIDAD_FACTURACION = ''CFDI'' '); //AND A.SISTEMA = :SISTEMA
  IBQuery3.ParamByName('SERIE').AsString := Serie;
  IBQuery3.ParamByName('TIPO_DOCTO').AsString := TipoDocto;
  //IBQuery3.ParamByName('SISTEMA').AsString := Modulo;
  IBQuery3.Open;
  FolioVentasId := IBQuery3.FieldByName('FOLIO_VENTAS_ID').Asinteger;
  Folio := IBQuery3.FieldByName('CONSECUTIVO').Asinteger;
  FolioSig := IBQuery3.FieldByName('CONSECUTIVO').Asinteger+1;


  IBQuery3.Close;
  IBQuery3.SelectSQL.Clear;
  IBQuery3.SelectSQL.Add('SELECT A.FOLIOS_FISCALES_ID ');
  IBQuery3.SelectSQL.Add('FROM FOLIOS_FISCALES A  ');
  IBQuery3.SelectSQL.Add('WHERE A.SERIE = :SERIE AND A.MODALIDAD_FACTURACION = ''CFDI'' ');
  IBQuery3.ParamByName('SERIE').AsString := Serie;
  IBQuery3.Open;
  FoliosFiscalesId := IBQuery3.FieldByName('FOLIOS_FISCALES_ID').AsInteger;

  if FoliosFiscalesId = 0 then
  begin

    IBQuery3.Close;
    IBQuery3.SelectSQL.Clear;
    IBQuery3.SelectSQL.Add('INSERT INTO FOLIOS_FISCALES (FOLIOS_FISCALES_ID, SERIE, FOLIO_INI,  ');
    IBQuery3.SelectSQL.Add('FOLIO_FIN, ULTIMO_UTILIZADO, NUM_APROBACION, ANO_APROBACION, MODALIDAD_FACTURACION ) VALUES ');
    IBQuery3.SelectSQL.Add('(:FOLIOS_FISCALES_ID, :SERIE, :FOLIO_INI,   ');
    IBQuery3.SelectSQL.Add(':FOLIO_FIN, :ULTIMO_UTILIZADO, :NUM_APROBACION, :ANO_APROBACION, :MODALIDAD_FACTURACION ) ');
    FoliosFiscalesId := GetDoctoId();
    IBQuery3.ParamByName('FOLIOS_FISCALES_ID').AsInteger := FoliosFiscalesId;
    IBQuery3.ParamByName('SERIE').AsString := Serie;
    IBQuery3.ParamByName('FOLIO_INI').AsInteger := 1;
    IBQuery3.ParamByName('FOLIO_FIN').AsInteger := 999999999;
    IBQuery3.ParamByName('ULTIMO_UTILIZADO').AsInteger := 0;
    IBQuery3.ParamByName('NUM_APROBACION').AsString := '1';
    IBQuery3.ParamByName('ANO_APROBACION').AsInteger := 1;
    IBQuery3.ParamByName('MODALIDAD_FACTURACION').AsString := 'CFDI';
    IBQuery3.Open;
  end;

  IBQuery3.Close;
  IBQuery3.SelectSQL.Clear;
  IBQuery3.SelectSQL.Add('INSERT INTO USOS_FOLIOS_FISCALES (USO_FOLIO_ID, FOLIOS_FISCALES_ID, FOLIO, FECHA, ');
  IBQuery3.SelectSQL.Add('SISTEMA, DOCTO_ID, XML, PROV_CERT, FECHA_HORA_TIMBRADO, UUID) VALUES ( ');
  IBQuery3.SelectSQL.Add(':USO_FOLIO_ID, :FOLIOS_FISCALES_ID, :FOLIO , :FECHA ,  ');
  IBQuery3.SelectSQL.Add(':SISTEMA, :DOCTO_ID, :XML, :PROV_CERT, :FECHA_HORA_TIMBRADO, :UUID ) ');
  UsoFolioId := GetDoctoId();
  IBQuery3.ParamByName('USO_FOLIO_ID').AsInteger := UsoFolioId;
  IBQuery3.ParamByName('FOLIOS_FISCALES_ID').AsInteger := FoliosFiscalesId;
  IBQuery3.ParamByName('FOLIO').AsInteger := Folio;
  IBQuery3.ParamByName('FECHA').AsDate := IBDatabase1.GetServerTime;
  IBQuery3.ParamByName('SISTEMA').AsString := Modulo;
  IBQuery3.ParamByName('DOCTO_ID').AsInteger := DoctoId;
  IBQuery3.ParamByName('XML').Clear;
  IBQuery3.ParamByName('PROV_CERT').Clear;
  IBQuery3.ParamByName('FECHA_HORA_TIMBRADO').Clear;
  IBQuery3.ParamByName('UUID').Clear;
  IBQuery3.Open;

  IBQuery3.Close;
  IBQuery3.SelectSQL.Clear;
  IBQuery3.SelectSQL.Add('UPDATE FOLIOS_VENTAS SET CONSECUTIVO = :CONSECUTIVO WHERE (FOLIO_VENTAS_ID = :FOLIO_VENTAS_ID ); ');
  IBQuery3.ParamByName('FOLIO_VENTAS_ID').AsInteger := FolioVentasId;
  IBQuery3.ParamByName('CONSECUTIVO').AsInteger := FolioSig;
  IBQuery3.Open;

  if Length(Serie) = 1  then
     Result := Serie + FormatFloat('00000000',Folio);
  if Length(Serie) = 2  then
     Result := Serie + FormatFloat('0000000',Folio);
  if Length(Serie) = 3  then
     Result := Serie + FormatFloat('000000',Folio);

 end
except on e : exception do
 begin
   Error := 'Al asignar folio '+ e.Message;
   Result := '';
 end
end;

end;

function TFacturaEFormV40.NuevaFacturaPv(MetodoPagoSAT,Serie,dDescripcion,ClaveCli,TipoDscto,ImpuestoIncluido,VUsoCFDI:String;
         TipoCambio,DsctoImpte,DsctoPctje:Double; ClienteId,ConsigId,CajaId,MonedaId,LugarExp:Integer; Fecha:TDateTime;
         Var Error:String):Integer;
Var DoctoPvId:Integer;
    ModalidadFacturacion,Folio:String;
    LUGAR_EXPEDICION_ID:Integer;
    SUCURSAL_ID:Integer;
begin
Result := 0;
try
 begin
   DoctoPvId := GetDoctoId();

   IBQuery3.Close;
   IBQuery3.SelectSQL.Clear;
   IBQuery3.SelectSQL.Add('SELECT A.SERIE,A.CONSECUTIVO,A.MODALIDAD_FACTURACION ');
   IBQuery3.SelectSQL.Add('FROM FOLIOS_VENTAS A ');
   IBQuery3.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''F'' AND A.SERIE = :SERIE ');
   IBQuery3.ParamByName('SERIE').AsString := Serie;
   IBQuery3.Open;
   ModalidadFacturacion := IBQuery3.FieldByName('MODALIDAD_FACTURACION').AsString;

   IBQuery3.Close;
   IBQuery3.SelectSQL.Clear;
   IBQuery3.SelectSQL.Add('SELECT FIRST 1 SUCURSAL_ID FROM SUCURSALES ');
   IBQuery3.Open;
   SUCURSAL_ID := 0;
   SUCURSAL_ID := IBQuery3.FieldByName('SUCURSAL_ID').AsInteger;

   if LugarExp = 0 then
   begin
     IBQuery3.Close;
     IBQuery3.SelectSQL.Clear;
     IBQuery3.SelectSQL.Add('SELECT FIRST 1 LUGAR_EXPEDICION_ID ');
     IBQuery3.SelectSQL.Add('FROM LUGARES_EXPEDICION ');
     IBQuery3.SelectSQL.Add('WHERE ES_PPAL = ''S'' ');
     IBQuery3.Open;
     LUGAR_EXPEDICION_ID := 0;
     LUGAR_EXPEDICION_ID := IBQuery3.FieldByName('LUGAR_EXPEDICION_ID').AsInteger;
   end else
   begin
     LUGAR_EXPEDICION_ID := LugarExp;
   end;

   Error := '';
   Folio := '';

   Folio := AsignaFolioFactura(DoctoPvId,Serie,'F','PV',Error);
   if Error <> '' then
     Raise Exception.Create('Al asignar el folio   '+Error);


   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('INSERT INTO DOCTOS_PV (DOCTO_PV_ID, CAJA_ID, TIPO_DOCTO, FOLIO, FECHA, HORA, CLAVE_CLIENTE, ');
   IBQuery.SelectSQL.Add('CLIENTE_ID, CLAVE_CLIENTE_FAC, CLIENTE_FAC_ID, DIR_CLI_ID, MONEDA_ID, IMPUESTO_INCLUIDO, ');
   IBQuery.SelectSQL.Add('TIPO_CAMBIO, TIPO_DSCTO, DSCTO_PCTJE, DSCTO_IMPORTE, ESTATUS, APLICADO, IMPORTE_NETO, TOTAL_IMPUESTOS, ');
   IBQuery.SelectSQL.Add('IMPORTE_DONATIVO, TOTAL_FPGC, TICKET_EMITIDO, FORMA_EMITIDA, FORMA_GLOBAL_EMITIDA, CONTABILIZADO, ');
   IBQuery.SelectSQL.Add('SISTEMA_ORIGEN, CARGAR_SUN, UNID_COMPROM, DESCRIPCION, ');
   IBQuery.SelectSQL.Add('ES_CFD, MODALIDAD_FACTURACION, ENVIADO, EMAIL_ENVIO, ');
   IBQuery.SelectSQL.Add('USUARIO_CREADOR, CFDI_CERTIFICADO, FECHA_HORA_CREACION, USUARIO_ULT_MODIF, ');
   IBQuery.SelectSQL.Add('FECHA_HORA_ULT_MODIF, FECHA_HORA_ENVIO, TIPO_GEN_FAC, USO_CFDI, LUGAR_EXPEDICION_ID, METODO_PAGO_SAT, SUCURSAL_ID) ');
   IBQuery.SelectSQL.Add('VALUES (:DOCTO_PV_ID, :CAJA_ID, :TIPO_DOCTO, :FOLIO, :FECHA, :HORA, :CLAVE_CLIENTE, ');
   IBQuery.SelectSQL.Add(':CLIENTE_ID, :CLAVE_CLIENTE_FAC, :CLIENTE_FAC_ID, :DIR_CLI_ID, :MONEDA_ID, :IMPUESTO_INCLUIDO, ');
   IBQuery.SelectSQL.Add(':TIPO_CAMBIO, :TIPO_DSCTO, :DSCTO_PCTJE, :DSCTO_IMPORTE, :ESTATUS, :APLICADO, :IMPORTE_NETO, :TOTAL_IMPUESTOS, ');
   IBQuery.SelectSQL.Add(':IMPORTE_DONATIVO, 0, ''N'', ''N'', ''N'', ''N'', ');
   IBQuery.SelectSQL.Add(' ''PV'', :CARGAR_SUN, ''N'', :DESCRIPCION, :ES_CFD, :MODALIDAD_FACTURACION, :ENVIADO, :EMAIL_ENVIO, ');
   IBQuery.SelectSQL.Add(':USUARIO_CREADOR, ''N'', :FECHA_HORA_CREACION , :USUARIO_ULT_MODIF, '); //   IBQuery.SelectSQL.Add(':USUARIO_CREADOR, ''N'', :FECHA_HORA_CREACION, :USUARIO_ULT_MODIF, ');
   IBQuery.SelectSQL.Add(':FECHA_HORA_ULT_MODIF, :FECHA_HORA_ENVIO, :TIPO_GEN_FAC, :USO_CFDI, :LUGAR_EXPEDICION_ID, :METODO_PAGO_SAT, :SUCURSAL_ID ) ');

   IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
   IBQuery.ParamByName('CAJA_ID').AsInteger := CajaId;
   IBQuery.ParamByName('TIPO_DOCTO').AsString := 'F';
   IBQuery.ParamByName('FOLIO').AsString := Folio;
   IBQuery.ParamByName('FECHA').AsDate := Fecha;
   IBQuery.ParamByName('HORA').AsDateTime := Fecha;
   IBQuery.ParamByName('CLAVE_CLIENTE').AsString := ClaveCli;
   IBQuery.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
   IBQuery.ParamByName('CLAVE_CLIENTE_FAC').AsString := ClaveCli;
   IBQuery.ParamByName('CLIENTE_FAC_ID').AsInteger := ClienteId;
   IBQuery.ParamByName('DIR_CLI_ID').AsInteger := ConsigId;
   IBQuery.ParamByName('MONEDA_ID').AsInteger := MonedaId;
   IBQuery.ParamByName('IMPUESTO_INCLUIDO').AsString := ImpuestoIncluido;
   IBQuery.ParamByName('TIPO_CAMBIO').AsFloat := TipoCambio;
   IBQuery.ParamByName('TIPO_DSCTO').AsString := TipoDscto;
   IBQuery.ParamByName('DSCTO_PCTJE').AsFloat := DsctoPctje;
   IBQuery.ParamByName('DSCTO_IMPORTE').AsFloat := DsctoImpte;
   IBQuery.ParamByName('ESTATUS').AsString := 'N';
   IBQuery.ParamByName('APLICADO').AsString := 'N';
   IBQuery.ParamByName('IMPORTE_NETO').AsFloat := 0.00;
   IBQuery.ParamByName('TOTAL_IMPUESTOS').AsFloat := 0.00;
   IBQuery.ParamByName('IMPORTE_DONATIVO').AsFloat := 0.00;
   IBQuery.ParamByName('CARGAR_SUN').AsString := 'N';
   if (ModalidadFacturacion = 'CFD') OR (ModalidadFacturacion = 'CFDI') then
     IBQuery.ParamByName('ES_CFD').AsString := 'S'
   else
     IBQuery.ParamByName('ES_CFD').AsString := 'N';
   IBQuery.ParamByName('MODALIDAD_FACTURACION').AsString := ModalidadFacturacion;
   IBQuery.ParamByName('ENVIADO').AsString := 'N';
   IBQuery.ParamByName('EMAIL_ENVIO').Clear;
   IBQuery.ParamByName('USUARIO_CREADOR').AsString := 'SYSDBA';
   IBQuery.ParamByName('FECHA_HORA_CREACION').AsDateTime := IBDatabase1.GetServerTime;
   IBQuery.ParamByName('USUARIO_ULT_MODIF').Clear;
   IBQuery.ParamByName('FECHA_HORA_ULT_MODIF').Clear;
   IBQuery.ParamByName('FECHA_HORA_ENVIO').Clear;
   IBQuery.ParamByName('TIPO_GEN_FAC').AsString := 'D';
   IBQuery.ParamByName('USO_CFDI').AsString := VUsoCFDI;
   if LUGAR_EXPEDICION_ID > 0 then
      IBQuery.ParamByName('LUGAR_EXPEDICION_ID').AsInteger := LUGAR_EXPEDICION_ID
   else
      IBQuery.ParamByName('LUGAR_EXPEDICION_ID').Clear;
   IBQuery.ParamByName('METODO_PAGO_SAT').AsString := MetodoPagoSAT;//'PUE';     //SUCURSAL_ID
   IBQuery.ParamByName('SUCURSAL_ID').AsInteger := SUCURSAL_ID;
   IBQuery.ParamByName('DESCRIPCION').AsString := Copy(dDescripcion,1,200);
   IBQuery.Open;  //

   Result := DoctoPvId;
 end
except on e : exception do
 begin
   Error := e.Message;
   Result := 0;
 end;
end;

end;

function TFacturaEFormV40.ValidarRFC(RFC:String):String;
var Cadena1,Numerica,Cadena2,AnoActual : String;
Longitud,nAno,nMes,nDia,nAnoActual : Integer;
Ano,Mes,Dia,Fecha:String;
dFecha : Tdate;
begin

  Result := '';

  Longitud := Length(RFC);

  if longitud > 13 then
  begin
       Result := 'El rfc no es válido.';
       ExiT;
  end
  else
  begin

     if Longitud = 12 then //  Moral
     begin
        Cadena1 := Copy(RFC,1,3);
        Numerica := Copy(RFC,4,6);
        Cadena2 := Copy(RFC,10,12);
     end;


     if Longitud = 13 then //  Física
     begin
        Cadena1 := Copy(RFC,1,4);
        Numerica := Copy(RFC,5,6);
        Cadena2 := Copy(RFC,11,13);
     end;
  end;


  if ContieneNumeros(cadena1) then
  begin
       Result := 'El rfc no es válido.';
       Exit;
  end;
  try
   begin
    Ano := copy(Numerica,1,2);
    Mes := copy(Numerica,3,2);
    Dia := copy(Numerica,5,2);
    nAno := StrToInt(Ano);
    nMes := StrToInt(Mes);
    nDia := StrToInt(Dia);
   end
  except
   begin
     Result := 'El rfc no es válido, la fecha no es válida.';
     Exit;
   end
  end;

  if nMes > 12 then
  begin
       Result := 'El rfc no es válido, el mes no es correcto.';
       Exit;
  end;

  Fecha := Dia+'/'+Mes+'/'+Ano;

  Result := '';


end;

function TFacturaEFormV40.ContieneNumeros(Cadena:String):Boolean;
Var I : Integer;
begin
Result:= False;
  for I := 1 to length(cadena) do
  begin
     if cadena[I] in ['1','2','3','4','5','6','7','8','9','0'] then
     begin
        result := True;
     end;
  end;

end;


procedure TFacturaEFormV40.GetDatosFac();
begin
  gPathCertificado := '';
  gPathLlave := '';
  gContrasena := '';

  gPathCertificado := GetPrefer('PathCert');
  if gPathCertificado = '' then raise Exception.Create('C001: El cetificado de sello digital no se ha configurado ');

  gPathLlave := GetPrefer('PathLlave');
  if gPathLlave = '' then raise Exception.Create('C001: La llave del sello digital no se ha configurado ');

  gContrasena := GetPrefer('PassLlave');
  if gContrasena = '' then raise Exception.Create('C001: La contraseña del sello digital no se ha configurado ');

  gUrlTimbre := GetPrefer('DirTimbre');
  if gUrlTimbre = '' then raise Exception.Create('C001: La dirección de timbrado no se ha configurado ');

  gUsuarioTimbre := GetPrefer('UsuarioTimbre');
  if gUsuarioTimbre = '' then raise Exception.Create('C001: El usuario de timbrado no se ha configurado ');

  gPassTimbre := GetPrefer('PassTimbre');
  if gPassTimbre = '' then raise Exception.Create('C001: La contraseña de timbrado no se ha configurado ');
end;

function TFacturaEFormV40.ValidarDatosCliente(ConsigId:Integer):String;
var Valor:String;
begin
try
 begin
  IBQuery.Close;
  IBQuery.SelectSQL.Clear;
  IBQuery.SelectSQL.Add('SELECT A.DIR_CLI_ID,A.CLIENTE_ID,A.NOMBRE_CONSIG,A.CALLE,A.NOMBRE_CALLE, ');
  IBQuery.SelectSQL.Add('    A.NUM_EXTERIOR,A.NUM_INTERIOR,A.COLONIA,A.POBLACION,A.REFERENCIA, ');
  IBQuery.SelectSQL.Add('    A.CIUDAD_ID,A.ESTADO_ID, D.PAIS_ID,A.EMAIL,A.RFC_CURP,A.ES_DIR_PPAL, ');
  IBQuery.SelectSQL.Add('    B.NOMBRE CIUDAD,C.NOMBRE ESTADO, D.NOMBRE PAIS,A.CODIGO_POSTAL,A.TIPO_PERSONA, A.CLAVE_REGIMEN_FISCAL ');
  IBQuery.SelectSQL.Add('    FROM DIRS_CLIENTES A ');
  IBQuery.SelectSQL.Add('    LEFT JOIN CIUDADES B ON ( A.CIUDAD_ID = B.CIUDAD_ID ) ');
  IBQuery.SelectSQL.Add('    LEFT JOIN ESTADOS C ON ( B.ESTADO_ID = C.ESTADO_ID ) ');
  IBQuery.SelectSQL.Add('    LEFT JOIN PAISES D ON ( C.PAIS_ID = D.PAIS_ID ) ');
  IBQuery.SelectSQL.Add('    WHERE A.DIR_CLI_ID = :DIR_CLI_ID ');
  IBQuery.ParamByName('DIR_CLI_ID').AsInteger := ConsigId;
  IBQuery.Open;

  if IBQuery.FieldByName('CLIENTE_ID').AsInteger = 0 then
    Raise Exception.Create('No existe el cliente. Error:'+IntToStr(ConsigId) );

  if IBQuery.FieldByName('CODIGO_POSTAL').AsString = '' then
    Raise Exception.Create('No existe código postal. Error:'+IntToStr(ConsigId) );

  if IBQuery.FieldByName('TIPO_PERSONA').AsString = '' then
    Raise Exception.Create('No existe tipo de persona. Error:'+IntToStr(ConsigId) );

  if IBQuery.FieldByName('CLAVE_REGIMEN_FISCAL').AsString = '' then
    Raise Exception.Create('No existe regimen fiscal. Error:'+IntToStr(ConsigId) );

  {$REGION ' Solicitar factura '}
      Valor := '';
      IBQuery4.Close;
      IBQuery4.SelectSQL.Clear;
      IBQuery4.SelectSQL.Add('SELECT A.VALOR FROM MGFACTURA_CONFIG A WHERE A.NOMBRE = ''CorreoAlterno'' ');
      IBQuery4.Open;
      Valor := IBQuery4.FieldByName('VALOR').AsString;
      if Valor = 'S' then

      else
      begin
        if Length(Trim(IBQuery.FieldByName('EMAIL').AsString)) = 0 then
          Raise Exception.Create('Indique el email en la dirección del cliente para la factura.');
      end;
  {$ENDREGION}



  if ValidarRFC(IBQuery.FieldByName('RFC_CURP').AsString) <> '' then
    Raise Exception.Create(ValidarRFC(IBQuery.FieldByName('RFC_CURP').AsString)+' Clave: '+IBQuery.FieldByName('RFC_CURP').AsString);

  Result := '';

 end
except on e : Exception do
 begin
   Result := e.Message;
 end;
end;

end;

function TFacturaEFormV40.GetDoctoId():Integer;
begin
  spGenDoctoId.ExecProc;
  Result := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
end;

function TFacturaEFormV40.GetCatalogoId():Integer;
begin
  spGenCatId.ExecProc;
  Result := spGenCatId.FieldByName('CATALOGO_ID').AsInteger;
end;

function TFacturaEFormV40.AgregaConsig(ConsigId,ClienteId:Integer; Var Error:String ):Integer;
Var NombreConsig, NombreCli, Calle, NombreCalle, NumExt, NumInt, Colonia, Poblacion,
    Referencia, CodPostal, Tel1, Tel2, Fax, Email, Rfc, Contacto, UsarEnvio,
    UsarFactura, Gln : String;
    DirCliId, CiudadId, EstadoId, PaisId, ViaEmbarqueId : Integer;
    ES_DIR_PPAL, TIPO_PERSONA, CLAVE_REGIMEN_FISCAL :String;
begin
  Result := 0;

try
 begin
  {$REGION 'Inicializar variables'}
  NombreConsig := '';                 NombreCli := '';                  Calle := '';
  NombreCalle := '';                  NumExt := '';                     NumInt := '';
  Colonia := '';                      Poblacion := '';                  Referencia := '';
  CodPostal := '';                    Tel1 := '';                       Tel2 := '';
  Fax := '';                          Email := '';                      Rfc := '';
  Contacto := '';                     UsarEnvio := '';                  UsarFactura := '';
  CiudadId := 0;                      EstadoId := 0;                    PaisId := 0;
  ViaEmbarqueId := 0;
  {$ENDREGION}

  IBQuery.Close;
  IBQuery.SelectSQL.Clear;
  IBQuery.SelectSQL.Add('SELECT A.NOMBRE_CONSIG,A.CALLE,A.NOMBRE_CALLE,A.NUM_EXTERIOR,A.NUM_INTERIOR, ');
  IBQuery.SelectSQL.Add('A.COLONIA,A.POBLACION,A.REFERENCIA,A.CIUDAD_ID,A.ESTADO_ID,A.CODIGO_POSTAL, ');
  IBQuery.SelectSQL.Add('A.PAIS_ID,A.TELEFONO1,A.TELEFONO2,A.FAX,A.EMAIL,A.RFC_CURP,A.CONTACTO, ');
  IBQuery.SelectSQL.Add('A.VIA_EMBARQUE_ID,A.USAR_PARA_ENVIOS,A.USAR_PARA_FACTURAR,A.GLN, ');
  IBQuery.SelectSQL.Add('B.NOMBRE NOMBRE_CLIENTE, A.ES_DIR_PPAL, A.TIPO_PERSONA, A.CLAVE_REGIMEN_FISCAL ');
  IBQuery.SelectSQL.Add('FROM DIRS_CLIENTES A ');
  IBQuery.SelectSQL.Add('INNER JOIN CLIENTES B ON ( A.CLIENTE_ID = B.CLIENTE_ID ) ');
  IBQuery.SelectSQL.Add('WHERE A.DIR_CLI_ID = :DIR_CLI_ID ');
  IBQuery.ParamByName('DIR_CLI_ID').AsInteger := ConsigId;
  IBQuery.Open;

{$REGION 'Asignación de valores'}
  NombreConsig := IBQuery.FieldByName('NOMBRE_CONSIG').AsString;
  NombreCli := IBQuery.FieldByName('NOMBRE_CLIENTE').AsString;
  Calle := IBQuery.FieldByName('CALLE').AsString;
  NombreCalle := IBQuery.FieldByName('NOMBRE_CALLE').AsString;
  NumExt := IBQuery.FieldByName('NUM_EXTERIOR').AsString;
  NumInt := IBQuery.FieldByName('NUM_INTERIOR').AsString;
  Colonia := IBQuery.FieldByName('COLONIA').AsString;
  Poblacion := IBQuery.FieldByName('POBLACION').AsString;
  Referencia := IBQuery.FieldByName('REFERENCIA').AsString;
  CodPostal := IBQuery.FieldByName('CODIGO_POSTAL').AsString;
  Tel1 := IBQuery.FieldByName('TELEFONO1').AsString;
  Tel2 := IBQuery.FieldByName('TELEFONO2').AsString;
  Fax := IBQuery.FieldByName('FAX').AsString;
  Email := IBQuery.FieldByName('EMAIL').AsString;
  Rfc := IBQuery.FieldByName('RFC_CURP').AsString;
  Contacto := IBQuery.FieldByName('CONTACTO').AsString;
  UsarEnvio := IBQuery.FieldByName('USAR_PARA_ENVIOS').AsString;
  UsarFactura := IBQuery.FieldByName('USAR_PARA_FACTURAR').AsString;
  CiudadId := IBQuery.FieldByName('CIUDAD_ID').AsInteger;
  EstadoId := IBQuery.FieldByName('ESTADO_ID').AsInteger;
  PaisId := IBQuery.FieldByName('PAIS_ID').AsInteger;
  ViaEmbarqueId := IBQuery.FieldByName('VIA_EMBARQUE_ID').AsInteger;
  ES_DIR_PPAL := IBQuery.FieldByName('ES_DIR_PPAL').AsString;

  TIPO_PERSONA := IBQuery.FieldByName('TIPO_PERSONA').AsString;
  CLAVE_REGIMEN_FISCAL := IBQuery.FieldByName('CLAVE_REGIMEN_FISCAL').AsString;


  if ES_DIR_PPAL = 'S' then
      NombreConsig := NombreCli;
{$ENDREGION}

  if not IBQuery.Eof then
  begin
    IBQuery2.Close;
    IBQuery2.SelectSQL.Clear;
    IBQuery2.SelectSQL.Add('SELECT A.DIR_CLI_ID ');
    IBQuery2.SelectSQL.Add('FROM DIRS_CLIENTES A ');
    IBQuery2.SelectSQL.Add('WHERE UPPER(A.NOMBRE_CONSIG) = UPPER(:NOMBRE_CONSIG) ');
    IBQuery2.SelectSQL.Add('AND A.CLIENTE_ID = :CLIENTE_ID ');
    IBQuery2.ParamByName('NOMBRE_CONSIG').AsString := NombreConsig;
    IBQuery2.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
    IBQuery2.Open;

    if IBQuery2.FieldByName('DIR_CLI_ID').AsInteger = 0 then
    begin
      IBQuery2.Close;
      IBQuery2.SelectSQL.Clear;
      IBQuery2.SelectSQL.Add('INSERT INTO DIRS_CLIENTES (DIR_CLI_ID, CLIENTE_ID, NOMBRE_CONSIG, CALLE, NOMBRE_CALLE, ');
      IBQuery2.SelectSQL.Add('NUM_EXTERIOR, NUM_INTERIOR, COLONIA, POBLACION, REFERENCIA, CIUDAD_ID, ESTADO_ID, CODIGO_POSTAL, ');
      IBQuery2.SelectSQL.Add('PAIS_ID, TELEFONO1, TELEFONO2, FAX, EMAIL, RFC_CURP, CONTACTO, VIA_EMBARQUE_ID, ES_DIR_PPAL, ');
      IBQuery2.SelectSQL.Add('USAR_PARA_ENVIOS, USAR_PARA_FACTURAR, GLN, TIPO_PERSONA, CLAVE_REGIMEN_FISCAL) VALUES ( ');
      IBQuery2.SelectSQL.Add(':DIR_CLI_ID, :CLIENTE_ID, :NOMBRE_CONSIG, :CALLE, :NOMBRE_CALLE, ');
      IBQuery2.SelectSQL.Add(':NUM_EXTERIOR, :NUM_INTERIOR, :COLONIA, :POBLACION, :REFERENCIA, :CIUDAD_ID, :ESTADO_ID, :CODIGO_POSTAL, ');
      IBQuery2.SelectSQL.Add(':PAIS_ID, :TELEFONO1, :TELEFONO2, :FAX, :EMAIL, :RFC_CURP, :CONTACTO, :VIA_EMBARQUE_ID, :ES_DIR_PPAL, ');
      IBQuery2.SelectSQL.Add(':USAR_PARA_ENVIOS, :USAR_PARA_FACTURAR, :GLN, :TIPO_PERSONA, :CLAVE_REGIMEN_FISCAL ); ');
      DirCliId := GetCatalogoId();
      IBQuery2.ParamByName('DIR_CLI_ID').AsInteger := DirCliId;
      IBQuery2.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
      IBQuery2.ParamByName('NOMBRE_CONSIG').AsString := NombreConsig;
      IBQuery2.ParamByName('CALLE').AsString := Calle;
      IBQuery2.ParamByName('NOMBRE_CALLE').AsString := NombreCalle;
      IBQuery2.ParamByName('NUM_EXTERIOR').AsString := NumExt;
      IBQuery2.ParamByName('NUM_INTERIOR').AsString := NumInt;
      IBQuery2.ParamByName('COLONIA').AsString := Colonia;
      IBQuery2.ParamByName('POBLACION').AsString := Poblacion;
      IBQuery2.ParamByName('REFERENCIA').AsString := Referencia;
      if CiudadId > 0 then
        IBQuery2.ParamByName('CIUDAD_ID').AsInteger := CiudadId
      else
        IBQuery2.ParamByName('CIUDAD_ID').Clear;

      if EstadoId > 0 then
        IBQuery2.ParamByName('ESTADO_ID').AsInteger := EstadoId
      else
        IBQuery2.ParamByName('ESTADO_ID').Clear;


      IBQuery2.ParamByName('CODIGO_POSTAL').AsString := CodPostal;
      if PaisId > 0 then
        IBQuery2.ParamByName('PAIS_ID').AsInteger := PaisId
      else
        IBQuery2.ParamByName('PAIS_ID').Clear;

      IBQuery2.ParamByName('TELEFONO1').AsString := Tel1;
      IBQuery2.ParamByName('TELEFONO2').AsString := Tel2;
      IBQuery2.ParamByName('FAX').AsString := Fax;
      IBQuery2.ParamByName('EMAIL').AsString := Email;
      IBQuery2.ParamByName('RFC_CURP').AsString := Rfc;
      IBQuery2.ParamByName('CONTACTO').AsString := Contacto;
      if ViaEmbarqueId > 0 then
        IBQuery2.ParamByName('VIA_EMBARQUE_ID').AsInteger := ViaEmbarqueId
      else
        IBQuery2.ParamByName('VIA_EMBARQUE_ID').Clear;
      IBQuery2.ParamByName('ES_DIR_PPAL').AsString := 'N';
      IBQuery2.ParamByName('USAR_PARA_ENVIOS').AsString := UsarEnvio;
      IBQuery2.ParamByName('USAR_PARA_FACTURAR').AsString := 'S';
      IBQuery2.ParamByName('GLN').AsString := Gln;
      IBQuery2.ParamByName('TIPO_PERSONA').AsString := TIPO_PERSONA;
      IBQuery2.ParamByName('CLAVE_REGIMEN_FISCAL').AsString := CLAVE_REGIMEN_FISCAL;
      IBQuery2.Open;

      if InsertRFCS_LCO(Rfc, NombreConsig, CodPostal, Error ) then
      begin
        //DirCliId := 0;
        //raise Exception.Create(Error);
        //Result := DirCliId;
      end;

      Result := DirCliId;
      Error := '';
    end else
    begin
      DirCliId := IBQuery2.FieldByName('DIR_CLI_ID').AsInteger;

      if InsertRFCS_LCO(Rfc, NombreConsig, CodPostal, Error ) then
      begin
        //DirCliId := 0;
        //raise Exception.Create(Error);
        //Result := DirCliId;
      end;

      if UpdateDIRS_CLIENTES(DirCliId, TIPO_PERSONA, CLAVE_REGIMEN_FISCAL, Error ) then
      begin
        //DirCliId := 0;
        //raise Exception.Create(Error);
        //Result := DirCliId;
      end;


      Result := DirCliId;
    end;

  end else
  begin
      DirCliId := 0;
      raise Exception.Create('No existe el consignatario fuente.');
      Result := DirCliId;
  end;


 end
except on e : exception do
 begin
   Error := e.Message;
   Result := 0;
 end;
end;

end;

function TFacturaEFormV40.Rellena(cadena:String; Var SerieVnta:String):string;
var
serie,folio:string;
S,i,largo:integer;
begin
folio := Cadena;
S:=0;
for i:= 1 to length(folio) do
        if (folio[i] <> '0') and (folio[i] <> '1') and (folio[i] <> '2') and (folio[i] <> '3') and (folio[i] <> '4') and (folio[i] <> '5') and (folio[i] <> '6') and (folio[i] <> '7') and (folio[i] <> '8') and (folio[i] <> '9') then
                S := S+1;

Serie:=copy(folio,1,S);
Serie := Uppercase(Serie);
IF LENGTH(SERIE) < 4 THEN
BEGIN
if S=0 then Cadena := '000000000';
if S=1 then Cadena := '00000000';
if S=2 then Cadena := '0000000';
if S=3 then Cadena := '000000';

SerieVnta := Serie;

Folio := copy(folio,S+1,length(folio)-S);

for i:=1 to length(folio) do
        Cadena[10-S-i] := Folio[length(folio)+1-i];
RESULT:=SERIE+CADENA;
END
ELSE RESULT := '';
end;

function TFacturaEFormV40.GetPrefer(Nombre:String):String;
Var Valor,Consulta:String;
begin
  if (Nombre = 'AsuntoMail') or (Nombre = 'MensajeMail') or (Nombre = 'AsuntoMailPass') or (Nombre = 'MensajeMailPass')  or (Nombre = 'AsuntoMailNC') or (Nombre = 'MensajeMailNC') or (Nombre = 'AsuntoMailPago') or (Nombre = 'MensajeMailPago') then
     Consulta := 'SELECT VALOR_BLOB VALOR FROM MGFACTURA_CONFIG WHERE NOMBRE = :NOMBRE '
  else
     Consulta := 'SELECT VALOR FROM MGFACTURA_CONFIG WHERE NOMBRE = :NOMBRE ';

  Valor := '';
  IBQuery.Close;
  IBQuery.SelectSQL.Clear;
  IBQuery.SelectSQL.Add (Consulta);
  IBQuery.ParamByName('NOMBRE').AsString := Nombre;
  IBQuery.Open;
  Valor := IBQuery.FieldByName('VALOR').AsString;

  if Valor <> '' then
  begin
      if (Nombre = 'PassTimbre') or (Nombre = 'PassLlave') or (Nombre = 'PassMail') or (Nombre = 'PassCon') then
         Valor := TRIM(IBQuery.FieldByName('VALOR').AsString);
  end else
      Valor := '';

  Result := Valor;

end;

procedure TFacturaEFormV40.HTTPSClientCertificateValidate(Sender: TObject;
  Certificate: TElX509Certificate; var Validity: TSBCertificateValidity;
  var Reason: TSBCertificateValidityReason);
  var Validate :Boolean;
begin
  Validity := cvOk;
  Reason := [];
  if (Certificate.Chain = nil) or Certificate.Chain.Certificates[0].Equals(Certificate) then
  begin

  //Certificate.
	// For proper CRL and OCSP validation please read instructions in
	// description of ElX509CertificateValidator class in the help file
    CertificateValidator.ValidateForSSL(Certificate, HTTPSClient.RemoteHost, HTTPSClient.RemoteIP, hrServer, nil, true, Now, Validity, Reason); //false,
    Validate := Validity = cvOk;
  end
end;

procedure TFacturaEFormV40.HTTPSClientCloseConnection(Sender: TObject;
  CloseReason: TSBCloseReason);
begin
    Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientData(Sender: TObject; Buffer: Pointer;
  Size: Integer);
var S :AnsiString;
begin

  SetLength(S, Size);
  Move(Buffer^, S[1], Size);
  gXml40 := gXml40 + S;
  Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientDocumentBegin(Sender: TObject);
begin
   Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientDocumentEnd(Sender: TObject);
begin
   Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientPreparedHeaders(Sender: TObject;
  Headers: TElStringList);
begin
   Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientReceivingHeaders(Sender: TObject;
  Headers: TElStringList);
begin
   Application.ProcessMessages;
end;

procedure TFacturaEFormV40.HTTPSClientRedirection(Sender: TObject;
  const OldURL: string; var NewURL: string; var AllowRedirection: Boolean);
begin
  AllowRedirection := true;
end;

function TFacturaEFormV40.descifrarTexto(Str : String): String;
var
  Src: TMemoryStream;
  Dst: TStringStream;
  Size: Integer;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
begin
  Result:= EmptyStr;
  Src:= TMemoryStream.Create;
  try
    Dst:= TStringStream.Create(Str);
    try
      StrToStream(Str,Src);
      Src.Position:= 0;
      FillChar(Key,Sizeof(Key),#0);
      if Length(Clave) > Sizeof(Key) then
        move(PChar(Clave)^,Key,Sizeof(key))
      else
        move(PChar(Clave)^,Key,Length(Clave));
      AESExpandKey(ExpandedKey,Key);
      // Leemos el tamaño del texto
      Src.ReadBuffer(Size,Sizeof(Size));
      AESDecryptStreamECB(Src,Dst,ExpandedKey);
      Dst.Size:= Size;
      Result:= Dst.DataString;
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;

function TFacturaEFormV40.CreaDoctoVe(DoctoPedID, LugarExp, ConsigId, FormaCobroId:Integer; serie, UsoCFDI, lDescripcion:String; Var Error:String ):Integer;
var doctoVeId, folioFiscalId, articuloId, usoFolioId, artId, FolioSerieId, detIdOrig,
    FormCobId, CondPagID :Integer;
    unidades, precio, pctjeDscto, consecutivo, sigConsecutivo, total, uReales,
    importe, dsctoArt, pctjeDsctoCli, dsctoExtra, pctjeDsctoVol, pctjeDsctoPromo,
    pctjeComis:Double;
    PathCert, PathKey, Pass, errorA, lError, folio, consecStr, claArt,
    rolD, docto, serId, notas, rol, EsCredito:String;
    SerieSC:String;
Begin
  try
  Begin
    Result := 0;

    doctoVeId := 0;
    errorA := ''; folio := '';
    consecutivo := 0;
    consecStr := '';
    sigConsecutivo := 0; FolioSerieId := 0;
    docto := '';  serId := '';

    // Es remision
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT FIRST 1 A.FORMA_COBRO_CC_ID FROM FORMAS_COBRO_CC A ');
    IBQuery.Open;
    if FormaCobroId>0 then
    FormCobId := FormaCobroId
    else FormCobId := IBQuery.FieldByName('FORMA_COBRO_CC_ID').AsInteger;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.FOLIO_VENTAS_ID, A.CONSECUTIVO FROM FOLIOS_VENTAS A ');
    IBQuery.SelectSQL.Add('WHERE A.SERIE = :SERIE ');
    IBQuery.ParamByName('SERIE').AsString := serie;
    IBQuery.Open;
    FolioSerieId := IBQuery.FieldByName('FOLIO_VENTAS_ID').AsInteger;
    consecutivo := IBQuery.FieldByName('CONSECUTIVO').AsFloat;
    consecStr := FloatToStr(consecutivo);

    if serie <> '@' then  folio := serie + consecStr
      else  folio := consecStr;

    folio := Rellena(folio, SerieSC);

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = :TIPO_DOCTO AND A.FOLIO = :FOLIO ');
    IBQuery.ParamByName('TIPO_DOCTO').AsString := 'F';
    IBQuery.ParamByName('FOLIO').AsString := folio;
    IBQuery.Open;

    if not IBQuery.IsEmpty then
    Begin
        raise Exception.Create('La factura con folio "' + folio + '" ya existe en Microsip, no es posible continuar.');
    End;

    FolioFacVENuew := '';
    FolioFacVENuew := folio;
    doctoVeId := NuevoDoctoVe(DoctoPedID, LugarExp, ConsigId, 'F', folio, UsoCFDI, lDescripcion, errorA);//ConsigId
    if doctoVeId = 0 then  raise Exception.Create(errorA);

    {$region 'Busca detalles'}
    IBQuery2.Close;
    IBQuery2.SelectSQL.Clear;
    IBQuery2.SelectSQL.Add('SELECT A.* ');
    IBQuery2.SelectSQL.Add('FROM DOCTOS_VE_DET A ');
    IBQuery2.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery2.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPedID;
    IBQuery2.Open;

    while not IBQuery2.Eof do
    Begin
        articuloId := 0;
        unidades := 0;
        precio := 0;
        importe := 0;
        pctjeDscto := 0;
        dsctoArt := 0;
        pctjeDsctoCli := 0;
        dsctoExtra := 0;
        pctjeDsctoVol := 0;
        pctjeDsctoPromo := 0;
        pctjeComis := 0;
        notas := '';
        rol := '';
        claArt := '';
        detIdOrig := 0;

        articuloId := IBQuery2.FieldByName('ARTICULO_ID').AsInteger;
        unidades := IBQuery2.FieldByName('UNIDADES').AsFloat;
        precio := IBQuery2.FieldByName('PRECIO_UNITARIO').AsFloat;
        importe := IBQuery2.FieldByName('PRECIO_TOTAL_NETO').AsFloat;
        pctjeDscto := IBQuery2.FieldByName('PCTJE_DSCTO').AsFloat;
        dsctoArt := IBQuery2.FieldByName('DSCTO_ART').AsFloat;
        pctjeDsctoCli := IBQuery2.FieldByName('PCTJE_DSCTO_CLI').AsFloat;
        dsctoExtra := IBQuery2.FieldByName('DSCTO_EXTRA').AsFloat;
        pctjeDsctoVol := IBQuery2.FieldByName('PCTJE_DSCTO_VOL').AsFloat;
        pctjeDsctoPromo := IBQuery2.FieldByName('PCTJE_DSCTO_PROMO').AsFloat;
        pctjeComis := IBQuery2.FieldByName('PCTJE_COMIS').AsFloat;
        rol := IBQuery2.FieldByName('ROL').AsString;
        notas := IBQuery2.FieldByName('NOTAS').AsString;
        claArt := IBQuery2.FieldByName('CLAVE_ARTICULO').AsString;
        detIdOrig := IBQuery2.FieldByName('DOCTO_VE_DET_ID').AsInteger;

        if RenglonDoctoVe(DoctoPedID, detIdOrig, doctoVeId, articuloId, unidades, precio, importe, pctjeDscto, dsctoArt,
          pctjeDsctoCli, dsctoExtra, pctjeDsctoVol, pctjeDsctoPromo, pctjeComis, rol, notas, claArt, errorA) = False then
            raise Exception.Create(errorA);

        IBQuery2.Next;
    End;
    {$endregion}


    {$region 'Inserta forma de cobro'}
	IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.COND_PAGO_ID, A.CLIENTE_ID, A.VIA_EMBARQUE_ID ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := DoctoPedID;
    IBQuery.Open;
	CondPagID := 0;
    CondPagID := IBQuery.FieldByName('COND_PAGO_ID').AsInteger;

	EsCredito:='N';
    if CondPagID <> 0 then
    Begin
	  IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT SUM(DIAS_PLAZO) DIAS ');
	  IBQuery.SelectSQL.Add('FROM PLAZOS_COND_PAG ');
	  IBQuery.SelectSQL.Add('WHERE COND_PAGO_ID = :COND_PAGO_ID ');
      IBQuery.ParamByName('COND_PAGO_ID').AsInteger := CondPagID;
      IBQuery.Open;
	  EsCredito:='N';
	  if IBQuery.FieldByName('DIAS').AsInteger > 0 then
	  begin
		EsCredito:='S';
	  end;
    End;

    try
    Begin
      if EsCredito <> 'S' then
	  begin
		IBQuery.Close;
		IBQuery.SelectSQL.Clear;
		IBQuery.SelectSQL.Add('INSERT INTO FORMAS_COBRO_DOCTOS (FORMA_COBRO_DOC_ID, NOM_TABLA_DOCTOS, DOCTO_ID, ');
		IBQuery.SelectSQL.Add('FORMA_COBRO_ID, NUM_CTA_PAGO, CLAVE_SIS_FORMA_COB, REFERENCIA, IMPORTE) ');
		IBQuery.SelectSQL.Add('VALUES (:FORMA_COBRO_DOC_ID, :NOM_TABLA_DOCTOS, :DOCTO_ID, :FORMA_COBRO_ID, ');
		IBQuery.SelectSQL.Add(':NUM_CTA_PAGO, :CLAVE_SIS_FORMA_COB, :REFERENCIA, :IMPORTE) ');
		IBQuery.ParamByName('FORMA_COBRO_DOC_ID').AsInteger := -1;
		IBQuery.ParamByName('NOM_TABLA_DOCTOS').AsString := 'DOCTOS_VE';
		IBQuery.ParamByName('DOCTO_ID').AsInteger := doctoVeId;
		IBQuery.ParamByName('FORMA_COBRO_ID').AsInteger := FormCobId;
		IBQuery.ParamByName('NUM_CTA_PAGO').Clear;
		IBQuery.ParamByName('CLAVE_SIS_FORMA_COB').AsString := 'CC';
		IBQuery.ParamByName('REFERENCIA').AsString := '';
		IBQuery.ParamByName('IMPORTE').AsFloat := 0;
		IBQuery.Open;
	  end;
    End;
    except on e:Exception do
    Begin
        raise Exception.Create('Insertar forma de cobro. Error: ' + e.Message);
    End;
    end;

    {$endregion}


    {$region 'Insertar en usos folios fiscales'}
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT B.FOLIOS_FISCALES_ID ');
    IBQuery.SelectSQL.Add('FROM FOLIOS_VENTAS A ');
    IBQuery.SelectSQL.Add('LEFT JOIN FOLIOS_FISCALES B ON (A.SERIE = B.SERIE) ');
    IBQuery.SelectSQL.Add('WHERE A.TIPO_DOCTO = ''F'' AND A.MODALIDAD_FACTURACION = ''CFDI'' ');
    IBQuery.SelectSQL.Add('AND A.SERIE = :SERIE ');
    IBQuery.ParamByName('SERIE').AsString := serie;
    IBQuery.Open;
    folioFiscalId := IBQuery.FieldByName('FOLIOS_FISCALES_ID').AsInteger;

    if folioFiscalId = 0 then
    Begin
      folioFiscalId := ObtenerDoctoId();
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('INSERT INTO FOLIOS_FISCALES ');
      IBQuery.SelectSQL.Add('(FOLIOS_FISCALES_ID, SERIE, FOLIO_INI, FOLIO_FIN, ULTIMO_UTILIZADO, NUM_APROBACION, ');
      IBQuery.SelectSQL.Add('ANO_APROBACION, MODALIDAD_FACTURACION, FECHA_APROBACION, FECHA_VENCIMIENTO, IMAGEN_CBB) ');
      IBQuery.SelectSQL.Add('VALUES ');
      IBQuery.SelectSQL.Add('(:FOLIOS_FISCALES_ID, :SERIE, :FOLIO_INI, :FOLIO_FIN, :ULTIMO_UTILIZADO, :NUM_APROBACION, ');
      IBQuery.SelectSQL.Add(':ANO_APROBACION, :MODALIDAD_FACTURACION, :FECHA_APROBACION, :FECHA_VENCIMIENTO, :IMAGEN_CBB) ');
      IBQuery.ParamByName('FOLIOS_FISCALES_ID').AsInteger := folioFiscalId;
      IBQuery.ParamByName('SERIE').AsString := UpperCase(serie);
      IBQuery.ParamByName('FOLIO_INI').AsFloat := 1;
      IBQuery.ParamByName('FOLIO_FIN').AsFloat := 999999999;
      IBQuery.ParamByName('ULTIMO_UTILIZADO').AsInteger := 0;
      IBQuery.ParamByName('NUM_APROBACION').AsString := '1';
      IBQuery.ParamByName('ANO_APROBACION').AsInteger := 1;
      IBQuery.ParamByName('MODALIDAD_FACTURACION').AsString := 'CFDI';
      IBQuery.ParamByName('FECHA_APROBACION').Clear;
      IBQuery.ParamByName('FECHA_VENCIMIENTO').Clear;
      IBQuery.ParamByName('IMAGEN_CBB').Clear;
      IBQuery.Open;

    End;

    usoFolioId := ObtenerDoctoId();
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('INSERT INTO USOS_FOLIOS_FISCALES (USO_FOLIO_ID, FOLIOS_FISCALES_ID, FOLIO, FECHA, SISTEMA, DOCTO_ID) ');
    IBQuery.SelectSQL.Add('VALUES (:USO_FOLIO_ID, :FOLIOS_FISCALES_ID, :FOLIO, :FECHA, ''VE'', :DOCTO_ID); ');
    IBQuery.ParamByName('USO_FOLIO_ID').AsInteger := usoFolioId;
    IBQuery.ParamByName('FOLIOS_FISCALES_ID').AsInteger := folioFiscalId;
    IBQuery.ParamByName('FOLIO').AsFloat := consecutivo;
    IBQuery.ParamByName('FECHA').AsDate := Now;
    IBQuery.ParamByName('DOCTO_ID').AsInteger := doctoVeId;
    IBQuery.Open;
    {$endregion}

    //Calcula los totales del documento
    spCalcTotVe.Close;
    spCalcTotVe.ParamByName('DOCTO_VE_ID').AsInteger:= doctoVeId;
    spCalcTotVe.ParamByName('SOLO_LECTURA').AsString:= 'N';
    spCalcTotVe.ExecProc;

    //Aplica el documento en Microsip
    spAplicaVe.Close;
    spAplicaVe.ParamByName('V_DOCTO_VE_ID').AsInteger:= doctoVeId;
    spAplicaVe.ExecProc;

    GeneraXmlVe40(doctoVeId,'F',Error);
    if Trim(Error) <> '' then
    begin
        Raise Exception.Create('Ocurrió un error al momento de generar la factura electrónica. '+#13+Error);
    end;

    //Actualiza consecutivo de la serie de la remisión
    sigConsecutivo := consecutivo + 1;
    if ModificaFoliosSiguientes(sigConsecutivo, FolioSerieId, errorA) = False then
        raise Exception.Create(errorA);

    Result := doctoVeId;
  End;
  except on e:Exception do
  Begin
      Error := 'Error general al crear la factura: ' +IntToStr(LugarExp)+'liz'+gmetodoPagoSat+ e.Message;
      Result := 0;
  End;
  end;
End;

function TFacturaEFormV40.NuevoDoctoVe(pedId, LugarExp, dirCliId:Integer; tipoDocto, folio, UsoCFDI, lDescripcion:String; Var Error:String):Integer;
var monedaId, doctoVeId, vendedorId, almacenId, lugarExpedicionId,
    diasPpag, CondPago, ClienteId, ViaEmbId, SUCURSAL_ID :Integer;
    claveCli, metodoPagoSat, docto, estatus, OCompra1:String;
    tipoCambio, pctjePpag, DSCTO_PCTJE, DSCTO_IMPORTE:Double;
    fechaHora, FOCompra1:TDateTime;
    fecha, fechaPpag:TDateTime;
	EsCredito, TIPO_DSCTO, DESCRIPCION_ORI, SCondPago:String;
begin
  try
  begin
    Result := 0;

    CondPago := 0; almacenId := 0; monedaId := 0; vendedorId := 0;

	tipoCambio := 0; SUCURSAL_ID := 0;
    metodoPagoSat := '';
    lugarExpedicionId := 0;
    claveCli := ''; estatus := '';
    pctjePpag := 0; diasPpag := 0; fechaPpag := 0;  ViaEmbId := 0;

    if tipoDocto = 'F' then
      docto := 'factura';

    IBQuery3.Close;
    IBQuery3.SelectSQL.Clear;
    IBQuery3.SelectSQL.Add('SELECT FIRST 1 SUCURSAL_ID FROM SUCURSALES ');
    IBQuery3.Open;
    SUCURSAL_ID := 0;
    SUCURSAL_ID := IBQuery3.FieldByName('SUCURSAL_ID').AsInteger;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.COND_PAGO_ID, A.CLIENTE_ID, A.VIA_EMBARQUE_ID, A.ORDEN_COMPRA, A.FECHA_ORDEN_COMPRA, A.TIPO_DSCTO, ');
    IBQuery.SelectSQL.Add('A.DSCTO_PCTJE, A.DSCTO_IMPORTE, A.DESCRIPCION');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := pedId;
    IBQuery.Open;
    CondPago := IBQuery.FieldByName('COND_PAGO_ID').AsInteger;
    SCondPago := IBQuery.FieldByName('COND_PAGO_ID').AsString;
    ClienteId := IBQuery.FieldByName('CLIENTE_ID').AsInteger;
    ViaEmbId := IBQuery.FieldByName('VIA_EMBARQUE_ID').AsInteger;
    OCompra1 := IBQuery.FieldByName('ORDEN_COMPRA').AsString;
    FOCompra1 := IBQuery.FieldByName('FECHA_ORDEN_COMPRA').AsDateTime;
    TIPO_DSCTO := IBQuery.FieldByName('TIPO_DSCTO').AsString;
    DSCTO_PCTJE := IBQuery.FieldByName('DSCTO_PCTJE').AsFloat;
    DSCTO_IMPORTE := IBQuery.FieldByName('DSCTO_IMPORTE').AsFloat;
    DESCRIPCION_ORI := IBQuery.FieldByName('DESCRIPCION').AsString;

    if CondPago <> 0 then
    Begin
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT A.PCTJE_DSCTO_PPAG, A.DIAS_PPAG ');
      IBQuery.SelectSQL.Add('FROM CONDICIONES_PAGO A ');
      IBQuery.SelectSQL.Add('WHERE A.COND_PAGO_ID = :COND_PAGO_ID ');
      IBQuery.ParamByName('COND_PAGO_ID').AsInteger := CondPago;
      IBQuery.Open;
      pctjePpag:=IBQuery.FieldByName('PCTJE_DSCTO_PPAG').AsFloat;
      diasPpag:=IBQuery.FieldByName('DIAS_PPAG').AsInteger;

	  IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT SUM(DIAS_PLAZO) DIAS ');
	  IBQuery.SelectSQL.Add('FROM PLAZOS_COND_PAG ');
	  IBQuery.SelectSQL.Add('WHERE COND_PAGO_ID = :COND_PAGO_ID ');
      IBQuery.ParamByName('COND_PAGO_ID').AsInteger := CondPago;
      IBQuery.Open;
	  EsCredito:='N';
	  if IBQuery.FieldByName('DIAS').AsInteger > 0 then
	  begin
		EsCredito:='S';
	  end;
    End;

    {$region 'Validad Via de Embarque'}
    if ViaEmbId = 0 then
    begin
        IBQuery.Close;
        IBQuery.SelectSQL.Clear;
        IBQuery.SelectSQL.Add('SELECT A.VIA_EMBARQUE_ID FROM DIRS_CLIENTES A  ');
        IBQuery.SelectSQL.Add('WHERE A.ES_DIR_PPAL = ''S''  ');
        IBQuery.SelectSQL.Add('AND A.CLIENTE_ID = :CLIENTE_ID  ');
        IBQuery.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
        IBQuery.Open;
        ViaEmbId := IBQuery.FieldByName('VIA_EMBARQUE_ID').AsInteger;
        if ViaEmbId = 0 then
        begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT A.VIA_EMBARQUE_ID FROM VIAS_EMBARQUE A ');
            IBQuery.SelectSQL.Add('WHERE A.ES_PREDET = ''S'' ');
            IBQuery.Open;
            ViaEmbId := IBQuery.FieldByName('VIA_EMBARQUE_ID').AsInteger;
            if ViaEmbId = 0 then
            begin
                IBQuery.Close;
                IBQuery.SelectSQL.Clear;
                IBQuery.SelectSQL.Add('SELECT FIRST 1 A.VIA_EMBARQUE_ID FROM VIAS_EMBARQUE A  ');
                IBQuery.Open;
                ViaEmbId := IBQuery.FieldByName('VIA_EMBARQUE_ID').AsInteger;
                if ViaEmbId = 0 then raise Exception.Create('Verifique la vía de embarque');
            end;
        end;
    end;
    {$endregion}

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.ALMACEN_ID, A.VENDEDOR_ID, A.TIPO_CAMBIO, A.MONEDA_ID, A.CLAVE_CLIENTE ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := pedId;
    IBQuery.Open;

    almacenId:=IBQuery.FieldByName('ALMACEN_ID').AsInteger;
    vendedorId:=IBQuery.FieldByName('VENDEDOR_ID').AsInteger;
    tipoCambio:=IBQuery.FieldByName('TIPO_CAMBIO').AsFloat;
    monedaId:=IBQuery.FieldByName('MONEDA_ID').AsInteger;
    claveCli:=IBQuery.FieldByName('CLAVE_CLIENTE').AsString;


    if dirCliId = 0 then
    begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT FIRST 1 A.DIR_CLI_ID, A.VIA_EMBARQUE_ID FROM DIRS_CLIENTES A  ');
            IBQuery.SelectSQL.Add('WHERE A.CLIENTE_ID=:CLIENTE_ID AND A.ES_DIR_PPAL=''S'' ');
            IBQuery.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
            IBQuery.Open;
            dirCliId := IBQuery.FieldByName('DIR_CLI_ID').AsInteger;
    end;

    if tipoCambio=0 then
      tipoCambio:=1;

    lugarExpedicionId := LugarExp;


	if EsCredito <> 'S' then
      metodoPagoSat := 'PUE'
    else
      metodoPagoSat := 'PPD';

   gmetodoPagoSat := metodoPagoSat;

    estatus := 'N';

    fechaHora:= Now;
    fecha := Date;
    if CondPago <> 0 then
      fechaPpag := fecha + diasPpag;

    {$REGION 'Inserta docto ventas'}
    doctoVeId := ObtenerDoctoId();

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('INSERT INTO DOCTOS_VE (DOCTO_VE_ID, TIPO_DOCTO, SUBTIPO_DOCTO, FOLIO, FECHA, HORA, ');
    IBQuery.SelectSQL.Add('CLAVE_CLIENTE, CLIENTE_ID, DIR_CLI_ID, DIR_CONSIG_ID, ALMACEN_ID, LUGAR_EXPEDICION_ID, ');
    IBQuery.SelectSQL.Add('MONEDA_ID, TIPO_CAMBIO, TIPO_DSCTO, DSCTO_PCTJE, DSCTO_IMPORTE, ESTATUS, APLICADO, ');
    IBQuery.SelectSQL.Add('FECHA_VIGENCIA_ENTREGA, ORDEN_COMPRA, FECHA_ORDEN_COMPRA, FOLIO_RECIBO_MERCANCIA, ');
    IBQuery.SelectSQL.Add('FECHA_RECIBO_MERCANCIA, DESCRIPCION, IMPORTE_NETO, FLETES, OTROS_CARGOS, TOTAL_IMPUESTOS, ');
    IBQuery.SelectSQL.Add('TOTAL_RETENCIONES, TOTAL_ANTICIPOS, PESO_EMBARQUE, FORMA_EMITIDA, CONTABILIZADO, ACREDITAR_CXC, ');
    IBQuery.SelectSQL.Add('SISTEMA_ORIGEN, COND_PAGO_ID, FECHA_DSCTO_PPAG, PCTJE_DSCTO_PPAG, VENDEDOR_ID, PCTJE_COMIS, ');
    IBQuery.SelectSQL.Add('VIA_EMBARQUE_ID, IMPORTE_COBRO, DESCRIPCION_COBRO, IMPUESTO_SUSTITUIDO_ID, IMPUESTO_SUSTITUTO_ID, ');
    IBQuery.SelectSQL.Add('USUARIO_CREADOR, ES_CFD, MODALIDAD_FACTURACION, ENVIADO, FECHA_HORA_ENVIO, EMAIL_ENVIO, ');
    IBQuery.SelectSQL.Add('CFD_ENVIO_ESPECIAL, USO_CFDI, METODO_PAGO_SAT, CFDI_CERTIFICADO, ');  //CFDI_FACT_DEVUELTA_ID,
    IBQuery.SelectSQL.Add('FECHA_HORA_CREACION, USUARIO_ULT_MODIF, USUARIO_AUT_CREACION, FECHA_HORA_ULT_MODIF, ');
    IBQuery.SelectSQL.Add('CARGAR_SUN, USUARIO_AUT_MODIF, USUARIO_CANCELACION, FECHA_HORA_CANCELACION, USUARIO_AUT_CANCELACION, SUCURSAL_ID) ');

    IBQuery.SelectSQL.Add('VALUES (:DOCTO_VE_ID, :TIPO_DOCTO, ''N'', :FOLIO, :FECHA, :HORA, ');
    IBQuery.SelectSQL.Add(':CLAVE_CLIENTE, :CLIENTE_ID, :DIR_CLI_ID, :DIR_CONSIG_ID, :ALMACEN_ID, :LUGAR_EXPEDICION_ID, ');
    IBQuery.SelectSQL.Add(':MONEDA_ID, :TIPO_CAMBIO, :TIPO_DSCTO, :DSCTO_PCTJE, :DSCTO_IMPORTE, :ESTATUS, ''N'', ');
    IBQuery.SelectSQL.Add('NULL, :ORDEN_COMPRA, :FECHA_ORDEN_COMPRA, :FOLIO_RECIBO_MERCANCIA, ');
    IBQuery.SelectSQL.Add(':FECHA_RECIBO_MERCANCIA, :DESCRIPCION, 0, 0, 0, 0, ');
    IBQuery.SelectSQL.Add('0, 0, 0, ''N'', ''N'', ''N'', ');
    IBQuery.SelectSQL.Add('''VE'', :COND_PAGO_ID, :FECHA_DSCTO_PPAG, :PCTJE_DSCTO_PPAG, :VENDEDOR_ID, 0, ');
    IBQuery.SelectSQL.Add(':VIA_EMBARQUE_ID, 0, NULL, NULL, NULL, ');
    IBQuery.SelectSQL.Add(':USUARIO_CREADOR, :ES_CFD, :MODALIDAD_FACTURACION, ''N'', :FECHA_HORA_ENVIO, NULL, ');
    IBQuery.SelectSQL.Add('''N'', :USO_CFDI, :METODO_PAGO_SAT, ''N'', ');  //NULL,
    IBQuery.SelectSQL.Add(':FECHA_HORA_CREACION, :USUARIO_ULT_MODIF, NULL, :FECHA_HORA_ULT_MODIF, ');
    IBQuery.SelectSQL.Add('''S'', NULL, NULL, NULL, NULL, :SUCURSAL_ID) ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := doctoVeId;
    IBQuery.ParamByName('TIPO_DOCTO').AsString := tipoDocto;
    IBQuery.ParamByName('FOLIO').AsString := folio;

    IBQuery.ParamByName('FECHA').AsDate := fecha;
    IBQuery.ParamByName('HORA').AsTime := Time;
    IBQuery.ParamByName('CLAVE_CLIENTE').AsString := claveCli;
    IBQuery.ParamByName('CLIENTE_ID').AsInteger := ClienteId;
    if dirCliId > 0 then
      IBQuery.ParamByName('DIR_CLI_ID').AsInteger:= dirCliId
    else
      IBQuery.ParamByName('DIR_CLI_ID').Clear;
    if dirCliId > 0 then
      IBQuery.ParamByName('DIR_CONSIG_ID').AsInteger := dirCliId//dirConsigId
    else
      IBQuery.ParamByName('DIR_CONSIG_ID').Clear;
    IBQuery.ParamByName('ALMACEN_ID').AsInteger:= almacenId;
    if lugarExpedicionId = 0 then
     IBQuery.ParamByName('LUGAR_EXPEDICION_ID').Clear
    else
      IBQuery.ParamByName('LUGAR_EXPEDICION_ID').AsInteger := lugarExpedicionId;
    IBQuery.ParamByName('MONEDA_ID').AsInteger := monedaId;
    IBQuery.ParamByName('TIPO_CAMBIO').AsFloat := tipoCambio;

    IBQuery.ParamByName('TIPO_DSCTO').AsString := TIPO_DSCTO;//28/01/2022'P';
    IBQuery.ParamByName('DSCTO_IMPORTE').AsFloat := DSCTO_IMPORTE;//28/01/2022 0;
    IBQuery.ParamByName('DSCTO_PCTJE').AsFloat := DSCTO_PCTJE;


    IBQuery.ParamByName('ESTATUS').AsString := estatus;
    if OCompra1<>'' then
    begin
      IBQuery.ParamByName('ORDEN_COMPRA').AsString  := OCompra1;
      IBQuery.ParamByName('FECHA_ORDEN_COMPRA').AsDate := FOCompra1;
    end
    else
    begin
    IBQuery.ParamByName('ORDEN_COMPRA').Clear;
    IBQuery.ParamByName('FECHA_ORDEN_COMPRA').Clear;
    end;

    IBQuery.ParamByName('FOLIO_RECIBO_MERCANCIA').Clear;
    IBQuery.ParamByName('FECHA_RECIBO_MERCANCIA').Clear;
    IBQuery.ParamByName('DESCRIPCION').AsString := Copy(DESCRIPCION_ORI+' '+lDescripcion,1,200);
    if CondPago>0 then
    Begin
      IBQuery.ParamByName('COND_PAGO_ID').AsInteger := CondPago;
      IBQuery.ParamByName('FECHA_DSCTO_PPAG').AsDate := fechaPpag;
      IBQuery.ParamByName('PCTJE_DSCTO_PPAG').AsFloat := pctjePpag;
    End
    else
    Begin
      IBQuery.ParamByName('COND_PAGO_ID').Clear;
      IBQuery.ParamByName('FECHA_DSCTO_PPAG').Clear;
      IBQuery.ParamByName('PCTJE_DSCTO_PPAG').Clear;
    End;

    if vendedorId > 0 then
      IBQuery.ParamByName('VENDEDOR_ID').AsInteger:=vendedorId
    else
     IBQuery.ParamByName('VENDEDOR_ID').Clear;

    IBQuery.ParamByName('VIA_EMBARQUE_ID').AsInteger:=ViaEmbId;
    IBQuery.ParamByName('USUARIO_CREADOR').AsString := 'SYSDBA';
    IBQuery.ParamByName('ES_CFD').AsString := 'S';
    IBQuery.ParamByName('MODALIDAD_FACTURACION').AsString := 'CFDI';
    IBQuery.ParamByName('FECHA_HORA_ENVIO').AsDateTime := fechaHora;
    IBQuery.ParamByName('USO_CFDI').AsString := UsoCFDI;
    if metodoPagoSat = '' then
      IBQuery.ParamByName('METODO_PAGO_SAT').Clear
    else
      IBQuery.ParamByName('METODO_PAGO_SAT').AsString := metodoPagoSat;
    IBQuery.ParamByName('FECHA_HORA_CREACION').AsDateTime:= fechaHora;
    IBQuery.ParamByName('USUARIO_ULT_MODIF').AsString := 'SYSDBA';
    IBQuery.ParamByName('FECHA_HORA_ULT_MODIF').AsDateTime:=fechaHora;
    IBQuery.ParamByName('SUCURSAL_ID').AsInteger := SUCURSAL_ID;
    IBQuery.Open;

    if tipoDocto = 'F' then
    Begin
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('DELETE FROM VENCIMIENTOS_CARGOS_VE WHERE DOCTO_VE_ID = :DOCTO_VE_ID');
      IBQuery.ParamByName('DOCTO_VE_ID').AsInteger:= doctoVeId;
      IBQuery.Open;

      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT DIAS_PLAZO, PCTJE_VEN FROM PLAZOS_COND_PAG WHERE COND_PAGO_ID = :COND_PAGO_ID');
      IBQuery.ParamByName('COND_PAGO_ID').AsInteger := CondPago;
      IBQuery.Open;

      while not IBQuery.Eof do
      begin
        IBQuery2.Close;
        IBQuery2.SelectSQL.Clear;
        IBQuery2.SelectSQL.Add('INSERT INTO VENCIMIENTOS_CARGOS_VE(DOCTO_VE_ID, FECHA_VENCIMIENTO, PCTJE_VEN)');
        IBQuery2.SelectSQL.Add('VALUES(:DOCTO_VE_ID, :FECHA_VENCIMIENTO, :PCTJE_VEN)');
        IBQuery2.ParamByName('DOCTO_VE_ID').AsInteger := doctoVeId;
        IBQuery2.ParamByName('FECHA_VENCIMIENTO').AsDate := fecha + IBQuery.Fieldbyname('DIAS_PLAZO').AsInteger; //lFecha
        IBQuery2.ParamByName('PCTJE_VEN').AsFloat := IBQuery.Fieldbyname('PCTJE_VEN').AsFloat;
        IBQuery2.Open;

        IBQuery.Next;
      end;
    End;

    {$ENDREGION}

    Result := doctoVeId;
  end
  except on e:exception do
  begin
      Error := '[Encabezado] Docto: ' + docto + ' - ' +SCondPago+EsCredito+metodoPagoSat+ e.Message;
      Result := 0;
  end;
  end;
end;

function TFacturaEFormV40.RenglonDoctoVe(pedId, pedDetId, doctoVeId, articuloId:Integer; unidades, precio, importe, pctjeDscto, dsctoArt,
          pctjeDsctoCli, dsctoExtra, pctjeDsctoVol, pctjeDsctoPromo, pctjeComis:Double; rol, notas, claArt:String; Var Error:String):Boolean;
var doctoVeLigaId, doctoVeDet :Integer;
    uni:Double;
begin
  try
  begin
    Result:= False;
    doctoVeDet := 0;

    doctoVeDet := ObtenerDoctoId();

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('INSERT INTO DOCTOS_VE_DET (DOCTO_VE_DET_ID, DOCTO_VE_ID, CLAVE_ARTICULO, ARTICULO_ID, ');
    IBQuery.SelectSQL.Add('UNIDADES, PRECIO_UNITARIO, PCTJE_DSCTO, DSCTO_ART, PCTJE_DSCTO_CLI, ');
    IBQuery.SelectSQL.Add('DSCTO_EXTRA, PCTJE_DSCTO_VOL, PCTJE_DSCTO_PROMO, PRECIO_TOTAL_NETO, ');
    IBQuery.SelectSQL.Add('PCTJE_COMIS, ROL, NOTAS, POSICION) ');
    IBQuery.SelectSQL.Add('VALUES (:DOCTO_VE_DET_ID, :DOCTO_VE_ID, :CLAVE_ARTICULO, :ARTICULO_ID, :UNIDADES, ');
    IBQuery.SelectSQL.Add(':PRECIO_UNITARIO, :PCTJE_DSCTO, :DSCTO_ART, :PCTJE_DSCTO_CLI, :DSCTO_EXTRA, ');
    IBQuery.SelectSQL.Add(':PCTJE_DSCTO_VOL, :PCTJE_DSCTO_PROMO, :PRECIO_TOTAL_NETO, :PCTJE_COMIS, :ROL, :NOTAS, :POSICION) ');
    IBQuery.ParamByName('DOCTO_VE_DET_ID').AsInteger := doctoVeDet;
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := doctoVeId;
    IBQuery.ParamByName('CLAVE_ARTICULO').AsString := claArt;
    IBQuery.ParamByName('ARTICULO_ID').AsInteger := articuloId;
    IBQuery.ParamByName('UNIDADES').AsFloat := unidades;
    IBQuery.ParamByName('PRECIO_UNITARIO').AsFloat := precio;
    IBQuery.ParamByName('PCTJE_DSCTO').AsFloat := pctjeDscto;
    IBQuery.ParamByName('DSCTO_ART').AsFloat := 0;
    IBQuery.ParamByName('PCTJE_DSCTO_CLI').AsFloat := pctjeDsctoCli;
    IBQuery.ParamByName('DSCTO_EXTRA').AsFloat := dsctoExtra;
    IBQuery.ParamByName('PCTJE_DSCTO_VOL').AsFloat := pctjeDsctoVol;
    IBQuery.ParamByName('PCTJE_DSCTO_PROMO').AsFloat := pctjeDsctoPromo;
    IBQuery.ParamByName('PRECIO_TOTAL_NETO').AsFloat := Importe;
    IBQuery.ParamByName('PCTJE_COMIS').AsFloat := pctjeComis;
    IBQuery.ParamByName('ROL').AsString := rol;
    IBQuery.ParamByName('NOTAS').AsString := notas;
    IBQuery.ParamByName('POSICION').AsFloat := -1;
    IBQuery.Open;

    //Inserta ligas entre remision y factura encabezado
    doctoVeLigaId := 0;
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_LIGA_ID ');
    IBQuery.SelectSQL.Add('FROM DOCTOS_VE_LIGAS A ');
    IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_FTE_ID = :DOCTO_VE_FTE_ID ');
    IBQuery.SelectSQL.Add('AND A.DOCTO_VE_DEST_ID = :DOCTO_VE_DEST_ID ');
    IBQuery.ParamByName('DOCTO_VE_FTE_ID').AsInteger := pedId;
    IBQuery.ParamByName('DOCTO_VE_DEST_ID').AsInteger := doctoVeId;
    IBQuery.Open;

    doctoVeLigaId := IBQuery.FieldByName('DOCTO_VE_LIGA_ID').AsInteger;

    if doctoVeLigaId = 0 then
    Begin
      doctoVeLigaId := ObtenerDoctoId();

      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('INSERT INTO DOCTOS_VE_LIGAS (DOCTO_VE_LIGA_ID, DOCTO_VE_FTE_ID, DOCTO_VE_DEST_ID) ');
      IBQuery.SelectSQL.Add('VALUES (:DOCTO_VE_LIGA_ID, :DOCTO_VE_FTE_ID, :DOCTO_VE_DEST_ID) ');
      IBQuery.ParamByName('DOCTO_VE_LIGA_ID').AsInteger := doctoVeLigaId;
      IBQuery.ParamByName('DOCTO_VE_FTE_ID').AsInteger := pedId;
      IBQuery.ParamByName('DOCTO_VE_DEST_ID').AsInteger := doctoVeId;
      IBQuery.Open;

    End;

    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('INSERT INTO DOCTOS_VE_LIGAS_DET (DOCTO_VE_LIGA_ID, DOCTO_VE_DET_FTE_ID, DOCTO_VE_DET_DEST_ID) ');
    IBQuery.SelectSQL.Add('VALUES (:DOCTO_VE_LIGA_ID, :DOCTO_VE_DET_FTE_ID, :DOCTO_VE_DET_DEST_ID) ');
    IBQuery.ParamByName('DOCTO_VE_LIGA_ID').AsInteger := doctoVeLigaId;
    IBQuery.ParamByName('DOCTO_VE_DET_FTE_ID').AsInteger := pedDetId;
    IBQuery.ParamByName('DOCTO_VE_DET_DEST_ID').AsInteger := doctoVeDet;
    IBQuery.Open;

    Result := True;
  end
  except on e:exception do
  begin
      Error := '[Detalle]: '+e.Message;
      Result := False;
  end;
  end;
end;

function TFacturaEFormV40.ObtenerDoctoId():Integer;
Begin
  Result := 0;
  spGenDoctoId.Close;
  spGenDoctoId.ExecProc();
  Result := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
End;

function TFacturaEFormV40.ModificaFoliosSiguientes(consecutivo:Double; serieId:Integer; Var Error:String):Boolean;
Begin
    Result := False;
    try
    Begin
        IBQuery.Close;
        IBQuery.SelectSQL.Clear;
        IBQuery.SelectSQL.Add('UPDATE FOLIOS_VENTAS ');
        IBQuery.SelectSQL.Add('SET CONSECUTIVO = :CONSECUTIVO ');
        IBQuery.SelectSQL.Add('WHERE (FOLIO_VENTAS_ID = :FOLIO_VENTAS_ID) ');
        IBQuery.ParamByName('CONSECUTIVO').AsFloat := consecutivo;
        IBQuery.ParamByName('FOLIO_VENTAS_ID').AsInteger := serieId;
        IBQuery.Open;

        Result := True;
    End;
    except on e:Exception do
      Begin
          Error := 'Error general al modificar el consecutivo de la serie de ventas:' + e.Message;
          Result := False;
      End;
    end;
End;

function TFacturaEFormV40.ValidacionesTicket(Folio, SistemaOrigen :String; Var Error:String; var FolDoc, TipoDoc, OCompra:String):Integer;
Var FolioDev,FolioFac,Estatus:String;
TicketId,Dias,Diferencia, Docto_Dest :Integer;
FechaTicket:TDate;
ActivadoDias,SoloFacMesVM, TipoDoctoVE, TipoDocto, FolioR :String;
EnTiempo,MismoMes:Boolean;
SerieSC:String;
begin

try
 begin
      Result := 0;

      FolioDev := '';
      FolioFac := '';
      TicketId := 0;  Docto_Dest := 0;
      Estatus := '';  FolioR := '';
      FolioR := Rellena(Folio, SerieSC);
      SoloFacMesVM := '';  TipoDoctoVE := '';  TipoDocto := '';
      MismoMes := False;

      ActivadoDias := GetPrefer('ActivarDias');
      if ActivadoDias = 'S' then
      begin

         try
           begin
                Dias := StrToInt(GetPrefer('DiasTranscurridos'));
           end;
         except on e : exception do
             begin
                  Dias := 0;
             end;
         end;


      end
      else
         Dias := 0;

      SoloFacMesVM := GetPrefer('FactMesVM');
      if SoloFacMesVM = '' then
        SoloFacMesVM := 'N';

      if ((SistemaOrigen = 'VM') or (SistemaOrigen = 'VMPE') or (SistemaOrigen = 'VMRE')) then
      begin
        {$region 'Venta mostrador'}
        IBQuery.Close;
        IBQuery.SelectSQL.Clear;
        IBQuery.SelectSQL.Add('SELECT A.DOCTO_PV_ID,A.ESTATUS,A.FECHA,A.TIPO_DOCTO FROM DOCTOS_PV A ');
        IBQuery.SelectSQL.Add('WHERE A.FOLIO = :FOLIO AND A.TIPO_DOCTO = ''V'' ');
        IBQuery.ParamByName('FOLIO').AsString := FolioR;
        IBQuery.Open;
        Estatus := IBQuery.FieldByName('ESTATUS').AsString;
        TicketId := IBQuery.FieldByName('DOCTO_PV_ID').AsInteger;
        FechaTicket := IBQuery.FieldByName('FECHA').AsDateTime;
        TipoDocto := 'VM';
        FolDoc := FolioR;

        if TicketId>0 then
        begin
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT A.DOCTO_PV_DEST_ID,B.TIPO_DOCTO,B.FOLIO ');
          IBQuery.SelectSQL.Add('FROM DOCTOS_PV_LIGAS A ');
          IBQuery.SelectSQL.Add('INNER JOIN DOCTOS_PV B ON ( B.DOCTO_PV_ID = A.DOCTO_PV_DEST_ID ) ');
          IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_FTE_ID = :DOCTO_PV_FTE_ID ');
          IBQuery.ParamByName('DOCTO_PV_FTE_ID').AsInteger := TicketId;
          IBQuery.Open;

          if IBQuery.FieldByName('DOCTO_PV_DEST_ID').AsInteger <> 0 then
          begin
            if IBQuery.FieldByName('TIPO_DOCTO').AsString = 'F' then
              FolioFac := IBQuery.FieldByName('FOLIO').AsString;
            if IBQuery.FieldByName('TIPO_DOCTO').AsString = 'D' then
              FolioDev := IBQuery.FieldByName('FOLIO').AsString;
          end;
        end;
        {$endregion}
      end;

      if ((SistemaOrigen = 'RE') or (SistemaOrigen = 'VMRE')) then
      begin
        if TicketId=0 then
        begin
          {$region 'Remisiones'}
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID, A.ESTATUS, A.FECHA, B.DOCTO_VE_DEST_ID  ');
          IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
          IBQuery.SelectSQL.Add('LEFT JOIN DOCTOS_VE_LIGAS B ON (B.DOCTO_VE_FTE_ID = A.DOCTO_VE_ID)  ');
          IBQuery.SelectSQL.Add('WHERE A.FOLIO = :FOLIO  ');
          IBQuery.SelectSQL.Add('AND A.TIPO_DOCTO = ''R''  ');
          IBQuery.ParamByName('FOLIO').AsString := FolioR;
          IBQuery.Open;
          TicketId := IBQuery.FieldByName('DOCTO_VE_ID').AsInteger;
          FolDoc := FolioR;

          if TicketId=0 then
          begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID, A.ESTATUS, A.FECHA, B.DOCTO_VE_DEST_ID, A.FOLIO  ');
            IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
            IBQuery.SelectSQL.Add('LEFT JOIN DOCTOS_VE_LIGAS B ON (B.DOCTO_VE_FTE_ID = A.DOCTO_VE_ID)  ');
            IBQuery.SelectSQL.Add('WHERE A.ORDEN_COMPRA = :ORDEN_COMPRA  ');
            IBQuery.SelectSQL.Add('AND A.TIPO_DOCTO = ''R''  ');
            IBQuery.ParamByName('ORDEN_COMPRA').AsString := Folio;
            IBQuery.Open;
            TicketId := IBQuery.FieldByName('DOCTO_VE_ID').AsInteger;
            if TicketId > 0 then
            begin
              OCompra := Folio;
              FolDoc := IBQuery.FieldByName('FOLIO').AsString;
              FolioR := Folio;
            end;
          end;

          Estatus := IBQuery.FieldByName('ESTATUS').AsString;
          FechaTicket := IBQuery.FieldByName('FECHA').AsDateTime;
          Docto_Dest := IBQuery.FieldByName('DOCTO_VE_DEST_ID').AsInteger;
          TipoDocto := 'RE';

          if Docto_Dest > 0 then
          begin
              TipoDoctoVE := '';
              IBQuery.Close;
              IBQuery.SelectSQL.Clear;
              IBQuery.SelectSQL.Add('SELECT A.TIPO_DOCTO FROM DOCTOS_VE A  ');
              IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID  ');
              IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := Docto_Dest;
              IBQuery.Open;
              TipoDoctoVE := IBQuery.FieldByName('TIPO_DOCTO').AsString;
          end;
          {$endregion}
        end;
      end;

      if ((SistemaOrigen = 'PE') or (SistemaOrigen = 'VMPE')) then
      begin
        if TicketId=0 then
        begin
          {$region 'Pedidos'}
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID, A.ESTATUS, A.FECHA, B.DOCTO_VE_DEST_ID, A.FOLIO  ');
          IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
          IBQuery.SelectSQL.Add('LEFT JOIN DOCTOS_VE_LIGAS B ON (B.DOCTO_VE_FTE_ID = A.DOCTO_VE_ID)  ');
          IBQuery.SelectSQL.Add('WHERE A.FOLIO = :FOLIO  ');
          IBQuery.SelectSQL.Add('AND A.TIPO_DOCTO = ''P''  ');
          IBQuery.ParamByName('FOLIO').AsString := FolioR;
          IBQuery.Open;
          TicketId := IBQuery.FieldByName('DOCTO_VE_ID').AsInteger;
          FolDoc := IBQuery.FieldByName('FOLIO').AsString;
          if TicketId=0 then
          begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT A.DOCTO_VE_ID, A.ESTATUS, A.FECHA, B.DOCTO_VE_DEST_ID, A.FOLIO   ');
            IBQuery.SelectSQL.Add('FROM DOCTOS_VE A ');
            IBQuery.SelectSQL.Add('LEFT JOIN DOCTOS_VE_LIGAS B ON (B.DOCTO_VE_FTE_ID = A.DOCTO_VE_ID)  ');
            IBQuery.SelectSQL.Add('WHERE A.ORDEN_COMPRA = :ORDEN_COMPRA  ');
            IBQuery.SelectSQL.Add('AND A.TIPO_DOCTO = ''P''  ');
            IBQuery.ParamByName('ORDEN_COMPRA').AsString := Folio;
            IBQuery.Open;
            TicketId := IBQuery.FieldByName('DOCTO_VE_ID').AsInteger;
            if TicketId > 0 then
            begin
              OCompra := Folio;
              FolDoc := IBQuery.FieldByName('FOLIO').AsString;
              FolioR := Folio;
            end;
          end;

          Estatus := IBQuery.FieldByName('ESTATUS').AsString;
          FechaTicket := IBQuery.FieldByName('FECHA').AsDateTime;
          Docto_Dest := IBQuery.FieldByName('DOCTO_VE_DEST_ID').AsInteger;
          TipoDocto := 'PE';

          if Docto_Dest > 0 then
          begin
              TipoDoctoVE := '';
              IBQuery.Close;
              IBQuery.SelectSQL.Clear;
              IBQuery.SelectSQL.Add('SELECT A.TIPO_DOCTO FROM DOCTOS_VE A  ');
              IBQuery.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID  ');
              IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := Docto_Dest;
              IBQuery.Open;
              TipoDoctoVE := IBQuery.FieldByName('TIPO_DOCTO').AsString;
          end;
          {$endregion}
        end;
      end;

      Diferencia := DaysBetween(IBDatabase1.GetServerTime,FechaTicket);

      if ActivadoDias = 'S' then
      begin
          if Diferencia > Dias then
               EnTiempo := False
          else EnTiempo := True
      end else
          EnTiempo := True;

      if SoloFacMesVM = 'S' then
      begin
         if FormatDateTime('MM/YYYY',FechaTicket) = FormatDateTime('MM/YYYY',IBDatabase1.GetServerTime) then
         begin
             MismoMes := True;
         end else
         begin
             MismoMes := False;
         end;
      end else
         MismoMes := True;

      {$region 'Validaciones  -  Venta mostrador'}
      if TipoDocto = 'VM' then
      begin
          if (FolioDev = '') AND (FolioFac='') AND (Estatus='N') and (EnTiempo) and (MismoMes) then
          begin
             Error := '';
             Result := TicketId;
          end else
          begin

            if TicketId = 0 then
                 Raise Exception.Create('El ticket '+FolioR+' no existe.'+SistemaOrigen+'1'+TipoDocto); //+SistemaOrigen+'1'+TipoDocto
            if FolioDev <> '' then
                 Raise Exception.Create('El ticket '+FolioR+' tiene una devolución. ');
            if FolioFac <> '' then
                Raise Exception.Create('El ticket '+FolioR+' ya se facturó anteriormente. ');
            if Estatus = 'C' then
                 Raise Exception.Create('El ticket '+FolioR+' está cancelado. ');
            if not EnTiempo then
                 Raise Exception.Create('El tiempo para facturar su ticket ha vencido.');
            if not MismoMes then
                 Raise Exception.Create('Únicamente se puede facturar el ticket en el mes de emisión.');

          end;
      end;
      {$endregion}

      {$region 'Validadciones  -  Remisiones'}
      if TipoDocto = 'RE' then
      begin
          if (TipoDoctoVE = '') AND (Estatus='P') and (EnTiempo) and (MismoMes) then
          begin
             Error := '';
             Result := TicketId;
          end
          else
          begin
            if TicketId = 0 then
                Raise Exception.Create('El ticket '+FolioR+' no existe.'+SistemaOrigen+'2'+TipoDocto);//+SistemaOrigen+'2'+TipoDocto
            if TipoDoctoVE = 'F' then
                Raise Exception.Create('El ticket '+FolioR+' ya se facturó anteriormente. ');
            if Estatus = 'C' then
                Raise Exception.Create('El ticket '+FolioR+' está cancelado. ');
            if not EnTiempo then
                Raise Exception.Create('El tiempo para facturar su ticket ha vencido.');
            if not MismoMes then
                Raise Exception.Create('Únicamente se puede facturar el ticket en el mes de emisión.');
          end;
      end;
      {$endregion}

      {$region 'Validadciones  -  Remisiones'}
      if TipoDocto = 'PE' then
      begin
          if (TipoDoctoVE = '') AND (Estatus='P') and (EnTiempo) and (MismoMes) then
          begin
             Error := '';
             Result := TicketId;
          end
          else
          begin
            if TicketId = 0 then
                 Raise Exception.Create('El ticket '+FolioR+' no existe.'+SistemaOrigen+'3'+TipoDocto);//+SistemaOrigen+'3'+TipoDocto+'*'+Folio
            if TipoDoctoVE = 'R' then
                 Raise Exception.Create('El ticket '+FolioR+' tiene una remisión. ');
            if TipoDoctoVE = 'F' then
                Raise Exception.Create('El ticket '+FolioR+' ya se facturó anteriormente. ');
            if Estatus = 'C' then
                 Raise Exception.Create('El ticket '+FolioR+' está cancelado. ');
            if not EnTiempo then
                 Raise Exception.Create('El tiempo para facturar su ticket ha vencido.');
            if not MismoMes then
                 Raise Exception.Create('Únicamente se puede facturar el ticket en el mes de emisión.');

          end;
      end;
      {$endregion}

      TipoDoc := TipoDocto;
 end
except on e : exception do
 begin
   Error := e.message;
   Result := 0;
 end;
end;

end;

function TFacturaEFormV40.LeerParams(Parametro:String; NoParam:Integer):String;
Var Parametros,Comilla1,Comilla2,PosIni,PosFin:Integer;
  I: Integer;
begin
  Result := '';
  Parametros := 0;
  Comilla1 := 0;
  Comilla2 := 0;
  for I := 1 to Length(Parametro) do
  begin
    if Parametro[I] = '"' then
    begin
      if Comilla1 > 0 then
        Comilla2 := I;
      if Comilla1 = 0 then
        Comilla1 := I;
    end;

    if ((Comilla1 > 0) and (Comilla2 > 0)) then
    begin
      Inc(Parametros);
      PosIni := Comilla1;
      PosFin := Comilla2;
      Comilla1 := 0;
      Comilla2 := 0;
    end;

    if Parametros = NoParam then
    begin
      Result := Copy( Parametro,PosIni+1,(PosFin-PosIni)-1);
    end;
  end;
end;

function TFacturaEFormV40.Conexion(StringConexion:String; Var Error:String):Boolean;
Var Usuario,Pass,BaseDatos:String;
begin

Result := False;

try
 begin
  BaseDatos := '';
  Usuario := '';
  Pass := '';

  BaseDatos := LeerParams(StringConexion,3);
  Usuario := LeerParams(StringConexion,1);

  Pass := StringReplace(LeerParams(StringConexion,2),'igual','=',[rfReplaceAll, rfIgnoreCase]);
  Pass := StringReplace(Pass,'\/','/',[rfReplaceAll, rfIgnoreCase]);

  if Usuario = '' then
    Raise Exception.Create('Indique un usuario BD.');
  if Pass = '' then
    Raise Exception.Create('Indique una contraseña BD.');
  if BaseDatos = '' then
    Raise Exception.Create('Indique una base de datos .');

  IBDatabase1.DatabaseName := BaseDatos;
  IBDatabase1.DBParams.Clear;
  IBDatabase1.dbParams.Add('user_name='+Usuario);
  IBDatabase1.dbParams.Add('password='+Pass);
  IBDatabase1.dbParams.Add('lc_ctype=ISO8859_1');
  IBDatabase1.useLoginPrompt := false;

  TRY
      IBDatabase1.Connected := true;
      EXCEPT
            on e:Exception do
            begin
              if pos('Your user name and password are not defined', E.Message)<>0 then
                Raise Exception.Create('El usuario o la contraseña no son válidos BD.  Usuario: '+Usuario+'     '+'Pass2: '+Pass)
              else if pos('Unable to complete network request', E.Message)<>0 then
                       Raise Exception.Create('No se puede hacer contacto con el servidor BD.')
                   else if pos('I/O error for file', E.Message)<>0 then
                           Raise Exception.Create('La carpeta de datos Microsip no es válida BD.')
                        else if pos('load library fbclient', E.Message)<>0 then
                                Raise Exception.Create('No es posible cargar la librería fbclient.dll. ' + #13 + 'Intente copiarla a la carpeta del programa e intente nuevamente. BD')
                             else  Raise Exception.Create('Ha ocurrido un error al intentarse conectar a la base de datos BD. ' + #13 + 'Error: '+E.Message);
              Exit;
            end
      END;

  Result := True;
 end
except on e : exception do
 begin
   Error := e.Message;
   Result := False;
 end;
end;

end;

function TFacturaEFormV40.AbrirSellos(PathCert,PathKey,Password:String; Var Error:String ):Boolean;
Var
   StreamKey : TStream;
   Tam,OutSize,n : Integer;
   certificateByteArray: ByteArray;
   IniVigencia,FinVigencia : tdate;
   FechaInicio,FechaFin,Serie : String;
   temp : TStringList;


	function TP(posicion : integer) : word;
	begin
		if posicion = 0 then
		begin
			if Pos('ENE',temp.Text) > 0 then Result := 1 else
			if Pos('FEB',temp.Text) > 0 then Result := 2 else
			if Pos('MAR',temp.Text) > 0 then Result := 3 else
			if Pos('ABR',temp.Text) > 0 then Result := 4 else
			if Pos('MAY',temp.Text) > 0 then Result := 5 else
			if Pos('JUN',temp.Text) > 0 then Result := 6 else
			if Pos('JUL',temp.Text) > 0 then Result := 7 else
			if Pos('AGO',temp.Text) > 0 then Result := 8 else
			if Pos('SEP',temp.Text) > 0 then Result := 9 else
			if Pos('OCT',temp.Text) > 0 then Result := 10 else
			if Pos('NOV',temp.Text) > 0 then Result := 11 else
			if Pos('DIC',temp.Text) > 0 then Result := 12 else
			Result := 0; //error seguro
		end
		else
			Result := StrToIntDef(temp.Strings[posicion],1);
	end;

begin
AbrirSellos := False;
try
 begin
  FreeAndNil(gCertVerif);
  gCertVerif := TElX509Certificate.Create(nil);
  gCertVerif.LoadFromFileAuto(PathCert,Password);
  StreamKey := TFileStream.Create(PathKey, fmOpenRead or fmShareDenyWrite);
  gCertVerif.LoadKeyFromStreamPKCS8(StreamKey,Password,0);

  Tam := gCertVerif.CertificateSize;
  OutSize := 0;
  gCertificado :='';
  SetLength(certificateByteArray,Tam);
  gCertVerif.SaveToBuffer(@certificateByteArray[0],Tam);
  SetLength(certificateByteArray,Tam);
  gCertificado := SBEncoding.Base64EncodeArray(certificateByteArray,True);
  IniVigencia := gCertVerif.ValidFrom;
  FinVigencia := gCertVerif.ValidTo;
  gNoCertificado := StringOfBytes(gCertVerif.SerialNumber);

  AbrirSellos := True;

 end
except on e : exception do
 begin
  AbrirSellos := False;
  Error:= e.Message;
 end;
end;

{$REGION 'Validaciones'}
  temp.Free;
  temp := TStringList.Create;
  FechaInicio := FormatDateTime('mmm dd HH:nn:ss YYYY' ,IniVigencia );
  FechaInicio := UpperCase(FechaInicio[1])+ Copy(FechaInicio,2,length(FechaInicio));
  {$REGION 'Inicio vigencia'}
  temp.Text := FechaInicio;
  temp.Text := UpperCase(temp.Text);
	temp.Text := RemplazaCad(' ','  ',temp.Text);
	temp.Text := RemplazaCad(#13#10,' ',temp.Text);
	temp.Text := RemplazaCad(#13#10,':',temp.Text);
	try
		IniVigencia := EncodeDateTime(TP(5),TP(0),TP(1),TP(2),TP(3),TP(4),0);
	except
     Error := 'Inicio de Vigencia (Decode)';
     exit;
  end;
  {$ENDREGION}
  {$REGION 'Fin vigencia'}
  temp.Free;
  temp := TStringList.Create;
  FechaFin := FormatDateTime('mmm dd HH:nn:ss YYYY' ,FinVigencia );
  FechaFin := UpperCase(FechaFin[1])+ Copy(FechaFin,2,length(FechaFin));
  temp.Text := FechaFin;
  temp.Text := UpperCase(temp.Text);
	temp.Text := RemplazaCad(' ','  ',temp.Text);
	temp.Text := RemplazaCad(#13#10,' ',temp.Text);
	temp.Text := RemplazaCad(#13#10,':',temp.Text);

  try
    FinVigencia := EncodeDateTime(TP(5),TP(0),TP(1),TP(2),TP(3),TP(4),0);
  except
    error := 'Fin de Vigencia (Decode)';
    exit;
  end;
  {$ENDREGION}
  {$REGION 'No de certificado'}
  temp.Free;
  temp := TStringList.Create;
  temp.Text := gNoCertificado;
  Serie := ''; n := 1;
		while n < length(temp.Text) do
		begin
			Serie := Serie + temp.Text[n];
			n := n+1;
		end;
		if length(Trim(Serie)) <> 20 then
		begin error := 'Número de Serie (longitud <> 20)  '; exit; end;
  {$ENDREGION}

{$ENDREGION}

end;

function TFacturaEFormV40.ValidaCadena(Cadena:String):String;
Var NuevaCadena:String;
begin
  result := '';
  Cadena := AnsiUpperCase(Cadena);
  NuevaCadena := StringReplace(Cadena,'-','',[rfReplaceAll, rfIgnoreCase]);
  NuevaCadena := StringReplace(NuevaCadena,' ','',[rfReplaceAll, rfIgnoreCase]);

  Result := NuevaCadena;
end;

procedure TFacturaEFormV40.GeneraCadenaOriginalCFDI40(CFDIxml:TXMLDocument);
const pipe = '|';
var n,n1, n2, jo : integer;
  EsExcento, TieneImpto:String;
	CFDICopy : IXMLComprobante;

	procedure AgregaDato(atom : string);
	begin
		if atom <> '' then gCadenaOriginal := gCadenaOriginal + pipe + atom;
	end;
begin

  gCadenaOriginal := pipe;

  CFDIxml.Active := True;
  CFDICopy := GetComprobante(CFDIxml);
	with CFDICopy do
	begin
		{a.	version         b.	fecha                c.	tipoDeComprobante       d.	formaDePago       e.	condicionesDePago
     f.	subTotal        g.	descuento            h.	TipoCambio              i.	Moneda            j.	total
     k.	metodoDePago    l.	LugarExpedicion      m.	NumCtaPago              n.	FolioFiscalOrig   o.	SerieFolioFiscalOrig
     p.	FechaFolioFiscalOrig      q.	MontoFolioFiscalOrig }

    AgregaDato(Version);   AgregaDato(Serie);  AgregaDato(Folio);  AgregaDato(Fecha);
    AgregaDato(FormaPago); AgregaDato(NoCertificado); AgregaDato(SubTotal); AgregaDato(Descuento);
    AgregaDato(Moneda);
    AgregaDato(TipoCambio);
    AgregaDato(Total); AgregaDato(TipoDeComprobante); AgregaDato(Exportacion); AgregaDato(MetodoPago);
    AgregaDato(CondicionesDePago);
    AgregaDato(LugarExpedicion);

		with Emisor do
		begin
			AgregaDato(Rfc); AgregaDato(Nombre); AgregaDato(RegimenFiscal);
		end; {with CFD.Emisor}

		with Receptor do
		begin
      AgregaDato(Rfc);
      AgregaDato(Nombre);
      AgregaDato(DomicilioFiscalReceptor);
      AgregaDato(RegimenFiscalReceptor);
      AgregaDato(UsoCFDI);

		end; {with CFD.Receptor}

		with Conceptos do
		for n := 0 to ChildNodes.Count-1 do
		if ChildNodes[n].NodeType = ntElement then
		begin
			AgregaDato(Concepto[n].ClaveProdServ);
      AgregaDato(Concepto[n].NoIdentificacion);
      AgregaDato(Concepto[n].Cantidad);
      AgregaDato(Concepto[n].ClaveUnidad);
      AgregaDato(Concepto[n].Unidad);
      AgregaDato(Concepto[n].Descripcion);
      AgregaDato(Concepto[n].ValorUnitario);
      AgregaDato(Concepto[n].Importe);
      AgregaDato(Concepto[n].Descuento);
      AgregaDato(Concepto[n].ObjetoImp);

			for n1 := 0 to Concepto[n].ChildNodes.Count-1 do
			begin
         if Concepto[n].ChildNodes[n1].NodeName = 'cfdi:InformacionAduanera' then
 	  		 begin
  					AgregaDato(Concepto[n].InformacionAduanera.Items[0].NumeroPedimento);
				 end;
				 if Concepto[n].ChildNodes[n1].NodeName = 'CuentaPredial' then
				 begin
				  	AgregaDato(Concepto[n].CuentaPredial.Items[0].Numero);
				 end;
         if Concepto[n].ChildNodes[n1].NodeName = 'Impuestos' then
         begin
            with Concepto[n].Impuestos.Traslados do
	       		for n2:= 0 to ChildNodes.Count-1 do
      			if ChildNodes[n2].NodeType = ntElement then
			      begin
      				AgregaDato(Concepto[n].Impuestos.Traslados[n2].Base);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].Impuesto);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].TipoFactor);
              EsExcento := Concepto[n].Impuestos.Traslados[n2].TipoFactor;
              if EsExcento <> 'Exento' then
              begin
                  AgregaDato(Concepto[n].Impuestos.Traslados[n2].TasaOCuota);
                  AgregaDato(Concepto[n].Impuestos.Traslados[n2].Importe);
                  TieneImpto:='S';
              end;
      			end;
         end;

			end;
		end; {with CFD.Conceptos}

		with Impuestos do
		begin
			with Retenciones do
			for n:= 0 to ChildNodes.Count-1 do
			if ChildNodes[n].NodeType = ntElement then
			begin
				AgregaDato(Retencion[n].Impuesto); AgregaDato(Retencion[n].Importe);
			end; {with CFD.Impuestos.Retenciones}
			AgregaDato(TotalImpuestosRetenidos);

      if TieneImpto = 'S' then
      begin
			  with Traslados do
			  for n:= 0 to ChildNodes.Count-1 do
			  if ChildNodes[n].NodeType = ntElement then
			  begin
          AgregaDato(Traslados[n].Base);
				  AgregaDato(Traslados[n].Impuesto); AgregaDato(Traslados[n].TipoFactor); AgregaDato(Traslados[n].TasaOCuota);
          AgregaDato(Traslados[n].Importe);
			  end; {with CFD.Impuestos.Traslados}
      end;

			AgregaDato(TotalImpuestosTrasladados);
		end; {with CFD.Impuestos}

		AgregaDato(pipe);
	end; {with CFD}


	gCadenaOriginal := RemplazaCad(' ',#8,gCadenaOriginal);        //Regla 5.a
	gCadenaOriginal := RemplazaCad(' ',#10,gCadenaOriginal);       //Regla 5.a
	gCadenaOriginal := RemplazaCad(' ',#13,gCadenaOriginal);       //Regla 5.a
	gCadenaOriginal := RemplazaCad(pipe,' '+pipe,gCadenaOriginal); //Regla 5.b
	gCadenaOriginal := RemplazaCad(pipe,pipe+' ',gCadenaOriginal); //Regla 5.b
	gCadenaOriginal := RemplazaCad(' ','  ',gCadenaOriginal);      //Regla 5.c

end;

function TFacturaEFormV40.SellaFactura(Cert:TElX509Certificate; CadOriginal:WideString):String;
Var
   CadOriginalUtf8 : AnsiString;
   signer: TElRSAPublicKeyCrypto;
   KeyMaterial : TElRSAKeyMaterial;
   StreamInput, StreamOutput: TStringStream;
begin
try
  begin
  CadOriginalUtf8 := UTF8Encode(CadOriginal);

  signer := TElRSAPublicKeyCrypto.Create(SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION); //TElRSAPublicKeyCrypto.Create(SB_CERT_ALGORITHM_SHA1_RSA_ENCRYPTION);  //SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION;
  signer.InputEncoding := pkeBinary;
  signer.OutputEncoding := pkeBase64;
  KeyMaterial := TElRSAKeyMaterial.Create;
  KeyMaterial.Assign(Cert.KeyMaterial);
  signer.KeyMaterial := KeyMaterial;
  StreamInput := TStringStream.Create(CadOriginalUtf8);
  StreamOutput := TStringStream.Create('');
  signer.SignDetached(StreamInput, StreamOutput);

  SellaFactura := StreamOutput.DataString;
  end;
except on E : Exception do
begin
  Result := e.Message;
end;
end;

end;

function TFacturaEFormV40.InsertaAdd(DoctoId:Integer; Modulo:String):String;
Var
    ComprobranteCFDI : IXMLComprobante;
    sFolio,sSerie,sMoneda,sTipoCambio,sFecha,sTotal,sRfcEmisor,sRfcReceptor,
    sNombreReceptor,sUUID,sTipoComprobante,Naturaleza,TipoComprobante : String;
    n,CfdiId : Integer;
begin

try
 begin

  dsQuery1.Close;
  dsQuery1.SelectSQL.Clear;
  dsQuery1.SelectSQL.Add('SELECT A.XML ');
  dsQuery1.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A ');
  dsQuery1.SelectSQL.Add('WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = :SISTEMA ');
  dsQuery1.ParamByName('SISTEMA').AsString := Modulo;
  dsQuery1.ParamByName('DOCTO_ID').AsInteger := DoctoId;
  dsQuery1.Open;

  if dsQuery1.FieldByName('XML').AsString <> ''  then
  begin
    {$REGION 'Inserta Repositorio'}
      xmlFac.Active := True;
      xmlFac.XML.Text := dsQuery1.FieldByName('XML').AsString;
      xmlFac.Active := True;

      ComprobranteCFDI := GetComprobante(xmlFac);

      With ComprobranteCFDI do
      Begin
        sFolio := Folio;
        try
           sSerie := Serie;
         except
            sSerie := '';
        end;

        sFecha := Fecha;
        sTotal := Total;

        sMoneda := Moneda;
        sTipoCambio := TipoCambio;

        if sTipoCambio = '' then
            sTipoCambio := '1.00';

        sTipoComprobante := TipoDeComprobante;

        with Emisor do
        begin
          sRfcEmisor:= Rfc;
        end;

        with Receptor do
        begin
          sRfcReceptor := Rfc;
          sNombreReceptor := Nombre;
        end;

        with Complemento do
        Begin
          for n := 0 to Complemento.ChildNodes.Count - 1  do
   		    begin
            if Complemento.ChildNodes[n].NodeName = 'tfd:TimbreFiscalDigital' then
				    begin
              sUUID := Complemento.ChildNodes[n].Attributes['UUID'];
            end;
          end;
        End;
      End;

      if sTipoComprobante = 'I' then
      begin
        Naturaleza := 'E';
        TipoComprobante := 'I';
      end else
      begin
        Naturaleza := 'E';
        TipoComprobante := 'E';
      end;

      spGenDoctoId.Close;
      spGenDoctoId.ExecProc;
      CfdiId := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
      dsQuery1.Close;
      dsQuery1.SelectSQL.Clear;
      dsQuery1.SelectSQL.Add('INSERT INTO REPOSITORIO_CFDI (CFDI_ID, MODALIDAD_FACTURACION, "VERSION", UUID, NATURALEZA, ');
      dsQuery1.SelectSQL.Add('TIPO_COMPROBANTE, TIPO_DOCTO_MSP, FOLIO, FECHA, RFC, TAXID, NOMBRE, IMPORTE, MONEDA, ');
      dsQuery1.SelectSQL.Add('TIPO_CAMBIO, ES_PARCIALIDAD, NOM_ARCH, XML, REFER_GRUPO, FECHA_CANCELACION, ');
      dsQuery1.SelectSQL.Add('SELLO_VALIDADO, USUARIO_VAL_SELLO, USUARIO_CREADOR, FECHA_HORA_CREACION, ');
      dsQuery1.SelectSQL.Add('USUARIO_AUT_CREACION, USUARIO_ULT_MODIF, FECHA_HORA_ULT_MODIF, USUARIO_AUT_MODIF) ');
      dsQuery1.SelectSQL.Add(' VALUES (:CFDI_ID, :MODALIDAD_FACTURACION, ''4.0'', :UUID, :NATURALEZA, ');
      dsQuery1.SelectSQL.Add(':TIPO_COMPROBANTE, :TIPO_DOCTO_MSP, :FOLIO, :FECHA, :RFC, :TAXID, :NOMBRE, :IMPORTE, :MONEDA, ');
      dsQuery1.SelectSQL.Add(':TIPO_CAMBIO, :ES_PARCIALIDAD, :NOM_ARCH, :XML, :REFER_GRUPO, :FECHA_CANCELACION, ');
      dsQuery1.SelectSQL.Add('''M'', :USUARIO_VAL_SELLO, :USUARIO_CREADOR, :FECHA_HORA_CREACION, ');
      dsQuery1.SelectSQL.Add(':USUARIO_AUT_CREACION, :USUARIO_ULT_MODIF, :FECHA_HORA_ULT_MODIF, :USUARIO_AUT_MODIF) ');
      dsQuery1.ParamByName('CFDI_ID').AsInteger := CfdiId;
      dsQuery1.ParamByName('MODALIDAD_FACTURACION').AsString := 'CFDI';
      dsQuery1.ParamByName('UUID').AsString := sUUID;
      dsQuery1.ParamByName('NATURALEZA').AsString := Naturaleza; {E,R}
      dsQuery1.ParamByName('TIPO_COMPROBANTE').AsString := TipoComprobante;  {I,E}
      dsQuery1.ParamByName('TIPO_DOCTO_MSP').AsString := 'Factura';
      dsQuery1.ParamByName('FOLIO').AsString := sSerie+sFolio;
      dsQuery1.ParamByName('FECHA').AsDate := StrToDate(Copy(sFecha,9,2)+'/'+Copy(sFecha,6,2)+'/'+Copy(sFecha,0,4));
      dsQuery1.ParamByName('RFC').AsString := sRfcEmisor;
      dsQuery1.ParamByName('TAXID').Clear;
      dsQuery1.ParamByName('NOMBRE').AsString := sNombreReceptor;
      dsQuery1.ParamByName('IMPORTE').AsString := sTotal;
      dsQuery1.ParamByName('MONEDA').AsString := sMoneda;
      dsQuery1.ParamByName('TIPO_CAMBIO').AsString := sTipoCambio;
      dsQuery1.ParamByName('ES_PARCIALIDAD').AsString := 'N';
      dsQuery1.ParamByName('NOM_ARCH').AsString := sRfcEmisor+'_Factura_'+sSerie+sFolio+'_'+FormatDateTime('yyyymmdd',StrToDate(Copy(sFecha,9,2)+'/'+Copy(sFecha,6,2)+'/'+Copy(sFecha,0,4)))+'.xml';
      dsQuery1.ParamByName('XML').AsString := xmlFac.XML.Text;
      dsQuery1.ParamByName('REFER_GRUPO').Clear;
      dsQuery1.ParamByName('FECHA_CANCELACION').Clear;
      //dsQuery1.ParamByName('SELLO_VALIDADO').AsString := 'M';
      {  'M' = Por microsip
         'U' =
         'P' =
         'N' =               }
      dsQuery1.ParamByName('USUARIO_VAL_SELLO').Clear;
      dsQuery1.ParamByName('USUARIO_CREADOR').AsString := 'SYSDBA';
      dsQuery1.ParamByName('FECHA_HORA_CREACION').AsDateTime := Now;
      dsQuery1.ParamByName('USUARIO_AUT_CREACION').Clear;
      dsQuery1.ParamByName('USUARIO_ULT_MODIF').AsString := 'SYSDBA';
      dsQuery1.ParamByName('FECHA_HORA_ULT_MODIF').AsDateTime := Now;
      dsQuery1.ParamByName('USUARIO_AUT_MODIF').Clear;
      dsQuery1.Open;

      dsQuery1.Close;
      dsQuery1.SelectSQL.Clear;
      dsQuery1.SelectSQL.Add('UPDATE USOS_FOLIOS_FISCALES ');
      dsQuery1.SelectSQL.Add('SET CFDI_ID = :CFDI_ID ');
      dsQuery1.SelectSQL.Add('WHERE DOCTO_ID = :DOCTO_ID ');
      dsQuery1.ParamByName('CFDI_ID').AsInteger := CfdiId;
      dsQuery1.ParamByName('DOCTO_ID').AsInteger := DoctoId;
      dsQuery1.Open;

      Result := '';
    {$ENDREGION}
  end else
  begin
    Result := 'No se encontró el XML.';
  end;

 end
except on e : exception do
 begin
   Result := e.Message;
 end;
end;

end;

function TFacturaEFormV40.InsertFacturaElectronica(DoctoVeId:Integer; xmlFactura:TXMLDocument; Modulo:String; Var Error:String ):Boolean;
begin
 try
  begin
   xmlFactura.Active := True;
   dsQuery1.Close;
   dsQuery1.SelectSQL.Clear;
   dsQuery1.SelectSQL.Add('UPDATE USOS_FOLIOS_FISCALES SET XML = :XML ');
   dsQuery1.SelectSQL.Add('WHERE (DOCTO_ID = :DOCTO_ID) AND (SISTEMA = :SISTEMA); ');
   dsQuery1.ParamByName('DOCTO_ID').AsInteger := DoctoVeId;
   dsQuery1.ParamByName('SISTEMA').AsString := Modulo;
   dsQuery1.ParamByName('XML').AsString := StringReplace(xmlFactura.XML.Text, '<?xml version="1.0"?>', '<?xml version="1.0" encoding="UTF-8"?>', [rfReplaceAll, rfIgnoreCase]); //'<?xml version="1.0" encoding="UTF-8"?>'+UTF8Encode(xmlFactura.XML.Text); //'<?xml version="1.0" encoding="UTF-8" ?>'+
   dsQuery1.Open;

   InsertFacturaElectronica:=True;
  end
  except on e:Exception do
  begin
    Error := 'Error al generar guardar la factura electrónica.  Error:'+e.Message;
    InsertFacturaElectronica:=False;
  end;
 end;
end;

function TFacturaEFormV40.GeneraXmlVe40(DoctoVeId:Integer; TipoComp:String; {F,D} Var Error:String ):WideString;
Var XmlCfdi,XmlCfdiCopy : TXMLDocument;
    CfdiVe : IXMLComprobante;
    ContReg,n,DoctoInDetId : Integer;
    TotalImptoT,TotalImptoR, ValPrctjImpto, BaseImptoDet: Double;
    XmlText : WideString;
    Pedimento, HayRet, NameEm, NameRe :String;
    F :TextFile;
    sLinea: String;
    PathIni:String;
    Item:Integer;
    NameArt:WideString;
    DEC:Double;
    NumD, NumD1, PosD:Integer;
    sDEC, sDEC1, EsSoloExento:String;
    ConteoExento, ConteoOtrosImptos:Integer;
    lTipoFactor,TieneImpto, lpaso:String;
begin
Error := '';
NameEm := ''; NameRe := ''; NameArt := '';
try
 begin
  {$REGION 'Abrir datasets'}
  TieneImpto := 'N';
  dsEmpresa.CloseOpen(False);

  dsDoctosVe.Close;
  dsDoctosVe.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  dsDoctosVe.Open;

  dsDoctosVeDet.Close;
  dsDoctosVeDet.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  dsDoctosVeDet.Open;

  dsFormasCobroCC.Close;
  dsFormasCobroCC.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  dsFormasCobroCC.Open;

  spCalcTotVe.Close;
  spCalcTotVe.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  spCalcTotVe.ParamByName('SOLO_LECTURA').AsString := 'S';
  spCalcTotVe.ExecProc;

  spCalcTotalesVEIEPS.Close;
  spCalcTotalesVEIEPS.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  spCalcTotalesVEIEPS.ExecProc;

  dsQuery1.Close();
  dsQuery1.SelectSQL.Clear;
  dsQuery1.SelectSQL.Add('SELECT A.LUGAR_EXPEDICION_ID');
  dsQuery1.SelectSQL.Add('FROM DOCTOS_VE A');
  dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_ID=:DOCTO_VE_ID');
  dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
  dsQuery1.Open;

  dsLugExpDoctosVe.Close;
  dsLugExpDoctosVe.ParamByName('LUGAR_EXPEDICION_ID').AsInteger := dsQuery1.FieldByName('LUGAR_EXPEDICION_ID').AsInteger;
  dsLugExpDoctosVe.Open;

  dsLugExpRegistry.CloseOpen(False);
  {$ENDREGION}

  XmlCfdi := TXMLDocument.Create(nil);

  XmlCfdi.XML.Text := '<?xml version="1.0" encoding="UTF-8" ?><cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4"></cfdi:Comprobante>';
	XmlCfdi.Active := True;
	CfdiVe := GetComprobante(XmlCfdi);

  With CfdiVe do
	Begin
    {$REGION 'Atributos comprobante'}
    Version := '4.0';
    if dsDoctosVe.FieldByName('SERIE').AsString <> '@' then
        Serie := dsDoctosVe.FieldByName('SERIE').AsString;
    Folio := dsDoctosVe.FieldByName('FOLIO').AsString;
    Fecha := FormatDateTime('YYYY-MM-DD',dsDoctosVe.FieldByName('FECHA').AsDateTime)+'T'+FormatDateTime('HH:MM:SS',dsDoctosVe.FieldByName('FECHA_HORA_CREACION').AsDateTime);
    Sello := '';

    ContReg := 0;

    if dsDoctosVe.FieldByName('METODO_PAGO_SAT').AsString = '' then
    begin
      raise Exception.Create('El Método de pago SAT del documento Microsip es incorrecta.');
    end;

    if dsDoctosVe.FieldByName('METODO_PAGO_SAT').AsString = 'PPD' then
       FormaPago := '99'
    else if dsDoctosVe.FieldByName('METODO_PAGO_SAT').AsString = 'PUE' then
    begin
      dsFormasCobroCC.First;
      while not dsFormasCobroCC.Eof do
      begin
        Inc(ContReg);
        if ContReg = 1 then
          FormaPago := dsFormasCobroCC.FieldByName('CLAVE_FISCAL').AsString
        else
          FormaPago := FormaPago+','+dsFormasCobroCC.FieldByName('CLAVE_FISCAL').AsString;
        dsFormasCobroCC.Next;
      end;
    end;

    NoCertificado := gNoCertificado;

    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#x0D;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xD;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #13, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #10, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #8, '', [rfReplaceAll, rfIgnoreCase]);

    Certificado := gCertificado;

    dsIEPS_VE.Close;
    dsIEPS_VE.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
    dsIEPS_VE.Open;

    if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
    begin

      if dsIEPS_VE.FieldByName('NREG').AsInteger>0 then
      begin
        if spCalcTotVe.FieldByName('DSCTO_ARTS').AsFloat>0 then
          SubTotal := FloatToStrF(StrToFloatDef(spCalcTotalesVEIEPS.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2)
        else
          SubTotal := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotVe.FieldByName('TOTAL_A_PAGAR').AsFloat-spCalcTotalesVEIEPS.FieldByName('TOTAL_IMPUESTOS').AsFloat),0),ffFixed,10,2)
      end
      else
      begin
        if spCalcTotVe.FieldByName('DSCTO_ARTS').AsFloat>0 then
          SubTotal := FloatToStrF(StrToFloatDef( spCalcTotVe.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2)
        else
          SubTotal := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotVe.FieldByName('TOTAL_A_PAGAR').AsFloat-spCalcTotalesVEIEPS.FieldByName('TOTAL_IMPUESTOS').AsFloat),0),ffFixed,10,2)
      end;
    end
    else
      SubTotal := FloatToStrF(StrToFloatDef(spCalcTotVe.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2);

    if dsIEPS_VE.FieldByName('NREG').AsInteger>0 then
      Descuento := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotalesVEIEPS.FieldByName('DSCTO_ARTS').AsFloat+spCalcTotalesVEIEPS.FieldByName('DSCTO_EXTRA_IMPORTE').AsFloat),0),ffFixed,10,2)
    else
      Descuento := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotVe.FieldByName('DSCTO_ARTS').AsFloat+spCalcTotVe.FieldByName('DSCTO_EXTRA_IMPORTE').AsFloat),0),ffFixed,10,2);

    if dsDoctosVe.FieldByName('MONEDA_ID').AsInteger = 1 then
      Moneda := 'MXN'
    else
      if dsDoctosVe.FieldByName('CLAVE_MONEDA').AsString <> '' then
          Moneda := dsDoctosVe.FieldByName('CLAVE_MONEDA').AsString;

    Total := FloatToStrF(StrToFloatDef(spCalcTotVe.FieldByName('TOTAL_A_PAGAR').AsString,0),ffFixed,10,2);

    if TipoComp = 'F' then
      TipoDeComprobante := 'I';
    if TipoComp = 'D' then
      TipoDeComprobante := 'E';

    Exportacion := '01'; //liz No aplica cuando se registre el valor “02”, se debe incluir el “Complemento para Comercio Exterior”.

    if dsDoctosVe.FieldByName('METODO_PAGO_SAT').AsString = 'PPD' then
       MetodoPago := 'PPD'
    else if dsDoctosVe.FieldByName('METODO_PAGO_SAT').AsString = 'PUE' then
       MetodoPago := 'PUE';

    if dsLugExpDoctosVe.FieldByName('CODIGO_POSTAL').AsString='' then
      LugarExpedicion := dsLugExpRegistry.FieldByName('VALOR').AsString
    else  LugarExpedicion := dsLugExpDoctosVe.FieldByName('CODIGO_POSTAL').AsString;

    if LugarExpedicion='' then
      raise Exception.Create('El código postal del lugar de expedición es incorrecto.');

    SetAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
    SetAttribute('xsi:schemaLocation','http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd');

    {$ENDREGION}
    With Emisor do
    Begin
        {$REGION 'Emisor'}
        Rfc := ValidaCadena(dsEmpresa.FieldByName('RFC').AsString);

        dsDatosEmisor.Close;
        dsDatosEmisor.ParamByName('RFC').AsString := Rfc;
        dsDatosEmisor.Open;

        NameEm := dsDatosEmisor.FieldByName('NOMBRE_FISCAL').AsString;
        NameEm := StringReplace(NameEm,'Á','A',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'É','E',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'Í','I',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'Ñ','N',[rfReplaceAll, rfIgnoreCase]);

        NameEm := StringReplace(NameEm,'á','a',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'é','e',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'í','i',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'ó','o',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'ú','u',[rfReplaceAll, rfIgnoreCase]);
        NameEm := StringReplace(NameEm,'ñ','n',[rfReplaceAll, rfIgnoreCase]);
        Nombre := NameEm;

        RegimenFiscal := dsEmpresa.FieldByName('CLAVE_REGIMEN_FISCAL').AsString;
        {$ENDREGION}
    End;

    with Receptor do
    begin
        {$REGION 'Receptor'}
        Rfc := ValidaCadena(dsDoctosVe.FieldByName('RFC_CURP').AsString);

        NameRe := '';
        NameRe := dsDoctosVe.FieldByName('CLIENTE').AsString;
        NameRe := StringReplace(NameRe,'Á','A',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'É','E',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'Í','I',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'Ñ','N',[rfReplaceAll, rfIgnoreCase]);

        NameRe := StringReplace(NameRe,'á','a',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'é','e',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'í','i',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'ó','o',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'ú','u',[rfReplaceAll, rfIgnoreCase]);
        NameRe := StringReplace(NameRe,'ñ','n',[rfReplaceAll, rfIgnoreCase]);
        Nombre := NameRe;

        DomicilioFiscalReceptor  := dsDoctosVe.FieldByName('CODIGO_POSTAL').AsString;
        RegimenFiscalReceptor := dsDoctosVe.FieldByName('CLAVE_REGIMEN_FISCAL').AsString; //'616';
        UsoCFDI := dsDoctosVe.FieldByName('USO_CFDI').AsString; //'S01';
        {$ENDREGION}
    end;

    HayRet := 'N';
    with Conceptos do
    begin
    {$REGION 'Conceptos'}
      dsDoctosVeDet.First;

      if dsDoctosVeDet.IsEmpty then
      begin
        raise Exception.Create('El y/o artículo(s), no tienen clave SAT registrada en Microsip.');
      end;

      while not dsDoctosVeDet.Eof do
      begin
          With Conceptos.Add do
			    Begin
            ClaveProdServ := dsDoctosVeDet.FieldByName('CLAVE_ART_SAT').AsString;

            if dsDoctosVeDet.FieldByName('CLAVE_ARTICULO').AsString <> '' then
              NoIdentificacion := dsDoctosVeDet.FieldByName('CLAVE_ARTICULO').AsString;

            Cantidad := FloatToStrF(StrToFloatDef(dsDoctosVeDet.FieldByName('UNIDADES').AsString,0),ffFixed,10,2);
            ClaveUnidad:= dsDoctosVeDet.FieldByName('CLAVE_MEDIDA_SAT').AsString;
            Unidad := dsDoctosVeDet.FieldByName('UNIDAD_VENTA').AsString;

            NameArt := '';
            NameArt := dsDoctosVeDet.FieldByName('ARTICULO').AsString;
            NameArt := StringReplace(NameArt,'Á','A',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'É','E',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'Í','I',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'Ñ','N',[rfReplaceAll, rfIgnoreCase]);

            NameArt := StringReplace(NameArt,'á','a',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'é','e',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'í','i',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'ó','o',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'ú','u',[rfReplaceAll, rfIgnoreCase]);
            NameArt := StringReplace(NameArt,'ñ','n',[rfReplaceAll, rfIgnoreCase]);

            Descripcion :=  NameArt;

            dsIEPS_VE_P.Close;
            dsIEPS_VE_P.ParamByName('DOCTO_VE_DET_ID').AsInteger := dsDoctosVeDet.FieldByName('DOCTO_VE_DET_ID').AsInteger;
            dsIEPS_VE_P.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
            dsIEPS_VE_P.Open;

            dsDoctoVeDet40_IEPS_Inc.Close;
            dsDoctoVeDet40_IEPS_Inc.ParamByName('DOCTO_VE_DET_ID').AsInteger := dsDoctosVeDet.FieldByName('DOCTO_VE_DET_ID').AsInteger;
            dsDoctoVeDet40_IEPS_Inc.Open;

            if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
            begin
              {$REGION 'MyRegion'}
              if (dsIEPS_VE_P.FieldByName('NREG').AsInteger > 0) then
              begin
                DEC := Frac(dsDoctosVeDet.FieldByName('FACTOR_RED_PRECIO_CON_IMPTO').AsFloat);
                sDEC := FLOATTOSTR(DEC);
                NumD := 0;  PosD := 0; NumD1 := 0;
                NumD := Length(sDEC);
                PosD := Pos('.', sDEC);
                sDEC1 := Copy(sDEC, PosD+1, NumD);
                NumD1 := Length(sDEC1);

                if NumD1>1 then
                begin
                  spRoundProd.Close;
                  spRoundProd.ParamByName('V_FACTOR2').AsFloat := dsDoctoVeDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat;
                  spRoundProd.ParamByName('V_FACTOR_RED').AsFloat := dsDoctosVeDet.FieldByName('FACTOR_RED_PRECIO_CON_IMPTO').AsFloat;
                  spRoundProd.ExecProc;
                  ValorUnitario := spRoundProd.FieldByName('PRODUCTO').AsString;
                  Importe := FloatToStrF(StrToFloatDef(FloatToStr(spRoundProd.FieldByName('PRODUCTO').AsFloat*dsDoctosVeDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
                end
                else
                begin
                  ValorUnitario := dsDoctoVeDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsString;
                  Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoVeDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctosVeDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
                end;
              end
              else
              begin
                ValorUnitario := dsDoctoVeDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsString;
                Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoVeDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctosVeDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
              end;
              {$ENDREGION}
            end
            else
            begin
              ValorUnitario := FloatToStrF(StrToFloatDef(dsDoctosVeDet.FieldByName('PRECIO_UNITARIO').AsString,0),ffFixed,10,4);//2
              Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctosVeDet.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctosVeDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
            end;

            if (dsIEPS_VE_P.FieldByName('NREG').AsInteger > 0) then
              Descuento := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoVeDet40_IEPS_Inc.FieldByName('DSCTO_ART').AsFloat+dsDoctoVeDet40_IEPS_Inc.FieldByName('DSCTO_EXTRA').AsFloat),0),ffFixed,10,2)
            else
              Descuento := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctosVeDet.FieldByName('DSCTO_ART').AsFloat+dsDoctosVeDet.FieldByName('DSCTO_EXTRA').AsFloat),0),ffFixed,10,2);

            {$REGION 'Impuestos Concepto'}
            dsQuery1.Close;
            dsQuery1.SelectSQL.Clear;
            dsQuery1.SelectSQL.Add('SELECT A.IMPORTE_IMPUESTO, A.VENTA_NETA, B.NOMBRE, A.PCTJE_IMPUESTO, B.TIPO, C.TIPO_IVA  ');
            dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A ');
            dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID) ');
            dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
            dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_DET_ID = :DOCTO_VE_DET_ID AND A.DOCTO_VE_ID = :DOCTO_VE_ID');
            dsQuery1.SelectSQL.Add('AND B.TIPO = ''I'' ');
            if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
              dsQuery1.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P'' ');
            dsQuery1.ParamByName('DOCTO_VE_DET_ID').AsInteger := dsDoctosVeDet.FieldByName('DOCTO_VE_DET_ID').AsInteger;
            dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
            dsQuery1.CloseOpen(false);

            if dsQuery1.IsEmpty then
            begin
              ObjetoImp := '01';
            end
            else
            begin
              ObjetoImp := '02';

              If dsQuery1.FieldByName('NOMBRE').AsString <> '' then
              Begin
                while NOT dsQuery1.Eof do
                BEGIN
                  With Impuestos do
                  begin
                    if dsQuery1.FieldByName('TIPO').AsString='I' then
                    begin
                      With Traslados.Add do
                      begin
                        lTipoFactor := '';
                        if dsQuery1.FieldByName('TIPO_IVA').AsString = '4' then
                          lTipoFactor := 'Exento'
                        else
                          lTipoFactor := 'Tasa';

                        {$REGION 'Traslados'}
                        if (dsQuery1.FieldByName('NOMBRE').AsString = 'IVA') then
                        begin
                            dsQuery2.Close;
                            dsQuery2.SelectSQL.Clear;
                            dsQuery2.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) IMPORTE_IMPUESTO ');
                            dsQuery2.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A ');
                            dsQuery2.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID) ');
                            dsQuery2.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
                            dsQuery2.SelectSQL.Add('WHERE A.DOCTO_VE_DET_ID = :DOCTO_VE_DET_ID AND A.DOCTO_VE_ID = :DOCTO_VE_ID ');
                            dsQuery2.SelectSQL.Add('AND B.TIPO = ''I'' ');
                            dsQuery2.SelectSQL.Add('AND UPPER(B.NOMBRE) <> UPPER(''IVA'') ');
                            dsQuery2.ParamByName('DOCTO_VE_DET_ID').AsInteger := dsDoctosVeDet.FieldByName('DOCTO_VE_DET_ID').AsInteger;
                            dsQuery2.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
                            dsQuery2.CloseOpen(false);
                            BaseImptoDet:= 0.000000000000000000000000000000000000000000000000000000000000000000000000000000;
                            BaseImptoDet:= dsQuery2.FieldByName('IMPORTE_IMPUESTO').AsFloat;
                            BaseImptoDet := dsQuery1.FieldByName('VENTA_NETA').AsFloat + BaseImptoDet;
                            Base := FormatFloat('###0.00',BaseImptoDet); //IVA, IEPS
                            Impuesto := '002';
                        end
                        else if (dsQuery1.FieldByName('NOMBRE').AsString = 'IEPS') then
                        begin
                            Base := FormatFloat('###0.00',dsQuery1.FieldByName('VENTA_NETA').AsFloat); //IVA, IEPS
                            Impuesto := '003';
                        end;
                        {$ENDREGION}

					              TipoFactor := lTipoFactor; //'Tasa';
                        ValPrctjImpto := 0.000000000000000000000000000000000000000000000000000000000000000000000;
                        ValPrctjImpto := dsQuery1.FieldByName('PCTJE_IMPUESTO').AsFloat / 100;

                        if lTipoFactor <> 'Exento' then
                        begin
                          TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);
                          if dsQuery1.FieldByName('IMPORTE_IMPUESTO').AsFloat > 0.0000 then
                          begin
                            Importe := FormatFloat('###0.00',dsQuery1.FieldByName('IMPORTE_IMPUESTO').AsFloat);
                          end
                          else
                          begin
                            Importe := '0.00';
                          end;

                          TieneImpto := 'S';
                        end;
                    end;
                  end
                  else if dsQuery1.FieldByName('TIPO').AsString='R' then
                  begin
                    if dsDoctosVe.FieldByName('RETIENE_IMPUESTOS').AsString='S' then
                    begin
                      HayRet := 'S';
                      With Retenciones.Add do
                      begin
                        {$REGION 'Traslados'}
                        if (dsQuery1.FieldByName('NOMBRE').AsString = 'IVA retenido') then
                        begin
                            dsQuery2.Close;
                            dsQuery2.SelectSQL.Clear;
                            dsQuery2.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) IMPORTE_IMPUESTO ');
                            dsQuery2.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A ');
                            dsQuery2.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID) ');
                            dsQuery2.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
                            dsQuery2.SelectSQL.Add('WHERE A.DOCTO_VE_DET_ID = :DOCTO_VE_DET_ID AND A.DOCTO_VE_ID = :DOCTO_VE_ID ');
                            dsQuery2.SelectSQL.Add('AND B.TIPO = ''R'' ');
                            dsQuery2.SelectSQL.Add('AND UPPER(B.NOMBRE) <> UPPER(''IVA RETENIDO'') ');
                            dsQuery2.ParamByName('DOCTO_VE_DET_ID').AsInteger := dsDoctosVeDet.FieldByName('DOCTO_VE_DET_ID').AsInteger;
                            dsQuery2.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
                            dsQuery2.CloseOpen(false);
                            BaseImptoDet:= 0.000000000000000000000000000000000000000000000000000000000000000000000000000000;
                            BaseImptoDet:= dsQuery2.FieldByName('IMPORTE_IMPUESTO').AsFloat;
                            BaseImptoDet := dsQuery1.FieldByName('VENTA_NETA').AsFloat + BaseImptoDet;
                            Base := FormatFloat('###0.00',BaseImptoDet); //IVA, IEPS
                            Impuesto := '002';
                        end
                        else if (dsQuery1.FieldByName('NOMBRE').AsString = 'IEPS retenido') then
                        begin
                            Base := FormatFloat('###0.00',dsQuery1.FieldByName('VENTA_NETA').AsFloat); //IVA, IEPS
                            Impuesto := '003';
                        end;
                        {$ENDREGION}

					              TipoFactor := 'Tasa';
                        ValPrctjImpto := 0.000000000000000000000000000000000000000000000000000000000000000000000;
                        ValPrctjImpto := dsQuery1.FieldByName('PCTJE_IMPUESTO').AsFloat / 100;
                        TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);
                        Importe := FormatFloat('###0.0000',dsQuery1.FieldByName('IMPORTE_IMPUESTO').AsFloat);
                      end;
                    end;
                  end;
                end;
              dsQuery1.Next;
              END;
            End;
            end;
           {$ENDREGION}

           {$REGION 'Pedimentos'}
            dsQuery1.Close;
            dsQuery1.SelectSQL.Clear;
            dsQuery1.SelectSQL.Add('SELECT I.DOCTO_IN_DET_ID, I.ARTICULO_ID, V.ALMACEN_ID, V.FECHA FROM DOCTOS_VE V');
            dsQuery1.SelectSQL.Add('INNER JOIN DOCTOS_ENTRE_SIS D ON (V.DOCTO_VE_ID = D.DOCTO_FTE_ID) ');
            dsQuery1.SelectSQL.Add('INNER JOIN DOCTOS_IN_DET I ON (I.DOCTO_IN_ID = D.DOCTO_DEST_ID) ');
            dsQuery1.SelectSQL.Add('WHERE D.CLAVE_SIS_FTE = ''VE'' AND D.CLAVE_SIS_DEST = ''IN'' AND D.TIPO_DOCTO = ''F'' ');
            dsQuery1.SelectSQL.Add(' AND V.DOCTO_VE_ID = :DOCTO_VE_ID ');
            dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
            dsQuery1.CloseOpen(false);
            ContReg := 1;
            while not dsQuery1.Eof do
            begin
              DoctoInDetId := dsQuery1.FieldByName('DOCTO_IN_DET_ID').AsInteger;

              if dsDoctosVeDet.FieldByName('POSICION').AsInteger = ContReg then
              begin
                  Break;
              end;
              dsQuery1.Next;
              inc(ContReg);

            end;

            dsPedimentosVE.Close;
            dsPedimentosVE.Parambyname('DOCTO_VE_ID').asinteger := DoctoVeId;
            dsPedimentosVE.Parambyname('DOCTO_IN_DET_ID').asinteger := DoctoInDetId;
            dsPedimentosVE.Open;

            If (dsPedimentosVE.FieldByName('ADUANA_CLAVE').AsString <> '') then
            Begin

               while NOT dsPedimentosVE.Eof do
               BEGIN

                 if  (dsPedimentosVE.FieldByName('ADUANA_CLAVE').AsString <> 'SIN PEDIMENTO') then
                 BEGIN
                   With InformacionAduanera do
                   begin
                     With InformacionAduanera.Add do
                     Begin
                        Pedimento := NumPed(dsPedimentosVE.FieldByName('ADUANA_CLAVE').AsString);
                        NumeroPedimento:= Pedimento;
                        End;
                   end;
                 END;
               dsPedimentosVE.Next;
               END;
            End;
            {$ENDREGION}
          End;
        dsDoctosVeDet.Next;
      end;
    {$ENDREGION}
    end; // Conceptos

    //12/04/2022 TotalImptoT := spCalcTotVe.FieldByName('TOTAL_IMPUESTOS').AsFloat; //SumaImtoConceptos
    dsQuery1.Close;
    dsQuery1.SelectSQL.Clear;
    dsQuery1.SelectSQL.Add('SELECT SUM(IMPORTE_IMPUESTO) AS IMPT_IMPTO ');
    dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE A ');
    dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS B ON (A.IMPUESTO_ID = B.IMPUESTO_ID) ');
    dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS C ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
    dsQuery1.SelectSQL.Add('WHERE C.TIPO = ''I'' ');
    dsQuery1.SelectSQL.Add('AND DOCTO_VE_ID = :DOCTO_VE_ID ');
    if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
    begin
      dsQuery1.SelectSQL.Add('AND B.TIPO_IVA <> ''4'' ');
      dsQuery1.SelectSQL.Add('AND C.ID_INTERNO <> ''P'' ');
    end;
    dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
    dsQuery1.Open;
    TotalImptoT := dsQuery1.FieldByName('IMPT_IMPTO').AsFloat;

    TotalImptoR := spCalcTotVe.FieldByName('TOTAL_RETENCIONES').AsFloat;

    if ((TotalImptoT>0) or (TotalImptoR>0) or (TieneImpto='S')) then
    begin
      with Impuestos do
      begin
        {$REGION 'Impuestos'}
        TotalImpuestosTrasladados := FloatToStrF(StrToFloatDef(FloatToStr(TotalImptoT),0),ffFixed,10,2);

        if (dsDoctosVe.FieldByName('RETIENE_IMPUESTOS').AsString='S') and (TotalImptoR > 0) then
          TotalImpuestosRetenidos := FloatToStrF(StrToFloatDef(FloatToStr(TotalImptoR),0),ffFixed,10,2);

        EsSoloExento := 'N';
        dsQuery1.Close;
        dsQuery1.SelectSQL.Clear;
        dsQuery1.SelectSQL.Add('SELECT COUNT(C.TIPO_IVA) CONTEO, C.TIPO_IVA ');
        dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A  ');
        dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
        dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
        dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID  ');
        dsQuery1.SelectSQL.Add('AND B.TIPO = ''I''  ');
        dsQuery1.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
        dsQuery1.SelectSQL.Add('GROUP BY C.TIPO_IVA  ');
        dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
        dsQuery1.Open;
        ConteoExento := 0;
        ConteoOtrosImptos := 0;
        while not dsQuery1.Eof do
        begin
           if dsQuery1.FieldByName('TIPO_IVA').AsString = '4' then
              ConteoExento := ConteoExento + 1
           else
              ConteoOtrosImptos := ConteoOtrosImptos +1;

           dsQuery1.Next;
        end;

        if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
        begin
          dsQuery1.Close;
          dsQuery1.SelectSQL.Clear;
          dsQuery1.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) BASE, SUM(A.VENTA_NETA) VENTA_NETA, SUM(A.OTROS_IMPUESTOS) OTROS_IMPUESTOS, B.NOMBRE TIPO_IMPTO, A.PCTJE_IMPUESTO, C.TIPO_IVA  ');
          dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A  ');
          dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
          dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
          dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID  ');
          dsQuery1.SelectSQL.Add('AND B.TIPO = ''I''  ');
          if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
          begin
            dsQuery1.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
          end;
          dsQuery1.SelectSQL.Add('GROUP BY B.NOMBRE, A.PCTJE_IMPUESTO, C.TIPO_IVA  ');
          dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
          dsQuery1.Open;
        end
        else
        begin
          dsQuery1.Close;
          dsQuery1.SelectSQL.Clear;
          dsQuery1.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) BASE, SUM(A.VENTA_NETA) VENTA_NETA, SUM(A.OTROS_IMPUESTOS) OTROS_IMPUESTOS, B.NOMBRE TIPO_IMPTO, A.PCTJE_IMPUESTO, C.TIPO_IVA   ');
          dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE_DET A  ');
          dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
          dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
          dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID  ');
          dsQuery1.SelectSQL.Add('AND B.TIPO = ''I''  ');
          if dsDoctosVe.FieldByName('SUJETO_IEPS').AsString='N' then
          begin
            dsQuery1.SelectSQL.Add('AND C.TIPO_IVA <> ''4''  ');
            dsQuery1.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
          end;
          dsQuery1.SelectSQL.Add('GROUP BY B.NOMBRE, A.PCTJE_IMPUESTO, C.TIPO_IVA  ');
          dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
          dsQuery1.Open;
        end;

        while not dsQuery1.Eof do
        begin
          With Traslados.Add do
    			  Begin
					      //IVA, IEPS
               if (dsQuery1.FieldByName('TIPO_IMPTO').AsString = 'IVA') then
               begin
                      Impuesto := '002';
                      Base := FormatFloat('###0.00',(dsQuery1.FieldByName('VENTA_NETA').AsFloat+dsQuery1.FieldByName('OTROS_IMPUESTOS').AsFloat));
               end
               else
                      Impuesto := '003';

               if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
               begin
                  if (dsQuery1.FieldByName('TIPO_IVA').AsString = '4') then
                      TipoFactor := 'Exento'
                  else
                      TipoFactor := 'Tasa';
               end
               else
                  TipoFactor := 'Tasa';

               ValPrctjImpto := 0.000000000000000000000000000000000000000000000000000000000000000000000;
               ValPrctjImpto := dsQuery1.FieldByName('PCTJE_IMPUESTO').AsFloat / 100;


               if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
               begin
                 if (dsQuery1.FieldByName('TIPO_IVA').AsString = '4') then
                 begin

                 end
                 else
                 begin
    					     TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);
	    				     Importe := FormatFloat('###0.00',dsQuery1.FieldByName('BASE').AsFloat);
                 end;
               end
               else
               begin
                 TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);
    				     Importe := FormatFloat('###0.00',dsQuery1.FieldByName('BASE').AsFloat);
               end;
		    	   End;
          dsQuery1.Next;
        end;

      if ((dsDoctosVe.FieldByName('RETIENE_IMPUESTOS').AsString='S') and (HayRet='S')) then
      begin
        if (TotalImptoR = 0) then
        begin
          With Retenciones.Add do
          Begin
            Impuesto := '002';
            Importe := '0.00';
          End;
        end
        else
        begin
          dsQuery1.Close;
          dsQuery1.SelectSQL.Clear;
          dsQuery1.SelectSQL.Add('SELECT B.NOMBRE IMPUESTO,B.PCTJE_IMPUESTO,C.NOMBRE TIPO_IMPTO,A.IMPORTE_IMPUESTO ');
          dsQuery1.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_VE A ');
          dsQuery1.SelectSQL.Add('INNER JOIN IMPUESTOS B ON ( A.IMPUESTO_ID = B.IMPUESTO_ID ) ');
          dsQuery1.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS C ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID ) ');
          dsQuery1.SelectSQL.Add('WHERE A.DOCTO_VE_ID = :DOCTO_VE_ID ');
          dsQuery1.ParamByName('DOCTO_VE_ID').AsInteger := DoctoVeId;
          dsQuery1.Open;
          while not dsQuery1.Eof do
          begin
              With Retenciones.Add do
              Begin
                if (dsQuery1.FieldByName('TIPO_IMPTO').AsString = 'IVA retenido') then
                  Impuesto := '002'
                else if (dsQuery1.FieldByName('TIPO_IMPTO').AsString = 'IEPS retenido') then
                  Impuesto := '003';

                 Importe := FormatFloat('###0.00',dsQuery1.FieldByName('IMPORTE_IMPUESTO').AsFloat);
              End;
              dsQuery1.Next;
          end;
        end;
      end;

      {$ENDREGION}
      end; // Impuestos
    end;
  End;

  XmlCfdiCopy := TXMLDocument.Create(nil);
  XmlCfdiCopy.XML := XmlCfdi.XML;
  XmlCfdi.Active := True;

  GeneraCadenaOriginalCFDI40(XmlCfdiCopy);

  CfdiVe.Sello := SellaFactura(gCertVerif,gCadenaOriginal);

  XmlCfdi.Active := True;
  Error := '';
  InsertFacturaElectronica( DoctoVeId,XmlCfdi,'VE',Error);
  if Error <> '' then
    raise Exception.Create('Err. InsertaFactE:'+Error);

  XmlCfdi.Active := True;
  XmlCfdi.SaveToFile('C:\Rem_Fact.xml');
  Result := XmlCfdi.XML.Text;

 end;
except on e : exception do
 begin
    Error:='Xml :'+lpaso+e.Message;
    Result := '';
 end;
end;
end;

function TFacturaEFormV40.NumPed(CadNumPed:String):String;
var Pedimento, PedimentoAux, PedimentoFin:String;
Tam:Integer;
begin
    Pedimento := stringreplace(CadNumPed, ' ', '',
                              [rfReplaceAll, rfIgnoreCase]);

    Tam := Length(Pedimento);
    PedimentoAux := Copy(Pedimento,1,2);
    PedimentoFin := PedimentoAux+'  ';
    PedimentoAux := Copy(Pedimento,3,2);
    PedimentoFin := PedimentoFin+PedimentoAux+'  ';
    PedimentoAux := Copy(Pedimento,5,4);
    PedimentoFin := PedimentoFin+PedimentoAux+'  ';
    PedimentoAux := Copy(Pedimento,9,Tam);
    PedimentoFin := PedimentoFin+PedimentoAux;

    Result := PedimentoFin;
end;

function TFacturaEFormV40.GeneraXmlPv40(DoctoPvId:Integer; TipoComp:String; Var Error:String ):WideString;
Var XmlCfdi,XmlCfdiCopy : TXMLDocument;
    CfdiVe : IXMLComprobante;
    ContReg,n,DoctoInDetId,TicketId : Integer;
    TotalImptoT,TotalImptoR,RSubtotal : Double;
    Incremento:Integer;
    cadCertificado:String;

    ValPrctjImpto:Double;
    BaseImptoDet:Double;
    CodPostaLugarExp:String;
    BaseTot, ImporteImtoTot, lFactorR, TBaseImptoDet, ImpteImp:Double;
    CadenaXML:String;
    lTipoFactor,TieneImpto:String;

DEC:Double;
NumD, NumD1, PosD:Integer;
sDEC, sDEC1, EsSoloExento:String;
ConteoExento, ConteoOtrosImptos:Integer;
begin
try
 begin

  TieneImpto := 'N';
  sysutils.Decimalseparator := '.';

    {$REGION 'Abrir datasets'}
      dsEmpresa.CloseOpen(False);

      dsDoctoPv.Close;
      dsDoctoPv.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
      dsDoctoPv.Open;

      dsDoctoPvDet.Close;
      dsDoctoPvDet.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
      dsDoctoPvDet.Open;

      dsFormasCobroCC40.Close;
      dsFormasCobroCC40.ParamByName('DOCTO_ID').AsInteger := DoctoPvId;
      dsFormasCobroCC40.Open;

      spCalcTotalesPV.Close;
      spCalcTotalesPV.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
      spCalcTotalesPV.ParamByName('SOLO_LECTURA').AsString := 'S';
      spCalcTotalesPV.ParamByName('IMPTO_INCLUIDO').AsString := 'N';
      spCalcTotalesPV.ExecProc;

      spCalcTotalesPVIEPS.Close;
      spCalcTotalesPVIEPS.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
      spCalcTotalesPVIEPS.ExecProc;

      IBQuery2.Close;
      IBQuery2.SelectSQL.Clear;
      IBQuery2.SelectSQL.Add('SELECT A.DOCTO_PV_FTE_ID ');
      IBQuery2.SelectSQL.Add('FROM DOCTOS_PV_LIGAS A ');
      IBQuery2.SelectSQL.Add('WHERE A.DOCTO_PV_DEST_ID = :DOCTO_PV_DEST ');
      IBQuery2.ParamByName('DOCTO_PV_DEST').AsInteger := DoctoPvId;
      IBQuery2.Open;
      TicketId := IBQuery2.FieldByName('DOCTO_PV_FTE_ID').AsInteger;

      IBQuery2.Close;
      IBQuery2.SelectSQL.Clear;
      IBQuery2.SelectSQL.Add('SELECT B.CODIGO_POSTAL ');
      IBQuery2.SelectSQL.Add('FROM DOCTOS_PV A ');
      IBQuery2.SelectSQL.Add('INNER JOIN LUGARES_EXPEDICION B ON (A.LUGAR_EXPEDICION_ID = B.LUGAR_EXPEDICION_ID) ');
      IBQuery2.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID ');
      IBQuery2.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
      IBQuery2.Open;
      CodPostaLugarExp := '';
      CodPostaLugarExp := IBQuery2.FieldByName('CODIGO_POSTAL').AsString;
      if CodPostaLugarExp = '' then
      begin
          CodPostaLugarExp := '';
          IBQuery2.Close;
          IBQuery2.SelectSQL.Clear;
          IBQuery2.SelectSQL.Add('SELECT A.CODIGO_POSTAL FROM DATOS_EMPRESA  A ');
          IBQuery2.Open;
          CodPostaLugarExp := IBQuery2.FieldByName('CODIGO_POSTAL').AsString;
      end;
      if CodPostaLugarExp = '' then raise Exception.Create('La empresa no tiene un código postal asignado');

      dsDatosAlmacen40.Close;
      dsDatosAlmacen40.ParamByName('DOCTO_PV_ID').AsInteger := TicketId;
      dsDatosAlmacen40.Open;
    {$ENDREGION}

  XmlCfdi := TXMLDocument.Create(nil);
  XmlCfdi.XML.Text := '<?xml version="1.0" encoding="UTF-8" ?><cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4"></cfdi:Comprobante>';
	XmlCfdi.Active := True;
	CfdiVe := GetComprobante(XmlCfdi);

  With CfdiVe do
	Begin
    {$REGION 'Atributos comprobante'}
    Version := '4.0';
    if dsDoctoPv.FieldByName('SERIE').AsString <> '@' then
        Serie := dsDoctoPv.FieldByName('SERIE').AsString;
    Folio := dsDoctoPv.FieldByName('FOLIO').AsString;
    Fecha := FormatDateTime('YYYY-MM-DD',dsDoctoPv.FieldByName('FECHA').AsDateTime)+'T'+FormatDateTime('HH:MM:SS',dsDoctoPv.FieldByName('FECHA_HORA_CREACION').AsDateTime);
    Sello := '';

    ContReg := 0;
    if dsFormasCobroCC40.IsEmpty then
       FormaPago := '99'
    else
    begin
      dsFormasCobroCC40.First;
      while not dsFormasCobroCC40.Eof do
      begin
        Inc(ContReg);
        if ContReg = 1 then
        begin
          if dsFormasCobroCC40.FieldByName('CLAVE_FISCAL').AsString = '' then
            FormaPago := '99'
          else
            FormaPago := dsFormasCobroCC40.FieldByName('CLAVE_FISCAL').AsString;
        end
        else
        begin
          if dsFormasCobroCC40.FieldByName('CLAVE_FISCAL').AsString = '' then
            FormaPago := FormaPago+','+'99'
          else
            FormaPago := FormaPago+','+dsFormasCobroCC40.FieldByName('CLAVE_FISCAL').AsString;
        end;
        dsFormasCobroCC40.Next;
      end;
    end;

    NoCertificado := gNoCertificado;


    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#x0D;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xD;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #13, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #10, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #8, '', [rfReplaceAll, rfIgnoreCase]);

    Certificado := gCertificado;

    dsIEPS_PV.Close;
    dsIEPS_PV.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
    dsIEPS_PV.Open;

    if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
    begin

      if dsIEPS_PV.FieldByName('NREG').AsInteger>0 then
      begin
        if spCalcTotalesPV.FieldByName('DSCTO_ARTS').AsFloat>0 then
          SubTotal := FloatToStrF(StrToFloatDef(spCalcTotalesPVIEPS.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2)
        else
          SubTotal := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotalesPV.FieldByName('TOTAL_A_PAGAR').AsFloat-spCalcTotalesPVIEPS.FieldByName('TOTAL_IMPUESTOS').AsFloat),0),ffFixed,10,2)
      end
      else
      begin
        if spCalcTotalesPV.FieldByName('DSCTO_ARTS').AsFloat>0 then
          SubTotal := FloatToStrF(StrToFloatDef( spCalcTotalesPV.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2)
        else
          SubTotal := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotalesPV.FieldByName('TOTAL_A_PAGAR').AsFloat-spCalcTotalesPVIEPS.FieldByName('TOTAL_IMPUESTOS').AsFloat),0),ffFixed,10,2)
      end;
    end
    else
      SubTotal := FloatToStrF(StrToFloatDef(spCalcTotalesPV.FieldByName('SUBTOTAL').AsString,0),ffFixed,10,2);

    if dsIEPS_PV.FieldByName('NREG').AsInteger>0 then
      Descuento := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotalesPVIEPS.FieldByName('DSCTO_ARTS').AsFloat+spCalcTotalesPVIEPS.FieldByName('DSCTO_EXTRA_IMPORTE').AsFloat),0),ffFixed,10,2)
    else
      Descuento := FloatToStrF(StrToFloatDef( FloatToStr(spCalcTotalesPV.FieldByName('DSCTO_ARTS').AsFloat+spCalcTotalesPV.FieldByName('DSCTO_EXTRA_IMPORTE').AsFloat),0),ffFixed,10,2);


    if dsDoctoPv.FieldByName('MONEDA_ID').AsInteger = 1 then
      Moneda := 'MXN'
    else
      if dsDoctoPv.FieldByName('CLAVE_MONEDA').AsString <> '' then
          Moneda := dsDoctoPv.FieldByName('CLAVE_MONEDA').AsString;

    Total := FloatToStrF(StrToFloatDef(spCalcTotalesPV.FieldByName('TOTAL_A_PAGAR').AsString,0),ffFixed,10,2);


    if TipoComp = 'F' then
      TipoDeComprobante := 'I';
    if TipoComp = 'D' then
      TipoDeComprobante := 'E';

    Exportacion := '01'; //liz No aplica cuando se registre el valor “02”, se debe incluir el “Complemento para Comercio Exterior”.

    MetodoPago := dsDoctoPv.FieldByName('METODO_PAGO_SAT').AsString;

    if CodPostaLugarExp <> '' then
      LugarExpedicion := CodPostaLugarExp
    else
      LugarExpedicion := dsDatosAlmacen40.FieldByName('ALM_CODIGO_POSTAL').AsString;

    TipoCambio := '1';


    SetAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
    SetAttribute('xsi:schemaLocation','http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd');
    {$ENDREGION}

    With Emisor do
    Begin
    {$REGION 'Emisor'}
      Rfc := ValidaCadena(dsEmpresa.FieldByName('RFC').AsString);

      dsDatosEmisor.Close;
      dsDatosEmisor.ParamByName('RFC').AsString := Rfc;
      dsDatosEmisor.Open;

      CadenaXML := '';
      CadenaXML := dsDatosEmisor.FieldByName('NOMBRE_FISCAL').AsString;
      CadenaXML := StringReplace(CadenaXML,'Á','A',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'É','E',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Í','I',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ñ','N',[rfReplaceAll, rfIgnoreCase]);


      CadenaXML := StringReplace(CadenaXML,'á','a',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'é','e',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'í','i',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ó','o',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ú','u',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ñ','n',[rfReplaceAll, rfIgnoreCase]);

      Nombre := CadenaXML;

      RegimenFiscal := dsEmpresa.FieldByName('CLAVE_REGIMEN_FISCAL').AsString;

      {$ENDREGION}
    End; // Emisor

    with Receptor do
    begin
    {$REGION 'Receptor'}
      Rfc := ValidaCadena(dsDoctoPv.FieldByName('RFC_CURP').AsString);

      CadenaXML := '';
      CadenaXML := dsDoctoPv.FieldByName('CLIENTE').AsString;
      CadenaXML := StringReplace(CadenaXML,'Á','A',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'É','E',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Í','I',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'Ñ','N',[rfReplaceAll, rfIgnoreCase]);

      CadenaXML := StringReplace(CadenaXML,'á','a',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'é','e',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'í','i',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ó','o',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ú','u',[rfReplaceAll, rfIgnoreCase]);
      CadenaXML := StringReplace(CadenaXML,'ñ','n',[rfReplaceAll, rfIgnoreCase]);
      Nombre := CadenaXML;

      DomicilioFiscalReceptor  := dsDoctoPv.FieldByName('CODIGO_POSTAL').AsString;
      RegimenFiscalReceptor := dsDoctoPv.FieldByName('CLAVE_REGIMEN_FISCAL').AsString; //'616';
      UsoCFDI := dsDoctoPv.FieldByName('USO_CFDI').AsString; //'S01';

      //Raise Exception.Create(dsDoctoPv.FieldByName('RFC_CURP').AsString+'*'+dsDoctoPv.FieldByName('CLIENTE').AsString+'*'+dsDoctoPv.FieldByName('CODIGO_POSTAL').AsString+'*'+dsDoctoPv.FieldByName('CLAVE_REGIMEN_FISCAL').AsString+'*'+dsDoctoPv.FieldByName('USO_CFDI').AsString);
    {$ENDREGION}
    end;


    with Conceptos do
    begin
    {$REGION 'Conceptos'}
      TBaseImptoDet := 0;
      dsDoctoPvDet.First;
      while not dsDoctoPvDet.Eof do
      begin
          With Conceptos.Add do
			    Begin
            ClaveProdServ := dsDoctoPvDet.FieldByName('CLAVE_ART_SAT').AsString;

            if dsDoctoPvDet.FieldByName('CLAVE_ARTICULO').AsString <> '' then
              NoIdentificacion := dsDoctoPvDet.FieldByName('CLAVE_ARTICULO').AsString;

            Cantidad := FloatToStrF(StrToFloatDef(dsDoctoPvDet.FieldByName('UNIDADES').AsString,0),ffFixed,10,4);

            ClaveUnidad:= dsDoctoPvDet.FieldByName('CLAVE_MEDIDA_SAT').AsString;

            if dsDoctoPvDet.FieldByName('UNIDAD_VENTA').AsString <> '' then
              Unidad := dsDoctoPvDet.FieldByName('UNIDAD_VENTA').AsString;

            CadenaXML := '';
            CadenaXML := dsDoctoPvDet.FieldByName('ARTICULO').AsString;
            CadenaXML := StringReplace(CadenaXML,'Á','A',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'É','E',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'Í','I',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'Ó','O',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'Ú','U',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'Ñ','N‘',[rfReplaceAll, rfIgnoreCase]);

            CadenaXML := StringReplace(CadenaXML,'á','a',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'é','e',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'í','i',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'ó','o',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'ú','u',[rfReplaceAll, rfIgnoreCase]);
            CadenaXML := StringReplace(CadenaXML,'ñ','n',[rfReplaceAll, rfIgnoreCase]);

            Descripcion := CadenaXML;

            dsIEPS.Close;
            dsIEPS.ParamByName('DOCTO_PV_DET_ID').AsInteger := dsDoctoPvDet.FieldByName('DOCTO_PV_DET_ID').AsInteger;
            dsIEPS.ParamByName('DOCTO_PV_ID').AsInteger := TicketId;
            dsIEPS.Open;

            dsDoctoPvDet40_IEPS_Inc.Close;
            dsDoctoPvDet40_IEPS_Inc.ParamByName('DOCTO_PV_DET_ID').AsInteger := dsDoctoPvDet.FieldByName('DOCTO_PV_DET_ID').AsInteger;
            dsDoctoPvDet40_IEPS_Inc.Open;

            if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
            begin
              {$REGION 'MyRegion'}
              //ValorUnitario := FloatToStrF(StrToFloatDef(dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsString,0),ffFixed,10,4);
              if (dsIEPS.FieldByName('NREG').AsInteger > 0) then
              begin
                DEC := Frac(dsDoctoPvDet.FieldByName('FACTOR_RED_PRECIO_CON_IMPTO').AsFloat);
                sDEC := FLOATTOSTR(DEC);
                NumD := 0;  PosD := 0; NumD1 := 0;
                NumD := Length(sDEC);
                PosD := Pos('.', sDEC);
                sDEC1 := Copy(sDEC, PosD+1, NumD);
                NumD1 := Length(sDEC1);

                if NumD1>1 then
                begin
                  spRoundProd.Close;
                  spRoundProd.ParamByName('V_FACTOR2').AsFloat := dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat;
                  spRoundProd.ParamByName('V_FACTOR_RED').AsFloat := dsDoctoPvDet.FieldByName('FACTOR_RED_PRECIO_CON_IMPTO').AsFloat;
                  spRoundProd.ExecProc;
                  ValorUnitario := spRoundProd.FieldByName('PRODUCTO').AsString;
                  Importe := FloatToStrF(StrToFloatDef(FloatToStr(spRoundProd.FieldByName('PRODUCTO').AsFloat*dsDoctoPvDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
                end
                else
                begin
                  ValorUnitario := dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsString;
                  Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctoPvDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
                end;
              end
              else
              begin
                ValorUnitario := dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsString;
                Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoPvDet40_IEPS_Inc.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctoPvDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
              end;
              {$ENDREGION}
            end
            else
            begin
              ValorUnitario := FloatToStrF(StrToFloatDef(dsDoctoPvDet.FieldByName('PRECIO_UNITARIO').AsString,0),ffFixed,10,4);//2
              Importe := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoPvDet.FieldByName('PRECIO_UNITARIO').AsFloat*dsDoctoPvDet.FieldByName('UNIDADES').AsFloat),0),ffFixed,10,2);
            end;

            if (dsIEPS.FieldByName('NREG').AsInteger > 0) then
              Descuento := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoPvDet40_IEPS_Inc.FieldByName('DSCTO_ART').AsFloat+dsDoctoPvDet40_IEPS_Inc.FieldByName('DSCTO_EXTRA').AsFloat),0),ffFixed,10,2)
            else
              Descuento := FloatToStrF(StrToFloatDef(FloatToStr(dsDoctoPvDet.FieldByName('DSCTO_ART').AsFloat+dsDoctoPvDet.FieldByName('DSCTO_EXTRA').AsFloat),0),ffFixed,10,2);

            //////Termina encabezado conceptos

            {$REGION 'Pedimentos'}
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT I.DOCTO_IN_DET_ID, I.ARTICULO_ID, V.ALMACEN_ID, V.FECHA ');
            IBQuery.SelectSQL.Add('FROM DOCTOS_PV V ');
            IBQuery.SelectSQL.Add('INNER JOIN DOCTOS_ENTRE_SIS D ON (V.DOCTO_PV_ID = D.DOCTO_FTE_ID) ');
            IBQuery.SelectSQL.Add('INNER JOIN DOCTOS_IN_DET I ON (I.DOCTO_IN_ID = D.DOCTO_DEST_ID) ');
            IBQuery.SelectSQL.Add('WHERE D.CLAVE_SIS_FTE = ''PV'' AND D.CLAVE_SIS_DEST = ''IN'' ');
            IBQuery.SelectSQL.Add('AND V.DOCTO_PV_ID = :DOCTO_PV_ID ');
            IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := TicketId;
            IBQuery.CloseOpen(false);
            ContReg := 1;
            while not IBQuery.Eof do
            begin
              DoctoInDetId := IBQuery.FieldByName('DOCTO_IN_DET_ID').AsInteger;
              if dsDoctoPvDet.FieldByName('POSICION').ASINTEGER = ContReg then
                Break;
              IBQuery.Next;
              inc(ContReg);
            end;

            dsPedimentosPv.Close;
            dsPedimentosPv.Parambyname('DOCTO_PV_ID').asinteger := DoctoPvId;
            dsPedimentosPv.Parambyname('DOCTO_IN_DET_ID').asinteger := DoctoInDetId;
            dsPedimentosPv.Open;

            If dsPedimentosPv.FieldByName('ADUANA_CLAVE').AsString <> '' then
            Begin
              while NOT dsPedimentosPv.Eof do
              BEGIN
                With InformacionAduanera do
                begin
                  With InformacionAduanera.Add do
         			    Begin
                    fecha:=dsPedimentosPv.FieldByName('ADUANA_FECHA').AsString;
                  End;
                end;
              dsPedimentosPv.Next;
              END;
            End;
           {$ENDREGION}

           {$REGION 'Impuestos Concepto'}
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT A.IMPORTE_IMPUESTO, A.VENTA_NETA, B.NOMBRE, A.PCTJE_IMPUESTO, A.ID_INTERNO_TIPO_IMPTO, C.TIPO_IVA  ');
            IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV_DET A ');
            IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID) ');
            IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
            IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_DET_ID = :DOCTO_PV_DET_ID ');
            IBQuery.SelectSQL.Add('AND A.DOCTO_PV_ID = :DOCTO_PV_ID ');
            IBQuery.SelectSQL.Add('AND B.TIPO = ''I'' ');
            if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
              IBQuery.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P'' ');

            IBQuery.ParamByName('DOCTO_PV_DET_ID').AsInteger := dsDoctoPvDet.FieldByName('DOCTO_PV_DET_ID').AsInteger;//DoctoInDetId;   //DOCTO_PV_DET_ID    DOCTO_PV_DET_ID
            IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
            IBQuery.CloseOpen(false);

            if IBQuery.IsEmpty then
            begin
              ObjetoImp := '01';
            end
            else
            begin
              ObjetoImp := '02';

              If IBQuery.FieldByName('NOMBRE').AsString <> '' then
              Begin
                while NOT IBQuery.Eof do
                BEGIN
                  With Impuestos do
                  begin
                    With Traslados.Add do
                    begin
                        lTipoFactor := '';
                        if IBQuery.FieldByName('TIPO_IVA').AsString = '4' then
                          lTipoFactor := 'Exento'
                        else
                          lTipoFactor := 'Tasa';

                          if (IBQuery.FieldByName('NOMBRE').AsString = 'IVA') then
                          begin
                            IBQuery2.Close;
                            IBQuery2.SelectSQL.Clear;
                            IBQuery2.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) IMPORTE_IMPUESTO');
                            IBQuery2.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV_DET A ');
                            IBQuery2.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID) ');
                            IBQuery2.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
                            IBQuery2.SelectSQL.Add('WHERE A.DOCTO_PV_DET_ID = :DOCTO_PV_DET_ID ');
                            IBQuery2.SelectSQL.Add('AND A.DOCTO_PV_ID = :DOCTO_PV_ID ');
                            IBQuery2.SelectSQL.Add('AND B.TIPO = ''I'' ');
                            IBQuery2.SelectSQL.Add('AND UPPER(B.NOMBRE) <> UPPER(''IVA'') ');
                            IBQuery2.ParamByName('DOCTO_PV_DET_ID').AsInteger := dsDoctoPvDet.FieldByName('DOCTO_PV_DET_ID').AsInteger;//DoctoInDetId;   //DOCTO_PV_DET_ID    DOCTO_PV_DET_ID
                            IBQuery2.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
                            IBQuery2.CloseOpen(false);
                            BaseImptoDet:= 0.000000000000000000000000000000000000000000000000000000000000000000000000000000;
                            BaseImptoDet:= IBQuery2.FieldByName('IMPORTE_IMPUESTO').AsFloat;
                            BaseImptoDet := IBQuery.FieldByName('VENTA_NETA').AsFloat + BaseImptoDet;
                            Base := FormatFloat('###0.00',BaseImptoDet); //IVA, IEPS
                            Impuesto := '002';
                        end
                        else
                        begin
                            Base := FormatFloat('###0.00',IBQuery.FieldByName('VENTA_NETA').AsFloat); //IVA, IEPS
                            Impuesto := '003';
                        end;

					              TipoFactor := lTipoFactor; //'Tasa';
                        ValPrctjImpto := 0.000000000000000000000000000000000000000000000000000000000000000000000;
                        ValPrctjImpto := IBQuery.FieldByName('PCTJE_IMPUESTO').AsFloat / 100;

                        if lTipoFactor <> 'Exento' then
                        begin
                          TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);
                          if IBQuery.FieldByName('IMPORTE_IMPUESTO').AsFloat > 0.0000 then
                          begin
                            Importe := FormatFloat('###0.00',IBQuery.FieldByName('IMPORTE_IMPUESTO').AsFloat);
                          end
                          else
                          begin
                            Importe := '0.00';
                            ImpteImp := 0;
                          end;

                          TieneImpto := 'S';
                        end;

                      end;
                    end;
                    IBQuery.Next;
                  END;
                End;
            end;
           {$ENDREGION}

          End;
        dsDoctoPvDet.Next;
      end;
    {$ENDREGION}
    end; // Conceptos

    //TotalImptoT := spCalcTotalesPV.FieldByName('TOTAL_IMPUESTOS').AsFloat;
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT SUM(IMPORTE_IMPUESTO) AS IMPT_IMPTO ');
    IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV A ');
    IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS B ON (A.IMPUESTO_ID = B.IMPUESTO_ID) ');
    IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS C ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID) ');
    IBQuery.SelectSQL.Add('WHERE C.TIPO = ''I'' ');
    IBQuery.SelectSQL.Add('AND DOCTO_PV_ID = :DOCTO_PV_ID ');
    if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
    begin
      IBQuery.SelectSQL.Add('AND B.TIPO_IVA <> ''4'' ');
      IBQuery.SelectSQL.Add('AND C.ID_INTERNO <> ''P'' ');
    end;
    IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
    IBQuery.Open;

    TotalImptoT := IBQuery.FieldByName('IMPT_IMPTO').AsFloat;
    TotalImptoR := 0;

    if ((TotalImptoT>0) or (TotalImptoR>0) or (TieneImpto='S')) then
    begin

    with Impuestos do
    begin
      {$REGION 'Impuestos'}
        TotalImpuestosTrasladados := FloatToStrF(StrToFloatDef(FloatToStr(TotalImptoT),0),ffFixed,10,2);

        if TotalImptoR > 0.00 then
          TotalImpuestosRetenidos := FloatToStrF(StrToFloatDef(FloatToStr(TotalImptoR),0),ffFixed,10,2);

        EsSoloExento := 'N';
        IBQuery.Close;
        IBQuery.SelectSQL.Clear;
        IBQuery.SelectSQL.Add('SELECT COUNT(C.TIPO_IVA) CONTEO, C.TIPO_IVA ');
        IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV_DET A  ');
        IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
        IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
        IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID  ');
        IBQuery.SelectSQL.Add('AND B.TIPO = ''I''  ');
        IBQuery.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
        IBQuery.SelectSQL.Add('GROUP BY C.TIPO_IVA  ');
        IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
        IBQuery.Open;
        ConteoExento := 0;
        ConteoOtrosImptos := 0;
        while not IBQuery.Eof do
        begin
           if IBQuery.FieldByName('TIPO_IVA').AsString = '4' then
              ConteoExento := ConteoExento + 1
           else
              ConteoOtrosImptos := ConteoOtrosImptos +1;

           IBQuery.Next;
        end;

        if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
        begin
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) BASE, SUM(A.VENTA_NETA) VENTA_NETA, SUM(A.OTROS_IMPUESTOS) OTROS_IMPUESTOS, B.NOMBRE TIPO_IMPTO, A.PCTJE_IMPUESTO, C.TIPO_IVA  ');
          IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV_DET A  ');
          IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
          IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
          IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID  ');
          IBQuery.SelectSQL.Add('AND B.TIPO = ''I''  ');
          if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
          begin
            IBQuery.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
          end;
          IBQuery.SelectSQL.Add('GROUP BY B.NOMBRE, A.PCTJE_IMPUESTO, C.TIPO_IVA  ');
          IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
          IBQuery.Open;
        end
        else
        begin
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT SUM(A.IMPORTE_IMPUESTO) BASE, SUM(A.VENTA_NETA) VENTA_NETA, SUM(A.OTROS_IMPUESTOS) OTROS_IMPUESTOS, B.NOMBRE TIPO_IMPTO, A.PCTJE_IMPUESTO  ');
          IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV_DET A  ');
          IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS C ON (A.IMPUESTO_ID = C.IMPUESTO_ID)  ');
          IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS B ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID)  ');
          IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID  ');
          IBQuery.SelectSQL.Add('AND B.TIPO = ''I''  ');
          if dsDoctoPv.FieldByName('SUJETO_IEPS').AsString='N' then
          begin
            IBQuery.SelectSQL.Add('AND C.TIPO_IVA <> ''4''  ');
            IBQuery.SelectSQL.Add('AND A.ID_INTERNO_TIPO_IMPTO <> ''P''  ');
          end;
          IBQuery.SelectSQL.Add('GROUP BY B.NOMBRE, A.PCTJE_IMPUESTO  ');
          IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
          IBQuery.Open;
        end;

        while not IBQuery.Eof do
        begin
          With Traslados.Add do
    			  Begin
					      //IVA, IEPS
               if (IBQuery.FieldByName('TIPO_IMPTO').AsString = 'IVA') then
               begin
                      Impuesto := '002';
                      Base := FormatFloat('###0.00',(IBQuery.FieldByName('VENTA_NETA').AsFloat+IBQuery.FieldByName('OTROS_IMPUESTOS').AsFloat));
               end
               else
                      Impuesto := '003';

               if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
               begin
                  if (IBQuery.FieldByName('TIPO_IVA').AsString = '4') then
                      TipoFactor := 'Exento'
                  else
                      TipoFactor := 'Tasa';
               end
               else
                  TipoFactor := 'Tasa';

               ValPrctjImpto := 0.000000000000000000000000000000000000000000000000000000000000000000000;
               ValPrctjImpto := IBQuery.FieldByName('PCTJE_IMPUESTO').AsFloat / 100;

               if (ConteoExento > 0) and (ConteoOtrosImptos > 0) then
               begin
                 if (IBQuery.FieldByName('TIPO_IVA').AsString = '4') then
                 begin

                 end
                 else
                 begin
    					     TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);//FormatFloat('###0.00',IBQuery.FieldByName('PCTJE_IMPUESTO').AsFloat);
	    				     Importe := FormatFloat('###0.00',IBQuery.FieldByName('BASE').AsFloat); //FormatFloat('###0.0000',ImporteImtoTot);  //
                 end;
               end
               else
               begin
                 TasaOCuota := FormatFloat('###0.000000',ValPrctjImpto);//FormatFloat('###0.00',IBQuery.FieldByName('PCTJE_IMPUESTO').AsFloat);
    				     Importe := FormatFloat('###0.00',IBQuery.FieldByName('BASE').AsFloat); //FormatFloat('###0.0000',ImporteImtoTot);  //
               end;
		    	   End;
          IBQuery.Next;
        end;

        if (TotalImptoR > 0) then
        begin
          IBQuery.Close;
          IBQuery.SelectSQL.Clear;
          IBQuery.SelectSQL.Add('SELECT B.NOMBRE IMPUESTO,B.PCTJE_IMPUESTO,C.NOMBRE TIPO_IMPTO,A.IMPORTE_IMPUESTO ');
          IBQuery.SelectSQL.Add('FROM IMPUESTOS_DOCTOS_PV A ');
          IBQuery.SelectSQL.Add('INNER JOIN IMPUESTOS B ON ( A.IMPUESTO_ID = B.IMPUESTO_ID ) ');
          IBQuery.SelectSQL.Add('INNER JOIN TIPOS_IMPUESTOS C ON ( C.TIPO_IMPTO_ID = B.TIPO_IMPTO_ID ) ');
          IBQuery.SelectSQL.Add('WHERE A.DOCTO_PV_ID = :DOCTO_PV_ID AND C.NOMBRE = :TIPO_IMPTO ');
          IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := DoctoPvId;
          IBQuery.ParamByName('TIPO_IMPTO').AsString := 'IVA retenido';
          IBQuery.Open;
          while not IBQuery.Eof do
          begin
            With Retenciones.Add do
              Begin
                 if (IBQuery.FieldByName('TIPO_IMPTO').AsString = 'IVA') then
                              Impuesto := '002'
                          else
                              Impuesto := '003';
                 Importe := FormatFloat('###0.00',IBQuery.FieldByName('IMPORTE_IMPUESTO').AsFloat);
               End;
            IBQuery.Next;
          end;
      end;
      {$ENDREGION}
    end; // Impuestos

    end;

  End;

  XmlCfdiCopy := TXMLDocument.Create(nil);
  XmlCfdi.SaveToFile('C:\11.xml');


  XmlCfdiCopy.XML := XmlCfdi.XML;
  GeneraCadenaOriginalCFDI40(XmlCfdiCopy);

  //Raise Exception.Create('cadena: '+gCadenaOriginal);

  CfdiVe.Sello := SellaFactura(gCertVerif,gCadenaOriginal);
  XmlCfdi.Active := True;

  Result := XmlCfdi.XML.Text;

  XmlCfdi.SaveToFile('C:\ClientesSelloXXX.xml');

  Error := '';


  if not InsertFacturaElectronica( DoctoPvId,XmlCfdi,'PV',Error) then
     Exception.Create(Error);

  XmlCfdi.SaveToFile('C:\1.XML');

  end
except on e : exception do
 begin
   //Error := gCadenaOriginal+' - '+Error+#13+e.Message;
   Error := e.Message;
   XmlCfdi.XML.Text := '';
   GeneraXmlPv40:= '';
   Result := '';
 end;
end;
end;

function TFacturaEFormV40.TimbrarFac40(DoctoId:Integer; SisOrigen, Url,Usuario,Pass,Serie:String; Var Error:String):boolean;
Var
   UUID,FechaTimbrado:String;
   FOLIOS_FISCALES_ID,USO_FOLIO_ID,n,HIST_TIMBRE_ID,CFDI_ID : Integer;
   CFDICopy : IXMLComprobante;
   PathG:String;

   respuesta: TElStringList;
   ResServidor :TStream;
   valorPost:Integer;
   Codigo:String;
   Error2:String;
   FactXml:WideString;
   Consulta :String;
begin
   Result := False;
   PathG := GetPrefer('CarpetaArchivos');
   Consulta := '';

   Url:=StringReplace(Url, 'HTTPS://', '', [rfReplaceAll, rfIgnoreCase]);
   Url:=StringReplace(Url, 'https://', '', [rfReplaceAll, rfIgnoreCase]);
   Url:=StringReplace(Url, 'HTTP://', '', [rfReplaceAll, rfIgnoreCase]);
   Url:=StringReplace(Url, 'http://', '', [rfReplaceAll, rfIgnoreCase]);

   if SisOrigen = 'VM' then
   begin
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT A.XML,A.FOLIOS_FISCALES_ID,A.USO_FOLIO_ID   ');
      IBQuery.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = ''PV''  ');
      IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoId;
      IBQuery.Open;
      Consulta := 'UPDATE DOCTOS_PV SET CFDI_CERTIFICADO = ''S'' WHERE ( DOCTO_PV_ID = :DOCTO_ID )  ';
   end;
   if (SisOrigen = 'RE') or (SisOrigen = 'PE') then
   begin
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('SELECT A.XML,A.FOLIOS_FISCALES_ID,A.USO_FOLIO_ID  ');
      IBQuery.SelectSQL.Add('FROM USOS_FOLIOS_FISCALES A WHERE A.DOCTO_ID = :DOCTO_ID AND A.SISTEMA = ''VE''  ');
      IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoId;
      IBQuery.Open;
      Consulta := 'UPDATE DOCTOS_VE SET CFDI_CERTIFICADO = ''S'' WHERE ( DOCTO_VE_ID = :DOCTO_ID )   ';
   end;

   xmlFac.XML.Text := IBQuery.FieldByName('XML').AsString;
   xmlFac.Active := True;

   xmlFacCopy.XML.Text := IBQuery.FieldByName('XML').AsString;
   xmlFacCopy.Active := True;

   FactXml := IBQuery.FieldByName('XML').AsString;

   FOLIOS_FISCALES_ID := IBQuery.FieldByName('FOLIOS_FISCALES_ID').AsInteger;
   USO_FOLIO_ID := IBQuery.FieldByName('USO_FOLIO_ID').AsInteger;

  try
  begin
    try
    begin
      gXML40 := '';
      Error := '';
      Error2 := '';
      respuesta := TElStringList.Create;
      ResServidor := TStream.Create;
      HttpsClient.RequestParameters.CustomHeaders.Clear;
      HttpsClient.RequestParameters.CustomHeaders.Add('usrws:'+Usuario);//RFC
      HttpsClient.RequestParameters.CustomHeaders.Add('pwdws:'+Pass);//Contraseña de comercio digital PWD

      if (pos('pruebas', Url)<>0) or (pos('PRUEBAS', Url)<>0) then
      begin
        //https://pruebas.comercio-digital.mx/timbre/timbrarV5.aspx
        valorPost := HttpsClient.Post('https://pruebas.comercio-digital.mx/timbre4/timbrarV5', FactXml);
      end
      else
      begin
        //liz checar esta liga se le quita .aspx
        valorPost := HttpsClient.Post('https' + '://' + 'microsip.comercio-digital.mx/timbre4/timbrarV5', FactXml);
      end;

      respuesta := HttpsClient.ResponseHeaders;

      Codigo := HttpsClient.GetHeaderByName(respuesta, 'codigo');
      UUID := HttpsClient.GetHeaderByName(respuesta, 'uuid');
      Error := HttpsClient.GetHeaderByName(respuesta, 'errmsg');

      if Codigo <> '000' then
      begin
          Error2 := CodigosError(Codigo);
      end;

      //Error2 := 'Codigo '+Codigo +'UUID '+ UUID+'Error '+Error;

    end;
    finally
      HttpsClient.Close(true);
    end;
  end;
  except
    on E : Exception do
    begin
      Error := E.Message;
    end;
  end;

  if (Error <> '') or (Error2 <> '') then
  begin
      Result := False;
      Raise Exception.Create('Ocurrió un error al momento de timbrar la factura electrónica: '+Error +','+ Error2);
  end;

   xmlTimbre.XML.Text := gXml40;
   xmlTimbre.Active := true;

   //xmlTimbre.SaveToFile('C:\Timbrado.xml');

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('INSERT INTO MGFACTURA_HIST_TIMBRES (HIST_TIMBRE_ID, FOLIO, XML, ');
   IBQuery.SelectSQL.Add('XML_TIMBRE_RECIBIDO) VALUES ');
   IBQuery.SelectSQL.Add('( :HIST_TIMBRE_ID, :FOLIO, :XML, :XML_TIMBRE_RECIBIDO ) ');
   spGenDoctoId.ExecProc;
   HIST_TIMBRE_ID := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
   IBQuery.ParamByName('HIST_TIMBRE_ID').AsInteger := HIST_TIMBRE_ID;
   IBQuery.ParamByName('FOLIO').AsString := Serie;
   IBQuery.ParamByName('XML').AsString := xmlFac.XML.Text;
   IBQuery.ParamByName('XML_TIMBRE_RECIBIDO').AsString := xmlTimbre.XML.Text;
   IBQuery.Open;

   if trTrans.InTransaction then
      trTrans.Commit;

   trTrans.StartTransaction;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT XML_TIMBRE_RECIBIDO ');
   IBQuery.SelectSQL.Add('FROM MGFACTURA_HIST_TIMBRES ');
   IBQuery.SelectSQL.Add('WHERE HIST_TIMBRE_ID = :HIST_TIMBRE_ID ');
   IBQuery.ParamByName('HIST_TIMBRE_ID').AsInteger := HIST_TIMBRE_ID;
   IBQuery.Open;
   XMLfacCopy.XML.Text := IBQuery.FieldByName('XML_TIMBRE_RECIBIDO').AsString;

	 XMLfacCopy.Active := true;
	 CFDICopy := GetComprobante(XMLfacCopy);

   with CFDICopy do
   begin
     with Complemento do
     begin

      for n := 0 to Complemento.ChildNodes.Count - 1  do
   		begin
        if Complemento.ChildNodes[n].NodeName = 'tfd:TimbreFiscalDigital' then
				begin
          UUID := Complemento.ChildNodes[n].Attributes['UUID'];
          FechaTimbrado := Complemento.ChildNodes[n].Attributes['FechaTimbrado'];
        end;
      end;

     end;
   end;

   if xmlTimbre.XML.Text <> '' then
   begin
      CFDI_ID := InsertaRepositorio40(xmlTimbre, 5,  Error);
      if ((CFDI_ID = 0) or (Error<>'')) then
          raise EXCEPTion.Create(Error);

     IBQuery.Close;
     IBQuery.SelectSQL.Clear;
     IBQuery.SelectSQL.Add('UPDATE USOS_FOLIOS_FISCALES SET PROV_CERT = :PROV_CERT, ');
     IBQuery.SelectSQL.Add('FECHA_HORA_TIMBRADO = :FECHA_HORA_TIMBRADO, XML = :XML, ');
     IBQuery.SelectSQL.Add('UUID = :UUID, CFDI_ID = :CFDI_ID WHERE ( USO_FOLIO_ID = :USO_FOLIO_ID ); ');
     IBQuery.ParamByName('USO_FOLIO_ID').AsInteger := USO_FOLIO_ID;
     IBQuery.ParamByName('PROV_CERT').AsString := 'CDIGITAL';
     IBQuery.ParamByName('FECHA_HORA_TIMBRADO').AsString := FechaTimbrado;
     IBQuery.ParamByName('UUID').AsString := UUID;
     IBQuery.ParamByName('XML').AsString := xmlTimbre.XML.Text;
     IBQuery.ParamByName('CFDI_ID').AsInteger := CFDI_ID;
     IBQuery.Open;

     IBQuery.Close;
     IBQuery.SelectSQL.Clear;
     IBQuery.SelectSQL.Add(Consulta);
     IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoId;
     IBQuery.Open;

     Result := True;
   end else
   begin
     Result := False;
     Raise Exception.Create('Ocurrió un error al momento de timbrar la factura electrónica.' + UUID + ' ** '+FechaTimbrado);
   end;

end;

function TFacturaEFormV40.InsertaRepositorio40(sXML:TXMLDocument; ConceptoId:Integer; var Error:String):Integer;
Var ComprobranteCFDI : IXMLComprobante;
CfdiId : Integer;
TipoConcepto,sUUID,sFecha,sFolio,sSerie,sRfcCliente,sNombreCli,sTotal,sRfcEmisor,sNomConcepto,
sMoneda,sTipoCambio,
sSubtotal, sDescuento, sMetPag, sCodPag, sForPag, sRegFis, sUso,sLugExp,sUUIDR :String;
n:Integer;
sxmlText:WideString;
begin
Error:='';
Result := 0;



  try
   Begin

    SysUtils.ShortDateFormat := 'dd/mm/yyyy';
      sXML.Active := True;
      sxmlText := sXML.XML.Text;

      ComprobranteCFDI := GetComprobante(sXML);

      With ComprobranteCFDI do
      Begin
        sFolio := Folio;
        try
           sSerie := Serie;
         except
            sSerie := '';
        end;

        sFecha := Fecha;
        sTotal := Total;
        sSubtotal := SubTotal;
        sDescuento := Descuento;
        sMetPag := MetodoPago;
        sCodPag := CondicionesDePago;
        sForPag := FormaPago;
        sLugExp := LugarExpedicion;

        sMoneda := Moneda;
        sTipoCambio := TipoCambio;

        if sTipoCambio = '' then
            sTipoCambio := '1.00';

        with Emisor do
        begin
          sRfcCliente := Rfc;
          sRegFis:=RegimenFiscal;
        end;

        with Receptor do
        begin
          sRfcEmisor := Rfc;
          sNombreCli := Nombre;
          sUso := UsoCFDI;
        end;

        with Complemento do
        Begin
          for n := 0 to Complemento.ChildNodes.Count - 1  do
   		    begin
            if Complemento.ChildNodes[n].NodeName = 'tfd:TimbreFiscalDigital' then
				    begin
              sUUID := Complemento.ChildNodes[n].Attributes['UUID'];
            end;
          end;
        End;
      End;

      spGenDoctoId.Close;
      spGenDoctoId.ExecProc;
      CfdiId := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
      IBQuery.Close;
      IBQuery.SelectSQL.Clear;
      IBQuery.SelectSQL.Add('INSERT INTO REPOSITORIO_CFDI (CFDI_ID, MODALIDAD_FACTURACION, VERSION, UUID, NATURALEZA, ');
      IBQuery.SelectSQL.Add('TIPO_COMPROBANTE, TIPO_DOCTO_MSP, FOLIO, FECHA, RFC, TAXID, NOMBRE, IMPORTE, MONEDA, ');
      IBQuery.SelectSQL.Add('TIPO_CAMBIO, ES_PARCIALIDAD, NOM_ARCH, XML, REFER_GRUPO, FECHA_CANCELACION, ');
      IBQuery.SelectSQL.Add('SELLO_VALIDADO, USUARIO_VAL_SELLO, USUARIO_CREADOR, FECHA_HORA_CREACION, ');
      IBQuery.SelectSQL.Add('LUGAR_EXPEDICION,SUBTOTAL,DESCUENTO,METODO_PAGO,CONDICIONES_PAGO,FORMA_PAGO,REGIMEN_FISCAL_EMISOR,USO_CFDI, ');
      IBQuery.SelectSQL.Add('USUARIO_AUT_CREACION, USUARIO_ULT_MODIF, FECHA_HORA_ULT_MODIF, USUARIO_AUT_MODIF) ');
      IBQuery.SelectSQL.Add(' VALUES (:CFDI_ID, :MODALIDAD_FACTURACION, ''4.0'', :UUID, :NATURALEZA, ');
      IBQuery.SelectSQL.Add(':TIPO_COMPROBANTE, :TIPO_DOCTO_MSP, :FOLIO, :FECHA, :RFC, :TAXID, :NOMBRE, :IMPORTE, :MONEDA, ');
      IBQuery.SelectSQL.Add(':TIPO_CAMBIO, :ES_PARCIALIDAD, :NOM_ARCH, :XML, :REFER_GRUPO, :FECHA_CANCELACION, ');
      IBQuery.SelectSQL.Add(':SELLO_VALIDADO, :USUARIO_VAL_SELLO, :USUARIO_CREADOR, :FECHA_HORA_CREACION, ');
      IBQuery.SelectSQL.Add(':LUGAR_EXPEDICION,:SUBTOTAL,:DESCUENTO,:METODO_PAGO,:CONDICIONES_PAGO,:FORMA_PAGO,:REGIMEN_FISCAL_EMISOR,:USO_CFDI, ');
      IBQuery.SelectSQL.Add(':USUARIO_AUT_CREACION, :USUARIO_ULT_MODIF, :FECHA_HORA_ULT_MODIF, :USUARIO_AUT_MODIF) ');
      IBQuery.ParamByName('CFDI_ID').AsInteger := CfdiId;
      IBQuery.ParamByName('MODALIDAD_FACTURACION').AsString := 'CFDI';
      IBQuery.ParamByName('UUID').AsString := sUUID;
      IBQuery.ParamByName('NATURALEZA').AsString := 'E'; {E,R}
      IBQuery.ParamByName('TIPO_COMPROBANTE').AsString := 'I';  {I,E}
      IBQuery.ParamByName('TIPO_DOCTO_MSP').AsString := 'Factura';
      IBQuery.ParamByName('FOLIO').AsString := sSerie+sFolio;
      IBQuery.ParamByName('FECHA').AsDate := Now;//StrToDate(Copy(sFecha,9,2)+'/'+Copy(sFecha,6,2)+'/'+Copy(sFecha,0,4));
      IBQuery.ParamByName('RFC').AsString := sRfcEmisor;
      IBQuery.ParamByName('TAXID').Clear;
      IBQuery.ParamByName('NOMBRE').AsString := sNombreCli;
      IBQuery.ParamByName('IMPORTE').AsString := sTotal;
      IBQuery.ParamByName('MONEDA').AsString := sMoneda;
      IBQuery.ParamByName('TIPO_CAMBIO').AsString := sTipoCambio;
      IBQuery.ParamByName('ES_PARCIALIDAD').AsString := 'N';
      IBQuery.ParamByName('NOM_ARCH').AsString := sRfcEmisor+'_Factura'+sSerie+sFolio+'_'+FormatDateTime('yyyymmdd',StrToDate(Copy(sFecha,9,2)+'/'+Copy(sFecha,6,2)+'/'+Copy(sFecha,0,4)))+'.xml';
      IBQuery.ParamByName('XML').AsString := sxmlText;
      IBQuery.ParamByName('REFER_GRUPO').Clear;
      IBQuery.ParamByName('FECHA_CANCELACION').Clear;
      IBQuery.ParamByName('SELLO_VALIDADO').AsString := 'M';
      {  'M' = Por microsip
         'U' =
         'P' =
         'N' =              }
      IBQuery.ParamByName('USUARIO_VAL_SELLO').Clear;
      IBQuery.ParamByName('FECHA_HORA_CREACION').AsDateTime := IBDatabase1.GetServerTime;

      IBQuery.ParamByName('LUGAR_EXPEDICION').AsString := sLugExp;
      IBQuery.ParamByName('SUBTOTAL').AsString := sSubtotal;
      IBQuery.ParamByName('DESCUENTO').AsString := sDescuento;
      IBQuery.ParamByName('METODO_PAGO').AsString := sMetPag;
      IBQuery.ParamByName('CONDICIONES_PAGO').AsString := sCodPag;
      IBQuery.ParamByName('FORMA_PAGO').AsString := sForPag;
      IBQuery.ParamByName('REGIMEN_FISCAL_EMISOR').AsString := sRegFis;
      IBQuery.ParamByName('USO_CFDI').AsString := sUso;

      IBQuery.ParamByName('USUARIO_AUT_CREACION').Clear;
      IBQuery.ParamByName('FECHA_HORA_ULT_MODIF').AsDateTime := IBDatabase1.GetServerTime;
      IBQuery.ParamByName('USUARIO_AUT_MODIF').Clear;
      IBQuery.Open;

      Result := CfdiId;
      Error := '';
  End
  except on e : Exception do
  Begin
     Error:='Error al inserta repositorio 4.0: - '+e.Message;
     Result := 0;
  End;
  end;

end;

function TFacturaEFormV40.CodigosError(Codigo:String):String;
var Error:String;
begin

        Error := '';

        if Codigo = '123' then
        Error := 'CSD no está en la Lista de Contribuyentes con Obligación (SCO).';

        if Codigo = '140' then
        Error := 'El valor del atributo Version no es 3.2.';

        if Codigo = '301' then
        Error := 'XML mal formado o no cumple con la validación del XSD del SAT ( algún campo invalido ).';

        if Codigo = '302' then
        Error := 'Sello mal formado o Invalido; al verificar el sello contra el HASH generado por la Cadena Original no coinciden puede ser problema de Cadena Original mal formada, mal generado el HASH de la cadena original o mal generado el sello del HASH.';

        if Codigo = '303' then
        Error := 'Sello no corresponde al emisor; el RFC del Certificado no es el mismo RFC del Emisor   304: Certificado revocado o caduco.';

        if Codigo = '305' then
        Error := 'Fecha emisión del CFDI no está dentro de vigencia CSD emisor.';

        if Codigo = '306' then
        Error := 'Certificado no es tipo CSD (puede ser FIEL).';

        if Codigo = '307' then
        Error := 'CFDI contiene timbre previo.';

        if Codigo = '308' then
        Error := 'Certificado no expedido por SAT.';

        if Codigo = '401' then
        Error := 'Fecha y hora de generación fuera de rango (72 horas).';

        if Codigo = '402' then
        Error := 'RFC emisor no se encuentra en régimen contribuyentes.';

        if Codigo = '403' then
        Error := 'Fecha emisión no es posterior a 2011-01-01.';

        if Codigo = '404' then
        Error := 'Hora Posterior.';

        if Codigo = '505' then
        Error := 'Error interno en el servicio. (normalmente es que servicio de base de datos no está disponible).';

        if Codigo = '501' then
        Error := 'Error interno SCD.';

        if Codigo = '700' then
        Error := 'Error en autorización del usuario (No Aplica para Superusuario).';

        if Codigo = '701' then
        Error := 'Usuario No autorizado (No Aplica para Superusuario).';

        if Codigo = '702' then
        Error := 'Combinación de usuario/contraseña invalida (No Aplica para Superusuario).';

        if Codigo = '703' then
        Error := 'Saldo insuficiente para Timbrar (No Aplica para Superusuario).';

        if Codigo = '704' then
        Error := 'Usuario distinto del RFC emisor (No aplica para usuarios de tipo agencia o Superusuario).';

        if Codigo = '801' then
        Error := 'Versión del comprobante en la fecha de emisión es invalida.';

        if Codigo = '802' then
        Error := 'Versión 3.0 del CFDI es obsoleta.';

        if Codigo = '803' then
        Error := 'RFC no tiene validez de obligaciones para emitir CFDIs.';

        if Codigo = '901' then
        Error := 'XML es muy grande.';

        if Codigo = '902' then
        Error := 'Solicitud contiene caracteres ilegales.';

        if Codigo = '903' then
        Error := 'Solicitud no contiene los parámetros requeridos.';

        if Codigo = '904' then
        Error := 'Solicitud vacía.';

        if Codigo = '905' then
        Error := 'Método de HTTPS no permitido.';

        if Codigo = '906' then
        Error := 'Content-Type no permitido.';

        if Codigo = '907' then
        Error := 'Encoding no permitido.';

        if Codigo = '908' then
        Error := 'Content-Length no coincide con el tamaño de la solicitud recibida.';

        if Codigo = '909' then
        Error := 'Núm. Certificado no es numérico.';

        if Codigo = '910' then
        Error := 'No hay base de datos.';

        if Codigo = '921' then
        Error := 'Contiene Complemento bancario.';

        if Codigo = '923' then
        Error := 'Complemento Acreditamiento de IEPS no vigente.';

        Result:= Error;
end;

//********************Metodos Evaluados***********************//

procedure TFacturaEFormV40.GeneraJSonMongo(CFDIxml:TXMLDocument);
const pipe = '|';
var n,n1, n2, jo : integer;
	CFDICopy : IXMLComprobante;

	procedure AgregaDato(atom : string);
	begin
		if atom <> '' then gCadenaOriginal := gCadenaOriginal + pipe + atom;
	end;
begin

  gCadenaOriginal := pipe;

  CFDIxml.Active := True;
  CFDICopy := GetComprobante(CFDIxml);
	with CFDICopy do
	begin
		{a.	version         b.	fecha                c.	tipoDeComprobante       d.	formaDePago       e.	condicionesDePago
     f.	subTotal        g.	descuento            h.	TipoCambio              i.	Moneda            j.	total
     k.	metodoDePago    l.	LugarExpedicion      m.	NumCtaPago              n.	FolioFiscalOrig   o.	SerieFolioFiscalOrig
     p.	FechaFolioFiscalOrig      q.	MontoFolioFiscalOrig }

    AgregaDato(Version);   AgregaDato(Serie);  AgregaDato(Folio);  AgregaDato(Fecha);
    AgregaDato(FormaPago); AgregaDato(NoCertificado); AgregaDato(SubTotal); AgregaDato(Descuento);
    AgregaDato(Moneda);
    AgregaDato(TipoCambio);
    AgregaDato(Total); AgregaDato(TipoDeComprobante);  AgregaDato(MetodoPago);
    AgregaDato(CondicionesDePago);
    AgregaDato(LugarExpedicion);

		with Emisor do
		begin
			AgregaDato(Rfc); AgregaDato(Nombre); AgregaDato(RegimenFiscal);
		end; {with CFD.Emisor}

		with Receptor do
		begin
      AgregaDato(Rfc);
      AgregaDato(Nombre);
      AgregaDato(UsoCFDI);

		end; {with CFD.Receptor}

		with Conceptos do
		for n := 0 to ChildNodes.Count-1 do
		if ChildNodes[n].NodeType = ntElement then
		begin
			AgregaDato(Concepto[n].ClaveProdServ);
      AgregaDato(Concepto[n].NoIdentificacion);
      AgregaDato(Concepto[n].Cantidad);
      AgregaDato(Concepto[n].ClaveUnidad);
      AgregaDato(Concepto[n].Unidad);
      AgregaDato(Concepto[n].Descripcion);
      AgregaDato(Concepto[n].ValorUnitario);
      AgregaDato(Concepto[n].Importe);
      AgregaDato(Concepto[n].Descuento);

			for n1 := 0 to Concepto[n].ChildNodes.Count-1 do
			begin
         if Concepto[n].ChildNodes[n1].NodeName = 'cfdi:InformacionAduanera' then
 	  		 begin
  					AgregaDato(Concepto[n].InformacionAduanera.Items[0].NumeroPedimento);
				 end;
				 if Concepto[n].ChildNodes[n1].NodeName = 'CuentaPredial' then
				 begin
				  	AgregaDato(Concepto[n].CuentaPredial[0].Numero);
				 end;

         if Concepto[n].ChildNodes[n1].NodeName = 'Impuestos' then
         begin


            with Concepto[n].Impuestos.Traslados do
	       		for n2:= 0 to ChildNodes.Count-1 do
      			if ChildNodes[n2].NodeType = ntElement then
			      begin
      				AgregaDato(Concepto[n].Impuestos.Traslados[n2].Base);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].Impuesto);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].TipoFactor);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].TasaOCuota);
              AgregaDato(Concepto[n].Impuestos.Traslados[n2].Importe);
      			end; {with CFD.Impuestos.Traslados}

            //AgregaDato ('Dentro de impuesto');

             {
             AgregaDato(Concepto[n].Impuestos.TrasladosCon.TrasladoCon[n1].Base);
             AgregaDato(Concepto[n].Impuestos.TrasladosCon.TrasladoCon[n1].Impuesto);
             AgregaDato(Concepto[n].Impuestos.TrasladosCon.TrasladoCon[n1].TipoFactor);
             AgregaDato(Concepto[n].Impuestos.TrasladosCon.TrasladoCon[n1].TasaOCuota);
             AgregaDato(Concepto[n].Impuestos.TrasladosCon.TrasladoCon[n1].Importe);
             }
             {
             try
               begin
                   AgregaDato(Concepto[n].Impuestos.RetencionesCon.RetencionCon[0].Base);
                   AgregaDato(Concepto[n].Impuestos.RetencionesCon.RetencionCon[0].Impuesto);
                   AgregaDato(Concepto[n].Impuestos.RetencionesCon.RetencionCon[0].TipoFactor);
                   AgregaDato(Concepto[n].Impuestos.RetencionesCon.RetencionCon[0].TasaOCuota);
                   AgregaDato(Concepto[n].Impuestos.RetencionesCon.RetencionCon[0].Importe);
               end;
             except on e : exception do
               begin
                  jo := 1;
               end;
             end;
             }

         end;

			end;
		end; {with CFD.Conceptos}

		with Impuestos do
		begin
			with Retenciones do
			for n:= 0 to ChildNodes.Count-1 do
			if ChildNodes[n].NodeType = ntElement then
			begin
				AgregaDato(Retencion[n].Impuesto); AgregaDato(Retencion[n].Importe);
			end; {with CFD.Impuestos.Retenciones}
			AgregaDato(TotalImpuestosRetenidos);

			with Traslados do
			for n:= 0 to ChildNodes.Count-1 do
			if ChildNodes[n].NodeType = ntElement then
			begin
				AgregaDato(Traslados[n].Impuesto); AgregaDato(Traslados[n].TipoFactor); AgregaDato(Traslados[n].TasaOCuota);
        AgregaDato(Traslados[n].Importe);
			end; {with CFD.Impuestos.Traslados}

			AgregaDato(TotalImpuestosTrasladados);
		end; {with CFD.Impuestos}

		AgregaDato(pipe);
	end; {with CFD}


	gCadenaOriginal := RemplazaCad(' ',#8,gCadenaOriginal);        //Regla 5.a
	gCadenaOriginal := RemplazaCad(' ',#10,gCadenaOriginal);       //Regla 5.a
	gCadenaOriginal := RemplazaCad(' ',#13,gCadenaOriginal);       //Regla 5.a
	gCadenaOriginal := RemplazaCad(pipe,' '+pipe,gCadenaOriginal); //Regla 5.b
	gCadenaOriginal := RemplazaCad(pipe,pipe+' ',gCadenaOriginal); //Regla 5.b
	gCadenaOriginal := RemplazaCad(' ','  ',gCadenaOriginal);      //Regla 5.c

end;

function TFacturaEFormV40.ProcesaFactura(CadenaXML:String; Var Error:String ):WideString;
Var XmlCfdi,XmlCfdiCopy : TXMLDocument;
    CfdiVe : IXMLComprobante;
    ContReg,n,DoctoInDetId,TicketId : Integer;
    TotalImptoT,TotalImptoR : Double;
    Incremento:Integer;
    cadCertificado:String;

    ValPrctjImpto:Double;
    BaseImptoDet:Double;
    TieneImpt:String;
    CodPostaLugarExp:String;
    BaseTot, ImporteImtoTot:Double;
begin
try
 begin

  TieneImpt := 'N';
  //Exception.Create('inicia la funcion');
  XmlCfdi := TXMLDocument.Create(nil);
  XmlCfdi.XML.Text := CadenaXML;
	XmlCfdi.Active := True;
	CfdiVe := GetComprobante(XmlCfdi);

  With CfdiVe do
	Begin
    {$REGION 'Atributos comprobante'}
    //TIPO_CAMBIO
    Sello := '';
    NoCertificado := gNoCertificado;
    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xA;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#x0D;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, '&#xD;', '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #13, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #10, '', [rfReplaceAll, rfIgnoreCase]);
    gCertificado:=StringReplace(gCertificado, #8, '', [rfReplaceAll, rfIgnoreCase]);

    Certificado := gCertificado;
    SetAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
    SetAttribute('xsi:schemaLocation','http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd');
    {$ENDREGION}
  End;
  XmlCfdiCopy := TXMLDocument.Create(nil);
  XmlCfdiCopy.XML := XmlCfdi.XML;
  GeneraCadenaOriginalCFDI40(XmlCfdiCopy);

  CfdiVe.Sello := SellaFactura(gCertVerif,gCadenaOriginal);
  XmlCfdi.Active := True;

  Result := XmlCfdi.XML.Text;

  Error := '';
  XmlCfdi.SaveToFile('C:\1.XML');
  end
except on e : exception do
 begin
   //Error := gCadenaOriginal+' - '+Error+#13+e.Message;
   Error := e.Message;
   XmlCfdi.XML.Text := '';
   Result := '';
 end;
end;
end;

function TFacturaEFormV40.ValidarImporte(IdTicket:Integer;TipoDoc:String;TotalPagar:Double):String;
var ImtoTotal:Double;
begin
  {$region 'Ventas mostrador'}
  if (TipoDoc = 'VM') then
  begin
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT B.TOTAL_A_PAGAR ');
    IBQuery.SelectSQL.Add('FROM CALC_TOTALES_DOCTO_PV( :DOCTO_PV_ID , ''S'', ''N'', 0 ) B  ');
    IBQuery.ParamByName('DOCTO_PV_ID').AsInteger := IdTicket;
    IBQuery.Open;
    ImtoTotal := IBQuery.FieldByName('TOTAL_A_PAGAR').Asfloat;
  end;
  {$endregion}

  {$region 'Remisiones, Pedidos'}
  if ((TipoDoc = 'RE') or (TipoDoc = 'PE')) then
  begin
    IBQuery.Close;
    IBQuery.SelectSQL.Clear;
    IBQuery.SelectSQL.Add('SELECT A.TOTAL_A_PAGAR FROM CALC_TOTALES_DOCTO_VE(:DOCTO_VE_ID , ''S'') A  ');
    IBQuery.ParamByName('DOCTO_VE_ID').AsInteger := IdTicket;
    IBQuery.Open;
    ImtoTotal := IBQuery.FieldByName('TOTAL_A_PAGAR').Asfloat;
  end;
  {$endregion}

  if ImtoTotal <> TotalPagar then
    Result:= 'Error'
  else
    Result:= '';
end;

function TFacturaEFormV40.ValidarSucursales(SistemaOrigen, SistemaOrigen1, FolDoc:String; var ClientePublicoId:Integer; var Error:String):String;
var ValidaSucursales, SerieFolio, FolioL:String;
begin
      ValidaSucursales := '';
      ValidaSucursales := GetPrefer('FacturarPorSucursal');

      FolioL := ''; ClientePublicoId := 0;
      if ValidaSucursales = 'S' then
      begin
          SerieFolio := '';
          FolioL := Rellena(FolDoc, SerieFolio);

          if SistemaOrigen = 'VM' then
          begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT FIRST 1 CLIENTE_ID, SERIE_FAC, CLAVE_SUCURSAL ');
            IBQuery.SelectSQL.Add('FROM MGFACTURA_SUCRUSALES_CONFIG ');
            IBQuery.SelectSQL.Add('WHERE SERIE_VM = :SERIE_VM ');
            IBQuery.ParamByName('SERIE_VM').AsString := Trim(SerieFolio);
            IBQuery.Open;
          end;

          if (SistemaOrigen = 'RE') or (SistemaOrigen = 'PE') then
          begin
            IBQuery.Close;
            IBQuery.SelectSQL.Clear;
            IBQuery.SelectSQL.Add('SELECT FIRST 1 CLIENTE_ID, SERIE_FAC, CLAVE_SUCURSAL ');
            IBQuery.SelectSQL.Add('FROM MGFACTURA_SUCRUSALES_CONFIG ');
            IBQuery.SelectSQL.Add('WHERE SERIE_VE = :SERIE_VE ');
            IBQuery.ParamByName('SERIE_VE').AsString := Trim(SerieFolio);
            IBQuery.Open;
          end;

          ClientePublicoId := IBQuery.FieldByName('CLIENTE_ID').AsInteger;
          FolioL := IBQuery.FieldByName('SERIE_FAC').AsString;

          if ClientePublicoId = 0  then
          begin
             Error := 'El folio no pertenece a ninguna sucursal configurada. Póngase en contacto con el administrador del sitio.';
          end;

          if FolioL = '' then
            Error := 'No se ha configurado la serie de facturación para la sucursal '+IBQuery.FieldByName('CLAVE_SUCURSAL').AsString+'.';

      end else
      begin
          if SistemaOrigen = 'VM' then
          begin
            IBQuery.Close;
            IBQuery.SelectSql.Clear;
            IBQuery.selectSql.Add('SELECT A.VALOR ');
            IBQuery.selectSql.Add('FROM REGISTRY A ');
            IBQuery.selectSql.Add('WHERE A.NOMBRE = ''CLIENTE_EVENTUAL_PV_ID'' ');
            IBQuery.Open;
          end;

          if (SistemaOrigen = 'RE') or (SistemaOrigen = 'PE') then
          begin
            IBQuery.Close;
            IBQuery.SelectSql.Clear;
            IBQuery.selectSql.Add('SELECT A.VALOR ');
            IBQuery.selectSql.Add('FROM REGISTRY A ');
            IBQuery.selectSql.Add('WHERE A.NOMBRE = ''CLIENTE_EVENTUAL_ID'' ');
            IBQuery.Open;
          end;

          ClientePublicoId := IBQuery.FieldByName('VALOR').asinteger;
          FolioL := GetPrefer('Serie');

          if ClientePublicoId = 0  then
          begin
             Error := 'No se ha configurado el cliente eventual en preferencias de la empresa.';
          end;

          if FolioL = '' then
            Error := 'No se ha configurado la serie de facturación en parámetros generales.';
    end;

          if (SistemaOrigen1='VM') and ((SistemaOrigen = 'RE') or (SistemaOrigen = 'PE')) then
            Error := 'El folio del documento indicado no corresponde a un documento origen valido.';

          if (SistemaOrigen1='PE') and ((SistemaOrigen = 'VM') or (SistemaOrigen = 'RE')) then
            Error := 'El folio del documento indicado no corresponde a un documento origen valido.';

         if (SistemaOrigen1='RE') and ((SistemaOrigen = 'VM') or (SistemaOrigen = 'PE')) then
            Error := 'El folio del documento indicado no corresponde a un documento origen valido.';

         if (SistemaOrigen1='VMPE') and (SistemaOrigen = 'RE') then
            Error := 'El folio del documento indicado no corresponde a un documento origen valido.';

         if (SistemaOrigen1='VMRE') and (SistemaOrigen = 'PE') then
            Error := 'El folio del documento indicado no corresponde a un documento origen valido.';

    Result := FolioL;
end;

procedure TFacturaEFormV40.ObtenerDatosFact40Pago();
var NodoListXML,NodoListOrigXML,NodoList,NodoListTimbre: IXMLNodeList;
AtribList: IXMLNodeList;
AtributoNombre,AtributoValor : String;
i,n : Integer;
begin
   xmlTimbre.Active := True;

   NodoListOrigXML:= xmlTimbre.ChildNodes;

   For i := 0 to NodoListOrigXML.Count - 1 do
   begin
    if (NodoListOrigXML.Nodes[i].NodeName = 'cfdi:Comprobante') then
    begin
    {$REGION 'CFDI'}
         xmlTimbre.Active := True;

         XMLfac.XML.Text := xmlTimbre.XML.Text;
         xmlFacCopy.XML.Text := xmlTimbre.XML.Text;
         GeneraCadenaOriginalCFDI40(xmlTimbre);

         XMLfac.XML.Text := xmlFacCopy.XML.Text;

         XMLfac.Active := True;

         CFDI40 := GetComprobante(XMLfac);
         gCERTIFICADO := '';

         with CFDI40 do
         begin
             gSelloDigital := CFDI40.Sello;
             gCERTIFICADO := trim(CFDI40.Certificado);
             gNoCertificado := Trim(CFDI40.NoCertificado);
             gFECHAXML := CFDI40.Fecha;
           with CFDI40.Emisor do
           begin
            with CFDI40.Emisor.AttributeNodes do
             begin
               gRfcEmisor := CFDI40.Emisor.Attributes['Rfc'];
             end;
           end;

           with CFDI40.Receptor do
           begin
             with CFDI40.Receptor.AttributeNodes do
             begin
               gRfcReceptor := CFDI40.Receptor.Attributes['Rfc'];
             end;
           end;

            try
             begin
                with CFDI40.Complemento do
                begin

                  for n := 0 to Complemento.ChildNodes.Count - 1  do
               		begin
                  if Complemento.ChildNodes[n].NodeName = 'tfd:TimbreFiscalDigital' then
          				begin
                   gCadenaOriginalTimbre := '';
                   gUUID := Complemento.ChildNodes[n].Attributes['UUID'];
                   gSelloSAT := Complemento.ChildNodes[n].Attributes['selloSAT'];
                   gCertificadoSAT := Complemento.ChildNodes[n].Attributes['noCertificadoSAT'];
                   gFechaTimbrado := Complemento.ChildNodes[n].Attributes['FechaTimbrado'];
                   gSelloCFD := Complemento.ChildNodes[n].Attributes['selloCFD'];

                   gCadenaOriginalTimbre := '||';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['version']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['UUID']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['FechaTimbrado']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['selloCFD']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['noCertificadoSAT']+'||';
                  end;
                  end;

                end;
             end;
           except
             begin
                with CFDI40.Complemento do
                begin
                  for n := 0 to Complemento.ChildNodes.Count - 1  do
               		begin
                  if Complemento.ChildNodes[n].NodeName = 'tfd:TimbreFiscalDigital' then
          				begin
                   gCadenaOriginalTimbre := '';
                   gUUID := Complemento.ChildNodes[n].Attributes['UUID'];
                   gSelloSAT := Complemento.ChildNodes[n].Attributes['SelloSAT'];
                   gCertificadoSAT := Complemento.ChildNodes[n].Attributes['NoCertificadoSAT'];
                   gFechaTimbrado := Complemento.ChildNodes[n].Attributes['FechaTimbrado'];
                   gSelloCFD := Complemento.ChildNodes[n].Attributes['SelloCFD'];

                   gCadenaOriginalTimbre := '||';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['Version']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['UUID']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['FechaTimbrado']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['SelloCFD']+'|';
                   gCadenaOriginalTimbre := gCadenaOriginalTimbre+
                                       Complemento.ChildNodes[n].Attributes['NoCertificadoSAT']+'||';
                  end;
                  end;

                end;
             end;
           end;



          // raise exception.Create('Antes de leer complemento1');

         end;
         gAnoAprob := '';
         gNOAPROBACION := '';

         {$ENDREGION}
    end;



   end;

  //  Raise Exception.Create('gUUID:'+gUUID+' gRfcEmisor:'+gRfcEmisor);
end;

function TFacturaEFormV40.InsertRFCS_LCO(RFC, NOMBRE_FISCAL, DOMICILIO_FISCAL:String; Var Error:String ):Boolean;
begin
 try
  begin

   Error := '';
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.RFC_LCO_ID FROM RFCS_LCO A WHERE A.RFC = :RFC ');
   IBQuery.ParamByName('RFC').AsString := RFC;
   IBQuery.Open;

   if IBQuery.FieldByName('RFC_LCO_ID').AsInteger=0 then
   begin
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('INSERT INTO RFCS_LCO (RFC_LCO_ID, RFC, NOMBRE_FISCAL, DOMICILIO_FISCAL, ESTATUS_VERIFICACION) ');
   IBQuery.SelectSQL.Add('VALUES (-1, :RFC, :NOMBRE_FISCAL, :DOMICILIO_FISCAL, ''T''); ');
   IBQuery.ParamByName('RFC').AsString := RFC;
   IBQuery.ParamByName('NOMBRE_FISCAL').AsString := NOMBRE_FISCAL;
   IBQuery.ParamByName('DOMICILIO_FISCAL').AsString := DOMICILIO_FISCAL;
   IBQuery.Open;
   end;

   Result:=True;
  end
  except on e:Exception do
  begin
    Error := 'Error al guardar RFC.  Error:'+e.Message;
    Result:=False;
  end;
 end;
end;

function TFacturaEFormV40.UpdateDIRS_CLIENTES(DIR_CLI_ID:Integer; TIPO_PERSONA, CLAVE_REGIMEN_FISCAL:String; Var Error:String ):Boolean;
begin
 try
  begin

   Error := '';

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('SELECT A.TIPO_PERSONA, A.CLAVE_REGIMEN_FISCAL FROM DIRS_CLIENTES A WHERE A.DIR_CLI_ID = :DIR_CLI_ID ');
   IBQuery.ParamByName('DIR_CLI_ID').AsInteger := DIR_CLI_ID;
   IBQuery.Open;

   if ((IBQuery.FieldByName('TIPO_PERSONA').AsString='') or (IBQuery.FieldByName('TIPO_PERSONA').AsString='')) then
   begin
   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('UPDATE DIRS_CLIENTES SET TIPO_PERSONA = :TIPO_PERSONA, CLAVE_REGIMEN_FISCAL = :CLAVE_REGIMEN_FISCAL WHERE (DIR_CLI_ID = :DIR_CLI_ID); ');
   IBQuery.ParamByName('TIPO_PERSONA').AsString := TIPO_PERSONA;
   IBQuery.ParamByName('CLAVE_REGIMEN_FISCAL').AsString := CLAVE_REGIMEN_FISCAL;
   IBQuery.ParamByName('DIR_CLI_ID').AsInteger := DIR_CLI_ID;
   IBQuery.Open;
   end;

   Result:=True;
  end
  except on e:Exception do
  begin
    Error := 'Error al actualizar datos fiscales del cliente.  Error:'+e.Message;
    Result:=False;
  end;
 end;
end;



initialization


SetLicenseKey('9F9E1396AE7F6332436EE0F25CAE2331F908FF2D3971253C694E193700D72101' +
'788FFB37BE9AED96D0F0B4F0A2D24A2C89DB92B7CD42F059B2B597747AB74FCD' +
'93E1D93FB8421C189BF362658820501B64A4DC8DBD6D59B72063C6170B975A5A' +
'1CCB55152541D1C4669F14978334BEABF75087981A202E9C61B0F82124C5D38D' +
'BC1BDCE243E34CC6EBC5C6A6E94248E45EC4797AB3EC71D47E481EBF9126F9C0' +
'B6872B77AD000591301E49F09C8B7E9FFF634665854891E37A236AC866DB066A' +
'95C03E0AC1D5CE04BD12BDEE5B2D62897B5C4F449CBEB6E331AB10D037B5DD74' +
'11A78A5E182C04E7844C78B1E5F83E899A4802F722FE99C34CDA6214CA0A9AA7');

end.
