commit
75d96ce1c1
5 changed files with 147 additions and 20 deletions
|
@ -30,7 +30,7 @@ class ItemController(object):
|
|||
def __init__(self, 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.
|
||||
|
||||
Arguments:
|
||||
|
@ -45,7 +45,7 @@ class ItemController(object):
|
|||
|
||||
in_cart = (
|
||||
Q(productitem__cart__user=self.user) &
|
||||
Q(productitem__cart__status=commerce.Cart.STATUS_PAID)
|
||||
Q(productitem__cart__status=cart_status)
|
||||
)
|
||||
|
||||
quantities_in_cart = When(
|
||||
|
@ -72,6 +72,20 @@ class ItemController(object):
|
|||
out.append(ProductAndQuantity(prod, prod.quantity))
|
||||
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):
|
||||
''' Gets all of the items that the user has reserved, but has not yet
|
||||
paid for.
|
||||
|
@ -82,14 +96,16 @@ class ItemController(object):
|
|||
|
||||
'''
|
||||
|
||||
all_items = commerce.ProductItem.objects.filter(
|
||||
cart__user=self.user,
|
||||
cart__status=commerce.Cart.STATUS_ACTIVE,
|
||||
).select_related(
|
||||
"product",
|
||||
"product__category",
|
||||
).order_by(
|
||||
"product__category__order",
|
||||
"product__order",
|
||||
)
|
||||
return all_items
|
||||
return self._items(commerce.Cart.STATUS_ACTIVE)
|
||||
|
||||
def items_released(self):
|
||||
''' Gets all of the items that the user previously paid for, but has
|
||||
since refunded.
|
||||
|
||||
Returns:
|
||||
[ProductAndQuantity, ...]: A list of product-quantity pairs for the
|
||||
items that the user has not yet paid for.
|
||||
|
||||
'''
|
||||
|
||||
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 inventory
|
||||
|
||||
|
@ -347,3 +348,33 @@ class VoucherForm(forms.Form):
|
|||
help_text="If you have a voucher code, enter it here",
|
||||
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)
|
||||
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,
|
||||
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)
|
||||
|
||||
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 = []
|
||||
|
||||
|
@ -349,7 +349,7 @@ def attendee_list(request):
|
|||
|
||||
for attendee in attendees:
|
||||
data.append([
|
||||
attendee.id,
|
||||
attendee.user.id,
|
||||
attendee.attendeeprofilebase.attendee_name(),
|
||||
attendee.user.email,
|
||||
attendee.has_registered > 0,
|
||||
|
|
|
@ -13,12 +13,15 @@ from .views import (
|
|||
invoice_access,
|
||||
edit_profile,
|
||||
guided_registration,
|
||||
amend_registration,
|
||||
)
|
||||
|
||||
|
||||
public = [
|
||||
url(r"^amend/([0-9]+)$", amend_registration, name="amend_registration"),
|
||||
url(r"^category/([0-9]+)$", product_category, name="product_category"),
|
||||
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"^invoice/([0-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.discount import DiscountController
|
||||
from registrasion.controllers.invoice import InvoiceController
|
||||
from registrasion.controllers.item import ItemController
|
||||
from registrasion.controllers.product import ProductController
|
||||
from registrasion.exceptions import CartValidationError
|
||||
|
||||
|
@ -18,6 +19,7 @@ from collections import namedtuple
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -504,7 +506,7 @@ def _handle_voucher(request, prefix):
|
|||
|
||||
|
||||
@login_required
|
||||
def checkout(request):
|
||||
def checkout(request, user_id=None):
|
||||
''' Runs the checkout process for the current cart.
|
||||
|
||||
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
|
||||
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:
|
||||
render or redirect:
|
||||
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":
|
||||
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)
|
||||
|
||||
|
||||
@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