Создание и первичная инициализация базы даных успешно завершена. Наполнение демо-данными прошло без ошибок

This commit is contained in:
2025-12-06 12:58:42 +03:00
parent f378de38da
commit f07843de5a
49 changed files with 734 additions and 353 deletions
+290 -43
View File
@@ -1,4 +1,11 @@
from db.handlers import StockHandler, StocksRecordsHandler
import random
from db.handlers.stock import StockHandler
from db.handlers.toolbox import ToolboxHandler
from db.handlers.toolkit import ToolkitHandler
from db.handlers.user import UserHandler
from db.handlers.access import AccessLevelHandler
from db.handlers.records import StocksRecordsHandler
from utils import logger
@@ -32,7 +39,7 @@ class StocksActions:
recorded = await StocksRecordsHandler.add(
action="Оприходование",
source_stock_id=None,
target_stock_id=newStocks.id,
target_stock_id=newStocks.get("id"),
source_toolbox_id=None,
target_toolbox_id=toolbox_id,
toolkit_id=toolkit_id,
@@ -46,7 +53,7 @@ class StocksActions:
f"Оприходование инструмента {toolkit_id} на складе {toolbox_id} прошло {'успешно' if recorded else 'не успешно'}"
)
if recorded:
accepted = await StocksRecordsHandler.accept(
accepted = await StocksRecordsHandler.decide(
recorded, user_id, None, quantity, price
)
if not accepted:
@@ -84,7 +91,7 @@ class StocksActions:
return False
totalTakeQuantity = 0
writeDownList = []
movementsList = []
for stock in availability:
if quantity == totalTakeQuantity:
@@ -108,14 +115,15 @@ class StocksActions:
f"Списание инструмента {toolkit_id} со склада {source_toolbox_id} на склад {target_toolbox_id} в количестве {takeQuantity} по цене {stock['price']} успешно завершена"
)
movementsList.append(
{
"id": sourceEdit["id"],
"quantity": takeQuantity,
"price": stock["price"],
}
)
if not target_toolbox_id:
writeDownList.append(
{
"id": sourceEdit["id"],
"quantity": takeQuantity,
"price": stock["price"],
}
)
continue
existing = await StockHandler.getByToolboxIdAndToolkitIdAndQPrice(
@@ -168,7 +176,6 @@ class StocksActions:
reason=reason,
quantity=quantity,
price=stock["price"],
target_placement=target_placement,
)
if not recorded:
logger.error(
@@ -179,7 +186,7 @@ class StocksActions:
logger.info(
f"{action} инструмента {toolkit_id} со склада {source_toolbox_id} на склад {target_toolbox_id} прошло успешно"
)
return True if target_toolbox_id else writeDownList
return movementsList
async def movingRequest(
action: str,
@@ -213,29 +220,50 @@ class StocksActions:
)
return recorded
async def movingAcceptance(self, record_id: int, user_id: int):
logger.info(f"Принятие записи о движении инструмента {record_id} ...")
writeDownARecord = await StocksRecordsHandler.getById(record_id, True)
if not writeDownARecord:
async def movingDecision(record_id: int, user_id: int, accepted: bool = True):
logger.info(
f"{'Принятие' if accepted else 'Отклонение'} записи о движении инструмента {record_id} ..."
)
movingRecord = await StocksRecordsHandler.getById(record_id, True)
if not movingRecord:
logger.error(f"Запись {record_id} не найдена")
return False
if writeDownARecord.accepted_at is not None:
logger.error(f"Запись {record_id} уже была принята")
if movingRecord.accepted is not None:
logger.error(
f"Запись {record_id} уже была {'принята' if movingRecord.accepted else 'отклонена'}"
)
return False
stocksMovements = await self.moving(
action=writeDownARecord.action,
source_toolbox_id=writeDownARecord.source_toolbox_id,
target_toolbox_id=writeDownARecord.target_toolbox_id,
toolkit_id=writeDownARecord.toolkit_id,
quantity=writeDownARecord.quantity,
if not accepted:
return await StocksRecordsHandler.decide(
record_id,
user_id,
movingRecord.source_stock_id,
movingRecord.quantity,
movingRecord.price,
accepted,
)
target_toolbox_id = (
movingRecord.target_toolbox_id
if movingRecord.action != "Списание"
else None
)
logger.warning(f"{target_toolbox_id = }, {movingRecord.action = }")
stocksMovements = await StocksActions.moving(
action=movingRecord.action,
source_toolbox_id=movingRecord.source_toolbox_id,
target_toolbox_id=target_toolbox_id,
toolkit_id=movingRecord.toolkit_id,
quantity=movingRecord.quantity,
user_id=user_id,
reason=writeDownARecord.reason,
reason=movingRecord.reason,
)
if not stocksMovements:
logger.error(f"Ошибка при {writeDownARecord.action} инструмента")
logger.error(f"Ошибка при {movingRecord.action} инструмента")
return False
accept = await StocksRecordsHandler.accept(
accept = await StocksRecordsHandler.decide(
record_id,
user_id,
stocksMovements[0].get("id"),
@@ -250,23 +278,23 @@ class StocksActions:
if len(stocksMovements) > 1:
for stock in stocksMovements[1:]:
recorded = await StocksRecordsHandler.add(
action=writeDownARecord.action,
action=movingRecord.action,
source_stock_id=stock.get("id"),
target_stock_id=None,
source_toolbox_id=writeDownARecord.source_toolbox_id,
target_toolbox_id=writeDownARecord.target_toolbox_id,
toolkit_id=writeDownARecord.toolkit_id,
init_user_id=writeDownARecord.init_user_id,
reason=writeDownARecord.reason,
source_toolbox_id=movingRecord.source_toolbox_id,
target_toolbox_id=target_toolbox_id,
toolkit_id=movingRecord.toolkit_id,
init_user_id=movingRecord.init_user_id,
reason=movingRecord.reason,
quantity=stock.get("quantity"),
price=stock.get("price"),
return_record_id=True,
)
if not recorded:
return False
accept = await StocksRecordsHandler.accept(
accept = await StocksRecordsHandler.decide(
record_id=recorded,
accept_user_id=user_id,
decision_user_id=user_id,
source_stock_id=stock.get("id"),
quantity=stock.get("quantity"),
price=stock.get("price"),
@@ -276,12 +304,11 @@ class StocksActions:
totalRecordsIds.append(recorded)
logger.info(
f"Записи {', '.join(map(str, totalRecordsIds))} о {writeDownARecord.action} инструмента успешно приняты {user_id}"
f"Записи {', '.join(map(str, totalRecordsIds))} о {movingRecord.action} инструмента успешно приняты {user_id}"
)
return True
async def takeToolkit(
self,
source_toolbox_id: int,
target_toolbox_id: int,
toolkit_id: int,
@@ -293,7 +320,7 @@ class StocksActions:
logger.info(
f"Формирование запроса на получение инструмента {toolkit_id} на склад {target_toolbox_id} со склада {source_toolbox_id} в количестве {quantity} ..."
)
takeRequest = await self.movingRequest(
takeRequest = await StocksActions.movingRequest(
action="Получение",
source_toolbox_id=source_toolbox_id,
target_toolbox_id=target_toolbox_id,
@@ -315,7 +342,7 @@ class StocksActions:
logger.info(
f"Принятие запроса {takeRequest} на получение инструмента {toolkit_id} ..."
)
accepted = await self.movingAcceptance(takeRequest, user_id)
accepted = await StocksActions.movingDecision(takeRequest, user_id)
if not accepted:
logger.error(
f"Принятие запроса {takeRequest} на получение инструмента {toolkit_id} не удалось"
@@ -327,6 +354,226 @@ class StocksActions:
return True
async def initialize():
# TODO прописать наполнение общих складов, получение на личные, возвраты и списания.
# Не все запросы на возвраты и списания нужно принять автоматически, нужно оставить несколько для демонстрации
pass
toolboxes = await ToolboxHandler.getAll()
toolboxesDict = {
toolbox.get("title"): toolbox.get("id") for toolbox in toolboxes
}
toolboxesOwners = {
toolbox.get("owner_id"): toolbox.get("id")
for toolbox in toolboxes
if toolbox.get("owner_id")
}
users = await UserHandler.getAll()
usersDict = {user.get("login"): user.get("id") for user in users}
toolkits = await ToolkitHandler.getAll()
logger.warning("Наполнение складов ...")
for toolkit in toolkits:
if "Сверло" in toolkit.get("title"):
toolboxId = toolboxesDict.get("Шкаф")
else:
toolboxId = toolboxesDict.get("Стеллаж")
placement = chr(65 + random.randint(0, 25)) + str(random.randint(1, 19))
registryCount = 5
logger.warning(
f">> Наполнение склада {toolboxId} инструментом {toolkit.get('title')}"
)
for i in range(registryCount):
quantity = random.randint(20, 30)
price = round(300 + random.random() * 500, 2)
logger.warning(f">>>> Количество: {quantity}, Цена: {price}")
success = await StocksActions.registration(
toolkit_id=toolkit.get("id"),
toolbox_id=toolboxId,
user_id=usersDict.get("storekeeper"),
quantity=quantity,
price=price,
placement=placement,
reason=f"Приход инструмента {toolkit.get('title')}. Счёт-фактура № {random.randint(1000, 10000)}-{i+1}",
)
if not success:
logger.error(f"Приход инструмента {toolkit.get('title')} не удался")
return False
logger.warning("Наполнение складов завершено")
logger.warning("Получение инструментов из общих складов ...")
accessLevels = await AccessLevelHandler.getAll()
accessLevelsDict = {
accessLevel.get("id"): accessLevel.get("available_own_toolbox")
for accessLevel in accessLevels
}
users = await UserHandler.getAll()
usersDict = {user.get("login"): user.get("id") for user in users}
for user in users:
userAccessLevelId = user.get("access_level_id")
if not accessLevelsDict.get(userAccessLevelId):
continue
own_toolbox_id = toolboxesOwners.get(user.get("id"))
logger.warning(
f"Получение инструментов из общего склада пользователем {user.get('login')} ..."
)
for toolkit in toolkits:
logger.warning(
f">> Выдача инструмента {toolkit.get('title')} пользователю {user.get('login')} ..."
)
if "Сверло" in toolkit.get("title"):
main_toolbox_id = toolboxesDict.get("Шкаф")
else:
main_toolbox_id = toolboxesDict.get("Стеллаж")
actionsCount = random.randint(3, 5)
for i in range(actionsCount):
success = await StocksActions.takeToolkit(
source_toolbox_id=main_toolbox_id,
target_toolbox_id=own_toolbox_id,
toolkit_id=toolkit.get("id"),
quantity=random.randint(10, 19),
reason=f"Получение инструмента {toolkit.get('title')}. Для выполнения заказа № {random.randint(1000, 10000)}",
user_id=user.get("id"),
)
if not success:
logger.error(
f"Получение инструмента {toolkit.get('title')} пользователю {user.get('login')} не удалось"
)
return False
logger.warning(
f">>>> Получение инструмента {toolkit.get('title')} пользователю {user.get('login')} успешно завершено"
)
logger.warning("Получение инструментов из общих складов завершено")
logger.warning("Направление запросов на возврат и списание инструментов ...")
requestsDict = {"Списание": [], "Возврат": []}
for user in users:
userAccessLevelId = user.get("access_level_id")
if not accessLevelsDict.get(userAccessLevelId):
continue
own_toolbox_id = toolboxesOwners.get(user.get("id"))
logger.warning(
f"Направление запросов на возврат и списание инструмента от пользователя {user.get('login')} ..."
)
for action in requestsDict.keys():
for toolkit in toolkits:
if action == "Списание":
main_toolbox_id = None
else:
if "Сверло" in toolkit.get("title"):
main_toolbox_id = toolboxesDict.get("Шкаф")
else:
main_toolbox_id = toolboxesDict.get("Стеллаж")
actionsCount = random.randint(1, 3)
for i in range(actionsCount):
success = await StocksActions.movingRequest(
action=action,
toolkit_id=toolkit.get("id"),
source_toolbox_id=own_toolbox_id,
target_toolbox_id=main_toolbox_id,
quantity=random.randint(3, 5),
reason=f"{action} инструмента {toolkit.get('title')}. После выполнения заказа",
user_id=user.get("id"),
return_record_id=True,
)
if not success:
logger.error(
f"{action} инструмента {toolkit.get('title')} пользователю {user.get('login')} не удалось"
)
return False
requestsDict.get(action).append(success)
logger.warning(
f">>>> {action} инструмента пользователю {user.get('login')} успешно завершено"
)
logger.warning(
"Направление запросов на возврат и списание инструментов завершено"
)
logger.warning("Обработка запросов на возврат и списание инструментов ...")
decisionsDict = {
"manager": {"accept": [], "reject": [], "ignore": []},
"storekeeper": {"accept": [], "reject": [], "ignore": []},
}
for recordsList in requestsDict.values():
managerList, storekeeperList = (
recordsList[: len(recordsList) // 2],
recordsList[len(recordsList) // 2 :],
)
(
decisionsDict["manager"]["accept"],
decisionsDict["manager"]["reject"],
decisionsDict["manager"]["ignore"],
) = (
managerList[: len(managerList) // 3],
managerList[len(managerList) // 3 : len(managerList) // 3 * 2],
managerList[len(managerList) // 3 * 2 :],
)
(
decisionsDict["storekeeper"]["accept"],
decisionsDict["storekeeper"]["reject"],
decisionsDict["storekeeper"]["ignore"],
) = (
storekeeperList[: len(storekeeperList) // 3],
storekeeperList[
len(storekeeperList) // 3 : len(storekeeperList) // 3 * 2
],
storekeeperList[len(storekeeperList) // 3 * 2 :],
)
for role in decisionsDict.keys():
user_id = usersDict.get(role)
for decision in decisionsDict.get(role).keys():
match decision:
case "accept":
accepted = True
case "reject":
accepted = False
case "ignore":
continue
for record_id in decisionsDict.get(role).get(decision):
success = await StocksActions.movingDecision(
record_id=record_id,
user_id=user_id,
accepted=accepted,
)
if not success:
logger.error(
f"Принятие записи {record_id} пользователем {role} не удалось"
)
return False
logger.warning(
"Обработка запросов на возврат и списание инструментов завершено"
)
return True