diff --git a/App/Auth/__init__.py b/App/Auth/__init__.py index 4d4ad1e..3e426da 100644 --- a/App/Auth/__init__.py +++ b/App/Auth/__init__.py @@ -9,14 +9,12 @@ def auth(): return render_template('auth.html') else: data = request.form.to_dict() - data['table'] = 'internal_users' if 'internal' in data else 'external_users' auth_data = auth_model(data) if auth_data.status: session.update({ 'login': auth_data.result[0]['login'], + 'access_user': data['access'], 'role': auth_data.result[0]['user_role'], - 'db_config': current_app.config['db_config'], - 'access_user': 'in' if 'internal' in data else 'ext', 'permanent': True }) return redirect(url_for('index')) diff --git a/App/Auth/auth_model.py b/App/Auth/auth_model.py index 856f73c..7446ac6 100644 --- a/App/Auth/auth_model.py +++ b/App/Auth/auth_model.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from Database.select import select_list -from Database.sql_provider import SQLProvider +from .db.select import select_list +from .db.sql_provider import SQLProvider from flask import current_app import os diff --git a/App/Database/DBconnect.py b/App/Auth/db/DBconnect.py similarity index 100% rename from App/Database/DBconnect.py rename to App/Auth/db/DBconnect.py diff --git a/App/Database/__init__.py b/App/Auth/db/__init__.py similarity index 100% rename from App/Database/__init__.py rename to App/Auth/db/__init__.py diff --git a/App/Database/select.py b/App/Auth/db/select.py similarity index 100% rename from App/Database/select.py rename to App/Auth/db/select.py diff --git a/App/Database/sql_provider.py b/App/Auth/db/sql_provider.py similarity index 100% rename from App/Database/sql_provider.py rename to App/Auth/db/sql_provider.py diff --git a/App/Auth/description.txt b/App/Auth/description.txt new file mode 100644 index 0000000..b8d4d0b --- /dev/null +++ b/App/Auth/description.txt @@ -0,0 +1,13 @@ +. +├── auth_model.py - реализация модели авторизации +├── db +│   ├── DBconnect.py - коннектор к СУБД +│   ├── __init__.py - файл для инициализации db как модуль +│   ├── select.py - файл для выполнения select-запросов к СУБД +│   └── sql_provider.py - SQL-провайдер для формирования запроса к СУБД +├── __init__.py - файл для инициализации Auth как модуль +├── sql +│   └── auth.sql - sql-запрос, проверяющий наличие пользователя в СУБД +└── templates + └── auth.html - шаблон для страницы авторизации + diff --git a/App/Auth/sql/auth.sql b/App/Auth/sql/auth.sql index 0902578..4fb90bf 100644 --- a/App/Auth/sql/auth.sql +++ b/App/Auth/sql/auth.sql @@ -1,4 +1,4 @@ -SELECT login, user_role FROM $table +SELECT login, user_role FROM $access WHERE login = '$login' AND password = '$password' LIMIT 1; \ No newline at end of file diff --git a/App/Auth/templates/auth.html b/App/Auth/templates/auth.html index 5ce4b62..08ef3c2 100644 --- a/App/Auth/templates/auth.html +++ b/App/Auth/templates/auth.html @@ -7,16 +7,22 @@ +

Авторизация


-

Внутренний пользователь

+

+ Уровень доступа: + +

- diff --git a/App/Auth/templates/error.html b/App/Auth/templates/error.html deleted file mode 100644 index bff5bb4..0000000 --- a/App/Auth/templates/error.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Ошибка - - - -

Сожалеем

-

{{ error_message }}

