Added testing for DateField, DateTimeField, and validators on the Model and ModelForm (#23)

* Added testing for DateField and DateTimeField

* Update makefile

* Adding some of the tests with validators on model

* Added ModelForm clean_field and clean tests

Co-authored-by: Thu Trang Pham <thu@joinmodernhealth.com>
This commit is contained in:
Thu Trang Pham
2021-03-31 12:46:02 -07:00
committed by GitHub
parent c88eb16a9b
commit 4d6b2900d8
16 changed files with 763 additions and 11 deletions
+15 -2
View File
@@ -1,8 +1,10 @@
import factory
from random import choice, randint
from django.utils import timezone
from tests.market.models import Item, Shop, Inventory
from .market.models import Item, Shop, Inventory, Transaction
from .market.constants import VALID_CURRENCIES
class ItemFactory(factory.django.DjangoModelFactory):
@@ -11,7 +13,7 @@ class ItemFactory(factory.django.DjangoModelFactory):
name = factory.Faker("name")
price = factory.LazyAttribute(lambda _: randint(5, 500))
currency = factory.LazyAttribute(lambda _: choice(Item.VALID_CURRENCIES))
currency = "CAD"
class ShopFactory(factory.django.DjangoModelFactory):
@@ -28,3 +30,14 @@ class InventoryFactory(factory.django.DjangoModelFactory):
shop = factory.SubFactory(ShopFactory)
item = factory.SubFactory(ItemFactory)
quantity = factory.Sequence(lambda n: n)
class TransactionFactory(factory.django.DjangoModelFactory):
class Meta:
model = Transaction
currency = "CAD"
total = 0
date = factory.LazyAttribute(lambda _: timezone.now().date())
timestamp = factory.LazyAttribute(lambda _: timezone.now())
shop = factory.SubFactory(ShopFactory)
+16 -1
View File
@@ -1,15 +1,30 @@
from django.contrib import admin
from ..models import GeneralManager, Item, Inventory, Shop, ShoppingMall
from ..models import (
GeneralManager,
Item,
Inventory,
ItemSale,
Shop,
ShoppingMall,
Transaction,
Checkout,
)
from .item_admin import ItemAdmin
from .inventory_admin import InventoryAdmin
from .shop_admin import ShopAdmin
from .shoppingmall_admin import ShoppingMallAdmin
from .generalmanager_admin import GeneralManagerAdmin
from .item_sale_admin import ItemSaleAdmin
from .transaction_admin import TransactionAdmin
from .checkout_admin import CheckoutAdmin
admin.site.register(Item, ItemAdmin)
admin.site.register(Inventory, InventoryAdmin)
admin.site.register(Shop, ShopAdmin)
admin.site.register(ShoppingMall, ShoppingMallAdmin)
admin.site.register(GeneralManager, GeneralManagerAdmin)
admin.site.register(Transaction, TransactionAdmin)
admin.site.register(ItemSale, ItemSaleAdmin)
admin.site.register(Checkout, CheckoutAdmin)
+46
View File
@@ -0,0 +1,46 @@
from django.core.exceptions import ValidationError
from admin_confirm.admin import AdminConfirmMixin
from django.contrib.admin import ModelAdmin
from django.forms import ModelForm
from ..models import Checkout
class CheckoutForm(ModelForm):
class Meta:
model = Checkout
fields = [
"currency",
"shop",
"total",
"timestamp",
"date",
]
def clean_total(self):
try:
total = float(self.cleaned_data["total"])
except:
raise ValidationError("Invalid Total From clean_total")
if total == 111: # Use to cause error in test
raise ValidationError("Invalid Total 111")
return total
def clean(self):
try:
total = float(self.data["total"])
except:
raise ValidationError("Invalid Total From clean")
if total == 222: # Use to cause error in test
raise ValidationError("Invalid Total 222")
self.cleaned_data["total"] = total
class CheckoutAdmin(AdminConfirmMixin, ModelAdmin):
confirm_add = True
confirm_change = True
autocomplete_fields = ["shop"]
form = CheckoutForm
+9
View File
@@ -0,0 +1,9 @@
from admin_confirm.admin import AdminConfirmMixin
from django.contrib.admin import ModelAdmin
class ItemSaleAdmin(AdminConfirmMixin, ModelAdmin):
confirm_add = True
confirm_change = True
+9
View File
@@ -0,0 +1,9 @@
from admin_confirm.admin import AdminConfirmMixin
from django.contrib.admin import ModelAdmin
class TransactionAdmin(AdminConfirmMixin, ModelAdmin):
confirm_add = True
confirm_change = True
+4
View File
@@ -0,0 +1,4 @@
VALID_CURRENCIES = (
("CAD", "CAD"),
("USD", "USD"),
)
@@ -0,0 +1,45 @@
# Generated by Django 3.1.7 on 2021-03-10 23:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('market', '0009_auto_20210304_0355'),
]
operations = [
migrations.CreateModel(
name='Transaction',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateField(auto_created=True)),
('total', models.DecimalField(decimal_places=2, editable=False, max_digits=5)),
('currency', models.CharField(choices=[('CAD', 'CAD'), ('USD', 'USD')], max_length=3)),
('shop', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='market.shop')),
],
),
migrations.CreateModel(
name='ItemSale',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('total', models.DecimalField(decimal_places=2, editable=False, max_digits=5)),
('currency', models.CharField(choices=[('CAD', 'CAD'), ('USD', 'USD')], max_length=3)),
('item', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='market.item')),
('transaction', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_sales', to='market.transaction')),
],
),
migrations.CreateModel(
name='Checkout',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('market.transaction',),
),
]
@@ -0,0 +1,30 @@
# Generated by Django 3.1.7 on 2021-03-26 01:30
from django.db import migrations, models
from ..validators import validate_currency
class Migration(migrations.Migration):
dependencies = [
("market", "0010_checkout_itemsale_transaction"),
]
operations = [
migrations.AddField(
model_name="itemsale",
name="quantity",
field=models.PositiveIntegerField(default=1),
),
migrations.AddField(
model_name="transaction",
name="date",
field=models.DateTimeField(default=None),
preserve_default=False,
),
migrations.AlterField(
model_name="itemsale",
name="currency",
field=models.CharField(max_length=5, validators=[validate_currency]),
),
]
@@ -0,0 +1,23 @@
# Generated by Django 3.1.7 on 2021-03-26 02:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('market', '0011_auto_20210326_0130'),
]
operations = [
migrations.AlterField(
model_name='transaction',
name='date',
field=models.DateField(),
),
migrations.AlterField(
model_name='transaction',
name='timestamp',
field=models.DateTimeField(auto_created=True),
),
]
+52 -4
View File
@@ -1,11 +1,14 @@
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.db.models.aggregates import Sum
from django.db import models
from .constants import VALID_CURRENCIES
from .validators import validate_currency
class Item(models.Model):
VALID_CURRENCIES = (
("CAD", "CAD"),
("USD", "USD"),
)
# Because I'm lazy and don't want to update all test references
VALID_CURRENCIES = VALID_CURRENCIES
name = models.CharField(max_length=120)
price = models.DecimalField(max_digits=5, decimal_places=2)
currency = models.CharField(max_length=3, choices=VALID_CURRENCIES)
@@ -57,3 +60,48 @@ class ShoppingMall(models.Model):
def __str__(self):
return self.name
class Transaction(models.Model):
total = models.DecimalField(max_digits=5, decimal_places=2, default=0)
currency = models.CharField(max_length=3, choices=VALID_CURRENCIES)
shop = models.ForeignKey(Shop, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_created=True)
date = models.DateField()
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
class ItemSale(models.Model):
transaction = models.ForeignKey(
Transaction, on_delete=models.CASCADE, related_name="item_sales"
)
item = models.ForeignKey(Item, on_delete=models.SET_NULL, null=True)
quantity = models.PositiveIntegerField(default=1)
total = models.DecimalField(max_digits=5, decimal_places=2)
currency = models.CharField(max_length=5, validators=[validate_currency])
def clean(self):
errors = {}
# check that shop has the stock
shop = self.transaction.shop
inventory = Inventory.objects.filter(shop=shop, item=self.item)
if not inventory:
errors["item"] = "Shop does not have the item stocked"
else:
in_stock = inventory.aggregate(Sum("quantity")).get("quantity__sum", 0)
if in_stock < self.quantity:
errors["item"] = "Shop does not have enough of the item stocked"
if errors:
raise ValidationError(errors)
class Checkout(Transaction):
"""
Proxy Model to use in Django Admin to create a Transaction
As if a customer was checking out at a physical checkout
"""
class Meta:
proxy = True
+8
View File
@@ -0,0 +1,8 @@
from django.core.exceptions import ValidationError
from .constants import VALID_CURRENCIES
def validate_currency(value: str):
currency_values = [c[0] for c in VALID_CURRENCIES]
if value not in currency_values:
raise ValidationError("Invalid Currency")