BO 1.23 controlling, cron: sync customers

This commit is contained in:
Tibor Bossanyi (Freelancer) 2021-07-27 07:44:37 +02:00
parent ffbfe4c877
commit 3c02685ed6
26 changed files with 464 additions and 5 deletions

View File

@ -12,3 +12,4 @@ from .training_plan import TrainingPlanAdmin, TrainingPlanDetailAdmin
from .faq import FaqAdmin
from .split_tests import SplitTestAdmin
from .training_plan_day import TrainingPlanDayAdmin
from .controlling import ControllingAdmin

View File

@ -1,6 +1,9 @@
{% extends "admin/base_site.html" %}
{% block extrahead %}
<script>window.CKEDITOR_BASEPATH = '/static/ckeditor/ckeditor/';</script>
{{ block.super }}
{% endblock %}
{% endblock %}
{% block content %}
<p>Controlling</p>
{% endblock %}

View File

@ -0,0 +1,29 @@
from django.contrib import admin
from django.db import models
from django.urls import path
from django.http import HttpResponse
class Controlling(models.Model):
class Meta:
verbose_name_plural = 'Controlling'
app_label = 'aitrainer_backoffice'
def my_custom_view(request):
return HttpResponse('Admin Custom View')
class ControllingAdmin(admin.ModelAdmin):
model = Controlling
def get_urls(self):
view_name = '{}_{}_changelist'.format(
self.model._meta.app_label, self.model._meta.model_name)
return [
path('my_admin_path/', my_custom_view, name=view_name),
]
admin.site.register(Controlling, ControllingAdmin)
admin.autodiscover()

View File

@ -0,0 +1,22 @@
class TestRouter:
"""
A router to control all database operations on models
"""
live_app_labels = {'controlling'}
def db_for_read(self, model, **hints):
if model._meta.app_label == 'controlling':
return 'live'
else:
return 'default'
def db_for_write(self, model, **hints):
if model._meta.app_label == 'controlling':
raise Exception("This table cannot be changed!")
return 'default'
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model_name=None, **hints):
return False

View File

@ -15,3 +15,4 @@ from .training_plan import TrainingPlan, TrainingPlanDetail
from .faq import Faq, FaqTranslation
from .split_tests import SplitTests
from .training_plan_day import TrainingPlanDay, TrainingPlanDayTranslation
from .controlling import Controlling

View File

@ -0,0 +1,9 @@
from django.db import models
class Controlling(models.Model):
sort = models.IntegerField(blank=True)
class Meta:
verbose_name_plural = 'Controlling'
app_label = 'controlling'

View File

@ -0,0 +1,28 @@
from django.contrib import admin
class MultiDBModelAdmin(admin.ModelAdmin):
# A handy constant for the name of the alternate database.
using = 'default'
def save_model(self, request, obj, form, change):
# Tell Django to save objects to the 'other' database.
obj.save(using=self.using)
def delete_model(self, request, obj):
# Tell Django to delete objects from the 'other' database
obj.delete(using=self.using)
def get_queryset(self, request):
# Tell Django to look for objects on the 'other' database.
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
# Tell Django to populate ForeignKey widgets using a query
# on the 'other' database.
return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs):
# Tell Django to populate ManyToMany widgets using a query
# on the 'other' database.
return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)

View File

@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
import os
BACKOFFICE_VERSION = 1.22
BACKOFFICE_VERSION = 1.23
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -38,6 +38,7 @@ ALLOWED_HOSTS = ['localhost']
INSTALLED_APPS = [
'aitrainer_backoffice',
'controlling.apps.ControllingConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -47,6 +48,8 @@ INSTALLED_APPS = [
'ckeditor',
'ckeditor_uploader',
'django_admin_json_editor',
'rangefilter',
'django_crontab'
]
MIDDLEWARE = [
@ -93,7 +96,7 @@ DATABASES = {
},
'live': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'aitrainer2',
'NAME': 'aitrainer',
'USER': 'aitrainer',
'PASSWORD': 'andio2009',
'HOST': '127.0.0.1',
@ -101,6 +104,8 @@ DATABASES = {
}
}
DATABASE_ROUTERS = ['aitrainer_backoffice.db_router.TestRouter']
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
@ -166,3 +171,7 @@ LOGGING = {
},
},
}
CRONJOBS = [
('4 */1 * * *', 'controlling.cron.sync_customers')
]

View File

@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
import os
BACKOFFICE_VERSION = 1.22
BACKOFFICE_VERSION = 1.23
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -34,6 +34,7 @@ ALLOWED_HOSTS = ['62.171.188.119', 'localhost', 'andio.eu', 'aitrainer.info','ai
INSTALLED_APPS = [
'aitrainer_backoffice.aitrainer_backoffice',
'controlling.apps.ControllingConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -43,6 +44,8 @@ INSTALLED_APPS = [
'ckeditor',
'ckeditor_uploader',
'django_admin_json_editor',
'rangefilter',
'django_crontab'
]
MIDDLEWARE = [
@ -89,6 +92,8 @@ DATABASES = {
}
}
DATABASE_ROUTERS = ['aitrainer_backoffice.db_router.TestRouter']
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
@ -170,3 +175,7 @@ CACHES = {
}
}
CRONJOBS = [
('4 */1 * * *', 'controlling.cron.sync_customers')
]

