unit uDataModule;

interface

uses
  FIBDatabase, pFIBDatabase,
  FIBDataSet, pFIBDataSet, AES, BASE64,  FIBQuery,
  pFIBQuery, pFIBStoredProc, CHILKATMAILLib2_TLB,
  SBTypes, SBCustomCertStorage, SBEncoding, SBPublicKeyCrypto, SBConstants, SBX509,
  SBUtils, SBCryptoProv, TimbrarCD, SBSocket, SBSimpleSSL,
  SBHTTPSClient, SBCertValidator,  IdBaseComponent, IdCoder,
  IdCoder3to4, IdCoderMIME, frxClass,

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, StrUtils, DateUtils, xmldom, XMLIntf, msxmldom,
  XMLDoc, DB,
  ZAbstractRODataset, ZAbstractDataset, ZDataset, ZSequence, ZSqlMonitor,
  ZConnection,  ZSqlUpdate;
type
  TfrmDataModule = class(TDataModule)
    IBDatabase1: TpFIBDatabase;
    xmlWebservice: TXMLDocument;
    IBQuery: TpFIBDataSet;
    trTrans: TpFIBTransaction;
    IBQuery2: TpFIBDataSet;
    spPrecioImpto: TpFIBStoredProc;
    IBQuery4: TpFIBDataSet;
    IBQuery3: TpFIBDataSet;
    spGenCatId: TpFIBStoredProc;
    dsDoctoFte: TpFIBDataSet;
    spGenDoctoId: TpFIBStoredProc;
    spCopiaFteDestPV: TpFIBStoredProc;
    spCalcTotalesPV: TpFIBStoredProc;
    dsEmpresa: TpFIBDataSet;
    dsDoctoPv33: TpFIBDataSet;
    dsDoctoPvDet33: TpFIBDataSet;
    dsFormasCobroCC33: TpFIBDataSet;
    dsDatosAlmacen33: TpFIBDataSet;
    dsPedimentosPv: TpFIBDataSet;
    xmlFac: TXMLDocument;
    xmlFacCopy: TXMLDocument;
    HTTPSClient: TElHTTPSClient;
    CertificateValidator: TElX509CertificateValidator;
    xmlTimbre: TXMLDocument;
    IdEncoderMIME1: TIdEncoderMIME;
    procedure HTTPSClientCertificateValidate(Sender: TObject;
      Certificate: TElX509Certificate; var Validity: TSBCertificateValidity;
      var Reason: TSBCertificateValidityReason);
    procedure HTTPSClientData(Sender: TObject; Buffer: Pointer; Size: Integer);
  private
    { Private declarations }
  public
    FConnection: TZConnection;
    FDataset: TZQuery;
    FUpdateSQL: TZUpdateSQL;

    const   CLAVE = 'MICROSIP4856';
    CLAVE_PRODUCTO = '04';
    NOMBRE_PRODUCTO = 'Facturación en línea';
    { Public declarations }
    var gVERCFDI:String;
    gPathCertificado,gPathLlave,gContrasena,gTipoFacturacion : String;
    gUsuarioTimbre,gPassTimbre,gUrlTimbre,gCertificado,gNoCertificado,
    gCadenaOriginal,gFechaXml,gRfcEmisor,gRfcReceptor,gSelloDigital,
    gCadenaOriginalTimbre,gUUID,gSelloSat,gCertificadoSAT,gFechaTimbrado,
    gSelloCFD,gAnoAprob,gNoAprobacion:String;
    gCertVerif : TElX509Certificate;
    gXML33:{$ifndef SB_UNICODE_VCL}string{$else}AnsiString{$endif};

    //Propiedades para conexion a amazon
    property Connection: TZConnection read FConnection write FConnection;
    property Dataset: TZQuery read FDataset write FDataset;
    property UpdateSQL: TZUpdateSQL read FUpdateSQL write FUpdateSQL;

    function Conexion(StringConexion:String; Var Error:String):Boolean;
    function LeerParams(Parametro:String; NoParam:Integer):String;
    function descifrarTexto(Str : String): String;
    function ValidaCadena(Cadena:String):String;
    function GetPrefer(Nombre:String):String;
    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 ValidarRFC(RFC:String):String;
    function ContieneNumeros(Cadena:String):Boolean;
    function cifrarTexto(Str : String) : String;
    function Rellena(cadena:String; Var SerieVnta:String):string;
    function ValidacionesTicket(Folio, SistemaOrigen :String; Var Error:String; var FolDoc, TipoDoc, OCompra:String ):Integer;
    function AgregaConsig(ConsigId,ClienteId:Integer; Var Error:String ):Integer;
    function GetDoctoId():Integer;
    function ValidarDatosCliente(ConsigId:Integer):String;
    procedure GetDatosFac();
    function AbrirSellos(PathCert,PathKey,Password:String; Var Error: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 CopiarDetallePv(DoctoOrigen,DoctoDest:Integer; ModifEncab : String; Var Error:String):Boolean;
    function FormasCobroPV(IdTicket,DoctoPvId:Integer; Var Error:String):Boolean;
    function AplicaDoctoPv(DoctoPvId:Integer; SoloLectura,ImptoIncluido:String; Var Error:String):Boolean;
    function SellaFactura(Cert:TElX509Certificate; CadOriginal:WideString):String;
    function InsertFacturaElectronica(DoctoVeId:Integer; xmlFactura:TXMLDocument; Modulo:String; Var Error:String ):Boolean;

    function CodigosError(Codigo:String):String;

    function NumLet(mNum: Currency; iIdioma, iModo: Smallint):string;

    function GeneraPDF(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;
    function CodificaPDF(PdfPath:String):widestring;
    function GeneraPDFEmail(Folio,TotalLetra,Modulo,TipoFact:String; TotalPagar:Double; IdDocto:Integer):String;

    procedure ConectarBDAWS();
    function ValidacionesGenerales(ClaveLic,Cliente:String; var lError:String):Boolean;
    function ValidarSucursales(SistemaOrigen, SistemaOrigen1, FolDoc:String; var ClientePublicoId:Integer; var Error:String):String;
    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
  frmDataModule: TfrmDataModule;

implementation

{%CLASSGROUP 'System.Classes.TPersistent'}

{$R *.dfm}

Uses
FormUnit1, Sello, Utils;

function TfrmDataModule.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]);


  //BaseDatos := StringReplace(LeerParams(StringConexion,3),'-','\',[rfReplaceAll, rfIgnoreCase]);

  {
  try
    Pass := descifrarTexto(Pass);
  except
    Raise Exception.Create('Contraseña incorrecta (desencriptar).'+'    '+'Pass: '+Pass);
  end;
   }
  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 TfrmDataModule.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 TfrmDataModule.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 TfrmDataModule.ValidaCadena(Cadena:String):String;
Var NuevaCadena:String;
begin
  // aun no, hay que documentar acerca de lo del rfc.
  result := '';
  Cadena := AnsiUpperCase(Cadena);
  NuevaCadena := StringReplace(Cadena,'-','',[rfReplaceAll, rfIgnoreCase]);
  NuevaCadena := StringReplace(NuevaCadena,' ','',[rfReplaceAll, rfIgnoreCase]);

  Result := NuevaCadena;
end;

function TfrmDataModule.GetPrefer(Nombre:String):String;
Var Valor,Consulta:String;
begin
  {
if (Nombre = 'ConfigOK') then
begin
   Raise Exception.Create('inicio de preferencias.');
end;
   }
  if (Nombre = 'AsuntoMail') or (Nombre = 'MensajeMail') or (Nombre = 'AsuntoMailPass') or (Nombre = 'MensajeMailPass') 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); // DescifrarTexto(TRIM(IBQuery.FieldByName('VALOR').AsString));
  end else
      Valor := '';

  Result := Valor;

end;

procedure TfrmDataModule.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);
    Validate := Validity = cvOk;
  end
end;

procedure TfrmDataModule.HTTPSClientData(Sender: TObject; Buffer: Pointer;
  Size: Integer);
  var S : {$ifndef SB_UNICODE_VCL}string{$else}AnsiString{$endif};
begin
  SetLength(S, Size);
  Move(Buffer^, S[1], Size);
  gXML33 := gXML33 + S;
end;

function TfrmDataModule.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;
  Result := NuevaCad;
