unit uRptContratosCliente_Server;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, frxClass, frxDBSet, uDAScriptingProvider,
  uDADataTable, uDACDSDataTable, DB, uDAClasses, uDABINAdapter, uROTypes,
  uDAInterfaces, uDAMemDataTable, uDADataStreamer, uDABin2DataStreamer,
  frxGradient, frxChBox, frxCross, frxOLE, frxBarcode, frxRich, uDAEngine,
  IBSQL, IBDatabase, IBCustomDataSet, IBQuery, frxExportPDF, FactuGES_Intf;

type
  TRptContratosCliente = class(TDataModule)
    DADSCabecera: TDADataSource;
    DADSDetalles: TDADataSource;
    frxBarCodeObject1: TfrxBarCodeObject;
    frxOLEObject1: TfrxOLEObject;
    frxCrossObject1: TfrxCrossObject;
    frxCheckBoxObject1: TfrxCheckBoxObject;
    frxGradientObject1: TfrxGradientObject;
    frxDBCabecera: TfrxDBDataset;
    frxDBDetalles: TfrxDBDataset;
    tbl_Cabecera: TDAMemDataTable;
    frxReport: TfrxReport;
    IBDatabase1: TIBDatabase;
    IBTransaction1: TIBTransaction;
    DataSource1: TDataSource;
    DataSource2: TDataSource;
    capitulos: TIBQuery;
    DataSource3: TDataSource;
    detalles: TIBQuery;
    frxDBCapitulos: TfrxDBDataset;
    DABin2DataStreamer1: TDABin2DataStreamer;
    cabecera: TIBQuery;
    DADSCapitulos: TDADataSource;
    tbl_Capitulos: TDAMemDataTable;
    frxPDFExport1: TfrxPDFExport;
    DADSInformeListadoContratos: TDADataSource;
    tbl_InformeListadoContratos: TDAMemDataTable;
    frxDBInformeListadoContratos: TfrxDBDataset;
    frxDBInformeListadoContratosResumen: TfrxDBDataset;
    DADSInformeListadoContratosResumen: TDADataSource;
    tbl_InformeListadoContratosResumen: TDAMemDataTable;
    tbl_Detalles: TDAMemDataTable;
    cabeceraID: TIntegerField;
    cabeceraID_EMPRESA: TIntegerField;
    cabeceraFECHA_CONTRATO: TDateField;
    cabeceraREFERENCIA: TIBStringField;
    cabeceraOBSERVACIONES: TMemoField;
    cabeceraIMPORTE_NETO: TIBBCDField;
    cabeceraIMPORTE_PORTE: TIBBCDField;
    cabeceraDESCUENTO: TFloatField;
    cabeceraIMPORTE_DESCUENTO: TIBBCDField;
    cabeceraBASE_IMPONIBLE: TIBBCDField;
    cabeceraIVA: TFloatField;
    cabeceraID_CLIENTE: TIntegerField;
    cabeceraNIF_CIF: TIBStringField;
    cabeceraNOMBRE: TIBStringField;
    cabeceraIMPORTE_IVA: TIBBCDField;
    cabeceraIMPORTE_TOTAL: TIBBCDField;
    cabeceraPERSONA_CONTACTO: TIBStringField;
    cabeceraCALLE: TIBStringField;
    cabeceraPOBLACION: TIBStringField;
    cabeceraPROVINCIA: TIBStringField;
    cabeceraCODIGO_POSTAL: TIBStringField;
    tbl_DetallesArticulos: TDAMemDataTable;
    DADSDetallesArticulos: TDADataSource;
    frxDBDetallesArticulos: TfrxDBDataset;
    schReport: TDASchema;
    DataDictionary: TDADataDictionary;
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
    function frxReportUserFunction(const MethodName: string;
      var Params: Variant): Variant;
  private
    FConnection: IDAConnection;
    FIdEmpresa: Integer;
    FFechaInicio: Variant;
    FFechaFin: Variant;
    FListaIDClientes: TIntegerArray;
    FListaNombresClientes: TStringList;
    FImporteMinimo: Currency;
    FDesglosado : Boolean;
    FVerLogotipo : Boolean;
    FNombreEmpresa: String;
    FVerPrecios: Boolean;
    FVerTotales: Boolean;
    FVerCondiciones: Boolean;
    FTamLetra: Integer;

    procedure _GenerarContrato(const AID : Integer);

    procedure PrepararTablaInforme(ATabla: TDAMemDataTable);
    procedure PrepararTablaResumenInforme(ATabla: IDADataset);

    function _GenerarInforme(const TipoInforme: String): Binary;
    procedure IniciarParametrosInforme;
    procedure RecuperarNombresClientes;
  public
    function GenerarContrato(const ListaID : TIntegerArray; const VerCondiciones: Boolean; const TamLetra: Integer): Binary;
    function GenerarContratoEnPDF(const ListaID : TIntegerArray; const VerCondiciones: Boolean): Binary;
    function GenerarInformeListadoContratos(const IdEmpresa: Integer; const FechaInicio: Variant; const FechaFin: Variant; const ListaIDClientes: TIntegerArray; const Desglosado: Boolean; const ImporteMinimo: Currency): Binary;
  end;

