import arrow from typing import Optional, Dict from services.common.redis_handler import RedisHandler, RedisSaveModels from services.common.models import BuildingCluster, BuildPart, BuildLivingSpace, Person, User, OccupantType, BuildRequirements from prisma_client import PrismaService class DefaultImportsToMemory: def __init__(self, prisma_service: Optional[PrismaService] = None): self.prisma_service = None if prisma_service: self.prisma_service = prisma_service self.redis_handler = RedisHandler() self.today = arrow.now().to('GMT+3').datetime # Redis Actions async def get_count_person_data_due_to_build_info(self) -> Optional[BuildRequirements]: """Get count of person data due to build with comprehensive inner joins""" return self.redis_handler.get_json(RedisSaveModels.COMMENT_BUILDING_INFO) async def set_count_person_data_due_to_build_info(self, data: BuildRequirements): """Set count of person data due to build with comprehensive inner joins""" return self.redis_handler.set_json(RedisSaveModels.COMMENT_BUILDING_INFO, data.dict()) async def get_count_person_data_due_to_build_data(self): """Get count of person data due to build with comprehensive inner joins""" data = self.redis_handler.get_json(RedisSaveModels.COMMENT_BUILDING_CLUSTER) return {i: BuildingCluster(**v) for i, v in data.items()} async def set_count_person_data_due_to_build_data(self, data: Dict[str, BuildingCluster]): """Set count of person data due to build with comprehensive inner joins""" excluded_dict = {i: v.dict(exclude_none=True) for i, v in data.items()} return self.redis_handler.set_json(RedisSaveModels.COMMENT_BUILDING_CLUSTER, excluded_dict) # Database Actions def check_if_database_is_available(self): if not self.prisma_service: raise ValueError("PrismaService is not initialized") async def get_count_person_data_due_to_build(self) -> BuildRequirements: """Get count of person data due to build with comprehensive inner joins""" self.check_if_database_is_available() async with self.prisma_service._asession() as db: occupant_flat_owner = await db.occupant_types.find_first(where={"occupant_code": "FL-OWN", "active": True, "is_confirmed": True}, include={"user_types": True}) occupant_tenant = await db.occupant_types.find_first(where={"occupant_code": "FL-TEN", "active": True, "is_confirmed": True}, include={"user_types": True}) possible_money_sender_occupants = [occupant_flat_owner.id, occupant_tenant.id] building_count = await db.build.count(where={"active": True, "is_confirmed": True,"expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}}) build_parts_count = await db.build_parts.count(where={"active": True, "is_confirmed": True, "human_livable": True, "expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}}) living_spaces_count = await db.build_living_space.count( where={"active": True, "is_confirmed": True, "expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}, "occupant_type_id": {"in": possible_money_sender_occupants}}, ) return BuildRequirements(building_count=building_count, living_space=living_spaces_count, build_parts=build_parts_count) async def retrieve_all_person_data_due_to_build(self) -> Dict[str, BuildingCluster]: """ Get all person data due to build with comprehensive inner joins Returns a dictionary of buildings clustered with their build parts, people, and living spaces """ self.check_if_database_is_available() buildings_dict = {} async with self.prisma_service._asession() as db: occupant_flat_owner = await db.occupant_types.find_first(where={"occupant_code": "FL-OWN", "active": True, "is_confirmed": True}, include={"user_types": True}) occupant_tenant = await db.occupant_types.find_first(where={"occupant_code": "FL-TEN", "active": True, "is_confirmed": True}, include={"user_types": True}) possible_money_sender_occupants = [occupant_flat_owner.id, occupant_tenant.id] buildings = await db.build.find_many(where={"active": True, "is_confirmed": True,"expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}}) for build in buildings: buildings_dict[str(build.id)] = BuildingCluster( id=build.id, uu_id=build.uu_id, build_name=build.build_name, build_no=build.build_no, build_date=str(build.build_date), decision_period_date=str(build.decision_period_date), expiry_starts=str(build.expiry_starts), expiry_ends=str(build.expiry_ends), is_confirmed=build.is_confirmed, active=build.active, build_parts=[] ) build_parts = await db.build_parts.find_many(where={"build_id": build.id, "active": True, "is_confirmed": True, "human_livable": True, "expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}}) for build_part in build_parts: part_obj = BuildPart( id=build_part.id, uu_id=build_part.uu_id, part_no=build_part.part_no, part_level=build_part.part_level, part_code=build_part.part_code, part_gross_size=build_part.part_gross_size, part_net_size=build_part.part_net_size, human_livable=build_part.human_livable, build_id=build_part.build_id, build_uu_id=build_part.build_uu_id, is_confirmed=build_part.is_confirmed, active=build_part.active, living_spaces=[], build=None ) living_spaces = await db.build_living_space.find_many( include={"occupant_types": True, "people": {"include": {"users": True}}}, where={"build_parts_id": build_part.id, "active": True, "is_confirmed": True, "expiry_starts": {"lte": self.today}, "expiry_ends": {"gte": self.today}, "occupant_type_id": {"in": possible_money_sender_occupants}}, ) for living_space in living_spaces: person = living_space.people user = await db.users.find_first(where={"person_id": person.id, "active": True, "is_confirmed": True}) user_of_person = None if user: user_of_person = User( id=user.id, uu_id=user.uu_id, user_tag=user.user_tag, user_type=user.user_type, email=user.email, phone_number=user.phone_number, related_company=user.related_company, is_confirmed=user.is_confirmed, active=user.active ) person_obj = Person( id=person.id, uu_id=person.uu_id, firstname=person.firstname, surname=person.surname, middle_name=person.middle_name, birthname=person.birthname, is_confirmed=person.is_confirmed, active=person.active, user=user_of_person ) occupant_type = living_space.occupant_types occupant_type_obj = OccupantType( id=occupant_type.id, uu_id=occupant_type.uu_id, occupant_code=occupant_type.occupant_code, occupant_type=occupant_type.occupant_type, is_confirmed=occupant_type.is_confirmed, active=occupant_type.active, user_type_uu_id=occupant_type.user_type_uu_id ) living_space_obj = BuildLivingSpace( id=living_space.id, uu_id=living_space.uu_id, expiry_starts=str(living_space.expiry_starts), expiry_ends=str(living_space.expiry_ends), fix_value=float(living_space.fix_value), fix_percent=float(living_space.fix_percent), agreement_no=living_space.agreement_no, marketing_process=living_space.marketing_process, build_parts_id=living_space.build_parts_id, build_parts_uu_id=living_space.build_parts_uu_id, person_id=living_space.person_id, person_uu_id=living_space.person_uu_id, occupant_type_id=living_space.occupant_type_id, occupant_type_uu_id=living_space.occupant_type_uu_id, is_confirmed=living_space.is_confirmed, active=living_space.active, person=person_obj, occupant_types=occupant_type_obj ) part_obj.living_spaces.append(living_space_obj) buildings_dict[str(build.id)].build_parts.append(part_obj) return buildings_dict async def retrieve_all_companies_data(self): self.check_if_database_is_available() async with self.prisma_service._asession() as db: return db.companies.find_many(where={"active": True, "is_confirmed": True}) async def renew_requirements(self): self.check_if_database_is_available() async def set_to_redis(): await self.set_count_person_data_due_to_build_info(count_person_data_due_to_build_info_db) all_person_data = await self.retrieve_all_person_data_due_to_build() await self.set_count_person_data_due_to_build_data(all_person_data) return count_person_data_due_to_build_info_db = await self.get_count_person_data_due_to_build() count_person_data_due_to_build_info_memory = await self.get_count_person_data_due_to_build_info() if not count_person_data_due_to_build_info_memory: return await set_to_redis() all_counts_in_memory = [count_person_data_due_to_build_info_memory.building_count, count_person_data_due_to_build_info_memory.living_space, count_person_data_due_to_build_info_memory.build_parts] all_counts_in_db = [count_person_data_due_to_build_info_db.building_count, count_person_data_due_to_build_info_db.living_space, count_person_data_due_to_build_info_db.build_parts] if not all_counts_in_memory == all_counts_in_db: return await set_to_redis()