Árvore de páginas

01. DATOS GENERALES


Producto

TOTVS Backoffice

Línea de producto: 

Línea Protheus

Segmento:

Backoffice

Módulo:

SIGAFIN - Financiero

Función:
Rutina Nombre TécnicoFecha
FINA998.AppFront de Totvs Recibos27/12/2024
País:Todos
Ticket:N/A
Requisito/Story/Issue (informe el requisito vinculado):DMINA-25574

|

02. SITUACIÓN/REQUISITO

En la rutina FINA998, cuando se realiza un descuento por pronto pago utilizando el PE F998VALBX, al colocar un pago parcial de una factura y después un porcentaje de descuento, no toma el valor ingresado en la moneda correspondiente, toma el valor total del titulo limitando la funcionalidad de un pago parcial.

03. SOLUCIÓN

Cambios realizados en los fuentes del aplicativo:

    • Front-end de Totvs Recibo (FINA99.APP): Se modificó el JSON de retorno al punto de entrada F998VALBX  donde se agrega un objeto de monedas el cual lleva el monto ingresado en cada moneda, donde el usuario puede elegir si utiliza valor del titulo completo o el ingresado en la moneda. 

Importante

El uso de este Punto de Entrada solo está habilitado para la versión de PO UI.

  1. Por medio del módulo configurador (SIGACFG) se dan de alta los siguientes campos

    Campos de ejemplo para el PE (No son estándar)

    1. E1_XPERDES - En el cual se guardara el descuento aplicado al título.
      1. Campo = E1_XPERDES.
      2. Tipo = Numérico.
      3. Tamaño = 5
      4. Decimal = 2
      5. Formato = @99.99
      6. Contexto = Real
      7. Propiedad = Modificar
      8. Nombre = Desc. PP
    2. E1_XCONDPP - En donde se indica la condición de pago.
      1. Campo = E1_XCONDPP.
      2. Tipo = Carácter.
      3. Tamaño = 3
      4. Decimal = 0
      5. Formato = @!
      6. Contexto = Real
      7. Propiedad = Modificar
      8. Nombre = Cond. PP
    3. E4_XDESCON - En el cual se guardara el límite de descuento aplicado al título.
      1. Campo = E4_XDESCON.
      2. Tipo = Numérico.
      3. Tamaño = 5
      4. Decimal = 2
      5. Formato = @99.99
      6. Contexto = Real
      7. Propiedad = Modificar
      8. Nombre = Lim Desc. PP


  2. Realizar un respaldo del repositorio (RPO).
  3. Aplicar el parche correspondiente al issue DMINA-25574.
  4. Validar que las rutinas actualizadas en el repositorio, coincidan con las descritas en el encabezado del presente Documento Técnico, así como las fechas.
  5. Crear la función de usuario F998VALBX  definiendo las propiedades para la vista , cálculos para los campos descuento, multa, interés y total,  así como la función a ejecutar para guardar los datos.
  6. Dentro del módulo Financiero ejecutar la rutina TOTVS Recibo (Actualizaciones | Cuentas por cobrar).
  7. En la rutina de Clientes (MATA030), ubicada en el módulo Financiero (Actualizaciones | Archivos) registre un cliente.

  8. En la rutina de Productos (MATA010), ubicada en el módulo Facturación (Actualizaciones | Archivos), incluir un nuevo producto.

  9. En la rutina de Tipos de Entrada y Salida (MATA080), ubicada en el módulo Facturación (Actualizaciones | Archivos), incluir una TES de salida.
  10. En la rutina de Facturaciones (MATA467N), ubicada en el módulo de Facturación (Actualizaciones | Facturaciones) se realiza una factura que genere un título financiero al cliente configurado anteriormente.
  1. Ingresar a la rutina TOTVS Recibo; SIGAFIN - Actualizaciones | Cuentas por Cobrar | TOTVS Recibo.

    1. Ingresar a la opción Nuevo Recibo.

      1. Informe el encabezado del recibo con los datos configurados anteriormente y dar clic en "Extraer Títulos". 

      2. Localizar el título generado anteriormente y dar clic en "Editar cobro".
        1. Verificar que se visualice el nuevo campo configurado "Descuento por pronto pago".
        2. Verificar que se realice la lógica matemática adecuadamente proporcionada al descuento.
      3. Agregar una forma de pago por el valor restante del título financiero.
      4. Guardar el recibo:
        1. Verificar que el valor se haya guardado correctamente en el campo configurado en el PE.


04. INFORMACIÓN ADICIONAL


