unit uAlbaranesProveedorController;

interface


uses
  SysUtils, uDADataTable, uEditorDBItem,
  uControllerBase, uIDataModuleAlbaranesProveedor, uProveedoresController,
  uDetallesAlbaranProveedorController, uBizAlbaranesProveedor,
  uBizDireccionesContacto, uBizInventario;

type
  IAlbaranesProveedorController = interface(IObservador)
  ['{E2FA2312-EDBD-4E80-B3D7-A8784F6A4E39}']
    function GetProveedorController: IProveedoresController;
    procedure SetProveedorController(const Value: IProveedoresController);
    property ProveedorController: IProveedoresController read GetProveedorController write SetProveedorController;

    function GetDetallesController: IDetallesAlbaranProveedorController;
    procedure SetDetallesController(const Value: IDetallesAlbaranProveedorController);
    property DetallesController: IDetallesAlbaranProveedorController read GetDetallesController write SetDetallesController;

    function Buscar(const ID: Integer): IBizAlbaranProveedor;
    function BuscarTodos: IBizAlbaranProveedor;
    function BuscarAlbaranesNormales: IBizAlbaranProveedor;
    function BuscarAlbaranesDevolucion: IBizAlbaranProveedor;
    function BuscarSinFacturar : IBizAlbaranProveedor;
    procedure Ver(AAlbaran : IBizAlbaranProveedor);
    procedure VerTodosAlbaranes(AAlbarans: IBizAlbaranProveedor);
    procedure VerTodosAlbaranesDev(AAlbarans: IBizAlbaranProveedor);
    procedure VerDireccionEntrega(AAlbaran : IBizAlbaranProveedor);
    function Nuevo : IBizAlbaranProveedor;
    function Anadir(AAlbaran : IBizAlbaranProveedor) : Boolean; overload;
    function AnadirAlbaranDev(AAlbaran : IBizAlbaranProveedor) : Boolean;
    function Anadir(AAlbaran : IBizAlbaranProveedor; const IDPedido : Integer; AInventarioRecibido: IBizInventario): Boolean; overload;

    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false): Boolean; overload;
    function Guardar(AAlbaran : IBizAlbaranProveedor): Boolean;
    procedure DescartarCambios(AAlbaran : IBizAlbaranProveedor);
    function Existe(const ID: Integer) : Boolean;
    function Duplicar(AAlbaran: IBizAlbaranProveedor): IBizAlbaranProveedor;

    function ExtraerSeleccionados(AAlbaran: IBizAlbaranProveedor) : IBizAlbaranProveedor;
    function ElegirAlbaranes(AAlbaran: IBizAlbaranProveedor; AMensaje: String; AMultiSelect: Boolean): IBizAlbaranProveedor;

    procedure CopiarDireccionEnvio (const ADireccionEnvio: IBizDireccionesContacto; AAlbaran: IBizAlbaranProveedor);
    procedure QuitarDireccionEnvio(AAlbaran: IBizAlbaranProveedor);
    procedure RecuperarProveedor(AAlbaran: IBizAlbaranProveedor);

    procedure RecalcularImportes(AAlbaran: IBizAlbaranProveedor);
    function EsModificable(AAlbaran: IBizAlbaranProveedor): Boolean;
    function EsEliminable(AAlbaran: IBizAlbaranProveedor): Boolean;

    procedure Preview(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false);
    procedure Print(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false);
  end;

  TAlbaranesProveedorController = class(TObservador, IAlbaranesProveedorController)
  protected
    FDataModule : IDataModuleAlbaranesProveedor;
    FProveedorController : IProveedoresController;
    FDetallesController : IDetallesAlbaranProveedorController;

    function GetProveedorController: IProveedoresController;
    procedure SetProveedorController(const Value: IProveedoresController);
    procedure RecuperarProveedor(AAlbaran : IBizAlbaranProveedor);
    function GetDetallesController: IDetallesAlbaranProveedorController;
    procedure SetDetallesController(const Value: IDetallesAlbaranProveedorController);

    //Estos son los tres métodos a sobre escribir si se desea heredar toda la logica de
    //este controller
    procedure AsignarDataModule; virtual;
    procedure RecuperarObjetos(AAlbaran: IBizAlbaranProveedor); virtual;

    procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override;
    procedure AsignarID(AAlbaran: IBizAlbaranProveedor; const IDNuevo : Integer);
    function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean;
    procedure FiltrarEmpresa(AAlbaran: IBizAlbaranProveedor);
    function _Vacio : IBizAlbaranProveedor;
    function ValidarAlbaran(AAlbaran: IBizAlbaranProveedor): Boolean;

  public
    property ProveedorController: IProveedoresController read GetProveedorController write SetProveedorController;
    property DetallesController: IDetallesAlbaranProveedorController read GetDetallesController write SetDetallesController;

    constructor Create; virtual;
    destructor Destroy; override;

    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false): Boolean; overload;
    function Guardar(AAlbaran : IBizAlbaranProveedor): Boolean;
    procedure DescartarCambios(AAlbaran : IBizAlbaranProveedor); virtual;
    function Existe(const ID: Integer) : Boolean; virtual;
    function Anadir(AAlbaran : IBizAlbaranProveedor) : Boolean; overload;
    function AnadirAlbaranDev(AAlbaran : IBizAlbaranProveedor) : Boolean;
    function Anadir(AAlbaran : IBizAlbaranProveedor; const IDPedido : Integer; AInventarioRecibido: IBizInventario): Boolean; overload;
    function Buscar(const ID: Integer): IBizAlbaranProveedor;
    function BuscarTodos: IBizAlbaranProveedor;
    function BuscarAlbaranesNormales: IBizAlbaranProveedor;
    function BuscarAlbaranesDevolucion: IBizAlbaranProveedor;
    function BuscarSinFacturar : IBizAlbaranProveedor;
    function Nuevo : IBizAlbaranProveedor;
    procedure Ver(AAlbaran : IBizAlbaranProveedor);
    procedure VerTodosAlbaranes(AAlbarans: IBizAlbaranProveedor);
    procedure VerTodosAlbaranesDev(AAlbarans: IBizAlbaranProveedor);
    procedure VerDireccionEntrega(AAlbaran : IBizAlbaranProveedor);
    function Duplicar(AAlbaran: IBizAlbaranProveedor): IBizAlbaranProveedor;
    procedure CopiarDireccionEnvio (const ADireccionEnvio: IBizDireccionesContacto;
      AAlbaran: IBizAlbaranProveedor);

    procedure QuitarDireccionEnvio(AAlbaran: IBizAlbaranProveedor);
    function ExtraerSeleccionados(AAlbaran: IBizAlbaranProveedor) : IBizAlbaranProveedor;
    function ElegirAlbaranes(AAlbaran: IBizAlbaranProveedor; AMensaje: String; AMultiSelect: Boolean): IBizAlbaranProveedor;

    procedure RecalcularImportes(AAlbaran: IBizAlbaranProveedor);
    function EsModificable(AAlbaran: IBizAlbaranProveedor): Boolean;
    function EsEliminable(AAlbaran: IBizAlbaranProveedor): Boolean;

    procedure Preview(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false);
    procedure Print(AAlbaran : IBizAlbaranProveedor; AllItems: Boolean = false);
  end;