- - - diff --git a/App/Report/__init__.py b/App/Report/__init__.py index 068da0c..74ffaad 100644 --- a/App/Report/__init__.py +++ b/App/Report/__init__.py @@ -1,6 +1,7 @@ -from flask import request, Blueprint, render_template +from flask import request, Blueprint, render_template, session, url_for from checker import check_auth from os import path +from .report_model import view_report, make_report import json with open(path.join(path.dirname(__file__), 'reports.json')) as f: @@ -8,14 +9,62 @@ with open(path.join(path.dirname(__file__), 'reports.json')) as f: report_bp = Blueprint('report_bp', __name__, template_folder='templates') -@report_bp.route('/', methods=['GET', 'POST']) +@report_bp.route('/menu') @check_auth def menu(): if request.method == 'GET': - return render_template('report_menu.html', options=report_list) - -@report_bp.route('/quaterly', methods=['GET', 'POST']) + return render_template('report_menu.html') + +@report_bp.route('/create', methods=['GET', 'POST']) @check_auth -def quaterly(): +def create(): if request.method == 'GET': - return render_template('quaterly.html') + return render_template('report_basic.html', + write=True, + title='Создание отчета', + items = report_list) + else: + data = dict(id=request.form.get('category'), + month=request.form.get('month'), + year=request.form.get('year')) + + with open(path.join(path.dirname(__file__), f'access/{data['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(id=request.form.get('category'), + month=request.form.get('month'), + year=request.form.get('year')) + + with open(path.join(path.dirname(__file__), f'access/{data['id']}.json')) as f: + report_access = json.load(f) + + if session['role'] in report_access['read']: + ready_report = view_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='Недосточно прав для чтения данного отчета!') \ No newline at end of file diff --git a/App/Report/access/1.json b/App/Report/access/1.json new file mode 100644 index 0000000..5c07c25 --- /dev/null +++ b/App/Report/access/1.json @@ -0,0 +1,7 @@ +{ + "title" : "Отчет о поставках заготовок", + "write" : ["Менеджер"], + "read" : ["Управляющий"], + "view" : "workpiece_report", + "procedure" : "report_workpiece" +} \ No newline at end of file diff --git a/App/Report/access/2.json b/App/Report/access/2.json new file mode 100644 index 0000000..d7a7537 --- /dev/null +++ b/App/Report/access/2.json @@ -0,0 +1,7 @@ +{ + "title" : "Отчет о поставках поставщиками", + "write" : ["Бухгалтер"], + "read" : ["Управляющий"], + "view" : "sellers_report", + "procedure" : "report_sellers" +} \ No newline at end of file diff --git a/App/Report/db/DBconnect.py b/App/Report/db/DBconnect.py new file mode 100644 index 0000000..b335654 --- /dev/null +++ b/App/Report/db/DBconnect.py @@ -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 + \ No newline at end of file diff --git a/App/Report/db/__init__.py b/App/Report/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/App/Report/db/sql_provider.py b/App/Report/db/sql_provider.py new file mode 100644 index 0000000..a3a1855 --- /dev/null +++ b/App/Report/db/sql_provider.py @@ -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) \ No newline at end of file diff --git a/App/Report/db/work.py b/App/Report/db/work.py new file mode 100644 index 0000000..2fd1ff3 --- /dev/null +++ b/App/Report/db/work.py @@ -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 \ No newline at end of file diff --git a/App/Report/description.txt b/App/Report/description.txt new file mode 100644 index 0000000..3889def --- /dev/null +++ b/App/Report/description.txt @@ -0,0 +1,20 @@ +. +├── access - json-файлы доступа к вариантам для формирования отчета +│   ├── 1.json +│   └── 2.json +├── db +│   ├── DBconnect.py - коннектор к СУБД +│   ├── __init__.py - файл для инициализации db как модуль +│   ├── sql_provider.py - SQL-провайдер для формирования запроса к СУБД +│   └── work.py - файл для выполнения select и call запросов +├── __init__.py - файл для инициализации Report как модуль +├── report_model.py - реализация модели варианта работы с отчетами +├── reports.json - файл с названиями отчетов и их идентификаторы +├── sql +│   ├── check_report.sql - sql-запрос для проверки наличия отчета в БД +│   ├── sellers_report.sql - sql-запрос для просмотра отчета о поставках поставщиков +│   └── workpiece_report.sql - sql-запрос для просмотра отчета о поставках заготовок +└── templates + ├── OK.html - шаблон для вывода информации об успешном добавлении отчета в БД + ├── report_basic.html - шаблон для ввода параметров просмотра/создания отчета + └── report_menu.html - шаблон для выбора просмотра/создания отчета \ No newline at end of file diff --git a/App/Report/report_model.py b/App/Report/report_model.py new file mode 100644 index 0000000..c875da2 --- /dev/null +++ b/App/Report/report_model.py @@ -0,0 +1,53 @@ +from dataclasses import dataclass +from .db.work import select_list, procedure +from .db.sql_provider import SQLProvider +from flask import current_app +from os import path + +sql_provider = SQLProvider(path.join(path.dirname(__file__), 'sql')) +@dataclass +class InfoRespronse: + result: tuple + error_message: str + status: bool + +def check_report(input_data: dict) -> bool: + _sql = sql_provider.get('check_report.sql', input_data) + result = select_list(current_app.config['db_config'], _sql) + if result is None or result[0]['exist'] == 0: + return False + return True + +def view_report(input_data: dict, view_script: str) -> InfoRespronse: + status = check_report(input_data) + if not status: + return InfoRespronse((), + error_message = 'Отчет не найден', + status=False) + + _sql = sql_provider.get(f'{view_script}.sql', input_data) + result = select_list(current_app.config['db_config'], _sql) + if result is None: + return InfoRespronse((), + error_message = 'Ошибка в подключении к базе данных. Свяжитесь с администратором', + status=False) + return InfoRespronse(result, error_message='', status=True) + +def make_report(input_data: dict, proc_name: str) -> InfoRespronse: + status = check_report(input_data) + if status: + return InfoRespronse((), + error_message = 'Отчет уже существует', + status=False) + + data = tuple(input_data.values()) + result = procedure(current_app.config['db_config'], proc_name, data) + if result is None: + return InfoRespronse((), + error_message = 'Ошибка в подключении к базе данных. Свяжитесь с администратором', + status=False) + elif result['message'] != 'OK': + return InfoRespronse((), + error_message = 'Невозможно создать отчет (нет продаж за выбранный период)', + status=False) + return InfoRespronse((), error_message='', status=True) \ No newline at end of file diff --git a/App/Report/reports.json b/App/Report/reports.json index 04f2742..ccab6f2 100644 --- a/App/Report/reports.json +++ b/App/Report/reports.json @@ -1,3 +1,4 @@ [ - {"name": "Квартальный отчет передвижений заготовок", "url": "report_bp.quaterly"} + {"id": 1, "name": "Заготовки"}, + {"id": 2, "name": "Поставщики"} ] \ No newline at end of file diff --git a/App/Report/sql/check_report.sql b/App/Report/sql/check_report.sql new file mode 100644 index 0000000..7e6106a --- /dev/null +++ b/App/Report/sql/check_report.sql @@ -0,0 +1,4 @@ +SELECT EXISTS ( + SELECT 1 FROM reports + WHERE report_category_id = '$id' AND (month = '$month' AND year = '$year') +) AS exist; \ No newline at end of file diff --git a/App/Report/sql/report1.sql b/App/Report/sql/report1.sql deleted file mode 100644 index bac1519..0000000 --- a/App/Report/sql/report1.sql +++ /dev/null @@ -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; diff --git a/App/Report/sql/sellers_report.sql b/App/Report/sql/sellers_report.sql new file mode 100644 index 0000000..b02253a --- /dev/null +++ b/App/Report/sql/sellers_report.sql @@ -0,0 +1,8 @@ +SELECT + s.name AS Поставщик, + SUM(reports.count) AS 'Количество поставок', + SUM(reports.sum) AS Сумма +FROM reports +JOIN sellers s ON reports.item_id = s.sel_id +WHERE report_category_id = '$id' AND (month = '$month' AND year = '$year') +GROUP BY s.name; \ No newline at end of file diff --git a/App/Report/sql/workpiece_report.sql b/App/Report/sql/workpiece_report.sql new file mode 100644 index 0000000..e35c331 --- /dev/null +++ b/App/Report/sql/workpiece_report.sql @@ -0,0 +1,8 @@ +SELECT w.name AS Наименование, + w.material AS Материал, + sum(sum) AS Сумма, + sum(reports.count) AS Количество + from reports +JOIN workpiece w ON reports.item_id = w.work_id +WHERE report_category_id = '$id' AND (month = '$month' AND year = '$year') +GROUP BY w.material, w.name; \ No newline at end of file diff --git a/App/Report/templates/OK.html b/App/Report/templates/OK.html new file mode 100644 index 0000000..bbb836c --- /dev/null +++ b/App/Report/templates/OK.html @@ -0,0 +1,15 @@ + + + + + Успех + + + + +