DescripciónActualizaciones
Punto de entrada:F998VALBX
Parámetros recibidos
NombreTipoDescripción
PARAMIXB[1]O

Definición de la vista del campo "Descuento por pronto pago"

Descripción del objeto PARAMIXB[1] cuando en el Json la bandera PARAMIXB[2] es Verdadera (.T.) y la bandera ["recalculate" ]  este como falsa (.F.)

Nombre en JsonEquivalenciaDescripción
['recalculate´]N/ASi es True (.T.) realizará los calculos, si es False (.F.) realizara la vista
titulos[nX]['branch']E1_FILIALFilial
titulos[nX]['billnumber']E1_NUMERONumero de Titulo
titulos[nX]['type']E1_TIPOTipo de Titulo
titulos[nX]['actualduedt']E1_VENCREAVencimiento Real
titulos[nX]['currency']E1_MOEDAMoneda
titulos[nX]['unit']E1_LOJATienda
titulos[nX]['installment']E1_PARCELACuota
titulos[nX]['billvalue']E1_VALORValor
titulos[nX]['customer']E1_CLIENTECliente
titulos[nX]['class']E1_NATUREZModalidad
titulos[nX]['custname']A1_NOMENombre del cliente
titulos[nX]['balance']E1_SALDOSaldo del titulo
titulos[nX]['prefix']E1_PREFIXOPrefijo del titulo
titulos[nX]['issuedt']E1_EMISSAOFecha de emisión
titulos[nX]['writeoffne']E1_VALLIQValor neto de la baja    
titulos[nX]['discount']E1_DESCONTDescuento
titulos[nX]['interest']E1_JUROSIntereses
titulos[nX]['fine']E1_MULTAMultas
titulos[nX]['series']E1_SERIESerie 
titulos[nX]['origin']E1_ORIGEMRuta origen del titulo
titulos[nX]['recno']R_E_C_N_O
titulos[nX]['client']E1_CLIENTECliente
titulos[nX]['originbranch']E1_FILORIGFilial Original
titulos[nX]['paycondf2']F2_CONDCondición SF2
titulos[nX]['paycondf1']F1_CONDCondición SF1
titulos[nX]['serie2f2']F2_SERIE2Serie SF2
titulos[nX]['serie2f1']F1_SERIE2Serie SF1
titulos[nX]['paymentcondition']
Condición de pago
titulos[nX]['cobrar']
Monto a cobrar en Numeric
titulos[nX]['billvalueString']
Total o saldo (Dependiendo la pantalla)
titulos[nX]['balanceString']
Saldo en String
titulos[nX]['cobrarString']
Monto a cobrar en String
titulos[nX]['discountString']
Descuento del titulo en String
titulos[nX]['interestString']
Interés del titulo en String
titulos[nX]['fineString']
Multa del titulo en String

Definición de la lógica del campo "Descuento por pronto pago"

Descripción del objeto PARAMIXB[1] cuando en el JSON la bandera PARAMIXB[2] es Verdadera (.T.) y la bandera ["recalculate" ] este como True (.T.)

Nombre en JsonDescripción
['recalculate´]Si es True (.T.) realizará los cálculos, si es False (.F.) realizara la vista
bind['discountInput']Descuento ingresado en el campo Descuento Pronto Pago
bind['descuento']Tipo de Titulo
bind['multa']Interés del titulo en String
bind['interes']Multa del titulo en String
bind['saldo']Saldo total (Ya tomando en cuenta, descuento, multa e interés)
coins[nX]['property']Nombre de la moneda
coins[nX]['coin']Moneda
coins[nX]['value']Valor ingresado



Definición de la grabación del campo "Descuento por pronto pago"

Descripción de los objetos (PARAMIXB[1]) mandados en el JSON cuando la bandera PARAMIXB[2] es Falsa (.F.) 

Nombre en JsonEquivalenciaDescripción
encabezado['serie']FJT_SERIESerie del recibo
encabezado['recibo']FJT_RECIBONumero de recibo
encabezado['emissa']FJT_EMISSAEmisión
encabezado['nature']FJT_NATURECobrador
encabezado['client']FJT_CLIENTCliente
encabezado['loja']FJT_LOJATienda
encabezado['cobrad']FJT_COBRADCobrador
encabezado['recprov']FJT_RECPRVRecibo Provisorio
Nombre en JsonEquivalenciaDescripción
titulos[nX]['branch']E1_FILIALFilial
titulos[nX]['billnumber']E1_NUMERONúmero de Titulo
titulos[nX]['type']E1_TIPOTipo de Titulo
titulos[nX]['actualduedt']E1_VENCREAVencimiento Real
titulos[nX]['currency']E1_MOEDAMoneda
titulos[nX]['unit']E1_LOJATienda
titulos[nX]['installment']E1_PARCELACuota
titulos[nX]['billvalue']E1_VALORValor
titulos[nX]['customer']E1_CLIENTECliente
titulos[nX]['class']E1_NATUREZModalidad
titulos[nX]['custname']A1_NOMENombre del cliente
titulos[nX]['balance']E1_SALDOSaldo del titulo
titulos[nX]['prefix']E1_PREFIXOPrefijo del titulo
titulos[nX]['issuedt']E1_EMISSAOFecha de emisión
titulos[nX]['writeoffne']E1_VALLIQValor neto de la baja    
titulos[nX]['discount']E1_DESCONTDescuento
titulos[nX]['interest']E1_JUROSIntereses
titulos[nX]['fine']E1_MULTAMultas
titulos[nX]['series']E1_SERIESerie 
titulos[nX]['origin']E1_ORIGEMRuta origen del titulo
titulos[nX]['recno']R_E_C_N_O
titulos[nX]['client']E1_CLIENTECliente
titulos[nX]['originbranch']E1_FILORIGFilial Original
titulos[nX]['paycondf2']F2_CONDCondición SF2
titulos[nX]['paycondf1']F1_CONDCondición SF1
titulos[nX]['serie2f2']F2_SERIE2Serie SF2
titulos[nX]['serie2f1']F1_SERIE2Serie SF1
titulos[nX]['paymentcondition']
Condición de pago
titulos[nX]['cobrar']
Monto a cobrar en Numeric
titulos[nX]['billvalueString']
Total o saldo (Dependiendo la pantalla)
titulos[nX]['balanceString']
Saldo en String
titulos[nX]['cobrarString']
Monto a cobrar en String
titulos[nX]['discountString']
Descuento del titulo en String
titulos[nX]['interestString']
Interés del titulo en String
titulos[nX]['fineString']
Multa del titulo en String
titulos[nX]['quickSelected']
Titulo seleccionado en el GRID
titulos[nX]['reasonBx']
Motivos de baja
titulos[nX]['peso']
Total en moneda
Nombre en JsonDescripción
monedas[nX]['coin']Nombre Moneda
monedas[nX]['tasa']Tasa
monedas[nX]['received']Cantidad recibida en esta moneda
monedas[nX]['balance']Saldo en Numeric
monedas[nX]['type']Nombre de Moneda
monedas[nX]['moneda']Numero de Moneda
monedas[nX]['stringTasa']Tasa de moneda
monedas[nX]['balanceString']Saldo en String
monedas[nX]['receivedString']Cantidad recibida en esta moneda
Nombre en JSONDescripción
formaspago[nX]['property']Nombre de la propiedad (Trae el mismo nombre registrado en la SX3)
formaspago[nX]['value']Valor de la propiedad
Nombre en JSONDescripción
params[nX]['mv_par01']Valor del parámetro 01

params[nX]['mv_par01']

.

.

.

params[nX]['mv_parxx']


PARAMIXB[2]LTrue (.T.) si es momento del guardado y False (.F.) si es configuración de la vista
Respuesta:

Descripción del objeto de respuesta cuando en el JSON la bandera PARAMIXB[2] es Verdadera (.T.) y la bandera ["recalculate" ]  este como falsa (.F.)

Nombre

Tipo

Descripción

Obligatorio

oJson['label']L

Nombre del campo nuevo a mostrar.

Si
oJson['disabledDiscount']LDeshabilitar o habilitar el campo de descuento.Si
oJson['disabledInterest']LDeshabilitar o habilitar el campo de Intereses.Si
oJson['disabledFine']LDeshabilitar o habilitar el campo de Multa.Si
oJson['disabledInput']LDeshabilitar o habilitar el input nuevoSi
oJson['maxDiscount']NSe informa el descuento permitido debe tener un rango mayor a 0 y menor a 100Si
oJson['warningMaxDiscount']C Mensaje personalizado por si se excede el descuento permitido, si no se informa el front-end mandará uno por defaultNo

Descripción del objeto de respuesta cuando en el JSON la bandera PARAMIXB[2] es Verdadera (.T.) y la bandera ["recalculate" ] este como True (.T.)

Nombre en JsonDescripción
oJson['descuento']Valor que será mostrado en el campo descuento
oJson['residuo']Valor que será mostrado como total del titulo (Después de descuentos, multa e intereses)
oJson['multa']Valor que será mostrado como multa del titulo
oJson['interes']Valor que será mostrado como interés del titulo

Descripción de los objetos de respuesta en el JSON cuando la bandera PARAMIXB[2] sea Falsa (.F.) 

N/A


Ejemplo donde el descuento se calcula con el saldo total del titulo

Ejemplo de PE F998VALBX
#Include 'Protheus.ch'

User Function F998VALBX()

    Local oResponse := JsonObject():New() as Object
    
    IF PARAMIXB[2]  //Vista
        IF PARAMIXB[1]['recalculate']
            oResponse:=setValues(PARAMIXB[1])
        ELSE
	        oResponse['label']              := "% Descuento por pronto pago"        //Nombre del campo nuevo a mostrar.
            oResponse['readonlyDiscount']   := .T.                  //Deshabilitar o habilitar el campo de descuento.
            oResponse['readonlyInterest']   := .T.                  //Deshabilitar o habilitar el campo de Intereses.
            oResponse['readonlyFine']       := .T.                  //Deshabilitar o habilitar el campo de Multa.
            oResponse['disabledInput']      := .F.//isDisable(PARAMIXB[1]) //Deshabilitar o habilitar el input nuevo
            oResponse['maxDiscount']        := 50//GetLimite(PARAMIXB[1]) //Se informa el descuento permitido debe tener un rango mayor a 0 y menor a 100
            oResponse['warningMaxDiscount'] := "Descuento por Pronto Pago mayor al permitido. En esta condición el tope es:"+ALLTRIM(STR(oResponse['maxDiscount'])) //Mensaje personalizado por si se excede el descuento permitido, si no se informa el front mandara uno por default
        ENDIF
    ELSE 
       SaveData(PARAMIXB[1]) //Grabación
    ENDIF

Return oResponse

/*/{Protheus.doc} setValues
Esta funcion determina los valores a mostrar en los campos de descuento, residuo, multa e interés
@type function
@version  
@author luis.aboytes
@since 25/7/2024
@param oJson, object, param_description
@return variant, return_description
/*/
Static Function setValues(oJson)
    Local oRes := JsonObject():New()       }
	
	// El cálculo se realiza por el total del título si se utiliza el dato PARAMIXB[1]['bind']['saldo']
    
	oRes['descuento']  := Round(PARAMIXB[1]['bind']['discountInput']/100*PARAMIXB[1]['bind']['saldo'],2)     			//Calculo con el total del titulo
    oRes['residuo']    := Round(PARAMIXB[1]['bind']['saldo']-oRes['descuento'],MsDecimais(SE1->E1_MOEDA))    			//Calculo con el total del titulo
	oRes['multa']      := 0
    oRes['interes']    := 0

Return oRes

/*/{Protheus.doc} SaveData
Guardamos el dato en un campo en especifico
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function SaveData(oJsonData)
    Local nCont as Numeric

    For nCont := 1 to LEN(oJsonData['titulos'])
        SE1->(dbSetOrder(1))
	    SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['titulos'][nCont]['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['titulos'][nCont]['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['titulos'][nCont]['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))
        RecLock("SE1",.F.)
            SE1->E1_XPERDES :=	oJsonData['titulos'][nCont]['percentDiscount']
		MsUnLock()
    Next
Return

/*/{Protheus.doc} GetLimite
Se retorna el limite de descuento
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function GetLimite(oJsonData)
    Local nTope := 0

    SE1->(dbSetOrder(1))
	SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))

    nTope:=IIF(VAZIO(Posicione("SE4", 1,xFilial("SE4")+SE1->E1_XCONDPP,"E4_XDESCON")),0,Posicione("SE4", 1,xFilial("SE4")+SE1->E1_XCONDPP,"E4_XDESCON"))
Return nTope

/*/{Protheus.doc} isDisable
Funcion que retorna si es editable o no el valor del input
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function isDisable(oJsonData)
    Local lRet := .t.

    SE1->(dbSetOrder(1))
	SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))

    IF SE1->E1_XCONDPP == '999'
        lRet := .f.
    ENDIF

Return lRet




Ejemplo donde el descuento se calcula con el valor ingresado en la moneda 1

Ejemplo de PE F998VALBX
#Include 'Protheus.ch'

User Function F998VALBX()

    Local oResponse := JsonObject():New() as Object
    
    IF PARAMIXB[2]  //Vista
        IF PARAMIXB[1]['recalculate']
            oResponse:=setValues(PARAMIXB[1])
        ELSE
	        oResponse['label']              := "% Descuento por pronto pago"        //Nombre del campo nuevo a mostrar.
            oResponse['readonlyDiscount']   := .T.                  //Deshabilitar o habilitar el campo de descuento.
            oResponse['readonlyInterest']   := .T.                  //Deshabilitar o habilitar el campo de Intereses.
            oResponse['readonlyFine']       := .T.                  //Deshabilitar o habilitar el campo de Multa.
            oResponse['disabledInput']      := .F.//isDisable(PARAMIXB[1]) //Deshabilitar o habilitar el input nuevo
            oResponse['maxDiscount']        := 50//GetLimite(PARAMIXB[1]) //Se informa el descuento permitido debe tener un rango mayor a 0 y menor a 100
            oResponse['warningMaxDiscount'] := "Descuento por Pronto Pago mayor al permitido. En esta condición el tope es:"+ALLTRIM(STR(oResponse['maxDiscount'])) //Mensaje personalizado por si se excede el descuento permitido, si no se informa el front mandara uno por default
        ENDIF
    ELSE 
       SaveData(PARAMIXB[1]) //Grabación
    ENDIF

Return oResponse

/*/{Protheus.doc} setValues
Esta funcion determina los valores a mostrar en los campos de descuento, residuo,multa e interes
@type function
@version  
@author luis.aboytes
@since 25/7/2024
@param oJson, object, param_description
@return variant, return_description
/*/
Static Function setValues(oJson)
    Local oRes := JsonObject():New()       

   	// El cálculo se realiza con el dato ingresado en la moneda 1 o en cualquier moneda puede 
	// utilizar por ejemplo PARAMIXB[1]["coins"][1]['value'] para la moneda 1.           

	oRes['descuento']  := Round(PARAMIXB[1]['bind']['discountInput']/100*PARAMIXB[1]["coins"][1]['value'],2)		 	//Calculo con el valor ingresado a pagar
    oRes['residuo']    := Round(PARAMIXB[1]["coins"][1]['value']-oRes['descuento'],MsDecimais(SE1->E1_MOEDA))   		//Calculo con el valor ingresado a pagar
    oRes['multa']      := 0
    oRes['interes']    := 0

Return oRes

/*/{Protheus.doc} SaveData
Guardamos el dato en un campo en especifico
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function SaveData(oJsonData)
    Local nCont as Numeric

    For nCont := 1 to LEN(oJsonData['titulos'])
        SE1->(dbSetOrder(1))
	    SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['titulos'][nCont]['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['titulos'][nCont]['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['titulos'][nCont]['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))
        RecLock("SE1",.F.)
            SE1->E1_XPERDES :=	oJsonData['titulos'][nCont]['percentDiscount']
		MsUnLock()
    Next
Return

/*/{Protheus.doc} GetLimite
Se retorna el limite de descuento
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function GetLimite(oJsonData)
    Local nTope := 0

    SE1->(dbSetOrder(1))
	SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))

    nTope:=IIF(VAZIO(Posicione("SE4", 1,xFilial("SE4")+SE1->E1_XCONDPP,"E4_XDESCON")),0,Posicione("SE4", 1,xFilial("SE4")+SE1->E1_XCONDPP,"E4_XDESCON"))
Return nTope

/*/{Protheus.doc} isDisable
Funcion que retorna si es editable o no el valor del input
@type function
@author luis.aboytes
@since 18/7/2024
/*/
Static Function isDisable(oJsonData)
    Local lRet := .t.

    SE1->(dbSetOrder(1))
	SE1->(dbSeek(xFilial("SE1")+PADR(oJsonData['prefix'],GetSx3Cache("E1_PREFIXO","X3_TAMANHO"))+PADR(oJsonData['billnumber'],GetSx3Cache("E1_NUM","X3_TAMANHO"))+PADR(oJsonData['installment'],GetSx3Cache("E1_PARCELA","X3_TAMANHO"))))

    IF SE1->E1_XCONDPP == '999'
        lRet := .f.
    ENDIF

Return lRet


¡IMPORTANTE!

La presente solución aplica para versión 12.1.2210 o superior, siempre y cuando se tengan las rutinas actualizadas a la fecha indicada en la sección 01 - Datos Generales.


05. ASUNTOS RELACIONADOS

  • TOTVS Recibo
  • 5.2 Puntos de entrada disponibles