• Este debate está vacío.
Viendo 3 entradas - de la 1 a la 3 (de un total de 3)
  • Autor
    Entradas
  • #31390
    Javier Ader
    Participante

    Prueba de concepto: En Ordenes de Pago se seleccionan dos facturas de proveedor. F1 y F2. A la primera se le salda 10, a la segunda 20. En la segundo tab se crean dos medios de pago en efectivo (esto último por simplicidad… con cualquier otro medio de pago el problema sigue estando); P1, de 10 y P2 de 20.
    Esto deberia generar un C_AllocationHdr y dos C_AlloctionLine asociadas al header(AL1, y AL2); la primera saldando el pago de F1 con P1, la segunda saldando el pago de F2 con P2. Ademas por cada un de los P1 y P2 se debe generar una linea en el libro de Caja; la priemra con valor 10, la segunda con valor 20 (LL1, LL2). Estas lineas deberían quedar asociadas a las lineas a alocacion; AL1 <-> LL1 (las dos saldando 10 de la F1); AL2 <->LL2 (las dos saldando 20 de F2).
    Bueno, el problema es que esto no ocurre( al menos en la version 10.3) y se generan 3 C_AlloctionLines; las dos primeras con monto 10 (asociadas la primera a F1 y la segunda a F2); PERO relacionadas con la primer linea de libro de caja (el cual tiene monto 10); la tercera con monto 10, saldando los otros 10 de F2 PERO relaciada a la linea de caja de monto 20.
    Pueden ejecutar la sig sentencia sql para verificarlo

    Code:
    select h.C_allocationhdr_id , l.amount,l.c_cashline_id, l.c_invoice_id, cl.amount as amountLineaLibro
    from c_allocationhdr h
    left join c_allocationline l on (l.c_allocationhdr_id = h.c_allocationhdr_id)
    inner join c_cashline cl on (cl.c_cashline_id = l.c_cashline_id)
    order by h.created desc, l.c_cashline_id

    Ahí se ve claramente, mirando las 3 primeras filas que la linea de libro de 10 (columna AmountLineaLibro) se usa para saldar dos veces tanto la primer factura como la segunda (y en los casos salda 10); y que la otra, que tiene AmountLineaLibro de 20, se usa para saldar 10 que le faltaban saldar a la segunda factura (a esa linea de caja concpetualmente le quedan 10 que pueden ser usados para saldar otras cosas…).

    El error por lo que vi (no lo testie… pero estoy casi seguro) esta en doPostProcesarNormal() en las lineas 1608-1618

    Code:
    if (compararMontos(deboPagar, sumaPagos) < 0) { // Si sobra ... int x = montosSubPagos.size() - 1; sobraDelPago = sumaPagos.subtract(deboPagar); // Si sobra plata, en el ultimo monto hay plata de más. montosSubPagos.set( x, montosSubPagos.get(x).subtract(sobraDelPago)); } else { sobraDelPago = null; }

    El tema es que el else de “Si sobra”, setea correctamente sobreDelPago a null, pero no incrementa el la variable usada para pasar al proximo MedioPago (payIdx), esto lleva a que un medio de pago que completa justo el saldo de una factura sea utilizado nuevamente para saldar la próxima. Esto es, el else debería hacer lo siguiente (o opcionalmente se podría dejar el else como esta e inicializando payIdx en -1, y si al principio del bucle de factura, si sobraDelPago == null, se incrementa payIdx; e.d payIdx++)

    Code:
    } else {
    //NO sobra nada del ultimo medio de pago, por lo tanto
    //se debe pasar al próximo Medio de Pago
    payIdx++; //Nunca “debería” generar un acceso fuera de indice sobre el vector de medios de pagos…
    sobraDelPago = null;
    }

    Igual, habría que mirarlo un poco más (me da un poco de miedo las pequeñas diferencias que creo que se permiten entre el monto a saldar entre todas las facturas y la suma en los medio de pagos… tal vez incrementando “ciegamente” payIdx, dispara un acceso fuera de limite bajo otras circunstancias; pero en ese caso el bug pasaría a estar en otro lugar)
    Que implicancias tiene? Con los pagos en efectivo no lo veo muy crítico, pero con los otros quizá sea un poco más complicado… no se como se reflejará saldar por ej, con un cheque de tercero de 10, dos facturas de 10 (para lograr esto, un debería agregar otro medio de pago para llegar a 20, si no el formulario “chlla” antes porque las cantidades a saldar y la suma de los medios de pago difieren; pero el cheque de tercero se va a usar para saldar las dos facturas, al menos a nivel de C_AllocationLine). Tener en cuenta igual que esto solo se produce cuando uno salda más de una factura y cuando los montos de los medios de pago “justo” concuerdan para que uno de estos alcance a saldar exactamente el monto a pagar de una de las facturas intermedias (este medio de pago se va a usar para saldar también la próxima).

    No mire el código de Ordenes de Cobro; tal vez ocurra lo mismo.

    PD: creo (mmmm no estoy muy seguro…) que al menos en la lineas de libro la factura asociada no siempre es la correcta (en particular cuando se salda más de una factura); tal vez esto se pueda subsanar seteandole el C_Invoice_Id dentro del bucle de facturas (y volverla a salvar acá….). Algo como

    Code:
    if (mp.getTipoMP().equals(MedioPago.TIPOMEDIOPAGO_EFECTIVO)) {
    MedioPagoEfectivo mpe = (MedioPagoEfectivo) mp;
    line = mpe.getCashLine();
    line.setC_Invoice_ID(C_Invoice_ID);//se setea aca
    saveOk = saveOk && line.save(); //y se salva
    allocLine.setC_CashLine_ID(line.getC_CashLine_ID());
    }

    Pero bueno habría que ver si esto no trae otros problemas (tal vez tire error el beforeSave de la lineas de libro… no se si se puede modificar la factura asociada una vez creada la linea…), ademas que ese save() creo que corre bajo otra transacción…
    Esto tal vez se aplique a otros medios de pago (no mire muchos mas…). De todas maneras esto último es más bien “cosmetica” y no se si importa mucho. Dicho sea de paso… una misma linea del libro puede usarse para saldar 2 o más facturas…. asi que la relación Linea Libro -> Factura no siempre va reflejar completamente la realidad (la “realidad” las muestra las lineas de alocación), pero por lo menos va apuntar siempre a una de las facturas (la última) que ayudo a saldar.

    #34443

    Gran aporte Javier! Estuve haciendo pruebas y tal como lo mencionas logré reproducir el error. Como vos decís, se tienen que dar una serie de condiciones para que justo se produzca el caso que falla, y creo que por esa complejidad no haya sido detectado antes.
    La solución? La misma que vos propusiste: agregar el incremento a payIdx cuando se cubre el total de una factura (rama del else).

    Code:
    } else {
    //NO sobra nada del ultimo medio de pago, por lo tanto
    //se debe pasar al próximo Medio de Pago
    payIdx++; //Nunca “debería” generar un acceso fuera de indice sobre el vector de medios de pagos…
    sobraDelPago = null;
    }

    En principio no se debería producir un acceso fuera de índice ya que se asume que la suma de los importes de los pagos es igual a la suma de los importes de las facturas, con lo cual, en la próxima iteración si aún queda un monto por cubrir de alguna factura también habrá un pago disponible en el arreglo para cubrir esa factura. De todos modos, habría que hacer pruebas con montos que no sean enteros, que tengan varios decimales porque ahí no me queda claro si la comparación puede llegar a fallar y en ese caso intentar acceder al arreglo de pagos cuando en realidad ya se han acabado.

    Este bug estará corregido obviamente en el próximo release de Libertya.
    Muchas gracias por tu aporte Javier
    Saludos
    Franco

    #34444
    Javier Ader
    Participante

    Gracias Franco y como siempre, es un gusto poder aportar algo a Libertya. En cuanto al acceso fuera de indice , de última y para andar por lo seguro, se podría incrementar solo sin no va a generar una excepcion en la proxima entrada al bucle

    Code:
    else{

    if (payIdx < pagos.size() -1 ) payIdx++; else log.log(Level.SEVERE, "mmm no debería pasar");; sobraDelPago = null; }

    Así en caso de no estar completamente seguros que de que no va generar una excepción, por lo menos nos evitamos agregar un nuevo error; dentro de ese bucle generar un ArrayIndexOutOfBoundsException debe ser una situación bastante desagradable (el remedio peor que la enfermedad)…. pero bueno, el while que esta justo antes no es tan “escrupuloso” e incrementa payIdx sin miramientos….

    Saludos

    PD : Programación defensiva vs código elegante, el viejo dilema…

Viendo 3 entradas - de la 1 a la 3 (de un total de 3)
  • Debes estar registrado para responder a este debate.