unit uBizImportesDetalleBase; interface uses uDAInterfaces, uDADataTable; const TIPODETALLE_CONCEPTO = 'C'; TIPODETALLE_TITULO = 'T'; TIPODETALLE_SUBTOTAL = 'S'; VISIBLE_TRUE = 'S'; VISIBLE_FALSE = 'N'; fld_NUMCONCEPTO = 'NUMCONCEPTO'; fld_POSICION = 'POSICION'; fld_TIPODETALLE = 'TIPO'; fld_IMPORTETOTAL = 'IMPORTETOTAL'; fld_CANTIDAD = 'CANTIDAD'; fld_IMPORTEUNIDAD = 'IMPORTEUNIDAD'; fld_VISIBLE = 'VISIBLE'; fld_DESCRIPCION = 'DESCRIPCION'; fld_PUNTOS = 'PUNTOS'; fld_IMPORTEPUNTOS = 'IMPORTEPUNTOS'; type { IMPORTANTE ********************************************************** PARCHE TEMPORAL -> Para evitar que se disparen los eventos de la clase de negocio cuando se hace el CancelUpdates de los detalles (se restaura la tabla a partir de los deltas y esto provoca que se disparen los eventos y se producen muchos fallos } IParche = interface ['{275F080F-054E-4E5A-BDF2-FE3494790388}'] procedure ActivarEventos; procedure DesactivarEventos; procedure Refrescar; function PuedoLanzarEvento : Boolean; end; IBizImportesDetalle = interface(IDAStronglyTypedDataTable) ['{16A36AC3-FABD-4809-A238-A806F1D02B95}'] procedure RecalcularImporte; function DarSumaTotalImportes : Currency; end; IBizPuntosDetalle = interface(IBizImportesDetalle) ['{72002878-BD11-4BB8-AB85-73E321A6D595}'] end; IBizVisibleDetalle = interface(IDAStronglyTypedDataTable) ['{6BA5B3BF-2E92-4465-A328-60F90F7EA3D2}'] end; TBizCantidadFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; TBizImporteUnidadFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; TBizTipoDetalleFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; TBizPuntosFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; TBizImportePuntosFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; TBizVisibleFieldRules = class(TDAFieldRules) protected procedure OnChange(Sender: TDACustomField); override; end; function DarMaximoNumConcepto(aDataTable : TDADataTable): integer; function DarMaximaPosicion(aDataTable : TDADataTable): integer; procedure IntercambiarPosiciones(aDataTable : TDADataTable; Pos1, Pos2 : Integer); procedure ReasignarPosiciones(aDataTable : TDADataTable); procedure AsignarPosicion(aDataTable : TDADataTable; IsAppend : Boolean); procedure AsignarNumConcepto(aDataTable : TDADataTable); procedure RecalcularImporteDetalle(aDataTable : TDADataTable; TieneSubtotales : Boolean; TienePuntos : Boolean); procedure RecalcularSubtotales(aDataTable : TDADataTable); function DarTotalDetalles(aDataTable : TDADataTable; TieneSubtotales : Boolean; TienePuntos : Boolean) : Currency; procedure RellenarImportePuntosEnCapitulo(aDataTable : TDADataTable); procedure RellenarVisibleEnCapitulo(aDataTable : TDADataTable); implementation uses SysUtils, DB, uBizImportesCabeceraBase, Controls, Forms, Dialogs, variants; procedure IntercambiarPosiciones(aDataTable : TDADataTable; Pos1, Pos2 : Integer); { Intercambia los valores del campo 'POSICION' de dos filas } var ABookmark : Pointer; AField : TDAField; AFieldTipo : TDAField; ACursor: TCursor; bRecalcularSubtotales : Boolean; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (IntercambiarPosicion)'); AField := aDataTable.FindField(fld_POSICION); if not Assigned(AField) then raise Exception.Create('Campo POSICION no encontrado (IntercambiarPosicion)'); // No importa si el TIPO no está en la lista de columnas AFieldTipo := aDataTable.FindField(fld_TIPODETALLE); if (aDataTable.State in dsEditModes) then aDataTable.Post; bRecalcularSubtotales := False; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; //aDataTable.DisableEventHandlers; <- No descomentar aDataTable.DisableControls; ABookmark := aDataTable.GetBookMark; try aDataTable.First; if aDataTable.Locate(fld_POSICION, Pos1, []) then begin // Si alguna de las dos filas es un subtotal, hay que recalcular todo if Assigned(AFieldTipo) and ((AFieldTipo.AsString = TIPODETALLE_SUBTOTAL) or (AFieldTipo.AsString = TIPODETALLE_TITULO)) then bRecalcularSubtotales := True; aDataTable.Edit; AField.AsInteger := 0; // Ponemos el 0 temporalmente aDataTable.Post; aDataTable.First; if aDataTable.Locate(fld_POSICION, Pos2, []) then begin // Si alguna de las dos filas es un subtotal, hay que recalcular todo if Assigned(AFieldTipo) and ((AFieldTipo.AsString = TIPODETALLE_SUBTOTAL) or (AFieldTipo.AsString = TIPODETALLE_TITULO)) then bRecalcularSubtotales := True; aDataTable.Edit; AField.AsInteger := Pos1; aDataTable.Post; aDataTable.First; aDataTable.Locate(fld_POSICION, 0, []); aDataTable.Edit; AField.AsInteger := Pos2; aDataTable.Post; end else raise Exception.Create('No se ha encontrado posición 2 (IntercambiarPosicion)'); end else raise Exception.Create('No se ha encontrado posición 1 (IntercambiarPosicion)'); finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; //aDataTable.EnableEventHandlers; <- No descomentar if bRecalcularSubtotales then RecalcularSubtotales(aDataTable); Screen.Cursor := ACursor; end; end; function DarMaximoNumConcepto(aDataTable : TDADataTable): integer; { Devuelve el valor máximo del campo 'NUMCONCEPTO' } var ABookmark : Pointer; AField : TDAField; ACursor: TCursor; begin Result := 0; if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (DarMaximoNumConcepto)'); if aDataTable.RecordCount < 1 then Exit; AField := aDataTable.FindField(fld_NUMCONCEPTO); if not Assigned(AField) then raise Exception.Create('Campo NUMCONCEPTO no encontrado (DarMaximoNumConcepto)'); ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; ABookmark := aDataTable.GetBookMark; try aDataTable.DisableControls; aDataTable.DisableEventHandlers; aDataTable.First; while not aDataTable.Eof do begin if AField.AsInteger > Result then Result := AField.AsInteger; aDataTable.Next; end; finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; aDataTable.EnableEventHandlers; Screen.Cursor := ACursor; end; end; function DarMaximaPosicion(aDataTable : TDADataTable): integer; { Devuelve el valor máximo del campo 'POSICION' } var ABookmark : Pointer; AField : TDAField; ACursor: TCursor; begin //Sort(['ForeignKeyFieldofMasterDetailRelation','YourSortField'],[sdAscending, NeededOrder ]); Result := 0; if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (DarMaximaPosicion)'); if aDataTable.RecordCount < 1 then Exit; AField := aDataTable.FindField(fld_POSICION); if not Assigned(AField) then raise Exception.Create('Campo POSICION no encontrado (DarMaximaPosicion)'); ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; ABookmark := aDataTable.GetBookMark; try aDataTable.DisableControls; aDataTable.DisableEventHandlers; aDataTable.First; while not aDataTable.Eof do begin if AField.AsInteger > Result then Result := AField.AsInteger; aDataTable.Next; end; finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; aDataTable.EnableEventHandlers; Screen.Cursor := ACursor; end; end; procedure ReasignarPosiciones(aDataTable : TDADataTable); { Recalcula el valor del campo 'POSICION' de todas las filas para eliminar huecos } var AField : TDAField; ABookmark : Pointer; Contador : Integer; NumCon : Integer; TotalConceptos : Integer; DetallesEditados : Integer; ACursor: TCursor; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (ReasignarNumConceptos)'); if aDataTable.RecordCount < 1 then Exit; AField := aDataTable.FindField(fld_POSICION); if not Assigned(AField) then raise Exception.Create('Campo POSICION no encontrado (ReasignarNumConceptos)'); Contador := 1; NumCon := 1; TotalConceptos := aDataTable.RecordCount; DetallesEditados := 0; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; ABookmark := aDataTable.GetBookMark; aDataTable.DisableControls; //aDataTable.DisableEventHandlers; <-- No descomentar try aDataTable.First; while DetallesEditados < TotalConceptos do begin if aDataTable.Locate(fld_POSICION, Contador, []) then begin aDataTable.Edit; AField.Value := NumCon; Inc(NumCon); aDataTable.Post; Inc(DetallesEditados); aDataTable.First; end; Inc(Contador); end; finally aDataTable.GotoBookmark(ABookmark); //aDataTable.EnableEventHandlers; <-- No descomentar aDataTable.EnableControls; Screen.Cursor := ACursor; end; end; procedure AsignarPosicion(aDataTable : TDADataTable; IsAppend : Boolean); { Calcula el valor del campo 'POSICION' para una fila nueva. Incrementa en 1 a las filas que estén por debajo de esa fila nueva } var AField : TDAField; ABookmark : Pointer; NumPosicion : Integer; MaxPosicion : Integer; ACursor: TCursor; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (AsignarPosicion)'); if aDataTable.RecordCount < 1 then Exit; AField := aDataTable.FindField(fld_POSICION); if not Assigned(AField) then raise Exception.Create('Campo POSICION no encontrado (AsignarPosicion)'); if not IsAppend then begin if not aDataTable.IsEmpty then begin ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; // Mover las filas que están por debajo de la actual MaxPosicion := DarMaximaPosicion(aDataTable); NumPosicion := (AField.AsInteger * (-1)); ABookmark := aDataTable.GetBookMark; try aDataTable.First; while aDataTable.Locate(fld_POSICION, MaxPosicion, []) do begin aDataTable.Edit; AField.Value := MaxPosicion + 1; aDataTable.Post; aDataTable.First; if MaxPosicion = NumPosicion then Break else Dec(MaxPosicion); end finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; Screen.Cursor := ACursor; end; end; NumPosicion := (AField.AsInteger * (-1)); end else begin if aDataTable.RecordCount > 1 then NumPosicion := DarMaximaPosicion(aDataTable) + 1 else // Sólo hay una fila en toda la tabla NumPosicion := (AField.AsInteger * (-1)); end; // Asignar posición a la nueva fila aDataTable.Edit; AField.Value := NumPosicion; aDataTable.Post; end; procedure AsignarNumConcepto(aDataTable : TDADataTable); { Asigna el valor del campo 'NUMCONCEPTO' para una fila nueva } var AField : TDAField; MaxConcepto : Integer; ACursor: TCursor; EnEdicion : Boolean; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (AsignarNumConcepto)'); if aDataTable.RecordCount < 1 then Exit; AField := aDataTable.FindField(fld_NUMCONCEPTO); if not Assigned(AField) then raise Exception.Create('Campo NUMCONCEPTO no encontrado (AsignarNumConcepto)'); // ¿Viene en modo edición? EnEdicion := (aDataTable.State in dsEditModes); MaxConcepto := DarMaximoNumConcepto(aDataTable); if not aDataTable.IsEmpty then begin ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; try if not EnEdicion then aDataTable.Edit; AField.AsInteger := MaxConcepto + 1; aDataTable.Post; if EnEdicion then aDataTable.Edit; finally Screen.Cursor := ACursor; aDataTable.EnableControls; end; end; end; procedure RecalcularImporteDetalle(aDataTable : TDADataTable; TieneSubtotales : Boolean; TienePuntos : Boolean); var TipoField : TDAField; TotalField : TDAField; CantidadField : TDAField; ImporteUnidadField : TDAField; PuntosField : TDAField; ImportePuntosField : TDAField; EnEdicion : Boolean; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (RecalcularImporteDetalle)'); if aDataTable.RecordCount < 1 then Exit; // ¿Viene en modo edición? EnEdicion := (aDataTable.State in dsEditModes); TotalField := aDataTable.FindField(fld_IMPORTETOTAL); if not Assigned(TotalField) then raise Exception.Create('Campo IMPORTETOTAL no encontrado (RecalcularImporteDetalle)'); CantidadField := aDataTable.FindField(fld_CANTIDAD); if not Assigned(CantidadField) then raise Exception.Create('Campo CANTIDAD no encontrado (RecalcularImporteDetalle)'); ImporteUnidadField := aDataTable.FindField(fld_IMPORTEUNIDAD); if not Assigned(ImporteUnidadField) then raise Exception.Create('Campo IMPORTEUNIDAD no encontrado (RecalcularImporteDetalle)'); if TienePuntos then begin PuntosField := aDataTable.FindField(fld_PUNTOS); if not Assigned(PuntosField) then raise Exception.Create('Campo PUNTOS no encontrado (RecalcularImporteDetalle)'); ImportePuntosField := aDataTable.FindField(fld_IMPORTEPUNTOS); if not Assigned(ImportePuntosField) then raise Exception.Create('Campo IMPORTEPUNTOS no encontrado (RecalcularImporteDetalle)'); end; if TieneSubtotales then begin TipoField := aDataTable.FindField(fld_TIPODETALLE); if not Assigned(TipoField) then raise Exception.Create('Campo TIPO no encontrado (RecalcularImporteDetalle)'); end; // if not EnEdicion then aDataTable.Edit; aDataTable.DisableEventHandlers; // Calcular el importe de la línea try if (TieneSubtotales) and ((TipoField.AsString = TIPODETALLE_SUBTOTAL) or (TipoField.AsString = TIPODETALLE_TITULO)) then begin CantidadField.Value := NULL; ImporteUnidadField.Value := NULL; TotalField.Value := NULL; if (TienePuntos) then begin PuntosField.Value := NULL; if (TipoField.AsString = TIPODETALLE_SUBTOTAL) then ImportePuntosField.Value := NULL; end; end else begin if TienePuntos and ((PuntosField.Value <> NULL) and (ImportePuntosField.Value <> NULL)) then ImporteUnidadField.Value := PuntosField.AsInteger * ImportePuntosField.AsCurrency; TotalField.Value := CantidadField.AsCurrency * ImporteUnidadField.AsCurrency; end; finally aDataTable.EnableEventHandlers; if not EnEdicion then aDataTable.Post; end; end; procedure RecalcularSubtotales(aDataTable : TDADataTable); { Recalcula el valor de todos los subtotales de la tabla } var ABookmark : Pointer; APosicion : Integer; MaxPos : Integer; Total : Currency; Subtotal : Currency; TipoField : TDAField; TotalField : TDAField; ACursor: TCursor; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (RecalcularTodosSubtotales)'); if aDataTable.RecordCount < 1 then Exit; TipoField := aDataTable.FindField(fld_TIPODETALLE); if not Assigned(TipoField) then raise Exception.Create('Campo TIPO no encontrado (RecalcularTodosSubtotales)'); TotalField := aDataTable.FindField(fld_IMPORTETOTAL); if not Assigned(TotalField) then raise Exception.Create('Campo IMPORTETOTAL no encontrado (RecalcularTodosSubtotales)'); ABookmark := aDataTable.GetBookMark; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; // aDataTable.DisableEventHandlers; <- No descomentar if (aDataTable.State in dsEditModes) then aDataTable.Post; APosicion := 1; Total := 0; Subtotal := 0; try MaxPos := DarMaximaPosicion(aDataTable); while (APosicion <= MaxPos) do begin aDataTable.First; if aDataTable.Locate(fld_POSICION, APosicion, []) then begin if (TipoField.AsString = TIPODETALLE_TITULO) then Subtotal := 0 else if (TipoField.AsString = TIPODETALLE_SUBTOTAL) then begin try aDataTable.Edit; TotalField.Value := SubTotal; aDataTable.Post; Total := Total + SubTotal; Subtotal := 0; except on E : Exception do ShowMessage(E.Message); end; end else begin Subtotal := Subtotal + TotalField.AsCurrency; if (APosicion = MaxPos) then Total := Total + SubTotal; end; Inc(APosicion); end else Break; end; finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; // aDataTable.EnableEventHandlers; <- No descomentar Screen.Cursor := ACursor; end; end; function DarTotalDetalles(aDataTable : TDADataTable; TieneSubtotales : Boolean; TienePuntos : Boolean) : Currency; { Calcula el total de todos los detalles a partir del importe total de cada uno } var EnEdicion : Boolean; ABookmark : Pointer; APosicion : Integer; MaxPos : Integer; Total : Currency; Subtotal : Currency; TipoField : TDAField; TotalField : TDAField; ACursor: TCursor; begin Result := 0; if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (DarTotalDetalles)'); if aDataTable.RecordCount < 1 then Exit; if TieneSubtotales then begin TipoField := aDataTable.FindField(fld_TIPODETALLE); if not Assigned(TipoField) then raise Exception.Create('Campo TIPO no encontrado (DarTotalDetalles)'); end; TotalField := aDataTable.FindField(fld_IMPORTETOTAL); if not Assigned(TotalField) then raise Exception.Create('Campo IMPORTETOTAL no encontrado (DarTotalDetalles)'); ABookmark := aDataTable.GetBookMark; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; // aDataTable.DisableEventHandlers; <- No descomentar // ¿Viene en modo edición? EnEdicion := (aDataTable.State in dsEditModes); if EnEdicion then aDataTable.Post; APosicion := 1; Total := 0; Subtotal := 0; try MaxPos := DarMaximaPosicion(aDataTable); while (APosicion <= MaxPos) do begin aDataTable.First; if aDataTable.Locate(fld_POSICION, APosicion, []) then begin if TieneSubtotales and (TipoField.AsString = TIPODETALLE_SUBTOTAL) then begin Total := Total + SubTotal; Subtotal := 0; end else begin Subtotal := Subtotal + TotalField.AsCurrency; if (APosicion = MaxPos) then Total := Total + SubTotal; end; Inc(APosicion); end else Break; end; finally Result := Total; aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; // aDataTable.EnableEventHandlers; <- No descomentar if EnEdicion then aDataTable.Edit; Screen.Cursor := ACursor; end; end; procedure RellenarImportePuntosEnCapitulo(aDataTable : TDADataTable); { Rellena el importe de puntos a todos los conceptos de un capítulo. El cursor está puesto en la fila que es el título. } var ABookmark : Pointer; APosicion : Integer; MaxPos : Integer; ImportePuntos : Currency; TipoField : TDAField; PosicionField : TDAField; ImportePuntosField : TDAField; ACursor: TCursor; EnEdicion : Boolean; ADetalle : IBizImportesDetalle; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (RellenarImportePuntosEnCapitulo)'); if aDataTable.RecordCount < 1 then Exit; if not Supports(aDataTable, IBizImportesDetalle, ADetalle) then raise Exception.Create('La tabla no soporta la interfaz requerida (RellenarImportePuntosEnCapitulo)'); PosicionField := aDataTable.FindField(fld_POSICION); if not Assigned(PosicionField) then raise Exception.Create('Campo POSICION no encontrado (RellenarImportePuntosEnCapitulo)'); TipoField := aDataTable.FindField(fld_TIPODETALLE); if not Assigned(TipoField) then raise Exception.Create('Campo TIPO no encontrado (RellenarImportePuntosEnCapitulo)'); ImportePuntosField := aDataTable.FindField(fld_IMPORTEPUNTOS); if not Assigned(ImportePuntosField) then raise Exception.Create('Campo IMPORTEPUNTOS no encontrado (RellenarImportePuntosEnCapitulo)'); ABookmark := aDataTable.GetBookMark; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; EnEdicion := (aDataTable.State in dsEditModes); if EnEdicion then aDataTable.Post; APosicion := PosicionField.Value + 1; // La posición siguiente a la fila de TITULO ImportePuntos := aDataTable.FindField(fld_IMPORTEPUNTOS).AsCurrency; // Importe de puntos de la fila de TITULO try MaxPos := DarMaximaPosicion(aDataTable); while (APosicion <= MaxPos) do begin if aDataTable.Locate(fld_POSICION, APosicion, []) then begin if (TipoField.AsString = TIPODETALLE_CONCEPTO) then begin aDataTable.Edit; aDataTable.DisableEventHandlers; // Para que no salten otros eventos try ImportePuntosField.AsCurrency := ImportePuntos; ADetalle.RecalcularImporte; finally aDataTable.EnableEventHandlers; end; aDataTable.Post; Inc(APosicion); end else break; // Es una fila de SUBTOTAL o de TITULO end else raise Exception.Create('Hay un hueco en la numeración de posiciones'); end; finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; Screen.Cursor := ACursor; if EnEdicion then aDataTable.Edit; end; end; procedure RellenarVisibleEnCapitulo(aDataTable : TDADataTable); { Rellena VISIBLE de todos los conceptos de un capítulo. El cursor está puesto en la fila que es el título. } var ABookmark : Pointer; APosicion : Integer; MaxPos : Integer; TipoField : TDAField; PosicionField : TDAField; VisibleField : TDAField; ACursor: TCursor; EnEdicion : Boolean; EsVisible : String; begin if not Assigned(aDataTable) then raise Exception.Create('Tabla no asignada (RellenarVisibleEnCapitulo)'); if aDataTable.RecordCount < 1 then Exit; PosicionField := aDataTable.FindField(fld_POSICION); if not Assigned(PosicionField) then raise Exception.Create('Campo POSICION no encontrado (RellenarVisibleEnCapitulo)'); TipoField := aDataTable.FindField(fld_TIPODETALLE); if not Assigned(TipoField) then raise Exception.Create('Campo TIPO no encontrado (RellenarVisibleEnCapitulo)'); VisibleField := aDataTable.FindField(fld_VISIBLE); if not Assigned(VisibleField) then raise Exception.Create('Campo VISIBLE no encontrado (RellenarVisibleEnCapitulo)'); ABookmark := aDataTable.GetBookMark; ACursor := Screen.Cursor; Screen.Cursor := crHourGlass; aDataTable.DisableControls; EnEdicion := (aDataTable.State in dsEditModes); if EnEdicion then aDataTable.Post; APosicion := PosicionField.Value + 1; // La posición siguiente a la fila de TITULO EsVisible := VisibleField.AsString; // Valor de VISIBLE de la fila de TITULO try MaxPos := DarMaximaPosicion(aDataTable); while (APosicion <= MaxPos) do begin if aDataTable.Locate(fld_POSICION, APosicion, []) then begin if (TipoField.AsString = TIPODETALLE_CONCEPTO) then begin aDataTable.Edit; aDataTable.DisableEventHandlers; // Para que no salten otros eventos try VisibleField.AsString := EsVisible; finally aDataTable.EnableEventHandlers; end; aDataTable.Post; Inc(APosicion); end else break; // Es una fila de SUBTOTAL o de TITULO end else raise Exception.Create('Hay un hueco en la numeración de posiciones'); end; finally aDataTable.GotoBookmark(ABookmark); aDataTable.EnableControls; Screen.Cursor := ACursor; if EnEdicion then aDataTable.Edit; end; end; { TBizCantidadFieldRules } procedure TBizCantidadFieldRules.OnChange(Sender: TDACustomField); var aDetalle : IBizImportesDetalle; aCabecera : IBizImportesCabecera; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if Supports(DataTable, IBizImportesDetalle, aDetalle) then begin if Sender.Value = 0 then Sender.Value := Null; aDetalle.RecalcularImporte; RecalcularSubtotales(aDetalle.DataTable); if Assigned(aDetalle.DataTable.MasterSource) and Supports(aDetalle.DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then ACabecera.RecalcularImporte; end; end; procedure TBizImporteUnidadFieldRules.OnChange(Sender: TDACustomField); var aDetalle : IBizImportesDetalle; aCabecera : IBizImportesCabecera; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if Supports(DataTable, IBizImportesDetalle, aDetalle) then begin if Sender.Value = 0 then Sender.Value := Null; aDetalle.RecalcularImporte; RecalcularSubtotales(aDetalle.DataTable); if Assigned(aDetalle.DataTable.MasterSource) and Supports(aDetalle.DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then ACabecera.RecalcularImporte; end; end; procedure TBizTipoDetalleFieldRules.OnChange(Sender: TDACustomField); var aDetalle : IBizImportesDetalle; aCabecera : IBizImportesCabecera; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if (Sender.AsString = TIPODETALLE_SUBTOTAL) or (Sender.AsString = TIPODETALLE_TITULO) then if Supports(DataTable, IBizImportesDetalle, aDetalle) then begin aDetalle.RecalcularImporte; RecalcularSubtotales(aDetalle.DataTable); if Assigned(aDetalle.DataTable.MasterSource) and Supports(aDetalle.DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then ACabecera.RecalcularImporte; end; end; procedure TBizPuntosFieldRules.OnChange(Sender: TDACustomField); var aDetalle : IBizPuntosDetalle; aCabecera : IBizImportesCabecera; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if Supports(DataTable, IBizPuntosDetalle, aDetalle) then begin if Sender.Value = 0 then Sender.Value := Null; aDetalle.RecalcularImporte; RecalcularSubtotales(aDetalle.DataTable); if Assigned(aDetalle.DataTable.MasterSource) and Supports(aDetalle.DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then ACabecera.RecalcularImporte; end; end; procedure TBizImportePuntosFieldRules.OnChange( Sender: TDACustomField); var aDetalle : IBizPuntosDetalle; aCabecera : IBizImportesCabecera; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if Supports(DataTable, IBizPuntosDetalle, aDetalle) then begin if Sender.Value = 0 then Sender.Value := Null; aDetalle.RecalcularImporte; if Assigned(aDetalle.DataTable.FindField(fld_TIPODETALLE)) then if (aDetalle.DataTable.FindField(fld_TIPODETALLE).AsString = TIPODETALLE_TITULO) then RellenarImportePuntosEnCapitulo(aDetalle.DataTable); RecalcularSubtotales(aDetalle.DataTable); if Assigned(aDetalle.DataTable.MasterSource) and Supports(aDetalle.DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then ACabecera.RecalcularImporte; end; end; { TBizVisibleFieldRules } procedure TBizVisibleFieldRules.OnChange(Sender: TDACustomField); var aDetalle : IBizVisibleDetalle; aParche : IParche; begin inherited; { PARCHE ********************************** } if Supports(DataTable, IParche, aParche) and not (aParche.PuedoLanzarEvento) then Exit; if Supports(DataTable, IBizVisibleDetalle, aDetalle) then begin if Assigned(aDetalle.DataTable.FindField(fld_TIPODETALLE)) then if (aDetalle.DataTable.FindField(fld_TIPODETALLE).AsString = TIPODETALLE_TITULO) then RellenarVisibleEnCapitulo(aDetalle.DataTable); end; end; initialization RegisterFieldRules('Client.Field.Cantidad', TBizCantidadFieldRules); RegisterFieldRules('Client.Field.ImporteUnidad', TBizImporteUnidadFieldRules); RegisterFieldRules('Client.Field.TipoDetalle', TBizTipoDetalleFieldRules); RegisterFieldRules('Client.Field.ImportePuntos', TBizImportePuntosFieldRules); RegisterFieldRules('Client.Field.Puntos', TBizPuntosFieldRules); RegisterFieldRules('Client.Field.Visible', TBizVisibleFieldRules); finalization end.