first commit
This commit is contained in:
248
app/api/v1/statistics.py
Normal file
248
app/api/v1/statistics.py
Normal file
@ -0,0 +1,248 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user