Fix in Requests + in Report part
This commit is contained in:
@@ -1,21 +1,67 @@
|
|||||||
from flask import request, Blueprint, render_template
|
from flask import request, Blueprint, render_template, session, url_for
|
||||||
from checker import check_auth
|
from checker import check_auth
|
||||||
from os import path
|
from os import path
|
||||||
|
from .report_model import sales_report, make_report
|
||||||
import json
|
import json
|
||||||
|
|
||||||
with open(path.join(path.dirname(__file__), 'reports.json')) as f:
|
with open(path.join(path.dirname(__file__), 'reports.json')) as f:
|
||||||
report_list = json.load(f)
|
report_list = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
report_bp = Blueprint('report_bp', __name__, template_folder='templates')
|
report_bp = Blueprint('report_bp', __name__, template_folder='templates')
|
||||||
|
|
||||||
@report_bp.route('/', methods=['GET', 'POST'])
|
@report_bp.route('/menu')
|
||||||
@check_auth
|
@check_auth
|
||||||
def menu():
|
def menu():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('report_menu.html', options=report_list)
|
return render_template('report_menu.html')
|
||||||
|
|
||||||
@report_bp.route('/quaterly', methods=['GET', 'POST'])
|
@report_bp.route('/create', methods=['GET', 'POST'])
|
||||||
@check_auth
|
@check_auth
|
||||||
def quaterly():
|
def create():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('quaterly.html')
|
return render_template('report_basic.html',
|
||||||
|
write=True,
|
||||||
|
title='Создание отчета',
|
||||||
|
items = report_list)
|
||||||
|
else:
|
||||||
|
data = dict(month=request.form.get('month'), year=request.form.get('year'))
|
||||||
|
id = request.form.get('category')
|
||||||
|
with open(path.join(path.dirname(__file__), f'access/{id}.json')) as f:
|
||||||
|
report_access = json.load(f)
|
||||||
|
|
||||||
|
if session['role'] in report_access['write']:
|
||||||
|
proc_name = report_access['procedure']
|
||||||
|
ready_report = make_report(data, proc_name)
|
||||||
|
if ready_report.status:
|
||||||
|
return render_template("OK.html")
|
||||||
|
else:
|
||||||
|
return render_template("error.html", error_message=ready_report.error_message)
|
||||||
|
else:
|
||||||
|
return render_template("error.html", error_message='Недостаточно прав для создания данного отчета!')
|
||||||
|
|
||||||
|
@report_bp.route('/view', methods=['GET', 'POST'])
|
||||||
|
@check_auth
|
||||||
|
def view():
|
||||||
|
if request.method == 'GET':
|
||||||
|
return render_template('report_basic.html',
|
||||||
|
write=False,
|
||||||
|
title='Просмотр отчета',
|
||||||
|
items = report_list)
|
||||||
|
else:
|
||||||
|
data = dict(month=request.form.get('month'), year=request.form.get('year'))
|
||||||
|
id = request.form.get('category')
|
||||||
|
with open(path.join(path.dirname(__file__), f'access/{id}.json')) as f:
|
||||||
|
report_access = json.load(f)
|
||||||
|
|
||||||
|
if session['role'] in report_access['read']:
|
||||||
|
ready_report = sales_report(data, report_access['view'])
|
||||||
|
if ready_report.status:
|
||||||
|
title= f'{report_access["title"]} за {data["month"]}-{data["year"]}'
|
||||||
|
return render_template("output.html", items=ready_report.result,
|
||||||
|
header=title,
|
||||||
|
link = url_for('report_bp.menu'))
|
||||||
|
else:
|
||||||
|
return render_template("error.html", error_message=ready_report.error_message)
|
||||||
|
else:
|
||||||
|
return render_template("error.html", error_message='Недосточно прав для чтения данного отчета!')
|
||||||
7
App/Report/access/1.json
Normal file
7
App/Report/access/1.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"title" : "Отчет о продажах",
|
||||||
|
"write" : ["Менеджер"],
|
||||||
|
"read" : ["Управляющий"],
|
||||||
|
"view" : "view_report",
|
||||||
|
"procedure" : "generate_report"
|
||||||
|
}
|
||||||
34
App/Report/db/DBconnect.py
Normal file
34
App/Report/db/DBconnect.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import pymysql
|
||||||
|
from pymysql.err import *
|
||||||
|
class DBContextManager:
|
||||||
|
def __init__(self, db_config : dict):
|
||||||
|
self.db_config = db_config
|
||||||
|
self.connection = None
|
||||||
|
self.cursor = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
try:
|
||||||
|
self.connection = pymysql.connect(
|
||||||
|
host=self.db_config['host'],
|
||||||
|
port=self.db_config['port'],
|
||||||
|
user=self.db_config['user'],
|
||||||
|
password=self.db_config['password'],
|
||||||
|
db=self.db_config['db']
|
||||||
|
)
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
return self.cursor
|
||||||
|
except (OperationalError, KeyError) as err:
|
||||||
|
print(err.args)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if self.connection and self.cursor:
|
||||||
|
if exc_type:
|
||||||
|
print(exc_type, '\n', exc_val)
|
||||||
|
self.connection.rollback()
|
||||||
|
else:
|
||||||
|
self.connection.commit()
|
||||||
|
self.cursor.close()
|
||||||
|
self.connection.close()
|
||||||
|
return True
|
||||||
|
|
||||||
0
App/Report/db/__init__.py
Normal file
0
App/Report/db/__init__.py
Normal file
14
App/Report/db/sql_provider.py
Normal file
14
App/Report/db/sql_provider.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import os
|
||||||
|
from string import Template
|
||||||
|
|
||||||
|
class SQLProvider:
|
||||||
|
def __init__(self, file_path):
|
||||||
|
self.scripts = {}
|
||||||
|
for file in os.listdir(file_path):
|
||||||
|
_sql = open(f'{file_path}/{file}').read()
|
||||||
|
self.scripts[file] = Template(_sql)
|
||||||
|
|
||||||
|
def get(self, name, params) -> dict:
|
||||||
|
if name not in self.scripts:
|
||||||
|
raise ValueError(f'SQL template {name} not found')
|
||||||
|
return self.scripts[name].substitute(**params)
|
||||||
23
App/Report/db/work.py
Normal file
23
App/Report/db/work.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from .DBconnect import DBContextManager
|
||||||
|
|
||||||
|
def select_list(db_config, sql) -> list:
|
||||||
|
with DBContextManager(db_config) as cursor:
|
||||||
|
if cursor is None:
|
||||||
|
raise ValueError("Cursor not created")
|
||||||
|
else:
|
||||||
|
cursor.execute(sql)
|
||||||
|
result = cursor.fetchall()
|
||||||
|
schema = [item[0] for item in cursor.description]
|
||||||
|
lst = [dict(zip(schema, row)) for row in result]
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def procedure(db_config, name, args: tuple):
|
||||||
|
with DBContextManager(db_config) as cursor:
|
||||||
|
if cursor is None:
|
||||||
|
raise ValueError("Cursor not created")
|
||||||
|
else:
|
||||||
|
cursor.callproc(name, args)
|
||||||
|
result = cursor.fetchall()[0]
|
||||||
|
schema = cursor.description[0]
|
||||||
|
lst = dict(zip(schema, result))
|
||||||
|
return lst
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
[
|
[
|
||||||
{"name": "Квартальный отчет передвижений заготовок", "url": "report_bp.quaterly"}
|
{"id": 1, "name": "Покупки за месяц", "json_file": "access/sales.json"}
|
||||||
]
|
]
|
||||||
4
App/Report/sql/check_report.sql
Normal file
4
App/Report/sql/check_report.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM reports
|
||||||
|
WHERE month = $month AND year = $year
|
||||||
|
) AS exist;
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
SELECT sellers.name AS 'Поставщик',
|
|
||||||
w.date_of_delivery AS 'Дата поставки',
|
|
||||||
SUM(wl.count) AS 'Общее количество заготовок',
|
|
||||||
SUM(wl.price) AS 'Общая стоимость поставленных заготовок'
|
|
||||||
FROM waybill w
|
|
||||||
JOIN waybill_lines wl USING(waybill_id)
|
|
||||||
JOIN workpiece USING(work_id)
|
|
||||||
JOIN sellers USING(sel_id)
|
|
||||||
WHERE workpiece.material = '${material}'
|
|
||||||
AND (w.date_of_delivery BETWEEN '${date_from}' AND '${date_to}')
|
|
||||||
GROUP BY sellers.name, w.date_of_delivery;
|
|
||||||
5
App/Report/sql/view_report.sql
Normal file
5
App/Report/sql/view_report.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
SELECT name_of_product AS 'Наименование',
|
||||||
|
count_of_bought AS 'Количество',
|
||||||
|
sum AS 'Общая стоимость'
|
||||||
|
FROM reports
|
||||||
|
WHERE month = '$month' AND year = '$year';
|
||||||
15
App/Report/templates/OK.html
Normal file
15
App/Report/templates/OK.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Успех</title>
|
||||||
|
<link href="/static/css/auth.css" type="text/css" rel="stylesheet">
|
||||||
|
<link href="/static/css/main.css" type="text/css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Успешно!</h1>
|
||||||
|
<p>Отчет успешно добавлен в базу данных!</p>
|
||||||
|
<a href="{{ url_for('index') }}"><button>На главную страницу</button></a>
|
||||||
|
<a href="{{ url_for('report_bp.menu') }}"><button>В меню отчетов</button></a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Квартальный отчет</title>
|
|
||||||
<link href="/static/css/main.css" type="text/css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="logout">
|
|
||||||
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
|
||||||
</div>
|
|
||||||
<!-- Not implemented -->
|
|
||||||
<h1>Заглушка для квартального отчета</h1>
|
|
||||||
<div class="return">
|
|
||||||
<a href="{{ url_for('index') }}"><button>Главное меню</button></a>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
45
App/Report/templates/report_basic.html
Normal file
45
App/Report/templates/report_basic.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
<link href="/static/css/main.css" type="text/css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="logout">
|
||||||
|
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
||||||
|
</div>
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
{% for item in items %}
|
||||||
|
<select name="category" required>
|
||||||
|
<option value="{{ item['id'] }}">{{ item['name'] }}</option>
|
||||||
|
</select>
|
||||||
|
{% endfor %}
|
||||||
|
<select name="month" required>
|
||||||
|
<option value="1">Январь</option>
|
||||||
|
<option value="2">Февраль</option>
|
||||||
|
<option value="3">Март</option>
|
||||||
|
<option value="4">Апрель</option>
|
||||||
|
<option value="5">Май</option>
|
||||||
|
<option value="6">Июнь</option>
|
||||||
|
<option value="7">Июль</option>
|
||||||
|
<option value="8">Август</option>
|
||||||
|
<option value="9">Сентябрь</option>
|
||||||
|
<option value="10">Октябрь</option>
|
||||||
|
<option value="11">Ноябрь</option>
|
||||||
|
<option value="12">Декабрь</option>
|
||||||
|
</select>
|
||||||
|
<input type="number" name="year" value="2024" min="1990" max="2100" required>
|
||||||
|
{% if write %}
|
||||||
|
<button type="submit" value="write">Создать</button>
|
||||||
|
{% else %}
|
||||||
|
<button type="submit" value="read">Просмотр</button>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
<div class="return">
|
||||||
|
<a href="{{ url_for('index') }}"><button>Главное меню</button></a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -10,11 +10,10 @@
|
|||||||
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
||||||
</div>
|
</div>
|
||||||
<h1>Выберите вариант отчетов</h1>
|
<h1>Выберите вариант отчетов</h1>
|
||||||
<nav class="menu">
|
<div style="text-align: center; margin: 20px 0;">
|
||||||
{% for point in options %}
|
<a href="{{ url_for('report_bp.create') }}"><button>Создать отчет</button></a>
|
||||||
<a href="{{ url_for(point['url']) }}"><button>{{ point['name'] }}</button></a>
|
<a href="{{ url_for('report_bp.view') }}"><button>Читать отчеты</button></a>
|
||||||
{% endfor %}
|
</div>
|
||||||
</nav>
|
|
||||||
<div class="return">
|
<div class="return">
|
||||||
<a href="{{ url_for('index') }}"><button>Главное меню</button></a>
|
<a href="{{ url_for('index') }}"><button>Главное меню</button></a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from db.select import select_list
|
from .db.select import select_list
|
||||||
from db.sql_provider import SQLProvider
|
from .db.sql_provider import SQLProvider
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
|
|||||||
@@ -26,4 +26,6 @@ def index():
|
|||||||
def logout():
|
def logout():
|
||||||
session.clear()
|
session.clear()
|
||||||
return render_template('main_menu.html', ses=session)
|
return render_template('main_menu.html', ses=session)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
app.run(port=5002, host='0.0.0.0')
|
app.run(port=5002, host='0.0.0.0')
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
{
|
{
|
||||||
"Менеджер": ["auth_bp", "requests_bp"],
|
"Менеджер": [
|
||||||
"Управляющий": ["auth_bp", "requests_bp", "report_bp"],
|
"requests_bp",
|
||||||
"Поставщик": ["auth_bp", "waybill_bp"]
|
"report_bp"],
|
||||||
|
"Управляющий": [
|
||||||
|
"requests_bp",
|
||||||
|
"report_bp"],
|
||||||
|
"Поставщик": [
|
||||||
|
"waybill_bp"]
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,18 +11,15 @@
|
|||||||
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
<a href="{{ url_for('logout') }}"><button>Выход</button></a>
|
||||||
</div>
|
</div>
|
||||||
<h1>Здравствуйте, {{ ses['login'] }}!</h1>
|
<h1>Здравствуйте, {{ ses['login'] }}!</h1>
|
||||||
<h2> Ваша роль: {{ ses['role'] }}</h2>
|
|
||||||
{% if ses['access_user'] == 'internal_users' %}
|
{% if ses['access_user'] == 'internal_users' %}
|
||||||
|
<h2> Ваша роль: {{ ses['role'] }}</h2>
|
||||||
<!-- Not implemented -->
|
<!-- Not implemented -->
|
||||||
<nav class="menu">
|
<nav class="menu">
|
||||||
<a href="{{ url_for('requests_bp.requests') }}"><button>Запросы</button></a>
|
<a href="{{ url_for('requests_bp.requests') }}"><button>Запросы</button></a>
|
||||||
<a href="{{ url_for('report_bp.menu') }}"><button>Отчеты</button></a>
|
<a href="{{ url_for('report_bp.menu') }}"><button>Отчеты</button></a>
|
||||||
</nav>
|
</nav>
|
||||||
{% else %}
|
{% else %}
|
||||||
<nav class="menu">
|
<p>Not implemented</p>
|
||||||
<!-- Not implemented -->
|
|
||||||
<a href="{{ url_for('waybill_bp.waybill') }}"><button>Новая накладная</button></a>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="login">
|
<div class="login">
|
||||||
|
|||||||
Reference in New Issue
Block a user