Files
CRM-OLD-API/app/api/v1/statistics.py
2025-07-24 20:13:47 +03:00

249 lines
7.7 KiB
Python

from time import time
from typing import Optional
from fastapi import APIRouter
from pydantic import BaseModel
from app import mongo
from app.mongo import deals_collection, transactions_collection
from app.utils.response_util import response
router = APIRouter()
class ProfitParams(BaseModel):
baseMarketplaceKey: str
boardId: int
clientId: int
dateRange: list
dealStatusId: int
expenseTagId: int
incomeTagId: int
isCompletedOnly: bool
managerId: int
projectId: int
groupTableBy: Optional[int] = None
def get_item_date(item: dict):
if item.get("completedAt"):
return item["completedAt"].split("T")[0]
if item.get("createdAt"):
return item["createdAt"].split("T")[0]
if item.get("spentDate"):
return item["spentDate"]
async def group_key(item: dict, group_by: int) -> Optional[str]:
if group_by == 0:
return get_item_date(item)
elif group_by == 1:
return item["clientName"]
elif group_by == 2:
project = await mongo.projects_collection.find_one({"id": item["board"]["projectId"]})
return project["name"] if project else None
elif group_by == 3:
board = await mongo.boards_collection.find_one({"id": item["board"]["id"]})
return board["name"] if board else None
elif group_by == 4:
return item["statusId"]
elif group_by == 5:
return item["shippingWarehouse"]
elif group_by == 6:
return item["baseMarketplace"]["name"]
elif group_by == 7:
manager = await mongo.users_collection.find_one({"id": item.get("managerId")})
return manager["name"] if manager else None
return None
async def get_profit_data(params: ProfitParams):
start_datetime = f'{params.dateRange[0]}T00:00:00'
end_datetime = f'{params.dateRange[1]}T23:59:59.999'
deals_query = {
"$and": [
{
"$or": [
{"isDeleted": False},
{"isDeleted": {"$exists": False}}
]
},
{
"$or": [
{"completedAt": {"$gte": start_datetime, "$lte": end_datetime}},
{"$and": [
{"completedAt": None},
{"createdAt": {"$gte": start_datetime, "$lte": end_datetime}}
]}
]
}
]
}
if params.dealStatusId != -1:
deals_query["statusId"] = params.dealStatusId
elif params.boardId != -1:
deals_query["board.id"] = params.boardId
elif params.projectId != -1:
deals_query["project.id"] = params.projectId
if params.isCompletedOnly:
deals_query["isCompleted"] = True
client = None
if params.clientId != -1:
client = await mongo.clients_collection.find_one({"id": params.clientId}, {"_id": False})
deals = []
for deal in await deals_collection.find(deals_query, {"_id": False}).to_list(None):
if params.baseMarketplaceKey != "all" and deal["baseMarketplace"]["key"] != params.baseMarketplaceKey:
continue
if client and deal["clientName"] != client["name"]:
continue
deals.append(deal)
transactions_query = {
"spentDate": {"$gte": params.dateRange[0], "$lte": params.dateRange[1]},
}
filter_income_tag = params.incomeTagId != -1
filter_expense_tag = params.expenseTagId != -1
transactions = await transactions_collection.find(transactions_query, {"_id": False}).to_list(None)
if filter_income_tag or filter_expense_tag:
def tag_matches(item, tag_id):
return any(tag.get("id") == tag_id for tag in item.get("tags", []))
filtered_transactions = []
for transaction in transactions:
if transaction["isIncome"] and filter_income_tag:
if tag_matches(transaction, params.incomeTagId):
filtered_transactions.append(transaction)
elif not transaction["isIncome"] and filter_expense_tag:
if tag_matches(transaction, params.expenseTagId):
filtered_transactions.append(transaction)
elif not filter_income_tag and not filter_expense_tag:
filtered_transactions.append(transaction)
transactions = filtered_transactions
return deals, transactions
@router.post("/get-profit-chart-data", tags=["Profit"])
async def get_profit_chart_data(params: ProfitParams):
start_time = time()
deals, transactions = await get_profit_data(params)
deals_total_prices = await mongo.get_deals_total_prices(*deals)
grouped = {}
for deal in deals:
date = get_item_date(deal)
if date not in grouped:
grouped[date] = {
"date": date,
"revenue": 0,
"expenses": 0,
"profit": 0,
"dealsCount": 0
}
grouped[date]["dealsCount"] += 1
if deal.get("isCompleted") or deal.get("completedAt"):
total_price = deals_total_prices.get(deal["id"])
if total_price:
grouped[date]["revenue"] += total_price
grouped[date]["profit"] += total_price
for transaction in transactions:
date = transaction["spentDate"]
if date not in grouped:
grouped[date] = {
"date": date,
"revenue": 0,
"expenses": 0,
"profit": 0,
"dealsCount": 0
}
if transaction["isIncome"]:
grouped[date]["revenue"] += transaction["amount"]
grouped[date]["profit"] += transaction["amount"]
else:
grouped[date]["expenses"] += transaction["amount"]
grouped[date]["profit"] -= transaction["amount"]
sorted_grouped_values = [value for _, value in sorted(grouped.items())]
return response({"data": sorted_grouped_values}, start_time=start_time)
@router.post("/get-profit-table-data", tags=["Profit"])
async def get_profit_table_data(params: ProfitParams):
start_time = time()
deals, transactions = await get_profit_data(params)
deals_total_prices = await mongo.get_deals_total_prices(*deals)
grouped = {}
for deal in deals:
key = await group_key(deal, params.groupTableBy)
if not key:
continue
if key not in grouped:
grouped[key] = {
"groupedValue": key,
"revenue": 0,
"expenses": 0,
"profit": 0,
"dealsCount": 0
}
grouped[key]["dealsCount"] += 1
if deal.get("isCompleted") or deal.get("completedAt"):
total_price = deals_total_prices.get(deal["id"])
if total_price:
grouped[key]["revenue"] += total_price
grouped[key]["profit"] += total_price
if params.groupTableBy == 0:
for transaction in transactions:
key = await group_key(transaction, params.groupTableBy)
if not key:
continue
if key not in grouped:
grouped[key] = {
"groupedValue": key,
"revenue": 0,
"expenses": 0,
"profit": 0,
"dealsCount": 0
}
if transaction["isIncome"]:
grouped[key]["revenue"] += transaction["amount"]
grouped[key]["profit"] += transaction["amount"]
else:
grouped[key]["expenses"] += transaction["amount"]
grouped[key]["profit"] -= transaction["amount"]
sorted_grouped_values = [value for _, value in sorted(grouped.items())]
return response({"data": sorted_grouped_values}, start_time=start_time)