end;

function TfrmDataModule.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 la factura PDF.';
       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 la factura 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;
      exit;
   end
   ELSE
   begin
      Result := True;
   end;


   FreeAndNil(mailman);

   Result := True;

end;

function TfrmDataModule.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 := '';
  {
   AAAA999999XXX fisicas y
   AAA999999XXX  morales
   FOVF620925F1
   }

  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;

 { AnoActual := FormatDateTime('YYYY',FechaActual);
  nAnoActual := StrToInt(Copy(AnoActual,3,2));
  if nAno > nAnoActual  then
      Ano := '19'+Ano
  else
      Ano := '20'+Ano;}

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

  Fecha := Dia+'/'+Mes+'/'+Ano;
  //Fecha := '29/02/2013';
  {
  try
    dFecha := StrToDate(Fecha);
  except
   begin
     Result := 'El rfc no es válido, la estructura no es válida.'+Fecha;
     Exit;
   end
  end;
  }

  Result := '';


end;

function TfrmDataModule.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;

function TfrmDataModule.cifrarTexto(Str : String) : String;
var
  Src: TStringStream;
  Dst: TMemoryStream;
  Size: Integer;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
begin
  Result:= EmptyStr;
  Src:= TStringStream.Create(Str);
  try
    Dst:= TMemoryStream.Create;
    try
      // Preparamos la clave, lo ideal es que tenga 32 caracteres
      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);
      // Guardamos el tamaño del texto original
      Size:= Src.Size;
      Dst.WriteBuffer(Size,Sizeof(Size));
      // Ciframos el texto
      AESEncryptStreamECB(Src,Dst,ExpandedKey);
      // Lo codificamos a base64
      Result:= BinToStr(Dst.Memory,Dst.Size);
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;
 {
function TfrmDataModule.Rellena(cadena: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';

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 TfrmDataModule.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 TfrmDataModule.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, FolioR :String;
EnTiempo,MismoMes :Boolean;
SerieFol, sis_ori, TipoDocto:String;
begin

try
 begin
      FolioDev := '';
      FolioFac := '';
      TicketId := 0;
      Estatus := '';
      SerieFol := '';
      FolioR := Rellena(Folio, SerieFol);
      SoloFacMesVM := '';
      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 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
            sis_ori := 'venta mostrador';
            if TicketId = 0 then
                 Raise Exception.Create('El ticket '+sis_ori+ ' '+FolioR+' no existe.');
            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') or (TipoDocto = 'PE')) then
      begin
        if (TipoDocto = 'RE')  then
          sis_ori := 'remisión';
        if (TipoDocto = 'PE')  then
          sis_ori := 'pedido';
        
          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 '+sis_ori+ ' '+FolioR+' no existe.');
            {if TipoDoctoVE = 'R' then
                 Raise Exception.Create('El ticket '+Folio+' 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}

      Result := TicketId;

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

end;

function TfrmDataModule.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;
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 ');
  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;

  if NombreConsig = 'Dirección principal' 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 A.NOMBRE_CONSIG = :NOMBRE_CONSIG AND A.RFC_CURP = :RFC ');
    IBQuery2.SelectSQL.Add('AND A.CLIENTE_ID = :CLIENTE_ID ');
    IBQuery2.ParamByName('NOMBRE_CONSIG').AsString := NombreConsig;
    IBQuery2.ParamByName('RFC').AsString := Rfc;
    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) 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 ); ');
      DirCliId := GetDoctoId();
      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;
      IBQuery2.ParamByName('CIUDAD_ID').AsInteger := CiudadId;
      IBQuery2.ParamByName('ESTADO_ID').AsInteger := EstadoId;
      IBQuery2.ParamByName('CODIGO_POSTAL').AsString := CodPostal;
      IBQuery2.ParamByName('PAIS_ID').AsInteger := PaisId;
      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.Open;
      Result := DirCliId;
      Error := '';
    end else
    begin
      //Error := 'El consignatario ya existe.';
      DirCliId := IBQuery2.FieldByName('DIR_CLI_ID').AsInteger;
      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 TfrmDataModule.GetDoctoId():Integer;
begin
  spGenDoctoId.ExecProc;
  Result := spGenDoctoId.FieldByName('DOCTO_ID').AsInteger;
end;

function TfrmDataModule.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,A.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 ');
  IBQuery.SelectSQL.Add('FROM DIRS_CLIENTES A ');
  IBQuery.SelectSQL.Add('INNER JOIN CIUDADES B ON ( B.CIUDAD_ID = A.CIUDAD_ID ) ');
  IBQuery.SelectSQL.Add('INNER JOIN ESTADOS C ON ( A.ESTADO_ID = C.ESTADO_ID ) ');
  IBQuery.SelectSQL.Add('INNER JOIN PAISES D ON ( D.PAIS_ID = A.PAIS_ID ) ');
  IBQuery.SelectSQL.Add('WHERE A.DIR_CLI_ID = :DIR_CLI_ID ');
  IBQuery.ParamByName('DIR_CLI_ID').AsInteger := ConsigId;
  IBQuery.Open;
  }
  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 ');
  IBQuery.SelectSQL.Add('    FROM DIRS_CLIENTES A ');
  IBQuery.SelectSQL.Add('    INNER JOIN CIUDADES B ON ( A.CIUDAD_ID = B.CIUDAD_ID ) ');
  IBQuery.SelectSQL.Add('    INNER JOIN ESTADOS C ON ( B.ESTADO_ID = C.ESTADO_ID ) ');
  IBQuery.SelectSQL.Add('    INNER 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) );

  { // Cambio noviembre: se comento la siguiente informacion puesto que no es requerida para crear la factura
  if Length(Trim(IBQuery.FieldByName('NOMBRE_CALLE').AsString)) = 0 then
    Raise Exception.Create('Indique la calle en la dirección del cliente para la factura.');

  if Length(Trim(IBQuery.FieldByName('NUM_EXTERIOR').AsString)) = 0 then
    Raise Exception.Create('Indique el número exterior en la dirección del cliente para la factura.');

  if Length(Trim(IBQuery.FieldByName('COLONIA').AsString)) = 0 then
    Raise Exception.Create('Indique la colonia en la dirección del cliente para la factura.');
   }
  {$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
      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));

  {// Cambio noviembre: se comento la siguiente informacion puesto que no es requerida para crear la factura
  if Length(Trim(IBQuery.FieldByName('CIUDAD').AsString)) = 0 then
    Raise Exception.Create('Indique la ciudad en la dirección del cliente para la factura.');

  if Length(Trim(IBQuery.FieldByName('ESTADO').AsString)) = 0 then
    Raise Exception.Create('Indique el estado en la dirección del cliente para la factura.');

  if Length(Trim(IBQuery.FieldByName('PAIS').AsString)) = 0 then
    Raise Exception.Create('Indique el país en la dirección del cliente para la factura.');

  if Length(Trim(IBQuery.FieldByName('CODIGO_POSTAL').AsString)) = 0 then
    Raise Exception.Create('Indique el código postal en la dirección del cliente para la factura.');
  }
  Result := '';

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

end;

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

  gPathCertificado := GetPrefer('PathCert');
  gPathLlave := GetPrefer('PathLlave');
  gContrasena := '12345678a'; //GetPrefer('PassLlave');
  gUrlTimbre := GetPrefer('DirTimbre');
  gUsuarioTimbre := GetPrefer('UsuarioTimbre');
  gPassTimbre := 'PWD'; //GetPrefer('PassTimbre');
  //AbrirSellos(dm.gPathCertificado,dm.gPathLlave,dm.gContrasena,Error)
end;

function TfrmDataModule.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) : '+gNoCertificado; exit; end;
  {$ENDREGION}

