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…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer