Refs #99 -- Improve support for currencies with less than 2 decimal places (#783)

* Refs #99 -- Fix stripe support for zero-decimal currencies

* Add new money formatting method

* Force decimal places in many places

* Locale-aware currency rendering

* Fix currencies in more places

* More currency fixes
This commit is contained in:
Raphael Michel
2018-02-26 10:46:07 +01:00
committed by GitHub
parent 29e22a0c6c
commit 3c3e59e932
49 changed files with 467 additions and 211 deletions

View File

@@ -1,7 +1,7 @@
{% load i18n %}{% load l10n %}{% blocktrans with bank=details|safe code=order.full_code total=order.total|localize currency=event.currency %}
{% load i18n %}{% load l10n %}{% load money %}{% blocktrans with bank=details|safe code=order.full_code total=order.total|money:event.currency %}
Please transfer the full amount to the following bank account.
Reference: {{ code }}
Amount: {{ total }} {{ currency }}
Amount: {{ total }}
{{ bank }}
{% endblocktrans %}

View File

@@ -1,5 +1,6 @@
{% load i18n %}
{% load l10n %}
{% load money %}
<p>{% blocktrans trimmed %}
Please transfer the full amount to the following bank account:
@@ -7,6 +8,6 @@
<address>
{{ details|linebreaksbr }}<br />
{% trans "Amount:" %} {{ order.total|localize }} {{ event.currency }}<br />
{% trans "Amount:" %} {{ order.total|money:event.currency }}<br />
<strong>{% trans "Reference code (important):" %} {{ order.full_code }}</strong>
</address>

View File

@@ -1,5 +1,6 @@
{% load i18n %}
{% load rich_text %}
{% load money %}
{% load staticfiles %}
<div class="table-responsive">
{% csrf_token %}
@@ -85,7 +86,7 @@
<td>
{% if trans.order %}
<a href="{% url "control:event.order" event=trans.order.event.slug organizer=request.organizer.slug code=trans.order.code %}"
data-toggle="tooltip" title="{{ trans.order.total|floatformat:2 }} {{ trans.order.event.currency }}">
data-toggle="tooltip" title="{{ trans.order.total|money:trans.order.event.currency }}">
{% if not request.event %}
{{ trans.order.event.slug|upper }}-{{ trans.order.code }}
{% else %}

View File

@@ -18,6 +18,7 @@ from pretix.base.models import Order, Quota
from pretix.base.services.mail import SendMailException
from pretix.base.services.orders import mark_order_paid
from pretix.base.settings import SettingsSandbox
from pretix.base.templatetags.money import money_filter
from pretix.control.permissions import (
EventPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
)
@@ -147,8 +148,6 @@ class ActionView(View):
})
def get(self, request, *args, **kwargs):
from django.utils.formats import localize
u = request.GET.get('query', '')
if len(u) < 2:
return JsonResponse({'results': []})
@@ -178,7 +177,7 @@ class ActionView(View):
{
'code': o.event.slug.upper() + '-' + o.code,
'status': o.get_status_display(),
'total': localize(o.total) + ' ' + o.event.currency
'total': money_filter(o.total, o.event.currency)
} for o in qs
]
})

View File

@@ -6,7 +6,7 @@ from defusedcsv import csv
from django import forms
from django.db.models import Max, OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.utils.formats import date_format, localize
from django.utils.formats import date_format
from django.utils.timezone import is_aware, make_aware
from django.utils.translation import pgettext, ugettext as _, ugettext_lazy
from pytz import UTC
@@ -15,6 +15,7 @@ from reportlab.platypus import Flowable, Paragraph, Spacer, Table, TableStyle
from pretix.base.exporter import BaseExporter
from pretix.base.models import Checkin, Order, OrderPosition, Question
from pretix.base.templatetags.money import money_filter
from pretix.plugins.reports.exporters import ReportlabExportMixin
@@ -200,7 +201,7 @@ class PDFCheckinList(ReportlabExportMixin, BaseCheckinList):
op.order.code,
name,
str(op.item.name) + (" " + str(op.variation.value) if op.variation else "") + "\n" +
self.event.currency + " " + localize(op.price),
money_filter(op.price, self.event.currency),
]
acache = {}
for a in op.answers.all():

View File

@@ -55,6 +55,8 @@ class Paypal(BasePaymentProvider):
('client_id',
forms.CharField(
label=_('Client ID'),
max_length=80,
min_length=80,
help_text=_('<a target="_blank" rel="noopener" href="{docs_url}">{text}</a>').format(
text=_('Click here for a tutorial on how to obtain the required keys'),
docs_url='https://docs.pretix.eu/en/latest/user/payments/paypal.html'
@@ -63,6 +65,8 @@ class Paypal(BasePaymentProvider):
('secret',
forms.CharField(
label=_('Secret'),
max_length=80,
min_length=80,
))
]
)

View File

@@ -7,7 +7,8 @@ from django import forms
from django.conf import settings
from django.contrib.staticfiles import finders
from django.db.models import Sum
from django.utils.formats import date_format, localize
from django.template.defaultfilters import floatformat
from django.utils.formats import date_format
from django.utils.timezone import get_current_timezone, now
from django.utils.translation import pgettext, pgettext_lazy, ugettext as _
@@ -194,49 +195,50 @@ class OverviewReport(Report):
]
items_by_category, total = order_overview(self.event, subevent=self.form_data.get('subevent'))
places = settings.CURRENCY_PLACES.get(self.event.currency, 2)
for tup in items_by_category:
if tup[0]:
tstyledata.append(('FONTNAME', (0, len(tdata)), (-1, len(tdata)), 'OpenSansBd'))
tdata.append([
tup[0].name,
str(tup[0].num_canceled[0]), localize(tup[0].num_canceled[1]),
str(tup[0].num_refunded[0]), localize(tup[0].num_refunded[1]),
str(tup[0].num_expired[0]), localize(tup[0].num_expired[1]),
str(tup[0].num_pending[0]), localize(tup[0].num_pending[1]),
str(tup[0].num_paid[0]), localize(tup[0].num_paid[1]),
str(tup[0].num_total[0]), localize(tup[0].num_total[1]),
str(tup[0].num_canceled[0]), floatformat(tup[0].num_canceled[1], places),
str(tup[0].num_refunded[0]), floatformat(tup[0].num_refunded[1], places),
str(tup[0].num_expired[0]), floatformat(tup[0].num_expired[1], places),
str(tup[0].num_pending[0]), floatformat(tup[0].num_pending[1], places),
str(tup[0].num_paid[0]), floatformat(tup[0].num_paid[1], places),
str(tup[0].num_total[0]), floatformat(tup[0].num_total[1], places),
])
for item in tup[1]:
tdata.append([
" " + str(item.name),
str(item.num_canceled[0]), localize(item.num_canceled[1]),
str(item.num_refunded[0]), localize(item.num_refunded[1]),
str(item.num_expired[0]), localize(item.num_expired[1]),
str(item.num_pending[0]), localize(item.num_pending[1]),
str(item.num_paid[0]), localize(item.num_paid[1]),
str(item.num_total[0]), localize(item.num_total[1]),
str(item.num_canceled[0]), floatformat(item.num_canceled[1], places),
str(item.num_refunded[0]), floatformat(item.num_refunded[1], places),
str(item.num_expired[0]), floatformat(item.num_expired[1], places),
str(item.num_pending[0]), floatformat(item.num_pending[1], places),
str(item.num_paid[0]), floatformat(item.num_paid[1], places),
str(item.num_total[0]), floatformat(item.num_total[1], places),
])
if item.has_variations:
for var in item.all_variations:
tdata.append([
" " + str(var),
str(var.num_canceled[0]), localize(var.num_canceled[1]),
str(var.num_refunded[0]), localize(var.num_refunded[1]),
str(var.num_expired[0]), localize(var.num_expired[1]),
str(var.num_pending[0]), localize(var.num_pending[1]),
str(var.num_paid[0]), localize(var.num_paid[1]),
str(var.num_total[0]), localize(var.num_total[1]),
str(var.num_canceled[0]), floatformat(var.num_canceled[1], places),
str(var.num_refunded[0]), floatformat(var.num_refunded[1], places),
str(var.num_expired[0]), floatformat(var.num_expired[1], places),
str(var.num_pending[0]), floatformat(var.num_pending[1], places),
str(var.num_paid[0]), floatformat(var.num_paid[1], places),
str(var.num_total[0]), floatformat(var.num_total[1], places),
])
tdata.append([
_("Total"),
str(total['num_canceled'][0]), localize(total['num_canceled'][1]),
str(total['num_refunded'][0]), localize(total['num_refunded'][1]),
str(total['num_expired'][0]), localize(total['num_expired'][1]),
str(total['num_pending'][0]), localize(total['num_pending'][1]),
str(total['num_paid'][0]), localize(total['num_paid'][1]),
str(total['num_total'][0]), localize(total['num_total'][1]),
str(total['num_canceled'][0]), floatformat(total['num_canceled'][1], places),
str(total['num_refunded'][0]), floatformat(total['num_refunded'][1], places),
str(total['num_expired'][0]), floatformat(total['num_expired'][1], places),
str(total['num_pending'][0]), floatformat(total['num_pending'][1], places),
str(total['num_paid'][0]), floatformat(total['num_paid'][1], places),
str(total['num_total'][0]), floatformat(total['num_total'][1], places),
])
table = Table(tdata, colWidths=colwidths, repeatRows=3)

View File

@@ -5,6 +5,7 @@ from collections import OrderedDict
import stripe
from django import forms
from django.conf import settings
from django.contrib import messages
from django.template.loader import get_template
from django.utils.translation import ugettext, ugettext_lazy as _
@@ -165,6 +166,10 @@ class StripeMethod(BasePaymentProvider):
def order_prepare(self, request, order):
return self.checkout_prepare(request, None)
def _get_amount(self, order):
places = settings.CURRENCY_PLACES.get(self.event.currency, 2)
return int(order.total * 10 ** places)
def _init_api(self):
stripe.api_version = '2017-06-05'
stripe.api_key = self.settings.get('secret_key')
@@ -180,7 +185,7 @@ class StripeMethod(BasePaymentProvider):
def _charge_source(self, request, source, order):
try:
charge = stripe.Charge.create(
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
source=source,
metadata={
@@ -269,7 +274,7 @@ class StripeMethod(BasePaymentProvider):
if order.payment_info:
payment_info = json.loads(order.payment_info)
if 'amount' in payment_info:
payment_info['amount'] /= 100
payment_info['amount'] /= 10 ** settings.CURRENCY_PLACES.get(self.event.currency, 2)
else:
payment_info = None
template = get_template('pretixplugins/stripe/control.html')
@@ -411,7 +416,7 @@ class StripeCC(StripeMethod):
request.session['payment_stripe_order_secret'] = order.secret
source = stripe.Source.create(
type='three_d_secure',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
three_d_secure={
'card': src.id
@@ -479,7 +484,7 @@ class StripeGiropay(StripeMethod):
try:
source = stripe.Source.create(
type='giropay',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
metadata={
'order': str(order.id),
@@ -538,7 +543,7 @@ class StripeIdeal(StripeMethod):
def _create_source(self, request, order):
source = stripe.Source.create(
type='ideal',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
metadata={
'order': str(order.id),
@@ -585,7 +590,7 @@ class StripeAlipay(StripeMethod):
def _create_source(self, request, order):
source = stripe.Source.create(
type='alipay',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
metadata={
'order': str(order.id),
@@ -634,7 +639,7 @@ class StripeBancontact(StripeMethod):
try:
source = stripe.Source.create(
type='bancontact',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
metadata={
'order': str(order.id),
@@ -706,7 +711,7 @@ class StripeSofort(StripeMethod):
def _create_source(self, request, order):
source = stripe.Source.create(
type='sofort',
amount=int(order.total * 100),
amount=self._get_amount(order),
currency=self.event.currency.lower(),
metadata={
'order': str(order.id),

View File

@@ -11,7 +11,7 @@ from django.core.files import File
from django.core.files.storage import default_storage
from django.http import HttpRequest
from django.template.loader import get_template
from django.utils.formats import date_format, localize
from django.utils.formats import date_format
from django.utils.translation import ugettext_lazy as _
from pytz import timezone
from reportlab.graphics import renderPDF
@@ -29,6 +29,7 @@ from reportlab.platypus import Paragraph
from pretix.base.i18n import language
from pretix.base.models import Order, OrderPosition
from pretix.base.templatetags.money import money_filter
from pretix.base.ticketoutput import BaseTicketOutput
from pretix.plugins.ticketoutputpdf.signals import (
get_fonts, layout_text_variables,
@@ -81,7 +82,7 @@ DEFAULT_VARIABLES = OrderedDict((
("price", {
"label": _("Price"),
"editor_sample": _("123.45 EUR"),
"evaluate": lambda op, order, event: '{} {}'.format(event.currency, localize(op.price))
"evaluate": lambda op, order, event: money_filter(op.price, event.currency)
}),
("attendee_name", {
"label": _("Attendee name"),