#include "hbclass.ch" CREATE CLASS TFuncFormulas DATA hFunciones INIT { => } DATA hTransformPlanCache INIT { => } DATA lCreated INIT .F. METHOD New() CONSTRUCTOR METHOD Init() METHOD Create() METHOD End() METHOD Ejecutar( cFuncion, aArgs ) METHOD Abs( uValor ) METHOD AddDays( uFecha, uDias ) METHOD AllTrim( uTexto ) METHOD At( uBuscar, uTexto ) METHOD RAt( uBuscar, uTexto ) METHOD StrPos( uTexto, uBuscar, uOcurrencia ) METHOD Barcode( uTexto, uTipo ) METHOD Chr( uCodigo ) METHOD Contains( uTexto, uBuscar ) METHOD CToD( uTexto ) METHOD Date() METHOD DateYMD( uAnio, uMes, uDia ) METHOD DateDifference( uFinal, uInitial ) METHOD Dow( uFecha ) METHOD DToC( uFecha ) METHOD DToS( uFecha ) METHOD Empty( uValor ) METHOD Exp10( uValor ) METHOD hb_MemoRead( uFichero ) METHOD Hour( uFechaHora ) METHOD Int( uValor ) METHOD IsNull( uValor ) METHOD Left( uTexto, uLongitud ) METHOD Len( uTexto ) METHOD LoadFile( uFichero, uAlternativo ) METHOD Lower( uTexto ) METHOD LTrim( uTexto ) METHOD Max( ... ) METHOD Month( uFecha ) METHOD Now() METHOD NULL() METHOD Right( uTexto, uLongitud ) METHOD RGB( uRojo, uVerde, uAzul ) METHOD Round( uValor, uDecimales ) METHOD RTrim( uTexto ) METHOD SToD( uTexto ) METHOD Str( uNumero, uLongitud, uDecimales ) METHOD StrTran( uTexto, uBuscar, uReemplazar, uPos, uOcurrencias ) METHOD SubStr( uTexto, uInicio, uLongitud ) METHOD Transform( uValor, uMascara ) METHOD Upper( uTexto ) METHOD Val( uTexto ) METHOD Year( uFecha ) HIDDEN: METHOD ValorAString( uValor ) METHOD ArgAt( aArgs, nIndex, uDefault ) METHOD EsNumerico( uValor ) METHOD NormalizarComponenteColor( uValor ) METHOD ResolverRutaFichero( cRuta ) METHOD FechaDesdeValor( uValor ) METHOD FechaDesdeTextoSerial( cTexto ) METHOD FechaDesdeTextoVisible( cTexto ) METHOD FechaValida( dFecha ) METHOD FormatearFechaVisible( dFecha ) METHOD FormatearFechaVisibleLarga( dFecha ) METHOD LongitudTexto( cTexto ) METHOD SubTexto( cTexto, nOffset, nLongitud ) METHOD ContarDecimalesMascara( cMascara ) METHOD MascaraUsaMiles( cMascara ) METHOD ExtraerPlantillaNumericaTransform( cMascara ) METHOD AjustarAnchoMascaraNumerica( cValor, cMascara ) METHOD AplicarSeparadorMiles( cValor, cSeparadorDecimal, cSeparadorMiles ) METHOD EsMascaraFecha( cMascara ) METHOD FormatearFechaConMascara( dFecha, cMascara ) METHOD NumeroATexto( nValor, nDecimales ) METHOD MaxArray( aValores ) METHOD ExtraerNumeroInicial( cTexto ) ENDCLASS METHOD New() CLASS TFuncFormulas ::Init() RETURN Self METHOD Init() CLASS TFuncFormulas ::hFunciones := { ; "ABS" => "Abs", ; "ADDDAYS" => "AddDays", ; "ALLTRIM" => "AllTrim", ; "AT" => "At", ; "BARCODE" => "Barcode", ; "CHR" => "Chr", ; "CONTAINS" => "Contains", ; "CTOD" => "CToD", ; "DATE" => "Date", ; "DATEYMD" => "DateYMD", ; "DOW" => "Dow", ; "DTOC" => "DToC", ; "DTOS" => "DToS", ; "EMPTY" => "Empty", ; "EXP10" => "Exp10", ; "HB_MEMOREAD" => "hb_MemoRead", ; "HOUR" => "Hour", ; "INT" => "Int", ; "ISNULL" => "IsNull", ; "LEFT" => "Left", ; "LEN" => "Len", ; "LOADFILE" => "LoadFile", ; "LOWER" => "Lower", ; "LTRIM" => "LTrim", ; "MAX" => "Max", ; "MONTH" => "Month", ; "NOW" => "Now", ; "NULL" => "NULL", ; "RAT" => "RAt", ; "STRPOS" => "StrPos", ; "RIGHT" => "Right", ; "RGB" => "RGB", ; "ROUND" => "Round", ; "RTRIM" => "RTrim", ; "STOD" => "SToD", ; "STR" => "Str", ; "STRTRAN" => "StrTran", ; "SUBSTR" => "SubStr", ; "TRANSFORM" => "Transform", ; "UPPER" => "Upper", ; "VAL" => "Val", ; "YEAR" => "Year" } ::hTransformPlanCache := { => } ::lCreated := .F. RETURN Self METHOD Create() CLASS TFuncFormulas ::lCreated := .T. RETURN Self METHOD End() CLASS TFuncFormulas ::hFunciones := { => } ::hTransformPlanCache := { => } ::lCreated := .F. RETURN NIL METHOD Ejecutar( cFuncion, aArgs ) CLASS TFuncFormulas LOCAL cClave := Upper( AllTrim( ::ValorAString( cFuncion ) ) ) LOCAL uArg2 LOCAL uArg3 LOCAL uArg4 LOCAL uArg5 aArgs := iif( HB_ISARRAY( aArgs ), aArgs, {} ) uArg2 := ::ArgAt( aArgs, 2, NIL ) uArg3 := ::ArgAt( aArgs, 3, NIL ) uArg4 := ::ArgAt( aArgs, 4, NIL ) uArg5 := ::ArgAt( aArgs, 5, NIL ) DO CASE CASE cClave == "ABS"; RETURN ::Abs( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "ADDDAYS"; RETURN ::AddDays( ::ArgAt( aArgs, 1, NIL ), uArg2 ) CASE cClave == "ALLTRIM"; RETURN ::AllTrim( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "AT"; RETURN ::At( ::ArgAt( aArgs, 1, "" ), uArg2 ) CASE cClave == "BARCODE"; RETURN ::Barcode( ::ArgAt( aArgs, 1, NIL ), uArg2 ) CASE cClave == "CHR"; RETURN ::Chr( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "CONTAINS"; RETURN ::Contains( ::ArgAt( aArgs, 1, "" ), uArg2 ) CASE cClave == "CTOD"; RETURN ::CToD( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "DATE"; RETURN ::Date() CASE cClave == "DATEYMD"; RETURN ::DateYMD( ::ArgAt( aArgs, 1, NIL ), uArg2, uArg3 ) CASE cClave == "DOW"; RETURN ::Dow( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "DTOC"; RETURN ::DToC( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "DTOS"; RETURN ::DToS( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "EMPTY"; RETURN ::Empty( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "EXP10"; RETURN ::Exp10( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "HB_MEMOREAD"; RETURN ::hb_MemoRead( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "HOUR"; RETURN ::Hour( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "INT"; RETURN ::Int( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "ISNULL"; RETURN ::IsNull( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "LEFT"; RETURN ::Left( ::ArgAt( aArgs, 1, "" ), uArg2 ) CASE cClave == "LEN"; RETURN ::Len( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "LOADFILE"; RETURN ::LoadFile( ::ArgAt( aArgs, 1, "" ), iif( ValType( uArg2 ) == "U", "", uArg2 ) ) CASE cClave == "LOWER"; RETURN ::Lower( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "LTRIM"; RETURN ::LTrim( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "MAX"; RETURN ::MaxArray( aArgs ) CASE cClave == "MONTH"; RETURN ::Month( ::ArgAt( aArgs, 1, NIL ) ) CASE cClave == "NOW"; RETURN ::Now() CASE cClave == "NULL"; RETURN ::NULL() CASE cClave == "RAT"; RETURN ::RAt( ::ArgAt( aArgs, 1, "" ), uArg2 ) CASE cClave == "STRPOS"; RETURN ::StrPos( ::ArgAt( aArgs, 1, "" ), uArg2, iif( ValType( uArg3 ) == "U", 1, uArg3 ) ) CASE cClave == "RIGHT"; RETURN ::Right( ::ArgAt( aArgs, 1, "" ), uArg2 ) CASE cClave == "RGB"; RETURN ::RGB( ::ArgAt( aArgs, 1, NIL ), uArg2, uArg3 ) CASE cClave == "ROUND"; RETURN ::Round( ::ArgAt( aArgs, 1, NIL ), iif( ValType( uArg2 ) == "U", 0, uArg2 ) ) CASE cClave == "RTRIM"; RETURN ::RTrim( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "STOD"; RETURN ::SToD( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "STR"; RETURN ::Str( ::ArgAt( aArgs, 1, NIL ), uArg2, uArg3 ) CASE cClave == "STRTRAN"; RETURN ::StrTran( ::ArgAt( aArgs, 1, "" ), uArg2, iif( ValType( uArg3 ) == "U", "", uArg3 ), iif( ValType( uArg4 ) == "U", 1, uArg4 ), uArg5 ) CASE cClave == "SUBSTR"; RETURN ::SubStr( ::ArgAt( aArgs, 1, "" ), uArg2, uArg3 ) CASE cClave == "TRANSFORM"; RETURN ::Transform( ::ArgAt( aArgs, 1, NIL ), uArg2 ) CASE cClave == "UPPER"; RETURN ::Upper( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "VAL"; RETURN ::Val( ::ArgAt( aArgs, 1, "" ) ) CASE cClave == "YEAR"; RETURN ::Year( ::ArgAt( aArgs, 1, NIL ) ) ENDCASE RETURN "[Funcion no implementada: " + ::ValorAString( cFuncion ) + "]" METHOD Abs( uValor ) CLASS TFuncFormulas IF ! ::EsNumerico( uValor ) RETURN "[Funcion Abs no valida]" ENDIF RETURN Abs( uValor ) METHOD AllTrim( uTexto ) CLASS TFuncFormulas RETURN AllTrim( ::ValorAString( uTexto ) ) METHOD AddDays( uFecha, uDias ) CLASS TFuncFormulas LOCAL dFecha IF ! ::EsNumerico( uDias ) RETURN "[Funcion AddDays no valida]" ENDIF dFecha := ::FechaDesdeValor( uFecha ) IF Empty( dFecha ) RETURN "[Funcion AddDays no valida]" ENDIF RETURN ::FormatearFechaVisible( dFecha + Int( Val( ::ValorAString( uDias ) ) ) ) METHOD At( uBuscar, uTexto ) CLASS TFuncFormulas RETURN At( ::ValorAString( uBuscar ), ::ValorAString( uTexto ) ) METHOD RAt( uBuscar, uTexto ) CLASS TFuncFormulas RETURN RAt( ::ValorAString( uBuscar ), ::ValorAString( uTexto ) ) METHOD StrPos( uTexto, uBuscar, uOcurrencia ) CLASS TFuncFormulas LOCAL cTexto := ::ValorAString( uTexto ) LOCAL cBuscar := ::ValorAString( uBuscar ) LOCAL nOcurrencia LOCAL nInicio := 1 LOCAL nPosicion := 0 LOCAL nRelativa LOCAL nIndice IF Empty( cBuscar ) .OR. ! ::EsNumerico( uOcurrencia ) RETURN -1 ENDIF nOcurrencia := Int( Val( ::ValorAString( uOcurrencia ) ) ) IF nOcurrencia < 1 RETURN -1 ENDIF FOR nIndice := 1 TO nOcurrencia nRelativa := At( cBuscar, SubStr( cTexto, nInicio ) ) IF nRelativa == 0 RETURN -1 ENDIF nPosicion := nInicio + nRelativa - 1 nInicio := nPosicion + Max( 1, Len( cBuscar ) ) NEXT RETURN nPosicion - 1 METHOD Chr( uCodigo ) CLASS TFuncFormulas IF ! ::EsNumerico( uCodigo ) .OR. Val( ::ValorAString( uCodigo ) ) < 0 RETURN "[Funcion Chr no valida]" ENDIF RETURN Chr( Int( Val( ::ValorAString( uCodigo ) ) ) ) METHOD Contains( uTexto, uBuscar ) CLASS TFuncFormulas IF ValType( uTexto ) == "U" .OR. ValType( uBuscar ) == "U" RETURN .F. ENDIF IF Empty( ::ValorAString( uBuscar ) ) RETURN .T. ENDIF RETURN At( ::ValorAString( uBuscar ), ::ValorAString( uTexto ) ) > 0 METHOD CToD( uTexto ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeTextoVisible( ::ValorAString( uTexto ) ) RETURN iif( Empty( dFecha ), "[Funcion CToD no valida]", ::FormatearFechaVisible( dFecha ) ) METHOD Date() CLASS TFuncFormulas RETURN ::FormatearFechaVisible( Date() ) METHOD DateYMD( uAnio, uMes, uDia ) CLASS TFuncFormulas LOCAL dFecha IF ! ::EsNumerico( uAnio ) .OR. ! ::EsNumerico( uMes ) .OR. ! ::EsNumerico( uDia ) RETURN "[Funcion DateYMD no valida]" ENDIF dFecha := hb_SToD( StrZero( Int( Val( ::ValorAString( uAnio ) ) ), 4 ) + StrZero( Int( Val( ::ValorAString( uMes ) ) ), 2 ) + StrZero( Int( Val( ::ValorAString( uDia ) ) ), 2 ) ) RETURN iif( Empty( dFecha ), "[Funcion DateYMD no valida]", ::FormatearFechaVisible( dFecha ) ) METHOD DateDifference( uFinal, uInitial ) CLASS TFuncFormulas LOCAL dFinal := ::FechaDesdeValor( uFinal ) LOCAL dInitial := ::FechaDesdeValor( uInitial ) IF Empty( dFinal ) .OR. Empty( dInitial ) RETURN NIL ENDIF RETURN dFinal - dInitial METHOD DToC( uFecha ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeValor( uFecha ) RETURN iif( Empty( dFecha ), "[Funcion DToC no valida]", ::FormatearFechaVisibleLarga( dFecha ) ) METHOD DToS( uFecha ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeValor( uFecha ) RETURN iif( Empty( dFecha ), "[Funcion DToS no valida]", DToS( dFecha ) ) METHOD Barcode( uTexto, uTipo ) CLASS TFuncFormulas IF ValType( uTexto ) == "U" .OR. ValType( uTipo ) == "U" RETURN { "tipo" => "barcode", "error" => "Funcion Barcode no valida" } ENDIF RETURN TBarcodeUtil():New():Crear( uTexto, uTipo ) METHOD Dow( uFecha ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeValor( uFecha ) RETURN iif( Empty( dFecha ), "[Funcion Dow no valida]", DoW( dFecha ) ) METHOD Empty( uValor ) CLASS TFuncFormulas DO CASE CASE ValType( uValor ) == "U" RETURN .T. CASE HB_ISLOGICAL( uValor ) RETURN ! uValor CASE HB_ISSTRING( uValor ) RETURN AllTrim( uValor ) == "" CASE HB_ISNUMERIC( uValor ) RETURN uValor == 0 CASE HB_ISARRAY( uValor ) .OR. HB_ISHASH( uValor ) RETURN Len( uValor ) == 0 ENDCASE RETURN .F. METHOD Exp10( uValor ) CLASS TFuncFormulas LOCAL nResultado IF ! ::EsNumerico( uValor ) RETURN "[Funcion Exp10 no valida]" ENDIF nResultado := 10 ^ Val( ::ValorAString( uValor ) ) RETURN iif( nResultado == Int( nResultado ), Int( nResultado ), nResultado ) METHOD Left( uTexto, uLongitud ) CLASS TFuncFormulas IF ! ::EsNumerico( uLongitud ) RETURN "[Funcion Left no valida]" ENDIF RETURN ::SubTexto( ::ValorAString( uTexto ), 0, Int( Val( ::ValorAString( uLongitud ) ) ) ) METHOD Len( uTexto ) CLASS TFuncFormulas RETURN ::LongitudTexto( ::ValorAString( uTexto ) ) METHOD Hour( uFechaHora ) CLASS TFuncFormulas LOCAL cFechaHora LOCAL aPartes LOCAL nEspacio LOCAL nHora LOCAL nSerial IF ValType( uFechaHora ) == "U" .OR. uFechaHora == NIL .OR. ( HB_ISSTRING( uFechaHora ) .AND. Empty( AllTrim( uFechaHora ) ) ) RETURN Val( Left( Time(), 2 ) ) ENDIF IF ValType( uFechaHora ) == "T" nSerial := hb_TToN( uFechaHora ) RETURN Int( ( nSerial - Int( nSerial ) ) * 24 + 0.0000001 ) ENDIF IF HB_ISDATE( uFechaHora ) RETURN 0 ENDIF cFechaHora := AllTrim( ::ValorAString( uFechaHora ) ) nEspacio := RAt( " ", cFechaHora ) IF nEspacio > 0 cFechaHora := AllTrim( SubStr( cFechaHora, nEspacio + 1 ) ) ENDIF aPartes := hb_ATokens( cFechaHora, ":" ) IF Len( aPartes ) < 2 .OR. ! ::EsNumerico( aPartes[ 1 ] ) RETURN "[Funcion Hour no valida]" ENDIF nHora := Val( aPartes[ 1 ] ) RETURN iif( nHora >= 0 .AND. nHora <= 23, nHora, "[Funcion Hour no valida]" ) METHOD Int( uValor ) CLASS TFuncFormulas IF ! ::EsNumerico( uValor ) RETURN "[Funcion Int no valida]" ENDIF RETURN Int( Val( ::ValorAString( uValor ) ) ) METHOD hb_MemoRead( uFichero ) CLASS TFuncFormulas RETURN ::LoadFile( uFichero, "" ) METHOD LoadFile( uFichero, uAlternativo ) CLASS TFuncFormulas LOCAL cRuta := ::ResolverRutaFichero( ::ValorAString( uFichero ) ) RETURN iif( Empty( cRuta ) .OR. ! hb_FileExists( cRuta ), ::ValorAString( uAlternativo ), hb_MemoRead( cRuta ) ) METHOD IsNull( uValor ) CLASS TFuncFormulas RETURN ValType( uValor ) == "U" METHOD Lower( uTexto ) CLASS TFuncFormulas RETURN Lower( ::ValorAString( uTexto ) ) METHOD LTrim( uTexto ) CLASS TFuncFormulas RETURN LTrim( ::ValorAString( uTexto ) ) METHOD Max( ... ) CLASS TFuncFormulas LOCAL aValores := hb_AParams() LOCAL uMax LOCAL uValor IF Len( aValores ) == 0 RETURN NIL ENDIF uMax := aValores[ 1 ] FOR EACH uValor IN aValores IF uValor > uMax uMax := uValor ENDIF NEXT RETURN uMax METHOD Month( uFecha ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeValor( uFecha ) RETURN iif( Empty( dFecha ), "[Funcion Month no valida]", Month( dFecha ) ) METHOD Now() CLASS TFuncFormulas RETURN ::FormatearFechaVisible( Date() ) METHOD NULL() CLASS TFuncFormulas RETURN NIL METHOD Right( uTexto, uLongitud ) CLASS TFuncFormulas LOCAL cTexto := ::ValorAString( uTexto ) LOCAL nLongitud LOCAL nTotal IF ! ::EsNumerico( uLongitud ) RETURN "[Funcion Right no valida]" ENDIF nLongitud := Int( Val( ::ValorAString( uLongitud ) ) ) IF nLongitud <= 0 RETURN "" ENDIF nTotal := ::LongitudTexto( cTexto ) RETURN iif( nLongitud >= nTotal, cTexto, ::SubTexto( cTexto, nTotal - nLongitud, NIL ) ) METHOD RGB( uRojo, uVerde, uAzul ) CLASS TFuncFormulas IF ValType( uRojo ) == "U" .OR. ValType( uVerde ) == "U" .OR. ValType( uAzul ) == "U" RETURN "[Funcion RGB no valida]" ENDIF RETURN "#" + Lower( hb_NumToHex( ::NormalizarComponenteColor( uRojo ), 2 ) + hb_NumToHex( ::NormalizarComponenteColor( uVerde ), 2 ) + hb_NumToHex( ::NormalizarComponenteColor( uAzul ), 2 ) ) METHOD Round( uValor, uDecimales ) CLASS TFuncFormulas LOCAL nDecimales LOCAL nResultado IF ! ::EsNumerico( uValor ) .OR. ! ::EsNumerico( uDecimales ) RETURN "[Funcion Round no valida]" ENDIF nDecimales := Int( Val( ::ValorAString( uDecimales ) ) ) nResultado := Round( Val( ::ValorAString( uValor ) ), nDecimales ) RETURN iif( nDecimales <= 0, Int( nResultado ), nResultado ) METHOD RTrim( uTexto ) CLASS TFuncFormulas RETURN RTrim( ::ValorAString( uTexto ) ) METHOD SToD( uTexto ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeTextoSerial( ::ValorAString( uTexto ) ) RETURN iif( Empty( dFecha ), "[Funcion SToD no valida]", ::FormatearFechaVisible( dFecha ) ) METHOD Str( uNumero, uLongitud, uDecimales ) CLASS TFuncFormulas LOCAL nLongitud := iif( ValType( uLongitud ) == "U", 10, Int( Val( ::ValorAString( uLongitud ) ) ) ) LOCAL nDecimales := iif( ValType( uDecimales ) == "U", 0, Max( 0, Int( Val( ::ValorAString( uDecimales ) ) ) ) ) LOCAL cNumero IF nLongitud <= 0 RETURN "" ENDIF IF ValType( uNumero ) == "U" .OR. ( HB_ISSTRING( uNumero ) .AND. AllTrim( uNumero ) == "" ) RETURN Space( nLongitud ) ENDIF IF ! ::EsNumerico( uNumero ) RETURN "[Funcion Str no valida]" ENDIF cNumero := ::NumeroATexto( Val( ::ValorAString( uNumero ) ), nDecimales ) IF Len( cNumero ) > nLongitud RETURN Replicate( "*", nLongitud ) ENDIF RETURN PadL( cNumero, nLongitud ) METHOD StrTran( uTexto, uBuscar, uReemplazar, uPos, uOcurrencias ) CLASS TFuncFormulas LOCAL cTexto := ::ValorAString( uTexto ) LOCAL cBuscar := ::ValorAString( uBuscar ) LOCAL cReemplazar := ::ValorAString( uReemplazar ) LOCAL nPos := Max( 1, Int( Val( ::ValorAString( uPos ) ) ) ) LOCAL nOcurrencias LOCAL cPrefijo LOCAL cTrabajo LOCAL cResultado := "" LOCAL nAt LOCAL nCount := 0 IF cBuscar == "" RETURN cTexto ENDIF cPrefijo := Left( cTexto, nPos - 1 ) cTrabajo := SubStr( cTexto, nPos ) IF ValType( uOcurrencias ) == "U" RETURN cPrefijo + StrTran( cTrabajo, cBuscar, cReemplazar ) ENDIF nOcurrencias := Max( 0, Int( Val( ::ValorAString( uOcurrencias ) ) ) ) IF nOcurrencias == 0 RETURN cTexto ENDIF DO WHILE nCount < nOcurrencias nAt := At( cBuscar, cTrabajo ) IF nAt <= 0 EXIT ENDIF cResultado += Left( cTrabajo, nAt - 1 ) + cReemplazar cTrabajo := SubStr( cTrabajo, nAt + Len( cBuscar ) ) nCount++ ENDDO RETURN cPrefijo + cResultado + cTrabajo METHOD SubStr( uTexto, uInicio, uLongitud ) CLASS TFuncFormulas LOCAL cTexto := ::ValorAString( uTexto ) LOCAL nInicio LOCAL nTotal LOCAL nOffset IF ! ::EsNumerico( uInicio ) RETURN "[Funcion SubStr no valida]" ENDIF nInicio := Int( Val( ::ValorAString( uInicio ) ) ) nTotal := ::LongitudTexto( cTexto ) nOffset := iif( nInicio >= 0, nInicio - 1, nTotal + nInicio ) nOffset := Max( 0, nOffset ) IF nOffset >= nTotal RETURN "" ENDIF IF ValType( uLongitud ) == "U" RETURN ::SubTexto( cTexto, nOffset, NIL ) ENDIF IF ! ::EsNumerico( uLongitud ) RETURN "[Funcion SubStr no valida]" ENDIF RETURN ::SubTexto( cTexto, nOffset, Int( Val( ::ValorAString( uLongitud ) ) ) ) METHOD Transform( uValor, uMascara ) CLASS TFuncFormulas LOCAL cMascara LOCAL dFecha LOCAL lEuropeo LOCAL cMascaraNumerica LOCAL nDecimales LOCAL cValor LOCAL cDecimal LOCAL cMiles LOCAL hPlan LOCAL nValor IF ValType( uValor ) == "U" .OR. ValType( uMascara ) == "U" RETURN "[Funcion Transform no valida]" ENDIF cMascara := AllTrim( ::ValorAString( uMascara ) ) IF cMascara == "" RETURN ::ValorAString( uValor ) ENDIF IF hb_HHasKey( ::hTransformPlanCache, cMascara ) hPlan := ::hTransformPlanCache[ cMascara ] ELSE lEuropeo := At( "@E", Upper( cMascara ) ) > 0 cMascaraNumerica := ::ExtraerPlantillaNumericaTransform( cMascara ) nDecimales := ::ContarDecimalesMascara( cMascaraNumerica ) cDecimal := iif( lEuropeo, ",", "." ) cMiles := iif( ::MascaraUsaMiles( cMascaraNumerica ), iif( lEuropeo, ".", "," ), "" ) hPlan := { ; "cMask" => cMascaraNumerica, ; "nDecimals" => nDecimales, ; "cDecimal" => cDecimal, ; "cThousands" => cMiles, ; "lDateMask" => ::EsMascaraFecha( cMascara ) ; } ::hTransformPlanCache[ cMascara ] := hPlan ENDIF IF hPlan[ "lDateMask" ] dFecha := ::FechaDesdeValor( uValor ) IF ! Empty( dFecha ) RETURN ::FormatearFechaConMascara( dFecha, cMascara ) ENDIF ENDIF IF ! ::EsNumerico( uValor ) RETURN ::ValorAString( uValor ) ENDIF cMascaraNumerica := hPlan[ "cMask" ] nDecimales := hPlan[ "nDecimals" ] cDecimal := hPlan[ "cDecimal" ] cMiles := hPlan[ "cThousands" ] IF HB_ISNUMERIC( uValor ) nValor := uValor ELSE nValor := Val( ::ValorAString( uValor ) ) ENDIF IF nDecimales > 0 cValor := ::NumeroATexto( nValor, nDecimales ) ELSE cValor := AllTrim( Transform( nValor, "999999999999" ) ) ENDIF IF cDecimal != "." cValor := StrTran( cValor, ".", cDecimal ) ENDIF IF ! Empty( cMiles ) cValor := ::AplicarSeparadorMiles( cValor, cDecimal, cMiles ) cValor := ::AjustarAnchoMascaraNumerica( cValor, cMascaraNumerica ) RETURN cValor ENDIF RETURN ::AjustarAnchoMascaraNumerica( cValor, cMascaraNumerica ) METHOD Val( uTexto ) CLASS TFuncFormulas RETURN Val( ::ExtraerNumeroInicial( ::ValorAString( uTexto ) ) ) METHOD Upper( uTexto ) CLASS TFuncFormulas RETURN Upper( ::ValorAString( uTexto ) ) METHOD Year( uFecha ) CLASS TFuncFormulas LOCAL dFecha := ::FechaDesdeValor( uFecha ) RETURN iif( Empty( dFecha ), "[Funcion Year no valida]", Year( dFecha ) ) METHOD ValorAString( uValor ) CLASS TFuncFormulas DO CASE CASE ValType( uValor ) == "U" RETURN "" CASE HB_ISSTRING( uValor) RETURN uValor CASE HB_ISNUMERIC( uValor ) IF uValor == Int( uValor ) RETURN AllTrim( Str( uValor, 20, 0 ) ) ENDIF RETURN AllTrim( Str( uValor ) ) CASE HB_ISLOGICAL( uValor ) RETURN iif( uValor, "1", "" ) ENDCASE RETURN AllTrim( hb_ValToStr( uValor ) ) METHOD ArgAt( aArgs, nIndex, uDefault ) CLASS TFuncFormulas IF HB_ISARRAY( aArgs ) .AND. nIndex >= 1 .AND. nIndex <= Len( aArgs ) RETURN aArgs[ nIndex ] ENDIF RETURN uDefault METHOD EsNumerico( uValor ) CLASS TFuncFormulas LOCAL cValor LOCAL nIndex LOCAL cChar LOCAL lHasDigit := .F. LOCAL nLen IF ValType( uValor ) == "N" RETURN .T. ENDIF IF ValType( uValor ) == "C" cValor := AllTrim( uValor ) IF cValor == "" RETURN .F. ENDIF nLen := Len( cValor ) FOR nIndex := 1 TO nLen cChar := SubStr( cValor, nIndex, 1 ) IF At( cChar, "0123456789" ) > 0 lHasDigit := .T. LOOP ENDIF IF nIndex == 1 .AND. At( cChar, "+-" ) > 0 LOOP ENDIF IF cChar == "." .OR. cChar == "," LOOP ENDIF RETURN .F. NEXT RETURN lHasDigit ENDIF RETURN .F. METHOD NormalizarComponenteColor( uValor ) CLASS TFuncFormulas RETURN Max( 0, Min( 255, Int( Val( ::ValorAString( uValor ) ) ) ) ) METHOD ResolverRutaFichero( cRuta ) CLASS TFuncFormulas LOCAL aRutas := {} LOCAL cCandidata LOCAL cNormalizada := AllTrim( cRuta ) LOCAL cPublicSinPrefijo IF cNormalizada == "" RETURN "" ENDIF AAdd( aRutas, cNormalizada ) AAdd( aRutas, "public" + hb_ps() + cNormalizada ) cPublicSinPrefijo := cNormalizada IF Lower( Left( cPublicSinPrefijo, 7 ) ) == "public/" cPublicSinPrefijo := SubStr( cPublicSinPrefijo, 8 ) AAdd( aRutas, "public" + hb_ps() + cPublicSinPrefijo ) ENDIF FOR EACH cCandidata IN aRutas cCandidata := StrTran( cCandidata, "/", hb_ps() ) IF hb_FileExists( cCandidata ) RETURN cCandidata ENDIF NEXT RETURN "" METHOD FechaDesdeValor( uValor ) CLASS TFuncFormulas LOCAL cValor := AllTrim( ::ValorAString( uValor ) ) LOCAL dFecha IF HB_ISDATE( uValor ) RETURN uValor ENDIF IF Len( cValor ) == 8 .AND. Val( cValor ) > 0 .AND. At( "/", cValor ) <= 0 dFecha := ::FechaDesdeTextoSerial( cValor ) IF ! Empty( dFecha ) RETURN dFecha ENDIF ENDIF RETURN ::FechaDesdeTextoVisible( cValor ) METHOD FechaDesdeTextoSerial( cTexto ) CLASS TFuncFormulas RETURN hb_SToD( AllTrim( cTexto ) ) METHOD FechaDesdeTextoVisible( cTexto ) CLASS TFuncFormulas LOCAL aPartes LOCAL nDia LOCAL nMes LOCAL nAnio cTexto := AllTrim( cTexto ) IF At( "/", cTexto ) <= 0 RETURN CToD( "" ) ENDIF aPartes := hb_ATokens( cTexto, "/" ) IF Len( aPartes ) != 3 RETURN CToD( "" ) ENDIF nDia := Val( aPartes[ 1 ] ) nMes := Val( aPartes[ 2 ] ) nAnio := Val( aPartes[ 3 ] ) IF nAnio < 100 nAnio += 2000 ENDIF RETURN hb_SToD( StrZero( nAnio, 4 ) + StrZero( nMes, 2 ) + StrZero( nDia, 2 ) ) METHOD FechaValida( dFecha ) CLASS TFuncFormulas RETURN HB_ISDATE( dFecha ) .AND. ! Empty( dFecha ) METHOD FormatearFechaVisible( dFecha ) CLASS TFuncFormulas RETURN SubStr( DToS( dFecha ), 7, 2 ) + "/" + SubStr( DToS( dFecha ), 5, 2 ) + "/" + SubStr( DToS( dFecha ), 3, 2 ) METHOD FormatearFechaVisibleLarga( dFecha ) CLASS TFuncFormulas RETURN SubStr( DToS( dFecha ), 7, 2 ) + "/" + SubStr( DToS( dFecha ), 5, 2 ) + "/" + SubStr( DToS( dFecha ), 1, 4 ) METHOD LongitudTexto( cTexto ) CLASS TFuncFormulas RETURN hb_UTF8Len( cTexto ) METHOD SubTexto( cTexto, nOffset, nLongitud ) CLASS TFuncFormulas IF ValType( nLongitud ) == "U" RETURN hb_UTF8SubStr( cTexto, nOffset + 1 ) ENDIF IF nLongitud <= 0 RETURN "" ENDIF RETURN hb_UTF8SubStr( cTexto, nOffset + 1, nLongitud ) METHOD ContarDecimalesMascara( cMascara ) CLASS TFuncFormulas LOCAL nPunto := RAt( ".", cMascara ) LOCAL nComa := RAt( ",", cMascara ) LOCAL nSep := Max( nPunto, nComa ) LOCAL nIndex LOCAL nCount := 0 LOCAL cChar LOCAL nLen IF nSep <= 0 RETURN 0 ENDIF nLen := Len( cMascara ) FOR nIndex := nSep + 1 TO nLen cChar := SubStr( cMascara, nIndex, 1 ) IF At( cChar, "0#9" ) > 0 nCount++ ENDIF NEXT RETURN nCount METHOD MascaraUsaMiles( cMascara ) CLASS TFuncFormulas LOCAL nPunto := RAt( ".", cMascara ) LOCAL nComa := RAt( ",", cMascara ) RETURN nPunto > 0 .AND. nComa > 0 .AND. Min( nPunto, nComa ) < Max( nPunto, nComa ) METHOD ExtraerPlantillaNumericaTransform( cMascara ) CLASS TFuncFormulas cMascara := AllTrim( cMascara ) IF Left( Upper( cMascara ), 2 ) == "@E" RETURN AllTrim( SubStr( cMascara, 3 ) ) ENDIF RETURN cMascara METHOD AjustarAnchoMascaraNumerica( cValor, cMascara ) CLASS TFuncFormulas RETURN iif( Len( cValor ) < Len( cMascara ), PadL( cValor, Len( cMascara ) ), cValor ) METHOD AplicarSeparadorMiles( cValor, cSeparadorDecimal, cSeparadorMiles ) CLASS TFuncFormulas LOCAL cSigno := "" LOCAL cEntero LOCAL cDecimales := "" LOCAL cResultado := "" LOCAL nDecimal := At( cSeparadorDecimal, cValor ) LOCAL nIndex LOCAL nEnteroLen IF Left( cValor, 1 ) == "-" .OR. Left( cValor, 1 ) == "+" cSigno := Left( cValor, 1 ) cValor := SubStr( cValor, 2 ) nDecimal := At( cSeparadorDecimal, cValor ) ENDIF IF nDecimal > 0 cEntero := Left( cValor, nDecimal - 1 ) cDecimales := SubStr( cValor, nDecimal ) ELSE cEntero := cValor ENDIF nEnteroLen := Len( cEntero ) FOR nIndex := 1 TO nEnteroLen IF nIndex > 1 .AND. Mod( nEnteroLen - nIndex + 1, 3 ) == 0 cResultado += cSeparadorMiles ENDIF cResultado += SubStr( cEntero, nIndex, 1 ) NEXT RETURN cSigno + cResultado + cDecimales METHOD EsMascaraFecha( cMascara ) CLASS TFuncFormulas RETURN cMascara == "99/99/99" .OR. cMascara == "99/99/9999" METHOD FormatearFechaConMascara( dFecha, cMascara ) CLASS TFuncFormulas RETURN iif( cMascara == "99/99/9999", ::FormatearFechaVisibleLarga( dFecha ), ::FormatearFechaVisible( dFecha ) ) METHOD NumeroATexto( nValor, nDecimales ) CLASS TFuncFormulas LOCAL cTexto := AllTrim( Str( nValor, 30, nDecimales ) ) RETURN cTexto METHOD MaxArray( aValores ) CLASS TFuncFormulas LOCAL uMax LOCAL uValor IF ! HB_ISARRAY( aValores ) .OR. Len( aValores ) == 0 RETURN NIL ENDIF uMax := aValores[ 1 ] FOR EACH uValor IN aValores IF uValor > uMax uMax := uValor ENDIF NEXT RETURN uMax METHOD ExtraerNumeroInicial( cTexto ) CLASS TFuncFormulas LOCAL cValor := LTrim( cTexto ) LOCAL cResultado := "" LOCAL nIndex LOCAL cChar LOCAL lDecimal := .F. LOCAL lDigit := .F. LOCAL nLen nLen := Len( cValor ) FOR nIndex := 1 TO nLen cChar := SubStr( cValor, nIndex, 1 ) IF nIndex == 1 .AND. At( cChar, "+-" ) > 0 cResultado += cChar LOOP ENDIF IF At( cChar, "0123456789" ) > 0 cResultado += cChar lDigit := .T. LOOP ENDIF IF cChar == "." .AND. ! lDecimal cResultado += cChar lDecimal := .T. LOOP ENDIF EXIT NEXT IF ! lDigit RETURN "0" ENDIF RETURN cResultado