implementation

uses
  uROTypes, Controls, cxControls, DB, uEditorRegistryUtils, uEditorPreview, DateUtils,
  uIEditorAlbaranesProveedor, uIEditorAlbaranesDevProveedor, uDataModuleAlbaranesProveedor,
  uBizDetallesAlbaranProveedor, uBizContactos, uDataTableUtils, uDataModuleUsuarios,
  schAlbaranesProveedorClient_Intf, uDAInterfaces, uDateUtils, uIEditorAlbaranProveedor,
  uIEditorElegirAlbaranesProveedor, uIEditorDireccionEntregaAlbaranProveedor,
  schContactosClient_Intf, Forms, schPedidosProveedorClient_Intf,
  uBizPedidosProveedor, uPedidosProveedorController, schInventarioClient_Intf,
  uArticulosController, uBizArticulos, uControllerDetallesBase, Classes,
  schArticulosClient_Intf, uControllerDetallesArticulos, Variants, uDialogUtils,
  uIEditorAlbaranDevProveedor, uAlbaranesProveedorReportController;


{ Métodos auxiliares }
procedure CopiarPedidoAAlbaran(APedido: IBizPedidoProveedor;
  AAlbaran : IBizAlbaranProveedor);
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (CopiarPedidoAAlbaran)');

  if not Assigned(APedido) then
    raise Exception.Create ('Pedido no asignado (CopiarPedidoAAlbaran)');

  if not APedido.DataTable.Active then
    APedido.DataTable.Active := True;

  // El albarán tiene que venir ya abierto y posicionado donde hay que copiar
  AAlbaran.ID_PROVEEDOR := APedido.ID_PROVEEDOR;
  AAlbaran.ID_PEDIDO := APedido.ID;
  AAlbaran.CALLE := APedido.CALLE;
  AAlbaran.CODIGO_POSTAL := APedido.CODIGO_POSTAL;
  AAlbaran.POBLACION := APedido.POBLACION;
  AAlbaran.PROVINCIA := APedido.PROVINCIA;
  AAlbaran.PERSONA_CONTACTO := APedido.PERSONA_CONTACTO;
  AAlbaran.TELEFONO := APedido.TELEFONO;
  AAlbaran.BASE_IMPONIBLE := APedido.BASE_IMPONIBLE;
  AAlbaran.IMPORTE_NETO := APedido.IMPORTE_NETO;
  AAlbaran.IMPORTE_PORTE := APedido.IMPORTE_PORTE;
  AAlbaran.IMPORTE_DESCUENTO := APedido.IMPORTE_DESCUENTO;
  AAlbaran.IMPORTE_IVA := APedido.IMPORTE_IVA;
  AAlbaran.IMPORTE_TOTAL := APedido.IMPORTE_TOTAL;
  AAlbaran.DESCUENTO := APedido.DESCUENTO;
  AAlbaran.IVA := APedido.IVA;
  AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorOBSERVACIONES).AsVariant := APedido.DataTable.FieldByName(fld_PedidosProveedorOBSERVACIONES).AsVariant;
  AAlbaran.ID_FORMA_PAGO := APedido.ID_FORMA_PAGO;
  AAlbaran.ID_ALMACEN := APedido.ID_ALMACEN;
end;

procedure CopiarArticulosAAlbaran(APedido: IBizPedidoProveedor; AAlbaran: IBizAlbaranProveedor;
    AInventarioRecibido: IBizInventario);
var
  i : integer;
  ADetalles : IBizDetallesAlbaranProveedor;
  ADetallesController : IDetallesAlbaranProveedorController;
  AArticulosController : IArticulosController;
  AArticulo : IBizArticulo;
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (CopiarArticulosAAlbaran)');

  if not Assigned(APedido) then
    raise Exception.Create ('Pedido no asignado (CopiarArticulosAAlbaran)');

  //Si esta asignado el inventario recibido es por una entrada de articulos de un pedido a almacén
  if Assigned(AInventarioRecibido) then
  begin
    if not AInventarioRecibido.DataTable.Active then
      AInventarioRecibido.DataTable.Active := True;

    // El albarán tiene que venir ya abierto y posicionado donde hay que copiar

    ADetalles := AAlbaran.Detalles;
    ADetallesController := TDetallesAlbaranProveedorController.Create;
    AArticulosController := TArticulosController.Create;
    try
      AInventarioRecibido.DataTable.First;
      for i := 0 to AInventarioRecibido.DataTable.RecordCount - 1 do
      begin
        AArticulo := AArticulosController.Buscar(AInventarioRecibido.ID_ARTICULO);
        if not Assigned(AArticulo) then
          raise Exception.Create(Format('No se ha encontrado el artículo con ID %d (CopiarArticulosAAlbaran)', [AInventarioRecibido.ID_ARTICULO]));

        if (AInventarioRecibido.CANTIDAD <> 0) then
        begin
          ADetallesController.Add(ADetalles, TIPO_DETALLE_CONCEPTO);
          ADetallesController.AnadirArticulo(ADetalles, AInventarioRecibido.REFERENCIA, tCliente);
          ADetalles.Edit;

          APedido.Detalles.First;
          if not APedido.Detalles.DataTable.Locate(fld_ArticulosREFERENCIA, ADetalles.REFERENCIA, []) then
             raise Exception.Create(Format('No se ha encontrado el artículo del pedido con REFERENCIA %s (CopiarArticulosAAlbaran)', [ADetalles.REFERENCIA]));
          ADetalles.IMPORTE_UNIDAD := APedido.Detalles.IMPORTE_UNIDAD;
          ADetalles.DESCUENTO := APedido.Detalles.DESCUENTO;
          ADetalles.IMPORTE_PORTE := APedido.Detalles.IMPORTE_PORTE;

          ADetalles.CANTIDAD := AInventarioRecibido.CANTIDAD;          
          ADetalles.Post;
        end;

        AInventarioRecibido.Next;
      end;

    finally
      ADetallesController := NIL;
      AArticulosController := NIL;
    end;
  end
  else begin
    // AInventarioRecibido = NIL

    // El albarán tiene que venir ya abierto y posicionado donde hay que copiar

    ADetalles := AAlbaran.Detalles;
    ADetallesController := TDetallesAlbaranProveedorController.Create;
    AArticulosController := TArticulosController.Create;
    try
      APedido.Detalles.DataTable.First;
      for i := 0 to APedido.Detalles.DataTable.RecordCount - 1 do
      begin
        AArticulo := AArticulosController.Buscar(APedido.Detalles.ID_ARTICULO);
        if not Assigned(AArticulo) then
          raise Exception.Create(Format('No se ha encontrado el artículo con ID %d (CopiarArticulosAAlbaran)', [APedido.Detalles.ID_ARTICULO]));

          if (APedido.Detalles.CANTIDAD <> 0) then
          begin
            ADetallesController.Add(ADetalles, TIPO_DETALLE_CONCEPTO);
            ADetallesController.AnadirArticulo(ADetalles, APedido.Detalles.REFERENCIA, tCliente);
            ADetalles.Edit;
            ADetalles.IMPORTE_UNIDAD := APedido.Detalles.IMPORTE_UNIDAD;
            ADetalles.DESCUENTO := APedido.Detalles.DESCUENTO;
            ADetalles.IMPORTE_PORTE := APedido.Detalles.IMPORTE_PORTE;
            ADetalles.CANTIDAD := APedido.Detalles.CANTIDAD;
            ADetalles.Post;
          end;
        APedido.Detalles.Next;
      end;
    finally
      ADetallesController := NIL;
      AArticulosController := NIL;
    end;
  end;
end;

{ TAlbaranesProveedorController }

