unit uControllerDetallesArticulos; interface uses Classes, Variants, uDACDSDataTable, uDADataTable, uControllerDetallesDTO, uBizArticulos, uArticulosController; const CAMPO_ID_ARTICULOS = 'ID_ARTICULO'; CAMPO_REFERENCIA = 'REFERENCIA'; //Campo ficticio CAMPO_REFERENCIA_PROVEEDOR = 'REFERENCIA_PROVEEDOR'; //Campo ficticio type TEnumReferencia = (tCliente, tProveedor); IControllerDetallesArticulos = interface(IControllerDetallesDTO) ['{6E156796-DB1F-4727-BBFB-FBAEF2E5C098}'] procedure AsignarID(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer; AEsNuevo:Boolean); procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable); function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1): Boolean; overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable); procedure AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String); end; TControllerDetallesArticulos = class (TControllerDetallesDTO, IControllerDetallesArticulos) protected FArticulosController: IArticulosController; procedure EliminarArticulosProveedor(ADetalles: IDAStronglyTypedDataTable); procedure RellenarDescuento(ADetalles: IDAStronglyTypedDataTable; ADescuento : Float); procedure AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); virtual; procedure RellenarDescuentos(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarGenerales(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); overload; procedure AsignarController; virtual; public procedure AsignarID(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer; AEsNuevo:Boolean); function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1): Boolean; overload; procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable); virtual; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable); procedure AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String); constructor Create; override; destructor Destroy; override; end; implementation { TControllerDetallesArticulos } uses Dialogs, cxControls, SysUtils, uDAInterfaces, uControllerDetallesBase, schArticulosClient_Intf; { TControllerDetallesArticulos } procedure TControllerDetallesArticulos.ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if (Assigned(ADetalles) and Assigned(AArticulos)) then begin if not AArticulos.DataTable.Active then AArticulos.DataTable.Active := True; BeginUpdate(ADetalles); try ADetalles.DataTable.First; with ADetalles.DataTable do begin while not Eof do begin Edit; AArticulos.DataTable.First; try if AArticulos.DataTable.Locate(CAMPO_ID, FieldByName(CAMPO_ID_ARTICULOS).AsVariant, []) then RellenarDetalle(ADetalles, AArticulos) else RellenarDetalle(ADetalles, Nil); except on E: Exception do ShowMessage(E.Message); end; Next; end; //Volvemos a dejarlo al principio ADetalles.DataTable.First; end; finally EndUpdate(ADetalles); end; end; end; procedure TControllerDetallesArticulos.Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if Assigned(ADetalles) and Assigned(AArticulos) then begin try ShowHourglassCursor; BeginUpdate(ADetalles); if not ADetalles.DataTable.Active then ADetalles.DataTable.Active := True; if not AArticulos.DataTable.Active then AArticulos.DataTable.Active := True; with AArticulos.DataTable do begin First; while not EOF do begin Self.Add(ADetalles, TIPO_DETALLE_CONCEPTO); RellenarDetalle(ADetalles, AArticulos); Next; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; end; function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1): Boolean; var AArticulo: IBizArticulo; begin { Añade el artículo con la referencia pasada por parametro a los detalles pasados por parametro En el caso de asignar un AClienteID el articulo debe contener el descuento para ese cliente } Result := False; BeginUpdate(ADetalles); ShowHourglassCursor; try AArticulo := FArticulosController.Buscar(IDArticulo, AClienteID); if Assigned(AArticulo) then begin AArticulo.DataTable.Active := True; if (AArticulo.RecordCount > 0) then begin RellenarDetalle(ADetalles, AArticulo); Result := True; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; procedure TControllerDetallesArticulos.AnadirArticulos(ADetalles: IDAStronglyTypedDataTable); var AArticulos: IBizArticulo; begin if Assigned(ADetalles) then begin try AArticulos := (FArticulosController.BuscarTodos as IBizArticulo); AArticulos := FArticulosController.ElegirArticulos(AArticulos, 'Elija los artículos que desea añadir', True); Add(ADetalles, AArticulos); finally AArticulos := Nil; end; end; end; procedure TControllerDetallesArticulos.AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String); begin if Assigned(ADetalles) then begin With ADetalles.DataTable do begin First; Add(ADetalles, TIPO_DETALLE_TITULO); Edit; FieldByName(CAMPO_CONCEPTO).AsString := AConcepto; Post; //Subimos la linea insertada al inicio de los detalles Self.Mover(ADetalles.DataTable, 1, -1); //Añadimos linea en blanco Add(ADetalles, TIPO_DETALLE_CONCEPTO); Edit; FieldByName(CAMPO_CONCEPTO).AsString := ''; Post; // First; end; end; end; procedure TControllerDetallesArticulos.AsignarController; begin FArticulosController := TArticulosController.Create; end; procedure TControllerDetallesArticulos.AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); begin // end; procedure TControllerDetallesArticulos.AsignarID(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer; AEsNuevo: Boolean); begin with ADetalles do begin DataTable.DisableControls; try begin 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_PRESUPUESTO. 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 presupuesto ya que en ese caso si que hay que hacer un recorrido total de las tuplas de detalle. } if AEsNuevo then begin while RecordCount > 0 do begin DataTable.First; AsignarDatos(ADetalles, IDCabecera); end end else begin DataTable.First; while not DataTable.EOF do begin if DataTable.FieldByName('ID').AsInteger < 0 then AsignarDatos(ADetalles, IDCabecera); DataTable.Next end; end; end; finally DataTable.EnableControls; end; end; end; procedure TControllerDetallesArticulos.CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable); begin //Cambia de signo los detalles de la pasados por parámetro if Assigned(ADetalles) then begin try BeginUpdate(ADetalles); if not ADetalles.DataTable.Active then ADetalles.DataTable.Active := True; with ADetalles.DataTable do begin First; while not EOF do begin if (FieldByName(CAMPO_CANTIDAD).AsInteger <> 0) then begin Edit; FieldByName(CAMPO_CANTIDAD).AsInteger := -1; end; Next; end; end; finally EndUpdate(ADetalles); end; end; end; constructor TControllerDetallesArticulos.Create; begin inherited; AsignarController; end; destructor TControllerDetallesArticulos.Destroy; begin FArticulosController := Nil; inherited; end; procedure TControllerDetallesArticulos.EliminarArticulosProveedor(ADetalles: IDAStronglyTypedDataTable); begin if Assigned(ADetalles) then begin with ADetalles.DataTable do begin First; while not Eof do if not FieldByName(CAMPO_ID_ARTICULOS).IsNull then Delete else Next; end; end; end; function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1): Boolean; var AArticulo: IBizArticulo; begin { Añade el artículo con la referencia pasada por parametro a los detalles pasados por parametro En el caso de asignar un AClienteID el articulo debe contener el descuento para ese cliente } Result := False; BeginUpdate(ADetalles); ShowHourglassCursor; try case TipoReferencia of tCliente: AArticulo := FArticulosController.BuscarReferencia(Referencia, AClienteID); tProveedor: AArticulo := FArticulosController.BuscarReferenciaProveedor(Referencia, AClienteID) end; if Assigned(AArticulo) then begin AArticulo.DataTable.Active := True; if (AArticulo.RecordCount > 0) then begin RellenarDetalle(ADetalles, AArticulo); Result := True; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; procedure TControllerDetallesArticulos.RellenarDescuento(ADetalles: IDAStronglyTypedDataTable; ADescuento: Float); begin ADetalles.DataTable.FieldByName(CAMPO_DESCUENTO).AsFloat := ADescuento; end; procedure TControllerDetallesArticulos.RellenarDescuentos(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin // Procedimiento que en los hijos se sobreescribirá para rellenar el campo descuento según necesidades end; procedure TControllerDetallesArticulos.RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if Assigned(ADetalles) then begin if not ADetalles.DataTable.Editing then ADetalles.DataTable.Edit; RellenarGenerales(ADetalles, AArticulos); RellenarImportes(ADetalles, AArticulos); RellenarDescuentos(ADetalles, AArticulos); ADetalles.DataTable.Post; end; end; procedure TControllerDetallesArticulos.RellenarGenerales(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if Assigned(AArticulos) then begin ADetalles.DataTable.FieldByName(CAMPO_ID_ARTICULOS).AsVariant := AArticulos.ID; ADetalles.DataTable.FieldByName(CAMPO_REFERENCIA).AsVariant := AArticulos.REFERENCIA; ADetalles.DataTable.FieldByName(CAMPO_REFERENCIA_PROVEEDOR).AsVariant := AArticulos.REFERENCIA_PROV; ADetalles.DataTable.FieldByName(CAMPO_CONCEPTO).AsVariant := AArticulos.DESCRIPCION; ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsInteger := 1; end; end; procedure TControllerDetallesArticulos.RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin // Procedimiento que en los hijos se sobreescribirá para rellenar el campo importe según necesidades end; end.