Успешно!

+

Отчет успешно добавлен в базу данных!

+ + + + \ No newline at end of file diff --git a/App/Report/templates/quaterly.html b/App/Report/templates/quaterly.html deleted file mode 100644 index 5698b30..0000000 --- a/App/Report/templates/quaterly.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Квартальный отчет - - - -
- -
- -

Заглушка для квартального отчета

-
- -
- - \ No newline at end of file diff --git a/App/Report/templates/report_basic.html b/App/Report/templates/report_basic.html new file mode 100644 index 0000000..dac88c9 --- /dev/null +++ b/App/Report/templates/report_basic.html @@ -0,0 +1,52 @@ + + + + + {{ title }} + + + +
+ +
+

{{ title }}

+
+
+ + + + +
+ + +
+ + {% if write %} + + {% else %} + + {% endif %} +
+
+ +
+
+ + diff --git a/App/Report/templates/report_menu.html b/App/Report/templates/report_menu.html index e604a1b..7af3b21 100644 --- a/App/Report/templates/report_menu.html +++ b/App/Report/templates/report_menu.html @@ -10,11 +10,10 @@

Выберите вариант отчетов

- +
+ + +
diff --git a/App/Requests/__init__.py b/App/Requests/__init__.py index 2203627..c3d0b8b 100644 --- a/App/Requests/__init__.py +++ b/App/Requests/__init__.py @@ -1,8 +1,7 @@ -from flask import request, Blueprint, render_template +from flask import request, Blueprint, render_template, url_for from os import path from checker import check_auth -from .requests_model import sklad, materials_per_seller -from datetime import date +from .requests_model import sklad, materials_per_seller, sellers_names, materials_names import json with open(path.join(path.dirname(__file__), 'zapros_menu.json')) as f: @@ -20,47 +19,28 @@ def requests(): @check_auth def sklad_zapros(): if request.method == 'GET': - materials = ['Сталь', 'Золото', 'Дерево', 'Стекло', 'Медь', 'Цемент'] - return render_template('zagotovki.html', materials=materials, header='Количество заготовок на складе') + materials = materials_names() + return render_template('zagotovki.html', materials=materials.result) else: material = dict(request.form) zagotovki = sklad(material) if zagotovki.status: - header = f'Заготовки на складе из материала \'{material["material"]}\'' - return render_template('output.html', items=zagotovki.result, object=header) + header = f'Заготовки на складе из материала \"{material["material"]}\"' + return render_template('output.html', items=zagotovki.result, header=header) else: return render_template('error.html', error_message=zagotovki.error_message) - -# Под вопросом -""" @requests_bp.route('/req2', methods=['GET', 'POST']) -@check_auth -def zagotovki_ship(): - if request.method == 'GET': - zagotovki = get_goods() - if zagotovki.status: - return render_template('zagotovki.html', materials=zagotovki.result, header='Поставки заготовок') - else: - return render_template('error.html', error_message=zagotovki.error_message) - else: - material = dict(request.form) - zagotovki = route(material, 'zapros2.sql') - if zagotovki.status: - header = f'Поставки заготовок из материала \'{material['material']}\'' - return render_template('output.html', items=zagotovki.result, object=header) - else: - return render_template('error.html', error_message=zagotovki.error_message) """ @requests_bp.route('/shipments', methods=['GET', 'POST']) @check_auth def sellers_ship(): if request.method == 'GET': - sellers = ['Car and bikes', 'Doto', 'LPD', 'Neva', 'PGG', 'Robot', 'Rost'] - return render_template('sellers_ship.html', sellers=sellers, year_from='2000', year_to=str(date.today().year)) + sellers = sellers_names() + return render_template('sellers_ship.html', sellers=sellers.result) else: seller = dict(request.form) zagotovki = materials_per_seller(seller) if zagotovki.status: - header = f'Поставки от поставщика \'{seller['seller']}\'' - return render_template('output.html', items=zagotovki.result, object=header) + header = f'Поставки от поставщика \"{seller["seller"]}\"' + return render_template('output.html', items=zagotovki.result, header=header, link=url_for('requests_bp.requests')) else: return render_template('error.html', error_message=zagotovki.error_message) \ No newline at end of file diff --git a/App/Requests/db/DBconnect.py b/App/Requests/db/DBconnect.py new file mode 100644 index 0000000..b335654 --- /dev/null +++ b/App/Requests/db/DBconnect.py @@ -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 + \ No newline at end of file diff --git a/App/Requests/db/__init__.py b/App/Requests/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/App/Requests/db/select.py b/App/Requests/db/select.py new file mode 100644 index 0000000..22cc3e7 --- /dev/null +++ b/App/Requests/db/select.py @@ -0,0 +1,12 @@ +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 \ No newline at end of file diff --git a/App/Requests/db/sql_provider.py b/App/Requests/db/sql_provider.py new file mode 100644 index 0000000..a3a1855 --- /dev/null +++ b/App/Requests/db/sql_provider.py @@ -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) \ No newline at end of file diff --git a/App/Requests/description.txt b/App/Requests/description.txt new file mode 100644 index 0000000..1b4d300 --- /dev/null +++ b/App/Requests/description.txt @@ -0,0 +1,18 @@ +. +├── db +│   ├── DBconnect.py - коннектор к СУБД +│   ├── __init__.py - файл для инициализации db как модуль +│   ├── select.py - файл для выполнения select-запросов к СУБД +│   └── sql_provider.py - SQL-провайдер для формирования запроса к СУБД +├── __init__.py - файл для инициализации Requests как модуль +├── requests_model.py - реализация модели варианта работы с запросами +├── sql +│   ├── materials_names.sql - sql-запрос для получения списка материалоа заготовок +│   ├── sellers_names.sql - sql-запрос для получения списка поставщиков +│   ├── ship_seller.sql - sql-запрос для получения списка поставок поставщиком +│   └── sklad_material.sql - sql-запрос для получения списка заготовок на складе +├── templates +│   ├── sellers_ship.html - шаблон для формы передачи параметров для запроса всех поставок выбранного поставщика +│   ├── zagotovki.html - шаблон для формы передачи параметров для запроса количества заготовок на складе +│   └── zapros_menu.html - шаблон для выбора варианта отчёта +└── zapros_menu.json - файл с названиями запросов и их ссылками \ No newline at end of file diff --git a/App/Requests/requests_model.py b/App/Requests/requests_model.py index 33378a9..f19df13 100644 --- a/App/Requests/requests_model.py +++ b/App/Requests/requests_model.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from Database.select import select_list -from Database.sql_provider import SQLProvider +from .db.select import select_list +from .db.sql_provider import SQLProvider from flask import current_app from os import path @@ -11,8 +11,26 @@ class InfoRespronse: error_message: str status: bool +def sellers_names() -> InfoRespronse: + _sql = sql_provider.get('sellers_names.sql', {}) + result = select_list(current_app.config['db_config'], _sql) + if result is None: + return InfoRespronse((), + error_message = 'Ошибка в подключении к базе данных. Свяжитесь с администратором', + status=False) + return InfoRespronse(result, error_message='', status=True) + +def materials_names() -> InfoRespronse: + _sql = sql_provider.get('materials_names.sql', {}) + result = select_list(current_app.config['db_config'], _sql) + if result is None: + return InfoRespronse((), + error_message = 'Ошибка в подключении к базе данных. Свяжитесь с администратором', + status=False) + return InfoRespronse(result, error_message='', status=True) + def sklad(input_data) -> InfoRespronse: - _sql = sql_provider.get('zapros1.sql', input_data) + _sql = sql_provider.get('sklad_material.sql', input_data) print("sql = ", _sql) result = select_list(current_app.config['db_config'], _sql) if result is None: @@ -21,8 +39,9 @@ def sklad(input_data) -> InfoRespronse: status=False) return InfoRespronse(result, error_message='', status=True) + def materials_per_seller(input_data) -> InfoRespronse: - _sql = sql_provider.get('zapros3.sql', input_data) + _sql = sql_provider.get('ship_seller.sql', input_data) result = select_list(current_app.config['db_config'], _sql) if result is None: return InfoRespronse((), diff --git a/App/Requests/sql/materials_names.sql b/App/Requests/sql/materials_names.sql new file mode 100644 index 0000000..e5873a7 --- /dev/null +++ b/App/Requests/sql/materials_names.sql @@ -0,0 +1 @@ +SELECT DISTINCT material FROM workpiece; \ No newline at end of file diff --git a/App/Requests/sql/sellers_names.sql b/App/Requests/sql/sellers_names.sql new file mode 100644 index 0000000..be9f77c --- /dev/null +++ b/App/Requests/sql/sellers_names.sql @@ -0,0 +1 @@ +SELECT name FROM sellers; \ No newline at end of file diff --git a/App/Requests/sql/zapros3.sql b/App/Requests/sql/ship_seller.sql similarity index 90% rename from App/Requests/sql/zapros3.sql rename to App/Requests/sql/ship_seller.sql index 7336117..582b34f 100644 --- a/App/Requests/sql/zapros3.sql +++ b/App/Requests/sql/ship_seller.sql @@ -5,5 +5,4 @@ FROM waybill w JOIN (SELECT waybill_id, SUM(count) AS cnt FROM waybill_lines wl GROUP BY waybill_id)wl USING (waybill_id) JOIN sellers USING(sel_id) WHERE sellers.name = '${seller}' -AND YEAR(date_of_delivery) = '${date}' GROUP BY date_of_delivery \ No newline at end of file diff --git a/App/Requests/sql/zapros1.sql b/App/Requests/sql/sklad_material.sql similarity index 100% rename from App/Requests/sql/zapros1.sql rename to App/Requests/sql/sklad_material.sql diff --git a/App/Requests/sql/zapros2.sql b/App/Requests/sql/zapros2.sql deleted file mode 100644 index 21d1431..0000000 --- a/App/Requests/sql/zapros2.sql +++ /dev/null @@ -1,9 +0,0 @@ -SELECT w.date_of_delivery AS 'Дата поставки', - name AS 'Поставщик', - wl.count AS 'Количество', - wl.price * wl.count AS 'Общая сумма' -FROM waybill w -JOIN waybill_lines wl USING(waybill_id) -JOIN workpiece wp USING(work_id) -JOIN sellers USING(sel_id) -WHERE material = '${material}'; \ No newline at end of file diff --git a/App/Requests/templates/error.html b/App/Requests/templates/error.html deleted file mode 100644 index c1a8828..0000000 --- a/App/Requests/templates/error.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Ошибка - - - -

