commit
75d96ce1c1
5 changed files with 147 additions and 20 deletions
|
@ -30,7 +30,7 @@ class ItemController(object):
|
||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
def items_purchased(self, category=None):
|
def _items(self, cart_status, category=None):
|
||||||
''' Aggregates the items that this user has purchased.
|
''' Aggregates the items that this user has purchased.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
@ -45,7 +45,7 @@ class ItemController(object):
|
||||||
|
|
||||||
in_cart = (
|
in_cart = (
|
||||||
Q(productitem__cart__user=self.user) &
|
Q(productitem__cart__user=self.user) &
|
||||||
Q(productitem__cart__status=commerce.Cart.STATUS_PAID)
|
Q(productitem__cart__status=cart_status)
|
||||||
)
|
)
|
||||||
|
|
||||||
quantities_in_cart = When(
|
quantities_in_cart = When(
|
||||||
|
@ -72,6 +72,20 @@ class ItemController(object):
|
||||||
out.append(ProductAndQuantity(prod, prod.quantity))
|
out.append(ProductAndQuantity(prod, prod.quantity))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def items_purchased(self, category=None):
|
||||||
|
''' Aggregates the items that this user has purchased.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
category (Optional[models.inventory.Category]): the category
|
||||||
|
of items to restrict to.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[ProductAndQuantity, ...]: A list of product-quantity pairs,
|
||||||
|
aggregating like products from across multiple invoices.
|
||||||
|
|
||||||
|
'''
|
||||||
|
return self._items(commerce.Cart.STATUS_PAID)
|
||||||
|
|
||||||
def items_pending(self):
|
def items_pending(self):
|
||||||
''' Gets all of the items that the user has reserved, but has not yet
|
''' Gets all of the items that the user has reserved, but has not yet
|
||||||
paid for.
|
paid for.
|
||||||
|
@ -82,14 +96,16 @@ class ItemController(object):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
all_items = commerce.ProductItem.objects.filter(
|
return self._items(commerce.Cart.STATUS_ACTIVE)
|
||||||
cart__user=self.user,
|
|
||||||
cart__status=commerce.Cart.STATUS_ACTIVE,
|
def items_released(self):
|
||||||
).select_related(
|
''' Gets all of the items that the user previously paid for, but has
|
||||||
"product",
|
since refunded.
|
||||||
"product__category",
|
|
||||||
).order_by(
|
Returns:
|
||||||
"product__category__order",
|
[ProductAndQuantity, ...]: A list of product-quantity pairs for the
|
||||||
"product__order",
|
items that the user has not yet paid for.
|
||||||
)
|
|
||||||
return all_items
|
'''
|
||||||
|
|
||||||
|
return self._items(commerce.Cart.STATUS_RELEASED)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from registrasion.controllers.product import ProductController
|
||||||
from registrasion.models import commerce
|
from registrasion.models import commerce
|
||||||
from registrasion.models import inventory
|
from registrasion.models import inventory
|
||||||
|
|
||||||
|
@ -347,3 +348,33 @@ class VoucherForm(forms.Form):
|
||||||
help_text="If you have a voucher code, enter it here",
|
help_text="If you have a voucher code, enter it here",
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def staff_products_form_factory(user):
|
||||||
|
''' Creates a StaffProductsForm that restricts the available products to
|
||||||
|
those that are available to a user. '''
|
||||||
|
|
||||||
|
products = inventory.Product.objects.all()
|
||||||
|
products = ProductController.available_products(user, products=products)
|
||||||
|
|
||||||
|
product_ids = [product.id for product in products]
|
||||||
|
product_set = inventory.Product.objects.filter(id__in=product_ids)
|
||||||
|
|
||||||
|
class StaffProductsForm(forms.Form):
|
||||||
|
''' Form for allowing staff to add an item to a user's cart. '''
|
||||||
|
|
||||||
|
product = forms.ModelChoiceField(
|
||||||
|
widget=forms.Select,
|
||||||
|
queryset=product_set,
|
||||||
|
)
|
||||||
|
|
||||||
|
quantity = forms.IntegerField(
|
||||||
|
min_value=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
return StaffProductsForm
|
||||||
|
|
||||||
|
def staff_products_formset_factory(user):
|
||||||
|
''' Creates a formset of StaffProductsForm for the given user. '''
|
||||||
|
form_type = staff_products_form_factory(user)
|
||||||
|
return forms.formset_factory(form_type)
|
||||||
|
|
|
@ -236,17 +236,17 @@ def credit_notes(request, form):
|
||||||
|
|
||||||
|
|
||||||
@report_view("Attendee", form_type=forms.UserIdForm)
|
@report_view("Attendee", form_type=forms.UserIdForm)
|
||||||
def attendee(request, form, attendee_id=None):
|
def attendee(request, form, user_id=None):
|
||||||
''' Returns a list of all manifested attendees if no attendee is specified,
|
''' Returns a list of all manifested attendees if no attendee is specified,
|
||||||
else displays the attendee manifest. '''
|
else displays the attendee manifest. '''
|
||||||
|
|
||||||
if attendee_id is None and not form.has_changed():
|
if user_id is None and not form.has_changed():
|
||||||
return attendee_list(request)
|
return attendee_list(request)
|
||||||
|
|
||||||
if form.cleaned_data["user"] is not None:
|
if form.cleaned_data["user"] is not None:
|
||||||
attendee_id = form.cleaned_data["user"]
|
user_id = form.cleaned_data["user"]
|
||||||
|
|
||||||
attendee = people.Attendee.objects.get(id=attendee_id)
|
attendee = people.Attendee.objects.get(user__id=user_id)
|
||||||
|
|
||||||
reports = []
|
reports = []
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ def attendee_list(request):
|
||||||
|
|
||||||
for attendee in attendees:
|
for attendee in attendees:
|
||||||
data.append([
|
data.append([
|
||||||
attendee.id,
|
attendee.user.id,
|
||||||
attendee.attendeeprofilebase.attendee_name(),
|
attendee.attendeeprofilebase.attendee_name(),
|
||||||
attendee.user.email,
|
attendee.user.email,
|
||||||
attendee.has_registered > 0,
|
attendee.has_registered > 0,
|
||||||
|
|
|
@ -13,12 +13,15 @@ from .views import (
|
||||||
invoice_access,
|
invoice_access,
|
||||||
edit_profile,
|
edit_profile,
|
||||||
guided_registration,
|
guided_registration,
|
||||||
|
amend_registration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
public = [
|
public = [
|
||||||
|
url(r"^amend/([0-9]+)$", amend_registration, name="amend_registration"),
|
||||||
url(r"^category/([0-9]+)$", product_category, name="product_category"),
|
url(r"^category/([0-9]+)$", product_category, name="product_category"),
|
||||||
url(r"^checkout$", checkout, name="checkout"),
|
url(r"^checkout$", checkout, name="checkout"),
|
||||||
|
url(r"^checkout/([0-9]+)$", checkout, name="checkout"),
|
||||||
url(r"^credit_note/([0-9]+)$", credit_note, name="credit_note"),
|
url(r"^credit_note/([0-9]+)$", credit_note, name="credit_note"),
|
||||||
url(r"^invoice/([0-9]+)$", invoice, name="invoice"),
|
url(r"^invoice/([0-9]+)$", invoice, name="invoice"),
|
||||||
url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", invoice, name="invoice"),
|
url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", invoice, name="invoice"),
|
||||||
|
|
|
@ -10,6 +10,7 @@ from registrasion.controllers.cart import CartController
|
||||||
from registrasion.controllers.credit_note import CreditNoteController
|
from registrasion.controllers.credit_note import CreditNoteController
|
||||||
from registrasion.controllers.discount import DiscountController
|
from registrasion.controllers.discount import DiscountController
|
||||||
from registrasion.controllers.invoice import InvoiceController
|
from registrasion.controllers.invoice import InvoiceController
|
||||||
|
from registrasion.controllers.item import ItemController
|
||||||
from registrasion.controllers.product import ProductController
|
from registrasion.controllers.product import ProductController
|
||||||
from registrasion.exceptions import CartValidationError
|
from registrasion.exceptions import CartValidationError
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ from collections import namedtuple
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
@ -504,7 +506,7 @@ def _handle_voucher(request, prefix):
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def checkout(request):
|
def checkout(request, user_id=None):
|
||||||
''' Runs the checkout process for the current cart.
|
''' Runs the checkout process for the current cart.
|
||||||
|
|
||||||
If the query string contains ``fix_errors=true``, Registrasion will attempt
|
If the query string contains ``fix_errors=true``, Registrasion will attempt
|
||||||
|
@ -512,6 +514,10 @@ def checkout(request):
|
||||||
cancelling expired discounts and vouchers, and removing any unavailable
|
cancelling expired discounts and vouchers, and removing any unavailable
|
||||||
products.
|
products.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
user_id (castable to int):
|
||||||
|
If the requesting user is staff, then the user ID can be used to
|
||||||
|
run checkout for another user.
|
||||||
Returns:
|
Returns:
|
||||||
render or redirect:
|
render or redirect:
|
||||||
If the invoice is generated successfully, or there's already a
|
If the invoice is generated successfully, or there's already a
|
||||||
|
@ -525,7 +531,15 @@ def checkout(request):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
current_cart = CartController.for_user(request.user)
|
if user_id is not None:
|
||||||
|
if request.user.is_staff:
|
||||||
|
user = User.objects.get(id=int(user_id))
|
||||||
|
else:
|
||||||
|
raise Http404()
|
||||||
|
else:
|
||||||
|
user = request.user
|
||||||
|
|
||||||
|
current_cart = CartController.for_user(user)
|
||||||
|
|
||||||
if "fix_errors" in request.GET and request.GET["fix_errors"] == "true":
|
if "fix_errors" in request.GET and request.GET["fix_errors"] == "true":
|
||||||
current_cart.fix_simple_errors()
|
current_cart.fix_simple_errors()
|
||||||
|
@ -790,3 +804,66 @@ def credit_note(request, note_id, access_code=None):
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "registrasion/credit_note.html", data)
|
return render(request, "registrasion/credit_note.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
@user_passes_test(_staff_only)
|
||||||
|
def amend_registration(request, user_id):
|
||||||
|
''' Allows staff to amend a user's current registration cart, and etc etc.
|
||||||
|
'''
|
||||||
|
|
||||||
|
user = User.objects.get(id=int(user_id))
|
||||||
|
current_cart = CartController.for_user(user)
|
||||||
|
|
||||||
|
items = commerce.ProductItem.objects.filter(
|
||||||
|
cart=current_cart.cart,
|
||||||
|
).select_related("product")
|
||||||
|
initial = [{"product": i.product, "quantity": i.quantity} for i in items]
|
||||||
|
|
||||||
|
StaffProductsFormSet = forms.staff_products_formset_factory(user)
|
||||||
|
formset = StaffProductsFormSet(
|
||||||
|
request.POST or None,
|
||||||
|
initial=initial,
|
||||||
|
prefix="products",
|
||||||
|
)
|
||||||
|
|
||||||
|
voucher_form = forms.VoucherForm(
|
||||||
|
request.POST or None,
|
||||||
|
prefix="voucher",
|
||||||
|
)
|
||||||
|
|
||||||
|
if request.POST and formset.is_valid():
|
||||||
|
|
||||||
|
pq = [
|
||||||
|
(f.cleaned_data["product"], f.cleaned_data["quantity"])
|
||||||
|
for f in formset
|
||||||
|
if "product" in f.cleaned_data and
|
||||||
|
f.cleaned_data["product"] is not None
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_cart.set_quantities(pq)
|
||||||
|
return redirect(amend_registration, user_id)
|
||||||
|
except ValidationError as ve:
|
||||||
|
for ve_field in ve.error_list:
|
||||||
|
product, message = ve_field.message
|
||||||
|
for form in formset:
|
||||||
|
if form.cleaned_data["product"] == product:
|
||||||
|
form.add_error("quantity", message)
|
||||||
|
|
||||||
|
if request.POST and voucher_form.is_valid():
|
||||||
|
try:
|
||||||
|
current_cart.apply_voucher(voucher_form.cleaned_data["voucher"])
|
||||||
|
return redirect(amend_registration, user_id)
|
||||||
|
except ValidationError as ve:
|
||||||
|
voucher_form.add_error(None, ve)
|
||||||
|
|
||||||
|
ic = ItemController(user)
|
||||||
|
data = {
|
||||||
|
"user": user,
|
||||||
|
"paid": ic.items_purchased(),
|
||||||
|
"cancelled": ic.items_released(),
|
||||||
|
"form": formset,
|
||||||
|
"voucher_form": voucher_form,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "registrasion/amend_registration.html", data)
|
||||||
|
|
Loading…
Reference in a new issue