from registrasion import forms from registrasion import models as rego from registrasion.controllers import discount from registrasion.controllers.cart import CartController from registrasion.controllers.invoice import InvoiceController from registrasion.controllers.product import ProductController from django.contrib.auth.decorators import login_required from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ValidationError from django.db import transaction from django.shortcuts import redirect from django.shortcuts import render @login_required def guided_registration(request, page_id=0): ''' Goes through the registration process in order, making sure user sees all valid categories. WORK IN PROGRESS: the finalised version of this view will allow grouping of categories into a specific page. Currently, it just goes through each category one by one ''' dashboard = redirect("dashboard") next_step = redirect("guided_registration") attendee = rego.Attendee.get_instance(request.user) if attendee.completed_registration: return dashboard # Step 1: Fill in a badge profile = rego.BadgeAndProfile.get_instance(attendee) if profile is None: ret = edit_profile(request) profile_new = rego.BadgeAndProfile.get_instance(attendee) if profile_new is None: # No new profile was created return ret else: return next_step # Step 2: Go through each of the categories in order category = attendee.highest_complete_category # Get the next category cats = rego.Category.objects cats = cats.filter(id__gt=category).order_by("order") if len(cats) == 0: # We've filled in every category attendee.completed_registration = True attendee.save() return dashboard ret = product_category(request, cats[0].id) attendee_new = rego.Attendee.get_instance(request.user) if attendee_new.highest_complete_category == category: # We've not yet completed this category return ret else: return next_step @login_required def edit_profile(request): attendee = rego.Attendee.get_instance(request.user) try: profile = rego.BadgeAndProfile.objects.get(attendee=attendee) except ObjectDoesNotExist: profile = None form = forms.ProfileForm(request.POST or None, instance=profile) if request.POST and form.is_valid(): form.instance.attendee = attendee form.save() data = { "form": form, } return render(request, "profile_form.html", data) @login_required def product_category(request, category_id): ''' Registration selections form for a specific category of items. ''' PRODUCTS_FORM_PREFIX = "products" VOUCHERS_FORM_PREFIX = "vouchers" category_id = int(category_id) # Routing is [0-9]+ category = rego.Category.objects.get(pk=category_id) current_cart = CartController.for_user(request.user) attendee = rego.Attendee.get_instance(request.user) products = rego.Product.objects.filter(category=category) products = products.order_by("order") products = ProductController.available_products( request.user, products=products, ) ProductsForm = forms.ProductsForm(products) if request.method == "POST": cat_form = ProductsForm( request.POST, request.FILES, prefix=PRODUCTS_FORM_PREFIX) voucher_form = forms.VoucherForm( request.POST, prefix=VOUCHERS_FORM_PREFIX) if (voucher_form.is_valid() and voucher_form.cleaned_data["voucher"].strip()): # Apply voucher # leave voucher = voucher_form.cleaned_data["voucher"] try: current_cart.apply_voucher(voucher) except Exception as e: voucher_form.add_error("voucher", e) # Re-visit current page. elif cat_form.is_valid(): try: handle_valid_cat_form(cat_form, current_cart) except ValidationError: pass # If category is required, the user must have at least one # in an active+valid cart if category.required: carts = rego.Cart.reserved_carts() carts = carts.filter(user=request.user) items = rego.ProductItem.objects.filter( product__category=category, cart=carts, ) if len(items) == 0: cat_form.add_error( None, "You must have at least one item from this category", ) if not cat_form.errors: if category_id > attendee.highest_complete_category: attendee.highest_complete_category = category_id attendee.save() return redirect("dashboard") else: # Create initial data for each of products in category items = rego.ProductItem.objects.filter( product__category=category, cart=current_cart.cart, ) quantities = [] for product in products: # Only add items that are enabled. try: quantity = items.get(product=product).quantity except ObjectDoesNotExist: quantity = 0 quantities.append((product, quantity)) cat_form = ProductsForm( prefix=PRODUCTS_FORM_PREFIX, product_quantities=quantities, ) voucher_form = forms.VoucherForm(prefix=VOUCHERS_FORM_PREFIX) discounts = discount.available_discounts(request.user, [], products) data = { "category": category, "discounts": discounts, "form": cat_form, "voucher_form": voucher_form, } return render(request, "product_category.html", data) @transaction.atomic def handle_valid_cat_form(cat_form, current_cart): for product_id, quantity, field_name in cat_form.product_quantities(): product = rego.Product.objects.get(pk=product_id) try: current_cart.set_quantity(product, quantity, batched=True) except ValidationError as ve: cat_form.add_error(field_name, ve) if cat_form.errors: raise ValidationError("Cannot add that stuff") current_cart.end_batch() @login_required def checkout(request): ''' Runs checkout for the current cart of items, ideally generating an invoice. ''' current_cart = CartController.for_user(request.user) current_invoice = InvoiceController.for_cart(current_cart.cart) return redirect("invoice", current_invoice.invoice.id) @login_required def invoice(request, invoice_id): ''' Displays an invoice for a given invoice id. ''' invoice_id = int(invoice_id) inv = rego.Invoice.objects.get(pk=invoice_id) current_invoice = InvoiceController(inv) data = { "invoice": current_invoice.invoice, } return render(request, "invoice.html", data) @login_required def pay_invoice(request, invoice_id): ''' Marks the invoice with the given invoice id as paid. WORK IN PROGRESS FUNCTION. Must be replaced with real payment workflow. ''' invoice_id = int(invoice_id) inv = rego.Invoice.objects.get(pk=invoice_id) current_invoice = InvoiceController(inv) if not inv.paid and current_invoice.is_valid(): current_invoice.pay("Demo invoice payment", inv.value) return redirect("invoice", current_invoice.invoice.id)