Created
January 28, 2021 15:38
-
-
Save Vasiliy566/bbe44b094c5cd9559c18fcbc4c67f0df to your computer and use it in GitHub Desktop.
BusinessAnalytics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django import forms | |
from django.contrib.auth.forms import AuthenticationForm | |
from django.contrib.auth.models import User | |
from .models import Deal | |
class AuthUserForm(AuthenticationForm, forms.ModelForm): | |
class Meta: | |
model = User | |
fields = ['username', 'password'] | |
def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
for field in self.fields: | |
self.fields[field].widget.attrs['class'] = 'form-control' | |
self.fields[field].help_text = None; | |
self.fields[field].label = "" | |
self.fields['username'].widget.attrs['placeholder'] = 'Логин' | |
self.fields['password'].widget.attrs['placeholder'] = 'Пароль' | |
self.fields['username'].widget.attrs['class'] = 'form-control mb-3' | |
class RegisterUserForm(forms.ModelForm): | |
class Meta: | |
model = User | |
fields = ['username', 'password'] | |
def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
for field in self.fields: | |
self.fields[field].widget.attrs['class'] = 'form-control' | |
self.fields[field].help_text = None; | |
self.fields[field].label = "" | |
self.fields['username'].widget.attrs['placeholder'] = 'Логин' | |
self.fields['password'].widget.attrs['placeholder'] = 'Пароль' | |
self.fields['username'].widget.attrs['class'] = 'form-control mb-3' | |
def save(self, commit=True): | |
user = super().save(commit=False) | |
user.set_password(self.cleaned_data["password"]) | |
if commit: | |
user.save() | |
return user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from django.contrib.postgres.fields import ArrayField | |
from django.db.models import JSONField | |
class Customer(models.Model): | |
""" | |
таблица организаций делающих заказы | |
""" | |
name_of_organisation = models.CharField('organisation`s name', max_length=200, unique=True) | |
def __str__(self): | |
return self.name_of_organisation | |
class Manager(models.Model): | |
""" | |
таблица менеджеров продающих товар | |
""" | |
manager_name = models.CharField('manager`s name', max_length=100, unique=True) | |
def __str__(self): | |
return self.manager_name | |
class Deal(models.Model): | |
""" | |
таблица сделок совершонных менеджером manager для покупателя customer | |
""" | |
customer = models.ForeignKey(Customer, on_delete=models.CASCADE) | |
manager = models.ForeignKey(Manager, on_delete=models.CASCADE) | |
date = models.DateField('date of drop off Shipping_date') | |
profit = models.FloatField() | |
payment_format = models.TextField('Формат оплаты', blank=True) | |
name_of_money_recipient = models.TextField('Фамилия получившего деньги по наличной сделке', blank=True) | |
date_of_receipt_of_money_cache = models.TextField('Дата получания денег по наличной сделке', blank=True) | |
payment_order_material = models.TextField('Материал заказа по платёжке', blank=True) | |
adress = models.TextField('АДРЕС', blank=True) | |
payment_amount = models.TextField('Объём заказа по платёжке заказчика', blank=True) | |
order_unit = models.TextField('Единица измерения заказа', blank=True) | |
unit_price_for_customer = models.TextField('Цена за единицу измерения для заказчика', blank=True) | |
actual_volume_received_by_the_customer = models.TextField('Фактически полученный объём заказчиком', blank=True) | |
Deal_balance_surplus_missed = models.TextField('Сальдо по сделке ++ излишки —— недовезли', blank=True) | |
payable_by_customer = models.FloatField('к оплате заказчиком') | |
the_date_of_payment = models.TextField('дата оплаты', blank=True) | |
Name_of_supplier_organization = models.TextField('Наименование организации поставщика', blank=True) | |
Form_No = models.TextField('№ по форме', blank=True) | |
Shipping_date = models.TextField('дата отгрузки', blank=True) | |
Amount_of_order_by_invoice_from_supplier = models.TextField('Объём заказа по счету от поставщика', blank=True) | |
Unit_price_from_supplier = models.TextField('Цена за единицу измерения от поставщика', blank=True) | |
Transportation_cost = models.TextField('Стоимость перевозки', blank=True) | |
Actual_shipped_volume_by_supplier = models.TextField('Фактически отгруженный объём поставщиком', blank=True) | |
The_balance_of_the_suppliers_deal_surplus_not_delivered = models.TextField('Сальдо по сделке у поставщика ++ излишки — недовезли', blank=True) | |
Payable_to_supplier = models.TextField('К оплате поставщику', blank=True) | |
Invoice_number_from_carrier = models.TextField('№ счета от перевозчика', blank=True) | |
Carrier = models.TextField('Перевозчик', blank=True) | |
Logist = models.TextField('Логист', blank=True) | |
def __str__(self): | |
return str(self.customer) + "_" + str(self.manager) + "_" + \ | |
str(self.date) + "_" + str(self.profit) | |
# objects = models.Manager() | |
class ApiStats(models.Model): | |
""" | |
таблица с данными по api ( вывод апи для этого поля - [A, B, C]) | |
""" | |
name_of_api = models.CharField('api name', max_length=200, unique=True) | |
conversation = ArrayField( | |
models.FloatField(), size=3, | |
) | |
created = models.DateTimeField(auto_now_add=True) | |
updated = models.DateTimeField(auto_now=True) | |
class ApiStatsJson(models.Model): | |
""" | |
таблица с данными по api ( вывод апи для этого поля - [[strings], [floats]] | |
""" | |
name_of_api = models.CharField('api name', max_length=200, unique=True) | |
conversation = ArrayField( | |
JSONField(), size=3, | |
) | |
created = models.DateTimeField(auto_now_add=True) | |
updated = models.DateTimeField(auto_now=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
import logging | |
from apscheduler.schedulers.background import BackgroundScheduler | |
from django.contrib.auth.mixins import LoginRequiredMixin | |
from django.contrib.auth.models import User | |
from django.contrib.auth.views import LoginView, LogoutView | |
from django.shortcuts import render, redirect | |
from django.http import HttpResponseRedirect, HttpResponseForbidden | |
from django.http import HttpResponseNotFound | |
from django.urls import reverse_lazy | |
from django.views import View | |
from django.views.generic import CreateView | |
from .businesslogic.apis import get_apis_stats, recreate_googlesheet | |
from .forms import AuthUserForm, RegisterUserForm | |
from .models import Customer, Manager, Deal | |
from .businesslogic.metrics_calculator import profit_last_days, proceeds_last_days, \ | |
get_average_check_last_days, get_profitability_last_days, get_amount_new_customers_last_days, \ | |
get_managers_info_last_days, get_profit_from_new_customers_last_n_days, set_all_data_into_BD_from_exel, \ | |
get_managers_bounty | |
from .businesslogic.common.utils import get_config | |
logger = logging.getLogger(__name__) | |
config = get_config() | |
class DealView(LoginRequiredMixin, View): | |
""" | |
отдает таблицу сделок авторизированного пользователя | |
""" | |
def get(self, request): | |
manager, created1 = Manager.objects.get_or_create( | |
manager_name=request.user | |
) | |
deal = Deal.objects.filter(manager=manager) | |
return render(request, "singlepage/table.html", {"deal": deal}) | |
class SalaryView(LoginRequiredMixin, View): | |
""" | |
отдает таблицу сделок авторизированного пользователя | |
""" | |
def get(self, request): | |
manager, created1 = Manager.objects.get_or_create( | |
manager_name=request.user | |
) | |
bounty = get_managers_bounty()[str(manager.manager_name)] | |
api_stats = get_apis_stats() | |
if manager in api_stats["ncalls_for_managers"]["7days"]: | |
ncalls = api_stats["ncalls_for_managers"]["7days"][manager] | |
else: | |
ncalls = 0 | |
return render(request, "singlepage/salary.html", | |
{"bounty": bounty, | |
"ncalls": ncalls}) | |
class SummaryView(LoginRequiredMixin, View): | |
""" | |
отдает сводку только для ADMIN | |
""" | |
target_dates = ["1days", "3days", "7days"] | |
def get(self, request): | |
def generate_dates_results(calculate_function): | |
return {date: calculate_function(i) for date, i in zip(self.target_dates, [1, 3, 7])} | |
if str(request.user) != config["admin"]: | |
return HttpResponseForbidden() | |
api_stats = get_apis_stats() | |
set_all_data_into_BD_from_exel() | |
profit = generate_dates_results(profit_last_days) | |
proceeds_arr = [proceeds_last_days(n) for n in [1, 3, 7]] | |
proceeds = {date: proceeds_arr[i] for date, i in zip(self.target_dates, [0, 1, 2])} | |
avg_check = generate_dates_results(get_average_check_last_days) | |
profitability = generate_dates_results(get_profitability_last_days) | |
new_customers = generate_dates_results(get_amount_new_customers_last_days) | |
sales_plan_percent = {date: round(proceeds_arr[i] / config["sales_plan"] * 100, 1) | |
for date, i in zip(self.target_dates, [0, 1, 2])} | |
managers_ncalls = api_stats["ncalls_for_managers"] | |
managers = {"1days": get_managers_info_last_days(1, managers_ncalls["1days"]), | |
"3days": get_managers_info_last_days(3, managers_ncalls["3days"]), | |
"7days": get_managers_info_last_days(7, managers_ncalls["7days"]), | |
"updated": managers_ncalls["updated"]} | |
inc_applications = api_stats["inc_application"] | |
income_application = {date: inc_applications[date] for date in self.target_dates} | |
income_application.update({"updated":inc_applications["updated"]}) | |
income_application.update({"updated": income_application["updated"]}) | |
spending = api_stats["spendings"] | |
spending_on_advertising = api_stats["spendings"] | |
incoming_request_cost = {date: round(spending[date] / (inc_applications[date] + 0.0001), 1) for date in | |
self.target_dates} | |
incoming_request_cost.update({"updated": spending["updated"]}) | |
profit_from_new_customers = [get_profit_from_new_customers_last_n_days(n) for n in [1, 3, 7]] | |
effectiveness_of_investment = { | |
"1days": round(profit_from_new_customers[0] / (spending["1days"] + 0.00001) * 100, 1), | |
"3days": round(profit_from_new_customers[1] / (spending["3days"] + 0.00001) * 100, 1), | |
"7days": round(profit_from_new_customers[2] / (spending["7days"] + 0.00001) * 100, 1), | |
"updated": spending["updated"]} | |
# TODO : pass JSON to html @markpristup !!! | |
diagram = {date: [list(api_stats["sources_stat"][date].keys()), | |
list(api_stats["sources_stat"][date].values())] for date in self.target_dates} | |
diagram.update({"updated": api_stats["sources_stat"]["updated"]}) | |
return render(request, "singlepage/summary.html", | |
{"profit": profit, "proceeds": proceeds, "managers": managers, | |
"avg_check": avg_check, "profitability": profitability, "new_customers": new_customers, | |
"income_application": income_application, "spending_on_advertising": spending_on_advertising, | |
"incoming_request_cost": incoming_request_cost, "sales_plan_percent": sales_plan_percent, | |
"effectiveness_of_investment": effectiveness_of_investment, | |
"unique_visitors": api_stats["unique_visitors"], | |
"diagram": diagram, "outgoing_calls": api_stats["outgoing_calls"], }) | |
class WholeTableView(LoginRequiredMixin, View): | |
""" | |
отдаёт таблицу всех сделок только для ADMIN | |
""" | |
def get(self, request): | |
if str(request.user) != config["admin"]: | |
return HttpResponseForbidden() | |
deal = Deal.objects.all() | |
return render(request, "singlepage/table.html", {"deal": deal}) | |
class DealCreateView(LoginRequiredMixin, View): | |
def post(self, request): | |
manager, created1 = Manager.objects.get_or_create( | |
manager_name=request.user | |
) | |
customer, created2 = Customer.objects.get_or_create( | |
name_of_organisation=request.POST.get("name_of_organisation") | |
) | |
def validate(date_text): | |
try: | |
datetime.datetime.strptime(date_text, '%Y-%m-%d') | |
except ValueError: | |
raise ValueError("Incorrect data format, should be YYYY-MM-DD") | |
date = request.POST.get("data") | |
validate(date) | |
Deal.objects.create(customer=customer, manager=manager, | |
profit=request.POST.get("profit"), | |
date=date, | |
payment_format=request.POST.get("payment_format"), | |
payable_by_customer=request.POST.get("payable_by_customer"), | |
name_of_money_recipient=request.POST.get("name_of_money_recipient"), | |
date_of_receipt_of_money_cache=request.POST.get("date_of_receipt_of_money_cache"), | |
payment_order_material=request.POST.get("payment_order_material"), | |
adress=request.POST.get("adress"), | |
payment_amount=request.POST.get("payment_amount"), | |
order_unit=request.POST.get("order_unit"), | |
unit_price_for_customer=request.POST.get("unit_price_for_customer"), | |
actual_volume_received_by_the_customer=request.POST.get( | |
"actual_volume_received_by_the_customer"), | |
Deal_balance_surplus_missed=request.POST.get("Deal_balance_surplus_missed"), | |
the_date_of_payment=request.POST.get("the_date_of_payment"), | |
Name_of_supplier_organization=request.POST.get("Name_of_supplier_organization"), | |
Form_No=max([int(x["Form_No"]) for x in list(Deal.objects.all().values("Form_No"))]) + 1, | |
Shipping_date=request.POST.get("Shipping_date"), | |
Amount_of_order_by_invoice_from_supplier=request.POST.get( | |
"Amount_of_order_by_invoice_from_supplier"), | |
Unit_price_from_supplier=request.POST.get("Unit_price_from_supplier"), | |
Transportation_cost=request.POST.get("Transportation_cost"), | |
Actual_shipped_volume_by_supplier=request.POST.get("Actual_shipped_volume_by_supplier"), | |
The_balance_of_the_suppliers_deal_surplus_not_delivered=request.POST.get( | |
"The_balance_of_the_suppliers_deal_surplus_not_delivered"), | |
Payable_to_supplier=request.POST.get("Payable_to_supplier"), | |
Invoice_number_from_carrier=request.POST.get("Invoice_number_from_carrier"), | |
Carrier=request.POST.get("Carrier"), | |
Logist=request.POST.get("Logist") | |
) | |
return HttpResponseRedirect("/singlepage/") | |
def get(self, request): | |
customers = Customer.objects.all() | |
return render(request, "singlepage/create.html", {"customers": customers}) | |
# формирование excele | |
def excele(request): | |
if str(request.user) == config["admin"]: | |
scheduler = BackgroundScheduler() | |
scheduler.add_job(recreate_googlesheet, | |
'date', | |
run_date=datetime.datetime.now() | |
) | |
scheduler.start() | |
return redirect( | |
"https://docs.google.com/spreadsheets/d/180_nue-UMtotdZJmQFLXIyP0k9OArCHMWge0kldUreY/edit#gid=0") | |
else: | |
return HttpResponseForbidden() | |
# удаление данных из бд | |
def delete(request, id): | |
try: | |
deal = Deal.objects.get(id=id) | |
manager_name = deal.manager | |
if str(manager_name) == str(request.user) or str(request.user) == config["admin"]: | |
name_of_organisation = deal.customer | |
deal.delete() | |
if not Deal.objects.filter(manager=manager_name).exists(): | |
try: | |
manager = Manager.objects.get(manager_name=manager_name) | |
manager.delete() | |
except Manager.DoesNotExist: | |
pass | |
if not Deal.objects.filter(customer=name_of_organisation).exists(): | |
try: | |
customer = Customer.objects.get(name_of_organisation=name_of_organisation) | |
customer.delete() | |
except Customer.DoesNotExist: | |
pass | |
return HttpResponseRedirect("/singlepage/") | |
else: | |
return HttpResponseForbidden() | |
except Deal.DoesNotExist: | |
return HttpResponseNotFound("<h2>Person not found</h2>") | |
# изменение данных в бд | |
def edit(request, id): | |
try: | |
deal = Deal.objects.get(id=id) | |
if str(deal.manager) == str(request.user) or str(request.user) == config["admin"]: | |
if request.method == "POST": | |
''' | |
сначала создаем нового покупателя если надо; | |
если покупатель которого меняем(обязательно) присутствует только в одно сделке, | |
то получаем меняемое поле в Customer, записываем в строку нового покупателя, | |
а потом удаляем меняемое поле. | |
''' | |
customer, created1 = Customer.objects.get_or_create( | |
name_of_organisation=request.POST.get("name_of_organisation") | |
) | |
if Deal.objects.filter(customer=deal.customer).count() == 1 and \ | |
str(deal.customer) != str(request.POST.get("name_of_organisation")): | |
customer_to_delete = Customer.objects.get(name_of_organisation=deal.customer) | |
deal.customer = customer | |
customer_to_delete.delete() | |
else: | |
deal.customer = customer | |
deal.date = request.POST.get("data") | |
deal.profit = request.POST.get("profit") | |
deal.payment_format = request.POST.get("payment_format") | |
deal.payable_by_customer = request.POST.get("payable_by_customer") | |
deal.name_of_money_recipient = request.POST.get("name_of_money_recipient") | |
deal.date_of_receipt_of_money_cache = request.POST.get("date_of_receipt_of_money_cache") | |
deal.payment_order_material = request.POST.get("payment_order_material") | |
deal.adress = request.POST.get("adress") | |
deal.payment_amount = request.POST.get("payment_amount") | |
deal.order_unit = request.POST.get("order_unit") | |
deal.unit_price_for_customer = request.POST.get("unit_price_for_customer") | |
deal.actual_volume_received_by_the_customer = request.POST.get("actual_volume_received_by_the_customer") | |
deal.Deal_balance_surplus_missed = request.POST.get("Deal_balance_surplus_missed") | |
deal.the_date_of_payment = request.POST.get("the_date_of_payment") | |
deal.Name_of_supplier_organization = request.POST.get("Name_of_supplier_organization") | |
deal.Shipping_date = request.POST.get("Shipping_date") | |
deal.Amount_of_order_by_invoice_from_supplier = request.POST.get( | |
"Amount_of_order_by_invoice_from_supplier") | |
deal.Unit_price_from_supplier = request.POST.get("Unit_price_from_supplier") | |
deal.Transportation_cost = request.POST.get("Transportation_cost") | |
deal.Actual_shipped_volume_by_supplier = request.POST.get("Actual_shipped_volume_by_supplier") | |
deal.The_balance_of_the_suppliers_deal_surplus_not_delivered = request.POST.get( | |
"The_balance_of_the_suppliers_deal_surplus_not_delivered") | |
deal.Payable_to_supplier = request.POST.get("Payable_to_supplier") | |
deal.Invoice_number_from_carrier = request.POST.get("Invoice_number_from_carrier") | |
deal.Carrier = request.POST.get("Carrier") | |
deal.Logist = request.POST.get("Logist") | |
deal.save() | |
return HttpResponseRedirect("/singlepage/") | |
else: | |
return render(request, "singlepage/edit.html", {"deal": deal}) | |
else: | |
return HttpResponseForbidden() | |
except Deal.DoesNotExist: | |
return HttpResponseNotFound("<h2>Deal not found</h2>") | |
class MyLoginView(LoginView): | |
template_name = 'singlepage/login.html' | |
success_url = reverse_lazy('main') | |
form_class = AuthUserForm | |
def get_success_url(self): | |
return self.success_url | |
class MyLogoutView(LogoutView): | |
next_page = reverse_lazy('login_page') | |
class RegisterUserView(CreateView): | |
model = User | |
template_name = 'singlepage/register_page.html' | |
success_url = reverse_lazy('main') | |
form_class = RegisterUserForm | |
success_msg = "Пользователь успешно создан" | |
def get(self, request, *args, **kwargs): | |
if str(request.user) != config["admin"]: | |
return HttpResponseForbidden() | |
else: | |
return super().get(self, request, *args, **kwargs) | |
def post(self, request, *args, **kwargs): | |
if str(request.user) != config["admin"]: | |
return HttpResponseForbidden() | |
else: | |
return super().post(self, request, *args, **kwargs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment