unit uGenerarAlbaranesProvUtils;

interface

uses
 Windows, SysUtils, Classes, uBizPedidosProveedor, pngimage, JSDialog;

type
  TdmGenerarAlbaranesProv = class(TDataModule)
    JsListaAlbaranesGenerados: TJSDialog;
  end;

  function GenerarAlbaranProv(const IDPedido : Integer) : Boolean; overload;
  function GenerarAlbaranProv(APedido : IBizPedidoProveedor) : Boolean; overload;
  function GenerarAlbaranProv : Boolean; overload;
  function RecibirPedidoProv(APedido: IBizPedidoProveedor): Boolean; overload;
  function RecibirPedidoProv: Boolean; overload;

implementation

{$R *.dfm}

uses
  Forms, Dialogs, uDialogUtils, uDataTableUtils, uBizDetallesPedidoProveedor,
  uBizDetallesAlbaranProveedor, uPedidosProveedorController,
  uDetallesPedidoProveedorController, uAlbaranesProveedorController,
  uProveedoresController, uDetallesAlbaranProveedorController,
  uControllerDetallesBase, uBizAlbaranesProveedor, uBizContactos,
  schPedidosProveedorClient_Intf, schAlbaranesProveedorClient_Intf,
  uInventarioController, uBizInventario;

var
  dmGenerarAlbaranesCli: TdmGenerarAlbaranesProv;
  APedidosProveedorController : IPedidosProveedorController;
  ADetallesPedidosProveedorController : IDetallesPedidoProveedorController;
  AAlbaranesProveedorController : IAlbaranesProveedorController;
  ADetallesAlbaranesController : IDetallesAlbaranProveedorController;
  AProveedoresController : IProveedoresController;
  AInventarioController : IInventarioController;

