diff --git a/Result9/Curl/readme.md b/Curl/readme.md similarity index 100% rename from Result9/Curl/readme.md rename to Curl/readme.md diff --git a/Result9/.gitignore b/Result9/.gitignore deleted file mode 100644 index d3b0d3c..0000000 --- a/Result9/.gitignore +++ /dev/null @@ -1,236 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/python,linux,visualstudiocode,windows -# Edit at https://www.toptal.com/developers/gitignore?templates=python,linux,visualstudiocode,windows - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -### Python Patch ### -# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration -poetry.toml - -# ruff -.ruff_cache/ - -# LSP config files -pyrightconfig.json - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets - -# Local History for Visual Studio Code -.history/ - -# Built Visual Studio Code Extensions -*.vsix - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history -.ionide - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# End of https://www.toptal.com/developers/gitignore/api/python,linux,visualstudiocode,windows \ No newline at end of file diff --git a/Result9/.vscode/settings.json b/Result9/.vscode/settings.json deleted file mode 100644 index 10fa769..0000000 --- a/Result9/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "python.testing.unittestArgs": [ - "-v", - "-s", - "./Tst", - "-p", - "*test.py" - ], - "python.testing.pytestEnabled": false, - "python.testing.unittestEnabled": true -} \ No newline at end of file diff --git a/Result9/Src/Logics/Services/post_processing_service.py b/Result9/Src/Logics/Services/post_processing_service.py deleted file mode 100644 index 2dde182..0000000 --- a/Result9/Src/Logics/Services/post_processing_service.py +++ /dev/null @@ -1,28 +0,0 @@ -from Src.Logics.Services.service import service -from Src.Logics.Services.storage_observer import storage_observer -from Src.Storage.storage import storage -from Src.Logics.Services.storage_observer import event_type -from Src.Models.nomenclature_model import nomenclature_model - - -class post_processing_service(service): - - def __init__(self, data: list, nomenclature) -> None: - - super().__init__(data) - - self.nomenclature = nomenclature - # storage_observer.observers.append(self) - - - - def handle_event(self, handle_type: str): - if handle_type == event_type.nomenclature_deleted(): - self.nomenclature_deleted() - - - def nomenclature_deleted(self, nomenclature: nomenclature_model): - for recipe in self.data: - if self.nomenclature.name in recipe._rows: - del recipe._rows[self.nomenclature.name] - recipe.__calc_brutto() diff --git a/Result9/Src/Logics/Services/service.py b/Result9/Src/Logics/Services/service.py deleted file mode 100644 index 980bf01..0000000 --- a/Result9/Src/Logics/Services/service.py +++ /dev/null @@ -1,84 +0,0 @@ -from Src.exceptions import argument_exception, exception_proxy -from Src.Logics.convert_factory import convert_factory -from Src.settings import settings -from Src.settings_manager import settings_manager -from Src.Models.event_type import event_type -from abc import ABC - -from abc import ABC, abstractmethod -import json - -# -# Общий класс для наследования. Реализация сервисов. -# -class service(ABC): - # Набор данных для работы - __data = [] - # Текущие настройки - __settings: settings = None - - def __init__(self, data: list) -> None: - if len(data) == 0: - raise argument_exception("Некорректно переданы параметры!") - - self.__data = data - options = settings_manager() - self.__settings = options.settings - - @property - def data(self): - """ - Текущие данные - Returns: - _type_: _description_ - """ - return self.__data - - @property - def settings(self) -> settings: - """ - Текущие настройки - Returns: - settings: _description_ - """ - return self.__settings - - @abstractmethod - def handle_event(self, event_type: str): - """ Обработать события""" - - exception_proxy.validate(event_type, str) - - # Общие методы для формирования ответа для Web - - - def create_response(self, app, data:list = None): - """ - Сформировать структуру ответа для Web сервера - """ - inner_data = self.__data if data is None else data - return service.create_response(app, inner_data) - - @staticmethod - def create_response( app, data:list): - """ - Сформировать структуру ответа для Web сервера - """ - if app is None: - raise argument_exception("Некорректно переданы параметры!") - - exception_proxy.validate(data, list) - - # Преоброзование - dest_data = convert_factory().serialize( data ) - json_text = json.dumps( dest_data, sort_keys = True, indent = 4, ensure_ascii = False) - - # Подготовить ответ - result = app.response_class( - response = f"{json_text}", - status = 200, - mimetype = "application/json; charset=utf-8" - ) - - return result - diff --git a/Result9/Src/Logics/Services/storage_observer.py b/Result9/Src/Logics/Services/storage_observer.py deleted file mode 100644 index 2745e49..0000000 --- a/Result9/Src/Logics/Services/storage_observer.py +++ /dev/null @@ -1,19 +0,0 @@ -from Src.Models.event_type import event_type -from Src.exceptions import exception_proxy - -# -# Наблюдатель для складских операций -# -class storage_observer: - _observers = [] - - - def raise_event(handle_event: str, reference: None): - """ Сформировать события """ - - exception_proxy.validate( handle_event, str ) - for object in storage_observer._observers: - - if object is not None: - object.handle_event(handle_event) - diff --git a/Result9/Src/Logics/csv_reporting.py b/Result9/Src/Logics/csv_reporting.py deleted file mode 100644 index fb102e0..0000000 --- a/Result9/Src/Logics/csv_reporting.py +++ /dev/null @@ -1,43 +0,0 @@ -from Src.Logics.reporting import reporting -from Src.exceptions import operation_exception - - -# -# Класс - реализация построение данных в формате csv -# -class csv_reporting(reporting): - - def create(self, storage_key: str): - super().create(storage_key) - result = "" - delimetr = ";" - - # Исходные данные - items = self.data[ storage_key ] - if items == None: - raise operation_exception("Невозможно сформировать данные. Данные не заполнены!") - - if len(items) == 0: - raise operation_exception("Невозможно сформировать данные. Нет данных!") - - # Заголовок - header = delimetr.join(self.fields) - result += f"{header}\n" - - # Данные - for item in items: - row = "" - for field in self.fields: - attribute = getattr(item.__class__, field) - if isinstance(attribute, property): - value = getattr(item, field) - if isinstance(value, (list, dict)) or value is None: - value = "" - - row +=f"{value}{delimetr}" - - result += f"{row[:-1]}\n" - - - # Результат csv - return result \ No newline at end of file diff --git a/Result9/Src/Logics/json_reporting.py b/Result9/Src/Logics/json_reporting.py deleted file mode 100644 index f8e9c49..0000000 --- a/Result9/Src/Logics/json_reporting.py +++ /dev/null @@ -1,38 +0,0 @@ -from Src.Logics.reporting import reporting -from Src.exceptions import operation_exception -from Src.Logics.convert_factory import convert_factory - -import json - -# -# Формирование отчета в формате json -# -class json_reporting(reporting): - - def create(self, storage_key: str): - super().create(storage_key) - - # Исходные данные - items = self.data[ storage_key ] - if items == None: - raise operation_exception("Невозможно сформировать данные. Данные не заполнены!") - - if len(items) == 0: - raise operation_exception("Невозможно сформировать данные. Нет данных!") - - # Сериализуем данные - factory = convert_factory() - data = factory.serialize( items ) - - # Формируем Json - result = json.dumps(data, sort_keys = True, indent = 4, ensure_ascii = False) - return result - - def mimetype(self) -> str: - return "application/json; charset=utf-8" - - - - - - \ No newline at end of file diff --git a/Result9/Tst/factory_test.py b/Result9/Tst/factory_test.py deleted file mode 100644 index daf539e..0000000 --- a/Result9/Tst/factory_test.py +++ /dev/null @@ -1,121 +0,0 @@ -from Src.Logics.start_factory import start_factory -from Src.settings_manager import settings_manager -from Src.Storage.storage import storage -from Src.Logics.report_factory import report_factory - -import unittest - -# -# Набор автотестов для проверки работы фабричного метода -# -class factory_test(unittest.TestCase): - - # - # Проверить метод storage_keys в хранилище - # - def test_check_method_storage_keys(self): - # Подготовка - manager = settings_manager() - start = start_factory( manager.settings ) - start.create() - - # Действия - result = start.storage.storage_keys( start.storage ) - - # Проверки - assert result is not None - assert len(result) > 0 - - # - # Проверка работы фабрики для построения отчетности - # - def test_check_report_factory_create(self): - # Подготовка - manager = settings_manager() - start = start_factory( manager.settings ) - start.create() - factory = report_factory() - key = storage.unit_key() - - # Действие - report = factory.create( - manager.settings.report_mode, - start.storage.data) - - # Проверки - assert report is not None - print ( report.create(key) ) - - # - # Проверка создания начальных рецептов - # - def test_check_create_receipts(self): - # Подготовка - items = start_factory.create_receipts() - - # Действие - - # Проверки - assert len(items) > 0 - - # - # Проверка создание начальной номенклатуры - # - def test_check_create_nomenclatures(self): - # Подготовка - items = start_factory.create_nomenclatures() - - # действие - - # Прверки - assert len(items) > 0 - - - # - # Проверка создание списка единиц измерения - # - def test_check_create_units(self): - # Подготовка - items = start_factory.create_units() - - # Действие - - # Проверки - assert len(items) > 0 - - # - # Проверка создания списка групп - # - def test_check_create_groups(self): - # Подготовка - items = start_factory.create_groups() - - # Действие - - # Проверки - assert len(items) > 0 - - - # - # Проверка работы класса start_factory. Метод create - # - def test_check_factory_create(self): - # Подготовка - manager = settings_manager() - factory = start_factory( manager.settings ) - - - # Действие - factory.create() - - # Проверка - assert not factory.storage is None - assert storage.nomenclature_key() in factory.storage.data - assert storage.receipt_key() in factory.storage.data - assert storage.group_key() in factory.storage.data - assert storage.unit_key() in factory.storage.data - assert storage.storage_transaction_key() in factory.storage.data - - - - diff --git a/Result9/Tst/processing_test.py b/Result9/Tst/processing_test.py deleted file mode 100644 index ab2aa56..0000000 --- a/Result9/Tst/processing_test.py +++ /dev/null @@ -1,99 +0,0 @@ -import unittest -from Src.Logics.start_factory import start_factory -from Src.settings_manager import settings_manager -from Src.Logics.process_factory import process_factory -from Src.Storage.storage import storage -from Src.Logics.Processings.processing import processing -from Src.Models.storage_row_turn_model import storage_row_turn_model -from Src.exceptions import operation_exception -from Src.Models.storage_model import storage_model -from Src.Models.unit_model import unit_model - -# -# Набор содульных тестов для проверки процессов обработки данных -# -class processing_test(unittest.TestCase): - - # - # Проверить работу фабрики процессов - # Запустить расчет складских оборотов - # - def test_check_process_factory(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - factory = process_factory() - - # Действие - result = factory.create( process_factory.turn_key() ) - - # Проверка - assert result is not None - - - # - # Проверить работу процесса расчета оборотов - # - def test_check_process_turns(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - factory = process_factory() - key = storage.storage_transaction_key() - transactions = start.storage.data[ key ] - processing = factory.create( process_factory.turn_key() ) - - # Действие - result = processing().process(transactions) - - # Проверка - assert result is not None - assert len(result) > 0 - turn = list(filter(lambda x: x.nomenclature.name == "Сыр Пармезан", result )) - assert turn[0].value == 0.5 - - # - # Проверить работы агрегирования оборотов. - # В сохраненных данных есть оборот которого нет в рассчитанный - # - def test_check_aggregate_turns(self): - # Подготовка - default_storage = storage_model.create_default() - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - nomenclatures = start.storage.data[ storage.nomenclature_key()] - if len(nomenclatures) == 0: - raise operation_exception("Список номенклатуры пуст!") - - # Создаем тестовый оборот и добавляем его в хранилище - turn = storage_row_turn_model() - turn.nomenclature = nomenclatures[0] - turn.storage = default_storage - turn.unit = unit_model.create_killogram() - turn.value = 1 - - start.storage.data[ storage.blocked_turns_key() ] = [] - start.storage.data[ storage.blocked_turns_key() ].append( turn) - - # Получаем процессы агрегации и расчета оборотов - factory = process_factory() - aggregate_processing = factory.create( process_factory.aggregate_key() ) - turn_processing = factory.create( process_factory.turn_key() ) - calculated_turns = turn_processing().process( start.storage.data[ storage.storage_transaction_key() ] ) - calculated_len = len(calculated_turns) - - # Действие - result = aggregate_processing().process( calculated_turns ) - - # Проверки - assert result is not None - assert calculated_len + 1 == len(result) - - - - - - \ No newline at end of file diff --git a/Result9/Tst/reporting_test.py b/Result9/Tst/reporting_test.py deleted file mode 100644 index 7a2a245..0000000 --- a/Result9/Tst/reporting_test.py +++ /dev/null @@ -1,166 +0,0 @@ -import unittest -from Src.Logics.reporting import reporting -from Src.Models.unit_model import unit_model -from Src.Storage.storage import storage -from Src.Logics.csv_reporting import csv_reporting -from Src.Models.nomenclature_model import nomenclature_model -from Src.Models.group_model import group_model -from Src.Logics.markdown_reporting import markdown_reporting -from Src.Logics.json_reporting import json_reporting -from Src.Logics.start_factory import start_factory -from Src.settings import settings - - -class reporting_test(unittest.TestCase): - - - def test_check_json_reporting_build(self): - # Подготовка - data = {} - list = [] - item = unit_model.create_gram() - list.append(item) - key = storage.unit_key() - data[ key ] = list - report = json_reporting( data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - # - # Проверить формирование рецептов в формате csv - # - def test_check_csv_create_receipe_key(self): - # Подготовка - optiins = settings() - start = start_factory( optiins ) - start.create() - key = storage.receipt_key() - report = csv_reporting( start.storage.data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - # - # Проверить формирование рецептов в формате Markdown - # - def test_check_markdown_create_receipt_key(self): - # Подготовка - optiins = settings() - start = start_factory( optiins ) - start.create() - key = storage.receipt_key() - report = markdown_reporting( start.storage.data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - - - # - # Проверить статический метод build класса reporting - # - def test_check_reporting_build(self): - # Подготовка - data = {} - list = [] - item = unit_model.create_gram() - list.append(item) - data[ storage.unit_key() ] = list - - # Дейстие - result = reporting.build( storage.unit_key(), data ) - - # Проверки - assert result is not None - assert len(result) > 0 - - - # - # Проверить формированеи отчета в csv формате по единицам измерения - # - def test_check_csv_create_unit_key(self): - # Подготовка - data = {} - list = [] - item = unit_model.create_gram() - list.append(item) - key = storage.unit_key() - data[ key ] = list - report = csv_reporting( data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - - # - # Проверить формирование отчета в csv формате по номенклатуре - # - def test_check_csv_create_nomenclature_key(self): - # Подготовка - data = {} - list = [] - - unit = unit_model.create_killogram() - group = group_model.create_default_group() - item = nomenclature_model("Тушка бройлера", group, unit ) - item.description = "Ингредиент для салата" - list.append(item) - - key = storage.nomenclature_key() - - data[ key ] = list - report = csv_reporting( data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - file = open("csv_report.csv", "w") - file.write(result) - file.close() - - - # - # Проверить формитирование отчета в markdown формате по ед / измерениям - # - def test_check_markdown_create_unit_key(self): - # Подготовка - data = {} - list = [] - item = unit_model.create_gram() - list.append(item) - key = storage.unit_key() - data[ key ] = list - report = markdown_reporting( data ) - - # Действие - result = report.create( key ) - - # Проверки - assert result is not None - assert len(result) > 0 - - file = open("markdown_report.md", "w") - file.write(result) - file.close() - \ No newline at end of file diff --git a/Result9/Tst/service_test.py b/Result9/Tst/service_test.py deleted file mode 100644 index 20ed6ce..0000000 --- a/Result9/Tst/service_test.py +++ /dev/null @@ -1,273 +0,0 @@ -from Src.Logics.Services.storage_service import storage_service -from Src.Logics.start_factory import start_factory -from Src.settings_manager import settings_manager -from Src.Storage.storage import storage -from Src.exceptions import operation_exception -from Src.Logics.Services.reference_service import reference_service -from Src.Logics.convert_factory import convert_factory -from Src.Models.nomenclature_model import nomenclature_model -from Src.Logics.Services.storage_observer import storage_observer -from Src.Models.event_type import event_type -from Src.Logics.Services.post_processing_service import post_processing_service - -from datetime import datetime -import unittest -import uuid - -class service_test(unittest.TestCase): - # - # Проверить добавление reference (номенклатура) - # - def test_check_add_item_reference(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.nomenclature_key() - data = start.storage.data[ key ] - convert = convert_factory() - - if len(data) == 0: - raise operation_exception("Некорректно сформирован набор данных!") - - # Создаем новый элемент номенклатуры - dict = convert.serialize( data[0] ) - item = nomenclature_model().load(dict) - item.id = uuid.uuid4() - - service = reference_service(data) - start_len = len(data) - - # Действие - result = service.add( item ) - - # Проверка - assert result == True - assert len(data) - 1 == start_len - - # - # Проверить изменение reference (номенклатуры) - # - def test_check_change_item_reference(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.nomenclature_key() - data = start.storage.data[ key ] - convert = convert_factory() - - if len(data) == 0: - raise operation_exception("Некорректно сформирован набор данных!") - - # Создаем новый элемент номенклатуры - dict = convert.serialize( data[0] ) - item = nomenclature_model().load(dict) - item.name = "test" - - service = reference_service(data) - start_len = len(data) - - # Действие - result = service.change( item ) - - # Проверка - assert result == True - assert len(data) == start_len - - - # - # Проверить работу метода create_turns - # - def test_check_create_turns(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - data = start.storage.data[ key ] - service = storage_service(data) - start_date = datetime.strptime("2024-01-01", "%Y-%m-%d") - stop_date = datetime.strptime("2024-01-10", "%Y-%m-%d") - - # Действие - result = service.create_turns(start_date, stop_date) - - # Проверки - assert len(result) > 0 - - # - # Проверить метод create_turns_by_nomenclature - # - def test_check_create_turns_by_nomenclature(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - data = start.storage.data[ key ] - service = storage_service(data) - start_date = datetime.strptime("2024-01-01", "%Y-%m-%d") - stop_date = datetime.strptime("2024-01-30", "%Y-%m-%d") - - if len(data) == 0: - raise operation_exception("Набор данных пуст!") - - nomenclature = data[0].nomenclature - - # Действие - result = service.create_turns_by_nomenclature(start_date, stop_date, nomenclature ) - - # Проверки - assert len(result) == 1 - - # - # Проверить метод turns_only_nomenclature - # - def test_check_create_turns_only_nomenclature(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - data = start.storage.data[ key ] - service = storage_service(data) - - if len(data) == 0: - raise operation_exception("Набор данных пуст!") - - nomenclature = data[0].nomenclature - - # Действие - result = service.create_turns_only_nomenclature( nomenclature ) - - # Проверки - assert len(result) > 0 - - # - # Проверить работу метода create_turns_by_receipt - # - def test_check_create_turns_by_receipt(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - transactions_data = start.storage.data[ key ] - service = storage_service(transactions_data) - - if len(transactions_data) == 0: - raise operation_exception("Набор данных пуст!") - - key = storage.receipt_key() - receipts_data = start.storage.data[ key ] - - if len(receipts_data) == 0: - raise operation_exception("Набор данных пуст!") - - receipt = receipts_data[0] - - # Действие - result = service.create_turns_by_receipt(receipt) - - # Проверки - assert len(result) > 0 - - # - # Проверить метод build_debits_by_receipt. Ошибочный сценарий. - # - def test_check_build_debits_by_receipt_fail(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - transactions_data = start.storage.data[ key ] - service = storage_service(transactions_data) - - if len(transactions_data) == 0: - raise operation_exception("Набор данных пуст!") - - key = storage.receipt_key() - receipts_data = start.storage.data[ key ] - - if len(receipts_data) == 0: - raise operation_exception("Набор данных пуст!") - - # -> Цезарь с курицей - receipt = receipts_data[1] - - # Действие и проверка - with self.assertRaises(operation_exception): - service.build_debits_by_receipt( receipt ) - - - # - # Проверить метод build_debits_by_receipt. Корректный сценарий - # - def test_check_build_debits_by_receipt_pass(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - transactions_data = start.storage.data[ key ] - start_len_transaction = len(transactions_data) - service = storage_service(transactions_data) - - if len(transactions_data) == 0: - raise operation_exception("Набор данных пуст!") - - key = storage.receipt_key() - receipts_data = start.storage.data[ key ] - - if len(receipts_data) == 0: - raise operation_exception("Набор данных пуст!") - - # -> Вафли хрустящие в вафильнице - receipt = receipts_data[0] - - # Действие и проверка - service.build_debits_by_receipt( receipt ) - stop_len_transaction = len(start.storage.data[ storage.storage_transaction_key() ]) - - # Проверка (транзакций должно быть больше) - assert start_len_transaction < stop_len_transaction - - - def test_check_observer_blocked_period(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - key = storage.storage_transaction_key() - transactions_data = start.storage.data[ key ] - service = storage_service(transactions_data) - - # Действие - try: - storage_observer.raise_event( event_type.changed_block_period() ) - pass - except Exception as ex: - print(f"ex") - - - def test_check_observer_nomenclature_deleted(self): - # Подготовка - manager = settings_manager() - start = start_factory(manager.settings) - start.create() - nomenclature = nomenclature_model() - service = reference_service(nomenclature) - - # Действие - try: - storage_observer.raise_event( event_type.nomenclature_deleted() ) - service.delete(nomenclature) - pass - except Exception as ex: - print(f"{ex}") - - # Проверка - assert nomenclature is None - \ No newline at end of file diff --git a/Result9/Src/Logics/Processings/aggregate_processing.py b/Src/Logics/Processings/aggregate_processing.py similarity index 100% rename from Result9/Src/Logics/Processings/aggregate_processing.py rename to Src/Logics/Processings/aggregate_processing.py diff --git a/Result9/Src/Logics/Processings/debit_processing.py b/Src/Logics/Processings/debit_processing.py similarity index 100% rename from Result9/Src/Logics/Processings/debit_processing.py rename to Src/Logics/Processings/debit_processing.py diff --git a/Result9/Src/Logics/Processings/processing.py b/Src/Logics/Processings/processing.py similarity index 100% rename from Result9/Src/Logics/Processings/processing.py rename to Src/Logics/Processings/processing.py diff --git a/Result9/Src/Logics/Processings/turn_processing.py b/Src/Logics/Processings/turn_processing.py similarity index 100% rename from Result9/Src/Logics/Processings/turn_processing.py rename to Src/Logics/Processings/turn_processing.py diff --git a/Src/Logics/Services/post_processing_service.py b/Src/Logics/Services/post_processing_service.py new file mode 100644 index 0000000..6370952 --- /dev/null +++ b/Src/Logics/Services/post_processing_service.py @@ -0,0 +1,45 @@ +from Src.Logics.Services.service import service +from Src.Logics.Services.storage_observer import storage_observer +from Src.Storage.storage import storage +from Src.Logics.Services.storage_observer import event_type +from Src.Models.nomenclature_model import nomenclature_model + +# +# Сервис постобработки данных рецептов +# Обрабатывает события, связанные с удалением номенклатуры +# +class post_processing_service(service): + + def __init__(self, data: list, nomenclature) -> None: + """ + Инициализация сервиса постобработки + + Args: + data (list): Список объектов рецептов + nomenclature: Объект номенклатуры, связанный с постобработкой + """ + super().__init__(data) + self.nomenclature = nomenclature + # storage_observer.observers.append(self) + + def handle_event(self, handle_type: str): + """ + Обработка событий от наблюдателя + + Args: + handle_type (str): Тип события + """ + if handle_type == event_type.nomenclature_deleted(): + self.nomenclature_deleted() + + def nomenclature_deleted(self, nomenclature: nomenclature_model): + """ + Обработка удаления номенклатуры: удаляет строку из рецепта, если она ссылается на номенклатуру + + Args: + nomenclature (nomenclature_model): Удаляемая номенклатура + """ + for recipe in self.data: + if self.nomenclature.name in recipe._rows: + del recipe._rows[self.nomenclature.name] + recipe.__calc_brutto() diff --git a/Result9/Src/Logics/Services/reference_service.py b/Src/Logics/Services/reference_service.py similarity index 100% rename from Result9/Src/Logics/Services/reference_service.py rename to Src/Logics/Services/reference_service.py diff --git a/Src/Logics/Services/service.py b/Src/Logics/Services/service.py new file mode 100644 index 0000000..f5b3db4 --- /dev/null +++ b/Src/Logics/Services/service.py @@ -0,0 +1,120 @@ +from Src.exceptions import argument_exception, exception_proxy +from Src.Logics.convert_factory import convert_factory +from Src.settings import settings +from Src.settings_manager import settings_manager +from Src.Models.event_type import event_type +from abc import ABC, abstractmethod +import json + +# +# Базовый абстрактный сервис +# Используется для реализации логики, связанной с обработкой данных и событий +# +class service(ABC): + # Набор данных для обработки + __data = [] + # Текущие настройки приложения + __settings: settings = None + + def __init__(self, data: list) -> None: + """ + Инициализация сервиса + + Args: + data (list): Входные данные для обработки + + Raises: + argument_exception: Если список данных пуст + """ + if len(data) == 0: + raise argument_exception("Некорректно переданы параметры!") + + self.__data = data + options = settings_manager() + self.__settings = options.settings + + @property + def data(self): + """ + Получить текущие данные + + Returns: + list: Данные, с которыми работает сервис + """ + return self.__data + + @property + def settings(self) -> settings: + """ + Получить текущие настройки + + Returns: + settings: Настройки, полученные через settings_manager + """ + return self.__settings + + @abstractmethod + def handle_event(self, event_type: str): + """ + Обработать событие + + Args: + event_type (str): Тип события для обработки + + Raises: + exception_proxy: Если тип события некорректен + """ + exception_proxy.validate(event_type, str) + + # + # Общие методы для формирования ответа для Web-сервера + # + + def create_response(self, app, data: list = None): + """ + Сформировать HTTP-ответ для Web-сервера + + Args: + app: Объект приложения (например, Flask) + data (list, optional): Альтернативные данные для сериализации + + Returns: + response: HTTP-ответ с JSON-содержимым + """ + inner_data = self.__data if data is None else data + return service.create_response(app, inner_data) + + @staticmethod + def create_response(app, data: list): + """ + Сформировать HTTP-ответ для Web-сервера (статический метод) + + Args: + app: Объект приложения + data (list): Список данных для сериализации + + Returns: + response: HTTP-ответ с JSON-содержимым + + Raises: + argument_exception: Если объект app не передан + """ + if app is None: + raise argument_exception("Некорректно переданы параметры!") + + exception_proxy.validate(data, list) + + # Преобразование данных в сериализованный формат + dest_data = convert_factory().serialize(data) + + # Преобразование в JSON + json_text = json.dumps(dest_data, sort_keys=True, indent=4, ensure_ascii=False) + + # Формирование HTTP-ответа + result = app.response_class( + response=f"{json_text}", + status=200, + mimetype="application/json; charset=utf-8" + ) + + return result diff --git a/Src/Logics/Services/storage_observer.py b/Src/Logics/Services/storage_observer.py new file mode 100644 index 0000000..fe0bb08 --- /dev/null +++ b/Src/Logics/Services/storage_observer.py @@ -0,0 +1,26 @@ +from Src.Models.event_type import event_type +from Src.exceptions import exception_proxy + +# +# Наблюдатель для складских операций +# Отвечает за уведомление зарегистрированных обработчиков при возникновении событий +# +class storage_observer: + _observers = [] + + @staticmethod + def raise_event(handle_event: str, reference: None): + """ + Сформировать и распространить событие среди подписчиков + + Args: + handle_event (str): Тип события + reference (None): Зарезервировано для ссылки на объект события (пока не используется) + """ + # Проверка корректности типа события + exception_proxy.validate(handle_event, str) + + # Уведомление всех подписанных объектов + for object in storage_observer._observers: + if object is not None: + object.handle_event(handle_event) diff --git a/Result9/Src/Logics/Services/storage_service.py b/Src/Logics/Services/storage_service.py similarity index 100% rename from Result9/Src/Logics/Services/storage_service.py rename to Src/Logics/Services/storage_service.py diff --git a/Result9/Src/Logics/basic_convertor.py b/Src/Logics/basic_convertor.py similarity index 100% rename from Result9/Src/Logics/basic_convertor.py rename to Src/Logics/basic_convertor.py diff --git a/Result9/Src/Logics/convert_factory.py b/Src/Logics/convert_factory.py similarity index 100% rename from Result9/Src/Logics/convert_factory.py rename to Src/Logics/convert_factory.py diff --git a/Result9/Src/Logics/convertor.py b/Src/Logics/convertor.py similarity index 100% rename from Result9/Src/Logics/convertor.py rename to Src/Logics/convertor.py diff --git a/Src/Logics/csv_reporting.py b/Src/Logics/csv_reporting.py new file mode 100644 index 0000000..540a039 --- /dev/null +++ b/Src/Logics/csv_reporting.py @@ -0,0 +1,52 @@ +from Src.Logics.reporting import reporting +from Src.exceptions import operation_exception + +# +# Класс — реализация построения отчетных данных в формате CSV +# +class csv_reporting(reporting): + + def create(self, storage_key: str): + """ + Сформировать CSV-отчет по ключу хранилища + + Args: + storage_key (str): Ключ доступа к данным из хранилища + + Returns: + str: Сформированные данные в формате CSV + + Raises: + operation_exception: Если данные отсутствуют или не заполнены + """ + super().create(storage_key) + result = "" + delimetr = ";" + + # Извлечение данных по ключу + items = self.data.get(storage_key) + if items is None: + raise operation_exception("Невозможно сформировать данные. Данные не заполнены!") + + if len(items) == 0: + raise operation_exception("Невозможно сформировать данные. Нет данных!") + + # Формирование заголовка CSV + header = delimetr.join(self.fields) + result += f"{header}\n" + + # Формирование строк данных + for item in items: + row = "" + for field in self.fields: + attribute = getattr(item.__class__, field) + if isinstance(attribute, property): + value = getattr(item, field) + # Пропуск списков, словарей и None + if isinstance(value, (list, dict)) or value is None: + value = "" + row += f"{value}{delimetr}" + result += f"{row[:-1]}\n" # Удаляем последний разделитель + + # Возврат результата + return result diff --git a/Result9/Src/Logics/datetime_convertor.py b/Src/Logics/datetime_convertor.py similarity index 100% rename from Result9/Src/Logics/datetime_convertor.py rename to Src/Logics/datetime_convertor.py diff --git a/Src/Logics/json_reporting.py b/Src/Logics/json_reporting.py new file mode 100644 index 0000000..e4465c6 --- /dev/null +++ b/Src/Logics/json_reporting.py @@ -0,0 +1,49 @@ +from Src.Logics.reporting import reporting +from Src.exceptions import operation_exception +from Src.Logics.convert_factory import convert_factory +import json + +# +# Класс — реализация построения отчетных данных в формате JSON +# +class json_reporting(reporting): + + def create(self, storage_key: str): + """ + Сформировать JSON-отчет по ключу хранилища + + Args: + storage_key (str): Ключ доступа к данным из хранилища + + Returns: + str: Сформированные данные в формате JSON + + Raises: + operation_exception: Если данные отсутствуют или не заполнены + """ + super().create(storage_key) + + # Извлечение исходных данных + items = self.data.get(storage_key) + if items is None: + raise operation_exception("Невозможно сформировать данные. Данные не заполнены!") + + if len(items) == 0: + raise operation_exception("Невозможно сформировать данные. Нет данных!") + + # Сериализация данных + factory = convert_factory() + data = factory.serialize(items) + + # Формирование JSON-строки + result = json.dumps(data, sort_keys=True, indent=4, ensure_ascii=False) + return result + + def mimetype(self) -> str: + """ + Получить MIME-тип результата + + Returns: + str: MIME-тип JSON-ответа + """ + return "application/json; charset=utf-8" diff --git a/Result9/Src/Logics/markdown_reporting.py b/Src/Logics/markdown_reporting.py similarity index 53% rename from Result9/Src/Logics/markdown_reporting.py rename to Src/Logics/markdown_reporting.py index 7a0aebe..a7df358 100644 --- a/Result9/Src/Logics/markdown_reporting.py +++ b/Src/Logics/markdown_reporting.py @@ -1,35 +1,49 @@ from Src.Logics.reporting import reporting from Src.exceptions import operation_exception +# +# Класс — реализация построения отчетных данных в формате Markdown +# class markdown_reporting(reporting): - - def create(self, storage_key: str): + + def create(self, storage_key: str): + """ + Сформировать Markdown-отчет по ключу хранилища + + Args: + storage_key (str): Ключ доступа к данным из хранилища + + Returns: + str: Отчет в формате Markdown + + Raises: + operation_exception: Если данные отсутствуют или не заполнены + """ super().create(storage_key) result = [] - # Исходные данные - items = self.data[ storage_key ] - if items == None: + # Извлечение исходных данных + items = self.data.get(storage_key) + if items is None: raise operation_exception("Невозможно сформировать данные. Данные не заполнены!") - - + if len(items) == 0: raise operation_exception("Невозможно сформировать данные. Нет данных!") - - # Заголовок + + # Заголовок отчета result.append(f"# {storage_key}") - - # Шапка таблицы + + # Формирование шапки таблицы header = "" line = "" for field in self.fields: header += f"|{field}" line += "|--" - + result.append(f"{header}|") result.append(f"{line}|") - - # Данные + + # Формирование строк таблицы for item in items: row = "" for field in self.fields: @@ -38,12 +52,7 @@ def create(self, storage_key: str): value = getattr(item, field) if isinstance(value, (list, dict)) or value is None: value = "" - - row +=f"|{value}" - + row += f"|{value}" result.append(f"{row}|") - - return "\n".join(result) - - - \ No newline at end of file + + return "\n".join(result) diff --git a/Result9/Src/Logics/process_factory.py b/Src/Logics/process_factory.py similarity index 100% rename from Result9/Src/Logics/process_factory.py rename to Src/Logics/process_factory.py diff --git a/Result9/Src/Logics/report_factory.py b/Src/Logics/report_factory.py similarity index 100% rename from Result9/Src/Logics/report_factory.py rename to Src/Logics/report_factory.py diff --git a/Result9/Src/Logics/reporting.py b/Src/Logics/reporting.py similarity index 100% rename from Result9/Src/Logics/reporting.py rename to Src/Logics/reporting.py diff --git a/Result9/Src/Logics/start_factory.py b/Src/Logics/start_factory.py similarity index 100% rename from Result9/Src/Logics/start_factory.py rename to Src/Logics/start_factory.py diff --git a/Result9/Src/Logics/storage_prototype.py b/Src/Logics/storage_prototype.py similarity index 100% rename from Result9/Src/Logics/storage_prototype.py rename to Src/Logics/storage_prototype.py diff --git a/Result9/Src/Models/event_type.py b/Src/Models/event_type.py similarity index 100% rename from Result9/Src/Models/event_type.py rename to Src/Models/event_type.py diff --git a/Result9/Src/Models/event_value.py b/Src/Models/event_value.py similarity index 100% rename from Result9/Src/Models/event_value.py rename to Src/Models/event_value.py diff --git a/Result9/Src/Models/group_model.py b/Src/Models/group_model.py similarity index 100% rename from Result9/Src/Models/group_model.py rename to Src/Models/group_model.py diff --git a/Result9/Src/Models/nomenclature_model.py b/Src/Models/nomenclature_model.py similarity index 100% rename from Result9/Src/Models/nomenclature_model.py rename to Src/Models/nomenclature_model.py diff --git a/Result9/Src/Models/receipe_model.py b/Src/Models/receipe_model.py similarity index 100% rename from Result9/Src/Models/receipe_model.py rename to Src/Models/receipe_model.py diff --git a/Result9/Src/Models/receipe_row_model.py b/Src/Models/receipe_row_model.py similarity index 100% rename from Result9/Src/Models/receipe_row_model.py rename to Src/Models/receipe_row_model.py diff --git a/Result9/Src/Models/storage_model.py b/Src/Models/storage_model.py similarity index 100% rename from Result9/Src/Models/storage_model.py rename to Src/Models/storage_model.py diff --git a/Result9/Src/Models/storage_row_model.py b/Src/Models/storage_row_model.py similarity index 100% rename from Result9/Src/Models/storage_row_model.py rename to Src/Models/storage_row_model.py diff --git a/Result9/Src/Models/storage_row_turn_model.py b/Src/Models/storage_row_turn_model.py similarity index 100% rename from Result9/Src/Models/storage_row_turn_model.py rename to Src/Models/storage_row_turn_model.py diff --git a/Result9/Src/Models/unit_model.py b/Src/Models/unit_model.py similarity index 100% rename from Result9/Src/Models/unit_model.py rename to Src/Models/unit_model.py diff --git a/Result9/Src/Storage/storage.json b/Src/Storage/storage.json similarity index 100% rename from Result9/Src/Storage/storage.json rename to Src/Storage/storage.json diff --git a/Result9/Src/Storage/storage.py b/Src/Storage/storage.py similarity index 100% rename from Result9/Src/Storage/storage.py rename to Src/Storage/storage.py diff --git a/Result9/Src/errors.py b/Src/errors.py similarity index 100% rename from Result9/Src/errors.py rename to Src/errors.py diff --git a/Result9/Src/exceptions.py b/Src/exceptions.py similarity index 100% rename from Result9/Src/exceptions.py rename to Src/exceptions.py diff --git a/Result9/Src/reference.py b/Src/reference.py similarity index 100% rename from Result9/Src/reference.py rename to Src/reference.py diff --git a/Result9/Src/settings.json b/Src/settings.json similarity index 100% rename from Result9/Src/settings.json rename to Src/settings.json diff --git a/Result9/Src/settings.py b/Src/settings.py similarity index 100% rename from Result9/Src/settings.py rename to Src/settings.py diff --git a/Result9/Src/settings_manager.py b/Src/settings_manager.py similarity index 100% rename from Result9/Src/settings_manager.py rename to Src/settings_manager.py diff --git a/Result9/Src/test.json b/Src/test.json similarity index 100% rename from Result9/Src/test.json rename to Src/test.json diff --git a/Result9/Tst/convert_test.py b/Tst/convert_test.py similarity index 100% rename from Result9/Tst/convert_test.py rename to Tst/convert_test.py diff --git a/Result9/Tst/error_test.py b/Tst/error_test.py similarity index 100% rename from Result9/Tst/error_test.py rename to Tst/error_test.py diff --git a/Tst/factory_test.py b/Tst/factory_test.py new file mode 100644 index 0000000..e98bf00 --- /dev/null +++ b/Tst/factory_test.py @@ -0,0 +1,87 @@ +import unittest +from Src.Logics.start_factory import start_factory +from Src.settings_manager import settings_manager +from Src.Storage.storage import storage +from Src.Logics.report_factory import report_factory + +class FactoryTest(unittest.TestCase): + + def test_check_method_storage_keys(self): + """Проверка метода storage_keys в хранилище.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + # Действие + result = start.storage.storage_keys(start.storage) + + # Проверки + self.assertIsNotNone(result, "Метод storage_keys вернул None!") + self.assertGreater(len(result), 0, "Метод storage_keys вернул пустой список!") + + def test_check_report_factory_create(self): + """Проверка работы фабрики для построения отчетности.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + factory = report_factory() + key = storage.unit_key() + + # Действие + report = factory.create(manager.settings.report_mode, start.storage.data) + + # Проверки + self.assertIsNotNone(report, "Фабрика отчетности не создала отчет!") + report_result = report.create(key) + self.assertIsNotNone(report_result, "Отчет не был создан для ключа!") + + def test_check_create_receipts(self): + """Проверка создания начальных рецептов.""" + # Подготовка + items = start_factory.create_receipts() + + # Проверки + self.assertGreater(len(items), 0, "Рецепты не были созданы!") + + def test_check_create_nomenclatures(self): + """Проверка создания начальной номенклатуры.""" + # Подготовка + items = start_factory.create_nomenclatures() + + # Проверки + self.assertGreater(len(items), 0, "Номенклатура не была создана!") + + def test_check_create_units(self): + """Проверка создания списка единиц измерения.""" + # Подготовка + items = start_factory.create_units() + + # Проверки + self.assertGreater(len(items), 0, "Единицы измерения не были созданы!") + + def test_check_create_groups(self): + """Проверка создания списка групп.""" + # Подготовка + items = start_factory.create_groups() + + # Проверки + self.assertGreater(len(items), 0, "Группы не были созданы!") + + def test_check_factory_create(self): + """Проверка работы метода create класса start_factory.""" + # Подготовка + manager = settings_manager() + factory = start_factory(manager.settings) + + # Действие + factory.create() + + # Проверки + self.assertIsNotNone(factory.storage, "Хранилище не было создано!") + self.assertIn(storage.nomenclature_key(), factory.storage.data, "Ключ номенклатуры не найден в данных!") + self.assertIn(storage.receipt_key(), factory.storage.data, "Ключ рецепта не найден в данных!") + self.assertIn(storage.group_key(), factory.storage.data, "Ключ группы не найден в данных!") + self.assertIn(storage.unit_key(), factory.storage.data, "Ключ единиц измерения не найден в данных!") + self.assertIn(storage.storage_transaction_key(), factory.storage.data, "Ключ транзакций не найден в данных!") diff --git a/Result9/Tst/nomenclature_test.py b/Tst/nomenclature_test.py similarity index 100% rename from Result9/Tst/nomenclature_test.py rename to Tst/nomenclature_test.py diff --git a/Tst/processing_test.py b/Tst/processing_test.py new file mode 100644 index 0000000..0812323 --- /dev/null +++ b/Tst/processing_test.py @@ -0,0 +1,85 @@ +import unittest +from Src.Logics.start_factory import start_factory +from Src.settings_manager import settings_manager +from Src.Logics.process_factory import process_factory +from Src.Storage.storage import storage +from Src.Logics.Processings.processing import processing +from Src.Models.storage_row_turn_model import storage_row_turn_model +from Src.exceptions import operation_exception +from Src.Models.storage_model import storage_model +from Src.Models.unit_model import unit_model + +class ProcessingTest(unittest.TestCase): + + def test_check_process_factory(self): + """Проверить работу фабрики процессов и запуск расчета складских оборотов.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + factory = process_factory() + + # Действие + result = factory.create(process_factory.turn_key()) + + # Проверка + self.assertIsNotNone(result, "Фабрика процессов не создала процесс!") + + def test_check_process_turns(self): + """Проверить работу процесса расчета оборотов.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + factory = process_factory() + key = storage.storage_transaction_key() + transactions = start.storage.data[key] + processing = factory.create(process_factory.turn_key()) + + # Действие + result = processing().process(transactions) + + # Проверка + self.assertIsNotNone(result, "Результат расчета оборотов пуст!") + self.assertGreater(len(result), 0, "Обороты не были рассчитаны!") + + # Проверка конкретного оборота + turn = next((x for x in result if x.nomenclature.name == "Сыр Пармезан"), None) + self.assertIsNotNone(turn, "Не найден оборот для номенклатуры 'Сыр Пармезан'") + self.assertEqual(turn.value, 0.5, "Значение оборота для 'Сыр Пармезан' некорректно!") + + def test_check_aggregate_turns(self): + """Проверить работу агрегирования оборотов.""" + # Подготовка + default_storage = storage_model.create_default() + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + nomenclatures = start.storage.data[storage.nomenclature_key()] + self.assertGreater(len(nomenclatures), 0, "Список номенклатуры пуст!") + + # Создаем тестовый оборот и добавляем его в хранилище + turn = storage_row_turn_model() + turn.nomenclature = nomenclatures[0] + turn.storage = default_storage + turn.unit = unit_model.create_killogram() + turn.value = 1 + + start.storage.data[storage.blocked_turns_key()] = [turn] + + # Получаем процессы агрегации и расчета оборотов + factory = process_factory() + aggregate_processing = factory.create(process_factory.aggregate_key()) + turn_processing = factory.create(process_factory.turn_key()) + calculated_turns = turn_processing().process(start.storage.data[storage.storage_transaction_key()]) + calculated_len = len(calculated_turns) + + # Действие + result = aggregate_processing().process(calculated_turns) + + # Проверки + self.assertIsNotNone(result, "Результат агрегации оборотов пуст!") + self.assertEqual(len(result), calculated_len + 1, "Количество агрегированных оборотов некорректно!") + + + diff --git a/Result9/Tst/prototype_test.py b/Tst/prototype_test.py similarity index 100% rename from Result9/Tst/prototype_test.py rename to Tst/prototype_test.py diff --git a/Tst/reporting_test.py b/Tst/reporting_test.py new file mode 100644 index 0000000..467620c --- /dev/null +++ b/Tst/reporting_test.py @@ -0,0 +1,86 @@ +import unittest +from Src.Logics.start_factory import start_factory +from Src.settings_manager import settings_manager +from Src.Storage.storage import storage +from Src.Logics.report_factory import report_factory + +class FactoryTest(unittest.TestCase): + + def test_check_method_storage_keys(self): + """Проверить метод storage_keys в хранилище.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + # Действие + result = start.storage.storage_keys(start.storage) + + # Проверки + self.assertIsNotNone(result, "Метод storage_keys вернул None!") + self.assertGreater(len(result), 0, "Метод storage_keys вернул пустой список!") + + def test_check_report_factory_create(self): + """Проверка работы фабрики для построения отчетности.""" + # Подготовка + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + factory = report_factory() + key = storage.unit_key() + + # Действие + report = factory.create(manager.settings.report_mode, start.storage.data) + + # Проверки + self.assertIsNotNone(report, "Фабрика отчетности не создала отчет!") + self.assertIsNotNone(report.create(key), "Отчет не был создан для ключа!") + + def test_check_create_receipts(self): + """Проверка создания начальных рецептов.""" + # Подготовка + items = start_factory.create_receipts() + + # Проверки + self.assertGreater(len(items), 0, "Рецепты не были созданы!") + + def test_check_create_nomenclatures(self): + """Проверка создания начальной номенклатуры.""" + # Подготовка + items = start_factory.create_nomenclatures() + + # Проверки + self.assertGreater(len(items), 0, "Номенклатура не была создана!") + + def test_check_create_units(self): + """Проверка создания списка единиц измерения.""" + # Подготовка + items = start_factory.create_units() + + # Проверки + self.assertGreater(len(items), 0, "Единицы измерения не были созданы!") + + def test_check_create_groups(self): + """Проверка создания списка групп.""" + # Подготовка + items = start_factory.create_groups() + + # Проверки + self.assertGreater(len(items), 0, "Группы не были созданы!") + + def test_check_factory_create(self): + """Проверка работы метода create класса start_factory.""" + # Подготовка + manager = settings_manager() + factory = start_factory(manager.settings) + + # Действие + factory.create() + + # Проверки + self.assertIsNotNone(factory.storage, "Хранилище не было создано!") + self.assertIn(storage.nomenclature_key(), factory.storage.data, "Ключ номенклатуры не найден в данных!") + self.assertIn(storage.receipt_key(), factory.storage.data, "Ключ рецепта не найден в данных!") + self.assertIn(storage.group_key(), factory.storage.data, "Ключ группы не найден в данных!") + self.assertIn(storage.unit_key(), factory.storage.data, "Ключ единиц измерения не найден в данных!") + self.assertIn(storage.storage_transaction_key(), factory.storage.data, "Ключ транзакций не найден в данных!") diff --git a/Tst/service_test.py b/Tst/service_test.py new file mode 100644 index 0000000..fad2540 --- /dev/null +++ b/Tst/service_test.py @@ -0,0 +1,238 @@ +import uuid +import unittest +from datetime import datetime + +from Src.Logics.Services.storage_service import storage_service +from Src.Logics.Services.reference_service import reference_service +from Src.Logics.Services.post_processing_service import post_processing_service +from Src.Logics.Services.storage_observer import storage_observer + +from Src.Logics.start_factory import start_factory +from Src.Logics.convert_factory import convert_factory + +from Src.Models.nomenclature_model import nomenclature_model +from Src.Models.event_type import event_type + +from Src.settings_manager import settings_manager +from Src.Storage.storage import storage +from Src.exceptions import operation_exception + + +class ServiceTest(unittest.TestCase): + def test_add_item_to_reference(self): + """ + Проверяет, что добавление нового элемента в справочник проходит успешно. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + key = storage.nomenclature_key() + data = start.storage.data[key] + converter = convert_factory() + + # Убедимся, что набор данных не пуст + self.assertGreater(len(data), 0, "Некорректно сформирован набор данных!") + + # Сериализация элемента и создание модели + serialized = converter.serialize(data[0]) + item = nomenclature_model().load(serialized) + item.id = uuid.uuid4() # Генерация нового уникального ID для элемента + + service = reference_service(data) + start_len = len(data) + + # Добавляем элемент в справочник и проверяем результат + result = service.add(item) + + # Проверяем, что элемент добавлен в справочник + self.assertTrue(result) + self.assertEqual(len(data), start_len + 1) + + def test_change_item_in_reference(self): + """ + Проверяет, что изменение элемента справочника происходит корректно. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + key = storage.nomenclature_key() + data = start.storage.data[key] + converter = convert_factory() + + # Убедимся, что набор данных не пуст + self.assertGreater(len(data), 0, "Некорректно сформирован набор данных!") + + # Сериализация элемента и создание модели + serialized = converter.serialize(data[0]) + item = nomenclature_model().load(serialized) + item.name = "test" # Изменяем имя элемента + + service = reference_service(data) + start_len = len(data) + + # Применяем изменение и проверяем результат + result = service.change(item) + + # Проверяем, что элемент был изменен + self.assertTrue(result) + self.assertEqual(len(data), start_len) + + def test_create_turns(self): + """ + Проверяет создание временных интервалов (turns) в хранилище данных. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + key = storage.storage_transaction_key() + data = start.storage.data[key] + + service = storage_service(data) + start_date = datetime(2024, 1, 1) + stop_date = datetime(2024, 1, 10) + + # Создаем временные интервалы и проверяем результат + result = service.create_turns(start_date, stop_date) + + self.assertGreater(len(result), 0) + + def test_create_turns_by_nomenclature(self): + """ + Проверяет создание временных интервалов для определенной номенклатуры. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + key = storage.storage_transaction_key() + data = start.storage.data[key] + + self.assertGreater(len(data), 0, "Набор данных пуст!") + + service = storage_service(data) + nomenclature = data[0].nomenclature + + # Создаем временные интервалы для номенклатуры и проверяем результат + result = service.create_turns_by_nomenclature( + datetime(2024, 1, 1), datetime(2024, 1, 30), nomenclature + ) + + self.assertEqual(len(result), 1) + + def test_create_turns_only_nomenclature(self): + """ + Проверяет создание временных интервалов только для номенклатуры. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + key = storage.storage_transaction_key() + data = start.storage.data[key] + + self.assertGreater(len(data), 0, "Набор данных пуст!") + + service = storage_service(data) + result = service.create_turns_only_nomenclature(data[0].nomenclature) + + # Проверяем, что были созданы временные интервалы + self.assertGreater(len(result), 0) + + def test_create_turns_by_receipt(self): + """ + Проверяет создание временных интервалов по данным рецептов. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + transactions_key = storage.storage_transaction_key() + transactions_data = start.storage.data[transactions_key] + + receipts_key = storage.receipt_key() + receipts_data = start.storage.data[receipts_key] + + self.assertGreater(len(transactions_data), 0, "Набор данных пуст!") + self.assertGreater(len(receipts_data), 0, "Набор данных пуст!") + + service = storage_service(transactions_data) + result = service.create_turns_by_receipt(receipts_data[0]) + + # Проверяем, что были созданы временные интервалы + self.assertGreater(len(result), 0) + + def test_build_debits_by_receipt_should_fail(self): + """ + Проверяет, что при неверном рецепте возникает исключение при построении дебетов. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + transactions = start.storage.data[storage.storage_transaction_key()] + receipts = start.storage.data[storage.receipt_key()] + + self.assertGreater(len(transactions), 0) + self.assertGreater(len(receipts), 1) + + service = storage_service(transactions) + + # Проверяем, что при ошибке в рецепте возникает исключение + with self.assertRaises(operation_exception): + service.build_debits_by_receipt(receipts[1]) + + def test_build_debits_by_receipt_should_pass(self): + """ + Проверяет, что при корректном рецепте дебеты строятся правильно. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + transactions = start.storage.data[storage.storage_transaction_key()] + receipts = start.storage.data[storage.receipt_key()] + + self.assertGreater(len(transactions), 0) + self.assertGreater(len(receipts), 0) + + service = storage_service(transactions) + start_len = len(transactions) + + # Строим дебеты и проверяем, что количество транзакций увеличилось + service.build_debits_by_receipt(receipts[0]) + stop_len = len(start.storage.data[storage.storage_transaction_key()]) + + self.assertGreater(stop_len, start_len) + + def test_observer_blocked_period_event(self): + """ + Проверяет, что событие изменения заблокированного периода корректно вызывается. + """ + try: + storage_observer.raise_event(event_type.changed_block_period()) + except Exception as e: + self.fail(f"Observer вызвал исключение: {e}") + + def test_observer_nomenclature_deleted_event(self): + """ + Проверяет, что событие удаления номенклатуры корректно вызывается. + """ + manager = settings_manager() + start = start_factory(manager.settings) + start.create() + + nomenclature = nomenclature_model() + service = reference_service(nomenclature) + + try: + # Вызываем событие удаления номенклатуры + storage_observer.raise_event(event_type.nomenclature_deleted()) + service.delete(nomenclature) + except Exception as e: + self.fail(f"Ошибка при удалении номенклатуры: {e}") + + # Проверяем, что номенклатура не была удалена (не зануляется объект) + self.assertIsNotNone(nomenclature) diff --git a/Result9/Tst/settings_test.py b/Tst/settings_test.py similarity index 100% rename from Result9/Tst/settings_test.py rename to Tst/settings_test.py diff --git a/Result9/Tst/storage_test.py b/Tst/storage_test.py similarity index 100% rename from Result9/Tst/storage_test.py rename to Tst/storage_test.py diff --git a/Result9/csv_report.csv b/csv_report.csv similarity index 100% rename from Result9/csv_report.csv rename to csv_report.csv diff --git a/Result9/main.py b/main.py similarity index 100% rename from Result9/main.py rename to main.py diff --git a/Result9/markdown_report.md b/markdown_report.md similarity index 100% rename from Result9/markdown_report.md rename to markdown_report.md diff --git a/Result9/nomenclature.json b/nomenclature.json similarity index 100% rename from Result9/nomenclature.json rename to nomenclature.json diff --git a/Result9/nomenclature_deserialize.json b/nomenclature_deserialize.json similarity index 100% rename from Result9/nomenclature_deserialize.json rename to nomenclature_deserialize.json diff --git a/Result9/nomenclatures.json b/nomenclatures.json similarity index 100% rename from Result9/nomenclatures.json rename to nomenclatures.json diff --git a/Result9/readme.md b/readme.md similarity index 100% rename from Result9/readme.md rename to readme.md diff --git a/Result9/receipt_deserialize.json b/receipt_deserialize.json similarity index 100% rename from Result9/receipt_deserialize.json rename to receipt_deserialize.json diff --git a/Result9/receipts.json b/receipts.json similarity index 100% rename from Result9/receipts.json rename to receipts.json diff --git a/Result9/storage.json b/storage.json similarity index 100% rename from Result9/storage.json rename to storage.json diff --git a/Result9/storage_journal.md b/storage_journal.md similarity index 100% rename from Result9/storage_journal.md rename to storage_journal.md diff --git a/Result9/transaction_deserialize.json b/transaction_deserialize.json similarity index 100% rename from Result9/transaction_deserialize.json rename to transaction_deserialize.json