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