admin_szolgáltatók_

This commit is contained in:
Roo
2026-07-01 02:27:38 +00:00
parent 189cbfd7ca
commit 6e627d0ebe
491 changed files with 20965 additions and 9703 deletions

View File

@@ -40,7 +40,7 @@ from sqlalchemy.orm import joinedload
from app.models.marketplace.organization import Organization, OrgType, Branch, OrganizationMember, OrgUserRole
from app.models.marketplace.service import ServiceProfile, ServiceStatus, ExpertiseTag, ServiceExpertise, ServiceStaging
from app.models.identity.social import ServiceProvider
from app.models.identity.social import ServiceProvider, ModerationStatus, SourceType
from app.models.gamification.gamification import PointRule, UserStats
from app.schemas.provider import (
ProviderSearchResult,
@@ -64,9 +64,12 @@ async def _award_provider_points(
"""
Dinamikus pontjóváírás a gamification.point_rules tábla alapján.
Ez a függvény az adatbázisból olvassa ki a pontértéket az action_key
alapján, így a pontok NINCSENEK beégetve a kódba. Az admin felületről
bármikor módosíthatók a point_rules táblában.
REFAKTOR (2026-06-30): A duplikált point_rules olvasási logika eltávolításra
került. A pontértékeket most a GamificationService.award_points() olvassa ki
a point_rules táblából az action_key alapján a process_activity() hívás során.
Ez a függvény már csak a providers_added_count statisztikát kezeli.
A pontok kiszámítása és naplózása a GamificationService-ben történik.
Args:
db: AsyncSession
@@ -76,39 +79,19 @@ async def _award_provider_points(
Returns:
int: A jóváírt pontok száma (0 ha a szabály nem található vagy inaktív)
"""
# 1. Pontszabály lekérdezése az adatbázisból (dinamikus!)
rule_stmt = select(PointRule).where(
PointRule.action_key == action_key,
PointRule.is_active == True,
)
rule_result = await db.execute(rule_stmt)
rule = rule_result.scalar_one_or_none()
if not rule:
logger.warning(
f"Pontszabály '{action_key}' nem található vagy inaktív. "
f"Pontjóváírás kihagyva user_id={user_id}."
)
return 0
points_to_award = rule.points
logger.info(
f"Dinamikus pont lekérés: action_key='{action_key}', "
f"points={points_to_award} (forrás: gamification.point_rules tábla)"
)
# 2. Pontok jóváírása a Gamification Service-en keresztül
# A GamificationService.award_points() kezeli a szorzókat, szintlépést,
# büntetés ledolgozást és a naplózást (PointsLedger).
# 1. Pontok jóváírása a Gamification Service-en keresztül (action_key alapján)
# A GamificationService.award_points() kezeli a point_rules olvasást, szorzókat,
# szintlépést, büntetés ledolgozást és a naplózást (PointsLedger).
await gamification_service.award_points(
db=db,
user_id=user_id,
amount=points_to_award,
reason=f"ADD_NEW_PROVIDER: +{points_to_award} pont új szolgáltató rögzítéséért",
commit=False, # A hívó (quick_add_provider) kezeli a commit-ot
amount=0,
reason=f"{action_key}",
commit=False, # A hívó kezeli a commit-ot
action_key=action_key,
)
# 3. Statisztika növelése (providers_added_count)
# 2. Statisztika növelése (providers_added_count)
stats_stmt = select(UserStats).where(UserStats.user_id == user_id)
stats = (await db.execute(stats_stmt)).scalar_one_or_none()
@@ -122,7 +105,7 @@ async def _award_provider_points(
# Ha még nincs UserStats rekordja, létrehozzuk
stats = UserStats(
user_id=user_id,
total_xp=points_to_award,
total_xp=0,
current_level=1,
providers_added_count=1,
)
@@ -132,7 +115,102 @@ async def _award_provider_points(
f"providers_added_count=1"
)
return points_to_award
return 0 # Visszatérési érték már nem a pontszám, mert az award_points kezeli
async def find_or_create_provider_by_name(
db: AsyncSession,
name: str,
added_by_user_id: int,
) -> tuple:
"""
Keres vagy létrehoz egy ServiceProvider-t a megadott név alapján.
Ez a függvény az expense auto-discovery hook része. Amikor egy user
költséget rögzít és megad egy external_vendor_name-t, ez a függvény
megkeresi, hogy létezik-e már a provider, és ha nem, létrehozza.
Logika:
1. Pontos match keresése ServiceProvider.name alapján (kisbetűs, space-sztrippelt)
2. Ha nem létezik → új provider létrehozása PENDING státusszal,
validation_score=10, source=import, vissza: PROVIDER_DISCOVERY
3. Ha létezik és APPROVED → vissza: PROVIDER_VERIFIED_USE
4. Ha létezik és nem APPROVED → vissza: PROVIDER_CONFIRMATION
5. A függvény meghívja a _award_provider_points()-t a megfelelő action_key-kel
Args:
db: AsyncSession
name: A provider neve (external_vendor_name)
added_by_user_id: A költséget rögzítő user ID-ja
Returns:
tuple[ServiceProvider, str]: (provider, action_key)
- action_key: "PROVIDER_DISCOVERY" | "PROVIDER_CONFIRMATION" | "PROVIDER_VERIFIED_USE"
"""
# 1. Pontos match keresése (kisbetűsen, space-sztrippelten)
clean_name = name.strip()
provider_stmt = select(ServiceProvider).where(
func.lower(ServiceProvider.name) == func.lower(clean_name)
)
provider_result = await db.execute(provider_stmt)
provider = provider_result.scalar_one_or_none()
if not provider:
# 2. Ha nem létezik → létrehozás + PROVIDER_DISCOVERY
new_provider = ServiceProvider(
name=clean_name,
address=clean_name,
status=ModerationStatus.pending,
source=SourceType.api,
validation_score=10,
added_by_user_id=added_by_user_id,
)
db.add(new_provider)
await db.flush()
logger.info(
f"Új provider felfedezve: name='{clean_name}', "
f"provider_id={new_provider.id}, user_id={added_by_user_id}"
)
# Gamification pont kiosztása
await _award_provider_points(
db=db,
user_id=added_by_user_id,
action_key="PROVIDER_DISCOVERY",
)
return new_provider, "PROVIDER_DISCOVERY"
# 3. Ha létezik, státusz alapján döntés
# P0 CRITICAL (Card #362): USE_UNVERIFIED_PROVIDER vs PROVIDER_CONFIRMATION
# - Ha a provider APPROVED -> PROVIDER_VERIFIED_USE (100 XP)
# - Ha a provider PENDING es a hasznalo user a provider letrehozoja -> PROVIDER_CONFIRMATION (150 XP)
# - Ha a provider PENDING es a hasznalo user NEM a provider letrehozoja -> USE_UNVERIFIED_PROVIDER (200 XP)
# Ez megakadalyozza az XP farmingot (sajat provider hasznalata sajat maganak).
if provider.status == ModerationStatus.approved:
action_key = "PROVIDER_VERIFIED_USE"
elif provider.added_by_user_id == added_by_user_id:
# A provider letrehozoja hasznalja a sajat pending provideret
action_key = "PROVIDER_CONFIRMATION"
else:
# Mas user hasznal egy pending providert
action_key = "USE_UNVERIFIED_PROVIDER"
logger.info(
f"Meglevo provider hasznalata: name='{clean_name}', "
f"provider_id={provider.id}, action_key='{action_key}', "
f"user_id={added_by_user_id}, provider_creator_id={provider.added_by_user_id}"
)
# Gamification pont kiosztása
await _award_provider_points(
db=db,
user_id=added_by_user_id,
action_key=action_key,
)
return provider, action_key
async def search_providers(