Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Balance mailing #24

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions borgia/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ['celery_app']"""
38 changes: 38 additions & 0 deletions borgia/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from __future__ import absolute_import, unicode_literals

import os
from celery import Celery, chain
from celery.schedules import crontab
from users.tasks import scan_mailing_balance_alert

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'borgia.settings')
"""import django
from django.conf import settings
settings.configure()
django.setup()"""

# set the default Django settings module for the 'celery' program.
app = Celery('borgia', backend='rpc://', broker='pyamqp://')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

# Console log
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))


@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
sender.add_periodic_task(
5,
scan_mailing_balance_alert.s(),
name='Alert mailing'
)
6 changes: 5 additions & 1 deletion borgia/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
'modules',
'stocks',
'graphene_django',
'static_precompiler'
'static_precompiler',
'django_celery_results'
]

MIDDLEWARE_CLASSES = [
Expand Down Expand Up @@ -221,3 +222,6 @@

CENTER_NAME = "Center Name"
DEFAULT_TEMPLATE = "light" #Default template, en minuscule

# Celery
CELERY_RESULT_BACKEND = 'django-db'
13 changes: 13 additions & 0 deletions borgia/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from modules.views import *
from notifications.views import *
from stocks.views import *
from settings_data.views import GlobalConfig, PriceConfig, LydiaConfig, BalanceConfig
from api.Schema.main import schema
from graphene_django.views import GraphQLView
from api.views import AuthGenerateJWT, AuthVerifyJWT, AuthInvalidateJWT, GraphQLJwtProtectedView
Expand All @@ -45,6 +46,18 @@
url(r'^jwt/token/(?P<token>.+)/(?P<pk>\d+).json$', AuthVerifyJWT.as_view()),
url(r'^jwt/invalidate/(?P<token>.+)/(?P<pk>\d+).json$', AuthInvalidateJWT.as_view()),

#####################
# CONFIG #
#####################
url(r'^(?P<group_name>[\w-]+)/config/$',
GlobalConfig.as_view(), name='url_global_config'),
url(r'^(?P<group_name>[\w-]+)/config/price/$',
PriceConfig.as_view(), name='url_price_config'),
url(r'^(?P<group_name>[\w-]+)/config/lydia/$',
LydiaConfig.as_view(), name='url_lydia_config'),
url(r'^(?P<group_name>[\w-]+)/config/balance/$',
BalanceConfig.as_view(), name='url_balance_config'),

#####################
# WORKBOARDS #
#####################
Expand Down
15 changes: 15 additions & 0 deletions borgia/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,21 @@ def lateral_menu(user, group, active=None):
except ValueError:
pass

# Global config
try:
if (Permission.objects.get(codename='change_setting')
in group.permissions.all()):
nav_tree.append(simple_lateral_link(
label='Configuration',
faIcon='cogs',
id='lm_global_config',
url=reverse(
'url_global_config',
kwargs={'group_name': group.name})
))
except ObjectDoesNotExist:
pass

if active is not None:
for link in nav_tree:
try:
Expand Down
Binary file added celerybeat-schedule.db
Binary file not shown.
3 changes: 2 additions & 1 deletion finances/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,9 @@ def __init__(self, **kwargs):
min_value = kwargs.pop('min_value')
max_value = kwargs.pop('max_value')
super(SelfLydiaCreateForm, self).__init__(**kwargs)
self.fields['amount'] = forms.IntegerField(
self.fields['amount'] = forms.DecimalField(
label='Montant (€)',
decimal_places=2, max_digits=9,
min_value=min_value,
max_value=max_value)
self.fields['tel_number'] = forms.CharField(
Expand Down
5 changes: 3 additions & 2 deletions finances/templates/finances/self_lydia_button.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% extends 'base_sober.html' %}
{% load static %}
{% load l10n %}
{% load bootstrap %}

{% block content %}
Expand All @@ -13,7 +14,7 @@
<form>
<div class="form-group">
<label>Montant (€) :</label>
<input type="email" class="form-control" disabled="disabled" value="{{ amount }}" />
<input type="number" class="form-control" disabled="disabled" value="{{ amount|unlocalize }}" />
</div>
<div class="form-group">
<label>Numéro de téléphone </label>
Expand All @@ -28,7 +29,7 @@
<script type="text/javascript">
$(document).ready(function() {
$('#lydiaButton').payWithLYDIA({
amount: {{ amount }},
amount: {{ amount|unlocalize }},
vendor_token: '{{ vendor_token }}',
recipient: '{{ tel_number }}', //cellphone or email of your client
message : '{{ message }}', //object of the payment
Expand Down
23 changes: 19 additions & 4 deletions finances/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,16 +1070,31 @@ class SelfLydiaCreate(GroupPermissionMixin, FormView,

def get_form_kwargs(self):
kwargs = super(SelfLydiaCreate, self).get_form_kwargs()

# Min value is always 0.01
try:
kwargs['min_value'] = Setting.objects.get(
min_value = Setting.objects.get(
name='LYDIA_MIN_PRICE').get_value()
if min_value is not None:
if min_value > 0:
kwargs['min_value'] = Decimal(min_value)
else:
kwargs['min_value'] = Decimal("0.01")
else:
kwargs['min_value'] = Decimal("0.01")
except ObjectDoesNotExist:
kwargs['min_value'] = 0
kwargs['min_value'] = Decimal("0.01")

try:
kwargs['max_value'] = Setting.objects.get(
max_value = Setting.objects.get(
name='LYDIA_MAX_PRICE').get_value()
if max_value is not None:
kwargs['max_value'] = Decimal(max_value)
else:
kwargs['max_value'] = None
except ObjectDoesNotExist:
kwargs['max_value'] = 1000
kwargs['max_value'] = None

return kwargs

def form_valid(self, form):
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ six==1.10.0
typing==3.6.2
django-static-precompiler==1.6
openpyxl==2.4.9
celery
django-celery-results==1.0.1
33 changes: 29 additions & 4 deletions settings_data/fixtures/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"pk": 1,
"fields": {
"name": "LYDIA_MIN_PRICE",
"description": "Valeur minimale (€) de rechargement en automatique par Lydia",
"description":
"Valeur minimale (€) de rechargement en automatique par Lydia",
"value": "5",
"value_type": "f"
}
Expand All @@ -14,19 +15,43 @@
"pk": 2,
"fields": {
"name": "LYDIA_MAX_PRICE",
"description": "Valeur maximale (€) de rechargement en automatique par Lydia",
"description":
"Valeur maximale (€) de rechargement en automatique par Lydia",
"value": "500",
"value_type": "f"
}
},
{
{
"model": "settings_data.setting",
"pk": 3,
"fields": {
"name": "MARGIN_PROFIT",
"description": "Marge (%) à appliquer sur le prix des produits calculés automatiquement",
"description":
"Marge (%) à appliquer sur le prix des produits calculés automatiquement",
"value": "5",
"value_type": "f"
}
},
{
"model": "settings_data.setting",
"pk": 4,
"fields": {
"name": "BALANCE_THRESHOLD_MAIL_ALERT",
"description":
"Valeur seuil (€) en dessous de laquelle (strictement) l'alerte par email est activée",
"value": "-10",
"value_type": "f"
}
},
{
"model": "settings_data.setting",
"pk": 4,
"fields": {
"name": "BALANCE_FREQUENCY_MAIL_ALERT",
"description":
"Fréquence (jours) à laquelle l'alerte mail est envoyée si le solde est inférieur à la valeur seuil",
"value": "7",
"value_type": "i"
}
}
]
27 changes: 0 additions & 27 deletions settings_data/form.py

This file was deleted.

44 changes: 44 additions & 0 deletions settings_data/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator


class PriceConfigForm(forms.Form):
margin_profit = forms.DecimalField(label='Marge appliquée aux prix en mode automatique',
decimal_places=2, max_digits=9,
validators=[
MinValueValidator(0, 'Le montant doit être positif')])


class LydiaConfigForm(forms.Form):
lydia_min_price = forms.DecimalField(label='Montant minimal de rechargement',
decimal_places=2, max_digits=9,
validators=[
MinValueValidator(0, 'Le montant doit être positif')],
required=False)
lydia_max_price = forms.DecimalField(label='Montant maximal de rechargement',
decimal_places=2, max_digits=9,
validators=[
MinValueValidator(0, 'Le montant doit être positif')],
required=False)
def clean(self):
"""
If min and max:
max >= min
"""
cleaned_data = super(LydiaConfigForm, self).clean()
lydia_min_price = cleaned_data.get("lydia_min_price", None)
lydia_max_price = cleaned_data.get("lydia_max_price", None)
if lydia_min_price is not None and lydia_max_price is not None:
if lydia_max_price < lydia_min_price:
raise ValidationError("Le montant maximal doit être supérieur ou égal au montant minimal")


class BalanceConfigForm(forms.Form):
balance_threshold_mail_alert = forms.DecimalField(label='Valeur seuil',
decimal_places=2, max_digits=9,
required=False)
balance_frequency_mail_alert = forms.IntegerField(label='Fréquence des emails d\'alerte',
validators=[
MinValueValidator(1, 'La fréquence doit être d\'au moins 1 jour')],
required=False)
5 changes: 4 additions & 1 deletion settings_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ def get_value(self):
if type(self.value) is bool:
return self.value
else:
return types[self.value_type](self.value)
try:
return types[self.value_type](self.value)
except ValueError:
return None

class Meta:
permissions = (
Expand Down
17 changes: 17 additions & 0 deletions settings_data/templates/settings_data/balance_config.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends 'base_sober.html' %}
{% load bootstrap %}

{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
Configuration des porte monnaies
</div>
<div class="panel-body">
<form method="post">
{% csrf_token %}
{{ form|bootstrap }}
<button class="btn btn-success" type="submit">Valider</button>
</form>
</div>
</div>
{% endblock %}
Loading