Changeset - 2f4ebc22afea
[Not reviewed]
registrasion/admin.py
Show inline comments
...
 
@@ -80,3 +80,15 @@ class VoucherAdmin(nested_admin.NestedAdmin):
 
        VoucherDiscountInline,
 
        VoucherEnablingConditionInline,
 
    ]
 

	
 

	
 
# Enabling conditions
 
@admin.register(rego.ProductEnablingCondition)
 
class ProductEnablingConditionAdmin(nested_admin.NestedAdmin):
 
    model = rego.ProductEnablingCondition
 

	
 

	
 
# Enabling conditions
 
@admin.register(rego.CategoryEnablingCondition)
 
class CategoryEnablingConditionAdmin(nested_admin.NestedAdmin):
 
    model = rego.CategoryEnablingCondition
registrasion/controllers/cart.py
Show inline comments
...
 
@@ -54,57 +54,91 @@ class CartController(object):
 
        self.cart.time_last_updated = timezone.now()
 
        self.cart.reservation_duration = max(reservations)
 

	
 
    def add_to_cart(self, product, quantity):
 
        ''' Adds _quantity_ of the given _product_ to the cart. Raises
 
        ValidationError if constraints are violated.'''
 

	
 
        prod = ProductController(product)
 
    def end_batch(self):
 
        ''' Performs operations that occur occur at the end of a batch of
 
        product changes/voucher applications etc. '''
 
        self.recalculate_discounts()
 

	
 
        # TODO: Check enabling conditions for product for user
 
        self.extend_reservation()
 
        self.cart.revision += 1
 
        self.cart.save()
 

	
 
        if not prod.can_add_with_enabling_conditions(self.cart.user, quantity):
 
            raise ValidationError("Not enough of that product left (ec)")
 
    def set_quantity(self, product, quantity, batched=False):
 
        ''' Sets the _quantity_ of the given _product_ in the cart to the given
 
        _quantity_. '''
 

	
 
        if not prod.user_can_add_within_limit(self.cart.user, quantity):
 
            raise ValidationError("Not enough of that product left (user)")
 
        if quantity < 0:
 
            raise ValidationError("Cannot have fewer than 0 items in cart.")
 

	
 
        try:
 
            # Try to update an existing item within this cart if possible.
 
            product_item = rego.ProductItem.objects.get(
 
                cart=self.cart,
 
                product=product)
 
            product_item.quantity += quantity
 
            old_quantity = product_item.quantity
 

	
 
            if quantity == 0:
 
                product_item.delete()
 
                return
 
        except ObjectDoesNotExist:
 
            if quantity == 0:
 
                return
 

	
 
            product_item = rego.ProductItem.objects.create(
 
                cart=self.cart,
 
                product=product,
 
                quantity=quantity,
 
                quantity=0,
 
            )
 

	
 
            old_quantity = 0
 

	
 
        # Validate the addition to the cart
 
        adjustment = quantity - old_quantity
 
        prod = ProductController(product)
 

	
 
        if not prod.can_add_with_enabling_conditions(
 
                self.cart.user, adjustment):
 
            raise ValidationError("Not enough of that product left (ec)")
 

	
 
        if not prod.user_can_add_within_limit(self.cart.user, adjustment):
 
            raise ValidationError("Not enough of that product left (user)")
 

	
 
        product_item.quantity = quantity
 
        product_item.save()
 

	
 
        self.recalculate_discounts()
 
        if not batched:
 
            self.end_batch()
 

	
 
        self.extend_reservation()
 
        self.cart.revision += 1
 
        self.cart.save()
 
    def add_to_cart(self, product, quantity):
 
        ''' Adds _quantity_ of the given _product_ to the cart. Raises
 
        ValidationError if constraints are violated.'''
 

	
 
        try:
 
            product_item = rego.ProductItem.objects.get(
 
                cart=self.cart,
 
                product=product)
 
            old_quantity = product_item.quantity
 
        except ObjectDoesNotExist:
 
            old_quantity = 0
 
        self.set_quantity(product, old_quantity + quantity)
 

	
 
    def apply_voucher(self, voucher):
 
        ''' Applies the given voucher to this cart. '''
 
    def apply_voucher(self, voucher_code):
 
        ''' Applies the voucher with the given code to this cart. '''
 

	
 
        # TODO: is it valid for a cart to re-add a voucher that they have?
 

	
 
        # Is voucher exhausted?
 
        active_carts = rego.Cart.reserved_carts()
 

	
 
        # Try and find the voucher
 
        voucher = rego.Voucher.objects.get(code=voucher_code.upper())
 

	
 
        carts_with_voucher = active_carts.filter(vouchers=voucher)
 
        if len(carts_with_voucher) >= voucher.limit:
 
            raise ValidationError("This voucher is no longer available")
 

	
 
        # If successful...
 
        self.cart.vouchers.add(voucher)
 

	
 
        self.extend_reservation()
 
        self.cart.revision += 1
 
        self.cart.save()
 
        self.end_batch()
 

	
 
    def validate_cart(self):
 
        ''' Determines whether the status of the current cart is valid;
...
 
@@ -153,7 +187,12 @@ class CartController(object):
 
        # Delete the existing entries.
 
        rego.DiscountItem.objects.filter(cart=self.cart).delete()
 

	
 
        for item in self.cart.productitem_set.all():
 
        # The highest-value discounts will apply to the highest-value
 
        # products first.
 
        product_items = self.cart.productitem_set.all()
 
        product_items = product_items.order_by('product__price')
 
        product_items = reversed(product_items)
 
        for item in product_items:
 
            self._add_discount(item.product, item.quantity)
 

	
 
    def _add_discount(self, product, quantity):
...
 
@@ -172,9 +211,7 @@ class CartController(object):
 
            # Get the count of past uses of this discount condition
 
            # as this affects the total amount we're allowed to use now.
 
            past_uses = rego.DiscountItem.objects.filter(
 
                cart__active=False,
 
                discount=discount.discount,
 
                product=product,
 
            )
 
            agg = past_uses.aggregate(Sum("quantity"))
 
            past_uses = agg["quantity__sum"]
registrasion/controllers/invoice.py
Show inline comments
...
 
@@ -59,20 +59,23 @@ class InvoiceController(object):
 

	
 
        # TODO: calculate line items.
 
        product_items = rego.ProductItem.objects.filter(cart=cart)
 
        product_items = product_items.order_by(
 
            "product__category__order", "product__order"
 
        )
 
        discount_items = rego.DiscountItem.objects.filter(cart=cart)
 
        invoice_value = Decimal()
 
        for item in product_items:
 
            product = item.product
 
            line_item = rego.LineItem.objects.create(
 
                invoice=invoice,
 
                description=item.product.name,
 
                description="%s - %s" % (product.category.name, product.name),
 
                quantity=item.quantity,
 
                price=item.product.price,
 
                price=product.price,
 
            )
 
            line_item.save()
 
            invoice_value += line_item.quantity * line_item.price
 

	
 
        for item in discount_items:
 

	
 
            line_item = rego.LineItem.objects.create(
 
                invoice=invoice,
 
                description=item.discount.description,
registrasion/forms.py
Show inline comments
 
new file 100644
 
import models as rego
 

	
 
from django import forms
 

	
 

	
 
def CategoryForm(category):
 

	
 
    PREFIX = "product_"
 

	
 
    def field_name(product):
 
        return PREFIX + ("%d" % product.id)
 

	
 
    class _CategoryForm(forms.Form):
 

	
 
        @staticmethod
 
        def initial_data(product_quantities):
 
            ''' Prepares initial data for an instance of this form.
 
            product_quantities is a sequence of (product,quantity) tuples '''
 
            initial = {}
 
            for product, quantity in product_quantities:
 
                initial[field_name(product)] = quantity
 

	
 
            return initial
 

	
 
        def product_quantities(self):
 
            ''' Yields a sequence of (product, quantity) tuples from the
 
            cleaned form data. '''
 
            for name, value in self.cleaned_data.items():
 
                if name.startswith(PREFIX):
 
                    product_id = int(name[len(PREFIX):])
 
                    yield (product_id, value, name)
 

	
 
        def disable_product(self, product):
 
            ''' Removes a given product from this form. '''
 
            del self.fields[field_name(product)]
 

	
 
    products = rego.Product.objects.filter(category=category).order_by("order")
 
    for product in products:
 

	
 
        help_text = "$%d -- %s" % (product.price, product.description)
 

	
 
        field = forms.IntegerField(
 
            label=product.name,
 
            help_text=help_text,
 
        )
 
        _CategoryForm.base_fields[field_name(product)] = field
 

	
 
    return _CategoryForm
 

	
 
class VoucherForm(forms.Form):
 
    voucher = forms.CharField(
 
        label="Voucher code",
 
        help_text="If you have a voucher code, enter it here",
 
        required=True,
 
    )
registrasion/migrations/0001_squashed_0002_auto_20160304_1723.py
Show inline comments
 
file renamed from registrasion/migrations/0001_initial.py to registrasion/migrations/0001_squashed_0002_auto_20160304_1723.py
...
 
@@ -9,6 +9,8 @@ from django.conf import settings
 

	
 
class Migration(migrations.Migration):
 

	
 
    replaces = [('registrasion', '0001_initial'), ('registrasion', '0002_auto_20160304_1723')]
 

	
 
    dependencies = [
 
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
 
    ]
...
 
@@ -225,12 +227,12 @@ class Migration(migrations.Migration):
 
        migrations.AddField(
 
            model_name='enablingconditionbase',
 
            name='categories',
 
            field=models.ManyToManyField(to=b'registrasion.Category'),
 
            field=models.ManyToManyField(to=b'registrasion.Category', blank=True),
 
        ),
 
        migrations.AddField(
 
            model_name='enablingconditionbase',
 
            name='products',
 
            field=models.ManyToManyField(to=b'registrasion.Product'),
 
            field=models.ManyToManyField(to=b'registrasion.Product', blank=True),
 
        ),
 
        migrations.AddField(
 
            model_name='discountitem',
registrasion/models.py
Show inline comments
...
 
@@ -99,6 +99,11 @@ class Voucher(models.Model):
 
    def __str__(self):
 
        return "Voucher for %s" % self.recipient
 

	
 
    def save(self, *a, **k):
 
        ''' Normalise the voucher code to be uppercase '''
 
        self.code = self.code.upper()
 
        super(Voucher, self).save(*a, **k)
 

	
 
    recipient = models.CharField(max_length=64, verbose_name=_("Recipient"))
 
    code = models.CharField(max_length=16,
 
                            unique=True,
...
 
@@ -149,13 +154,13 @@ class DiscountForProduct(models.Model):
 
        cats = DiscountForCategory.objects.filter(
 
            discount=self.discount,
 
            category=self.product.category)
 
        if len(prods) > 1 or self not in prods:
 
        if len(prods) > 1:
 
            raise ValidationError(
 
                _("You may only have one discount line per product"))
 
        if len(cats) != 0:
 
            raise ValidationError(
 
                _("You may only have one discount for "
 
                "a product or its category"))
 
                    "a product or its category"))
 

	
 
    discount = models.ForeignKey(DiscountBase, on_delete=models.CASCADE)
 
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
...
 
@@ -184,8 +189,8 @@ class DiscountForCategory(models.Model):
 
        if len(prods) != 0:
 
            raise ValidationError(
 
                _("You may only have one discount for "
 
                "a product or its category"))
 
        if len(cats) > 1 or self not in cats:
 
                    "a product or its category"))
 
        if len(cats) > 1:
 
            raise ValidationError(
 
                _("You may only have one discount line per category"))
 

	
...
 
@@ -257,8 +262,8 @@ class EnablingConditionBase(models.Model):
 

	
 
    description = models.CharField(max_length=255)
 
    mandatory = models.BooleanField(default=False)
 
    products = models.ManyToManyField(Product)
 
    categories = models.ManyToManyField(Category)
 
    products = models.ManyToManyField(Product, blank=True)
 
    categories = models.ManyToManyField(Category, blank=True)
 

	
 

	
 
class TimeOrStockLimitEnablingCondition(EnablingConditionBase):
registrasion/templates/invoice.html
Show inline comments
 
new file 100644
 
<!--- Sample template. Move elsewhere once it's ready to go. -->
 

	
 
{% extends "site_base.html" %}
 
{% block body %}
 

	
 
<h1>Invoice {{ invoice.id }}</h1>
 

	
 
<ul>
 
  <li>Void: {{ invoice.void }}</li>
 
  <li>Paid: {{ invoice.paid }}</li>
 
</ul>
 

	
 
<table>
 
  <tr>
 
    <th>Description</th>
 
    <th>Quantity</th>
 
    <th>Price/Unit</th>
 
    <th>Total</th>
 
  </tr>
 
  {% for line_item in invoice.lineitem_set.all %}
 
    <tr>
 
      <td>{{line_item.description}}</td>
 
      <td>{{line_item.quantity}}</td>
 
      <td>{{line_item.price}}</td>
 
      <td><!-- multiply --> FIXME</td>
 
    </tr>
 
  {% endfor %}
 
  <tr>
 
    <th>TOTAL</th>
 
    <td></td>
 
    <td></td>
 
    <td>{{ invoice.value }}</td>
 
  </tr>
 
</table>
 

	
 

	
 
{% endblock %}
registrasion/templates/product_category.html
Show inline comments
 
new file 100644
 
<!--- Sample template. Move elsewhere once it's ready to go. -->
 

	
 
{% extends "site_base.html" %}
 
{% block body %}
 

	
 
  <h1>Product Category: {{ category.name }}</h1>
 

	
 
  <p>{{ category.description }}</p>
 

	
 
  <form method="post" action="">
 
    {% csrf_token %}
 

	
 
    <table>
 
        {{ voucher_form }}
 
    </table>
 

	
 
    <input type="submit">
 

	
 
    <table>
 
        {{ form }}
 
    </table>
 

	
 
    <input type="submit">
 

	
 
  </form>
 

	
 

	
 
{% endblock %}
registrasion/tests/test_cart.py
Show inline comments
...
 
@@ -3,6 +3,7 @@ import pytz
 

	
 
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.test import TestCase
 

	
...
 
@@ -81,7 +82,18 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
 
            limit_per_user=10,
 
            order=10,
 
        )
 
        cls.PROD_2.save()
 
        cls.PROD_3.save()
 

	
 
        cls.PROD_4 = rego.Product.objects.create(
 
            name="Product 4",
 
            description="This is a test product. It costs $5. "
 
                        "A user may have 10 of them.",
 
            category=cls.CAT_2,
 
            price=Decimal("5.00"),
 
            limit_per_user=10,
 
            order=10,
 
        )
 
        cls.PROD_4.save()
 

	
 
    @classmethod
 
    def make_ceiling(cls, name, limit=None, start_time=None, end_time=None):
...
 
@@ -159,6 +171,38 @@ class BasicCartTests(RegistrationCartTestCase):
 
        item = items[0]
 
        self.assertEquals(2, item.quantity)
 

	
 
    def test_set_quantity(self):
 
        current_cart = CartController.for_user(self.USER_1)
 

	
 
        def get_item():
 
            return rego.ProductItem.objects.get(
 
                cart=current_cart.cart,
 
                product=self.PROD_1)
 

	
 
        current_cart.set_quantity(self.PROD_1, 1)
 
        self.assertEqual(1, get_item().quantity)
 

	
 
        # Setting the quantity to zero should remove the entry from the cart.
 
        current_cart.set_quantity(self.PROD_1, 0)
 
        with self.assertRaises(ObjectDoesNotExist):
 
            get_item()
 

	
 
        current_cart.set_quantity(self.PROD_1, 9)
 
        self.assertEqual(9, get_item().quantity)
 

	
 
        with self.assertRaises(ValidationError):
 
            current_cart.set_quantity(self.PROD_1, 11)
 

	
 
        self.assertEqual(9, get_item().quantity)
 

	
 
        with self.assertRaises(ValidationError):
 
            current_cart.set_quantity(self.PROD_1, -1)
 

	
 
        self.assertEqual(9, get_item().quantity)
 

	
 
        current_cart.set_quantity(self.PROD_1, 2)
 
        self.assertEqual(2, get_item().quantity)
 

	
 
    def test_add_to_cart_per_user_limit(self):
 
        current_cart = CartController.for_user(self.USER_1)
 

	
registrasion/tests/test_discount.py
Show inline comments
...
 
@@ -29,7 +29,10 @@ class DiscountTestCase(RegistrationCartTestCase):
 
        return discount
 

	
 
    @classmethod
 
    def add_discount_prod_1_includes_cat_2(cls, amount=Decimal(100)):
 
    def add_discount_prod_1_includes_cat_2(
 
            cls,
 
            amount=Decimal(100),
 
            quantity=2):
 
        discount = rego.IncludedProductDiscount.objects.create(
 
            description="PROD_1 includes CAT_2 " + str(amount) + "%",
 
        )
...
 
@@ -40,7 +43,7 @@ class DiscountTestCase(RegistrationCartTestCase):
 
            discount=discount,
 
            category=cls.CAT_2,
 
            percentage=amount,
 
            quantity=2
 
            quantity=quantity,
 
        ).save()
 
        return discount
 

	
...
 
@@ -169,3 +172,31 @@ class DiscountTestCase(RegistrationCartTestCase):
 

	
 
        discount_items = list(cart.cart.discountitem_set.all())
 
        self.assertEqual(2, discount_items[0].quantity)
 

	
 
    def test_category_discount_applies_once_per_category(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # Add two items from category 2
 
        cart.add_to_cart(self.PROD_3, 1)
 
        cart.add_to_cart(self.PROD_4, 1)
 

	
 
        discount_items = list(cart.cart.discountitem_set.all())
 
        # There is one discount, and it should apply to one item.
 
        self.assertEqual(1, len(discount_items))
 
        self.assertEqual(1, discount_items[0].quantity)
 

	
 
    def test_category_discount_applies_to_highest_value(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # Add two items from category 2, add the less expensive one first
 
        cart.add_to_cart(self.PROD_4, 1)
 
        cart.add_to_cart(self.PROD_3, 1)
 

	
 
        discount_items = list(cart.cart.discountitem_set.all())
 
        # There is one discount, and it should apply to the more expensive.
 
        self.assertEqual(1, len(discount_items))
 
        self.assertEqual(self.PROD_3, discount_items[0].product)
registrasion/tests/test_invoice.py
Show inline comments
...
 
@@ -91,7 +91,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
 
        ).save()
 

	
 
        current_cart = CartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
registrasion/tests/test_voucher.py
Show inline comments
...
 
@@ -3,6 +3,7 @@ import pytz
 

	
 
from decimal import Decimal
 
from django.core.exceptions import ValidationError
 
from django.db import IntegrityError
 

	
 
from registrasion import models as rego
 
from registrasion.controllers.cart import CartController
...
 
@@ -15,10 +16,10 @@ UTC = pytz.timezone('UTC')
 
class VoucherTestCases(RegistrationCartTestCase):
 

	
 
    @classmethod
 
    def new_voucher(self):
 
    def new_voucher(self, code="VOUCHER"):
 
        voucher = rego.Voucher.objects.create(
 
            recipient="Voucher recipient",
 
            code="VOUCHER",
 
            code=code,
 
            limit=1
 
        )
 
        voucher.save()
...
 
@@ -30,18 +31,18 @@ class VoucherTestCases(RegistrationCartTestCase):
 
        self.set_time(datetime.datetime(2015, 01, 01, tzinfo=UTC))
 

	
 
        cart_1 = CartController.for_user(self.USER_1)
 
        cart_1.apply_voucher(voucher)
 
        cart_1.apply_voucher(voucher.code)
 
        self.assertIn(voucher, cart_1.cart.vouchers.all())
 

	
 
        # Second user should not be able to apply this voucher (it's exhausted)
 
        cart_2 = CartController.for_user(self.USER_2)
 
        with self.assertRaises(ValidationError):
 
            cart_2.apply_voucher(voucher)
 
            cart_2.apply_voucher(voucher.code)
 

	
 
        # After the reservation duration
 
        # user 2 should be able to apply voucher
 
        self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
 
        cart_2.apply_voucher(voucher)
 
        cart_2.apply_voucher(voucher.code)
 
        cart_2.cart.active = False
 
        cart_2.cart.save()
 

	
...
 
@@ -49,7 +50,7 @@ class VoucherTestCases(RegistrationCartTestCase):
 
        # voucher, as user 2 has paid for their cart.
 
        self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
 
        with self.assertRaises(ValidationError):
 
            cart_1.apply_voucher(voucher)
 
            cart_1.apply_voucher(voucher.code)
 

	
 
    def test_voucher_enables_item(self):
 
        voucher = self.new_voucher()
...
 
@@ -69,7 +70,7 @@ class VoucherTestCases(RegistrationCartTestCase):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # Apply the voucher
 
        current_cart.apply_voucher(voucher)
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
    def test_voucher_enables_discount(self):
...
 
@@ -89,6 +90,20 @@ class VoucherTestCases(RegistrationCartTestCase):
 

	
 
        # Having PROD_1 in place should add a discount
 
        current_cart = CartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher)
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        self.assertEqual(1, len(current_cart.cart.discountitem_set.all()))
 

	
 
    def test_voucher_codes_unique(self):
 
        voucher1 = self.new_voucher(code="VOUCHER")
 
        with self.assertRaises(IntegrityError):
 
            voucher2 = self.new_voucher(code="VOUCHER")
 

	
 
    def test_multiple_vouchers_work(self):
 
        voucher1 = self.new_voucher(code="VOUCHER1")
 
        voucher2 = self.new_voucher(code="VOUCHER2")
 

	
 
    def test_vouchers_case_insensitive(self):
 
        voucher = self.new_voucher(code="VOUCHeR")
 
        current_cart = CartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code.lower())
registrasion/urls.py
Show inline comments
 
new file 100644
 
from django.conf.urls import url, patterns
 

	
 
urlpatterns = patterns(
 
    "registrasion.views",
 
    url(r"^category/([0-9]+)$", "product_category", name="product_category"),
 
    url(r"^checkout$", "checkout", name="checkout"),
 
    url(r"^invoice/([0-9]+)$", "invoice", name="invoice"),
 
    url(r"^invoice/([0-9]+)/pay$", "pay_invoice", name="pay_invoice"),
 
)
registrasion/views.py
Show inline comments
 
new file 100644
 
from registrasion import forms
 
from registrasion import models as rego
 
from registrasion.controllers.cart import CartController
 
from registrasion.controllers.invoice import InvoiceController
 
from registrasion.controllers.product import ProductController
 

	
 
from django.contrib.auth.decorators import login_required
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.exceptions import ValidationError
 
from django.db import transaction
 
from django.shortcuts import redirect
 
from django.shortcuts import render
 

	
 

	
 
@login_required
 
def product_category(request, category_id):
 
    ''' Registration selections form for a specific category of items '''
 

	
 
    PRODUCTS_FORM_PREFIX = "products"
 
    VOUCHERS_FORM_PREFIX = "vouchers"
 

	
 
    category_id = int(category_id)  # Routing is [0-9]+
 
    category = rego.Category.objects.get(pk=category_id)
 
    current_cart = CartController.for_user(request.user)
 

	
 
    CategoryForm = forms.CategoryForm(category)
 

	
 
    products = rego.Product.objects.filter(category=category)
 
    products = products.order_by("order")
 

	
 
    if request.method == "POST":
 
        cat_form = CategoryForm(request.POST, request.FILES, prefix=PRODUCTS_FORM_PREFIX)
 
        voucher_form = forms.VoucherForm(request.POST, prefix=VOUCHERS_FORM_PREFIX)
 

	
 
        if voucher_form.is_valid():
 
            # Apply voucher
 
            # leave
 
            voucher = voucher_form.cleaned_data["voucher"]
 
            try:
 
                current_cart.apply_voucher(voucher)
 
            except Exception as e:
 
                voucher_form.add_error("voucher", e)
 
        elif cat_form.is_valid():
 
            try:
 
                with transaction.atomic():
 
                    for product_id, quantity, field_name \
 
                            in cat_form.product_quantities():
 
                        product = rego.Product.objects.get(pk=product_id)
 
                        try:
 
                            current_cart.set_quantity(
 
                                product, quantity, batched=True)
 
                        except ValidationError as ve:
 
                            cat_form.add_error(field_name, ve)
 
                    if cat_form.errors:
 
                        raise ValidationError("Cannot add that stuff")
 
                    current_cart.end_batch()
 
            except ValidationError as ve:
 
                pass
 

	
 
    else:
 
        # Create initial data for each of products in category
 
        items = rego.ProductItem.objects.filter(
 
            product__category=category,
 
            cart=current_cart.cart,
 
        )
 
        quantities = []
 
        for product in products:
 
            # Only add items that are enabled.
 
            prod = ProductController(product)
 
            try:
 
                quantity = items.get(product=product).quantity
 
            except ObjectDoesNotExist:
 
                quantity = 0
 
            quantities.append((product, quantity))
 

	
 
        initial = CategoryForm.initial_data(quantities)
 
        cat_form = CategoryForm(prefix=PRODUCTS_FORM_PREFIX, initial=initial)
 

	
 
        voucher_form = forms.VoucherForm(prefix=VOUCHERS_FORM_PREFIX)
 

	
 
    for product in products:
 
        # Remove fields that do not have an enabling condition.
 
        prod = ProductController(product)
 
        if not prod.can_add_with_enabling_conditions(request.user, 0):
 
            cat_form.disable_product(product)
 

	
 

	
 
    data = {
 
        "category": category,
 
        "form": cat_form,
 
        "voucher_form": voucher_form,
 
    }
 

	
 
    return render(request, "product_category.html", data)
 

	
 

	
 
@login_required
 
def checkout(request):
 
    ''' Runs checkout for the current cart of items, ideally generating an
 
    invoice. '''
 

	
 
    current_cart = CartController.for_user(request.user)
 
    current_invoice = InvoiceController.for_cart(current_cart.cart)
 

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

	
 

	
 
@login_required
 
def invoice(request, invoice_id):
 
    ''' Displays an invoice for a given invoice id. '''
 

	
 
    invoice_id = int(invoice_id)
 
    inv = rego.Invoice.objects.get(pk=invoice_id)
 
    current_invoice = InvoiceController(inv)
 

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

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

	
 
@login_required
 
def pay_invoice(request, invoice_id):
 
    ''' Marks the invoice with the given invoice id as paid.
 
    WORK IN PROGRESS FUNCTION. Must be replaced with real payment workflow.
 

	
 
    '''
 

	
 
    invoice_id = int(invoice_id)
 
    inv = rego.Invoice.objects.get(pk=invoice_id)
 
    current_invoice = InvoiceController(inv)
 
    if not inv.paid and not current_invoice.is_valid():
 
        current_invoice.pay("Demo invoice payment", inv.value)
 

	
 
    return redirect("invoice", current_invoice.invoice.id)
0 comments (0 inline, 0 general)