- Este debate está vacío.
-
AutorEntradas
-
20 octubre, 2010 a las 3:34 pm #31569Javier AderParticipante
Buenas, vi que esta clase fue modificada en la nueva versión; estuve mirando los fuentes y encontré un par de observaciones para hacer (no muy importantes, pero bueno):
1) Pagos: loadInvoicePayments ejecuta un select ordenado por la cantidad del pago, pero de manera ascendente; creo que la idea, mirando un poco el código es que haga lo contrario; esto es, que traiga los pagos de mayor valor primero. Es decir, habría que cambiar al final de la variable sql “ORDER BY PaidAmount” por “ORDER BY PaidAmount DESC”
2) Facturas sin pagos y con pagos a “crédito”: aca pienso que hay una inconsistencia; ejemplo
100 a pagar; 10 efectivo, 90 a credito
-> se envia al controlador fiscal solo un pago
“Efectivo 10”
Pero el controlador (bajo Hasar), al recibir posteriormente el cierre de documento agrega el un “pago” con nombre establecido por configuración con el monto faltante, por defecto “Cuenta Corriente”:
“Cuenta Corriente 90”Ahora, si un factura se paga totalmente a crédito (desde el TPV o desde la ventana de Facturas de Cliente), loadInvoicePayments no va a encontrar ningúb pago asociado (“A crédito” no es un pago real bajo Libertya); y en ese caso va a volver al funcionamiento de la versión 10.03 agregando un pago cuyo nombre lo toma de la “regla de pago” de la factura y cuyo monto es el total de la misma; acá se le va enviar, dependiendo de algo que no tiene nada que ver con un pagos, algo como:
“A Crédito 100”
o incluso
“Efectivo 100”;
(este ultimo aún cuando no se pago nada; esto ocurre porque este valor viene asociado a los regla de pago de la factura)Esto es, si se paga una parte a crédito se imprime lo que dice la configuración del CF; si se paga todo a crédito, se imprime lo que dice la regla de pago (que ademas puede traer cualquier cosa; como por ej, efecivo). Para mi la solucion es : bueno, si no hay pagos, simplemente no se envian pagos al CF, y asi siempre se imprime la misma leyenda para los pagos (totales o parciales) a crédito. Esto es, la linea 792, se cambian por:
Code://NO SE AGREGA NINGUN pago; la leyenda por el pago total
//la imprime el CF dep. de su configuración; por defecto “Cuenta Corriente”
if (totalPaidAmt.compareTo(BigDecimal.ZERO) == 0) {
return; //NO SE AGREGA NINGUN pago; la leyenda la imprime el CF
}else….Otra forma de decirlo: no se mira nunca la regla de pago de la factura; no se usa nunca: si hay no hay ningún pago, no se emite ninguno y listo (el CF lo va a hacer automáticamente por nosotros).
3) Total de pagos máximos permitidos: bueno como en el código se ve, nunca se envían mas pagos que los que soporta el CF. Ahora bien, la documentación de Hasar no es del todo clara, pero consultando con el soporte hace un tiempo, es claro que hay que tener cuidado con ese limite. Básicamente es así: la mayoría de la tiqueadoras/facturadoras soportan recibir como máximo 4 comandos TotalTender, porque físicamente (o internamente) tiene esta cantidad de lineas para la imprimir los pagos. Ahora, bien, el tema es cuando uno emite el último pago permitido: este tiene que necesariamente saldar el total a pagar (la ultima linea es especial, poruqe es la misma que usa el CF automáticamente para saldar los pagos no alcanzan el total; dice algo asi “la ultima linea es mia, la podes usar vos pero siempre y cuando saldes completamente la factura, si no alcanzas, no la podes usar”).
El problema se agrava debido a quetotal a saldar segun el CF puede ser distinto (quizá por un par de centavos, pero distinto) que lo que supone Libertya; la razón es el CF hace sus propias cuentas (con sus propios redondeos) para inferir cual es el monto total.
Aca veo dos soluciones:
-cortar por lo sano: emitir a los sumo TotalDePagosPermitidos menos 1. Es medio restrictivo, pero hay que tener en cuenta que muchos CF no permiten cancelar un documento una vez emitido al menos un TotalTender; si se da la situación de que se usaron todos los pagos permitidos pero no se saldo se alcanzo a saldar totalmente la factura, el ultimo TotalTender es rechazado, pero ademas, no se puede cancelar el documento en curso (esto es; el usuario no puede simplemente reintentar el pago subiendo unos centavos alguno de los medios de pagos con la intención de que el error no vuelva a ocurrir porque el CF simplemente se niega a abrir otro documento; el documento anterior esta a al espera de ser cerrado o de que reciba un TotalTender que lo salde completamente….)
-un poco mas complejo: los comandos de pago TotalTender y el comando SubTotal (que esta siendo emitido por los drivers actualmente) retornan lo que falta saldar; esto valor se podria mantener en una varialbe de estado y en caso de que uno este por emitir el TotalTender permitido mirar si el valor que se va a enviar es menor el ultimo valor retornado por TotalTender y en ese caso, emitir un ultimo TotalTender con este valor o simplemente no emitirlo (dejando que el CF salde exactamente la factura con su ultimo pago automático). Igual aca surge otro problema: se estaria incrementando el valor del ulitmo pago para satisfacer el redondeo , cuando puede darse el caso de que este pago sea muy inferior al retorno el TotalTender (e.d, uno incrementa el valor suponiendo que es un error de redondeo cundo en realidad es porque un parte importante que es a credito…); ej:
Total 100
Pagos a emitir:
Efectivo 10
Cheque1 10
Cheque2 10
Cheuqe3 10
(resto a credito: 60)
El TotalTender del cheque2 va a retornar que falta pagar 70; uno tiene el ultimo pago permitido (Cheque3) con un valor de 10. Si ahí se asume que hubo un error de redondeo se estaría emitiendo el Cheque3 incrementándolo de 10 a 70.
Fijense que este ejemplo, aún cuando no haya discrepancia de redondeos hace que la impresión falle.
Tal vez la una solución intermedia sea:
*si es el ultimo pago permitido y lo que hay que saldar segun nos informo el CF mediante el ultimo TotalTenderCF es “un poco menor”, se incrementa este pago, porque se asume un error de redondeo (“un poco menor” digamos 1, o si se quiere un poco mas grande: 5)
*si no, esto es la discrepacia es demasiado grande como para asumir que es un error de redondeo: o no se emite envia el pago (y se deja el que el CF salde por su cuenta el total emitiendo por si mismo el último pago) o se envia un ultimo pago con el valor que informo el ultimo TotalTender, pero se le cambia la leyenda: digamos, en el ejemplo, el Cheque 3 podría ir asi:
“A. Crd. por 60, y Cheque3” 70
o
“Cheque3 por 10 Resto Cred.” 70Estaría perfecto, porque no se perdería información, si no fuera problema de que la descripción se puede hacer muy larga, y por lo tanto, por una limitación del CF quede algo como
“Cheque3 por 10 R” 70
Esto se da más que nada en la tiqueadoras que tiene un limite de ancho de 24/28 para las descripciones de pago (las facturadoras creo que tiene un limite de 80; un poco mas difícil de alcanzarlo)
Probablemente, tal vez sea mejor poner un prefijo mas corto:
“C:60 Cheque3” 70El prefijo C:60 se debería entender como que el valor del cheque real es por la diferencia entre lo que dice la linea impresa y el monto que dice el prefijo (C:60 dice “60 son en realidad a crédito, el cheque es por 10”).
Con cualquiera de estas formas, se solucionaría el problema y la facturación al menos no fallaria. Yo en una versión de 10.03 modificada para tener la emisión de pagos dada en la 10.09, opte por la primera… simplemente el total de pagos máximos emitidos es el total real menos uno (justo en mi caso no me complica mucho la vida, porque se va a usar contra un P441 que tiene un limite de real de 5 emisiones de pagos; por lo tanto el limite que impone libertya es 4, lo debe alcanzar y sobrar para los mayoria de los casos; también, podría haber dejado el limite en 5 ya que esta tiqueadora tiene la capacidad de cancelar documentos incluso luego de la emisión de TotalTender…..).
4) TotalTender que falla porque ya se saldo el pago: bueno, esta un poco relacionado con el anterior y con el redondeo: un TotalTender puede fallar si se emite cuando según el controlador no hay nada que saldar según el TotalTender anterior (el TotalTender retorna un numero positivo para expresar lo que falta; un numero negativo para expresar el cambio y que el TotalTender emitido ya saldo el total; +0 cuando el TotalTender saldo exactamente el total). En estos casos NO se debe emitir mas TotalTender porque van a fallar. Este caso es un poco mas difícil que se de que el anterior pero es probable. La solución que me imagino es que los drivers vayan mirando esto valores de retorno (seria la misma variable de estado usada para la segunda solución del punto anterior) y dejen de emitir TotalTender cuando sea menor o igual que cero, independientemente de lo si el documento tiene mas pagos.
5) Pagos con tarjeta (problema menor): actualmente se emite algo como “VISA xxxxxxxxxxxx”; donde X’s son el numero de tarjeta, si no me equivoco un numero de 20 dígitos; bien, el tema es que se puede cortar en el caso de las tiquedoras (limite de 28) si en vez de VISA se pone por ej “Mastercard”; si se pusiese un abreviado, digamos MSTC no pasaria. Igual, esto creo que no es un problema importante y un poco dificil de solucionar (al hacer las descripciones se debería sabe si se va a emitir sobre una tiqueadora o facturadora…).
Igual, una solución sería tener la convención de emitir siempre primero el número de la tarjeta y despues el nombre (esto es; en vez de “Mastercard XXX….XXXXX”, emitir “XXXX….XXXXX Mastercard”; si se corta a lo sumo quedaria algo como “XXX…XXXX Mast” que se puede llegar a inferir que es un tarjeta de credito Mastercard). Lo mismo se podria aplicar a transferencias bancarias, cheques o notas de créditos (esto es, en vez de “Cheque XXXX…XXXX” ; “XXXX…XXXX Cheque”). Esta convención quizá se correcta usarla solo si se sabe que el CF es una tiqueadora (para esto ultimo pienso que habría que modificar la interfaz FiscalPrinter para agregar un método tal como “IsTiqueadora” o algo por el estilo); bajo una facturadora, es muy difícil que esto pase.Saludos.
21 octubre, 2010 a las 10:20 pm #35093Javier AderParticipanteBueno, aporto unas modificaciones que hice para manejar el tema del último TotalTender permitido; básicamente agregue tres métodos (yo los agregue a un driver que aún no termino completamte; despues lo subo; en el código de 10.09 o 10.03 debería ir en HasarFiscalPrinter.printInvoice, posiblemente modificando la forma en que se llama a cmdTotaTender):
Code://SOPORTE PARA PrintPayments. Ader 20 oct 2010
/**
* Detemina si el CF soporta la cancelación de documentos despues de la emisión
* de un TotalTender; todas las tiqueadoras no soportan la cancelación leugos
* de la emisión de un TotalTender “excepto en los modelos SMH/P-PR5F (versión 2.01),
* SMH/P-715F (versiones 3.02 y posteriores), y SMH/P-441F.” (Sic. 3.4.10 TotalTender, Doc Hasar
* PubTick.pdf); todas las facturadoras parecen no permitir esto (Sic. 3.7.1. Cancel , Doc Hasar
* PubFact). Implemtanción default retonra false.
* @return
*/
protected boolean allowCancelAfterTotalTender()
{
return false;
}/**
* Dada una respuesta a un TotalTender retorna el valor del campo que representa
* el faltante para saldar el total de la factura según el CF. Un valor
* positivo supone un faltante; cero saldado exactamente; y un némero negativo
* reqpresenta “cambio”.
* NOTA: este metodo retorna null si encuentra algún problema (por ej, el rspTotalTender
* no tiene el formado requerido); esto es asi porque propagar una excepcion en este
* punto puede llegar a dejar a varios CF en un estado de bloqueo (los documetnos abiertos
* no se pueden cancelar luego de emitido un TotalTender en mucho modelos/versiones).
* NOTA2: esta implementación siempre retorna un BigDeciaml redondeado a dos decimales
* con redondeo DOWN (hacia cero); esto no deberia afectar ya que todos CF Hasar retorna 2 decimales
* en esta respueta.
* @param rspTotalTender
* @return
*/
protected BigDecimal getRemainingAmount(FiscalPacket rspTotalTender)
{
BigDecimal remAmount = null;
if (rspTotalTender == null)
return null;
try{
//el monto esta en 3er campo
String remAmoutString = rspTotalTender.getString(3);
//se asume que que el CF no retorna cosas raras como “+.00” o “-0.”
remAmount = new BigDecimal(remAmoutString);
remAmount = remAmount.setScale(2, RoundingMode.DOWN);
}catch(Exception ex){}return remAmount;
}
//FIN de soporte para printPayments/**
* Ref C++ Hasar: ver ImpresorFiscal::ImprimirPago
* NOTA Maxima cantidad de pagos permitidos: Este metodo emite a los sumo
* getAllowedPaymentQty() de TotalTenders
* NOTA Tiqueadoras: Para los modelos SMH/P-715F -versiones 3.02 y posteriores-,
* SMH/P-PR5F -versión 2.01- y SMH/P-441F puede emitirse 5 veces; 4 en el resto.
*
* NOTA Cancelacion luego de pagos: esta implementación invoca a setCancellowed(false) luego
* de la emisión de un TotalTender solo si allowCancelAfterTotalTender() retonra false. Esto último
* es el comportamiento por defecto, ya que todas los CF Hasar no permiten la cancelación
* de docuemtnos luego de la emisión de un TotalTender, salvo las tiqueadoras
* SMH/P-715F -versiones 3.02 y posteriores-, SMH/P-PR5F -versión 2.01- y SMH/P-441F en
* las cuales la cancelación SIEMPRE es posible; los drivers de estos modelos deberían redefinir
* allowCancelAfterTotalTender() para que retorne true.
*
*
* Comentario acerda del último pago: El Comando TotalTender asociado puede
* fallar (es rechazado) si el pago adeudado es 0, o, mas importante, si se esta emitiendo
* el ultimo TotalTender permitido (el quinto o el cuarto, dep. del modelo/version) y este no
* alcanza a saldar totalmente el monto a saldar. Aca hay dos posibles soluciones: siempre emitir
* una cantidad menor de TotalTenders (4 o 3 maximo, dep. del modeolo/version) o en usar el valor
* de la respuesta Monto Faltante del anterior TotalTender usar este monto como el
* monto del ulimto TotalTender en caso de que Payment.getAmount sea menor.
* NOTA modificación 20 oct 2010 :
* MODIFICACION DE MANJEJO DE ULITMO TOTAL TENDER:
* 1) Por cada Payment
* -SI, monto faltante según el CF es menor o igual que cero; finaliza la impresión de pagos
* -SI no, si estamos estamos en el ultimo pago y este es menor al faltante, CAMBIAR MONTO de pago
* al faltante y posiblemente su descripción
* 2) ejecución normal de un TotalTender, chequear si se deben prohibir cancelaciones,
* actualización del total faltante a partir de la respueta del TotalTender.
*
* @param payments
*/
protected void printPayments(Listpayments) throws FiscalPrinterIOException, FiscalPrinterStatusError
{
if (payments == null || payments.size()<=0) return; int maxTotalTenders = getAllowedPaymentQty(); BigDecimal remAmount = null; for (int i = 0; i < payments.size(); i++) { Payment pay = payments.get(i); BigDecimal payAmount = pay.getAmount(); String payDesc = pay.getDescription(); int numPayment = i + 1; //1,2,3.... if (numPayment > maxTotalTenders)
{
//NO debeira pasar, significa que se agregar mas payments que los
//permitidos a por getAllowedPaymentQty
break;
}
//assert(numPayment<= maxTotalTenders) if (remAmount != null) { if (remAmount.compareTo(BigDecimal.ZERO)<=0) { //se saldo completamente y aún quedan pagos! aca podria ir //un warning o mensaje, ya que no deberia pasar en general break; } //assert(remAmount != null && remAmount > 0)-> esto es, hay faltante//estamos por emitir el ulitmo TotalTender permitido, hay que chequear
//redondeos o modifaciones de la descripción del pago y del monto
//a pagar eviando remAmount para que no genere error (obligadamente se debe saldar
//completamente el documento con este TotalTender).
//Estas modificaiones solo son necesarias cuando el monto del pago es menor a
//el faltante; si es mayor o igual no se genera error nunca.
if (numPayment == maxTotalTenders && payAmount.compareTo(remAmount)< 0) { //el monto que le falta a payAmount para saldar completamente el documento BigDecimal difCredito = remAmount.subtract(payAmount); //modificación de la descripción original: //por simplicidad SIEMPRE se agrega a la descipción //"CC: difCredito, Resto:
//esto es, se supone que no hay error de redondeo; otra forma
//seria simplemente poner “Otro Pagos” y no usar el prefijo.
payDesc = “CC:” + difCredito.toPlainString()
+”, Resto:” + payDesc;
//finalmente, el monto a pagar realmente se pone a remAmount, asi
//el TotalTender salda exactametne el total de la factura. Este
//es el unico punto en que se cambia el monto a enviar.
payAmount = remAmount;}
}//se ejecuta el TotalTender
FiscalPacket rspTotalTender = execute(
cmdTotalTender( payDesc,payAmount,””));//solo setea cancelAllowed a false, si el CF NO permite la cancelación de documentos
//luego de un TotalTender.
if (!allowCancelAfterTotalTender())
setCancelAllowed(false);//se atualiza el totalFaltante o cambio
remAmount = getRemainingAmount(rspTotalTender);
//assert(remAmount != null) si no seria un error de formato en la respuesta}
}
Esta bastante comentado, supongo que se entiende; básicamente opte por implementar la solución mas complicada (esto es permite la emisión de pagos máxima, pero si se llega al último pago permitido y se ve que no va saldar completamente la factura, se cambiar el valor a emitir en el pago, pero cambiándole la descripción).
OBS: mi versión de printDocument(Invoice) no llama directamente cmdTotalTender si no que lo delega a printPayments; es decir las lineasCode://////////////////////////////////////////////////////////////
// Se ingresan los pagos realizados por el comprador.
// Comando: @TotalTender
for (Payment payment : invoice.getPayments()) {
execute(cmdTotalTender(
payment.getDescription(),
payment.getAmount(),
false,
null)
);
setCancelAllowed(false);
}se cambian por
Code://////////////////////////////////////////////////////////////
// Se ingresan los pagos realizados por el comprador.
// varios @TotalTender
printPayments(invoice.getPayments());Testeo:
lo testie forzando a llegar al limite te pagos y no saldar:
Total a pagar:
A PAGAR: 363,00
-50 efectivo
-100 tarjeta 1234, cupon 1
-100 tarjeta 1234, cupon 2
-100 tarteta 1234, cupon 3
-Resto a Credito desde el TPV: 13.00
Esto genera 4 TotalTenders (y por el efectivo y 3 por los pagos con tarjeta), pero el ulimto que emite de las tarjeta los hace por 113.00 , con la descripcion de la forma “CC:13.00, Resto:Visa 1”. Esto es, salda completamte la factura con el ultimo pago, pero le cambia la descripción reflejando este hecho.
EL otro teste que hice fue por el mismo monto y cantidad de pagos reales, pero de tal manera que no sea necesario una parte a crédito:
A PAGAR: 363,00
-50 efectivo
-110 tarjeta 1234, cupon 1001
-90 tarjeta 1234, cupon 1002
-113 tarteta 1234, cupon 1003
El último pago salda exactamente la factura, asi que al emitir el úttimo TotalTender, no le cambia la descripción.28 octubre, 2010 a las 12:48 pm #35094Franco BonafineMiembroAlgunos comentarios sobre la implementación actual y las correcciones de Javier:
1) Correcto, lo más lógico es que ordene los pagos según su importe de mayor a menor y no de menor a mayor como lo está haciendo ahora.
2) Correcto para TPV, pero hay que tener en cuenta que en Libertya también se puede emitir facturas desde la ventana de Facturas de Cliente. Al completar una factura, se emite el comprobante fiscal y aquí no es tan válida la suposición que hace Javier. Cuando completamos la factura desde esta ventana, nunca va a tener pagos asociados dado que justamente la estamos completando. Es por eso que se tuvo en cuenta el caso (pagos = 0) en el cual se imprime lo que dice el PaymentRule de la factura, ya que, si al completar la factura desde la ventanas de facturas la misma tiene un PaymentRule “A Crédito”, entonces hay que indicar eso mismo en el ticket, y si tiene un PaymentRule “Efectivo” (recordar que aquí se crea la línea de caja automáticamente), el ticket debe imprimir “Efectivo” (cosa que con la solución de Javier seguiría imprimiendo el default del CF, que es normalmente “Crédito” o “Cuenta Corriente”). Aquí, con los cambios realizados también se produce una inconsistencia entre el documento en Libertya y el ticket/factura impresa, con lo cual hay que definir una solución diferente que se adapte a los dos casos.
28 octubre, 2010 a las 3:02 pm #35095Javier AderParticipanteBuenas Franco. Más allá de lo que decís, sigo pensando que es incorrecto. Los TotalTenders (emisiones de pagos), son para registrar pagos reales, y típicamente van precedidos de un leyenda “Recibos:” (y si uno una factura por 100$ lee “recibimos: efectivo 100”, se entiende que esta saldada, cuando esto no es necesariamente el caso con el código actual incluso cuando no se generaran automáticamente lineas de cajas). La PaymentRule pienso que se deberia usar para registrar solo la forma de pagos requeridas para pagar lo que falta saldar, no se deberia tomar nunca como un pago por el simple hecho de que tal pago no se realizo. Esto es, la PaymentRule es solo para especificar como el cliente deberia pagar lo que falta (“pagame lo que resta en efectivo; pagame lo que resta a 30 dias, etc”).
Ahora bien, si no se quiere perder esta información (que en realidad solo tendria sentido para aquellas facturas no saldadas completamente) se podria imprimir como texto fiscal antes de los items (las strings de observaciones en Document; yo actualmente estoy usando estas lineas, pero para otros datos).
Ahora bien, en las facturas no-TPV, seteadas para “generar un linea caja”, no lo probe pero deberían ser impresas y tratadas exactamente igual que facturas generadas desde el TPV y totalmente saldadas en efectivo. Si esto no ocurre (creo que no, ya que las tablas que son afectadas desde el TPV y desde la “completacion” de facturas, son distintas; en particular, creo que la ultima NO genera una AllocationLine y por lo tanto FiscalDocumentPrint no va “a ver” ningún pago), se deberia tratar como un caso especial (o modificar el codigo de MInovice.completeIt para que sea consistente con la lógica del TPV). Las facturas no-TPV, con reglas de pago “efetivo” pero sin generación automatica de la linea de caja, se deberian tratar como una factura sin ningun pago real (y como dije, si no se quiere perder la información del “acuerdo de pago”, se envia como un texto fiscal antes de los items).En conclusión, la forma en que pienso que deberia tratarse todos estos casos serian:
1) si FiscalDocumentPrint, encuentra la menos un pago real, actua tal como hasta ahora junto con la modificación del codigo del driver para tratar correctamente “el último pago” (esto igual debería darse solo en casos bastante raros).
2) si FiscalDocumentPrint no encuentra ningun pago
2.1) si “descubre” que fue creada con “generar linea de caja”, genera un solo pago por el total utilzando la misma leyenda que usaria en 1) para pagos en efectivo (esto de paso, logra una consistencia que ahora no existe).
2.2) si no, no emite ningún pago real; a lo sumo setea la regla de pago como una observación fiscal.En el caso 1 entran todas las facturas generadas desde el TPV con al menos un pago “real” (cualquiera de los medios de pagos que no sean “A crédito”). En el caso 2.1 entrarían solo aquellas facturas no-TPV que fueron creadas con “generar linea de caja”; en el caso 2.2 entrarían aquellas facturas TPV cuyo único medio de pago es “A Crédito”, las facturas no-TPV cuya regla de pago no era efectivo y las facturas no-TPV cuyo medio de pago sí era efectivo, pero no generaron una linea de caja por el total. En todos los casos, la regla de pago nunca va a parar a un TotalTender.
En cuanto a cuando imprimir la regla de pago en las observaciones, supongo que se podría simplificar e imprimirse siempre (el único problema potencial acá es que estas lineas son escasas; existen solo 4 en la mayoría de los documentos; de cualquier manera el código actual no esta haciendo uso de ninguna de ellas; en un versión propia se están imprimiendo por ej los números de pedidos y código del vendedor, en estos caso ya jode un poco mas darle un “linea” para imprimir este dato).
PD : tal vez, no haya que imprimir la regla de pagos como observación, si no, los términos de pagos…
-
AutorEntradas
- Debes estar registrado para responder a este debate.