249 lines
7.7 KiB
Python
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)
|