Esta es la decimosexta entrega de la serie sobre utilidades para Business Central. En esta ocasión presento una función que resuelve un problema clásico en desarrollos con documentos de venta: insertar una línea nueva entre dos líneas existentes con un número de línea válido que no colisione con las ya existentes.
¡Vamos manos a la obra! ✂️
✂️ Calcular el número de línea intermedio: SplitLine
procedure SplitLine(var SalesLine: Record "Sales Line") ReturnValue: Integer
var
AuxSalesLine: Record "Sales Line";
LastSalesLine: Record "Sales Line";
Step: Integer;
CurrLineNo: Integer;
LastLineNo: Integer;
NewLine: Integer;
begin
// Paso "clásico" en BC
Step := 10000;
// Asegura clave por rendimiento (Document Type, Document No., Line No.)
AuxSalesLine.Reset();
AuxSalesLine.SetCurrentKey("Document Type", "Document No.", "Line No.");
AuxSalesLine.SetRange("Document Type", SalesLine."Document Type");
AuxSalesLine.SetRange("Document No.", SalesLine."Document No.");
// 1) Si no hay líneas en el documento, primera línea = 10000
if not AuxSalesLine.FindFirst() then
exit(Step);
// 2) Confirma el número de la línea "actual"
CurrLineNo := SalesLine."Line No.";
if CurrLineNo = 0 then begin
// Si te pasan una línea sin número (poco común), usa la última + Step
LastSalesLine.Copy(AuxSalesLine);
LastSalesLine.FindLast();
exit(LastSalesLine."Line No." + Step);
end;
// 3) Busca la "siguiente" estrictamente mayor que la actual
AuxSalesLine.SetFilter("Line No.", '>%1', CurrLineNo);
if AuxSalesLine.FindFirst() then
LastLineNo := AuxSalesLine."Line No."
else begin
// No hay siguiente → devuelve última + Step
LastSalesLine.Reset();
LastSalesLine.SetCurrentKey("Document Type", "Document No.", "Line No.");
LastSalesLine.SetRange("Document Type", SalesLine."Document Type");
LastSalesLine.SetRange("Document No.", SalesLine."Document No.");
LastSalesLine.FindLast();
exit(LastSalesLine."Line No." + Step);
end;
// 4) Calcula un número intermedio seguro
NewLine := LastLineNo - CurrLineNo;
if NewLine > 1 then begin
// Mitad del hueco (evita repetir el actual)
ReturnValue := CurrLineNo + (NewLine div 2);
// Protección adicional por si el gap era 1 (ya habría salido arriba)
if (ReturnValue = CurrLineNo) or (ReturnValue = LastLineNo) then
ReturnValue := LastLineNo - 1;
// Si por cualquier motivo quedó igual, cae al fallback de última + Step
if (ReturnValue <= CurrLineNo) or (ReturnValue >= LastLineNo) then begin
LastSalesLine.Reset();
LastSalesLine.SetCurrentKey("Document Type", "Document No.", "Line No.");
LastSalesLine.SetRange("Document Type", SalesLine."Document Type");
LastSalesLine.SetRange("Document No.", SalesLine."Document No.");
LastSalesLine.FindLast();
ReturnValue := LastSalesLine."Line No." + Step;
end;
exit(ReturnValue);
end else begin
// Gap <= 1 → sin espacio intermedio; usa última + Step
LastSalesLine.Reset();
LastSalesLine.SetCurrentKey("Document Type", "Document No.", "Line No.");
LastSalesLine.SetRange("Document Type", SalesLine."Document Type");
LastSalesLine.SetRange("Document No.", SalesLine."Document No.");
LastSalesLine.FindLast();
exit(LastSalesLine."Line No." + Step);
end;
end;
¿Qué problema resuelve?
En Business Central, los números de línea de los documentos van en saltos de 10.000 (10000, 20000, 30000...). Cuando necesitas insertar una nueva línea justo después de una línea concreta (y no al final del documento), tienes que calcular un número de línea que:
- Sea mayor que el de la línea actual.
- Sea menor que el de la siguiente línea existente.
- No colisione con ningún número existente.
SplitLine resuelve exactamente esto devolviendo el número de línea adecuado.
Explicación paso a paso
1. Caso sin líneas o línea sin número
Si el documento no tiene líneas, devuelve directamente 10000. Si la línea actual tiene número 0, busca la última línea y devuelve su número + 10000.
2. Busca la siguiente línea existente
Filtra las líneas del mismo documento con un número estrictamente mayor al de la línea actual. Si no hay ninguna (la línea actual es la última), devuelve última + 10000.
3. Calcula el punto medio
Si hay espacio entre las dos líneas (diferencia > 1), calcula el punto medio del hueco:
ReturnValue := CurrLineNo + (NewLine div 2);
Incluye protecciones adicionales para evitar que el resultado coincida accidentalmente con alguno de los extremos.
4. Sin espacio disponible
Si no hay hueco entre las líneas (gap <= 1), cae al fallback: devuelve última línea + 10000. En este caso la nueva línea irá al final del documento.
Ejemplo de uso
var
Utils: Codeunit Utils;
SalesLine: Record "Sales Line";
NewSalesLine: Record "Sales Line";
NewLineNo: Integer;
begin
// SalesLine es la línea después de la cual insertar
NewLineNo := Utils.SplitLine(SalesLine);
NewSalesLine.Init();
NewSalesLine."Document Type" := SalesLine."Document Type";
NewSalesLine."Document No." := SalesLine."Document No.";
NewSalesLine."Line No." := NewLineNo;
// ... rellenar resto de campos
NewSalesLine.Insert(true);
end;
💡 Aplicaciones prácticas
- Dividir una línea de pedido en varias líneas más pequeñas.
- Insertar líneas de comentario o descripción entre líneas de artículo.
- Procesos automáticos que generan líneas adicionales basadas en líneas existentes.
- Mantenimiento del orden visual del documento sin reordenar todas las líneas.
Conclusión
En esta decimosexta entrega de la serie Utils, muestro cómo calcular correctamente el número de línea intermedio para insertar una nueva línea de venta en Business Central sin colisionar con las existentes. Una función pequeña pero con una lógica robusta que cubre todos los casos límite.
Para seguir todos los posts de esta serie, puedes encontrarlos bajo la etiqueta #UtilsBc.
Si quieres ver el código completo, está en GitHub.
¡Nos vemos en la próxima!