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