- Suporte a extenso
- Geração Automática (param:
bol:show_in_words
) - Possibilidade de armazenamento em outro campo (param:
Field:in_words_field
) - Suporte a multiplas moedas
- Armazenamento da moeda
- Suporte a internacionalização baseado nas informações do unicode.org
- Tendo em vista que as informações de formatos de moeda, estão disponíveis e parametrizadas na base de dados do unicode.org, é interessante utilizar estas informações, pois com base nas configurações, ou moeda escolhida, pode-se formatar a visualização exata de cada moeda.
Last active
November 10, 2017 19:33
-
-
Save MaxMorais/5013885 to your computer and use it in GitHub Desktop.
Web2py MoneyInput Widget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This widget requires jQuery-iMask to run | |
#https://github.com/cwolves/jQuery-iMask | |
def money_widget_factory(international=False): | |
import locale, string, random | |
from gluon.sqlhtml import StringWidget | |
from gluon import current | |
from gluon.http import HTTP | |
T = current.T | |
locale.setlocale(locale.LC_ALL, '') | |
loc = locale.localeconv() | |
if not getattr(current.session, 'mw_uids', None): | |
current.session.mw_uids = {} | |
if not international: | |
SYMBOL = loc.get('currency_symbol', None) or '' | |
DECIMAL_PLACES = loc.get('frac_digits', None) or 2 | |
DECIMAL_SEPARATOR = loc.get('mon_decimal_point', None) or '.' | |
THOUSAND_PLACES = loc.get('mon_grouping', [3,0])[0] | |
THOUSAND_SEPARATOR = loc.get('mon_thousands_sep', None) or ',' | |
else: | |
SYMBOL = loc.get('int_curr_symbol', None) or '', | |
DECIMAL_PLACES = loc.get('int_frac_digits', None) or 2 | |
DECIMAL_SEPARATOR = loc.get('mon_decimal_point', None) or '.' | |
THOUSAND_PLACES = loc.get('mon_grouping', [3,0])[0] | |
THOUSAND_SEPARATOR = loc.get('mon_thousands_sep', None) or ',' | |
lib = URL(c='static', f='js/jquery-imask.js'); | |
basescripts = [""" | |
;/* Plugin jQuery para o agendamento da execucao de uma determinada acao | |
no instante em que o objeto passar a existir */ | |
$.fn.onAvailable = function(fn){ | |
var self = this, sel = this.selector, timer; | |
if (this.length > 0) { | |
fn.call(this); | |
} else { | |
timer = setInterval(function(){ | |
if ($(sel).length > 0) { | |
fn.call(self); | |
clearInterval(timer); | |
} | |
}, 50); | |
} | |
};""", | |
""" | |
;function maskMoneyThis(uid){ | |
$('input[uid="' + uid + '"]').onAvailable(function(){ | |
var element = $('input[uid="' + uid + '"]'); | |
if (!element.data('masked')){ | |
element.iMask({ | |
'type': 'number', | |
'currencySymbol': element.data('symbol'), | |
'decDigits': parseFloat(element.data('decimal_places')), | |
'groupSymbol': element.data('thousand_separator'), | |
'decSymbol': element.data('decimal_separator'), | |
'groupDigits': parseFloat(element.data('thousand_places')) | |
}); | |
element.focus(); | |
} | |
element.focusout(function(event){ | |
var val = element.val() | |
.replace(element.data('symbol'), '') | |
.replace(element.data('thousand_separator'), '') | |
.replace(element.data('decimal_separator'), '.'); | |
if (val.length){ | |
console.log(element.data('url')+'?'+element.data('keyword')+'='+val); | |
console.log(element.data('target')); | |
ajax(element.data('url')+'?'+element.data('keyword')+'='+val, [], element.data('target')); | |
} | |
}); | |
}); | |
}; | |
""" | |
] | |
if not lib in response.files: | |
response.files.append(lib) | |
response.js = (response.js or '') | |
for basescript in basescripts: | |
if not basescript in response.js: | |
response.js += basescript.strip() | |
def in_words(integer): | |
""" | |
Retorna string por extenso para o dado inteiro. | |
""" | |
if not integer: return '' | |
n = int(integer) | |
known = { | |
0: T('zero'), 1: T('one'), 2: T('two'), 3: T('three'), 4: T('four'), | |
5: T('five'), 6: T('six'), 7: T('seven'), 8: T('eight'), 9: T('nine'), | |
10: T('ten'), 11: T('eleven'), 12 : T('twelve'), 13: T('thirteen'), 14: T('fourteen'), | |
15: T('fifteen'), 16: T('sixteen'), 17: T('seventeen'), 18: T('eighteen'), 19: T('nineteen'), | |
20: T('twenty'), 30: T('thirty'), 40: T('forty'), 50: T('fifty'), 60: T('sixty'), | |
70: T('seventy'), 80: T('eighty'), 90: T('ninety') | |
} | |
def psn(n, known, xpsn): | |
import sys; | |
if n in known: return known[n] | |
bestguess, remainder = str(n), 0 | |
if n<=20: | |
print >> sys.stderr, n, T('How did this happen?') | |
assert 0 | |
elif n < 100: | |
bestguess = xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn) | |
return bestguess | |
elif n < 1000: | |
bestguess = xpsn(n//100, known, xpsn) + ' ' + T('hundred') | |
remainder = n % 100 | |
elif n < 1000000: | |
bestguess= xpsn(n//1000, known, xpsn) + ' ' + T('thousand') | |
remainder = n % 1000 | |
elif n < 1000000000: | |
bestguess= xpsn(n//1000000, known, xpsn) + ' ' + T('million') | |
remainder = n%1000000 | |
else: | |
bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + T('billion') | |
remainder = n%1000000000 | |
if remainder: | |
comma = ',' if remainder >= 100 else '' | |
return bestguess + comma + ' ' + xpsn(remainder, known, xpsn) | |
else: | |
return bestguess | |
return psn(n, known, psn) | |
def money_in_words(value, main_currency='reais', fraction_currency='centavos'): | |
""" | |
Retorna uma string por extenso com a moeda e a fracao de moeda | |
""" | |
n = "%0.2f" % float(value) | |
main, fraction = n.split('.') | |
if len(fraction) == 1: | |
fraction += '0' | |
out = in_words(main).title() + ' ' + main_currency | |
if int(fraction): | |
out = out + ' ' + T('and') + ' ' + in_words(fraction).title() + ' ' + fraction_currency | |
return out + '.' | |
# Cria uma string randomica - útil para identificadores | |
UID = lambda length=8: ''.join([random.choice(string.ascii_letters+string.digits) for x in range(length)]) | |
class MoneyWidget(StringWidget): | |
_class = 'money' | |
_keyword = 'keyword_' | |
@classmethod | |
def widget(cls, field, value, **attributes): | |
#remove todos os caracters que não compõem um decimal | |
fin = lambda data: str(data).replace(SYMBOL, '').replace(THOUSAND_SEPARATOR, '').replace(DECIMAL_SEPARATOR, '.').strip() or '0.00' if data else None | |
if request.vars: | |
if request.vars[field.name]: | |
request.vars[field.name] = fin(request.vars[field.name]) | |
uid = current.session.mw_uids[field.name] | |
keyword = cls._keyword+uid | |
if keyword in request.vars: | |
cls.callback(uid) | |
else: | |
uid = UID() | |
current.session.mw_uids[field.name] = uid | |
keyword = cls._keyword+uid | |
target = field.name + '_extenso' | |
defaults = { | |
'_data-SYMBOL': (SYMBOL + ' ') if SYMBOL else '', | |
'_data-DECIMAL_PLACES': DECIMAL_PLACES, | |
'_data-DECIMAL_SEPARATOR': DECIMAL_SEPARATOR, | |
'_data-THOUSAND_PLACES': THOUSAND_PLACES, | |
'_data-THOUSAND_SEPARATOR': THOUSAND_SEPARATOR, | |
'_data-URL': URL(), | |
'_data-KEYWORD': keyword, | |
'_data-TARGET': target, | |
'_uid': uid, | |
} | |
attr = cls._attributes(field, defaults, **attributes) | |
script = ";maskMoneyThis(%s);"%`uid` | |
if not script in response.js: | |
response.js += script | |
return DIV( | |
StringWidget.widget(field, fin(value), **attr), | |
P(_id=target) | |
) | |
@classmethod | |
def callback(cls, uid): | |
value = request.vars[cls._keyword+uid] | |
raise HTTP(200, money_in_words(value)) | |
return MoneyWidget.widget | |
Contatos = db.define_table('contatos', | |
Field('nome', 'string', notnull=True), | |
Field('email', 'string'), | |
Field('celular', 'string', widget=masked_widget_factory('(99) 9999-9999')), | |
Field('emprestimo', 'float', widget=money_widget_factory()), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment