Changeset - 4cdbdb71ceee
[Not reviewed]
0 6 0
Christopher Neugebauer - 8 years ago 2016-04-25 07:37:33
chrisjrn@gmail.com
flake8 fixes
6 files changed with 20 insertions and 16 deletions:
0 comments (0 inline, 0 general)
registrasion/controllers/discount.py
Show inline comments
...
 
@@ -50,49 +50,49 @@ def available_discounts(user, categories, products):
 

	
 
    # The set of all potential discounts
 
    potential_discounts = set(itertools.chain(
 
        product_discounts,
 
        all_category_discounts,
 
    ))
 

	
 
    discounts = []
 

	
 
    # Markers so that we don't need to evaluate given conditions more than once
 
    accepted_discounts = set()
 
    failed_discounts = set()
 

	
 
    for discount in potential_discounts:
 
        real_discount = conditions.DiscountBase.objects.get_subclass(
 
            pk=discount.discount.pk,
 
        )
 
        cond = ConditionController.for_condition(real_discount)
 

	
 
        # Count the past uses of the given discount item.
 
        # If this user has exceeded the limit for the clause, this clause
 
        # is not available any more.
 
        past_uses = commerce.DiscountItem.objects.filter(
 
            cart__user=user,
 
            cart__status=commerce.Cart.STATUS_PAID, # Only past carts count
 
            cart__status=commerce.Cart.STATUS_PAID,  # Only past carts count
 
            discount=real_discount,
 
        )
 
        agg = past_uses.aggregate(Sum("quantity"))
 
        past_use_count = agg["quantity__sum"]
 
        if past_use_count is None:
 
            past_use_count = 0
 

	
 
        if past_use_count >= discount.quantity:
 
            # This clause has exceeded its use count
 
            pass
 
        elif real_discount not in failed_discounts:
 
            # This clause is still available
 
            if real_discount in accepted_discounts or cond.is_met(user):
 
                # This clause is valid for this user
 
                discounts.append(DiscountAndQuantity(
 
                    discount=real_discount,
 
                    clause=discount,
 
                    quantity=discount.quantity - past_use_count,
 
                ))
 
                accepted_discounts.add(real_discount)
 
            else:
 
                # This clause is not valid for this user
 
                failed_discounts.add(real_discount)
 
    return discounts
registrasion/templatetags/registrasion_tags.py
Show inline comments
 
from registrasion.models import commerce
 
from registrasion.models import inventory
 
from registrasion.controllers.category import CategoryController
 

	
 
from collections import namedtuple
 
from django import template
 
from django.db.models import Sum
 

	
 
register = template.Library()
 

	
 
_ProductAndQuantity = namedtuple("ProductAndQuantity", ["product", "quantity"])
 

	
 

	
 
class ProductAndQuantity(_ProductAndQuantity):
 
    ''' Class that holds a product and a quantity.
 

	
 
    Attributes:
 
        product (models.inventory.Product)
 

	
 
        quantity (int)
 

	
 
    '''
 
    pass
 

	
 

	
 
@register.assignment_tag(takes_context=True)
 
def available_categories(context):
 
    ''' Gets all of the currently available products.
 

	
 
    Returns:
 
        [models.inventory.Category, ...]: A list of all of the categories that
 
            have Products that the current user can reserve.
 

	
 
    '''
 
    return CategoryController.available_categories(context.request.user)
 

	
 

	
registrasion/tests/test_cart.py
Show inline comments
...
 
@@ -5,78 +5,82 @@ from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.exceptions import ValidationError
 
from django.core.management import call_command
 
from django.test import TestCase
 

	
 
from registrasion.models import commerce
 
from registrasion.models import conditions
 
from registrasion.models import inventory
 
from registrasion.models import people
 
from registrasion.controllers.product import ProductController
 

	
 
from controller_helpers import TestingCartController
 
from patch_datetime import SetTimeMixin
 

	
 
UTC = pytz.timezone('UTC')
 

	
 

	
 
