forked from DGNum/gestioCOF
Rework validation et enregistrement opés K-Psul
- Utilisations d'update pour les balances et autres afin d'éviter les lost update - Validation tout en un puis enregistrement tout en un - Ajout du lien vers K-Psul dans le nav
This commit is contained in:
parent
7af7c03466
commit
51c1767ffe
2 changed files with 69 additions and 97 deletions
|
@ -13,6 +13,7 @@
|
||||||
{% if perms.kfet.is_team %}
|
{% if perms.kfet.is_team %}
|
||||||
Equipe
|
Equipe
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a href="{% url "kfet.kpsul" %}">K-Psul</a></li>
|
||||||
<li><a href="{% url "kfet.account" %}">Comptes</a></li>
|
<li><a href="{% url "kfet.account" %}">Comptes</a></li>
|
||||||
<li><a href="{% url "kfet.checkout" %}">Caisses</a></li>
|
<li><a href="{% url "kfet.checkout" %}">Caisses</a></li>
|
||||||
<li><a href="{% url "kfet.article" %}">Articles</a></li>
|
<li><a href="{% url "kfet.article" %}">Articles</a></li>
|
||||||
|
|
165
kfet/views.py
165
kfet/views.py
|
@ -398,34 +398,27 @@ def get_missing_perms(required_perms, user):
|
||||||
@permission_required('kfet.is_team')
|
@permission_required('kfet.is_team')
|
||||||
def kpsul_perform_operations(request):
|
def kpsul_perform_operations(request):
|
||||||
# Initializing response data
|
# Initializing response data
|
||||||
data = defaultdict(list)
|
data = { 'operation_group': 0, 'operations': [],
|
||||||
|
'warnings': {}, 'errors': {} }
|
||||||
|
|
||||||
# Checking operationgroup
|
# Checking operationgroup
|
||||||
operationgroup_form = KPsulOperationGroupForm(request.POST)
|
operationgroup_form = KPsulOperationGroupForm(request.POST)
|
||||||
if not operationgroup_form.is_valid():
|
if not operationgroup_form.is_valid():
|
||||||
data['errors'].append({'operation_group': list(operationgroup_form.errors)})
|
data['errors']['operation_group'] = list(operationgroup_form.errors)
|
||||||
|
|
||||||
# Checking operation_formset
|
# Checking operation_formset
|
||||||
operation_formset = KPsulOperationFormSet(request.POST)
|
operation_formset = KPsulOperationFormSet(request.POST)
|
||||||
if not operation_formset.is_valid():
|
if not operation_formset.is_valid():
|
||||||
data['errors'].append({'operations': list(operation_formset.errors) })
|
data['errors']['operations'] = list(operation_formset.errors)
|
||||||
|
|
||||||
# Returning BAD REQUEST if errors
|
# Returning BAD REQUEST if errors
|
||||||
if 'errors' in data:
|
if data['errors']:
|
||||||
return JsonResponse(data, status=400)
|
return JsonResponse(data, status=400)
|
||||||
|
|
||||||
# Pre-saving (no commit)
|
# Pre-saving (no commit)
|
||||||
operationgroup = operationgroup_form.save(commit = False)
|
operationgroup = operationgroup_form.save(commit = False)
|
||||||
operations = operation_formset.save(commit = False)
|
operations = operation_formset.save(commit = False)
|
||||||
|
|
||||||
# Specific account's checking
|
|
||||||
if operationgroup.on_acc.is_cash:
|
|
||||||
for operation in operations:
|
|
||||||
if operation.type in [Operation.DEPOSIT, Operation.WITHDRAW]:
|
|
||||||
data['errors'].append(
|
|
||||||
{'account': 'Charge et retrait impossible sur LIQ'})
|
|
||||||
return JsonResponse(data, status=400)
|
|
||||||
|
|
||||||
# Retrieving COF grant
|
# Retrieving COF grant
|
||||||
cof_grant = Settings.SUBVENTION_COF()
|
cof_grant = Settings.SUBVENTION_COF()
|
||||||
# Retrieving addcosts data
|
# Retrieving addcosts data
|
||||||
|
@ -433,121 +426,99 @@ def kpsul_perform_operations(request):
|
||||||
addcost_for = Settings.ADDCOST_FOR()
|
addcost_for = Settings.ADDCOST_FOR()
|
||||||
|
|
||||||
# Initializing vars
|
# Initializing vars
|
||||||
required_perms = set()
|
required_perms = set() # Required perms to perform all operations
|
||||||
cof_grant_divisor = 1 + cof_grant / 100
|
cof_grant_divisor = 1 + cof_grant / 100
|
||||||
|
to_addcost_for_balance = 0 # For balance of addcost_for
|
||||||
|
to_checkout_balance = 0 # For balance of selected checkout
|
||||||
|
to_articles_stocks = defaultdict(lambda:0) # For stocks articles
|
||||||
is_addcost = (addcost_for and addcost_amount
|
is_addcost = (addcost_for and addcost_amount
|
||||||
and addcost_for != operationgroup.on_acc)
|
and addcost_for != operationgroup.on_acc)
|
||||||
addcost_total = 0
|
|
||||||
to_checkout_balance = 0
|
|
||||||
|
|
||||||
# 1. Calculating amount of each PURCHASE operations
|
# Filling data of each operations + operationgroup + calculating other stuffs
|
||||||
# 1.1 Standard price for n articles
|
|
||||||
# 1.2 Adding addcost if there is one
|
|
||||||
# 1.3 Taking into account cof status
|
|
||||||
# 2. Updating (no commit) stock of article for PURCHASE operations
|
|
||||||
# 3. Calculating amount of operation group
|
|
||||||
# 4. Adding required permissions to perform each operation
|
|
||||||
# 5. Calculating total addcost
|
|
||||||
# and adding addcost_for in operation instance
|
|
||||||
# 6. Calculating diff for checkout's balance
|
|
||||||
for operation in operations:
|
for operation in operations:
|
||||||
if operation.type == Operation.PURCHASE:
|
if operation.type == Operation.PURCHASE:
|
||||||
# 1.1
|
|
||||||
operation.amount = - operation.article.price * operation.article_nb
|
operation.amount = - operation.article.price * operation.article_nb
|
||||||
if is_addcost:
|
if is_addcost:
|
||||||
# 1.2
|
operation.addcost_for = addcost_for
|
||||||
operation.addcost_amount = addcost_amount * operation.article_nb
|
operation.addcost_amount = addcost_amount * operation.article_nb
|
||||||
operation.amount -= operation.addcost_amount
|
operation.amount -= operation.addcost_amounty
|
||||||
# 5
|
to_addcost_for_balance += operation.addcost_amount
|
||||||
addcost_total += operation.addcost_amount
|
|
||||||
operation.addcost_for = addcost_for
|
|
||||||
# 6
|
|
||||||
if operationgroup.on_acc.is_cash:
|
if operationgroup.on_acc.is_cash:
|
||||||
to_checkout_balance += -operation.amount
|
to_checkout_balance += -operation.amount
|
||||||
# 1.3
|
|
||||||
if operationgroup.on_acc.is_cof:
|
if operationgroup.on_acc.is_cof:
|
||||||
operation.amount = operation.amount / cof_grant_divisor
|
operation.amount = operation.amount / cof_grant_divisor
|
||||||
# 2
|
to_articles_stocks[operation.article] -= operation.article_nb
|
||||||
operation.article.stock -= operation.article_nb
|
|
||||||
else:
|
else:
|
||||||
# Ope.type is deposit or withdraw
|
if operationgroup.on_acc.is_cash:
|
||||||
# 6 too
|
data['errors']['account'] = 'Charge et retrait impossible sur LIQ'
|
||||||
to_checkout_balance += operation.amount
|
to_checkout_balance += operation.amount
|
||||||
# 3
|
|
||||||
operationgroup.amount += operation.amount
|
operationgroup.amount += operation.amount
|
||||||
# 4
|
|
||||||
if operation.type == Operation.DEPOSIT:
|
if operation.type == Operation.DEPOSIT:
|
||||||
required_perms.add('kfet.perform_deposit')
|
required_perms.add('kfet.perform_deposit')
|
||||||
|
|
||||||
|
(perms, stop) = operationgroup.on_acc.perms_to_perform_operation(
|
||||||
|
amount = operationgroup.amount)
|
||||||
|
required_perms |= perms
|
||||||
|
|
||||||
|
if stop or not request.user.has_perms(required_perms):
|
||||||
|
missing_perms = get_missing_perms(required_perms, request.user)
|
||||||
|
if missing_perms:
|
||||||
|
data['errors']['missing_perms'] = missing_perms
|
||||||
|
if stop:
|
||||||
|
data['errors']['negative'] = True
|
||||||
|
return JsonResponse(data, status=403)
|
||||||
|
|
||||||
|
# If 1 perm is required, filling who perform the operations
|
||||||
|
if required_perms:
|
||||||
|
operationgroup.valid_by = request.user.profile.account_kfet
|
||||||
|
# Filling cof status for statistics
|
||||||
|
operationgroup.is_cof = operationgroup.on_acc.is_cof
|
||||||
|
|
||||||
# Starting transaction to ensure data consistency
|
# Starting transaction to ensure data consistency
|
||||||
# Using select_for_update where it is critical
|
with transaction.atomic():
|
||||||
try:
|
# If not cash account,
|
||||||
with transaction.atomic():
|
# saving account's balance and adding to Negative if not in
|
||||||
on_acc = operationgroup.on_acc
|
if not operationgroup.on_acc.is_cash:
|
||||||
on_acc = Account.objects.select_for_update().get(pk=on_acc.pk)
|
Account.objects.filter(pk=operationgroup.on_acc.pk).update(
|
||||||
# Adding required permissions to perform operation group
|
balance = F('balance') + operationgroup.amount)
|
||||||
(opegroup_perms, stop_ope) = on_acc.perms_to_perform_operation(
|
operationgroup.on_acc.refresh_from_db()
|
||||||
amount = operationgroup.amount)
|
if operationgroup.on_acc.balance < 0:
|
||||||
required_perms |= opegroup_perms
|
if hasattr(on_acc, 'negative'):
|
||||||
|
if not on_acc.negative.start:
|
||||||
# Checking authenticated user has all perms
|
on_acc.negative.start = timezone.now()
|
||||||
if stop_ope or not request.user.has_perms(required_perms):
|
on_acc.negative.save()
|
||||||
raise PermissionDenied
|
|
||||||
|
|
||||||
# If 1 perm is required, saving who perform the operations
|
|
||||||
if len(required_perms) > 0:
|
|
||||||
operationgroup.valid_by = request.user.profile.account_kfet
|
|
||||||
|
|
||||||
# Filling cof status for statistics
|
|
||||||
operationgroup.is_cof = on_acc.is_cof
|
|
||||||
|
|
||||||
# If not cash account,
|
|
||||||
# saving account's balance and adding to Negative if not in
|
|
||||||
if not on_acc.is_cash:
|
|
||||||
on_acc.balance += operationgroup.amount
|
|
||||||
on_acc.save()
|
|
||||||
if on_acc.balance < 0:
|
|
||||||
if hasattr(on_acc, 'negative'):
|
|
||||||
if not on_acc.negative.start:
|
|
||||||
on_acc.negative.start = timezone.now()
|
|
||||||
on_acc.negative.save()
|
|
||||||
else:
|
else:
|
||||||
negative = AccountNegative(
|
negative = AccountNegative(
|
||||||
account = on_acc, start = timezone.now())
|
account = operationgroup.on_acc, start = timezone.now())
|
||||||
negative.save()
|
negative.save()
|
||||||
elif (hasattr(on_acc, 'negative')
|
elif (hasattr(on_acc, 'negative')
|
||||||
and not on_acc.negative.balance_offset):
|
and not on_acc.negative.balance_offset):
|
||||||
on_acc.negative.delete()
|
on_acc.negative.delete()
|
||||||
|
|
||||||
# Updating checkout's balance
|
# Updating checkout's balance
|
||||||
operationgroup.checkout.balance += to_checkout_balance
|
if to_checkout_balance:
|
||||||
operationgroup.checkout.save()
|
Checkout.objects.filter(pk=operationgroup.checkout.pk).update(
|
||||||
|
balance = F('balance') + to_checkout_balance)
|
||||||
|
|
||||||
# Saving addcost_for with new balance if there is one
|
# Saving addcost_for with new balance if there is one
|
||||||
if is_addcost:
|
if is_addcost and to_addcost_for_balance:
|
||||||
addcost_for.balance += addcost_total
|
Account.objects.filter(pk=addcost_for.pk).update(
|
||||||
addcost_for.save()
|
balance = F('balance') + to_addcost_for_balance)
|
||||||
|
|
||||||
# Saving operation group
|
# Saving operation group
|
||||||
operationgroup.save()
|
operationgroup.save()
|
||||||
data['operationgroup'] = operationgroup.pk
|
data['operationgroup'] = operationgroup.pk
|
||||||
|
|
||||||
# Filling operationgroup id for each operations and saving
|
# Filling operationgroup id for each operations and saving
|
||||||
# Saving articles with new stock
|
for operation in operations:
|
||||||
for operation in operations:
|
operation.group = operationgroup
|
||||||
operation.group = operationgroup
|
operation.save()
|
||||||
operation.save()
|
data['operations'].append(operation.pk)
|
||||||
if operation.type == Operation.PURCHASE:
|
|
||||||
operation.article.save()
|
# Updating articles stock
|
||||||
data['operations'].append(operation.pk)
|
for article in to_articles_stocks:
|
||||||
except PermissionDenied:
|
Article.objects.filter(pk=article.pk).update(
|
||||||
# Sending BAD_REQUEST with missing perms or url to manage negative
|
stock = F('stock') + to_articles_stocks[article])
|
||||||
missing_perms = get_missing_perms(required_perms, request.user)
|
|
||||||
if missing_perms:
|
|
||||||
data['errors'].append({'missing_perms': missing_perms })
|
|
||||||
if stop_ope:
|
|
||||||
data['errors'].append({'negative': 'url to manage negative'})
|
|
||||||
return JsonResponse(data, status=403)
|
|
||||||
|
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue