def create(self, request, *args, **kwargs): serializer = OrderCreateSerializer( data=request.data, context=self.get_serializer_context()) serializer.is_valid(raise_exception=True) with transaction.atomic(): self.perform_create(serializer) order = serializer.instance serializer = OrderSerializer(order, context=serializer.context) order.log_action( 'pretix.event.order.placed', user=request.user if request.user.is_authenticated else None, auth=request.auth, ) order_placed.send(self.request.event, order=order) gen_invoice = invoice_qualified(order) and ( (order.event.settings.get('invoice_generate') == 'True') or (order.event.settings.get('invoice_generate') == 'paid' and order.status == Order.STATUS_PAID)) and not order.invoices.last() if gen_invoice: generate_invoice(order, trigger_pdf=True) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def _create_order(event: Event, email: str, positions: list, dt: datetime, payment_provider: BasePaymentProvider, locale: str = None): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee expires = [ dt + timedelta(days=event.settings.get('payment_term_days', as_type=int)) ] if event.settings.get('payment_term_last'): expires.append( event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create(status=Order.STATUS_PENDING, event=event, email=email, datetime=dt, expires=min(expires), locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier) OrderPosition.transform_cart_positions(positions, order) order_placed.send(event, order=order) return order
def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, payment_provider: BasePaymentProvider, locale: str=None, address: int=None, meta_info: dict=None): from datetime import date, time total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee tz = pytz.timezone(event.settings.timezone) exp_by_date = now_dt.astimezone(tz) + timedelta(days=event.settings.get('payment_term_days', as_type=int)) exp_by_date = exp_by_date.astimezone(tz).replace(hour=23, minute=59, second=59, microsecond=0) if event.settings.get('payment_term_weekdays'): if exp_by_date.weekday() == 5: exp_by_date += timedelta(days=2) elif exp_by_date.weekday() == 6: exp_by_date += timedelta(days=1) expires = exp_by_date if event.settings.get('payment_term_last'): last_date = make_aware(datetime.combine( event.settings.get('payment_term_last', as_type=date), time(hour=23, minute=59, second=59) ), tz) if last_date < expires: expires = last_date with transaction.atomic(): order = Order.objects.create( status=Order.STATUS_PENDING, event=event, email=email, datetime=now_dt, expires=expires, locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier, meta_info=json.dumps(meta_info or {}), ) OrderPosition.transform_cart_positions(positions, order) if address is not None: try: addr = InvoiceAddress.objects.get( pk=address ) if addr.order is not None: addr.pk = None addr.order = order addr.save() except InvoiceAddress.DoesNotExist: pass order.log_action('pretix.event.order.placed') order_placed.send(event, order=order) return order
def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, payment_provider: BasePaymentProvider, locale: str=None, address: int=None, meta_info: dict=None): from datetime import date, time total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee tz = pytz.timezone(event.settings.timezone) exp_by_date = now_dt.astimezone(tz) + timedelta(days=event.settings.get('payment_term_days', as_type=int)) exp_by_date = exp_by_date.replace(hour=23, minute=59, second=59, microsecond=0) if event.settings.get('payment_term_weekdays'): if exp_by_date.weekday() == 5: exp_by_date += timedelta(days=2) elif exp_by_date.weekday() == 6: exp_by_date += timedelta(days=1) expires = exp_by_date if event.settings.get('payment_term_last'): last_date = make_aware(datetime.combine( event.settings.get('payment_term_last', as_type=date), time(hour=23, minute=59, second=59) ), tz) if last_date < expires: expires = last_date order = Order.objects.create( status=Order.STATUS_PENDING, event=event, email=email, datetime=now_dt, expires=expires, locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier, meta_info=json.dumps(meta_info or {}), ) OrderPosition.transform_cart_positions(positions, order) if address is not None: try: addr = InvoiceAddress.objects.get( pk=address ) if addr.order is not None: addr.pk = None addr.order = order addr.save() except InvoiceAddress.DoesNotExist: pass order.log_action('pretix.event.order.placed') order_placed.send(event, order=order) return order
def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, payment_provider: BasePaymentProvider, locale: str = None, address: int = None): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee exp_by_date = now_dt + timedelta( days=event.settings.get('payment_term_days', as_type=int)) if event.settings.get('payment_term_weekdays'): if exp_by_date.weekday() == 5: exp_by_date += timedelta(days=2) elif exp_by_date.weekday() == 6: exp_by_date += timedelta(days=1) expires = [exp_by_date] if event.settings.get('payment_term_last'): expires.append( event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create(status=Order.STATUS_PENDING, event=event, email=email, datetime=now_dt, expires=min(expires), locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier) OrderPosition.transform_cart_positions(positions, order) if address is not None: try: addr = InvoiceAddress.objects.get(pk=address) if addr.order is not None: addr.pk = None addr.order = order addr.save() except InvoiceAddress.DoesNotExist: pass order.log_action('pretix.event.order.placed') order_placed.send(event, order=order) return order
def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, payment_provider: BasePaymentProvider, locale: str=None, address: int=None): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee exp_by_date = now_dt + timedelta(days=event.settings.get('payment_term_days', as_type=int)) if event.settings.get('payment_term_weekdays'): if exp_by_date.weekday() == 5: exp_by_date += timedelta(days=2) elif exp_by_date.weekday() == 6: exp_by_date += timedelta(days=1) expires = [exp_by_date] if event.settings.get('payment_term_last'): expires.append(event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create( status=Order.STATUS_PENDING, event=event, email=email, datetime=now_dt, expires=min(expires), locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier ) OrderPosition.transform_cart_positions(positions, order) if address is not None: try: addr = InvoiceAddress.objects.get( pk=address ) if addr.order is not None: addr.pk = None addr.order = order addr.save() except InvoiceAddress.DoesNotExist: pass order.log_action('pretix.event.order.placed') order_placed.send(event, order=order) return order
def place_order(event, user, positions, dt, payment_provider): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee expires = [dt + timedelta(days=event.settings.get('payment_term_days', as_type=int))] if event.settings.get('payment_term_last'): expires.append(event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create( status=Order.STATUS_PENDING, event=event, user=user, datetime=dt, expires=min(expires), total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier, ) OrderPosition.transform_cart_positions(positions, order) order_placed.send(event, order=order) return order
def _create_order(event: Event, email: str, positions: list, dt: datetime, payment_provider: BasePaymentProvider, locale: str=None): total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee expires = [dt + timedelta(days=event.settings.get('payment_term_days', as_type=int))] if event.settings.get('payment_term_last'): expires.append(event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create( status=Order.STATUS_PENDING, event=event, email=email, datetime=dt, expires=min(expires), locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier ) OrderPosition.transform_cart_positions(positions, order) order_placed.send(event, order=order) return order
def create(self, request, *args, **kwargs): serializer = OrderCreateSerializer(data=request.data, context=self.get_serializer_context()) serializer.is_valid(raise_exception=True) with transaction.atomic(): self.perform_create(serializer) order = serializer.instance serializer = OrderSerializer(order, context=serializer.context) order.log_action( 'pretix.event.order.placed', user=request.user if request.user.is_authenticated else None, auth=request.auth, ) order_placed.send(self.request.event, order=order) gen_invoice = invoice_qualified(order) and ( (order.event.settings.get('invoice_generate') == 'True') or (order.event.settings.get('invoice_generate') == 'paid' and order.status == Order.STATUS_PAID) ) and not order.invoices.last() if gen_invoice: generate_invoice(order, trigger_pdf=True) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, payment_provider: BasePaymentProvider, locale: str=None, address: int=None, meta_info: dict=None): from datetime import time total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee tz = pytz.timezone(event.settings.timezone) exp_by_date = now_dt.astimezone(tz) + timedelta(days=event.settings.get('payment_term_days', as_type=int)) exp_by_date = exp_by_date.astimezone(tz).replace(hour=23, minute=59, second=59, microsecond=0) if event.settings.get('payment_term_weekdays'): if exp_by_date.weekday() == 5: exp_by_date += timedelta(days=2) elif exp_by_date.weekday() == 6: exp_by_date += timedelta(days=1) expires = exp_by_date term_last = event.settings.get('payment_term_last', as_type=RelativeDateWrapper) if term_last: if event.has_subevents: term_last = min([ term_last.datetime(se).date() for se in event.subevents.filter(id__in=[p.subevent_id for p in positions]) ]) else: term_last = term_last.datetime(event).date() term_last = make_aware(datetime.combine( term_last, time(hour=23, minute=59, second=59) ), tz) if term_last < expires: expires = term_last with transaction.atomic(): order = Order.objects.create( status=Order.STATUS_PENDING, event=event, email=email, datetime=now_dt, expires=expires, locale=locale, total=total, payment_fee=payment_fee, payment_provider=payment_provider.identifier, meta_info=json.dumps(meta_info or {}), ) if address: if address.order is not None: address.pk = None address.order = order address.save() order._calculate_tax() # Might have changed due to new invoice address order.save() OrderPosition.transform_cart_positions(positions, order) order.log_action('pretix.event.order.placed') order_placed.send(event, order=order) return order
def create(self, request, *args, **kwargs): serializer = OrderCreateSerializer( data=request.data, context=self.get_serializer_context()) serializer.is_valid(raise_exception=True) with transaction.atomic(): self.perform_create(serializer) send_mail = serializer._send_mail order = serializer.instance serializer = OrderSerializer(order, context=serializer.context) order.log_action( 'pretix.event.order.placed', user=request.user if request.user.is_authenticated else None, auth=request.auth, ) order_placed.send(self.request.event, order=order) gen_invoice = invoice_qualified(order) and ( (order.event.settings.get('invoice_generate') == 'True') or (order.event.settings.get('invoice_generate') == 'paid' and order.status == Order.STATUS_PAID)) and not order.invoices.last() invoice = None if gen_invoice: invoice = generate_invoice(order, trigger_pdf=True) if send_mail: payment = order.payments.last() free_flow = (payment and order.total == Decimal('0.00') and order.status == Order.STATUS_PAID and not order.require_approval and payment.provider == "free") if free_flow: email_template = request.event.settings.mail_text_order_free log_entry = 'pretix.event.order.email.order_free' email_attendees = request.event.settings.mail_send_order_free_attendee email_attendees_template = request.event.settings.mail_text_order_free_attendee else: email_template = request.event.settings.mail_text_order_placed log_entry = 'pretix.event.order.email.order_placed' email_attendees = request.event.settings.mail_send_order_placed_attendee email_attendees_template = request.event.settings.mail_text_order_placed_attendee _order_placed_email(request.event, order, payment.payment_provider if payment else None, email_template, log_entry, invoice, payment) if email_attendees: for p in order.positions.all(): if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email: _order_placed_email_attendee(request.event, order, p, email_attendees_template, log_entry) if not free_flow and order.status == Order.STATUS_PAID and payment: payment._send_paid_mail(invoice, None, '') if self.request.event.settings.mail_send_order_paid_attendee: for p in order.positions.all(): if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email: payment._send_paid_mail_attendee(p, None) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def import_orders(event: Event, fileid: str, settings: dict, locale: str, user) -> None: # TODO: quotacheck? cf = CachedFile.objects.get(id=fileid) user = User.objects.get(pk=user) with language(locale, event.settings.region): cols = get_all_columns(event) parsed = parse_csv(cf.file) orders = [] order = None data = [] # Run validation for i, record in enumerate(parsed): if not any(record.values()): continue values = {} for c in cols: val = c.resolve(settings, record) if isinstance(val, str): val = val.strip() try: values[c.identifier] = c.clean(val, values) except ValidationError as e: raise DataImportError( _('Error while importing value "{value}" for column "{column}" in line "{line}": {message}' ).format(value=val if val is not None else '', column=c.verbose_name, line=i + 1, message=e.message)) data.append(values) # Prepare model objects. Yes, this might consume lots of RAM, but allows us to make the actual SQL transaction # shorter. We'll see what works better in reality… for i, record in enumerate(data): try: if order is None or settings['orders'] == 'many': order = Order( event=event, testmode=settings['testmode'], ) order.meta_info = {} order._positions = [] order._address = InvoiceAddress() order._address.name_parts = { '_scheme': event.settings.name_scheme } orders.append(order) position = OrderPosition(positionid=len(order._positions) + 1) position.attendee_name_parts = { '_scheme': event.settings.name_scheme } position.meta_info = {} order._positions.append(position) position.assign_pseudonymization_id() for c in cols: c.assign(record.get(c.identifier), order, position, order._address) except ImportError as e: raise ImportError( _('Invalid data in row {row}: {message}').format( row=i, message=str(e))) # quota check? with event.lock(): with transaction.atomic(): save_transactions = [] for o in orders: o.total = sum([c.price for c in o._positions ]) # currently no support for fees if o.total == Decimal('0.00'): o.status = Order.STATUS_PAID o.save() OrderPayment.objects.create( local_id=1, order=o, amount=Decimal('0.00'), provider='free', info='{}', payment_date=now(), state=OrderPayment.PAYMENT_STATE_CONFIRMED) elif settings['status'] == 'paid': o.status = Order.STATUS_PAID o.save() OrderPayment.objects.create( local_id=1, order=o, amount=o.total, provider='manual', info='{}', payment_date=now(), state=OrderPayment.PAYMENT_STATE_CONFIRMED) else: o.status = Order.STATUS_PENDING o.save() for p in o._positions: p.order = o p.save() o._address.order = o o._address.save() for c in cols: c.save(o) o.log_action('pretix.event.order.placed', user=user, data={'source': 'import'}) save_transactions += o.create_transactions( is_new=True, fees=[], positions=o._positions, save=False) Transaction.objects.bulk_create(save_transactions) for o in orders: with language(o.locale, event.settings.region): order_placed.send(event, order=o) if o.status == Order.STATUS_PAID: order_paid.send(event, order=o) gen_invoice = invoice_qualified(o) and ( (event.settings.get('invoice_generate') == 'True') or (event.settings.get('invoice_generate') == 'paid' and o.status == Order.STATUS_PAID)) and not o.invoices.last() if gen_invoice: generate_invoice(o, trigger_pdf=True) cf.delete()
def schedule_second_dose(self, event, op): op = OrderPosition.objects.select_related("item", "variation", "subevent", "order").get(pk=op) if LinkedOrderPosition.objects.filter(base_position=op).exists(): return itemconf = op.item.vacc_autosched_config earliest_date = make_aware( datetime.combine( op.subevent.date_from.astimezone(event.timezone).date() + timedelta(days=itemconf.days), op.subevent.date_from.astimezone(event.timezone).time(), ), event.timezone, ) target_event = itemconf.event or event possible_items = [ n for n in target_event.items.all() if (n.internal_name or str(n.name)) == ( op.item.internal_name or str(op.item.name)) ] if len(possible_items) != 1: op.order.log_action( "pretix_vacc_autosched.failed", data={ "reason": _("No product found"), "position": op.pk, }, ) return target_item = possible_items[0] if op.variation or target_item.variations.exists(): possible_variations = [ n for n in target_item.variations.all() if str(n.value) == ( str(op.variation.value) if op.variation else None) ] if len(possible_variations) != 1: op.order.log_action( "pretix_vacc_autosched.failed", data={ "reason": _("No product variation found"), "position": op.pk, }, ) return target_var = possible_variations[0] else: target_var = None for i in range(100): # max number of subevents to check subevent = (target_event.subevents.filter( date_from__gte=earliest_date, ).order_by("date_from").first()) if not subevent: op.order.log_action( "pretix_vacc_autosched.failed", data={ "reason": _("No available time slot found"), "position": op.pk, }, ) return try: with target_event.lock(), transaction.atomic(): avcode, avnr = target_item.check_quotas(subevent=subevent, fail_on_no_quotas=True) if avcode != Quota.AVAILABILITY_OK: # sold out, look for next one earliest_date += timedelta(minutes=1) continue childorder = Order.objects.create( event=target_event, status=Order.STATUS_PAID, require_approval=False, testmode=op.order.testmode, email=op.order.email, locale=op.order.locale, expires=now() + timedelta(days=30), total=Decimal("0.00"), expiry_reminder_sent=True, sales_channel=op.order.sales_channel, comment="Auto-generated through scheduling from order {}". format(op.order.code), meta_info=op.order.meta_info, ) op.order.log_action( "pretix_vacc_autosched.scheduled", data={ "position": op.pk, "event": target_event.pk, "event_slug": target_event.slug, "order": childorder.code, }, ) childorder.log_action( "pretix_vacc_autosched.created", data={ "event": event.pk, "event_slug": event.slug, "order": op.order.code, }, ) childorder.log_action("pretix.event.order.placed", data={"source": "vacc_autosched"}) childpos = childorder.positions.create( positionid=1, tax_rate=Decimal("0.00"), tax_rule=None, tax_value=Decimal("0.00"), subevent=subevent, item=target_item, variation=target_var, price=Decimal("0.00"), attendee_name_cached=op.attendee_name_cached, attendee_name_parts=op.attendee_name_parts, attendee_email=op.attendee_email, company=op.company, street=op.street, zipcode=op.zipcode, city=op.city, country=op.country, state=op.state, addon_to=None, voucher=None, meta_info=op.meta_info, ) for answ in op.answers.all(): q = childorder.event.questions.filter( identifier=answ.question.identifier).first() if not q: continue childansw = childpos.answers.create(question=q, answer=answ.answer, file=answ.file) if answ.options.all(): childopts = list( q.options.filter(identifier__in=[ o.identifier for o in answ.options.all() ])) if childopts: childansw.options.add(*childopts) LinkedOrderPosition.objects.create(base_position=op, child_position=childpos) order_placed.send(event, order=childorder) order_paid.send(event, order=childorder) if event.settings.vacc_autosched_mail: with language(childorder.locale, target_event.settings.region): email_template = event.settings.vacc_autosched_body email_subject = str(event.settings.vacc_autosched_subject) email_context = get_email_context(event=childorder.event, order=childorder) email_context["scheduled_datetime"] = date_format( subevent.date_from.astimezone(event.timezone), "SHORT_DATETIME_FORMAT", ) try: childorder.send_mail( email_subject, email_template, email_context, "pretix.event.order.email.order_placed", attach_tickets=True, attach_ical=target_event.settings.mail_attach_ical, ) except SendMailException: logger.exception( "Order approved email could not be sent") except LockTimeoutException: self.retry() return op.order.log_action( "pretix_vacc_autosched.failed", data={ "reason": _("No available time slot found"), "position": op.pk, }, ) return
def book_second_dose(*, op, item, variation, subevent, original_event): event = item.event with event.lock(), transaction.atomic(): avcode, avnr = item.check_quotas(subevent=subevent, fail_on_no_quotas=True) if avcode != Quota.AVAILABILITY_OK: logger.info( f"SECOND DOSE: cannot use slot {subevent.pk}, sold out") # sold out, look for next one return childorder = Order.objects.create( event=event, status=Order.STATUS_PAID, require_approval=False, testmode=op.order.testmode, email=op.order.email, phone=op.order.phone, locale=op.order.locale, expires=now() + timedelta(days=30), total=Decimal("0.00"), expiry_reminder_sent=True, sales_channel=op.order.sales_channel, comment="Auto-generated through scheduling from order {}".format( op.order.code), meta_info=op.order.meta_info, ) op.order.log_action( "pretix_vacc_autosched.scheduled", data={ "position": op.pk, "event": event.pk, "event_slug": event.slug, "order": childorder.code, }, ) childorder.log_action( "pretix_vacc_autosched.created", data={ "event": original_event.pk, "event_slug": original_event.slug, "order": op.order.code, }, ) childorder.log_action("pretix.event.order.placed", data={"source": "vacc_autosched"}) childpos = childorder.positions.create( positionid=1, tax_rate=Decimal("0.00"), tax_rule=None, tax_value=Decimal("0.00"), subevent=subevent, item=item, variation=variation, price=Decimal("0.00"), attendee_name_cached=op.attendee_name_cached, attendee_name_parts=op.attendee_name_parts, attendee_email=op.attendee_email, company=op.company, street=op.street, zipcode=op.zipcode, city=op.city, country=op.country, state=op.state, addon_to=None, voucher=None, meta_info=op.meta_info, ) for answ in op.answers.all(): q = childorder.event.questions.filter( identifier=answ.question.identifier).first() if not q: continue childansw = childpos.answers.create(question=q, answer=answ.answer, file=answ.file) if answ.options.all(): childopts = list( q.options.filter(identifier__in=[ o.identifier for o in answ.options.all() ])) if childopts: childansw.options.add(*childopts) LinkedOrderPosition.objects.create(base_position=op, child_position=childpos) childorder.create_transactions(is_new=True) order_placed.send(event, order=childorder) order_paid.send(event, order=childorder) if original_event.settings.vacc_autosched_mail: with language(childorder.locale, original_event.settings.region): email_template = original_event.settings.vacc_autosched_body email_subject = str(original_event.settings.vacc_autosched_subject) email_context = get_email_context(event=childorder.event, order=childorder) email_context["scheduled_datetime"] = date_format( subevent.date_from.astimezone(original_event.timezone), "SHORT_DATETIME_FORMAT", ) try: childorder.send_mail( email_subject, email_template, email_context, "pretix.event.order.email.order_placed", attach_tickets=True, attach_ical=event.settings.mail_attach_ical, ) except SendMailException: logger.exception("Order approved email could not be sent") if (original_event.settings.vacc_autosched_sms and can_use_juvare_api(original_event) and childorder.phone): with language(childorder.locale, original_event.settings.region): from pretix_juvare_notify.tasks import juvare_send_text template = original_event.settings.vacc_autosched_sms_text context = get_email_context(event=childorder.event, order=childorder) context["scheduled_datetime"] = date_format( subevent.date_from.astimezone(original_event.timezone), "SHORT_DATETIME_FORMAT", ) message = str(template).format_map(TolerantDict(context)) juvare_send_text.apply_async( kwargs={ "text": message, "to": childorder.phone, "event": original_event.pk, }) logger.info(f"SECOND DOSE: done, created order {childorder.code}") return childorder