{$ENDREGION}

end;

function TfrmDataModule.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'', '''', :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';
   IBQuery.ParamByName('SUCURSAL_ID').AsInteger := SUCURSAL_ID;
   IBQuery.Open;  //

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

end;

function TfrmDataModule.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'' ');
  IBQuery3.ParamByName('SERIE').AsString := Serie;
  IBQuery3.ParamByName('TIPO_DOCTO').AsString := TipoDocto;
  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 TfrmDataModule.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 TfrmDataModule.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 TfrmDataModule.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
   begin
     Error := 'Al aplicar el documento.';
     Result := False;
   end;
  end;
end;

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

  signer := TElRSAPublicKeyCrypto.Create(SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION); //SB_CERT_ALGORITHM_SHA1_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;

function TfrmDataModule.InsertFacturaElectronica(DoctoVeId:Integer; xmlFactura:TXMLDocument; Modulo:String; Var Error:String ):Boolean;
var CFDI_ID:Integer;
    xmlTexto : WideString;
begin
 try
  begin

   CFDI_ID := 0;
   Error := '';

   xmlFactura.Active := True;

   IBQuery.Close;
   IBQuery.SelectSQL.Clear;
   IBQuery.SelectSQL.Add('UPDATE USOS_FOLIOS_FISCALES SET XML = :XML , CFDI_ID = :CFDI_ID ');
   IBQuery.SelectSQL.Add('WHERE (DOCTO_ID = :DOCTO_ID) AND (SISTEMA = :SISTEMA); ');
   IBQuery.ParamByName('DOCTO_ID').AsInteger := DoctoVeId;
   IBQuery.ParamByName('SISTEMA').AsString := Modulo;
   IBQuery.ParamByName('CFDI_ID').Clear;  //SE AGREGO EL CAMPO CFDI_ID QUE REGRESA LA FUNCION InsertaRepositorio LA CUAL GENERA EL ADD EN EL TIMBRADO --> JOSUE SANTIAGO MARTINEZ
   IBQuery.ParamByName('XML').AsString := xmlFactura.XML.Text;
   IBQuery.Open;

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

function TfrmDataModule.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;

function TfrmDataModule.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 TfrmDataModule.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;
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;

  //Qrcode := PathGen+'\QRCODE'+Folio+'.BMP';

  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;


  fmPrincipal.frxReport1.LoadFromStream(ReportStream);
  if TipoFact = 'CFDI' then
  begin
    str_qrcode := '?re='+  gRfcEmisor + '&rr=' + gRfcReceptor + '&tt=' + FormatFloat( '#.000000' , TotalPagar) + '&id=' + gUUID;
    Qrcode := str_qrcode;
  end;

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

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

  if TipoFact = 'CFD' then
  begin
    fmPrincipal.frxReport1.Variables['ANO_APROBACION'] := ''''+gANOAPROB+'''';
    fmPrincipal.frxReport1.Variables['NO_APROBACION'] := ''''+gnoaprobacion+'''';
    Caracter := '''';
    gCadenaOriginal := StringReplace(gCadenaOriginal,Caracter,'',[rfReplaceAll, rfIgnoreCase]);;
    fmPrincipal.frxReport1.Variables['CADENA_ORIGINAL'] := ''''+gCadenaOriginal+'''';
  end;
  fmPrincipal.frxReport1.PrepareReport(True);
  fmPrincipal.ExportPDF.DefaultPath := GetPrefer('CarpetaArchivos');
  fmPrincipal.ExportPDF.FileName := 'Factura_' + Folio + '.pdf';
  fmPrincipal.ExportPDF.ShowDialog := false;
  fmPrincipal.frxReport1.Export(fmPrincipal.ExportPDF);
  FreeAndNil(ReportStream);
  pdfpath := fmPrincipal.ExportPDF.FileName;
  if FileExists(pdfpath) then
      Result := CodificaPDF(pdfpath);

  DeleteFile(PAnsiChar(Qrcode));
  DeleteFile(PAnsiChar(pdfpath));

 end
except on e : exception do
 begin
   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 TfrmDataModule.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 TfrmDataModule.GeneraPDFEmail(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;
begin
  Result := '';
  sysutils.decimalseparator:='.';

try
 begin

  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
    str_qrcode := '?re='+  gRfcEmisor + '&rr=' + gRfcReceptor + '&tt=' + FormatFloat( '#.000000' , TotalPagar) + '&id=' + gUUID;
    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;
   //NotaCredito_
  frxReport1.PrepareReport(True);
  ExportPDF.DefaultPath := GetPrefer('CarpetaArchivos');

  if Documento = 'F' then
    ExportPDF.FileName := 'Factura_' + Folio + '.pdf';

  if Documento = 'C' then
    ExportPDF.FileName := 'NotaCredito_' + Folio + '.pdf';

  if Documento = 'D' then
    ExportPDF.FileName := 'NotaCredito_' + Folio + '.pdf';

  if Documento = 'PA' then
    ExportPDF.FileName := 'Pago' + Folio + '.pdf';

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

  FreeAndNil(ReportStream);
  pdfpath := ExportPDF.FileName;

  if FileExists(pdfpath) then
      Result := CodificaPDF(pdfpath);
   }
  DeleteFile(PAnsiChar(Qrcode));


 end
except on e : exception do
 begin
   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 TfrmDataModule.ConectarBDAWS();
