make refactor (easy, simpler, DRY, KISS, reduce dublications) for BaseService.

backend/app/base/repo/base_repo.py:

from app.base.model.base_model import BaseModel as BaseAlchemyModel
from app.base.utils import get_current_datetime
T=TypeVar('T',bound=BaseAlchemyModel)
class BaseRepo(Generic[T,]):
	def __init__(self,model):self.model=model
	async def _commit_and_refresh(self,db,instance):
		try:await db.commit();await db.refresh(instance)
		except Exception as e:await db.rollback();logger.error(f"Transaction rolled back. Error: {e}",exc_info=True);raise
	async def _execute_query(self,db,stmt):result=await db.execute(stmt);return result.scalars().first()
	async def _execute_update(self,db,id,data):
		stmt=update(self.model).where(self.model.id==id).values(**data).returning(self.model);result=await db.execute(stmt);instance=result.scalars().first()
		if instance:await self._commit_and_refresh(db,instance)
		return instance
	def _get_relationships(self,relation_model):return[attr for attr in dir(self.model)if isinstance(getattr(self.model,attr).property,RelationshipProperty)and getattr(self.model,attr).property.mapper.class_==relation_model]
	async def _get_by_field(self,db,field,value,get_deleted=False):
		filters=[getattr(self.model,field)==value]
		if not get_deleted:filters.append(self.model.enabled.is_(True))
		stmt=select(self.model).where(*filters);return await self._execute_query(db,stmt)
	def _sort_order(self,field):return getattr(self.model,field[1:]).desc()if field.startswith('-')else getattr(self.model,field).asc()
	async def _update_instance(self,db,instance,defaults,kwargs):
		update_data={**defaults,**kwargs}if defaults else kwargs
		for(key,value)in update_data.items():
			if hasattr(instance,key):setattr(instance,key,value)
		await self._commit_and_refresh(db,instance)
	async def create(self,db,data):new_item=self.model(**data);db.add(new_item);await self._commit_and_refresh(db,new_item);return new_item
	async def get_by_id(self,db,id,get_deleted=False):return await self._get_by_field(db,'id',id,get_deleted)
	async def get_by_uuid(self,db,uuid,include_relations=False,relation_model=None):
		stmt=select(self.model).where(self.model.uuid==uuid,self.model.enabled.is_(True))
		if include_relations and relation_model:
			for rel in self._get_relationships(relation_model):stmt=stmt.options(selectinload(getattr(self.model,rel)))
		return await self._execute_query(db,stmt)
	async def get_id_by_uuid(self,db,uuid,get_deleted=False):return await self._get_by_field(db,'uuid',uuid,get_deleted)
	async def get_uuid_by_id(self,db,id,get_deleted=False):return await self._get_by_field(db,'id',id,get_deleted)
	async def get_by_name(self,db,name):return await self._get_by_field(db,'name',name)
	async def update(self,db,id,data):data['updated_at']=get_current_datetime();return await self._execute_update(db,id,data)
	async def soft_delete(self,db,id):
		existing_item=await self._get_by_field(db,'id',id,get_deleted=True)
		if not existing_item or not existing_item.enabled:return None
		return await self._execute_update(db,id,{'deleted_at':get_current_datetime(),'enabled':False})
	async def hard_delete(self,db,id):stmt=delete(self.model).where(self.model.id==id);result=await db.execute(stmt);await db.commit();return result.rowcount>0
	async def get_multi(self,db,*,skip=0,limit=100,filter_by=None,order_by=None):
		stmt=select(self.model).where(self.model.enabled.is_(True))
		if filter_by:stmt=stmt.filter(self._build_filters(filter_by))
		if order_by:stmt=stmt.order_by(*[self._sort_order(field)for field in order_by])
		stmt=stmt.offset(skip).limit(limit);result=await db.execute(stmt);return result.scalars().all()
	async def count(self,db,filter_by=None):
		stmt=select(func.count()).select_from(self.model).where(self.model.enabled.is_(True))
		if filter_by:stmt=stmt.filter(self._build_filters(filter_by))
		result=await db.execute(stmt);return result.scalar_one()
	async def exists(self,db,id):return await self._get_by_field(db,'id',id)is not None
	async def get_or_create(self,db,defaults=None,**kwargs):
		instance=await self.get_by_filters(db,**kwargs)
		if instance:return instance,False
		if defaults:kwargs.update(defaults)
		new_instance=await self.create(db,kwargs);return new_instance,True
	async def update_or_create(self,db,defaults=None,**kwargs):
		unique_criteria={k:v for(k,v)in kwargs.items()if k in self.model.__table__.primary_key.columns or self.model.__table__.columns[k].unique};instance=await self.get_by_filters(db,**unique_criteria)
		if instance:await self._update_instance(db,instance,defaults,kwargs);return instance,False
		create_data={**defaults,**kwargs}if defaults else kwargs
		try:new_instance=await self.create(db,create_data);return new_instance,True
		except IntegrityError as e:logger.error(f"IntegrityError during update_or_create: {e}");raise
	async def get_by_filters(self,db,**kwargs):
		stmt=select(self.model).where(self.model.enabled.is_(True))
		for(key,value)in kwargs.items():stmt=stmt.filter(getattr(self.model,key)==(value.value if isinstance(value,Enum)else value))
		instance=await self._execute_query(db,stmt);logger.debug(f"{'Found'if instance else'No'} instance found matching filters: {kwargs}");return instance
	def _build_filters(self,filter_by):
		if'or_'in filter_by:return or_(*[self._build_filters(f)for f in filter_by['or_']])
		if'and_'in filter_by:return and_(*[self._build_filters(f)for f in filter_by['and_']])
		return and_(*[self._build_filter(key,value)for(key,value)in filter_by.items()])
	def _build_filter(self,key,value):
		if isinstance(value,dict):
			op=list(value.keys())[0]
			if op=='like':return getattr(self.model,key).like(value[op])
			elif op=='lt':return self._build_lt_filter(key,value[op])
		return getattr(self.model,key)==value
	def _build_lt_filter(self,key,value):
		attr=getattr(self.model,key)
		if isinstance(attr.type,Date):return func.date(attr)<func.date(bindparam(key,value))
		return attr<bindparam(key,value)
		
