mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Merge pull request #989 from pretix/approvals
Require approval for orders of specific products
This commit is contained in:
@@ -237,7 +237,7 @@ def invoice_pdf_task(invoice: int):
|
||||
|
||||
|
||||
def invoice_qualified(order: Order):
|
||||
if order.total == Decimal('0.00'):
|
||||
if order.total == Decimal('0.00') or order.require_approval:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -169,6 +169,142 @@ def mark_order_expired(order, user=None, auth=None):
|
||||
return order
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def approve_order(order, user=None, send_mail: bool=True, auth=None):
|
||||
"""
|
||||
Mark this order as approved
|
||||
:param order: The order to change
|
||||
:param user: The user that performed the change
|
||||
"""
|
||||
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
||||
raise OrderError(_('This order is not pending approval.'))
|
||||
|
||||
order.require_approval = False
|
||||
order.set_expires(now(), order.event.subevents.filter(id__in=[p.subevent_id for p in order.positions.all()]))
|
||||
order.save()
|
||||
|
||||
order.log_action('pretix.event.order.approved', user=user, auth=auth)
|
||||
if order.total == Decimal('0.00'):
|
||||
p = order.payments.create(
|
||||
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||
provider='free',
|
||||
amount=0,
|
||||
fee=None
|
||||
)
|
||||
try:
|
||||
p.confirm(send_mail=False, count_waitinglist=False, user=user, auth=auth)
|
||||
except Quota.QuotaExceededException:
|
||||
raise OrderError(error_messages['unavailable'])
|
||||
|
||||
invoice = order.invoices.last() # Might be generated by plugin already
|
||||
if order.event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
|
||||
if not invoice:
|
||||
generate_invoice(
|
||||
order,
|
||||
trigger_pdf=not order.event.settings.invoice_email_attachment or not order.email
|
||||
)
|
||||
# send_mail will trigger PDF generation later
|
||||
|
||||
if send_mail:
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
|
||||
with language(order.locale):
|
||||
if order.total == Decimal('0.00'):
|
||||
email_template = order.event.settings.mail_text_order_free
|
||||
email_subject = _('Order approved and confirmed: %(code)s') % {'code': order.code}
|
||||
else:
|
||||
email_template = order.event.settings.mail_text_order_approved
|
||||
email_subject = _('Order approved and awaiting payment: %(code)s') % {'code': order.code}
|
||||
|
||||
email_context = {
|
||||
'total': LazyNumber(order.total),
|
||||
'currency': order.event.currency,
|
||||
'total_with_currency': LazyCurrencyNumber(order.total, order.event.currency),
|
||||
'date': LazyDate(order.expires),
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_approved', user
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order approved email could not be sent')
|
||||
|
||||
return order.pk
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
|
||||
"""
|
||||
Mark this order as canceled
|
||||
:param order: The order to change
|
||||
:param user: The user that performed the change
|
||||
"""
|
||||
if not order.require_approval or not order.status == Order.STATUS_PENDING:
|
||||
raise OrderError(_('This order is not pending approval.'))
|
||||
|
||||
with order.event.lock():
|
||||
order.status = Order.STATUS_CANCELED
|
||||
order.save()
|
||||
|
||||
order.log_action('pretix.event.order.denied', user=user, auth=auth, data={
|
||||
'comment': comment
|
||||
})
|
||||
i = order.invoices.filter(is_cancellation=False).last()
|
||||
if i:
|
||||
generate_cancellation(i)
|
||||
|
||||
for position in order.positions.all():
|
||||
if position.voucher:
|
||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=F('redeemed') - 1)
|
||||
|
||||
if send_mail:
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
invoice_company = order.invoice_address.company
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
email_template = order.event.settings.mail_text_order_denied
|
||||
email_context = {
|
||||
'total': LazyNumber(order.total),
|
||||
'currency': order.event.currency,
|
||||
'total_with_currency': LazyCurrencyNumber(order.total, order.event.currency),
|
||||
'date': LazyDate(order.expires),
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'comment': comment,
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
with language(order.locale):
|
||||
email_subject = _('Order denied: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_denied', user
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order denied email could not be sent')
|
||||
|
||||
return order.pk
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, oauth_application=None):
|
||||
"""
|
||||
@@ -342,7 +478,10 @@ def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvid
|
||||
meta_info: dict, event: Event):
|
||||
fees = []
|
||||
total = sum([c.price for c in positions])
|
||||
payment_fee = payment_provider.calculate_fee(total)
|
||||
if payment_provider:
|
||||
payment_fee = payment_provider.calculate_fee(total)
|
||||
else:
|
||||
payment_fee = 0
|
||||
pf = None
|
||||
if payment_fee:
|
||||
pf = OrderFee(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=payment_fee,
|
||||
@@ -370,6 +509,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
locale=locale,
|
||||
total=total,
|
||||
meta_info=json.dumps(meta_info or {}),
|
||||
require_approval=any(p.item.require_approval for p in positions)
|
||||
)
|
||||
order.set_expires(now_dt, event.subevents.filter(id__in=[p.subevent_id for p in positions]))
|
||||
order.save()
|
||||
@@ -389,12 +529,13 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
fee.tax_rule = None # TODO: deprecate
|
||||
fee.save()
|
||||
|
||||
order.payments.create(
|
||||
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||
provider=payment_provider,
|
||||
amount=total,
|
||||
fee=pf
|
||||
)
|
||||
if payment_provider:
|
||||
order.payments.create(
|
||||
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||
provider=payment_provider,
|
||||
amount=total,
|
||||
fee=pf
|
||||
)
|
||||
|
||||
OrderPosition.transform_cart_positions(positions, order)
|
||||
order.log_action('pretix.event.order.placed')
|
||||
@@ -410,9 +551,12 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
email: str, locale: str, address: int, meta_info: dict=None):
|
||||
|
||||
event = Event.objects.get(id=event)
|
||||
pprov = event.get_payment_providers().get(payment_provider)
|
||||
if not pprov:
|
||||
raise OrderError(error_messages['internal'])
|
||||
if payment_provider:
|
||||
pprov = event.get_payment_providers().get(payment_provider)
|
||||
if not pprov:
|
||||
raise OrderError(error_messages['internal'])
|
||||
else:
|
||||
pprov = None
|
||||
|
||||
if email == settings.PRETIX_EMAIL_NONE_VALUE:
|
||||
email = None
|
||||
@@ -445,7 +589,10 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
# send_mail will trigger PDF generation later
|
||||
|
||||
if order.email:
|
||||
if payment_provider == 'free':
|
||||
if order.require_approval:
|
||||
email_template = event.settings.mail_text_order_placed_require_approval
|
||||
log_entry = 'pretix.event.order.email.order_placed_require_approval'
|
||||
elif payment_provider == 'free':
|
||||
email_template = event.settings.mail_text_order_free
|
||||
log_entry = 'pretix.event.order.email.order_free'
|
||||
else:
|
||||
@@ -458,6 +605,12 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
|
||||
if pprov:
|
||||
payment_info = str(pprov.order_pending_mail_render(order))
|
||||
else:
|
||||
payment_info = None
|
||||
|
||||
email_context = {
|
||||
'total': LazyNumber(order.total),
|
||||
'currency': event.currency,
|
||||
@@ -468,7 +621,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'payment_info': str(pprov.order_pending_mail_render(order)),
|
||||
'payment_info': payment_info,
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
@@ -489,7 +642,8 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
def expire_orders(sender, **kwargs):
|
||||
eventcache = {}
|
||||
|
||||
for o in Order.objects.filter(expires__lt=now(), status=Order.STATUS_PENDING).select_related('event'):
|
||||
for o in Order.objects.filter(expires__lt=now(), status=Order.STATUS_PENDING,
|
||||
require_approval=False).select_related('event'):
|
||||
expire = eventcache.get(o.event.pk, None)
|
||||
if expire is None:
|
||||
expire = o.event.settings.get('payment_term_expire_automatically', as_type=bool)
|
||||
|
||||
Reference in New Issue
Block a user