var
  Url, Protocolo, Host,
  Puerto, Db, Usuario, Pass: string;
begin
  Protocolo := 'mysql';
  Host := 'exsimservicios.cicc11mxl3bu.us-east-1.rds.amazonaws.com';
  Puerto := '3306';
  Db := 'DB_Exsim_Servicios';
  Usuario := 'ExsimAdmin';
  Pass := 'exsim_4040';

  Connection := TZConnection.Create(Self);
  Dataset := TZQuery.Create(Self);
  Dataset.Connection := FConnection;
  Connection.AutoCommit := False;

  Connection.Protocol := 'mysql';
  Connection.HostName := Host;
  Connection.Database := Db;
  Connection.User := Usuario;
  Connection.Password := Pass;
  Dataset.Fields.Clear;

  Connection.Connect;

end;

function TfrmDataModule.ValidacionesGenerales(ClaveLic,Cliente:String; var lError:String):Boolean;
var ClaveArt:String;
dFechaTerminoLic,dFechaServidor:TDateTime;
Consulta:String;
ID, DiasRestantes, NumUsuarios:Integer;
FechaInicial, FechaFinal,FechaVerif1, FechaVerif2,EstatusLic,
ClaveClieMSP, Memoria, EsConcurrente:String;
begin

  lError := '';
  try
    begin

       try
         begin
	  ConectarBDAWS();
	 end;
       except on e : exception do
	 begin
    lError := 'No fue posible consulta la licencia.'+
      	 	    'Verifique que su servidor de base de datos Microsip esté conectado a internet o póngase en contacto con su distribuidor Microsip.';
	  exit;
         end;
       end;
         //Base_datos

       try
        begin
          Consulta := 'SELECT Licencia_ID, Usuarios, Estatus, Fecha_inicial, Fecha_final, ClaveClienteMicrosip, Memoria, EsConcurrente '+
                      'FROM Licencias where Numero_licencia = "'+Trim(ClaveLic)+'"  and Nombre_cliente = "'+Trim(Cliente)+'" ';
  	  dataset.SQL.Clear;
	  dataset.SQL.Add(Consulta);
	  Dataset.Open;
	end;
       except
	begin
	  lError := 'No fue posible consulta la licencia.'+
      	  'Verifique que su servidor de base de datos Microsip esté conectado a internet o póngase en contacto con su distribuidor Microsip.';
	  Connection.Disconnect;
	  exit;
	end;
       end;

	  ID := 0;
	  ID := Dataset.FieldByName('Licencia_ID').AsInteger;

	  EstatusLic := '';
	  EstatusLic := Dataset.FieldByName('Estatus').AsString;

	  NumUsuarios := 0;
	  NumUsuarios := Dataset.FieldByName('Usuarios').AsInteger;

	  FechaInicial := '';
	  FechaInicial := Dataset.FieldByName('Fecha_inicial').AsString;

	  FechaFinal := '';
	  FechaFinal := Dataset.FieldByName('Fecha_final').AsString;
	

       try
         begin
            FechaVerif1 := DateToStr(IBDatabase1.GetServerTime);
       		  FechaVerif2 := DateToStr(IBDatabase1.GetServerTime+30);
         end;
       except
         begin
            FechaVerif1 := DateToStr(Now());
       		  FechaVerif2 := DateToStr(Now()+30);
         end;
       end;


       ClaveClieMSP:= '';
       ClaveClieMSP := Dataset.FieldByName('ClaveClienteMicrosip').AsString;
       Memoria := '';
       Memoria := Dataset.FieldByName('Memoria').AsString;

       EsConcurrente := '';
       EsConcurrente := Dataset.FieldByName('EsConcurrente').AsString;



			 //form1.IBDatabase1.GetServerTime
       if ID = 0  then
       begin
           lError := 'El nombre del cliente o el número de la licencia no es válido.'+
     	     	     'Verifique su información o póngase en contacto con su distribuidor.';
	   Connection.Disconnect;
       end;



       ClaveArt := '';
       ClaveArt:=copy(Trim(ClaveLic),11,2);
       if ClaveArt <> CLAVE_PRODUCTO then
       begin
       	        lError := 'La licencia ingresada no pertenece a este sistema. '+
                          'Verifique la información de su licencia en su servidor Microsip. Si el problema persiste consulte a su distribuidor Microsip.';
		Connection.Disconnect;
		exit;
       end;

       if EstatusLic = 'S' then
       begin
       		lError := 'La licencia está suspendida, pónganse en contacto con su distribuidor Microsip.';
       		Connection.Disconnect;
                Result:=True;
		exit;
       end;

       if EstatusLic = 'B' then
       begin
       		lError := 'La licencia está dada de baja, pónganse en contacto con su distribuidor Microsip.';
                Result:=True;
		Connection.Disconnect;
		exit;
       end;

       try
        begin
                dFechaTerminoLic := StrToDate(FechaFinal);
	end;
       except
	begin
		 lError := 'Error al consultar la vigencia de la licencia.'+
                   'Verifique la información de su licencia en su servidor Microsip. Si el problema persiste consulte a su distribuidor Microsip.';
        	 Connection.Disconnect;
		 exit;
	end;
       end;


       try
         begin
            dFechaServidor := IBDatabase1.GetServerTime;
         end;
       except
         begin
            dFechaServidor := Now();
         end;
       end;



       if dFechaServidor >= dFechaTerminoLic then
       begin
       		lError := 'Su licencia ha expirado, solicite una renovación con su distribuidor Microsip.'+
                          'O ingrese una licencia valida.';
		Connection.Disconnect;
		exit;
       end;

       DiasRestantes := 0;
       DiasRestantes := DaysBetween(dFechaTerminoLic,dFechaServidor);


       if DiasRestantes < 30 then
          FechaVerif2 := DateToStr(dFechaTerminoLic);


       Connection.Disconnect;
       Result:=True;

    end;
  except
    begin
        lError := 'Error al validar la licencia';
    end;
  end;