Произошла ошибка

-

{{ error_message }}.

- - - diff --git a/App/Requests/templates/sellers_ship.html b/App/Requests/templates/sellers_ship.html index 8a14679..629f9fc 100644 --- a/App/Requests/templates/sellers_ship.html +++ b/App/Requests/templates/sellers_ship.html @@ -1,8 +1,8 @@ - + - Поставки поставщиком за год + Поставки поставщиком @@ -10,17 +10,15 @@ -

Поставки поставщиком за год

+

Поставки поставщиком

Выберите поставщика

-

Выберите год:

-

diff --git a/App/Requests/templates/zagotovki.html b/App/Requests/templates/zagotovki.html index eef759a..fab9e65 100644 --- a/App/Requests/templates/zagotovki.html +++ b/App/Requests/templates/zagotovki.html @@ -1,8 +1,8 @@ - + - {{ header }} + Количество заготовок на складе @@ -10,14 +10,16 @@
-

{{ header }}

+

Количество заготовок на складе

Выберите материал

diff --git a/App/Requests/templates/zapros_menu.html b/App/Requests/templates/zapros_menu.html index 852a439..e7d38b8 100644 --- a/App/Requests/templates/zapros_menu.html +++ b/App/Requests/templates/zapros_menu.html @@ -1,5 +1,5 @@ - + Запросы diff --git a/App/Requests/zapros_menu.json b/App/Requests/zapros_menu.json index 77b9a68..45c1b4b 100644 --- a/App/Requests/zapros_menu.json +++ b/App/Requests/zapros_menu.json @@ -1,5 +1,4 @@ [ {"name": "Количество заготовок на складе", "url": "requests_bp.sklad_zapros"}, - - {"name": "Поставки поставщиком за год", "url": "requests_bp.sellers_ship"} + {"name": "Поставки поставщиками", "url": "requests_bp.sellers_ship"} ] \ No newline at end of file diff --git a/App/app.py b/App/app.py index b718a1e..cd4ad61 100644 --- a/App/app.py +++ b/App/app.py @@ -26,4 +26,6 @@ def index(): def logout(): session.clear() return render_template('main_menu.html', ses=session) -app.run(port=5001, debug=True) \ No newline at end of file + +if __name__ == '__main__': + app.run(port=5002, host='0.0.0.0') \ No newline at end of file diff --git a/App/data/db_access.json b/App/data/db_access.json index 24d1e7e..a6ba414 100644 --- a/App/data/db_access.json +++ b/App/data/db_access.json @@ -1,5 +1,12 @@ { - "Менеджер": ["auth_bp", "requests_bp"], - "Управляющий": ["auth_bp", "requests_bp", "report_bp"], - "Поставщик": ["auth_bp", "waybill_bp"] - } \ No newline at end of file + "Менеджер": [ + "requests_bp", + "report_bp"], + "Управляющий": [ + "requests_bp", + "report_bp"], + "Бухгалтер": [ + "report_bp"], + "Поставщик": [ + "waybill_bp"] +} \ No newline at end of file diff --git a/App/description.txt b/App/description.txt new file mode 100644 index 0000000..4c64a2b --- /dev/null +++ b/App/description.txt @@ -0,0 +1,16 @@ + +. +├── app.py - основное приложение +├── checker.py - декораторы +├── data +│   ├── config.json - конфигурация для подключения к СУБД +│   └── db_access.json - доступ пользователей к вариантам использования ИС +├── static +│   └── css - стили для страниц +│   ├── auth.css +│   ├── main.css +│   └── output.css +└── templates + ├── error.html - универсальный шаблон для ошибок + ├── main_menu.html - шаблон главного меню + └── output.html - универсальный шаблон для вывода результатов diff --git a/App/static/css/main.css b/App/static/css/main.css index d641103..5cd5ee1 100644 --- a/App/static/css/main.css +++ b/App/static/css/main.css @@ -1,4 +1,4 @@ -h1,h2 { +h1, h2 { text-align: center; } @@ -26,6 +26,11 @@ div.logout, div.login { text-align: center; } +div.buttons_menu{ + text-align: center; + margin: 20px 0; +} + div.logout button { margin-top: -5px; background-color: #ff0000; @@ -37,11 +42,12 @@ div.login button { } div.return { - display: flex; - justify-content: center; + display: flex; + justify-content: center; + margin-top: 15px; } -div.return button{ +div.return button { background-color: chocolate; } @@ -50,4 +56,35 @@ div.form { left: 50%; top: 50%; transform: translate(-50%, -50%); -} \ No newline at end of file + text-align: center; + background-color: white; + padding: 20px; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +div.form label { + display: block; + margin-bottom: 5px; + font-size: 16px; + font-weight: bold; + color: #333; +} + +div.form select, div.form input[type=number] { + margin-bottom: 15px; + padding: 5px; + font-size: 14px; + width: 100%; + box-sizing: border-box; +} + +div.form .period { + display: flex; + gap: 10px; + justify-content: center; +} + +div.form button { + margin-top: 15px; +} diff --git a/App/templates/main_menu.html b/App/templates/main_menu.html index 4afda31..288fbd0 100644 --- a/App/templates/main_menu.html +++ b/App/templates/main_menu.html @@ -11,18 +11,15 @@

Здравствуйте, {{ ses['login'] }}!

-

Ваша роль: {{ ses['role'] }}

- {% if ses['access_user'] == 'in' %} + {% if ses['access_user'] == 'internal_users' %} +

Ваша роль: {{ ses['role'] }}

{% else %} - +

Not implemented

{% endif %} {% else %}
diff --git a/App/Requests/templates/output.html b/App/templates/output.html similarity index 83% rename from App/Requests/templates/output.html rename to App/templates/output.html index de25cbc..269fc09 100644 --- a/App/Requests/templates/output.html +++ b/App/templates/output.html @@ -2,7 +2,7 @@ - {{ object }} + {{ header }} @@ -10,7 +10,7 @@ -

{{ object }}

+

{{ header }}

{% if items %} @@ -31,6 +31,6 @@

Информации не найдено

{% endif %} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5684634 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +cryptography==43.0.3 +Flask==3.0.3 +PyMySQL==1.1.1