implementation

{$R *.dfm}

uses
  uSistemaFunc, StrUtils, uDataModuleServer, schContratosClienteClient_Intf,
  uROServer, DataAbstract4_Intf;


const
  rptInforme = 'InfContratoCliente.fr3';
  rptInformeListadoContratosDesglosado = 'InformeListadoContratosDesglosado.fr3';
  rptInformeListadoContratos = 'InformeListadoContratos.fr3';

  { Dataset names for schReport }
  ds_InformeListadoContratosResumen = 'InformeListadoContratosResumen';


procedure TRptContratosCliente.DataModuleCreate(Sender: TObject);
begin
  schReport.ConnectionManager := dmServer.ConnectionManager;
  FConnection := dmServer.DarNuevaConexion;
  frxReport.EngineOptions.NewSilentMode := simReThrow;

  frxDBCabecera.DataSource := DADSCabecera;
  frxDBCabecera.CloseDataSource := False;

  frxDBCapitulos.DataSource := DADSCapitulos;
  frxDBCapitulos.CloseDataSource := False;

  frxDBDetalles.DataSource := DADSDetalles;
  frxDBDetalles.CloseDataSource := False;

  FListaNombresClientes := TStringList.Create;

  with tbl_Detalles do
  begin
    MasterSource := DADSCapitulos;
    MasterFields := 'ID';
    DetailFields := 'ID_CAPITULO';
    MasterMappingMode := mmWhere;
  end;
end;

function TRptContratosCliente.GenerarContratoEnPDF(const ListaID: TIntegerArray; const VerCondiciones: Boolean): Binary;
var
  i: Integer;
begin
  Result := Binary.Create;

  //Inicializamos parametros
  FVerLogotipo := true;
  FNombreEmpresa := '';
  FVerPrecios := true;
  FVerTotales := true;
  FVerCondiciones := VerCondiciones;

  try
    //Vamos generando todos y cada uno de los Contratos recibidos
    for i := 0 to ListaID.Count - 1 do
        _GenerarContrato(ListaID.Items[i]);

    frxPDFExport1.Stream := Result;
    frxReport.Export(frxPDFExport1)
  finally
  end;
end;

procedure TRptContratosCliente.IniciarParametrosInforme;
var
  ATextos : TStringList;
  ACadena : String;
begin
  ATextos := TStringList.Create;

  try
    if (not VarIsNull(FFechaInicio)) and (not VarIsNull(FFechaFin)) then
      ACadena := Format('Fechas de Contrato desde el %s hasta el %s', [VarToStr(FFechaInicio), VarToStr(FFechaFin)])
    else
      ACadena := 'Sin rango de fechas';
    ATextos.Add(ACadena);
    ACadena := '';

    if (FImporteMinimo > 0) then
    begin
      ACadena := Format('Contratos con importe superior a %m', [FImporteMinimo]);
      ATextos.Add(ACadena);
      ACadena := '';
    end;

    if Assigned(FListaIDClientes) and (FListaIDClientes.Count > 0) then
    begin
      RecuperarNombresClientes;
      ACadena := FListaNombresClientes.Text;
    end
    else begin
      ACadena := 'Todos los clientes';
      if FDesglosado then
        ACadena := ACadena + ' (desglosados)'
    end;

    ATextos.Add(ACadena);
    ACadena := '';

    frxReport.Variables.Variables['TextoParametros'] := ATextos.Text;
  finally
    FreeAndNil(ATextos);
  end;
end;

procedure TRptContratosCliente.PrepararTablaInforme(ATabla: TDAMemDataTable);
var
  Condicion: TDAWhereExpression;
  i: Integer;