backend/app/base/service/base_service.py:
```
...

from pydantic import BaseModel as BasePydanticModel

from app.base.exceptions import InvalidFilterKeyError
from app.base.model.base_model import BaseModel as BaseAlchemyModel
from sqlalchemy.ext.asyncio import AsyncSession
from app.base.repo.base_repo import BaseRepo
from app.base.schema.base_schema import BaseSchema as BaseDTO
from app.base.utils import error_handler_service

T = TypeVar("T", bound=BaseAlchemyModel)
CreateT = TypeVar("CreateT", bound=BasePydanticModel)
ReadT = TypeVar("ReadT", bound=BasePydanticModel)
UpdateT = TypeVar("UpdateT", bound=BasePydanticModel)
ListReadT = TypeVar("ListReadT", bound=BasePydanticModel)
DeleteT = TypeVar("DeleteT", bound=BasePydanticModel)
RepoT = TypeVar("RepoT", bound=BaseRepo)


class BaseMapper(Generic[T]):
    @staticmethod
    def to_dto(obj: T, dto_class: Type[BaseDTO]) -> BaseDTO:
        return dto_class.model_validate(obj)

    @staticmethod
    def to_entity(dto: BaseDTO, entity_class: Type[T]) -> T:
        return entity_class(**dto.model_dump())


class BaseService(
    Generic[
        T,
        CreateT,
        ReadT,
        UpdateT,
        ListReadT,
        DeleteT,
        RepoT,
    ],
):
    def __init__(self, repo: RepoT, mapper: BaseMapper[T]):
        self.repo: RepoT = repo
        self.mapper: BaseMapper = mapper
        self.model: Type[T] = repo.model
        self.create_schema: Type[CreateT] | None = None
        self.read_schema: Type[ReadT] | None = None
        self.update_schema: Type[UpdateT] | None = None
        self.list_read_schema: Type[ListReadT] | None = None
        self.delete_schema: Type[DeleteT] | None = None

    @error_handler_service
    async def _get_id_by_uuid(
        self,
        db: AsyncSession,
        uuid: UUID,
        get_deleted: bool = False,
    ) -> int | None:
        return await self.repo.get_id_by_uuid(db, uuid, get_deleted)

    @error_handler_service
    async def _validate_filter_keys(self, filter_by: dict[str, Any] | None):
        if filter_by:
            invalid_keys = [
                key for key in filter_by if not hasattr(self.repo.model, key)
            ]
            if invalid_keys:
                raise InvalidFilterKeyError(", ".join(invalid_keys))

    @error_handler_service
    async def create(self, db: AsyncSession, data: CreateT) -> ReadT:
        db_item = await self.repo.create(db, data.model_dump())
        return self.mapper.to_dto(db_item, self.read_schema)

    @error_handler_service
    async def get_by_uuid(
        self,
        db: AsyncSession,
        uuid: UUID,
        include_relations: bool = False,
        relation_model: Type[BaseAlchemyModel] | None = None,
    ) -> ReadT | None:
        db_item = await self.repo.get_by_uuid(
            db,
            uuid,
            include_relations,
            relation_model,
        )
        return (
            self.mapper.to_dto(db_item, self.read_schema) if db_item else None
        )

    @error_handler_service
    async def get_multi(
        self,
        db: AsyncSession,
        *,
        skip: int = 0,
        limit: int = 100,
        filter_by: dict[str, Any] | None = None,
        order_by: list[str] | None = None,
    ) -> list[ListReadT]:
        await self._validate_filter_keys(filter_by)
        db_items = await self.repo.get_multi(
            db,
            skip=skip,
            limit=limit,
            filter_by=filter_by,
            order_by=order_by,
        )
        return [
            self.mapper.to_dto(item, self.list_read_schema)
            for item in db_items
        ]

    @error_handler_service
    async def update(
        self,
        db: AsyncSession,
        uuid: UUID,
        data: UpdateT,
    ) -> ReadT | None:
        object_id = await self._get_id_by_uuid(db, uuid)
        if not object_id:
            return None
        update_data = data.model_dump(exclude_unset=True)
        db_item = await self.repo.update(
            db,
            id=object_id,
            data=update_data,
        )
        return self.mapper.to_dto(db_item, self.read_schema)

    @error_handler_service
    async def count(
        self,
        db: AsyncSession,
        filter_by: dict[str, Any] | None = None,
    ) -> int:
        await self._validate_filter_keys(filter_by)
        return await self.repo.count(db, filter_by=filter_by)

    @error_handler_service
    async def exists(self, db: AsyncSession, uuid: UUID) -> bool:
        object_id = await self._get_id_by_uuid(db, uuid)
        if not object_id:
            return False
        return await self.repo.exists(db=db, id=object_id)

    @error_handler_service
    async def get_or_create(
        self,
        db: AsyncSession,
        defaults: dict[str, Any] | None = None,
        **kwargs,
    ) -> tuple[ReadT, bool]:
        db_item, created = await self.repo.get_or_create(
            db=db,
            defaults=defaults,
            **kwargs,
        )
        return self.mapper.to_dto(db_item, self.read_schema), created

    @error_handler_service
    async def update_or_create(
        self,
        db: AsyncSession,
        defaults: dict[str, Any] | None = None,
        **kwargs,
    ) -> tuple[ReadT, bool]:
        db_item, created = await self.repo.update_or_create(
            db=db,
            defaults=defaults,
            **kwargs,
        )
        return self.mapper.to_dto(db_item, self.read_schema), created

    @error_handler_service
    async def soft_delete(
        self,
        db: AsyncSession,
        uuid: UUID,
    ) -> DeleteT | None:
        object_id = await self.repo.get_id_by_uuid(db, uuid)
        if not object_id:
            return None
        deleted_item = await self.repo.soft_delete(db=db, id=object_id)
        return self.mapper.to_dto(deleted_item, self.delete_schema)

    @error_handler_service
    async def hard_delete(self, db: AsyncSession, uuid: UUID) -> bool:
        object_id = await self.repo.get_id_by_uuid(db, uuid)
        if not object_id:
            return False
        return await self.repo.hard_delete(db=db, id=object_id)

    @error_handler_service
    async def restore(self, db: AsyncSession, uuid: UUID) -> ReadT | None:
        object_id = await self._get_id_by_uuid(db, uuid, get_deleted=True)
        if not object_id:
            return None
        restored = await self.repo.update(
            db=db,
            id=object_id,
            data={"deleted_at": None, "enabled": True},
        )
        return self.mapper.to_dto(restored, self.read_schema)

    @error_handler_service
    async def get_deleted(
        self,
        db: AsyncSession,
        skip: int = 0,
        limit: int = 100,
    ) -> list[ListReadT]:  # TODO: check and fix
        db_items = await self.repo.get_multi(
            db=db,
            skip=skip,
            limit=limit,
            filter_by={"enabled": False},
        )
        return [
            self.mapper.to_dto(item, self.list_read_schema)
            for item in db_items
        ]

```