Líneas de propuesta de factura duplicadas en Dynamics AX 2012

Hace unas semanas encontramos y reportamos a Microsoft un error en el estándar de Microsoft Dynamics AX 2012 que provoca que las líneas se repitan al crear propuestas de factura y también al registrarlas posteriormente. Aunque Microsoft me confirmó entonces que está solucionado en Microsoft Dynamics AX 2012 R2, publico aquí el código que utilicé para solucionarlo ya que la pregunta ha aparecido en los foros de El Rincón Dynamics.

Poniendo “infos” en el código se puede detectar rápidamente que hay una función estándar que, aunque funciona correctamente, se ejecuta más veces de las necesarias. Concretamente se ejecuta para todas las líneas, una vez por línea, provocando que aparezca cada línea, tantas veces como líneas tenga la propuesta. Aquí se ve mas claro:

Esto se soluciona modificando el método doSalesLine de la clase estándar PSAProjProposalSelection como indico a continuación:


protected void doSalesLine()
{
    SalesLine               salesLine;
    SalesTable              salesTable;
    SalesQuantity           salesQuantity = SalesQuantity::construct(DocumentStatus::Invoice);
    SalesQty                deliverNow, remainBefore, remainAfter;
    Query                   saleQuery;
    QueryBuildDataSource    saleQbds;
    QueryBuildRange         salesIdQbr;
    QueryRun                saleQueryRun;

    // JAEE 20121022 begin
    // salesTable = m_oQueryRun.get(tablenum(SalesTable));
    salesLine = m_oQueryRun.get(tablenum(SalesLine));
    // JAEE 20121022 end
   
    // JAEE 20121022 begin
    //if (salesTable && salesOrderLine)
    if (salesLine && salesOrderLine)
    // JAEE 20121022 end
    {
        // JAEE 20121022 begin
        //
        // saleQuery = new Query();
        // saleQbds = saleQuery.addDataSource(tableNum(SalesLine));
        // saleQbds.addSortIndex(indexNum(SalesLine, SalesLineIdx));
        //
        // salesIdQbr = saleQbds.addRange(fieldNum(SalesLine,SalesId));
        // salesIdQbr.value(salesTable.SalesId);
        // this.addSalesLineRange(saleQbds);
        // saleQueryRun = new QueryRun(saleQuery);
        // while (saleQueryRun.next())
        // {
            // salesLine = saleQueryRun.get(tableNum(SalesLine));
        // JAEE 20121022 end
            salesLine.selectForUpdate(true);

            if (salesLine.canBeInvoiced())
            {
                [deliverNow, RemainBefore, RemainAfter] = salesQuantity.qtySales(salesLine, salesUpdate);

                if (deliverNow)
                {
                    m_tProjProposalTrans.clear();
                    m_tProjProposalTrans.initFromSalesLine(salesLine, deliverNow);
                    m_tProjProposalTrans.insert();
                }
            }
        // } // JAEE 20121022 commented
    }
}

Con este cambio se corrige la creación de propuestas de factura haciendo que la función correspondiente se ejecute para cada pedido, no para cada línea. Pero en el siguiente paso, al ir a registrar estas propuestas, el código sigue fallando de la misma manera:

Esto lo solucionamos modificando el método doProposal de la clase ProjInvoiceChooseNormal de esta manera:

protected void doProposal()
{
    super();

    // <PSA>
    //  Don't create proposals for Cap projects
    if (isConfigurationkeyEnabled(configurationkeynum(Project3)) && pProjTable.PSAInvoiceMethod == PSAInvoiceMethod::cap && !m_bUseTmpProjProjProposal)
    {
        return;
    }
    // </PSA>

    if (queryEmpl & queryRun.changed(tablenum(ProjEmplTrans)))
    {
        this.doEmpl();
    }

    if (queryCost && queryRun.changed(tablenum(ProjCostTrans)))
    {
        this.doCost();
    }

    if ((queryRevenue || querySubscription) && queryRun.changed(tablenum(ProjRevenueTrans)))
    {
        this.doRevenue();
    }

    if (queryItem && queryRun.changed(tablenum(ProjItemTrans)))
    {
        this.doItem();
    }

    /* <SYS>
    if (querySalesLine && queryRun.changed(tablenum(SalesTable)))
    </SYS> */

   
    // JAEE 20121022 (deleted) begin
    // <PSA>
    //if (querySalesLine &&
    //    (isConfigurationkeyEnabled(configurationkeynum(Project3)) ? queryRun.changed(tablenum(SalesLine)) : queryRun.changed(tablenum(SalesTable))))
    // </PSA>
    // JAEE 20121022 (deleted) end
   
    if (querySalesLine && queryRun.changed(tablenum(SalesTable))) // JAEE 20121022 Original code commented by <SYS> (!?)
    {
        this.doSalesLine();
    }
}

Evitando de nuevo un bucle interno que se repita para cada línea. Y así, de momento, todo está funcionando. Es importante decir que esta es MI solución y que por tanto puede no ser la definitiva ya que este funcionamiento no está documentado y está solucionado mediante ensayo-error-debug. Cualquier comentario lo podéis dejar en los comentarios a la espera de que se publique el hotfix definitivo. Cualquier uso que se dé a este código debe ser probado en un entorno de validación antes de ponerlo en producción.

Se puede consultar el ticket (cerrado) sobre esta incidencia en Microsoft Connect

Descargar código

2 comentarios
  • jaestevan
    octubre 24, 2012

    Hola Carlos,

    Gracias por el comentario, ya he arreglado el post con cada función donde le toca.

    Es posible que tu objeto no fuera de la misma versión y por eso uno de los métodos ya está arreglado. Mi código es de la MV de Microsoft publicada en PartnerSource, no recuerdo la versión pero diría que es AX 2012 CU2.

    Saludos.

  • Carlos Herrando
    octubre 23, 2012

    Buenas,
    estoy probando el código que comentas y el de la función doSalesLine ya está así en la versión del objeto que yo tengo, así que no he tenido que cambiar nada.
    Respecto a la función doProposal lo he cambiado y perfecto.
    Muchas gracias.
    Por cierto aquí en la web te has liado y has cambiado las funciones de sitio, pero genial.