540 lines
23 KiB
Python
540 lines
23 KiB
Python
import uuid
|
|
from datetime import time
|
|
|
|
from app.config import TaskEnv
|
|
from app.models.project import ProjectPriceReport
|
|
from app.models.report import StatusReport, ReportCountry, DonutList, DelayDonutDetail, PhysicalMonth
|
|
from core.service.mongo_db import use_collection
|
|
|
|
|
|
class ReportRepository():
|
|
async def project_status(self, _inp: StatusReport, type):
|
|
if _inp.state:
|
|
match = {f'{type}.sts': {'$exists': 1}, 'design.state': _inp.state}
|
|
else:
|
|
match = {f'{type}.sts': {'$exists': 1}}
|
|
if _inp.type_id:
|
|
match.update({'design.type_id': _inp.type_id})
|
|
if _inp.nature_id:
|
|
match.update({'design.nature_id': _inp.nature_id})
|
|
if type == 'monitor' and _inp.monitor_type:
|
|
match.update({'monitor.base_information.type': _inp.monitor_type})
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{
|
|
"$match": match
|
|
},
|
|
{
|
|
'$group': {
|
|
'_id': f"${type}.sts",
|
|
'count': {'$sum': 1}
|
|
}
|
|
}
|
|
]).to_list(None)
|
|
return report
|
|
|
|
async def project_status_design(self, _inp: StatusReport):
|
|
return await self.project_status(_inp, 'design')
|
|
|
|
async def project_status_monitor(self, _inp: StatusReport):
|
|
return await self.project_status(_inp, 'monitor')
|
|
|
|
async def report_country(self, _inp: ReportCountry):
|
|
match = {}
|
|
if _inp.state:
|
|
match = {'design.state': _inp.state}
|
|
if _inp.type_id:
|
|
match.update({'design.type_id': _inp.type_id})
|
|
if _inp.nature_id:
|
|
match.update({'design.nature_id': _inp.nature_id})
|
|
if _inp.monitor_type:
|
|
match.update({'monitor.base_information.type': _inp.monitor_type})
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{"$match": match},
|
|
{'$group': {
|
|
'_id': "$design.state",
|
|
'nature_id': {'$addToSet': '$design.nature_id'},
|
|
'type_id': {'$addToSet': '$design.type_id'},
|
|
'monitor_type': {'$addToSet': '$monitor.base_information.type'}
|
|
}},
|
|
{'$project': {
|
|
'count_nature_id': {"$size": "$nature_id"},
|
|
'count_type_id': {"$size": "$type_id"},
|
|
'count_monitor_type': {"$size": "$monitor_type"},
|
|
"_id": 1
|
|
}}
|
|
]).to_list(None)
|
|
# count_nature = await use_collection(TaskEnv.CLN_PROJECT).count_documents(
|
|
# {'design.nature_id': _inp.nature_id})
|
|
# count_type = await use_collection(TaskEnv.CLN_PROJECT).count_documents({'design.type_id':_inp.type_id})
|
|
# count_monitor_type = await use_collection(TaskEnv.CLN_PROJECT).count_documents({'monitor.base_information.type': _inp.monitor_type})
|
|
# return {'count_nature':count_nature,'count_type':count_type,'count_monitor_type':count_monitor_type}
|
|
return report
|
|
|
|
async def exist_project_state(self,_inp: StatusReport):
|
|
match ={}
|
|
aggregate = []
|
|
if _inp.type_id:
|
|
match.update({'design.type_id': _inp.type_id})
|
|
if _inp.nature_id:
|
|
match.update({'design.nature_id': _inp.nature_id})
|
|
if _inp.monitor_type:
|
|
match.update({'monitor.base_information.type': _inp.monitor_type})
|
|
if match:
|
|
aggregate.append({"$match": match})
|
|
aggregate.append({
|
|
'$group': {
|
|
'_id': "$design.state",
|
|
'count': {'$sum': 1}
|
|
}
|
|
})
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate(aggregate).to_list(None)
|
|
return report
|
|
|
|
async def donut(self, _select: int):
|
|
report = None
|
|
if _select == 1:
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{"$group": {"_id": "$design.nature_id", 'count': {'$sum': 1}}}
|
|
]).to_list(None)
|
|
elif _select == 2:
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{
|
|
"$group": {
|
|
"_id": {
|
|
"$cond": [
|
|
{"$lt": ["$design.building_infrastructure", 1000]}, # Check if a < 10
|
|
"less_than_1000",
|
|
{
|
|
"$cond": [
|
|
{"$and": [{"$gte": ["$design.building_infrastructure", 1000]},
|
|
{"$lt": ["$design.building_infrastructure", 5000]}]},
|
|
# Check if 10 <= a < 20
|
|
"between_1000_and_5000",
|
|
{
|
|
"$cond": [
|
|
{"$and": [{"$gte": ["$design.building_infrastructure", 5000]},
|
|
{"$lt": ["$design.building_infrastructure", 15000]}]},
|
|
"between_5000_and_15000",
|
|
{
|
|
"$cond": [
|
|
{"$and": [{"$gte": ["$design.building_infrastructure", 15000]},
|
|
{"$lt": ["$design.building_infrastructure", 30000]}]},
|
|
"between_15000_and_30000",
|
|
"greater_than_or_equal_30000" # Otherwise, a >= 30
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"total": {"$sum": 1},
|
|
}
|
|
}
|
|
]).to_list(None)
|
|
|
|
elif _select == 3:
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{"$group": {"_id": "$design.type_id", 'count': {'$sum': 1}}}
|
|
]).to_list(None)
|
|
return report
|
|
|
|
async def list_donut(self, _inp: DonutList):
|
|
_filter = None
|
|
if _inp.type == 1:
|
|
_filter = {'design.nature_id': int(_inp.donut_select)}
|
|
if _inp.type == 2:
|
|
if _inp.donut_select == "less_than_1000":
|
|
_filter = {'design.building_infrastructure': {'$lt': 1000}}
|
|
elif _inp.donut_select == "between_1000_and_5000":
|
|
_filter = {'design.building_infrastructure': {'$lt': 5000, "$gte": 1000}}
|
|
elif _inp.donut_select == "between_5000_and_15000":
|
|
_filter = {'design.building_infrastructure': {'$lt': 15000, "$gte": 5000}}
|
|
elif _inp.donut_select == "between_15000_and_30000":
|
|
_filter = {'design.building_infrastructure': {'$lt': 30000, "$gte": 15000}}
|
|
else:
|
|
_filter = {'design.building_infrastructure': {'$gte': 30000}}
|
|
elif _inp.type == 3:
|
|
_filter = {'design.type_id': int(_inp.donut_select)}
|
|
report = await use_collection(TaskEnv.CLN_PROJECT).find(_filter).to_list(None)
|
|
|
|
return report
|
|
|
|
async def delay_donut(self, project_id:uuid.UUID):
|
|
report = await use_collection(TaskEnv.CLN_BILL_DELAY).aggregate([
|
|
{"$match":{'project_id':project_id}},
|
|
{'$group': {"_id": None, "total_financial": {"$sum": "$financial.total"},
|
|
"total_force_major": {"$sum": "$force_major.total"},
|
|
"total_technical": {"$sum": "$technical.total"},
|
|
"total_extra_new_work": {"$sum": "$extra_new_work"},
|
|
"total_other": {"$sum": "$other"},
|
|
}}
|
|
]).to_list(None)
|
|
return report
|
|
async def delay_donut_detail(self, _inp:DelayDonutDetail):
|
|
_group = {}
|
|
if _inp.select == 'financial':
|
|
_group = {"_id": None, "total_status": {"$sum": "$financial.status"},
|
|
"total_prepayment": {"$sum": "$financial.prepayment"},
|
|
"total_modification": {"$sum": "$financial.modification"},
|
|
"total_good_job": {"$sum": "$financial.good_job"},
|
|
}
|
|
elif _inp.select == 'force_major':
|
|
_group = {"_id": None, "total_force_event": {"$sum": "$force_major.force_event"},
|
|
"total_material": {"$sum": "$force_major.material"},
|
|
"total_rules": {"$sum": "$force_major.rules"},
|
|
"total_define_indicators": {"$sum": "$force_major.define_indicators"},
|
|
}
|
|
elif _inp.select == 'technical':
|
|
_group = {"_id": None, "total_map_technical": {"$sum": "$technical.map_technical"},
|
|
"total_permit": {"$sum": "$technical.permit"},
|
|
"total_purchase": {"$sum": "$technical.purchase"},
|
|
"total_suspense": {"$sum": "$technical.suspense"},
|
|
}
|
|
report = await use_collection(TaskEnv.CLN_BILL_DELAY).aggregate([
|
|
{"$match": {'project_id': _inp.project_id}},
|
|
{'$group': _group}
|
|
]).to_list(None)
|
|
return report
|
|
|
|
async def progress_activity(self,project_id:uuid.UUID):
|
|
secondary = await use_collection(TaskEnv.CLN_MONITOR_SECONDARY).find({"project_id":project_id}).to_list(None)
|
|
_obj = {}
|
|
for i in secondary:
|
|
_obj[str(i["_id"])] = i['title']
|
|
ids = [i["_id"] for i in secondary]
|
|
report = await use_collection(TaskEnv.CLN_MONITOR_SUB_SECONDARY).aggregate([
|
|
{"$match": {"parent_id": {"$in": ids}}},
|
|
{"$group": {
|
|
"_id":"$parent_id",
|
|
"total_program": {"$sum": "$program"},
|
|
"total_real": {"$sum": "$real"},
|
|
}}
|
|
]).to_list(None)
|
|
if report:
|
|
for i in report:
|
|
i["title"] = _obj[str(i["_id"])]
|
|
return report
|
|
|
|
async def categorize_deviation(self):
|
|
report = await use_collection(TaskEnv.CLN_MONITOR_PYSICAL).aggregate(
|
|
[{"$match": {"deviation": {"$exists": True, "$ne": None}}},
|
|
{"$group": {
|
|
"_id": {
|
|
"$cond": [
|
|
{"$lt": ["$deviation", 10]},
|
|
"less_than_10",
|
|
{
|
|
"$cond": [
|
|
{"$and": [{"$gte": ["$deviation", 10]}, {"$lt": ["$deviation", 25]}]},
|
|
"between_10_and_25",
|
|
{
|
|
"$cond": [
|
|
{"$and": [{"$gte": ["$deviation", 25]},
|
|
{"$lt": ["$deviation", 40]}]},
|
|
"between_25_and_40",
|
|
"greater_than_40"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"count": {"$sum": 1},
|
|
"projectIds": { "$addToSet": "$project_id" },
|
|
"totalDeviation": {"$sum": "$deviation"}, }}]).to_list(None)
|
|
return report
|
|
|
|
async def delay_donut_all(self):
|
|
report = await use_collection(TaskEnv.CLN_BILL_DELAY).aggregate([
|
|
{'$group': {"_id": None, "total_financial": {"$sum": "$financial.total"},
|
|
"total_force_major": {"$sum": "$force_major.total"},
|
|
"total_technical": {"$sum": "$technical.total"},
|
|
"total_extra_new_work": {"$sum": "$extra_new_work"},
|
|
"total_other": {"$sum": "$other"},
|
|
}}
|
|
]).to_list(None)
|
|
return report
|
|
|
|
async def list_delay_donut(self, _select: str):
|
|
get_list = []
|
|
_map = {'1': 'financial.total', '2': 'force_major.total', '3': 'technical.total', '4': 'extra_new_work',
|
|
'5': 'other'}
|
|
report = await use_collection(TaskEnv.CLN_BILL_DELAY).aggregate([
|
|
{'$match': {_map[_select]: {'$gt': 0}}},
|
|
{'$group': {"_id": '$project_id'}}
|
|
]).to_list(None)
|
|
if report:
|
|
for i in report:
|
|
get_list.append(i['_id'])
|
|
# projects = await use_collection(TaskEnv.CLN_PROJECT).find({"_id":{"$in":get_list}}).to_list(None)
|
|
return get_list
|
|
|
|
async def sum_add_time_end_project(self):
|
|
result = {}
|
|
result['less_than_20'] = []
|
|
result['bet_20_50']= []
|
|
result['bet_50_100'] = []
|
|
result['bet_100_200'] = []
|
|
result['upper_than_200'] = []
|
|
get_dict_project_id = {}
|
|
report = await use_collection(TaskEnv.CLN_BILL_DELAY).aggregate([
|
|
{'$group': {"_id": '$project_id', 'sum':{'$sum':'$total_day'}}}
|
|
]).to_list(None)
|
|
get_list_project_id = [i['_id'] for i in report] if report else []
|
|
get_dict_project_id.update( {str(i['_id']):i for i in report} if report else [])
|
|
list_project = await use_collection(TaskEnv.CLN_PROJECT).find({"_id":{"$in":get_list_project_id}}).to_list(None)
|
|
if list_project:
|
|
for i in list_project:
|
|
if 'first_time' in i['monitor']['detail'] and i['monitor']['sts'] == 5:
|
|
cal = (get_dict_project_id[str(i["_id"])]['sum']/i['monitor']['detail']['first_time'])*100
|
|
if cal < 20 :
|
|
result['less_than_20'].append(i["_id"])
|
|
elif cal < 50:
|
|
result['bet_20_50'].append(i["_id"])
|
|
elif cal < 100:
|
|
result['bet_50_100'].append(i["_id"])
|
|
elif cal < 200:
|
|
result['bet_100_200'].append(i["_id"])
|
|
else:
|
|
result['upper_than_200'].append(i["_id"])
|
|
return result
|
|
|
|
#درصد میانگین افزایش هزینه پروژه های خاتمه یافته
|
|
async def add_cost(self):
|
|
result = {}
|
|
result['less_than_20'] = []
|
|
result['bet_20_50'] = []
|
|
result['bet_50_100'] = []
|
|
result['bet_100_200'] = []
|
|
result['upper_than_200'] = []
|
|
report = await use_collection(TaskEnv.CLN_PROJECT_PRICE_REPORT).find({}).to_list(None)
|
|
if report:
|
|
for i in report:
|
|
_model = ProjectPriceReport(**i)
|
|
if 'amount_status' in _model and 'amount_adjust' in _model:
|
|
cal = (_model.first_amount-_model.amount_status +_model.amount_adjust)/_model.first_amount
|
|
if cal < 20:
|
|
result['less_than_20'].append(_model.project_id)
|
|
elif cal < 50:
|
|
result['bet_20_50'].append(_model.project_id)
|
|
elif cal < 100:
|
|
result['bet_50_100'].append(_model.project_id)
|
|
elif cal < 200:
|
|
result['bet_100_200'].append(_model.project_id)
|
|
else:
|
|
result['upper_than_200'].append(_model.project_id)
|
|
return result
|
|
|
|
async def progress_report(self):
|
|
result = await use_collection(TaskEnv.CLN_MONITOR_PYSICAL).aggregate([
|
|
{
|
|
"$sort": {'date_at': -1}
|
|
},
|
|
{
|
|
'$group':
|
|
{
|
|
'_id': "$project_id",
|
|
'records': {"$push": "$$ROOT"},
|
|
}
|
|
},
|
|
{
|
|
"$project": {
|
|
"_id": 1,
|
|
"records": {"$slice": ["$records", 1]},
|
|
|
|
}
|
|
},
|
|
]).to_list(None)
|
|
result_report = {
|
|
'less_than_1':[],
|
|
'bet_1_2':[],
|
|
'bet_2_5':[],
|
|
'upper_than_5':[],
|
|
}
|
|
|
|
for i in result:
|
|
print(i['records'])
|
|
if ('records' in i) and (len(i['records'])>0) and 'last_month' in i['records'][0]:
|
|
cal = i['records'][0]['last_month']
|
|
if cal < 1:
|
|
result_report['less_than_1'].append(i["_id"])
|
|
elif cal <= 2:
|
|
result_report['bet_1_2'].append(i["_id"])
|
|
elif cal <= 5:
|
|
result_report['bet_2_5'].append(i["_id"])
|
|
else:
|
|
result_report['upper_than_5'].append(i["_id"])
|
|
return result_report
|
|
|
|
async def progress_avg_report(self):
|
|
result = await use_collection(TaskEnv.CLN_MONITOR_PYSICAL).aggregate([
|
|
{
|
|
'$group':
|
|
{
|
|
'_id': "$project_id",
|
|
'avg':{'$avg': "$real"},
|
|
}
|
|
},
|
|
|
|
]).to_list(None)
|
|
result_report = {
|
|
'less_than_1':[],
|
|
'bet_1_2':[],
|
|
'bet_2_5':[],
|
|
'upper_than_5':[],
|
|
}
|
|
|
|
for i in result:
|
|
if i['avg'] < 1:
|
|
result_report['less_than_1'].append(i["_id"])
|
|
elif i['avg'] <= 2:
|
|
result_report['bet_1_2'].append(i["_id"])
|
|
elif i['avg'] <= 5:
|
|
result_report['bet_2_5'].append(i["_id"])
|
|
else:
|
|
result_report['upper_than_5'].append(i["_id"])
|
|
return result_report
|
|
|
|
async def progress_month_report(self,_inp:PhysicalMonth):
|
|
from datetime import datetime, time
|
|
to_date = datetime.combine(_inp.to_date.date(), time.max)
|
|
from_date = _inp.from_date.combine(_inp.from_date.date(), time.min)
|
|
result = await use_collection(TaskEnv.CLN_MONITOR_PYSICAL).aggregate([
|
|
{"$match":{"date_at":{"$lte":to_date,"$gte":from_date}}},
|
|
{
|
|
"$sort": {'date_at': -1}
|
|
},
|
|
{"$group":
|
|
{'_id': {"year": "$year", "month": "$month"},
|
|
'avg': {'$avg': "$real"}},
|
|
}
|
|
]).to_list(None)
|
|
return result
|
|
|
|
async def design_progress_status(self):
|
|
result = await use_collection("design_progress").aggregate([
|
|
{'$match':{'complete_at':{"$exists":0},'parent_id':{"$exists":0}}},
|
|
{"$group":
|
|
{'_id': '$type',
|
|
'count': {'$sum': 1},
|
|
"projectIds": {"$addToSet": "$project_id"},
|
|
},
|
|
}
|
|
]).to_list(None)
|
|
return result
|
|
|
|
async def design_progress_status_state(self):
|
|
result = await use_collection("design_progress").aggregate([
|
|
{'$match':{'complete_at':{"$exists":0},'parent_id':{"$exists":0}}},
|
|
{"$group":
|
|
{'_id': {'state':"$state",'type':'$type'},
|
|
'count': {'$sum': 1},
|
|
"projectIds": {"$addToSet": "$project_id"},
|
|
},
|
|
}
|
|
]).to_list(None)
|
|
return result
|
|
#روند وضعیت پروژه ها
|
|
async def design_progress_status_progress(self):
|
|
result = await use_collection("design_progress").aggregate([
|
|
{'$match':{'complete_at':{"$exists":0},'parent_id':{"$exists":0}}},
|
|
{"$group":
|
|
{'_id': {"created_at": {
|
|
"$dateToString": {
|
|
"format": "%Y-%m-%d", # Format to extract date only (YYYY-MM-DD)
|
|
"date": "$created_at"
|
|
}
|
|
},'type':'$type'},
|
|
'count': {'$sum': 1},
|
|
"projectIds": {"$addToSet": "$project_id"},
|
|
},
|
|
}
|
|
]).to_list(None)
|
|
return result
|
|
|
|
async def design_sts(self):
|
|
result = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{"$group":{"_id":'$design.sts','count':{'$sum':1},"projectIds": {"$addToSet": "$_id"}}}
|
|
]).to_list(None)
|
|
return result
|
|
|
|
async def status_agreement(self):
|
|
result = await use_collection(TaskEnv.CLN_PROJECT).aggregate([
|
|
{'$match':{'design.status_agreement':{"$exists":1}}},
|
|
{"$group":{"_id":'$design.status_agreement','count':{'$sum':1},"projectIds": {"$addToSet": "$_id"}}}
|
|
]).to_list(None)
|
|
return result
|
|
|
|
async def status_agreement_progress(self):
|
|
result = await use_collection(TaskEnv.CLN_PROJECT_AGREEMENT).aggregate([
|
|
{
|
|
"$group": {
|
|
"_id": {
|
|
"created_at": {
|
|
"$dateToString": {
|
|
"format": "%Y-%m-%d", # Format to extract date only (YYYY-MM-DD)
|
|
"date": "$created_at"
|
|
}
|
|
},
|
|
"status": "$status"
|
|
},
|
|
"count": {"$sum": 1},
|
|
"projectIds": {"$addToSet": "$_id"}
|
|
}
|
|
}
|
|
]).to_list(None)
|
|
|
|
return result
|
|
async def get_extra_project(self,project_id:uuid):
|
|
res = {}
|
|
records_status = await (
|
|
use_collection(TaskEnv.CLN_AUDIT_STATUS)
|
|
.find({"project_id": project_id})
|
|
.sort('$natural', -1)
|
|
.to_list(None)
|
|
)
|
|
res['count_audit_status'] = len(records_status)
|
|
res['last_audit_status'] = records_status[0].get('amount') if records_status else None
|
|
|
|
financial_adjust = await use_collection(TaskEnv.CLN_FINANCIAL_ADJUST).count_documents({'project_id': project_id})
|
|
res['count_financial_adjust'] = financial_adjust
|
|
financial_adjust_accept = await use_collection(TaskEnv.CLN_FINANCIAL_ADJUST).find({'project_id': project_id,'amount_cycle_supervisor':{"$exists":1}}).sort('$natural', -1).to_list(None)
|
|
|
|
if financial_adjust_accept and len(financial_adjust_accept) > 0 and 'amount_cycle_supervisor' in financial_adjust_accept[0]:
|
|
res['last_financial_adjust'] = financial_adjust_accept[0]['amount_cycle_supervisor']
|
|
else:
|
|
res['last_financial_adjust'] = None
|
|
stats = await use_collection(TaskEnv.CLN_AUDIT_PROGRAM).aggregate([
|
|
{"$match": {"project_id": project_id}},
|
|
{
|
|
"$group": {
|
|
"_id": None,
|
|
"sum_diff": {"$sum": "$diff_price"},
|
|
"count": {"$sum": 1},
|
|
"diff_prices": {
|
|
"$push": "$diff_price"
|
|
}
|
|
}
|
|
}
|
|
]).to_list(None)
|
|
if stats:
|
|
sum_diff = stats[0]["sum_diff"]
|
|
diff_prices = stats[0]["diff_prices"]
|
|
result = []
|
|
for diff in diff_prices:
|
|
percentage = round((diff / sum_diff) * 100, 2) if sum_diff else 0
|
|
result.append({
|
|
"diff_price": diff,
|
|
"percentage": percentage
|
|
})
|
|
res['audit_program'] = result
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
|