end;

function TfrmDataModule.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;

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

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

   if IBQuery3.FieldByName('RFC_LCO_ID').AsInteger=0 then
   begin
   IBQuery4.Close;
   IBQuery4.SelectSQL.Clear;
   IBQuery4.SelectSQL.Add('INSERT INTO RFCS_LCO (RFC_LCO_ID, RFC, NOMBRE_FISCAL, DOMICILIO_FISCAL, ESTATUS_VERIFICACION) ');
   IBQuery4.SelectSQL.Add('VALUES (-1, :RFC, :NOMBRE_FISCAL, :DOMICILIO_FISCAL, ''T''); ');
   IBQuery4.ParamByName('RFC').AsString := RFC;
   IBQuery4.ParamByName('NOMBRE_FISCAL').AsString := NOMBRE_FISCAL;
   IBQuery4.ParamByName('DOMICILIO_FISCAL').AsString := DOMICILIO_FISCAL;
   IBQuery4.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 TfrmDataModule.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
   IBQuery2.Close;
   IBQuery2.SelectSQL.Clear;
   IBQuery2.SelectSQL.Add('UPDATE DIRS_CLIENTES SET TIPO_PERSONA = :TIPO_PERSONA, CLAVE_REGIMEN_FISCAL = :CLAVE_REGIMEN_FISCAL WHERE (DIR_CLI_ID = :DIR_CLI_ID);  ');
   IBQuery2.ParamByName('TIPO_PERSONA').AsString := TIPO_PERSONA;
   IBQuery2.ParamByName('CLAVE_REGIMEN_FISCAL').AsString := CLAVE_REGIMEN_FISCAL;
   IBQuery2.ParamByName('DIR_CLI_ID').AsInteger := DIR_CLI_ID;
   IBQuery2.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;


end.