function TAlbaranesProveedorController.Anadir(AAlbaran: IBizAlbaranProveedor) : Boolean;
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (Anadir)');

  if not AAlbaran.DataTable.Active then
    AAlbaran.DataTable.Active := True;

  AAlbaran.Insert;
  Result := True;
end;

function TAlbaranesProveedorController.Anadir(AAlbaran: IBizAlbaranProveedor;
  const IDPedido: Integer;
  AInventarioRecibido: IBizInventario): Boolean;
var
  APedidosController : TPedidosProveedorController;
  APedido : IBizPedidoProveedor;
begin
  Result := False;
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (Anadir)');

  if (IDPedido < 0) or (IDPedido = 0) then
    raise Exception.Create (Format('ID de pedido (%d) incorrecto (Anadir)', [IDPedido]));

  if not AAlbaran.DataTable.Active then
    AAlbaran.DataTable.Active := True;

  ShowHourglassCursor;
  Application.ProcessMessages;

  APedido := NIL;
  APedidosController := TPedidosProveedorController.Create;
  try
    APedido := APedidosController.Buscar(IDPedido);
    if not Assigned(APedido) then
      raise Exception.Create (Format('No se ha encontrado un pedido de proveedor con ID %d (Anadir)', [IDPedido]));

    APedido.DataTable.Active := True;

    if not Assigned(AInventarioRecibido) then
    begin
      if (APedido.ID_ALMACEN > 0) then
        raise Exception.Create ('Inventario recibido no asignado (Anadir)')
    end
    else begin
      if not AInventarioRecibido.DataTable.Active then
        AInventarioRecibido.DataTable.Active := True;
    end;

    Self.Anadir(AAlbaran);
    CopiarPedidoAAlbaran(APedido, AAlbaran);
    CopiarArticulosAAlbaran(APedido, AAlbaran, AInventarioRecibido);
    RecalcularImportes(AAlbaran);
    Result := True;
  finally
    APedido := NIL;
    APedidosController := NIL;
    HideHourglassCursor;
    Application.ProcessMessages;
  end;
end;

function TAlbaranesProveedorController.AnadirAlbaranDev(AAlbaran: IBizAlbaranProveedor): Boolean;
begin
  Result := Anadir(AAlbaran);
  AAlbaran.TIPO := CTE_TIPO_ALBARAN_DEV;
end;

procedure TAlbaranesProveedorController.AsignarDataModule;
begin
  FDataModule := TDataModuleAlbaranesProveedor.Create(Nil);
end;

procedure TAlbaranesProveedorController.AsignarID(AAlbaran: IBizAlbaranProveedor; const IDNuevo : Integer);
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado');

  if not Assigned(AAlbaran.Detalles) then
    raise Exception.Create ('Detalles de albarán no asignados');

  if not Assigned(FDetallesController) then
    raise Exception.Create ('Controller detalles no asignado');

  { Los detalles siempre hay que comprobarlos }
  FDetallesController.AsignarID(AAlbaran.Detalles, IDNuevo, AAlbaran.EsNuevo);

  if AAlbaran.EsNuevo then
  begin
    AAlbaran.Edit;
    AAlbaran.ID := IDNuevo;
    AAlbaran.Post;
  end;
end;

function TAlbaranesProveedorController.Buscar(const ID: Integer): IBizAlbaranProveedor;
begin
  Result := FDataModule.GetItem(ID);
  FiltrarEmpresa(Result);
end;

function TAlbaranesProveedorController.BuscarAlbaranesDevolucion: IBizAlbaranProveedor;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;
    with Result.DataTable.Where do
    begin
      if NotEmpty then
        AddOperator(opAND);
      OpenBraket;
      AddCondition(fld_AlbaranesProveedorIMPORTE_TOTAL, cLess, 0);
      CloseBraket;
    end;
  finally
    HideHourglassCursor;
  end;
end;

function TAlbaranesProveedorController.BuscarAlbaranesNormales: IBizAlbaranProveedor;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;
    with Result.DataTable.Where do
    begin
      if NotEmpty then
        AddOperator(opAND);
      OpenBraket;
      AddCondition(fld_AlbaranesProveedorIMPORTE_TOTAL, cMajorOrEqual, 0);
      CloseBraket;
    end;
  finally
    HideHourglassCursor;
  end;
end;

function TAlbaranesProveedorController.BuscarTodos: IBizAlbaranProveedor;
begin
  Result := FDataModule.GetItems;
  FiltrarEmpresa(Result);
end;

function TAlbaranesProveedorController.BuscarSinFacturar: IBizAlbaranProveedor;
begin
  ShowHourglassCursor;
  try
    Result := BuscarAlbaranesNormales;
    with Result.DataTable.Where do
    begin
      if NotEmpty then
        AddOperator(opAND);
      OpenBraket;
      AddText(fld_AlbaranesProveedorID_FACTURA + ' is null');
      CloseBraket;
    end;
  finally
    HideHourglassCursor;
  end;
end;

procedure TAlbaranesProveedorController.CopiarDireccionEnvio(
  const ADireccionEnvio: IBizDireccionesContacto; AAlbaran: IBizAlbaranProveedor);
var
  bEnEdicion : Boolean;
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albaran no asignado (CopiarDireccionEnvio)');

  if not Assigned(ADireccionEnvio) then
    raise Exception.Create ('No se ha indicado la dirección (CopiarDireccionEnvio)');

  if AAlbaran.DataTable.Active then
    AAlbaran.DataTable.Active := True;

  if ADireccionEnvio.DataTable.Active then
    ADireccionEnvio.DataTable.Active := True;


  bEnEdicion := (AAlbaran.DataTable.State in dsEditModes);
  if not bEnEdicion then
    AAlbaran.Edit;

  ShowHourglassCursor;
  AAlbaran.Edit;
  try
    AAlbaran.CALLE := ADireccionEnvio.CALLE;
    AAlbaran.POBLACION := ADireccionEnvio.POBLACION;
    AAlbaran.CODIGO_POSTAL := ADireccionEnvio.CODIGO_POSTAL;
    AAlbaran.PROVINCIA := ADireccionEnvio.PROVINCIA;
    AAlbaran.TELEFONO := ADireccionEnvio.TELEFONO;
    AAlbaran.PERSONA_CONTACTO := ADireccionEnvio.PERSONA_CONTACTO;

    if not bEnEdicion then
      AAlbaran.Post;
  finally
    HideHourglassCursor;
  end;
end;

constructor TAlbaranesProveedorController.Create;
begin
  AsignarDataModule;
  
  FProveedorController := TProveedoresController.Create;
  FDetallesController := TDetallesAlbaranProveedorController.Create;
  FDetallesController.addObservador(Self);
end;

function TAlbaranesProveedorController.CreateEditor(const AName: String;
  const IID: TGUID; out Intf): Boolean;
begin
  Result := Supports(EditorRegistry.CreateEditor(AName), IID, Intf);
end;

procedure TAlbaranesProveedorController.DescartarCambios(AAlbaran: IBizAlbaranProveedor);
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado');

  ShowHourglassCursor;
  try
    if (AAlbaran.State in dsEditModes) then
      AAlbaran.Cancel;

    AAlbaran.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TAlbaranesProveedorController.Destroy;
begin
  FDataModule := Nil;
  FProveedorController := Nil;
  FDetallesController := Nil;
  inherited;
end;

function TAlbaranesProveedorController.Duplicar(AAlbaran: IBizAlbaranProveedor): IBizAlbaranProveedor;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(AAlbaran.DataTable, Result.DataTable, mdrActual);
    DuplicarRegistros(AAlbaran.Detalles.DataTable, Result.Detalles.DataTable, mdrTodos);

    // Hay que dejar algunos campos como si fuera un presupuesto nuevo
    Result.Edit;
    with Result do
    begin
      ID_EMPRESA := dmUsuarios.IDEmpresaActual;
      USUARIO := dmUsuarios.LoginInfo.Usuario;
      FECHA_ALBARAN := DateOf(Now);
      INCIDENCIAS_ACTIVAS := 0;
      REFERENCIA := '';
      ID_PEDIDO := 0;
      ID_FACTURA := 0;
    end;
    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;

function TAlbaranesProveedorController.ValidarAlbaran(AAlbaran: IBizAlbaranProveedor): Boolean;
begin
  Result := False;

  if not Assigned(AAlbaran) then
     raise Exception.Create ('Albarán no asignado');

  if (AAlbaran.DataTable.State in dsEditModes) then
      AAlbaran.DataTable.Post;

  //Tambien hacemos post de sus tablas hija
  if (AAlbaran.Detalles.DataTable.State in dsEditModes) then
      AAlbaran.Detalles.DataTable.Post;

  if (AAlbaran.ID_PROVEEDOR < 0) or (AAlbaran.ID_PROVEEDOR = 0) then
  // Si hay altas automáticas no hay objeto Proveedor pero sí hay ID_PROVEEDOR
{     (not Assigned(AAlbaran.Proveedor)) or
     (AAlbaran.Proveedor.IsEmpty) then}
    raise Exception.Create('Debe indicar el proveedor de este albarán');

  if (EsFechaVacia(AAlbaran.FECHA_ALBARAN)) then
    raise Exception.Create('Debe indicar la fecha de este albarán');

  if (Length(AAlbaran.CALLE) = 0) and (AAlbaran.ID_ALMACEN = 0) then
    raise Exception.Create('Debe indicar una dirección de entrega o almacén para este albarán');

  //Tambien hacemos post de sus tablas hija
  if (AAlbaran.Detalles.DataTable.RecordCount = 0) then
    raise Exception.Create('El albarán de de tener al menos un concepto en su contenido');

  //En caso de ser un Albarán no podra tener un importe total negativo
  if (AAlbaran.TIPO = CTE_TIPO_ALBARAN) then
    if (AAlbaran.IMPORTE_TOTAL < 0) then
      raise Exception.Create('Un albarán no puede tener un importe total negativo');

  //En caso de ser una orden de devolución no podra tener un importe total positivo
  if (AAlbaran.TIPO = CTE_TIPO_ALBARAN_DEV) then
  begin
    if (AAlbaran.IMPORTE_TOTAL >= 0) then
      raise Exception.Create('Una orden de devolución no puede tener un importe total positivo');

    //Una orden de devolución debe tener relleno el almacén de salida de material
    if (AAlbaran.ID_ALMACEN < 0) or (AAlbaran.ID_ALMACEN = 0) then
      raise Exception.Create('Debe indicar el almacén de salida de esta orden de devolución');
  end;

  { Asegurarse de valores en campos "automáticos" tanto
    en MODIFICACIÓN como en INSERCIÓN. }
  AAlbaran.Edit;
  try
    AAlbaran.USUARIO := dmUsuarios.LoginInfo.Usuario;

    if Assigned(AAlbaran.Proveedor)
    and (AAlbaran.ID_PROVEEDOR <> AAlbaran.Proveedor.ID) then
      AAlbaran.ID_PROVEEDOR := AAlbaran.Proveedor.ID;

    Result := True;
  finally
    AAlbaran.Post;
  end;
end;

procedure TAlbaranesProveedorController.Ver(AAlbaran: IBizAlbaranProveedor);
var
  AEditor : IEditorDBItem;
begin
  AEditor := NIL;
  ShowHourglassCursor;
  try
    RecuperarObjetos(AAlbaran);

    if (AAlbaran.TIPO = CTE_TIPO_ALBARAN) then
        CreateEditor('EditorAlbaranProveedor', IEditorAlbaranProveedor, AEditor)
    else
        CreateEditor('EditorAlbaranDevProveedor', IEditorAlbaranDevProveedor, AEditor);

    if Assigned(AEditor) then
    with (AEditor as IEditorAlbaranProveedor) do
    begin
      Controller := Self; //OJO ORDEN MUY IMPORTANTE
      Albaran := AAlbaran;

      //MODO CONSULTAR
      if not EsModificable(AAlbaran) then
      begin
         SetDataTableReadOnly(AAlbaran.DataTable, True);
         ReadOnly := True;
      end;

      ShowModal;

      //MODO CONSULTAR (Se deja la tabla como estaba)
      if ReadOnly then
         SetDataTableReadOnly(AAlbaran.DataTable, False);

      AEditor.Release;
    end;
  finally
    AEditor := NIL;
    HideHourglassCursor;
  end;
end;

procedure TAlbaranesProveedorController.VerDireccionEntrega(AAlbaran: IBizAlbaranProveedor);
var
  AEditor : IEditorDireccionEntregaAlbaranProveedor;
begin
  AEditor := NIL;
  ShowHourglassCursor;
  try
    //RecuperarObjetos(AAlbaran); <- No descomentar. No hace falta
    CreateEditor('EditorDireccionEntregaAlbaranProveedor', IEditorDireccionEntregaAlbaranProveedor, AEditor);

    with (AEditor as IEditorDireccionEntregaAlbaranProveedor) do
    begin
      Albaran := AAlbaran;
    end;
  finally
    HideHourglassCursor;
  end;

  if Assigned(AEditor) then
    try
      AEditor.ShowModal;
      AEditor.Release;
    finally
      AEditor := NIL;
    end;
end;

procedure TAlbaranesProveedorController.VerTodosAlbaranes(AAlbarans: IBizAlbaranProveedor);
var
  AEditor : IEditorAlbaranesProveedor;
begin
  AEditor := NIL;
  ShowHourglassCursor;
  try
    CreateEditor('EditorAlbaranesProveedor', IEditorAlbaranesProveedor, AEditor);
    if Assigned(AEditor) then
      with AEditor do
      begin
        Controller := Self; //OJO ORDEN MUY IMPORTANTE
        Albaranes := AAlbarans;
        MultiSelect := True;
        ShowEmbedded;
      end;
  finally
    AEditor := NIL;
    HideHourglassCursor;
  end;
end;

procedure TAlbaranesProveedorController.VerTodosAlbaranesDev(AAlbarans: IBizAlbaranProveedor);
var
  AEditor : IEditorAlbaranesDevProveedor;
begin
  AEditor := NIL;
  ShowHourglassCursor;
  try
    CreateEditor('EditorAlbaranesDevProveedor', IEditorAlbaranesDevProveedor, AEditor);
    if Assigned(AEditor) then
      with AEditor do
      begin
        Controller := Self; //OJO ORDEN MUY IMPORTANTE
        Albaranes := AAlbarans;
        MultiSelect := True;
        ShowEmbedded;
      end;
  finally
    AEditor := NIL;
    HideHourglassCursor;
  end;
end;

function TAlbaranesProveedorController._Vacio: IBizAlbaranProveedor;
begin
  Result := Buscar(ID_NULO);
end;

function TAlbaranesProveedorController.Eliminar(const ID: Integer): Boolean;
var
  AAlbaran : IBizAlbaranProveedor;