{ 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;
  //Ojo se asignará al albarán el almacén ddestino que tenga el primer pedido del proveedor determinado
  AAlbaran.ID_ALMACEN := APedido.ID_ALMACEN;
  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.IMPORTE_NETO := APedido.IMPORTE_NETO;
  AAlbaran.IMPORTE_PORTE := APedido.IMPORTE_PORTE;
  AAlbaran.DESCUENTO := APedido.DESCUENTO;
  AAlbaran.IMPORTE_DESCUENTO := APedido.IMPORTE_DESCUENTO;
  AAlbaran.BASE_IMPONIBLE := APedido.BASE_IMPONIBLE;
  AAlbaran.IVA := APedido.IVA;
  AAlbaran.IMPORTE_IVA := APedido.IMPORTE_IVA;
  AAlbaran.IMPORTE_TOTAL := APedido.IMPORTE_TOTAL;
  AAlbaran.DataTable.FieldByName(fld_AlbaranesProveedorOBSERVACIONES).AsVariant := APedido.DataTable.FieldByName(fld_PedidosProveedorOBSERVACIONES).AsVariant;
  AAlbaran.ID_FORMA_PAGO := APedido.ID_FORMA_PAGO;
end;

procedure CopiarArticulosPendAAlbaran(
  APedido: IBizPedidoProveedor;
  AAlbaran: IBizAlbaranProveedor;
  AArticulosPendientes: IBizDetallesPedidoProveedorPend);
var
  i : integer;
  ADetalles : IBizDetallesAlbaranProveedor;
  ADetallesController : IDetallesAlbaranProveedorController;
begin

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

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

  if not Assigned(AArticulosPendientes) then
    raise Exception.Create ('Artículos pendientes no asignado (CopiarArticulosPendAAlbaran)');

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

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

  ADetalles := AAlbaran.Detalles;
  ADetallesController := TDetallesAlbaranProveedorController.Create;
  try
    //OJO IMPORTANTE
    //Siempre que vayamos a trabajar con los detalles debemos hacer un beginupdate de los mismos y un endupdate para
    //obligarle siempre a recalcular los detalles una sola vez
    ADetallesController.BeginUpdate(ADetalles);

    AArticulosPendientes.DataTable.First;
    for i := 0 to AArticulosPendientes.DataTable.RecordCount - 1 do
    begin
      APedido.Detalles.First;
      if (APedido.Detalles.Locate('ID_ARTICULO', AArticulosPendientes.ID_ARTICULO, [])) then
        if (AArticulosPendientes.CANTIDAD > 0) then
        begin
          ADetallesController.Add(ADetalles, TIPO_DETALLE_CONCEPTO);
          ADetalles.Edit;
          ADetalles.ID_PEDIDO := APedido.Detalles.ID_PEDIDO;
          ADetalles.REFERENCIA := APedido.Detalles.REFERENCIA;
          ADetalles.ID_ARTICULO := APedido.Detalles.ID_ARTICULO;
          ADetalles.CONCEPTO := APedido.Detalles.CONCEPTO;
          ADetalles.CANTIDAD := AArticulosPendientes.CANTIDAD;
          ADetalles.IMPORTE_UNIDAD := APedido.Detalles.IMPORTE_UNIDAD;
          ADetalles.IMPORTE_TOTAL := APedido.Detalles.IMPORTE_TOTAL;
          ADetalles.DESCUENTO := APedido.Detalles.DESCUENTO;
          ADetalles.IMPORTE_PORTE := APedido.Detalles.IMPORTE_PORTE;
          ADetalles.VISIBLE := APedido.Detalles.VISIBLE;
          ADetalles.REFERENCIA_PROVEEDOR := APedido.Detalles.REFERENCIA_PROVEEDOR;
          ADetalles.Post;
          AArticulosPendientes.Next;
        end;
    end;
  finally
    ADetallesController.EndUpdate(ADetalles);
    ADetallesController := NIL;
  end;
end;

procedure Inicializar;
begin
  dmGenerarAlbaranesCli := TdmGenerarAlbaranesProv.Create(nil);
  APedidosProveedorController := TPedidosProveedorController.Create;
  ADetallesPedidosProveedorController := TDetallesPedidoProveedorController.Create;
  AAlbaranesProveedorController := TAlbaranesProveedorController.Create;
  ADetallesAlbaranesController := TDetallesAlbaranProveedorController.Create;
  AProveedoresController := TProveedoresController.Create;
  AInventarioController := TInventarioController.Create;
end;

procedure Finalizar;
begin
  FreeAndNIL(dmGenerarAlbaranesCli);
  APedidosProveedorController := nil;
  ADetallesPedidosProveedorController := nil;
  AAlbaranesProveedorController := nil;
  ADetallesAlbaranesController := nil;
  AProveedoresController := nil;
  AInventarioController := nil;
end;


function GenerarAlbaranProv(const IDPedido : Integer) : Boolean; overload;
var
  APedido : IBizPedidoProveedor;
begin
  try
    if not Assigned(APedidosProveedorController) then
       Inicializar;

    APedido := APedidosProveedorController.Buscar(IDPedido);
    Result := GenerarAlbaranProv(APedido);

    if Assigned(APedidosProveedorController) then
       Finalizar;
  finally
    APedido := NIL;
  end;
end;

function GenerarAlbaranProv(APedido : IBizPedidoProveedor) : Boolean; overload;
var
  ARespuesta : Integer;
  AAlbaran : IBizAlbaranProveedor;
  AArticulosPendientes: IBizDetallesPedidoProveedorPend;

begin
  Result := False;

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

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

  try
    if not Assigned(APedidosProveedorController) then
       Inicializar;

    AArticulosPendientes := ADetallesPedidosProveedorController.ArticulosPendientes(APedido.ID);
    if not Assigned(AArticulosPendientes) then
       raise Exception.Create('Error al recuperar los artículos sin albarán del pedido (GenerarAlbaranProv)');

    AArticulosPendientes.DataTable.Active := True;
    if AArticulosPendientes.DataTable.RecordCount = 0 then
    begin
      ARespuesta := ShowConfirmMessage('Generar albarán a partir del pedido', 'Todos los artículos de este pedido ya figuran en uno o más albaranes de proveedor.' +
      #10#13 + '¿Desea generar de todas formas otro albarán para este pedido?');
      if (ARespuesta = IDNO) then
         Exit; // Aunque es un exit, se ejecuta la parte del finally antes de salir.
    end;

    AAlbaran := AAlbaranesProveedorController.Nuevo;
    CopiarPedidoAAlbaran(APedido, AAlbaran);
    CopiarArticulosPendAAlbaran(APedido, AAlbaran, AArticulosPendientes);

    //Sustituir por if de guardar
    if AAlbaranesProveedorController.Guardar(AAlbaran) then
    begin
//       ShowWarningMessage('Todos los artículos que contiene el pedido no están en el catálogo, y por lo tanto no se puede generar el albarán');

      with dmGenerarAlbaranesCli.JsListaAlbaranesGenerados do
      begin
        Instruction.Text := 'Se ha generado el albarán';
        Content.Clear;
        Content.Add(Format('Se ha generado correctamente el albarán %s a partir del pedido de cliente' + #10#13, [AAlbaran.REFERENCIA]));
        Execute;

        ARespuesta := CustomButtonResult;
        case ARespuesta of
          100 : begin
                  // Ver el albarán
                  AAlbaranesProveedorController.Ver(AAlbaran);
                end;
          200 : // Continuar;
        end;
      end;
    end;

    Result := True;
  finally
    AArticulosPendientes := NIL;
    if Assigned(APedidosProveedorController) then
       Finalizar;
  end;
end;

function GenerarAlbaranProv : Boolean; overload;
var
  APedido : IBizPedidoProveedor;
begin
  Result := False;
  try
    if not Assigned(APedidosProveedorController) then
       Inicializar;

    APedido := APedidosProveedorController.ElegirPedidos(APedidosProveedorController.BuscarPendientesRecepcion,
               'Elija el pedido de proveedor que desea utilizar para dar de alta el albarán correspondiente.'
               , False);
    if Assigned(APedido) then
       Result := GenerarAlbaranProv(APedido);

  finally
    if Assigned(APedidosProveedorController) then
       Finalizar;
  end;
end;

function RecibirPedidoProv(APedido: IBizPedidoProveedor): Boolean;
var
  bGenerarAlbaran : Boolean;
  ARespuesta : Integer;

  AArticulosPendientes: IBizDetallesPedidoProveedorPend;
  AAlbaran : IBizAlbaranProveedor;
  AInventarioRecibido: IBizInventario;

begin
  Result := False;
  bGenerarAlbaran := False;
  AInventarioRecibido := NIL;

  if not Assigned(AInventarioController) then
     Inicializar;

  // ¿Hay almacén asociado al pedido?
  if APedido.ID_ALMACEN = 0 then
  begin
    if (ShowConfirmMessage('Recepción de pedido a proveedor', 'Este pedido no tiene un almacén asociado por lo que se generará el albarán de proveedor correspondiente sin hacer ningún cambio en el stock de los almacenes.'
      + #10#13 + #10#13 + '¿Desea continuar?') = IDYES) then
      bGenerarAlbaran := True;
  end
  else begin
    try
      // En AInventarioRecibido tenemos la lista de articulos que hemos recibido y
      // que utilizaremos para hacer el albarán
      AArticulosPendientes := ADetallesPedidosProveedorController.ArticulosPendientes(APedido.ID);
      if not Assigned(AArticulosPendientes) then
         raise Exception.Create('Error al recuperar los artículos pendientes de recibir del pedido (GenerarAlbaranProv)');

      AArticulosPendientes.DataTable.Active := True;
      if AArticulosPendientes.DataTable.RecordCount = 0 then
      begin
        ARespuesta := ShowConfirmMessage('Generar albarán a partir del pedido', 'Todos los artículos de este pedido ya figuran en uno o más albaranes de proveedor.' +
        #10#13 + '¿Desea generar de todas formas otro albarán para este pedido?');
        if (ARespuesta = IDNO) then
            Exit; // Aunque es un exit, se ejecuta la parte del finally antes de salir.
      end;

      bGenerarAlbaran := AInventarioController.EntradaPedido(nil, APedido, AArticulosPendientes, AInventarioRecibido);
    except
      on E : Exception do
        ShowMessage(E.Message);
    end;
  end;

  if bGenerarAlbaran then
  begin
    try
      AAlbaran := AAlbaranesProveedorController.Nuevo;
      // En AInventarioRecibido tenemos la lista de articulos que hemos recibido y
      // que utilizaremos para hacer el albarán
      if AAlbaranesProveedorController.Anadir(AAlbaran, APedido.ID, AInventarioRecibido) then
      begin
        AAlbaranesProveedorController.Guardar(AAlbaran);
        AAlbaranesProveedorController.Ver(AAlbaran);

        //Si el pedido tiene obra relacionada y el destino del pedido no es esa obra, preguntamos si quiere reservar de los materiales para esa obra
        if (APedido.ID_OBRA > 0)
        and (APedido.ID_OBRA <> APedido.ID_ALMACEN) then
        begin
          if Application.MessageBox(PChar('Desea realizar la reserva del material recibido para la obra ' + APedido.NOMBRE_OBRA + ', asociada al pedido'), 'Atención', MB_YESNO) = IDYES then
          begin
             AInventarioRecibido.TipoMovimiento := tReserva;
             AInventarioRecibido.IDAlmacenOrigen := APedido.ID_ALMACEN;
             AInventarioRecibido.IDAlmacenDestino := APedido.ID_OBRA;
             AInventarioController.Guardar(AInventarioRecibido, AAlbaran.FECHA_ALBARAN, ('Reserva para obra ' + APedido.NOMBRE_OBRA + ' del pedido ' + APedido.REFERENCIA), False);
          end;
        end;
      end;
    finally
      AAlbaran := NIL;
      AInventarioRecibido := Nil;
    end;
  end;

  if Assigned(AAlbaranesProveedorController) then
     Finalizar;

  //  actRefrescar.Execute;
end;

function RecibirPedidoProv: Boolean; overload;
var
  APedido : IBizPedidoProveedor;
begin
  Result := False;
  try
    if not Assigned(APedidosProveedorController) then
       Inicializar;

    APedido := APedidosProveedorController.ElegirPedidos(APedidosProveedorController.BuscarPendientesRecepcion,
               'Elija el pedido de proveedor que desea recibir.'
               , False);
    if Assigned(APedido) then
       Result := RecibirPedidoProv(APedido);

  finally
    if Assigned(APedidosProveedorController) then
       Finalizar;
  end;
end;

end.
