forked from DGNum/gestioCOF
kfet.tests -- Add factories for many kfet models
- Article - ArticleCategory - Checkout - CheckoutStatement - Inventory - InventoryArticle - Operation - OperationGroup
This commit is contained in:
parent
928abc5a06
commit
d7ca072af3
2 changed files with 281 additions and 3 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
from decimal import Decimal
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -5,9 +8,16 @@ from django.test import TestCase
|
||||||
|
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile
|
||||||
|
|
||||||
from ..models import Account
|
from ..models import Account, Article, ArticleCategory, Checkout, Operation
|
||||||
from .testcases import TestCaseMixin
|
from .testcases import TestCaseMixin
|
||||||
from .utils import create_root, create_team, create_user, get_perms, user_add_perms
|
from .utils import (
|
||||||
|
create_operation_group,
|
||||||
|
create_root,
|
||||||
|
create_team,
|
||||||
|
create_user,
|
||||||
|
get_perms,
|
||||||
|
user_add_perms,
|
||||||
|
)
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -86,3 +96,80 @@ class PermHelpersTest(TestCaseMixin, TestCase):
|
||||||
map(repr, [self.perm1, self.perm2, self.perm_team]),
|
map(repr, [self.perm1, self.perm2, self.perm_team]),
|
||||||
ordered=False,
|
ordered=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OperationHelpersTest(TestCase):
|
||||||
|
def test_create_operation_group(self):
|
||||||
|
operation_group = create_operation_group()
|
||||||
|
|
||||||
|
on_acc = Account.objects.get(cofprofile__user__username="user")
|
||||||
|
checkout = Checkout.objects.get(name="Checkout")
|
||||||
|
self.assertDictEqual(
|
||||||
|
operation_group.__dict__,
|
||||||
|
{
|
||||||
|
"_checkout_cache": checkout,
|
||||||
|
"_on_acc_cache": on_acc,
|
||||||
|
"_state": mock.ANY,
|
||||||
|
"amount": 0,
|
||||||
|
"at": mock.ANY,
|
||||||
|
"checkout_id": checkout.pk,
|
||||||
|
"comment": "",
|
||||||
|
"id": mock.ANY,
|
||||||
|
"is_cof": False,
|
||||||
|
"on_acc_id": on_acc.pk,
|
||||||
|
"valid_by_id": None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertFalse(operation_group.opes.all())
|
||||||
|
|
||||||
|
def test_create_operation_group_with_content(self):
|
||||||
|
article_category = ArticleCategory.objects.create(name="Category")
|
||||||
|
article1 = Article.objects.create(
|
||||||
|
category=article_category, name="Article 1", price=Decimal("2.50")
|
||||||
|
)
|
||||||
|
article2 = Article.objects.create(
|
||||||
|
category=article_category, name="Article 2", price=Decimal("4.00")
|
||||||
|
)
|
||||||
|
operation_group = create_operation_group(
|
||||||
|
content=[
|
||||||
|
{
|
||||||
|
"type": Operation.PURCHASE,
|
||||||
|
"amount": Decimal("-3.50"),
|
||||||
|
"article": article1,
|
||||||
|
"article_nb": 2,
|
||||||
|
},
|
||||||
|
{"type": Operation.PURCHASE, "article": article2, "article_nb": 2},
|
||||||
|
{"type": Operation.PURCHASE, "article": article2},
|
||||||
|
{"type": Operation.DEPOSIT, "amount": Decimal("10.00")},
|
||||||
|
{"type": Operation.WITHDRAW, "amount": Decimal("-1.00")},
|
||||||
|
{"type": Operation.EDIT, "amount": Decimal("7.00")},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(operation_group.amount, Decimal("0.50"))
|
||||||
|
|
||||||
|
operation_list = list(operation_group.opes.all())
|
||||||
|
# Passed args: with purchase, article, article_nb, amount
|
||||||
|
self.assertEqual(operation_list[0].type, Operation.PURCHASE)
|
||||||
|
self.assertEqual(operation_list[0].article, article1)
|
||||||
|
self.assertEqual(operation_list[0].article_nb, 2)
|
||||||
|
self.assertEqual(operation_list[0].amount, Decimal("-3.50"))
|
||||||
|
# Passed args: with purchase, article, article_nb; without amount
|
||||||
|
self.assertEqual(operation_list[1].type, Operation.PURCHASE)
|
||||||
|
self.assertEqual(operation_list[1].article, article2)
|
||||||
|
self.assertEqual(operation_list[1].article_nb, 2)
|
||||||
|
self.assertEqual(operation_list[1].amount, Decimal("-8.00"))
|
||||||
|
# Passed args: with purchase, article; without article_nb, amount
|
||||||
|
self.assertEqual(operation_list[2].type, Operation.PURCHASE)
|
||||||
|
self.assertEqual(operation_list[2].article, article2)
|
||||||
|
self.assertEqual(operation_list[2].article_nb, 1)
|
||||||
|
self.assertEqual(operation_list[2].amount, Decimal("-4.00"))
|
||||||
|
# Passed args: with deposit, amount
|
||||||
|
self.assertEqual(operation_list[3].type, Operation.DEPOSIT)
|
||||||
|
self.assertEqual(operation_list[3].amount, Decimal("10.00"))
|
||||||
|
# Passed args: with withdraw, amount
|
||||||
|
self.assertEqual(operation_list[4].type, Operation.WITHDRAW)
|
||||||
|
self.assertEqual(operation_list[4].amount, Decimal("-1.00"))
|
||||||
|
# Passed args: with edit, amount
|
||||||
|
self.assertEqual(operation_list[5].type, Operation.EDIT)
|
||||||
|
self.assertEqual(operation_list[5].amount, Decimal("7.00"))
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
|
from datetime import timedelta
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from ..models import Account
|
from ..models import (
|
||||||
|
Account,
|
||||||
|
Article,
|
||||||
|
ArticleCategory,
|
||||||
|
Checkout,
|
||||||
|
CheckoutStatement,
|
||||||
|
Inventory,
|
||||||
|
InventoryArticle,
|
||||||
|
Operation,
|
||||||
|
OperationGroup,
|
||||||
|
)
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -184,3 +198,180 @@ def user_add_perms(user, perms_labels):
|
||||||
# it to avoid using of the previous permissions cache.
|
# it to avoid using of the previous permissions cache.
|
||||||
# https://docs.djangoproject.com/en/dev/topics/auth/default/#permission-caching
|
# https://docs.djangoproject.com/en/dev/topics/auth/default/#permission-caching
|
||||||
return User.objects.get(pk=user.pk)
|
return User.objects.get(pk=user.pk)
|
||||||
|
|
||||||
|
|
||||||
|
def create_checkout(**kwargs):
|
||||||
|
"""
|
||||||
|
Factory to create a checkout.
|
||||||
|
See defaults for unpassed arguments in code below.
|
||||||
|
"""
|
||||||
|
if "created_by" not in kwargs or "created_by_id" not in kwargs:
|
||||||
|
try:
|
||||||
|
team_account = Account.objects.get(cofprofile__user__username="team")
|
||||||
|
except Account.DoesNotExist:
|
||||||
|
team_account = create_team().profile.account_kfet
|
||||||
|
kwargs["created_by"] = team_account
|
||||||
|
kwargs.setdefault("name", "Checkout")
|
||||||
|
kwargs.setdefault("valid_from", timezone.now() - timedelta(days=14))
|
||||||
|
kwargs.setdefault("valid_to", timezone.now() - timedelta(days=14))
|
||||||
|
|
||||||
|
return Checkout.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_operation_group(content=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Factory to create an OperationGroup and a set of related Operation.
|
||||||
|
|
||||||
|
It aims to get objects for testing purposes with minimal setup, and
|
||||||
|
preserving consistency.
|
||||||
|
For this, it uses, and creates if necessary, default objects for unpassed
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content: list of dict
|
||||||
|
Describe set of Operation to create along the OperationGroup.
|
||||||
|
Each item is passed to the Operation factory.
|
||||||
|
kwargs:
|
||||||
|
Used to control OperationGroup creation.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if content is None:
|
||||||
|
content = []
|
||||||
|
|
||||||
|
# Prepare OperationGroup creation.
|
||||||
|
|
||||||
|
# Set 'checkout' for OperationGroup if unpassed.
|
||||||
|
if "checkout" not in kwargs and "checkout_id" not in kwargs:
|
||||||
|
try:
|
||||||
|
checkout = Checkout.objects.get(name="Checkout")
|
||||||
|
except Checkout.DoesNotExist:
|
||||||
|
checkout = create_checkout()
|
||||||
|
kwargs["checkout"] = checkout
|
||||||
|
|
||||||
|
# Set 'on_acc' for OperationGroup if unpassed.
|
||||||
|
if "on_acc" not in kwargs and "on_acc_id" not in kwargs:
|
||||||
|
try:
|
||||||
|
on_acc = Account.objects.get(cofprofile__user__username="user")
|
||||||
|
except Account.DoesNotExist:
|
||||||
|
on_acc = create_user().profile.account_kfet
|
||||||
|
kwargs["on_acc"] = on_acc
|
||||||
|
|
||||||
|
# Set 'is_cof' for OperationGroup if unpassed.
|
||||||
|
if "is_cof" not in kwargs:
|
||||||
|
# Use current is_cof status of 'on_acc'.
|
||||||
|
kwargs["is_cof"] = kwargs["on_acc"].cofprofile.is_cof
|
||||||
|
|
||||||
|
# Create OperationGroup.
|
||||||
|
group = OperationGroup.objects.create(**kwargs)
|
||||||
|
|
||||||
|
# We can now create objects referencing this OperationGroup.
|
||||||
|
|
||||||
|
# Process set of related Operation.
|
||||||
|
if content:
|
||||||
|
# Create them.
|
||||||
|
operation_list = []
|
||||||
|
for operation_kwargs in content:
|
||||||
|
operation = create_operation(group=group, **operation_kwargs)
|
||||||
|
operation_list.append(operation)
|
||||||
|
|
||||||
|
# Update OperationGroup accordingly, for consistency.
|
||||||
|
for operation in operation_list:
|
||||||
|
if not operation.canceled_at:
|
||||||
|
group.amount += operation.amount
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
|
||||||
|
def create_operation(**kwargs):
|
||||||
|
"""
|
||||||
|
Factory to create an Operation for testing purposes.
|
||||||
|
|
||||||
|
If you give a 'group' (OperationGroup), it won't update it, you have do
|
||||||
|
this "manually". Prefer using OperationGroup factory to get a consistent
|
||||||
|
group with operations.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if "group" not in kwargs and "group_id" not in kwargs:
|
||||||
|
# To get a consistent OperationGroup (amount...) for the operation
|
||||||
|
# in-creation, prefer using create_operation_group factory with
|
||||||
|
# 'content'.
|
||||||
|
kwargs["group"] = create_operation_group()
|
||||||
|
|
||||||
|
if "type" not in kwargs:
|
||||||
|
raise RuntimeError("Can't create an Operation without 'type'.")
|
||||||
|
|
||||||
|
# Apply defaults for purchase
|
||||||
|
if kwargs["type"] == Operation.PURCHASE:
|
||||||
|
if "article" not in kwargs:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"One could write a create_article factory. Right now, you must"
|
||||||
|
"pass an 'article'."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unpassed 'article_nb' defaults to 1.
|
||||||
|
kwargs.setdefault("article_nb", 1)
|
||||||
|
|
||||||
|
# Unpassed 'amount' will use current article price and quantity.
|
||||||
|
if "amount" not in kwargs:
|
||||||
|
if "addcost_for" in kwargs or "addcost_amount" in kwargs:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"One could handle the case where 'amount' is missing and "
|
||||||
|
"addcost applies. Right now, please pass an 'amount'."
|
||||||
|
)
|
||||||
|
kwargs["amount"] = -kwargs["article"].price * kwargs["article_nb"]
|
||||||
|
|
||||||
|
return Operation.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_checkout_statement(**kwargs):
|
||||||
|
if "checkout" not in kwargs:
|
||||||
|
kwargs["checkout"] = create_checkout()
|
||||||
|
if "by" not in kwargs:
|
||||||
|
try:
|
||||||
|
team_account = Account.objects.get(cofprofile__user__username="team")
|
||||||
|
except Account.DoesNotExist:
|
||||||
|
team_account = create_team().profile.account_kfet
|
||||||
|
kwargs["by"] = team_account
|
||||||
|
kwargs.setdefault("balance_new", kwargs["checkout"].balance)
|
||||||
|
kwargs.setdefault("balance_old", kwargs["checkout"].balance)
|
||||||
|
kwargs.setdefault("amount_taken", Decimal(0))
|
||||||
|
|
||||||
|
return CheckoutStatement.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_article(**kwargs):
|
||||||
|
kwargs.setdefault("name", "Article")
|
||||||
|
kwargs.setdefault("price", Decimal("2.50"))
|
||||||
|
kwargs.setdefault("stock", 20)
|
||||||
|
if "category" not in kwargs:
|
||||||
|
kwargs["category"] = create_article_category()
|
||||||
|
|
||||||
|
return Article.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_article_category(**kwargs):
|
||||||
|
kwargs.setdefault("name", "Category")
|
||||||
|
return ArticleCategory.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_inventory(**kwargs):
|
||||||
|
if "by" not in kwargs:
|
||||||
|
try:
|
||||||
|
team_account = Account.objects.get(cofprofile__user__username="team")
|
||||||
|
except Account.DoesNotExist:
|
||||||
|
team_account = create_team().profile.account_kfet
|
||||||
|
kwargs["by"] = team_account
|
||||||
|
|
||||||
|
return Inventory.objects.create(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def create_inventory_article(**kwargs):
|
||||||
|
if "inventory" not in kwargs:
|
||||||
|
kwargs["inventory"] = create_inventory()
|
||||||
|
if "article" not in kwargs:
|
||||||
|
kwargs["article"] = create_article()
|
||||||
|
kwargs.setdefault("stock_old", kwargs["article"].stock)
|
||||||
|
kwargs.setdefault("stock_new", kwargs["article"].stock)
|
||||||
|
|
||||||
|
return InventoryArticle.objects.create(**kwargs)
|
||||||
|
|
Loading…
Reference in a new issue