View File

@ -0,0 +1,12 @@
{% extends 'admin/change_list.html' %}
{% block object-tools %}
<div>
<form action="mautic/" method="POST">
{% csrf_token %}
<button type="submit">Mautic Sync</button>
</form>
</div>
<br />
{{ block.super }}
{% endblock %}

View File

@ -0,0 +1,3 @@
from .customer import CustomerAdmin
from .frequent_customers import FrequentCustomersAdmin
from .frequent_exercises import FrequentExerciseTypeAdmin

View File

@ -0,0 +1,83 @@
from abc import ABC
from datetime import datetime
from django.contrib.admin import SimpleListFilter
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin
from rangefilter.filters import DateRangeFilter, DateTimeRangeFilter
from django.urls import path
from ..models.customer import Customer
from ..models.customer import Sport
from ..mautic import MauticHelper
from ..cron import cron
class SportFilter(SimpleListFilter, ABC):
title = "Sport"
parameter_name = 'sport_id'
def lookups(self, request, model_admin):
data = []
for s in Sport.objects.filter():
data.append([s.sport_id, s.sport_name])
return data
def queryset(self, request, queryset):
if self.value():
return Customer.objects.filter(sport__sport_id=self.value())
else:
return queryset
class CustomerAdmin(admin.ModelAdmin):
change_list_template = "controlling/mautic.html"
list_display = ('customer_id', 'name','firstname', 'email', 'date_add', 'get_sport')
list_filter = (
('date_add', DateRangeFilter),
SportFilter
)
def get_sport(self, obj):
return obj.sport.sport_name
get_sport.short_description = 'Sport'
get_sport.admin_order_field = 'sport__sport_name'
# If you would like to add a default range filter
# method pattern "get_rangefilter_{field_name}_default"
def get_rangefilter_date_add_default(self, request):
return (datetime.today(), datetime.today())
# If you would like to change a title range filter
# method pattern "get_rangefilter_{field_name}_title"
def get_rangefilter_date_add_title(self, request, field_path):
return _('Registered')
def changelist_view(self, request, extra_context=None):
if not request.GET.__contains__('date_add__range__gte'):
q = request.GET.copy()
q['date_add__range__gte'] = datetime.today()
q['date_add__range__lte'] = datetime.today()
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(CustomerAdmin, self).changelist_view(
request, extra_context=extra_context)
def get_urls(self):
urls = super().get_urls()
my_urls = [
path('mautic/', self.set_mautic),
]
return my_urls + urls
def set_mautic(self, request):
cron.sync_customers()
self.message_user(request, "All heroes are now synced")
return HttpResponseRedirect("../")
admin.site.register(Customer, CustomerAdmin)
admin.autodiscover()

View File

@ -0,0 +1,24 @@
from django.contrib import admin
from ..models.frequent_customers import FrequentCustomers
class FrequentCustomersAdmin(admin.ModelAdmin):
list_display = ('customer_id', 'name', 'firstname', 'email', 'exercise_count')
#def get_queryset(self, request):
# qs = super(FrequentCustomersAdmin, self).get_queryset(request)
# return FrequentCustomers.objects.extra(
# select=["customer_id, name, firstname, email, ( select count(exercise_id) from exercises where exercises.customer_id = customer_customer.id) as exercise_count "],
#group_by=["customer_id"],
#having=["exercise_count > 10"],
# order_by=["-exercise_count"]
#)
#return qs.values("exercises").annotate(exercise_count=Count('exercises')).order_by('-exercise_count')
#return Exercises.objects.annotate(count=Count("customer__customer_id"))
#return qs.values('user').annotate(visit_sum=Count('visit_count')).order_by('-visit_sum')
admin.site.register(FrequentCustomers, FrequentCustomersAdmin)
admin.autodiscover()

View File

@ -0,0 +1,15 @@
from django.contrib import admin
from ..models import ExerciseType
class FrequentExerciseTypeAdmin(admin.ModelAdmin):
list_display = ('exercise_type_id', 'name', 'exercise_count')
def get_queryset(self, request):
qs = super(FrequentExerciseTypeAdmin, self).get_queryset(request)
return qs.filter(active=True)
admin.site.register(ExerciseType, FrequentExerciseTypeAdmin)
admin.autodiscover()

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ControllingConfig(AppConfig):
app_label = 'controlling'
name = 'controlling'

View File

@ -0,0 +1,6 @@
from ..mautic import MauticHelper
def sync_customers():
helper = MauticHelper()
helper.sync()

View File

@ -0,0 +1 @@
from .helper import MauticHelper

View File

@ -0,0 +1,71 @@
import requests
import logging
from django.db import connections
from ..models.customer import Customer
class MauticHelper:
def sync(self):
logger = logging.getLogger(__name__)
logger.info("Syncronising...")
last_synced_date = self.get_last_synced_date()
if len(last_synced_date) != 0:
qs = Customer.objects.raw(
'SELECT * from customer WHERE date_add > "' + last_synced_date + '" and synced_date is null')
else:
qs = Customer.objects.raw(
'SELECT * from customer WHERE synced_date is null')
headers = {
'content-type': "application/x-www-form-urlencoded",
'cache-control': "no-cache"
}
index = 0
for customer in qs:
goal = customer.goal if customer.goal is not None else ""
fitness_level = customer.fitness_level if customer.fitness_level is not None else ""
data = "mauticform[email]=" + customer.email + \
"&mauticform[f_name]=" + customer.name + \
"&mauticform[firstname]=" + customer.firstname + \
"&mauticform[goal]=" + goal + \
"&mauticform[fitness_level]=" + fitness_level + \
"&mauticform[subscribed]=" + str(customer.date_add) + \
"&mauticform[database_id]=" + str(customer.customer_id) + \
"&mauticform[formId]=1" + \
"&mauticform[formName]=appsync"
print(data)
form_url = 'https://mautic.aitrainer.app/form/submit?formId=1'
response = requests.post(form_url, data=data.encode('utf-8'), headers=headers)
print(str(response.status_code))
if response.status_code == 200:
with connections["live"].cursor() as cursor:
cursor.execute("UPDATE customer SET synced_date = NOW() WHERE customer_id="
+ str(customer.customer_id))
#if index == 0:
# break
index = index + 1
logger.info("Syncronised customer count: " + str(index))
return True
def get_last_synced_date(self):
qs = Customer.objects.raw('SELECT customer_id, max(synced_date) as synced_date from customer')
for c in qs:
if c.synced_date is None:
return ""
synced_date = c.synced_date.strftime('%Y-%m-%d')
print(synced_date)
return synced_date
def sync_frequent_users(self):
print("SYNC FREQ USERS")
return True

View File

@ -0,0 +1,4 @@
from .customer import Customer
from .exercises import Exercises
from .exercise_type import ExerciseType
from .frequent_customers import FrequentCustomers

View File

@ -0,0 +1,38 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Sport(models.Model):
sport_id = models.AutoField(primary_key = True)
language_code = models.CharField(max_length=2,default="hu")
sport_name = models.CharField(max_length=100)
class Meta:
db_table = 'sport_translation'
class Customer(models.Model):
customer_id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=100, help_text='Last name', verbose_name=_("name"))
firstname = models.CharField(max_length=100, help_text='First name', verbose_name=_("firstname"))
email = models.CharField(max_length=100)
sport = models.ForeignKey(Sport, on_delete=models.CASCADE)
goal = models.CharField(max_length=20)
fitness_level = models.CharField(max_length=20)
date_add = models.DateField()
synced_date = models.DateTimeField(blank=True,null=True)
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
class Meta:
db_table = 'customer'
verbose_name = _("Customer")
verbose_name_plural = _("Customers")
app_label = 'controlling'
def __str__(self):
return self.name

View File

@ -0,0 +1,28 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from ..models.exercises import Exercises
class ExerciseType(models.Model):
exercise_type_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
active = models.BooleanField()
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
@property
def exercise_count(self):
count = Exercises.objects.filter(exercise_type_id=self.exercise_type_id).count()
return count
class Meta:
db_table = 'exercise_type'
verbose_name = _("Frequent Exercise")
verbose_name_plural = _("Frequent Exercises")

View File

@ -0,0 +1,25 @@
from django.db import models
#from ..models.exercise_type import ExerciseType
from ..models.customer import Customer
class Exercises(models.Model):
exercise_id = models.BigAutoField(primary_key=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
exercise_type_id = models.IntegerField()
#exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
date_add = models.DateField()
quantity = models.DecimalField(decimal_places=0, max_digits=6)
unit = models.CharField(max_length=20)
unit_quantity = models.DecimalField(decimal_places=0, max_digits=6,blank=True, null=True)
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
class Meta:
db_table = 'exercises'

View File

@ -0,0 +1,32 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from .exercises import Exercises
class FrequentCustomers(models.Model):
customer_id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=100, help_text='Last name', verbose_name=_("name"))
firstname = models.CharField(max_length=100, help_text='First name', verbose_name=_("firstname"))
email = models.CharField(max_length=100)
date_add = models.DateField()
#exercises = models.ManyToManyField(Exercises)
#def exercises(self):
# exercises = Exercises.objects.filter(customer__customer_id=self.customer_id)
# return exercises
@property
def exercise_count(self):
count = Exercises.objects.filter(customer__customer_id=self.customer_id).count()
return count
class Meta:
db_table = 'customer'
verbose_name = _("Frequent Customer")
verbose_name_plural = _("Frequent Customers")
#ordering = ['exercise_count']
#filter(exercise_count__gt=10)
def __str__(self):
return self.name