// Moldado para C++ com uso da Qt Framework.
//
// Rotina simples que a partir de uma QVariant, converte números com ou sem casas decimais
// para valores por extenso, com ou sem referências à moeda corrente do nosso país (Real)
//
// É uma perfeita gambiarra. Suporta valores até quintilhões de reais.
//
// Exemplo de uso:
// QString str = valorPorExtenso(pow(2,32));
// // str = "Quatro Bilhões, Duzentos e Noventa e Quatro Milhões, Novecentos e Sessenta e Sete Mil e Duzentos e Noventa e Seis Reais"
//
// Includes necessários
#include <QObject>
#include <QStringList>
#include <QVariant>
#include <cmath>
/**
* @brief blocoExtenso - Funcao auxiliar para a valorPorExtenso(..)
* @param valor valor por extenso, limite de 3 numeros, maior que isso, ele trunca
* @return Retorna string contendo o bloco de 3 numeros por exenso
*/
static QString blocoExtenso(QVariant valor)
{
QString aux, num;
QString extenso;
bool ok = false, round = false;
static QStringList cent = QStringList()
<< "Cento" << "Duzentos" << "Trezentos" << "Quatrocentos"
<< "Quinhentos" << "Seiscentos" << "Setecentos" << "Oitocentos" << "Novecentos";
static QStringList deze = QStringList()
<< "Dez" << "Vinte" << "Trinta" << "Quarenta" << "Cinquenta"
<< "Sessenta" << "Setenta" << "Oitenta" << "Noventa";
static QStringList unid = QStringList()
<< "Um" << "Dois" << QObject::tr("Três") << "Quatro" << "Cinco" << "Seis" << "Sete"
<< "Oito" << "Nove" << "Dez" << "Onze" << "Doze" << "Treze" << "Quatorze"
<< "Quinze" << "Dezesseis" << "Dezessete" << "Dezoito" << "Dezenove";
int digito, tam = 2, val = valor.toInt(&ok);
if(!ok || !val) return QString();
num = valor.toString().rightJustified(3, '0');
num.truncate(3);
if(val < 20) {
aux = unid.at(val-1);
extenso.prepend(aux);
}
else if(val == 100)
extenso.prepend("Cem");
else {
for(int i = 0; i <= tam; i++) {
digito = num.at(tam-i).digitValue();
if(!digito) continue;
round = false;
switch (i) {
case 2:
aux = cent.at(digito-1); if(num.at(1) == QChar('0') && num.at(2) == QChar('0')) round = true;
break;
case 1:
if(num.at(1).digitValue() == 1 && num.at(0).digitValue() > 0) {
aux = blocoExtenso(num.mid(1,2)); round = true;
}
else
aux = deze.at(digito-1); if(num.at(0) == QChar('0') && num.at(2) == QChar('0')) round = true;
break;
case 0:
if(num.at(1).digitValue() == 1 && num.at(0).digitValue() > 0)
aux = "";
else
aux = unid.at(digito-1); round = true;
break;
}
(round) ? extenso.prepend(aux) : extenso.prepend(aux+" e ");
}
}
return extenso;
}
/**
* @brief valorPorExtenso - Imprime valor financeiro (ou nao) por extenso
* @param valor Valor a ser convertido
* @param decimais Decimais do numero na saida, maximo 3 casas
* @param semMoeda Omitir as palavras 'Reais' e 'Centavos' no valor por extenso
* @return Valor convertido para extenso.
*/
static QString valorPorExtenso(QVariant valor, int decimais = 2, bool semMoeda = false)
{
bool ok;
QString aux, num, frac;
QString extenso;
double val = valor.toDouble(&ok);
if(!ok) return "<NUMERO INVALIDO>";
if(decimais > 3) decimais = 3;
double inteiro, fracao = modf(val, &inteiro);
fracao *= pow(10, decimais);
num = QString::number(inteiro, 'f');
num = num.mid(0, num.indexOf('.'));
int tam = num.size();
if(tam % 3) {
num = num.rightJustified((int)(ceil(tam/3.0) * 3),'0');
tam = num.size();
}
frac = QString::number(fracao, 'f');
frac = frac.mid(0, frac.indexOf('.'));
bool match = false;
if(val < 100)
extenso.prepend(blocoExtenso(num)+" ");
else {
for(int i = 3; i <= tam; i+=3) {
aux = blocoExtenso(num.mid(tam-i, 3));
if(aux.size() == 0)
continue;
switch(i) {
case 21: aux += " Quinti"; match = true; break;
case 18: aux += " Quadri"; match = true; break;
case 15: aux += " Tri"; match = true; break;
case 12: aux += " Bi"; match = true; break;
case 9: aux += " Mi"; match = true; break;
case 6: aux += " Mi"; match = true; break;
default: aux += " "; break;
}
if(match) {
if(num.mid(i, tam).indexOf("[1-9]") && i != 6 && num.mid(tam-i, 3).toInt() != 1)
extenso.prepend(aux+QObject::tr("lhões, "));
else
(i == 6) ? extenso.prepend(aux+"l e ") : extenso.prepend(aux+QObject::tr("lhão, "));
match = false;
}
else
extenso.prepend(aux);
}
}
if(!semMoeda)
(val < 2) ? extenso.append("Real") : extenso.append("Reais");
if(fracao > 0) {
extenso += " e "+blocoExtenso(frac);
if(!semMoeda)
extenso += " centavos";
}
return extenso.replace(" ", " ").replace(" e Reais", " Reais").replace(", Reais"," de Reais");
}