begin
  AAlbaran := Buscar(ID);

  if not Assigned(AAlbaran) then
    raise Exception.Create(Format('No se ha encontrado el albarán con ID = %d', [ID]));

  Result := Eliminar(AAlbaran);
  AAlbaran := NIL;
end;

function TAlbaranesProveedorController.ElegirAlbaranes(AAlbaran: IBizAlbaranProveedor; AMensaje: String; AMultiSelect: Boolean): IBizAlbaranProveedor;
var
  AEditor : IEditorElegirAlbaranesProveedor;
begin
  Result := NIL;

  CreateEditor('EditorElegirAlbaranesProveedor', IEditorElegirAlbaranesProveedor, AEditor);
  try
    with AEditor do
    begin
      Controller := Self;
      Albaranes := AAlbaran;
      MultiSelect := AMultiSelect;
      Mensaje := AMensaje;
      if IsPositiveResult(ShowModal) then
        Result := AlbaranesProveedorSeleccionados;
	  Release;	
    end;
  finally
    AEditor := NIL;
  end;
end;

function TAlbaranesProveedorController.Eliminar(AAlbaran: IBizAlbaranProveedor; AllItems: Boolean = false): Boolean;
//En el caso de eliminar almenos un elemento del conjunto se devuelve true
var
  bEliminado: Boolean;

begin
  bEliminado := False;

  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignada');

  ShowHourglassCursor;
  try
    if (AAlbaran.State in dsEditModes) then
      AAlbaran.Cancel;

    //Siempre eliminaremos el seleccionado
    if EsEliminable(AAlbaran) then
    begin
      AAlbaran.Delete;
      bEliminado := True;
    end;

    //En el caso de querer eliminar todos los items del objeto AAlbaran
    if AllItems then
    begin
       with AAlbaran.DataTable do
       begin
         First;
         while not EOF do
         begin
           if EsEliminable(AAlbaran) then
           begin
              AAlbaran.Delete;
              bEliminado := True
           end
           else Next;
         end;
       end;
    end;

    if bEliminado then
    begin
       AAlbaran.DataTable.ApplyUpdates;
       Result := True;
    end
    else
       Result := False;

  finally
    HideHourglassCursor;
  end;
end;
function TAlbaranesProveedorController.EsEliminable(AAlbaran: IBizAlbaranProveedor): Boolean;
begin
  if not Assigned(AAlbaran) then
     raise Exception.Create ('Albarán no asignado: EsModificable');

  Result := EsModificable(AAlbaran);
end;

function TAlbaranesProveedorController.EsModificable(AAlbaran: IBizAlbaranProveedor): Boolean;
begin
  if not Assigned(AAlbaran) then
     raise Exception.Create ('Albarán no asignado: EsModificable');

  Result := not (AAlbaran.ID_FACTURA > 0);
end;

procedure TAlbaranesProveedorController.RecalcularImportes(
  AAlbaran: IBizAlbaranProveedor);
var
  bEnEdicion : Boolean;
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (RecalcularImportes)');

  if AAlbaran.DataTable.Active then
    AAlbaran.DataTable.Active := True;

  bEnEdicion := (AAlbaran.DataTable.State in dsEditModes);
  if not bEnEdicion then
    AAlbaran.Edit;

  ShowHourglassCursor;
  AAlbaran.Edit;
  try
    AAlbaran.IMPORTE_NETO := FDetallesController.DarTotalImporteTotal(AAlbaran.Detalles);
    if not bEnEdicion then
      AAlbaran.Post;
  finally
    HideHourglassCursor;
  end;
end;

procedure TAlbaranesProveedorController.RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable);
var
  AAlbaran : IBizAlbaranProveedor;
  ADetalles : IBizDetallesAlbaranProveedor;
begin
  inherited;

  if Supports(ADataTable, IBizDetallesAlbaranProveedor, ADetalles) and
     Supports(ADetalles.DataTable.MasterSource.DataTable, IBizAlbaranProveedor, AAlbaran) then
  begin
    RecalcularImportes(AAlbaran);
  end;
end;

procedure TAlbaranesProveedorController.RecuperarObjetos(AAlbaran: IBizAlbaranProveedor);
begin
  RecuperarProveedor(AAlbaran);
end;

procedure TAlbaranesProveedorController.RecuperarProveedor(AAlbaran: IBizAlbaranProveedor);
begin
  AAlbaran._Proveedor := (FProveedorController.Buscar(AAlbaran.ID_PROVEEDOR)  as IBizProveedor);
end;

function TAlbaranesProveedorController.Existe(const ID: Integer): Boolean;
var
  AAlbaran : IBizAlbaranProveedor;
begin
  try
    AAlbaran := Buscar(ID);
    Result := Assigned(AAlbaran) and (AAlbaran.ID = ID);
  finally
    AAlbaran := NIL;
  end;
end;

function TAlbaranesProveedorController.ExtraerSeleccionados(AAlbaran: IBizAlbaranProveedor): IBizAlbaranProveedor;
var
  ASeleccionados : IBizAlbaranProveedor;
