Crear documento a través de DI API

Buen día expertos, tengo el siguiente código que crea una oferta de venta dentro de SAP a través del DI API en una página web:

        private void CrearDocumento()
        {
            if (oCompany == null || !oCompany.Connected)
                this.ConectarCompany();

            Documents Cotizacion = oCompany.GetBusinessObject(BoObjectTypes.oQuotations);

            Cotizacion.CardCode = txtCodigoCliente.Text.ToString();
            Cotizacion.DocDate = DateTime.Now;
            Cotizacion.DocDueDate = DateTime.Now.AddMonths(1);
            Cotizacion.Series = 13;
            Cotizacion.DocCurrency = ddlMoneda.SelectedItem.Text.ToString();

            //Líneas
            Cotizacion.Lines.SetCurrentLine(0);
            Cotizacion.Lines.ItemCode = txtArticulo.Text.ToString();
            Cotizacion.Lines.Quantity = double.Parse(txtCantidadArticulo.Text.ToString());
            Cotizacion.Lines.Price = double.Parse(txtPrecioArticulo.Text.ToString());
            Cotizacion.Lines.DiscountPercent = double.Parse(txtDescuentoArticulo.Text.ToString());
            Cotizacion.Lines.UoMEntry = Convert.ToInt32(ddlUoM.SelectedValue.ToString());  

            if (Convert.ToInt32(ddlUoM.SelectedValue.ToString()) != -1)
                Cotizacion.Lines.UseBaseUnits = BoYesNoEnum.tNO;
            else
                Cotizacion.Lines.UseBaseUnits = BoYesNoEnum.tYES;

            Cotizacion.Lines.TaxCode = "A4";
            Cotizacion.Lines.WarehouseCode = "MTY";
            Cotizacion.Lines.ProjectCode = "01MTY";     

            Cotizacion.Comments = "Comentarios..";

            //Crear cotización
            int iret = Cotizacion.Add();        
        }

Tengo dos dudas respecto a esto, la primera es si hay forma de que por medio del DI API, me pueda traer el costo total ($) de la línea del artículo, es decir, cuando selecciono un código de artículo tengo que ejecutar una consulta que me trae las unidades de medida, el precio, etc, pero debo hacerlo yo “manualmente”, quería consultar si el DI API tiene alguna opción de hacer esto.

Y la segunda y más importante, estuve buscando temas relacionados al consumo de memoria del DI API y di con este post:

h_tps://www.appseconnect.com/di-api-memory-leak-in-sap-business-one-9-0/

Quería que me apoyaran revisando mi código y verificando si está desarrollado de la forma correcta, o si se requiere hacer algún tipo de “limpieza” de elementos (por ej. Garbage Colector, Dispose, regresar todo a NULL, etc.)

Agradezco de antemano cualquier apoyo, ejemplo, comentario u orientación que puedan brindarme.

Saludos cordiales.

Que tal @l.villarreal, buenos días

Con respecto al precio, con el siguiente código puedes recuperar el precio de acuerdo a la lista de precios asignada al cliente.

SAPbobsCOM.SBObob oSBObob = (SAPbobsCOM.SBObob) OrderApp.oCompany.GetBusinessObject(SAPbobsCOM.BoObjectTypes.BoBridge);
SAPbobsCOM.Recordset oRecordset = oSBObob.GetItemPrice(CodigoCliente, CodigoProducto, Cantidad, Fecha);
Double PrecioSegunListaDePrecios = Convert.ToDouble(oRecordSet.Fields.Item(0).Value);

Con respecto al tema de liberar las variables de objeto, puedes realizar lo siguiente para cada uno

System.Runtime.InteropServices.Marshal.ReleaseComObject(Cotizacion);
Cotizacion = null;

Y adicional puedes ejecutar este método del recolector de basura (Garbage Collector)
GC.Collect();

Recomendación, te sugiero realizar una validación al momento de intentar crear el documento, para que informes al usuario el resultado y evitar que tu proceso truene estando compilado con algún posible error, algo así:

int iret = Cotizacion.Add();
if(iret != 0) {
    oCompany.GetLastError(out errNumero, out errMensaje);
    // Esto en caso de que llegaras a tener transacciones en tu proceso
    if(oCompany.InTransaction == true) {
        oCompany.EndTransaction(BoWfTransOpt.wf_RollBack);
    }        // si la transacción sigue abierta, la cierra deshaciendo todos los cambios realizados hasta el momento
    MessageBox.Show("Ha ocurrido el siguiente error, al intentar crear la Oferta de Venta, revise por favor ...\n\n" + errNumero + " ---> " + errMensaje + ",  revise por favor ...");
}

Saludos
SAP B1, v9.2 PL03
México

2 Me gusta

Por cierto, en cuanto abras el parentesis del método “GetItemPrice”, te mostrará que parámetros son necesarios, como muestra la siguiente imagen:

Saludos

1 me gusta

Hola que tal @chavalito muchas gracias por tu respuesta.

Me recomiendas que esto lo realice sólo con el objeto Cotización? Por ejemplo, no sería necesario hacerlo con el objeto oCompany verdad? ya que quiero que la conexión se mantenga hasta que el usuario termine de realizar las cotizaciones que sean necesarias.

Fijate que si tengo una pero es bastante más sencilla que el ejemplo que me proporcionas:

if (iret == 0)
    HttpContext.Current.Response.Write("<script>alert('Se creó la cotización: " + oCompany.GetNewObjectKey() + "');</script>");
else
    HttpContext.Current.Response.Write("<script>alert('Error al crear el documento: " + oCompany.GetLastErrorDescription() + " | Código de error: " + oCompany.GetLastErrorCode() + "');</script>");

Después de ver tus ejemplos creo que optaré por implementarlos, ya que quiero utilizar las mejores prácticas a mi alcance y poder garantizar el correcto funcionamiento de la aplicación.

De nuevo gracias por tu respuesta estimado. Un saludo desde Monterrey (tierra de las carnes asadas :stuck_out_tongue_winking_eye:).

Buenas tardes @l.villarreal

De hecho no te sugerí liberar el objeto “oCompany”, porque veo que no te conectas en el mismo proceso, ya sea directo o mediante la llamada de un Clase/Método, sin embargo, como comentario, yo SI acostumbro abrir y cerrar la conexión. Finalmente mientras mantengas abierta la aplicación, solo la primera vez tarda un poco al momento de conectarse, posteriormente es relativamente rápido.

Saludos

Buen día @chavalito , perdón por la tardanza.

Si efectivamente, sólo hago una validación al inicio de la creación de la cotización para que se conecte, y como mencionas tu al ser la primera conexión tarda un poco, y posteriormente se agiliza bastante.

Imaginando que el usuario realizará 10 documentos en el programa, ¿Es mejor conectarse y desconectarse constantemente que generar una sola conexión al objeto Company?
Cabe mencionar que serían varios usuarios los que usen el programa al mismo tiempo, por lo que te agradecería mucho si me pudieras aclarar esta última duda en base a tu experiencia, con el fin de poder lograr el mejor rendimiento de la aplicación.

Gracias de antemano, saludos cordiales.

Buenas tardes @l.villarreal

Ambos son funcionales, sin embargo, hay situaciones en las que es mejor conectarse y desconectarse en el mismo proceso.
En lo personal, yo prefiero conectarme y desconectar, primero, no tengo procesos que necesiten correrlo una y otra vez, cuando mucho 2 veces al día (en ocasiones ninguna), segundo, en mi caso hay usuarios que están conectados a la red mediante antena, por lo cual hay desconexiones momentaneas durante el día, de tal forma que si mantengo abierta la conexión a SQL dependiente del tiempo, es problable que la aplicación truene cuando intentan ejecutarlo y eso de alguna manera causa incertidumbra ante el usuario.

En tu caso, si tus usuarios necesitan ejecutar el proceso muchas veces y además son continuas, es preferible que la dejes abierta, de esta forma te ahorras nos segundos en cada ejecución del proceso.

Saludos
SAP B1, v9.2 PL03
México

3 Me gusta

De acuerdo muchisimas gracias por tus aclaraciones y tu tiempo. Procederé a seguir tus consejos :slightly_smiling_face:

Saludos cordiales.

Este tema se cerró automáticamente 7 días después del último post. No se permiten nuevas respuestas.