begin
  // Filtrar el informe por empresa
  with ATabla.DynamicWhere do
  begin
    // (ID_EMPRESA >= ID)
    Condicion := NewBinaryExpression(NewField('', fld_ContratosClienteID_EMPRESA), NewConstant(FIdEmpresa, datInteger), dboEqual);
    if IsEmpty then
       Expression := Condicion
    else
       Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
  end;

  // Filtrar el informe por fechas
  if  not VarIsNull(FFechaInicio)
  and not VarIsNull(FFechaFin) then
  begin
    with ATabla.DynamicWhere do
    begin
      // (FECHA_INICIO between FECHA_FIN)
      Condicion := NewBinaryExpression(NewField('', fld_ContratosClienteFECHA_Contrato), NewConstant(FFechaInicio, datDateTime), dboGreaterOrEqual);
      Condicion := NewBinaryExpression(NewBinaryExpression(NewField('', fld_ContratosClienteFECHA_Contrato), NewConstant(FFechaFin, datDateTime), dboLessOrEqual), Condicion, dboAnd);
      if IsEmpty then
         Expression := Condicion
      else
         Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
    end;
  end;

  // Filtrar el informe por proveedor
  if  Assigned(FListaIDClientes) then
  begin
    with ATabla.DynamicWhere do
    begin
      for i := 0 to FListaIDClientes.Count - 1 do
      begin

        // (ID_CLIENTE = ID)
        Condicion := NewBinaryExpression(NewField('', fld_ContratosClienteID_CLIENTE), NewConstant(FListaIDClientes.Items[i], datInteger), dboEqual);
        if IsEmpty then
           Expression := Condicion
        else
           Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
        end;
    end;
  end;

  // Filtrar el informe por importe minimo
  if  (FImporteMinimo > 0) then
  begin
    with ATabla.DynamicWhere do
    begin
      // (IMPORTE_TOTAL > ImporteMinimo)
      Condicion := NewBinaryExpression(NewField('', fld_ContratosClienteIMPORTE_TOTAL), NewConstant(FImporteMinimo, datCurrency), dboGreaterOrEqual);
      if IsEmpty then
         Expression := Condicion
      else
         Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
    end;
  end;
end;

procedure TRptContratosCliente.PrepararTablaResumenInforme(ATabla: IDADataset);
var
  i: Integer;
  AWhereStr : String;