begin
  ASeleccionados := (Self.Buscar(ID_NULO) as IBizAlbaranProveedor);
  CopyDataTable(AAlbaran.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TAlbaranesProveedorController.FiltrarEmpresa(
  AAlbaran: IBizAlbaranProveedor);
begin
  if AAlbaran.DataTable.Active then
     AAlbaran.DataTable.Active := False;

  // Filtrar los presupuestos actuales por empresa
  with AAlbaran.DataTable.Where do
  begin
    if NotEmpty then
       AddOperator(opAND);
    AddCondition(fld_AlbaranesProveedorID_EMPRESA, cEqual, dmUsuarios.IDEmpresaActual);
  end;
end;

procedure TAlbaranesProveedorController.SetProveedorController(const Value: IProveedoresController);
begin
  FProveedorController := Value;
end;

procedure TAlbaranesProveedorController.SetDetallesController(const Value: IDetallesAlbaranProveedorController);
begin
  FDetallesController := Value;
end;

function TAlbaranesProveedorController.Guardar(AAlbaran: IBizAlbaranProveedor): Boolean;
var
  IDNuevo: Integer;
begin
  Result := False;

  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignada');

  if not Assigned(FDetallesController) then
    raise Exception.Create ('Controller detalles no asignado');

  if ValidarAlbaran(AAlbaran) then
  begin
    ShowHourglassCursor;

    // Asegurarnos de que todos los importes están bien.
    RecalcularImportes(AAlbaran);

    try
      if (AAlbaran.EsNuevo) then
        IDNuevo := FDataModule.GetNextID(AAlbaran.DataTable.LogicalName)
      else
        IDNuevo := AAlbaran.ID;

      AsignarID(AAlbaran, IDNuevo);
      AAlbaran.DataTable.ApplyUpdates;
      Result := True;
    finally
      HideHourglassCursor;
    end;
  end;
end;

function TAlbaranesProveedorController.Nuevo: IBizAlbaranProveedor;
var
  AAlbaran : IBizAlbaranProveedor;
begin
  AAlbaran := FDataModule.NewItem;
  FiltrarEmpresa(AAlbaran);
  AAlbaran.DataTable.Active := True;
  AAlbaran.Insert;
  Result := AAlbaran;
end;

procedure TAlbaranesProveedorController.Preview(AAlbaran: IBizAlbaranProveedor; AllItems: Boolean = false);
var
  AReportController : IAlbaranesProveedorReportController;
  ID_Albaranes: TStringList;

begin
  AReportController := TAlbaranesProveedorReportController.Create;
  try
   ID_Albaranes := TStringList.Create;

   //Si deseamos previsualizar todos los items del objeto albaran
   if AllItems then
   begin
     with AAlbaran.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Albaranes.Add(IntToStr(AAlbaran.ID));
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Albaranes.Add(IntToStr(AAlbaran.ID));

    AReportController.Preview(ID_Albaranes.CommaText);

  finally
    AReportController := NIL;
    ID_Albaranes.Free;
  end;
end;

procedure TAlbaranesProveedorController.Print(AAlbaran: IBizAlbaranProveedor; AllItems: Boolean = false);
var
  AReportController : IAlbaranesProveedorReportController;
  ID_Albaranes: TStringList;

begin
  AReportController := TAlbaranesProveedorReportController.Create;
  try
   ID_Albaranes := TStringList.Create;

   //Si deseamos previsualizar todos los items del objeto albaran
   if AllItems then
   begin
     with AAlbaran.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Albaranes.Add(IntToStr(AAlbaran.ID));
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Albaranes.Add(IntToStr(AAlbaran.ID));

    AReportController.Print(ID_Albaranes.CommaText);

  finally
    AReportController := NIL;
    ID_Albaranes.Free;
  end;
end;

procedure TAlbaranesProveedorController.QuitarDireccionEnvio(
  AAlbaran: IBizAlbaranProveedor);
var
  bEnEdicion : Boolean;
begin
  if not Assigned(AAlbaran) then
    raise Exception.Create ('Albarán no asignado (QuitarDireccionEnvio)');

  if AAlbaran.DataTable.Active then
    AAlbaran.DataTable.Active := True;

  bEnEdicion := (AAlbaran.DataTable.State in dsEditModes);
  if not bEnEdicion then
    AAlbaran.Edit;

  ShowHourglassCursor;
  AAlbaran.Edit;
  try
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorCALLE).Clear;
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorPOBLACION).Clear;
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorCODIGO_POSTAL).Clear;
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorPROVINCIA).Clear;
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorTELEFONO).Clear;
    AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorPERSONA_CONTACTO).Clear;

    if not bEnEdicion then
      AAlbaran.Post;
  finally
    HideHourglassCursor;
  end;    
end;

function TAlbaranesProveedorController.GetProveedorController: IProveedoresController;
begin
  Result := FProveedorController;
end;

function TAlbaranesProveedorController.GetDetallesController: IDetallesAlbaranProveedorController;
begin
  Result := FDetallesController;
end;

end.
