unit uDetallesMontajeController; interface uses Classes, uDADataTable, uControllerDetallesBase, uBizMontajesDetalles, uIDataModuleMontajesDetalle; const CAMPO_DESCUENTO = 'DESCUENTO'; TIPO_DETALLE_DTO = 'Descuento'; type IDetallesMontajeController = interface(IControllerDetallesBase) ['{DDBC2C9F-3313-4C1B-9B20-931A64C5859D}'] procedure AsignarID(ADetalles: IBizDetallesMontaje; IDCabecera: Integer; AEsNuevo: Boolean); procedure AddCapitulo(ADataTable: IDAStronglyTypedDataTable); end; TDetallesMontajeController = class(TControllerDetallesBase, IDetallesMontajeController) protected FDataModule : IDataModuleMontajesDetalle; FImporteSubtotal: Double; procedure TratamientoDetalleDTO(DataTable: TDADataTable); virtual; procedure CalculoDetalleDTO(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); virtual; procedure TratamientoDetalleSalto(DataTable: TDADataTable); override; procedure TratamientoDetalleTitulo(DataTable: TDADataTable); override; procedure TratamientoDetalleSubtotal(DataTable: TDADataTable); override; procedure TratamientoDetalleConcepto(DataTable: TDADataTable); override; procedure validarCampos(DataTable: TDADataTable); override; procedure CalculoDetalleSubtotal(DataTable: TDADataTable; var ImporteAcumulado : Double; var ImporteTotal : Double); override; function CalcularTotalesHijos(Modificar: Boolean; DataTable: TDADataTable; var ImporteAcumulado: Double; var ImporteTotal: Double): Double; override; public procedure Move(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray; Posiciones: Integer); override; procedure Add(ADataTable: IDAStronglyTypedDataTable; TipoConcepto: Variant); override; procedure Delete(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray); override; procedure AddCapitulo(ADataTable: IDAStronglyTypedDataTable); procedure AsignarID(ADetalles: IBizDetallesMontaje; IDCabecera: Integer; AEsNuevo: Boolean); constructor Create; override; destructor Destroy; override; function DarListaTiposDetalle: TStringList; override; end; implementation uses SysUtils, uDAInterfaces, Variants, uDataModuleMontajesDetalle; { TDetallesMontajeController } procedure TDetallesMontajeController.Add(ADataTable: IDAStronglyTypedDataTable; TipoConcepto: Variant); var AuxNumOrden : Variant; begin //Sobreescribimos el método porque si añadimos teniendo el puntero en un registro //de tipo subtotal, comprobamos si tiene descuento para añadir el nuevo registro //despues de dicho concepto y no entre medias. //inherited; AuxNumOrden := Null; BeginUpdate(ADataTable); try with ADataTable do begin if not DataTable.IsEmpty then begin AuxNumOrden := DataTable.FieldByName(CAMPO_POSICION).AsVariant; if (getTipo(ADataTable, AuxNumOrden) = TIPO_DETALLE_SUBTOTAL) and (getTipo(ADataTable, (AuxNumOrden + 1)) = TIPO_DETALLE_DTO) then Inc(AuxNumOrden); end; AuxNumOrden := desplazarNPosiciones(DataTable, AuxNumOrden, 1); DataTable.Insert; DataTable.FieldByName(CAMPO_POSICION).AsInteger := AuxNumOrden; DataTable.FieldByName(CAMPO_TIPO).AsString := TipoConcepto; if (TipoConcepto = TIPO_DETALLE_TITULO) then DataTable.FieldByName(CAMPO_CONCEPTO).AsVariant := '{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Comic Sans MS;}}\viewkind4\uc1\pard\lang3082\ul\b\f0\fs20 Cap\''edtulo de ...\par}' else if (TipoConcepto = TIPO_DETALLE_SUBTOTAL) then DataTable.FieldByName(CAMPO_CONCEPTO).AsVariant := '{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Comic Sans MS;}{\f1\fnil Tahoma;}}\viewkind4\uc1\pard\lang3082\b\f0\fs20 Total cap\''edtulo de ...\b0\f1\fs16\par}' else if (TipoConcepto = TIPO_DETALLE_DTO) then DataTable.FieldByName(CAMPO_CONCEPTO).AsVariant := '{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Comic Sans MS;}{\f1\fnil Tahoma;}}\viewkind4\uc1\pard\lang3082\b\f0\fs20 Descuento especial ...\b0\f1\fs16\par}'; DataTable.post; end; finally EndUpdate(ADataTable); end; end; procedure TDetallesMontajeController.AddCapitulo(ADataTable: IDAStronglyTypedDataTable); begin BeginUpdate(ADataTable); try with ADataTable do begin Add(ADataTable, TIPO_DETALLE_TITULO); Add(ADataTable, TIPO_DETALLE_CONCEPTO); Add(ADataTable, TIPO_DETALLE_CONCEPTO); Add(ADataTable, TIPO_DETALLE_CONCEPTO); Add(ADataTable, TIPO_DETALLE_SUBTOTAL); Add(ADataTable, TIPO_DETALLE_DTO); end; finally EndUpdate(ADataTable); end; end; procedure TDetallesMontajeController.AsignarID(ADetalles: IBizDetallesMontaje; IDCabecera: Integer; AEsNuevo:Boolean); begin with ADetalles do begin DataTable.DisableControls; try if not DataTable.Active then DataTable.Active := True; { ¡¡¡¡ OJO !!!! Para asignar el ID en los detalles hay que tener en cuenta una cosa: Si se cambia el ID, ese detalle ya no pertenece a esa cabecera porque ya no se cumple la condición de la relacion: Master.ID = Detail.ID_MONTAJE. Por esa razón no sirve hacer un recorrido desde el principio hasta el final porque las detalles van desapareciendo según asignamos el valor al campo ID y nos mueve aleatoriamente la posición del registro actual. Es mejor hacer un bucle sencillo hasta que "se gasten" todos los detalles. Cuando el RecordCount llegue a 0 quiere decir que hemos tratado todos los detalles. El bucle cambia en el caso de ser llamada esta funcion desde modificar un montaje ya que en ese caso sí que hay que hacer un recorrido total de las tuplas de detalle. } if AEsNuevo then begin while RecordCount > 0 do begin DataTable.First; Edit; ID := FDataModule.GetNextID(DataTable.LogicalName); ID_MONTAJE := IDCabecera; Post end end else begin DataTable.First; while not DataTable.EOF do begin if not AEsNuevo then begin Edit; ID := FDataModule.GetNextID(DataTable.LogicalName); ID_MONTAJE := IDCabecera; Post end; DataTable.Next end; end; finally DataTable.EnableControls; end; end; end; function TDetallesMontajeController.CalcularTotalesHijos(Modificar: Boolean; DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double): Double; begin if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_DTO) then begin if Modificar then TratamientoDetalleDTO(DataTable); CalculoDetalleDTO(DataTable, ImporteAcumulado, ImporteTotal); end end; procedure TDetallesMontajeController.CalculoDetalleDTO(DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double); var ImporteDto: Double; begin ImporteDto := (-1)*((FImporteSubtotal * DataTable.FieldByName(CAMPO_DESCUENTO).AsFloat) / 100); with DataTable do begin if not Editing then Edit; FieldByName(CAMPO_IMPORTE_TOTAL).AsFloat := ImporteDto; Post; end; FImporteSubtotal := 0; ImporteTotal := ImporteTotal + ImporteDto; end; procedure TDetallesMontajeController.CalculoDetalleSubtotal( DataTable: TDADataTable; var ImporteAcumulado, ImporteTotal: Double); begin FImporteSubtotal := ImporteAcumulado; inherited; end; constructor TDetallesMontajeController.Create; begin inherited; FDataModule := TDataModuleMontajesDetalles.Create(Nil); FImporteSubtotal := 0; end; function TDetallesMontajeController.DarListaTiposDetalle: TStringList; begin Result := inherited DarListaTiposDetalle; Result.Values[TIPO_DETALLE_DTO] := 'Descuento'; end; procedure TDetallesMontajeController.Delete(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray); var i: integer; AField: TDAField; DeletePosicion: Integer; begin //inherited 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 for i := 0 to High(POSICION) do begin DataTable.First; DeletePosicion := POSICION[i]; if DataTable.Locate(CAMPO_POSICION, IntToStr(DeletePosicion), []) then begin if (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_SUBTOTAL) then begin DataTable.Delete; DataTable.First; if (DataTable.Locate(CAMPO_POSICION, IntToStr((DeletePosicion + 1)), [])) and (DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_DTO) then DataTable.Delete; end else DataTable.Delete; end; end; renumerar(DataTable, DeletePosicion); end; finally EndUpdate(ADataTable); end; end; destructor TDetallesMontajeController.Destroy; begin FDataModule := Nil; inherited; end; procedure TDetallesMontajeController.Move(ADataTable: IDAStronglyTypedDataTable; Posicion: TIntegerArray; Posiciones: Integer); var i:Integer; AField: TDAField; PosicionesAux: Integer; begin //Sobreescribimos el método porque en el caso de mover un concepto y ser un subtitulo //el concepto a intercambiar posición comprobamos si tiene descuento para desplazar dos unidades //el concepto a mover //inherited; AField := ADataTable.DataTable.FindField(CAMPO_POSICION); if not Assigned(AField) then raise Exception.Create('Campo ' + CAMPO_POSICION + ' no encontrado (Move Montajes controller)'); BeginUpdate(ADataTable); try with ADataTable do begin //Empezamos desde abajo if Posiciones > 0 then begin for i:= High(POSICION) downto 0 do begin if (getTipo(ADataTable, (POSICION[i]+1)) = TIPO_DETALLE_SUBTOTAL) and (getTipo(ADataTable, (POSICION[i]+2)) = TIPO_DETALLE_DTO) then begin Mover(DataTable, POSICION[i], Posiciones); Mover(DataTable, POSICION[i]+1, Posiciones) end else Mover(DataTable, POSICION[i], Posiciones); end; end else //Empezamos desde arriba for i:= 0 to High(POSICION) do begin if (getTipo(ADataTable, (POSICION[i]-1)) = TIPO_DETALLE_DTO) and (getTipo(ADataTable, (POSICION[i]-2)) = TIPO_DETALLE_SUBTOTAL) then begin Mover(DataTable, POSICION[i], Posiciones); Mover(DataTable, POSICION[i]-1, Posiciones) end else Mover(DataTable, POSICION[i], Posiciones); end; end; finally EndUpdate(ADataTable); end; end; procedure TDetallesMontajeController.TratamientoDetalleConcepto(DataTable: TDADataTable); begin inherited; with DataTable do begin if not Editing then Edit; FieldByName(CAMPO_DESCUENTO).AsVariant := Null; Post; end; end; procedure TDetallesMontajeController.TratamientoDetalleDTO(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 TDetallesMontajeController.TratamientoDetalleSalto(DataTable: TDADataTable); begin inherited; with DataTable do begin if not Editing then Edit; FieldByName(CAMPO_DESCUENTO).AsVariant := Null; Post; end; end; procedure TDetallesMontajeController.TratamientoDetalleSubtotal(DataTable: TDADataTable); begin inherited; with DataTable do begin if not Editing then Edit; FieldByName(CAMPO_DESCUENTO).AsVariant := Null; Post; end; end; procedure TDetallesMontajeController.TratamientoDetalleTitulo(DataTable: TDADataTable); begin inherited; with DataTable do begin if not Editing then Edit; FieldByName(CAMPO_DESCUENTO).AsVariant := Null; Post; end; end; procedure TDetallesMontajeController.validarCampos(DataTable: TDADataTable); var AField: TDAField; begin inherited; //Validamos la existencia de todos los campos necesarios AField := DataTable.FindField(CAMPO_DESCUENTO); if not Assigned(AField) then raise Exception.Create('Campo ' + CAMPO_DESCUENTO + ' no encontrado (validarCampos)'); end; end.