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 AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ADescuento: Float; const AAll: Boolean = False); overload; procedure QuitarPrecioDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = False); procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = True); 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: Float); virtual; procedure RellenarDetalle(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float = 1); virtual; procedure Add(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo; const ACantidad: Float = 1); overload; procedure AsignarController; virtual; public function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload; function AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; IDArticulo: Integer; AClienteID: Integer = -1; const ACantidad: Float = 1): Boolean; overload; procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; const ANuevaFila :Boolean = True); procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ADescuento: Float; const AAll: Boolean = False); overload; procedure QuitarPrecioDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = False); procedure CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean = True); 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: Float; 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 //Para mantener la cantidad que ya tuviera el detalle se debe guardar y volver a poner ACantidad := ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat; 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.ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ADescuento: Float; const AAll: Boolean = False); // AAll => True -> cambiar los descuento en todas los conceptos, False -> sólo en los conceptos con cantidades/importe var ACantidad: Float; ACambiar : Boolean; begin if Assigned(ADetalles) then begin BeginUpdate(ADetalles); try ADetalles.DataTable.First; with ADetalles.DataTable do begin while not EOF do begin ACambiar := True; if (ADetalles.DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_CONCEPTO) then begin if (not AAll) and (ADetalles.DataTable.FieldByName('CANTIDAD').IsNull and ADetalles.DataTable.FieldByName('IMPORTE_UNIDAD').IsNull) then ACambiar := False; if ACambiar then begin Edit; try // Cuando el descuento es 0, quitar cualquier valor en el campo. if (ADescuento <> 0) then ADetalles.DataTable.FieldByName('DESCUENTO').AsFloat := ADescuento else ADetalles.DataTable.FieldByName('DESCUENTO').Clear; except on E: Exception do ShowMessage(E.Message); end; end; 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: Float); 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, AClienteID: Integer; const ACantidad: Float): 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); 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.CambiarSignoDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean); 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 //Cambia el signo a todos if AAll then begin First; while not EOF do begin if (FieldByName(CAMPO_CANTIDAD).AsFloat <> 0) then begin Edit; FieldByName(CAMPO_CANTIDAD).AsFloat := (-1) * FieldByName(CAMPO_CANTIDAD).AsFloat; end; Next; end; end //Solo cambia el signo al seleccionado else begin if (FieldByName(CAMPO_CANTIDAD).AsFloat <> 0) then begin Edit; FieldByName(CAMPO_CANTIDAD).AsFloat := (-1) * FieldByName(CAMPO_CANTIDAD).AsFloat; end; 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; procedure TControllerDetallesArticulos.QuitarPrecioDetalles(ADetalles: IDAStronglyTypedDataTable; const AAll: Boolean); // AAll => True -> quita el precio de todas los conceptos, False -> sólo quita el precio en los conceptos con cantidades/importe var ACantidad: Float; ACambiar : Boolean; begin if Assigned(ADetalles) then begin BeginUpdate(ADetalles); try ADetalles.DataTable.First; with ADetalles.DataTable do begin while not EOF do begin ACambiar := True; if (ADetalles.DataTable.FieldByName(CAMPO_TIPO).AsString = TIPO_DETALLE_CONCEPTO) then begin if (not AAll) and (ADetalles.DataTable.FieldByName('CANTIDAD').IsNull and ADetalles.DataTable.FieldByName('IMPORTE_UNIDAD').IsNull) then ACambiar := False; if ACambiar then begin Edit; try ADetalles.DataTable.FieldByName('IMPORTE_UNIDAD').Clear; except on E: Exception do ShowMessage(E.Message); end; end; end; Next; end; //Volvemos a dejarlo al principio ADetalles.DataTable.First; end; finally EndUpdate(ADetalles); end; end; end; function TControllerDetallesArticulos.AnadirArticulo(ADetalles: IDAStronglyTypedDataTable; Referencia: String; TipoReferencia: TEnumReferencia; AClienteID: Integer = -1; const ACantidad: Float = 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: Float); begin if Assigned(ADetalles) then begin ADetalles.DataTable.FieldByName(CAMPO_CANTIDAD).AsFloat := 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: Float); 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.