2018-10-04 14:18:00 +02:00
|
|
|
from datetime import timedelta
|
|
|
|
from decimal import Decimal
|
|
|
|
|
2017-08-10 15:02:08 +02:00
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from django.contrib.auth.models import Permission
|
2018-10-04 14:18:00 +02:00
|
|
|
from django.utils import timezone
|
|
|
|
|
|
|
|
from ..models import (
|
|
|
|
Account,
|
|
|
|
Article,
|
|
|
|
ArticleCategory,
|
|
|
|
Checkout,
|
|
|
|
CheckoutStatement,
|
|
|
|
Inventory,
|
|
|
|
InventoryArticle,
|
|
|
|
Operation,
|
|
|
|
OperationGroup,
|
|
|
|
)
|
2017-08-10 15:02:08 +02:00
|
|
|
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
|
|
|
|
|
|
def _create_user_and_account(user_attrs, account_attrs, perms=None):
|
2017-09-01 13:35:32 +02:00
|
|
|
"""
|
|
|
|
Create a user and its account, and assign permissions to this user.
|
|
|
|
|
|
|
|
Arguments
|
|
|
|
user_attrs (dict): User data (first name, last name, password...).
|
|
|
|
account_attrs (dict): Account data (department, kfet password...).
|
|
|
|
perms (list of str: 'app.perm'): These permissions will be assigned to
|
|
|
|
the created user. No permission are assigned by default.
|
|
|
|
|
|
|
|
If 'password' is not given in 'user_attrs', username is used as password.
|
|
|
|
|
|
|
|
If 'kfet.is_team' is in 'perms' and 'password' is not in 'account_attrs',
|
|
|
|
the account password is 'kfetpwd_<user pwd>'.
|
|
|
|
|
|
|
|
"""
|
2018-10-06 12:35:49 +02:00
|
|
|
user_pwd = user_attrs.pop("password", user_attrs["username"])
|
2017-08-16 17:45:59 +02:00
|
|
|
user = User.objects.create(**user_attrs)
|
|
|
|
user.set_password(user_pwd)
|
|
|
|
user.save()
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
account_attrs["cofprofile"] = user.profile
|
|
|
|
kfet_pwd = account_attrs.pop("password", "kfetpwd_{}".format(user_pwd))
|
2017-08-10 15:02:08 +02:00
|
|
|
|
|
|
|
account = Account.objects.create(**account_attrs)
|
|
|
|
|
|
|
|
if perms is not None:
|
|
|
|
user = user_add_perms(user, perms)
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
if "kfet.is_team" in perms:
|
2017-08-10 15:02:08 +02:00
|
|
|
account.change_pwd(kfet_pwd)
|
|
|
|
account.save()
|
|
|
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
def create_user(username="user", trigramme="000", **kwargs):
|
2017-09-01 13:35:32 +02:00
|
|
|
"""
|
|
|
|
Create a user without any permission and its kfet account.
|
|
|
|
|
|
|
|
username and trigramme are accepted as arguments (defaults to 'user' and
|
|
|
|
'000').
|
|
|
|
|
|
|
|
user_attrs, account_attrs and perms can be given as keyword arguments to
|
|
|
|
customize the user and its kfet account.
|
|
|
|
|
|
|
|
# Default values
|
|
|
|
|
|
|
|
User
|
|
|
|
* username: user
|
|
|
|
* password: user
|
|
|
|
* first_name: first
|
|
|
|
* last_name: last
|
|
|
|
* email: mail@user.net
|
|
|
|
Account
|
|
|
|
* trigramme: 000
|
|
|
|
|
|
|
|
"""
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs = kwargs.setdefault("user_attrs", {})
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs.setdefault("username", username)
|
|
|
|
user_attrs.setdefault("first_name", "first")
|
|
|
|
user_attrs.setdefault("last_name", "last")
|
|
|
|
user_attrs.setdefault("email", "mail@user.net")
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
account_attrs = kwargs.setdefault("account_attrs", {})
|
|
|
|
account_attrs.setdefault("trigramme", trigramme)
|
2017-08-10 15:02:08 +02:00
|
|
|
|
|
|
|
return _create_user_and_account(**kwargs)
|
|
|
|
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
def create_team(username="team", trigramme="100", **kwargs):
|
2017-09-01 13:35:32 +02:00
|
|
|
"""
|
|
|
|
Create a user, member of the kfet team, and its kfet account.
|
|
|
|
|
|
|
|
username and trigramme are accepted as arguments (defaults to 'team' and
|
|
|
|
'100').
|
|
|
|
|
|
|
|
user_attrs, account_attrs and perms can be given as keyword arguments to
|
|
|
|
customize the user and its kfet account.
|
|
|
|
|
|
|
|
# Default values
|
|
|
|
|
|
|
|
User
|
|
|
|
* username: team
|
|
|
|
* password: team
|
|
|
|
* first_name: team
|
|
|
|
* last_name: member
|
|
|
|
* email: mail@team.net
|
|
|
|
Account
|
|
|
|
* trigramme: 100
|
|
|
|
* kfet password: kfetpwd_team
|
|
|
|
|
|
|
|
"""
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs = kwargs.setdefault("user_attrs", {})
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs.setdefault("username", username)
|
|
|
|
user_attrs.setdefault("first_name", "team")
|
|
|
|
user_attrs.setdefault("last_name", "member")
|
|
|
|
user_attrs.setdefault("email", "mail@team.net")
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
account_attrs = kwargs.setdefault("account_attrs", {})
|
|
|
|
account_attrs.setdefault("trigramme", trigramme)
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
perms = kwargs.setdefault("perms", [])
|
|
|
|
perms.append("kfet.is_team")
|
2017-08-10 15:02:08 +02:00
|
|
|
|
|
|
|
return _create_user_and_account(**kwargs)
|
|
|
|
|
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
def create_root(username="root", trigramme="200", **kwargs):
|
2017-09-01 13:35:32 +02:00
|
|
|
"""
|
|
|
|
Create a superuser and its kfet account.
|
|
|
|
|
|
|
|
username and trigramme are accepted as arguments (defaults to 'root' and
|
|
|
|
'200').
|
|
|
|
|
|
|
|
user_attrs, account_attrs and perms can be given as keyword arguments to
|
|
|
|
customize the user and its kfet account.
|
|
|
|
|
|
|
|
# Default values
|
|
|
|
|
|
|
|
User
|
|
|
|
* username: root
|
|
|
|
* password: root
|
|
|
|
* first_name: super
|
|
|
|
* last_name: user
|
|
|
|
* email: mail@root.net
|
|
|
|
* is_staff, is_superuser: True
|
|
|
|
Account
|
|
|
|
* trigramme: 200
|
|
|
|
* kfet password: kfetpwd_root
|
|
|
|
|
|
|
|
"""
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs = kwargs.setdefault("user_attrs", {})
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
user_attrs.setdefault("username", username)
|
|
|
|
user_attrs.setdefault("first_name", "super")
|
|
|
|
user_attrs.setdefault("last_name", "user")
|
|
|
|
user_attrs.setdefault("email", "mail@root.net")
|
|
|
|
user_attrs["is_superuser"] = user_attrs["is_staff"] = True
|
2017-08-10 15:02:08 +02:00
|
|
|
|
2018-10-06 12:35:49 +02:00
|
|
|
account_attrs = kwargs.setdefault("account_attrs", {})
|
|
|
|
account_attrs.setdefault("trigramme", trigramme)
|
2017-08-10 15:02:08 +02:00
|
|
|
|
|
|
|
return _create_user_and_account(**kwargs)
|
2017-08-16 17:45:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_perms(*labels):
|
2017-09-01 13:35:32 +02:00
|
|
|
"""Return Permission instances from a list of '<app>.<perm_codename>'."""
|
2017-08-16 17:45:59 +02:00
|
|
|
perms = {}
|
|
|
|
for label in set(labels):
|
2018-10-06 12:35:49 +02:00
|
|
|
app_label, codename = label.split(".", 1)
|
2017-08-16 17:45:59 +02:00
|
|
|
perms[label] = Permission.objects.get(
|
2018-10-06 12:35:49 +02:00
|
|
|
content_type__app_label=app_label, codename=codename
|
2017-08-16 17:45:59 +02:00
|
|
|
)
|
|
|
|
return perms
|
|
|
|
|
|
|
|
|
|
|
|
def user_add_perms(user, perms_labels):
|
|
|
|
"""
|
|
|
|
Add perms to a user.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
user (User instance)
|
|
|
|
perms (list of str 'app.perm_name')
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The same user (refetched from DB to avoid missing perms)
|
|
|
|
|
|
|
|
"""
|
|
|
|
perms = get_perms(*perms_labels)
|
|
|
|
user.user_permissions.add(*perms.values())
|
|
|
|
|
|
|
|
# If permissions have already been fetched for this user, we need to reload
|
|
|
|
# it to avoid using of the previous permissions cache.
|
2017-11-19 18:41:39 +01:00
|
|
|
# https://docs.djangoproject.com/en/dev/topics/auth/default/#permission-caching
|
2017-08-16 17:45:59 +02:00
|
|
|
return User.objects.get(pk=user.pk)
|
2018-10-04 14:18:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
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)
|