begin
  // Filtrar el informe por empresa
  AWhereStr := ' (' + fld_ContratosClienteID_EMPRESA + ' = ' + IntToStr(FIdEmpresa) + ') ';

  // Filtrar el informe por fechas
  if  not VarIsNull(FFechaInicio)
  and not VarIsNull(FFechaFin) then
  begin
    if Length(AWhereStr) > 0 then
       AWhereStr := AWhereStr + 'AND';
    AWhereStr := AWhereStr + ' (' + fld_ContratosClienteFECHA_Contrato + ' between ''' + ReplaceStr(VarToStr(FFechaInicio),'/','.') + ''' and ''' + ReplaceStr(VarToStr(FFechaFin),'/','.') + ''') ';
  end;

  // Filtrar el informe por cliente
  if  Assigned(FListaIDClientes) then
  begin
    for i := 0 to FListaIDClientes.Count - 1 do
    begin
      if Length(AWhereStr) > 0 then
         AWhereStr := AWhereStr + 'AND';
      AWhereStr := AWhereStr + ' (' + fld_ContratosClienteID_CLIENTE + ' = ' + IntToStr(FListaIDClientes.Items[i]) + ') ';
    end;
  end;

  // Filtrar el informe por importe minimo
  if  (FImporteMinimo > 0) then
  begin
    if Length(AWhereStr) > 0 then
       AWhereStr := AWhereStr + 'AND';
    AWhereStr := AWhereStr + ' (' + fld_ContratosClienteIMPORTE_TOTAL + ' >= ' + CurrToStr(FImporteMinimo) + ') ';
  end;

  ATabla.Where.AddText(AWhereStr);
end;

procedure TRptContratosCliente.RecuperarNombresClientes;
var
  AContactosService : IsrvContactos;
  Intf : IInterface;
  AClientID : TGUID;

  ATableNameArray: StringArray;
  ATableRequestInfoArray: TableRequestInfoArray;
  ATableRequestInfo: TableRequestInfoV5;
  AStream: TMemoryStream;
  ADataTable: TDAMemDataTable;
  i: Integer;
  AWhereBuilder : TDAWhereBuilder;
  ACondicion : TDAWhereExpression;
begin
  CreateGUID(AClientID);

  GetClassFactory('srvContactos').CreateInstance(AClientID, Intf);

  if Assigned(Intf) then
  begin
    AContactosService := Intf as IsrvContactos;

    ATableNameArray := StringArray.Create;
    ATableRequestInfoArray := TableRequestInfoArray.Create;
    AWhereBuilder := TDAWhereBuilder.Create;
    try
      ATableNameArray.Add('Clientes');
      ATableRequestInfo := TableRequestInfoV5.Create;

      with ATableRequestInfo do
      begin
        IncludeSchema := True;
        MaxRecords := -1;
        UserFilter := '';

        AWhereBuilder.Clear;
        with AWhereBuilder do
          for i := 0 to FListaIDClientes.Count - 1 do
          begin
            ACondicion := NewBinaryExpression(
                NewBinaryExpression(NewField('', 'ID'), NewConstant(FListaIDClientes[i], datInteger), dboEqual),
                NewBinaryExpression(NewField('', 'ID_EMPRESA'), NewConstant(FIdEmpresa, datInteger), dboEqual),
                dboAnd);

            if not AWhereBuilder.IsEmpty then
              Expression := NewBinaryExpression(Expression, ACondicion, dboOr)
            else
              Expression := ACondicion;
          end;

        WhereClause := AWhereBuilder.ExpressionToXmlNode(AWhereBuilder.Expression);
      end;

      try
        ATableRequestInfoArray.Add(ATableRequestInfo);
        AStream := AContactosService.GetData(ATableNameArray, ATableRequestInfoArray);
        if Assigned(AStream) then
        begin
          ADataTable := TDAMemDataTable.Create(nil);
          try
            ADataTable.Name := 'Clientes';
            ADataTable.LocalDataStreamer := DABin2DataStreamer1;
            ADataTable.RemoteFetchEnabled := False;
            DABin2DataStreamer1.ReadDataset(AStream, ADataTable, True);

            ADataTable.Open;
            FListaNombresClientes.Clear;
            for i := 0 to ADataTable.RecordCount - 1 do
            begin
              FListaNombresClientes.Add(ADataTable.FieldByName('NOMBRE').AsString);
              ADataTable.Next;
            end;

          finally
            FreeANDNil(ADataTable);
          end;
        end;
      except
        on e: Exception do
          dmServer.EscribirLog(e.Message);
      end;
    finally
      FreeANDNIL(ATableRequestInfoArray);
      FreeANDNIL(ATableNameArray);
      FreeANDNIL(AWhereBuilder);
    end;
  end;
end;

procedure TRptContratosCliente.DataModuleDestroy(Sender: TObject);
begin
  tbl_Cabecera.Active := False;
  tbl_Capitulos.Active := False;
  tbl_Detalles.Active := False;

  FreeANDNIL(FListaNombresClientes);
end;

function TRptContratosCliente.frxReportUserFunction(const MethodName: string;
  var Params: Variant): Variant;
var
  AText : String;
begin
  Result := '';
  if (MethodName = 'PONERJUSTIFICACIONCOMPLETA') then
  begin
    AText := VarToStr(Params[0]);
    Result := ReplaceStr(AText, '\pard', '\qj');
  end;
end;

function TRptContratosCliente.GenerarInformeListadoContratos(
  const IdEmpresa: Integer; const FechaInicio, FechaFin: Variant;
  const ListaIDClientes: TIntegerArray; const Desglosado: Boolean;
  const ImporteMinimo: Currency): Binary;
var
  ATipoInforme: String;
  AStream: TMemoryStream;
  dsMaster: IDADataset;

begin
  FConnection.BeginTransaction; //<--- Creo que no va a hacer falta. "PUES SI ES NECESARIO"

  AStream := TMemoryStream.Create;
  try
    //Inicializamos parametros
    FIdEmpresa := IdEmpresa;
    FFechaInicio := FechaInicio;
    FFechaFin := FechaFin;
    FImporteMinimo := ImporteMinimo;

    if Assigned(FListaIDClientes) then
       FListaIDClientes.Free;
    FListaIDClientes := ListaIDClientes;

    if tbl_InformeListadoContratos.Active then
       tbl_InformeListadoContratos.Active := False;
    PrepararTablaInforme(tbl_InformeListadoContratos);

    //Se prepara la tabla del listado resumen del informe
    if tbl_InformeListadoContratosResumen.Active then
       tbl_InformeListadoContratosResumen.Active := False;
    dsMaster := schReport.NewDataset(FConnection, ds_InformeListadoContratosResumen, [], [], False);
    PrepararTablaResumenInforme(dsMaster);

    //Esto se hace para rellenar la tabla del datamodule que usa el informe.
    dsMaster.Open;
    AStream.Clear;
    DABin2DataStreamer1.WriteDataset(AStream, dsMaster, [woRows, woSchema], -1);
    DABin2DataStreamer1.ReadDataset(AStream, tbl_InformeListadoContratosResumen, TRUE, '', TRUE, TRUE);

    //DESGLOSADO POR CLIENTE EN ESTE INFORME NO SE DESGLOSARÁ POR CLIENTE
    FDesglosado := Desglosado;
    if FDesglosado then
       ATipoInforme := rptInformeListadoContratosDesglosado
    else
       ATipoInforme := rptInformeListadoContratos;

    //Finalmente se abren las tablas del informe
    tbl_InformeListadoContratos.Active := True;
    tbl_InformeListadoContratosResumen.Active := True;

    Result := _GenerarInforme(ATipoInforme);

  finally
    AStream.Free;
    dsMaster := Nil;
    FConnection.RollbackTransaction; //<--- Creo que no va a hacer falta. "PUES SI ES NECESARIO"
  end;
end;

function TRptContratosCliente.GenerarContrato(const ListaID: TIntegerArray; const VerCondiciones: Boolean; const TamLetra: Integer): Binary;
var
  i: Integer;
begin
  Result := Binary.Create;

  //Inicializamos parametros
  FVerLogotipo := True;
  FNombreEmpresa := '';
  FVerPrecios := True;
  FVerTotales := True;
  FVerCondiciones := VerCondiciones;
  FTamLetra := TamLetra;

  try
    //Vamos generando todos y cada uno de los Contratos recibidos
    for i := 0 to ListaID.Count - 1 do
        _GenerarContrato(ListaID.Items[i]);

    frxReport.PreviewPages.SaveToStream(Result);
  finally
  end;
end;

function TRptContratosCliente._GenerarInforme(const TipoInforme: String): Binary;
var
  AInforme: Variant;

begin
  Result := Binary.Create;
  AInforme := DarRutaFichero(DarRutaInformes, TipoInforme, IntToStr(FIdEmpresa));
  if VarIsNull(AInforme) then
     raise Exception.Create (('Error Servidor: _GenerarInforme, no encuentra informe ' + TipoInforme));

  frxReport.LoadFromFile(AInforme, True);
  IniciarParametrosInforme;

  frxReport.PrepareReport(False);
  frxReport.PreviewPages.SaveToStream(Result);
end;

procedure TRptContratosCliente._GenerarContrato(const AID: Integer);
var
  AInforme: Variant;
  AStyle: TfrxStyleItem;
begin
  FConnection.BeginTransaction; //<--- Creo que no va a hacer falta. "PUES SI ES NECESARIO"
  try
    tbl_Cabecera.Active := False;
    tbl_Capitulos.Active := False;
    tbl_Detalles.Active := False;
    tbl_DetallesArticulos.Active := False;

    tbl_Cabecera.ParamByName('ID').AsInteger := AID;
    tbl_Capitulos.ParamByName('ID_PRE_CON').AsInteger := AID;
    tbl_Detalles.ParamByName('ID_PRE_CON').AsInteger := AID;
    tbl_DetallesArticulos.ParamByName('ID_CONTRATO').AsInteger := AID;

    // Se asignan los parametros en este orden para que funcionen
    // dentro de las relaciones maestro-detalle (capítulos y conceptos).

    tbl_Cabecera.Active := True;
    tbl_Capitulos.Active := True;
    tbl_Detalles.Active := True;

    tbl_DetallesArticulos.Active := True;

    AInforme := DarRutaFichero(DarRutaInformes, rptInforme, tbl_Cabecera.FieldByName('ID_EMPRESA').AsString);
    if VarIsNull(AInforme) then
       raise Exception.Create (('Error Servidor: _GenerarContrato, no encuentra informe ' + rptInforme));

    frxReport.LoadFromFile(AInforme, True);
    frxReport.Variables.Variables['VerLogotipo'] := FVerLogotipo;
    frxReport.Variables.Variables['NombreEmpresa'] := ''''+FNombreEmpresa+'''';
    frxReport.Variables.Variables['VerPrecios'] := FVerPrecios;
    frxReport.Variables.Variables['VerTotales'] := FVerTotales;
    frxReport.Variables.Variables['VerCondiciones'] := FVerCondiciones;
    frxReport.AddFunction('function PONERJUSTIFICACIONCOMPLETA(ARTFText : String): String', 'User Function','');
    frxReport.ReportOptions.Name := 'Presupuesto ' + tbl_Cabecera.FieldByName('REFERENCIA').AsString;

//Prueba para ver si se puede reducir tamaño de letra
    AStyle := frxReport.Styles.Find('Concepto');
    AStyle.Font.Size := FTamLetra;
    frxReport.Styles.Apply;
    
    frxReport.PrepareReport(False);
  finally
    FConnection.RollbackTransaction; //<--- Creo que no va a hacer falta. "PUES SI ES NECESARIO"
  end;
end;

end.
