unit uDetallesFacturaClienteController; interface uses uDADataTable, uControllerDetallesArticulos, uBizDetallesFacturaCliente, uIDataModuleFacturasCliente, uBizContactos, uBizArticulos; type IDetallesFacturaClienteController = interface(IControllerDetallesArticulos) ['{D3942A48-C55B-4A98-AC5B-B5E652ED393E}'] procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente; const ANuevaFila :Boolean = True; const ACantidad: Integer = 1); overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente); procedure AnadirDetalleFacturaAsociadaAbono(ADetalles: IBizDetallesFacturaCliente; AReferencia: String; AFecha: String); procedure DesglosarPorteDetalles(ImportePorte: Currency; ADetalles: IDAStronglyTypedDataTable); function DarTotalPorteTotal(ADetalles: IDAStronglyTypedDataTable): Double; end; TDetallesFacturaClienteController = class(TControllerDetallesArticulos, IDetallesFacturaClienteController) private FDataModule : IDataModuleFacturasCliente; protected procedure AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); override; procedure RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); overload; override; procedure RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); override; procedure AsignarController; override; //Si sobreescribimos este método podremos tener en cuenta otras columnas para el calculo del importe total de un concepto function CalcularImporteTotalConcepto(DataTable: TDADataTable): Double; override; procedure ValidarCampos(DataTable: TDADataTable); override; procedure DesglosarPorteDetalles(ImportePorte: Currency; ADetalles: IDAStronglyTypedDataTable); function DarTotalPorteTotal(ADetalles: IDAStronglyTypedDataTable): Double; public procedure AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente; const ANuevaFila :Boolean = True; const ACantidad: Integer = 1); overload; procedure ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente); overload; //ABONOS procedure AnadirDetalleFacturaAsociadaAbono(ADetalles: IBizDetallesFacturaCliente; AReferencia: String; AFecha: String); constructor Create; override; destructor Destroy; override; end; implementation { TDetallesFacturaClienteController } uses Variants, uDataModuleFacturasCliente, uArticulosFacturaClienteController, uControllerDetallesBase, Dialogs, uDialogUtils, SysUtils, uCalculosUtils; procedure TDetallesFacturaClienteController.ActualizarDetalles(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente); var AArticulos : IBizArticulo; begin if Assigned(ADetalles) then begin try AArticulos := (FArticulosController.BuscarTodos(ACliente) as IBizArticulo); ActualizarDetalles(ADetalles, AArticulos); ShowInfoMessage('Se han actualizado los descuentos para el cliente seleccionado'); finally AArticulos := Nil; end; end; end; procedure TDetallesFacturaClienteController.AnadirArticulos(ADetalles: IDAStronglyTypedDataTable; ACliente: IBizCliente; const ANuevaFila :Boolean = True; const ACantidad: Integer = 1); var AArticulos: IBizArticulo; begin if Assigned(ADetalles) then begin try AArticulos := (FArticulosController.BuscarTodos(ACliente) 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 as IArticulosFacturaClienteController).ElegirArticulos(AArticulos, 'Elija los artículos que desea añadir a esta factura de cliente', True); Add(ADetalles, AArticulos, ACantidad) end else begin AArticulos := (FArticulosController as IArticulosFacturaClienteController).ElegirArticulos(AArticulos, 'Elija el artículo que desea añadir a esta factura de cliente', False); RellenarDetalle(ADetalles, AArticulos, ACantidad); end; finally AArticulos := Nil; end; end; end; procedure TDetallesFacturaClienteController.AnadirDetalleFacturaAsociadaAbono(ADetalles: IBizDetallesFacturaCliente; AReferencia: String; AFecha: String); begin AnadirConceptoInicial(ADetalles, 'ABONO DE FACTURA ' + AReferencia + ' con fecha ' + AFecha); end; procedure TDetallesFacturaClienteController.AsignarController; begin FArticulosController := TArticulosFacturaClienteController.Create; end; procedure TDetallesFacturaClienteController.AsignarDatos(ADetalles: IDAStronglyTypedDataTable; IDCabecera: Integer); begin inherited; with (ADetalles as IBizDetallesFacturaCliente) do begin Edit; ID := FDataModule.GetNextID(DataTable.LogicalName); ID_FACTURA := IDCabecera; Post end; end; {procedure TDetallesFacturaClienteController.AsignarID( ADetalles: IBizDetallesFacturaCliente; IDCabecera: Integer; EsNuevo: Boolean); begin with ADetalles do begin DataTable.DisableControls; try if not DataTable.Active then DataTable.Active := True; // AuxPosicion := POSICION; { ¡¡¡¡ 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 EsNuevo then begin while RecordCount > 0 do begin DataTable.First; Edit; ID := FDataModule.GetNextID(DataTable.LogicalName); ID_FACTURA := IDCabecera; Post end end else begin DataTable.First; while not DataTable.EOF do begin if ID < 0 then begin Edit; ID := FDataModule.GetNextID(DataTable.LogicalName); ID_FACTURA := IDCabecera; Post end; DataTable.Next end; end; finally DataTable.EnableControls; end; end; end;} function TDetallesFacturaClienteController.CalcularImporteTotalConcepto(DataTable: TDADataTable): Double; begin Result := CalcularLineaConcepto(DataTable); end; constructor TDetallesFacturaClienteController.Create; begin inherited; FDataModule := TDataModuleFacturasCliente.Create(Nil); end; function TDetallesFacturaClienteController.DarTotalPorteTotal(ADetalles: IDAStronglyTypedDataTable): Double; begin Result := DarTotalPorte(ADetalles); end; procedure TDetallesFacturaClienteController.DesglosarPorteDetalles(ImportePorte: Currency; ADetalles: IDAStronglyTypedDataTable); begin DesglosarPorte(ImportePorte, ADetalles); ActualizarTotales(ADetalles); end; destructor TDetallesFacturaClienteController.Destroy; begin FDataModule := Nil; inherited; end; procedure TDetallesFacturaClienteController.RellenarOtros(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if Assigned(AArticulos) then ADetalles.DataTable.FieldByName(CAMPO_DESCUENTO).AsFloat := AArticulos.DESCUENTO else ADetalles.DataTable.FieldByName(CAMPO_DESCUENTO).AsFloat := 0; end; procedure TDetallesFacturaClienteController.ValidarCampos(DataTable: TDADataTable); begin inherited; ValidarCamposLineaConcepto(DataTable); end; procedure TDetallesFacturaClienteController.RellenarImportes(ADetalles: IDAStronglyTypedDataTable; AArticulos: IBizArticulo); begin if Assigned(AArticulos) then ADetalles.DataTable.FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := AArticulos.PRECIO_COSTE else ADetalles.DataTable.FieldByName(CAMPO_IMPORTE_UNIDAD).AsVariant := Null; end; end.