unit uGenerarAlbaranesProvUtils; interface uses Windows, SysUtils, Classes, uBizPedidosProveedor, pngimage, JSDialog, uBizDetallesPedidoProveedor, uBizAlbaranesProveedor, uBizInventario; type TdmGenerarAlbaranesProv = class(TDataModule) JsListaAlbaranesGenerados: TJSDialog; end; function GenerarAlbaranProv(const IDPedido : Integer) : Boolean; overload; function GenerarAlbaranProv(APedido : IBizPedidoProveedor) : Boolean; overload; function GenerarAlbaranesProv(APedidos : IBizPedidoProveedor) : Boolean; overload; // function GenerarAlbaranProv : Boolean; overload; function GenerarAlbaranesProv : Boolean; overload; function RecibirPedidoProv(APedido: IBizPedidoProveedor): Boolean; overload; function RecibirPedidoProv: Boolean; overload; function GenerarAlbaranesdeListaPedidos(AAlbaranes: IBizAlbaranProveedor; AListaPedidos: IBizPedidoProveedor): Boolean; function Anadir(AAlbaran : IBizAlbaranProveedor; const IDPedido : Integer; AInventarioRecibido: IBizInventario): Boolean; overload; implementation {$R *.dfm} uses Dialogs, uDialogUtils, uBizDetallesAlbaranProveedor, uPedidosProveedorController, uDetallesPedidoProveedorController, uAlbaranesProveedorController, uProveedoresController, uDetallesAlbaranProveedorController, uControllerDetallesBase, uBizContactos, schPedidosProveedorClient_Intf, schAlbaranesProveedorClient_Intf, uInventarioController, schInventarioClient_Intf, uArticulosController, uBizArticulos, Variants, schArticulosClient_Intf, uDADataTable, DB, uControllerDetallesArticulos; var dmGenerarAlbaranesProv: 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; 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; AAlbaran.ID_ALMACEN := APedido.ID_ALMACEN; end; procedure CopiarArticulosPedido(ID_PEDIDO: Integer; AOrigen: IBizDetallesPedidoProveedor; ADestino : IBizDetallesAlbaranProveedor; AArticulosPendientes: IBizDetallesPedidoProveedorPend); var i : integer; ADetallesController : IDetallesAlbaranProveedorController; ACantidad: Variant; ArticulosAnadidosAux: TStringList; ACadena: String; begin if not Assigned(AOrigen) then raise Exception.Create ('Origen no asignado (CopiarArticulosPedido)'); if not Assigned(ADestino) then raise Exception.Create ('Destino no asignado (CopiarArticulosPedido)'); if not AOrigen.DataTable.Active then AOrigen.DataTable.Active := True; if not ADestino.DataTable.Active then ADestino.DataTable.Active := True; ADetallesController := TDetallesAlbaranProveedorController.Create; ArticulosAnadidosAux:= TStringList.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(ADestino); AOrigen.DataTable.First; for i := 0 to AOrigen.DataTable.RecordCount - 1 do begin ACadena := ''; if (AOrigen.ID_ARTICULO > 1) then begin //Comprobamos el articulo del pedido no haya sido recibido ya en otro albaran. AArticulosPendientes.DataTable.First; if AArticulosPendientes.DataTable.Locate(fld_PedidosProveedor_DetallesID_ARTICULO, AOrigen.ID_ARTICULO, []) then begin //Esto es para el caso de meter edl mismo articulo varias veces en el pedido cambiando la descripción, si esto ocurre, //Metemos en la primera aparición la suma de las unidades a recibir y en las siguiente apariciones se pone CERO if (ArticulosAnadidosAux.IndexOf(IntToStr(AOrigen.ID_ARTICULO)) = -1) then begin ACantidad := AArticulosPendientes.CANTIDAD; ArticulosAnadidosAux.Add(IntToStr(AOrigen.ID_ARTICULO)); end else begin ACantidad := 0; ACadena := #10 + #13 + ' - Artículo con ref. ' + AOrigen.REFERENCIA + ' repetido en otra linea y descripción diferente'; end; end else begin ACantidad := 0; //AOrigen.CANTIDAD; ACadena := ' - Recibido en un albarán anterior' end; end else ACantidad := AOrigen.CANTIDAD; ADetallesController.Add(ADestino, TIPO_DETALLE_CONCEPTO); ADestino.Edit; ADestino.REFERENCIA := AOrigen.REFERENCIA; if AOrigen.ID_ARTICULO > 0 then ADestino.ID_ARTICULO := AOrigen.ID_ARTICULO; ADestino.CONCEPTO := AOrigen.CONCEPTO + ACadena; ADestino.CANTIDAD := ACantidad; ADestino.IMPORTE_UNIDAD := AOrigen.IMPORTE_UNIDAD; ADestino.IMPORTE_TOTAL := AOrigen.IMPORTE_TOTAL; ADestino.DESCUENTO := AOrigen.DESCUENTO; ADestino.IMPORTE_PORTE := AOrigen.IMPORTE_PORTE; ADestino.VISIBLE := AOrigen.VISIBLE; ADestino.REFERENCIA_PROVEEDOR := AOrigen.REFERENCIA_PROVEEDOR; ADestino.ID_PEDIDO := ID_PEDIDO; ADestino.Post; AOrigen.Next; end; finally ArticulosAnadidosAux.Destroy; ADetallesController.EndUpdate(ADestino); ADetallesController := NIL; end; 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); //Se cambia porque puede haber articulos del pedido que no tengan referencia de proveedor // ADetallesController.AnadirArticulo(ADetalles, AInventarioRecibido.REFERENCIA, tCliente); ADetallesController.AnadirArticulo(ADetalles, AInventarioRecibido.ID_ARTICULO); ADetalles.Edit; APedido.Detalles.First; //Se cambia porque puede haber articulos del pedido que no tengan referencia de proveedor // if not APedido.Detalles.DataTable.Locate(fld_ArticulosREFERENCIA, ADetalles.REFERENCIA, []) then if not APedido.Detalles.Locate(fld_INVENTARIOID_ARTICULO, VarArrayOf([ADetalles.DataTable.FieldByName('ID_ARTICULO').AsVariant]), []) 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; ADetallesController.ActualizarTotales(ADetalles); 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.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 dmGenerarAlbaranesProv := 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(dmGenerarAlbaranesProv); 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); // Este método genera el albarán sin posibilidad de cancelar // Result := GenerarAlbaranesProv(APedido); if Assigned(APedidosProveedorController) then Finalizar; finally APedido := NIL; end; end; function GenerarAlbaranProv(APedido : IBizPedidoProveedor) : Boolean; overload; var ARespuesta : Integer; AAlbaran : IBizAlbaranProveedor; AArticulosPendientes: IBizDetallesPedidoProveedorPend; bEnEdicion : Boolean; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; if not Assigned(APedido) then raise Exception.Create('Pedidos de proveedor no asignado (GenerarAlbaranProv)'); if not APedido.DataTable.Active then APedido.DataTable.Active := True; try AArticulosPendientes := APedidosProveedorController.ArticulosPendientesDeRecibir(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); //Por cada pedido a añadir lo asignamos al campo manual de referencias de pedidos asociados REF_PEDIDOS_PROV bEnEdicion := (AAlbaran.DataTable.State in dsEditModes); if not bEnEdicion then AAlbaran.Edit; AAlbaran.REF_PEDIDOS_PROV := AAlbaran.REF_PEDIDOS_PROV + ' ' + APedido.REFERENCIA; AAlbaran.Post; if bEnEdicion then AAlbaran.Edit; AAlbaran.Detalles.DataTable.Last; // Añado el título ADetallesAlbaranesController.Add(AAlbaran.Detalles, TIPO_DETALLE_TITULO); with AAlbaran.Detalles do begin Edit; CONCEPTO := 'Pedido ' + APedido.REFERENCIA + ' del ' + DateToStr(APedido.FECHA_PEDIDO); Post; end; // Añado el contenido del pedido CopiarArticulosPedido(APedido.ID, APedido.Detalles, AAlbaran.Detalles, AArticulosPendientes); //Cuando solo se quieren tener en cuenta los pendientes //CopiarArticulosPendAAlbaran(APedido, AAlbaran, AArticulosPendientes); // Añado el resumen ADetallesAlbaranesController.Add(AAlbaran.Detalles, TIPO_DETALLE_SUBTOTAL); with AAlbaran.Detalles do begin Edit; CONCEPTO := 'Total del pedido ' + APedido.REFERENCIA; Post; end; // Añado una línea en blanco ADetallesAlbaranesController.Add(AAlbaran.Detalles, TIPO_DETALLE_CONCEPTO); with AAlbaran.Detalles do begin Edit; CONCEPTO := ''; Post; end; // Guardo el albaran que acabo de generar o editar AAlbaran.CalcularImporteTotal; AAlbaranesProveedorController.Ver(AAlbaran); //En el caso de que haya guardado miramos si tiene el ID_PEDIDO asociado ya que en este caso la asociación lo laquitamos //para a posteriori modificar el pedido de proveedor con el ID_ALBARAN correspondiente if not AAlbaran.ID_PEDIDOIsNull then begin //28/05/2025- Stefy nos dice que un albarán puede englobar a varios pedidos por lo que la relacion 1-n estará en los pedidos // AAlbaranes.ID_PEDIDO := AListaPedidos.ID; // Asociamos el albarán al pedido, aunque puede darse el caso de que un pedido llegue en varios albaranes, // en tal caso el ID que se almacena en el pedido será el último albarán, aunque en los albaranes guardamos las // referencias de los pedidos recibidos en cada albaran por lo que siempre podremos localizar los dos albaranes //donde se han recibido a no ser que el usuario lo borro manuelmente APedido.Edit; APedidosProveedorController.RecuperarProveedor(APedido); APedido.Proveedor.DataTable.Active := True; APedido.ID_ALBARAN := AAlbaran.ID; APedido.REF_ALBARAN := AAlbaran.REFERENCIA; APedido.Post; APedidosProveedorController.Guardar(APedido); end; Result := True; finally AAlbaran := Nil; AArticulosPendientes := NIL; if Assigned(APedidosProveedorController) then Finalizar; end; end; function GenerarAlbaranesProv(APedidos : IBizPedidoProveedor) : Boolean; overload; var AAlbaranesNuevos : IBizAlbaranProveedor; i: Integer; ARespuesta : Integer; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; if not Assigned(APedidos) then raise Exception.Create('Pedidos de proveedor no asignado (GenerarAlbaranesProv)'); if not APedidos.DataTable.Active then APedidos.DataTable.Active := True; try AAlbaranesNuevos := AAlbaranesProveedorController.Nuevo(False); if GenerarAlbaranesdeListaPedidos(AAlbaranesNuevos, APedidos) then begin if AAlbaranesNuevos.DataTable.RecordCount = 1 then begin with dmGenerarAlbaranesProv.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 proveedor' + #10#13, [AAlbaranesNuevos.REFERENCIA])); end; end else begin dmGenerarAlbaranesProv.JsListaAlbaranesGenerados.CustomButtons[1].Destroy; with dmGenerarAlbaranesProv.JsListaAlbaranesGenerados.Content do begin Clear; AAlbaranesNuevos.DataTable.Last; for i := 0 to AAlbaranesNuevos.DataTable.RecordCount - 1 do begin if Length(AAlbaranesNuevos.REFERENCIA) > 0 then Add(AAlbaranesNuevos.REFERENCIA + ': ' + AAlbaranesNuevos.NOMBRE); AAlbaranesNuevos.DataTable.Prior; end; end; end; dmGenerarAlbaranesProv.JsListaAlbaranesGenerados.Execute; ARespuesta := dmGenerarAlbaranesProv.JsListaAlbaranesGenerados.CustomButtonResult; case ARespuesta of 100 : begin // Ver el albarán AAlbaranesProveedorController.Ver(AAlbaranesNuevos); end; 200 : // Continuar; end; end; finally AAlbaranesNuevos := NIL; end; end; {function GenerarAlbaranProv : Boolean; overload; //Solo generará el albarán correspondiente al pedido seleccionado 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 GenerarAlbaranesProv : Boolean; overload; // Generara tantos albaranes como proveedores distintos tenga en la lista de pedidos seleccionada var APedidos : IBizPedidoProveedor; begin Result := False; try if not Assigned(APedidosProveedorController) then Inicializar; APedidos := APedidosProveedorController.ElegirPedidos(APedidosProveedorController.BuscarPendientesRecepcion, 'Elija el pedido o pedidos de proveedor que desea utilizar para dar de alta el albarán correspondiente.' , True); if Assigned(APedidos) then Result := GenerarAlbaranesProv(APedidos); 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 Anadir(AAlbaran, APedido.ID, AInventarioRecibido) then AAlbaranesProveedorController.Ver(AAlbaran); finally AAlbaran := 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; function GenerarAlbaranesdeListaPedidos(AAlbaranes: IBizAlbaranProveedor; AListaPedidos: IBizPedidoProveedor): Boolean; var AAlbaranActual : IBizAlbaranProveedor; APedidosController : IPedidosProveedorController; AArticulosPendientes : IBizDetallesPedidoProveedorPend; I: Integer; bEnEdicion : Boolean; begin Result := False; // ATENCIÓN!!! AAlbaranes tiene que estar vacio para no pisar albaranes // ya generados. if not Assigned(AAlbaranes) then raise Exception.Create ('Albaran no asignado (Anadir)'); if not Assigned(AListaPedidos) then raise Exception.Create ('Pedidos no asignados (Anadir)'); if not AAlbaranes.DataTable.Active then AAlbaranes.DataTable.Active := True; if not AListaPedidos.DataTable.Active then AListaPedidos.DataTable.Active := True; APedidosController := TPedidosProveedorController.Create; try // Ordenar por fecha de pedido AListaPedidos.DataTable.Sort([fld_PedidosProveedorFECHA_PEDIDO], [uDADataTable.sdAscending]); AListaPedidos.First; for I := 0 to AListaPedidos.DataTable.RecordCount - 1 do begin AListaPedidos._Proveedor := NIL; AAlbaranActual := NIL; // Busco si hay algun albarán ya hecho de ese Proveedor AAlbaranes.DataTable.First; if AAlbaranes.DataTable.Locate(fld_AlbaranesProveedorID_Proveedor, AListaPedidos.ID_Proveedor, []) then begin AAlbaranActual := AAlbaranes; //Si ya tenemos un albarán quiere decir que dicho albarán va ha recibir mas de un pedido //por lo que la relación con el pedido se traslada a los articulos detalles, es decir un albarán que recibe varios pedidos //el idPedido de la cabeceza será null. bEnEdicion := (AAlbaranActual.DataTable.State in dsEditModes); if not bEnEdicion then AAlbaranActual.Edit; AAlbaranActual.ID_PEDIDOIsNull := True; //Cuando elijo varios pedidos ponemos como almacén destino siempre el que tenga asociado el primer pedido del albaran // AAlbaranActual.ID_ALMACEN := AL PASADO POR PARAMETRO AAlbaranActual.Post; if bEnEdicion then AAlbaranActual.Edit; end else begin // No hay albaran de ese Proveedor. Creo una nueva AAlbaranesProveedorController.Anadir(AAlbaranes); //Siempre asignaremos por defecto el ID_PEDIDO del primer pedido de la lista, si hay más pedidos en el albarán luego los pondremos a null, //con ID_ALMACEN pasará lo mismo bEnEdicion := (AAlbaranes.DataTable.State in dsEditModes); if not bEnEdicion then AAlbaranes.Edit; //28/05/2025- Stefy nos dice que un albarán puede englobar a varios pedidos por lo que la relacion 1-n estará en los pedidos // AAlbaranes.ID_PEDIDO := AListaPedidos.ID; AAlbaranes.ID_ALMACEN := AListaPedidos.ID_ALMACEN; AAlbaranes.Post; if bEnEdicion then AAlbaranes.Edit; //Si el albaran es de tipo devolución hacemos la factura de tipo abono { if (AListaAlbaranes.TIPO = CTE_TIPO_ALBARAN_DEV) then begin bEnEdicion := (AFacturas.DataTable.State in dsEditModes); if not bEnEdicion then AFacturas.Edit; AFacturas.TIPO := CTE_TIPO_ABONO; AFacturas.Post; if bEnEdicion then AFacturas.Edit; end; } AAlbaranActual := AAlbaranes; end; //Asignamos el proveedor del pedido en el alñbarán siempre APedidosController.RecuperarProveedor(AListaPedidos); AAlbaranes.Proveedor := AListaPedidos.Proveedor; //Por cada pedido a añadir lo asignamos al campo manual de referencias de pedidos asociados REF_PEDIDOS_PROV bEnEdicion := (AAlbaranActual.DataTable.State in dsEditModes); if not bEnEdicion then AAlbaranActual.Edit; AAlbaranActual.REF_PEDIDOS_PROV := AAlbaranActual.REF_PEDIDOS_PROV + ' ' + AListaPedidos.REFERENCIA; AAlbaranes.Post; if bEnEdicion then AAlbaranActual.Edit; // Ya tengo el albarán. Le añado los conceptos del pedido //Recogemos los articulos pendientes de recibir de pedido, para solo recibir lo restante si ya estubiera recibido parcialmente. //SOLO SE TENDRA EN CUENTA LOS INVENTARIABLES AArticulosPendientes := APedidosController.ArticulosPendientesDeRecibir(AListaPedidos.ID); AAlbaranActual.Detalles.DataTable.Last; // Añado el título AAlbaranesProveedorController.DetallesController.Add(AAlbaranActual.Detalles, TIPO_DETALLE_TITULO); with AAlbaranActual.Detalles do begin Edit; CONCEPTO := 'Pedido ' + AListaPedidos.REFERENCIA + ' del ' + DateToStr(AListaPedidos.FECHA_PEDIDO); Post; end; // Añado el contenido del pedido CopiarArticulosPedido(AListaPedidos.ID, AListaPedidos.Detalles, AAlbaranActual.Detalles, AArticulosPendientes); {En los albaranes a proveedor el porte es a nivel del artículo Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Porte del albarán'; CANTIDAD := 1; IMPORTE_UNIDAD := AListaAlbaranes.IMPORTE_PORTE; Post; end; } // Añado el resumen AAlbaranesProveedorController.DetallesController.Add(AAlbaranActual.Detalles, TIPO_DETALLE_SUBTOTAL); with AAlbaranActual.Detalles do begin Edit; CONCEPTO := 'Total del pedido ' + AListaPedidos.REFERENCIA; Post; end; // Añado una línea en blanco AAlbaranesProveedorController.DetallesController.Add(AAlbaranActual.Detalles, TIPO_DETALLE_CONCEPTO); with AAlbaranActual.Detalles do begin Edit; CONCEPTO := ''; Post; end; // Guardo el albaran que acabo de generar o editar AAlbaranActual.CalcularImporteTotal; AAlbaranesProveedorController.Guardar(AAlbaranActual); // Asociamos el albarán al pedido, aunque puede darse el caso de que un pedido llegue en varios albaranes, // en tal caso el ID que se almacena en el pedido será el último albarán, aunque en los albaranes guardamos las // referencias de los pedidos recibidos en cada albaran por lo que siempre podremos localizar los dos albaranes //donde se han recibido a no ser que el usuario lo borro manuelmente AListaPedidos.Edit; AListaPedidos.ID_ALBARAN := AAlbaranActual.ID; AListaPedidos.REF_ALBARAN := AAlbaranActual.REFERENCIA; AListaPedidos.Post; APedidosController.Guardar(AListaPedidos); AListaPedidos.Next; end; Result := True; finally APedidosController := NIL; end; end; function 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; AAlbaranesProveedorController.Anadir(AAlbaran); CopiarPedidoAAlbaran(APedido, AAlbaran); CopiarArticulosAAlbaran(APedido, AAlbaran, AInventarioRecibido); AAlbaranesProveedorController.RecalcularImportes(AAlbaran); Result := True; finally APedido := NIL; APedidosController := NIL; // HideHourglassCursor; // Application.ProcessMessages; end; end; end.