unit uControllerDetallesArticulos; interface uses Classes, Variants, uDACDSDataTable, uDADataTable, uControllerDetallesBase, uBizArticulos, uArticulosController; const CAMPO_REFERENCIA = 'REFERENCIA'; //Campo ficticio CAMPO_REFERENCIA_PROVEEDOR = 'REFERENCIA_PROVEEDOR'; //Campo ficticio type TEnumReferencia = (tCliente, tProveedor); IControllerDetallesArticulos = interface(IControllerDetallesBase) ['{6E156796-DB1F-4727-BBFB-FBAEF2E5C098}'] procedure AsignarID(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer; AEsNuevo:Boolean); procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Integer = 1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Integer = 1): Boolean; overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable); procedure AnadirConceptoInicial(ADetalles: IDAStronglyTypedDataTable; AConcepto: String); end; TControllerDetallesArticulos = class (TControllerDetallesBase, IControllerDetallesArticulos) protected FArticulosController: IArticulosController; procedure EliminarArticulosProveedor(ADetalles: IDAStronglyTypedDataTable); procedure AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); virtual; procedure RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarGenerales(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); virtual; procedure RellenarCantidad(ADetalles: IDAStronglyTypedDataTable; const ACantidad: Integer); virtual; procedure RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Integer = 1); virtual; procedure Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Integer = 1); overload; procedure AsignarController; virtual; public procedure AsignarID(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer; AEsNuevo:Boolean); function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Integer = 1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Integer = 1): Boolean; overload; procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); 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 DB, Dialogs, cxControls, SysUtils, uDAInterfaces, uCalculosUtils, schArticulosClient_Intf; { TControllerDetallesArticulos } procedure TControllerDetallesArticulos.ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); var ACantidad: Integer; 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 begin ACantidad := ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsInteger; RellenarDetalle(ADetalles, AArticulos, ACantidad); end 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; const ACantidad: Integer); 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, ACantidad); Next; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; end; function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: 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, ACantidad); Result := True; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; procedure TControllerDetallesArticulos.AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); var AArticulos: IBizArticulo; begin if Assigned(ADetalles) then begin try AArticulos := (FArticulosController.BuscarTodos as IBizArticulo); //Si nueva fila es false, quiere decir que se sustituye un determinado artículo, por ello la lista a seleccionar no debe ser multiselect if ANuevaFila then begin AArticulos := FArticulosController.ElegirArticulos(AArticulos, 'Elija los artículos que desea añadir', True); Add(ADetalles, AArticulos) end else begin AArticulos := FArticulosController.ElegirArticulos(AArticulos, 'Elija el artículo que desea añadir', False); RellenarDetalle(ADetalles, AArticulos); end; 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) * FieldByName(CAMPO_CANTIDAD).AsInteger; 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; const ACantidad: 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, ACantidad); Result := True; end; end; finally EndUpdate(ADetalles); HideHourglassCursor; end; end; procedure TControllerDetallesArticulos.RellenarCantidad(ADetalles: IDAStronglyTypedDataTable; const ACantidad: Integer); begin if Assigned(ADetalles) then begin ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsInteger := ACantidad; end; end; procedure TControllerDetallesArticulos.RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin // Procedimiento que en los hijos se sobreescribirá para rellenar otros campos según necesidades end; procedure TControllerDetallesArticulos.RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Integer = 1); begin if Assigned(ADetalles) then begin BeginUpdate(ADetalles); try if not ADetalles.DataTable.Editing then ADetalles.DataTable.Edit; RellenarGenerales(ADetalles, AArticulos); RellenarCantidad(ADetalles, ACantidad); RellenarImportes(ADetalles, AArticulos); RellenarOtros(ADetalles, AArticulos); ADetalles.DataTable.Post; finally EndUpdate(ADetalles); end; 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; 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.