Tecsitel_FactuGES2/Source/Base/ControllerBase/uControllerDetallesBase.pas

586 lines
20 KiB
ObjectPascal
Raw Blame History

unit uControllerDetallesBase;
interface
uses Classes, Variants, uDACDSDataTable, uDADataTable, uControllerBase;
const
CAMPO_ID = 'ID';
CAMPO_POSICION = 'POSICION';
CAMPO_TIPO = 'TIPO_DETALLE';
CAMPO_CONCEPTO = 'CONCEPTO';
CAMPO_CANTIDAD = 'CANTIDAD';
CAMPO_IMPORTE_UNIDAD = 'IMPORTE_UNIDAD';
CAMPO_IMPORTE_TOTAL = 'IMPORTE_TOTAL';
TIPO_DETALLE_CONCEPTO = 'Concepto';
TIPO_DETALLE_TITULO = 'Titulo';
TIPO_DETALLE_SUBTOTAL = 'Subtotal';
TIPO_DETALLE_SALTO = 'Salto';
CTE_DESC_SALTO = 'SALTO DE PAGINA >>';
type
TIntegerArray = array of Integer;
IControllerDetallesBase = interface(ISujeto)
['{F0B0E714-EC0D-4B6B-98B1-76F72F70B735}']
function getTipo(ADataTable: IDAStronglyTypedDataTable; pPosicion: Integer): String;
procedure Clear(ADataTable: IDAStronglyTypedDataTable);
procedure Add(ADataTable: IDAStronglyTypedDataTable; TipoConcepto: Variant);
procedure Delete(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray);
procedure Move(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray; Posiciones: Integer);
// procedure Copy(SMExport: TSMExportToClipboard);
// procedure Paste;
procedure ActualizarTotales(ADataTable: IDAStronglyTypedDataTable);
function DarTotalImporteTotal(ADataTable: IDAStronglyTypedDataTable): Double;
function DarListaTiposDetalle: TStringList;
end;
TControllerDetallesBase = class (TSujeto, IControllerDetallesBase)
private
fUpdateCount: Integer;
function CalcularTotales(Modificar: boolean; DataTable: TDADataTable): Double;
protected
procedure Renumerar(DataTable: TDADataTable; LocalizaPosicion: Integer);
function DesplazarNPosiciones(DataTable: TDADataTable; NumOrdenIni: Variant; NPosiciones: Variant): Integer;
procedure Mover(DataTable: TDADataTable; Posicion: Integer; NumPosiciones: Integer);
procedure BeginUpdate(ADataTable: IDAStronglyTypedDataTable);
procedure EndUpdate(ADataTable: IDAStronglyTypedDataTable);
//Si en los hijos existen campos a tener en cuenta se sobreescribira este metodo
procedure validarCampos(DataTable: TDADataTable); virtual;
//Si sobreescribimos este m<>todo podremos tener en cuenta otras columnas para el calculo del importe total de un concepto
function CalcularImporteTotalConcepto(DataTable: TDADataTable): Double; virtual;
procedure TratamientoDetalleConcepto(DataTable: TDADataTable); virtual;
procedure CalculoDetalleConcepto(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); virtual;
procedure TratamientoDetalleSalto(DataTable: TDADataTable); virtual;
procedure CalculoDetalleSalto(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); virtual;
procedure TratamientoDetalleTitulo(DataTable: TDADataTable); virtual;
procedure CalculoDetalleTitulo(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); virtual;
procedure TratamientoDetalleSubtotal(DataTable: TDADataTable); virtual;
procedure CalculoDetalleSubtotal(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); virtual;
//Si sobreescribimos este metodo es para continuar el CalcularTotales segun los tipos de concepto de los hijos
function CalcularTotalesHijos(Modificar: boolean; DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double): Double; virtual;
public
constructor Create; override;
destructor Destroy; override;
function getTipo(ADataTable: IDAStronglyTypedDataTable; pPosicion: Integer): String;
procedure Clear(ADataTable: IDAStronglyTypedDataTable);
procedure Add(ADataTable: IDAStronglyTypedDataTable; TipoConcepto: Variant); virtual;
procedure Delete(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray); virtual;
procedure Move(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray; Posiciones: Integer); virtual;
// procedure Copy(SMExport: TSMExportToClipboard);
// procedure Paste;
procedure ActualizarTotales(ADataTable: IDAStronglyTypedDataTable);
function DarTotalImporteTotal(ADataTable: IDAStronglyTypedDataTable): Double;
function DarListaTiposDetalle: TStringList; virtual;
end;
implementation
{ TControllerDetallesBase }
uses cxControls, SysUtils, DB, uDAInterfaces;
procedure TControllerDetallesBase.ActualizarTotales(ADataTable: IDAStronglyTypedDataTable);
begin
BeginUpdate(ADataTable);
try
CalcularTotales(True, ADataTable.DataTable);
finally
EndUpdate(ADataTable);
end;
end;
procedure TControllerDetallesBase.Add(ADataTable: IDAStronglyTypedDataTable; TipoConcepto: Variant);
var
AuxNumOrden : Integer;
begin
BeginUpdate(ADataTable);
try
with ADataTable do
begin
AuxNumOrden := desplazarNPosiciones(DataTable, DataTable.FieldByName(CAMPO_POSICION).AsVariant, 1);
DataTable.Insert;
DataTable.FieldByName(CAMPO_POSICION).AsInteger := AuxNumOrden;
DataTable.FieldByName(CAMPO_TIPO).AsVariant := TipoConcepto;
DataTable.post;
end;
finally
EndUpdate(ADataTable);
end;
end;
procedure TControllerDetallesBase.BeginUpdate(ADataTable: IDAStronglyTypedDataTable);
begin
ShowHourglassCursor;
Inc(fUpdateCount);
ADataTable.DataTable.DisableControls;
end;
function TControllerDetallesBase.CalcularImporteTotalConcepto(DataTable: TDADataTable): Double;
begin
with DataTable do
Result := FieldByName(CAMPO_CANTIDAD).asInteger * FieldByName(CAMPO_IMPORTE_UNIDAD).AsFloat;
end;
function TControllerDetallesBase.CalcularTotales(Modificar: boolean; DataTable: TDADataTable): Double;
{
funcion que recalcula todos los detalles de la tabla pasada por parametro y devuelve
la cantidad total de los mismos
}
var
AuxPosicionIni : Integer;
AuxPosicion : Integer;
AuxImporteAcumulado : Double;
AuxImporteTotal : Double;
begin
if (DataTable.State in dsEditModes) then
DataTable.Post;
ValidarCampos(DataTable);
DataTable.DisableControls;
AuxPosicionIni := DataTable.FieldByName(CAMPO_POSICION).AsInteger;
AuxPosicion := 0;
AuxImporteAcumulado := 0;
AuxImporteTotal := 0;
try
DataTable.First;
while DataTable.Locate(CAMPO_POSICION, IntToStr(AuxPosicion), []) do
begin
//SALTOS DE LINEA
if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_SALTO) then
begin
if Modificar then
TratamientoDetalleSalto(DataTable); //Se podr<64> sobreescribir para que se tengan en cuenta nuevos campos en hijos
CalculoDetalleSalto(DataTable, AuxImporteAcumulado, AuxImporteTotal); //Se podr<64> sobreescribir para posibles nuevos calculos de los hijos
end
//TITULOS
else if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_TITULO) then
begin
if Modificar then
TratamientoDetalleTitulo(DataTable); //Se podr<64> sobreescribir para que se tengan en cuenta nuevos campos en hijos
CalculoDetalleTitulo(DataTable, AuxImporteAcumulado, AuxImporteTotal); //Se podr<64> sobreescribir para posibles nuevos calculos de los hijos
end
//SUBTITULOS
else if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_SUBTOTAL) then
begin
if Modificar then
TratamientoDetalleSubtotal(DataTable); //Se podr<64> sobreescribir para que se tengan en cuenta nuevos campos
CalculoDetalleSubtotal(DataTable, AuxImporteAcumulado, AuxImporteTotal); //Se podr<64> sobreescribir para posibles nuevos calculos de los hijos
end
//CONCEPTOS
else if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_CONCEPTO) then
begin
if Modificar then
TratamientoDetalleConcepto(DataTable); //Se podr<64> sobreescribir para que se tengan en cuenta nuevos campos
CalculoDetalleConcepto(DataTable, AuxImporteAcumulado, AuxImporteTotal); //Se podr<64> sobreescribir para posibles nuevos calculos de los hijos
end
//HIJOS
else CalcularTotalesHijos(Modificar, DataTable, AuxImporteAcumulado, AuxImporteTotal);
Inc(AuxPosicion);
DataTable.First;
end;
finally
//Dejamos el puntero en la misma posici<63>n que la que parti<74>
DataTable.Locate(CAMPO_POSICION, IntToStr(AuxPosicionIni), []);
DataTable.EnableControls;
end;
Result := AuxImporteTotal;
end;
function TControllerDetallesBase.CalcularTotalesHijos(Modificar: boolean; DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double): Double;
begin
//
Result := 0;
end;
procedure TControllerDetallesBase.CalculoDetalleConcepto(DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double);
begin
with DataTable do
begin
ImporteAcumulado := ImporteAcumulado + FieldByName(CAMPO_IMPORTE_TOTAL).AsFloat;
ImporteTotal := ImporteTotal + FieldByName(CAMPO_IMPORTE_TOTAL).AsFloat;
end;
end;
procedure TControllerDetallesBase.CalculoDetalleSalto(DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double);
begin
with DataTable do
begin
if not Editing then Edit;
FieldByName(CAMPO_CANTIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_TOTAL).AsVariant := Null;
Post;
end;
end;
procedure TControllerDetallesBase.CalculoDetalleSubtotal(DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double);
begin
with DataTable do
begin
if not Editing then Edit;
FieldByName(CAMPO_IMPORTE_TOTAL).AsFloat := ImporteAcumulado;
Post;
end;
ImporteAcumulado := 0;
end;
procedure TControllerDetallesBase.CalculoDetalleTitulo(DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double);
begin
//
end;
procedure TControllerDetallesBase.Clear(ADataTable: IDAStronglyTypedDataTable);
begin
//
end;
constructor TControllerDetallesBase.Create;
begin
inherited;
end;
function TControllerDetallesBase.DarListaTiposDetalle: TStringList;
begin
Result := TStringList.Create;
Result.Values[TIPO_DETALLE_CONCEPTO] := 'Concepto';
Result.Values[TIPO_DETALLE_TITULO] := 'T<>tulo de cap<61>tulo';
Result.Values[TIPO_DETALLE_SUBTOTAL] := 'Final de cap<61>tulo';
Result.Values[TIPO_DETALLE_SALTO] := 'Salto de p<>gina';
end;
function TControllerDetallesBase.darTotalImporteTotal(ADataTable: IDAStronglyTypedDataTable): Double;
begin
Result := CalcularTotales(False, ADataTable.DataTable);
end;
procedure TControllerDetallesBase.Delete(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray);
var
i: integer;
AField: TDAField;
DeletePosicion: Integer;
begin
AField := ADataTable.DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (Delete)');
BeginUpdate(ADataTable);
try
with ADataTable do
begin
DeletePosicion := 0;
for i := 0 to High(POSICION) do
begin
DataTable.First;
DeletePosicion := POSICION[i];
if DataTable.Locate(CAMPO_POSICION, IntToStr(DeletePosicion), []) then
DataTable.Delete;
end;
Renumerar(DataTable, DeletePosicion);
end;
finally
EndUpdate(ADataTable);
end;
end;
function TControllerDetallesBase.DesplazarNPosiciones(DataTable: TDADataTable; NumOrdenIni: Variant; NPosiciones: Variant): Integer;
{
Funci<EFBFBD>n que desplaza NPosiciones el numero de orden a partir del elemento con el
n<EFBFBD>mero de orden dado. Devuelve el numero de orden del primer elemento del hueco
generado
}
var
AuxNumOrden: Integer;
AuxNumPos: Integer;
AField: TDAField;
begin
AField := DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (desplazarNPosiciones)');
if VarIsNull(NPosiciones)
then AuxNumPos := 1
else AuxNumPos := NPosiciones;
if VarIsNull(NumOrdenIni)
then AuxNumOrden := 0
else AuxNumOrden := NumOrdenIni + 1; //A<>adimos por abajo siempre
Result := AuxNumOrden;
with DataTable do
begin
First;
while not EOF do
begin
if (FieldByName(CAMPO_POSICION).AsInteger >= AuxNumOrden) then
begin
if not Editing then Edit;
FieldByName(CAMPO_POSICION).AsInteger := FieldByName(CAMPO_POSICION).AsInteger + AuxNumPos;
Post;
end;
Next;
end;
end;
end;
destructor TControllerDetallesBase.Destroy;
begin
inherited;
end;
procedure TControllerDetallesBase.EndUpdate(ADataTable: IDAStronglyTypedDataTable);
begin
Dec(fUpdateCount);
CalcularTotales(True, ADataTable.DataTable);
ADataTable.DataTable.EnableControls;
if fUpdateCount = 0 then
AvisarObservadores(ADataTable);
HideHourglassCursor;
end;
function TControllerDetallesBase.getTipo(ADataTable: IDAStronglyTypedDataTable; pPosicion: Integer): String;
var
posIni: integer;
AField: TDAField;
begin
AField := ADataTable.DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (getTipo)');
Result := '';
BeginUpdate(ADataTable);
try
with ADataTable do
begin
//Guardamos la posicion en la que estamos
posIni := DataTable.FieldByName(CAMPO_POSICION).AsInteger;
DataTable.First;
if DataTable.Locate(CAMPO_POSICION, IntToStr(pPosicion), []) then
Result := DataTable.FieldByName(CAMPO_TIPO).AsString;
//Volvemos a posicionar el puntero donde estaba
DataTable.First;
if not DataTable.Locate(CAMPO_POSICION, IntToStr(posIni), []) then
raise Exception.Create('La posici<63>n ' + IntToStr(posIni) + ' no existe (getTipo)');
end;
finally
EndUpdate(ADataTable);
end;
end;
procedure TControllerDetallesBase.Move(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray; Posiciones: Integer);
var
i:Integer;
begin
BeginUpdate(ADataTable);
try
with ADataTable do
begin
//Empezamos desde abajo
if Posiciones > 0 then
for i:= High(POSICION) downto 0 do
Mover(DataTable, POSICION[i], Posiciones)
else
//Empezamos desde arriba
for i:= 0 to High(POSICION) do
Mover(DataTable, POSICION[i], Posiciones);
end;
finally
EndUpdate(ADataTable);
end;
end;
procedure TControllerDetallesBase.Mover(DataTable: TDADataTable; Posicion: Integer; NumPosiciones: Integer);
{
procedimiento que desplaza el n<>mero de posiciones (NumPosiciones) pasados por parametro
a la posicion (Posicion) dada, en caso de ser negativo ser<65> hacia arriba y positivo hacia
abajo
}
var
AuxOrden : Integer;
AuxID : Integer;
AField: TDAField;
begin
AField := DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (mover)');
AField := DataTable.FindField(CAMPO_ID);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_ID + ' no encontrado (mover)');
//Buscamos el elemento con la posicion pasada por parametro
DataTable.First;
if not DataTable.Locate(CAMPO_POSICION, IntToStr(Posicion), []) then
raise Exception.Create('Error, no se ha encontrado la POSICION [' + IntToStr(Posicion) + '] (mover)');
//Guardamos el id del elemento a cambiar de posicion y calculamos su nueva posicion
AuxID := DataTable.FieldByName(CAMPO_ID).AsInteger;
AuxOrden := Posicion + NumPosiciones;
DataTable.First;
if DataTable.Locate(CAMPO_POSICION, IntToStr(AuxOrden), []) then
begin
if not DataTable.Editing then DataTable.Edit;
DataTable.FieldByName(CAMPO_POSICION).AsInteger := DataTable.FieldByName(CAMPO_POSICION).AsInteger - NumPosiciones;
//Se hace dentro por si es el ultimo o el primero
DataTable.First;
if not DataTable.Locate(CAMPO_ID, IntToStr(AuxID), []) then
raise Exception.Create('Error, no se ha encontrado el ID [' + IntToStr(AuxID) + '] (mover)');
if not DataTable.Editing then DataTable.Edit;
DataTable.FieldByName(CAMPO_POSICION).AsInteger := AuxOrden;
DataTable.Post;
end;
//Colocamos el puntero en la posici<63>n en la que estaba
DataTable.First;
DataTable.Locate(CAMPO_ID, IntToStr(AuxID), []);
end;
procedure TControllerDetallesBase.Renumerar(DataTable: TDADataTable; LocalizaPosicion: Integer);
{
procedimiento que renumera todos los conceptos de la tabla dada por parametro
}
var
i, j : Integer;
AField: TDAField;
begin
AField := DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (renumerar)');
with DataTable do
begin
for i:=0 to RecordCount-1 do
begin
First;
if not Locate(CAMPO_POSICION, IntToStr(i), []) then
begin
j := i;
First;
while not Locate(CAMPO_POSICION, IntToStr(j), []) do
begin
Inc(j);
First;
end;
if not Editing then Edit;
FieldByName(CAMPO_POSICION).AsInteger := i;
Post;
end;
end;
//Posicionamos el puntero en la posici<63>n dada por parametro
if Locate(CAMPO_POSICION, IntToStr(LocalizaPosicion), []) then
end;
end;
procedure TControllerDetallesBase.TratamientoDetalleConcepto(DataTable: TDADataTable);
begin
with DataTable do
begin
if not Editing then Edit;
//Si alguno de los campos de calculo de total es nulo el total tambien ser<65> nulo
if (VarIsNull(FieldByName(CAMPO_CANTIDAD).AsVariant)
or VarIsNull(FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant))
then FieldByName(CAMPO_IMPORTE_TOTAL).AsVariant := Null
else FieldByName(CAMPO_IMPORTE_TOTAL).AsFloat := CalcularImporteTotalConcepto(DataTable);
Post;
end;
end;
procedure TControllerDetallesBase.TratamientoDetalleSalto(DataTable: TDADataTable);
begin
with DataTable do
begin
if not Editing then Edit;
FieldByName(CAMPO_CONCEPTO).AsString := CTE_DESC_SALTO;
FieldByName(CAMPO_CANTIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_TOTAL).AsVariant := Null;
Post;
end;
end;
procedure TControllerDetallesBase.TratamientoDetalleSubtotal(DataTable: TDADataTable);
begin
with DataTable do
begin
if not Editing then Edit;
if (FieldByName(CAMPO_CONCEPTO).AsString = CTE_DESC_SALTO) then
FieldByName(CAMPO_CONCEPTO).AsVariant := Null;
FieldByName(CAMPO_CANTIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := Null;
Post;
end;
end;
procedure TControllerDetallesBase.TratamientoDetalleTitulo(DataTable: TDADataTable);
begin
with DataTable do
begin
if not Editing then Edit;
if (FieldByName(CAMPO_CONCEPTO).AsString = CTE_DESC_SALTO) then
FieldByName(CAMPO_CONCEPTO).AsVariant := Null;
FieldByName(CAMPO_CANTIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := Null;
FieldByName(CAMPO_IMPORTE_TOTAL).AsVariant := Null;
Post;
end;
end;
procedure TControllerDetallesBase.validarCampos(DataTable: TDADataTable);
var
AField: TDAField;
begin
//Validamos la existencia de todos los campos necesarios
AField := DataTable.FindField(CAMPO_POSICION);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (validarCampos)');
AField := DataTable.FindField(CAMPO_TIPO);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_TIPO + ' no encontrado (validarCampos)');
AField := DataTable.FindField(CAMPO_CANTIDAD);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_CANTIDAD + ' no encontrado (validarCampos)');
AField := DataTable.FindField(CAMPO_IMPORTE_UNIDAD);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_IMPORTE_UNIDAD + ' no encontrado (validarCampos)');
AField := DataTable.FindField(CAMPO_IMPORTE_TOTAL);
if not Assigned(AField) then
raise Exception.Create('Campo ' + CAMPO_IMPORTE_TOTAL + ' no encontrado (validarCampos)');
end;
end.