allisson / django-pagseguro2

Integração da API v2 do PagSeguro com o Django.
MIT License
95 stars 44 forks source link

Formatação de casas decimais segundo padrão \d+.\d\{2\} estabelecido pelo PagSeguro #5

Closed salsotto closed 9 years ago

salsotto commented 9 years ago

Allison,

Enfrentei alguns problemas ao passar valores decimais com "zero" no final no PagSeguroItem. Exemplo: 19,90 era passado como 19.9.

Sugiro tratar isso diretamente na criação do objeto, uma vez que necessariamente esse parâmetro deve seguir o padão especificado do item 11029 (Item amount invalid pattern: {0}. Must fit the patern: \d+.\d{2}) na tabela de códigos de erro da API.

Sugestões: 1) Cast do parâmetro para Float 2) Formatação de duas casas decimais: format(value, '.2f')

Obs.: equivale para o shippingCost que segue o mesmo padrão.

Talvez você possa achar uma forma mais elegante, mas por hora são essas minhas sugestões.

Abraços!

allisson commented 9 years ago

Basta você passar um decimal diretamente ou uma string contendo o ponto.

Por exemplo:

Decimal(19,90) == Decimal(19.90) False

Se você passa com a vírgula, dá erro:

item1 = PagSeguroItem(id='0001', description='Meu item 0001', amount='100,00', quantity=1) Traceback (most recent call last): File "", line 1, in File "/Users/allisson/Projects/django-pagseguro2/pagseguro/api.py", line 45, in init raise Exception(form.errors.items()) Exception: [('amount', [u'Enter a number.'])]

Passando com o ponto tudo ocorre normalmente:

item1 = PagSeguroItem(id='0001', description='Meu item 0001', amount='100.00', quantity=1)

Você também pode criar um decimal diretamente e passar no amount:

amount = Decimal('19.90') item1 = PagSeguroItem(id='0001', description='Meu item 0001', amount=amount, quantity=1)

Em resumo, como essa validação é feita com decimal, é só passar '19.90' no lugar de '19,90' :)

allisson commented 9 years ago

Fiz esse pedido aqui usando o sandbox:

django-pagseguro2)allisson@Allissons-MacBook-Pro:~/Projects/django-pagseguro2> testapp/manage.py shell Python 2.7.8 (default, Oct 19 2014, 16:02:00) [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.54)] on darwin Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole)

from pagseguro.api import PagSeguroItem, PagSeguroApi item1 = PagSeguroItem(id='0001', description='Meu item 0001', amount='100.90', quantity=1) item2 = PagSeguroItem(id='0002', description='Meu item 0002', amount='150.90', quantity=1, shipping_cost='25.00', weight=500) pagseguro_api = PagSeguroApi(reference='id-unico-de-referencia-do-seu-sistema') pagseguro_api.add_item(item1) pagseguro_api.add_item(item2) data = pagseguro_api.checkout()

Indo para o redirect_url os valores estão ok, mesmo usando 100.90 e 150.90. pagseguro

salsotto commented 9 years ago

No meu caso, o valor é salvo no banco de dados como 19.9 e não salva o zero. Esse é o problema. O que eu passo para o objeto de fato é 19.9 (DecimalField) e não 19,90.

Estava assim: item = PagSeguroItem(id=plano.id, description=plano.nome_pagseguro, amount=plano.value, quantity=1)

e modifiquei assim: item = PagSeguroItem(id=plano.id, description=plano.nome_pagseguro, amount=format(plano.value, '.2f'), quantity=1)

allisson commented 9 years ago

Você tá salvando um valor no banco com apenas uma casa decimal?

Como tá esse seu field no model?

salsotto commented 9 years ago

O campo está configurado da seguinte maneira:

value = models.DecimalField(verbose_name=(u"Valor"), max_digits=10, decimal_places=2)

No entanto, se eu salvo qualquer valor que não termine com zero ele salva normalmente com as duas casas decimais, exemplo: 19,99 é salvo como 19.99.

allisson commented 9 years ago

Nesse caso é um bug no django ehheeheheh.

Você está usando sqlite como banco? Em caso positivo isso é um bug mesmo porque o sqlite não tem campo decimal: http://stackoverflow.com/questions/5418788/different-behavior-for-django-decimalfield-on-sqlite-vs-mysql/5419834#5419834

salsotto commented 9 years ago

Então é isso ai mesmo... estou usando o sqlite no desenvolvimento.

Mas de todo modo, você não acha que seria interessante assegurar que o parâmetro passado seja um valor decimal dentro do padrão do Pagseguro? Digo isso porque o erro que de fato me retornou no Django foi que o dicionário não possuia a chave 'redirect_url'.

Descobri o erro 11029 debugando. Talvez uma exceção direcionando o erro do Pagseguro?

E o que acha de tratar também esse caso do sqlite no objeto, pois não impactará de forma negativa para outras bases e garantirá o uso da app sem necessidades de ajustes da parte de quem usufrui.

Por favor, não entenda mal minhas sugestões, penso apenas maneiras de ajudar! ;)

Valeu pela atenção!

allisson commented 9 years ago

Eu estou usando o django forms para validar os dados, o problema que eu vi aqui é que o decimal_places=2 no form não garante que ele vai ter duas casas, garante que ele vai ter no máximo duas casas.

Eu pensei que ele seguia a mesma regra do decimalfield no model, de qualquer forma, eu vou fazer uma verificação manual pra garantir que o item não seja criado com menos de duas casas decimais.

:)

salsotto commented 9 years ago

Seria legal garantir também que o valor passado seja um decimal.

allisson commented 9 years ago

O django forms já faz essa conversão caso o valor passado seja uma string, então nesse caso não precisa.

Acredito que validando o número mínimo de casas decimais resolve todos os problemas :)