class RegistrationCartTestCase(SetTimeMixin, TestCase):
 

	
 
    def setUp(self):
 
        super(RegistrationCartTestCase, self).setUp()
 

	
 
    def tearDown(self):
 
        if False:
 
        if True:
 
            # If you're seeing segfaults in tests, enable this.
 
            call_command('flush', verbosity=0, interactive=False,
 
                             reset_sequences=False,
 
                             allow_cascade=False,
 
                             inhibit_post_migrate=False)
 
            call_command(
 
                'flush',
 
                verbosity=0,
 
                interactive=False,
 
                reset_sequences=False,
 
                allow_cascade=False,
 
                inhibit_post_migrate=False
 
            )
 

	
 
        super(RegistrationCartTestCase, self).tearDown()
 

	
 
    @classmethod
 
    def setUpTestData(cls):
 

	
 
        super(RegistrationCartTestCase, cls).setUpTestData()
 

	
 
        cls.USER_1 = User.objects.create_user(
 
            username='testuser',
 
            email='test@example.com',
 
            password='top_secret')
 

	
 
        cls.USER_2 = User.objects.create_user(
 
            username='testuser2',
 
            email='test2@example.com',
 
            password='top_secret')
 

	
 
        attendee1 = people.Attendee.get_instance(cls.USER_1)
 
        profile1 = people.AttendeeProfileBase.objects.create(
 
        people.AttendeeProfileBase.objects.create(
 
            attendee=attendee1,
 
        )
 
        attendee2 = people.Attendee.get_instance(cls.USER_2)
 
        profile2 = people.AttendeeProfileBase.objects.create(
 
        people.AttendeeProfileBase.objects.create(
 
            attendee=attendee2,
 
        )
 

	
 
        cls.RESERVATION = datetime.timedelta(hours=1)
 

	
 
        cls.categories = []
 
        for i in xrange(2):
 
            cat = inventory.Category.objects.create(
 
                name="Category " + str(i + 1),
 
                description="This is a test category",
 
                order=i,
 
                render_type=inventory.Category.RENDER_TYPE_RADIO,
 
                required=False,
 
            )
 
            cls.categories.append(cat)
 

	
 
        cls.CAT_1 = cls.categories[0]
 
        cls.CAT_2 = cls.categories[1]
 

	
 
        cls.products = []
 
        for i in xrange(4):
 
            prod = inventory.Product.objects.create(
 
                name="Product " + str(i + 1),
 
                description="This is a test product.",
registrasion/tests/test_invoice.py
Show inline comments
...
 
@@ -463,49 +463,49 @@ class InvoiceTestCase(RegistrationCartTestCase):
 
            cn.refund()
 

	
 
    def test_money_into_void_invoice_generates_credit_note(self):
 
        invoice = self._invoice_containing_prod_1(1)
 
        invoice.void()
 

	
 
        val = invoice.invoice.value
 

	
 
        invoice.pay("Paying into the void.", val, pre_validate=False)
 
        cn = self._credit_note_for_invoice(invoice.invoice)
 
        self.assertEqual(val, cn.credit_note.value)
 

	
 
    def test_money_into_refunded_invoice_generates_credit_note(self):
 
        invoice = self._invoice_containing_prod_1(1)
 

	
 
        val = invoice.invoice.value
 

	
 
        invoice.pay("Paying the first time.", val)
 
        invoice.refund()
 

	
 
        cnval = val - 1
 
        invoice.pay("Paying into the void.", cnval, pre_validate=False)
 

	
 
        notes = commerce.CreditNote.objects.filter(invoice=invoice.invoice)
 
        notes = sorted(notes, key = lambda note: note.value)
 
        notes = sorted(notes, key=lambda note: note.value)
 

	
 
        self.assertEqual(cnval, notes[0].value)
 
        self.assertEqual(val, notes[1].value)
 

	
 
    def test_money_into_paid_invoice_generates_credit_note(self):
 
        invoice = self._invoice_containing_prod_1(1)
 

	
 
        val = invoice.invoice.value
 

	
 
        invoice.pay("Paying the first time.", val)
 

	
 
        invoice.pay("Paying into the void.", val, pre_validate=False)
 
        cn = self._credit_note_for_invoice(invoice.invoice)
 
        self.assertEqual(val, cn.credit_note.value)
 

	
 
    def test_required_category_constraints_prevent_invoicing(self):
 
        self.CAT_1.required = True
 
        self.CAT_1.save()
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_3, 1)
 

	
 
        # CAT_1 is required, we don't have CAT_1 yet
 
        with self.assertRaises(ValidationError):
registrasion/views.py
Show inline comments
 
import sys
 

	
 
from registrasion import forms
 
from registrasion import util
 
from registrasion.models import commerce
 
from registrasion.models import inventory
 
from registrasion.models import people
 
from registrasion.controllers import discount
 
from registrasion.controllers.cart import CartController
 
from registrasion.controllers.credit_note import CreditNoteController
 
from registrasion.controllers.invoice import InvoiceController
 
from registrasion.controllers.product import ProductController
 
from registrasion.exceptions import CartValidationError
 

	
 
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 import messages
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.exceptions import ValidationError
 
from django.http import Http404
 
from django.shortcuts import get_object_or_404
 
from django.shortcuts import redirect
 
from django.shortcuts import render
 

	
 

	
 
_GuidedRegistrationSection = namedtuple(
 
    "GuidedRegistrationSection",
 
    (
 
        "title",
 
        "discounts",
 
        "description",
 
        "form",
 
    )
 
)
 

	
 

	
 
@util.all_arguments_optional
 
class GuidedRegistrationSection(_GuidedRegistrationSection):
 
    ''' Represents a section of a guided registration page.
 

	
 
    Attributes:
 
        title (str): The title of the section.
 
       title (str): The title of the section.
 

	
 
        discounts ([registrasion.contollers.discount.DiscountAndQuantity, ...]):
 
       discounts ([registrasion.contollers.discount.DiscountAndQuantity, ...]):
 
            A list of discount objects that are available in the section. You
 
            can display ``.clause`` to show what the discount applies to, and
 
            ``.quantity`` to display the number of times that discount can be
 
            applied.
 

	
 
        description (str): A description of the section.
 
       description (str): A description of the section.
 

	
 
        form (forms.Form): A form to display.
 
       form (forms.Form): A form to display.
 
    '''
 
    pass
 

	
 

	
 
def get_form(name):
 
    dot = name.rindex(".")
 
    mod_name, form_name = name[:dot], name[dot + 1:]
 
    __import__(mod_name)
 
    return getattr(sys.modules[mod_name], form_name)
 

	
 

	
 
@login_required
 
def guided_registration(request):
 
    ''' Goes through the registration process in order, making sure user sees
 
    all valid categories.
 

	
 
    The user must be logged in to see this view.
 

	
 
    Returns:
 
        render: Renders ``registrasion/guided_registration.html``,
 
            with the following data::
 

	
 
                {
 
                    "current_step": int(),  # The current step in the
...
 
@@ -548,49 +547,48 @@ def invoice_access(request, access_code):
 

	
 
    If the attendee has multiple invoices, we use the following tie-break:
 

	
 
    - If there's an unpaid invoice, show that, otherwise
 
    - If there's a paid invoice, show the most recent one, otherwise
 
    - Show the most recent invoid of all
 

	
 
    Arguments:
 

	
 
        access_code (castable to int): The access code for the user whose
 
            invoice you want to see.
 

	
 
    Returns:
 
        redirect:
 
            Redirect to the selected invoice for that user.
 

	
 
    Raises:
 
        Http404: If the user has no invoices.
 
    '''
 

	
 
    invoices = commerce.Invoice.objects.filter(
 
        user__attendee__access_code=access_code,
 
    ).order_by("-issue_time")
 

	
 

	
 
    if not invoices:
 
        raise Http404()
 

	
 
    unpaid = invoices.filter(status=commerce.Invoice.STATUS_UNPAID)
 
    paid = invoices.filter(status=commerce.Invoice.STATUS_PAID)
 

	
 
    if unpaid:
 
        invoice = unpaid[0]  # (should only be 1 unpaid invoice?)
 
    elif paid:
 
        invoice = paid[0]  # Most recent paid invoice
 
    else:
 
        invoice = invoices[0]  # Most recent of any invoices
 

	
 
    return redirect("invoice", invoice.id, access_code)
 

	
 

	
 
def invoice(request, invoice_id, access_code=None):
 
    ''' Displays an invoice.
 

	
 
    This view is not authenticated, but it will only allow access to either:
 
    the user the invoice belongs to; staff; or a request made with the correct
 
    access code.
 

	
 
    Arguments:
...
 
@@ -614,48 +612,49 @@ def invoice(request, invoice_id, access_code=None):
 
        Http404: if the current user cannot view this invoice and the correct
 
            access_code is not provided.
 

	
 
    '''
 

	
 
    current_invoice = InvoiceController.for_id_or_404(invoice_id)
 

	
 
    if not current_invoice.can_view(
 
            user=request.user,
 
            access_code=access_code,
 
            ):
 
        raise Http404()
 

	
 
    data = {
 
        "invoice": current_invoice.invoice,
 
    }
 

	
 
    return render(request, "registrasion/invoice.html", data)
 

	
 

	
 
def _staff_only(user):
 
    ''' Returns true if the user is staff. '''
 
    return user.is_staff
 

	
 

	
 
@user_passes_test(_staff_only)
 
def manual_payment(request, invoice_id):
 
    ''' Allows staff to make manual payments or refunds on an invoice.
 

	
 
    This form requires a login, and the logged in user needs to be staff.
 

	
 
    Arguments:
 
        invoice_id (castable to int): The invoice ID to be paid
 

	
 
    Returns:
 
        render:
 
            Renders ``registrasion/manual_payment.html`` with the following
 
            data::
 

	
 
                {
 
                    "invoice": models.commerce.Invoice(),
 
                    "form": form,   # A form that saves a ``ManualPayment``
 
                                    # object.
 
                }
 

	
 
    '''
 

	
 
    FORM_PREFIX = "manual_payment"
 

	
setup.cfg
Show inline comments
 
[flake8]
 
exclude = registrasion/migrations/*, build/*
 
exclude = registrasion/migrations/*, build/*, docs/*
0 comments (0 inline, 0 general)