frontend 2026-06-10 bontva a 2 felület

This commit is contained in:
Roo
2026-06-10 08:06:07 +00:00
parent b84b1bab41
commit 90e3173fbc
59 changed files with 8616 additions and 1412 deletions

View File

@@ -60,7 +60,7 @@ async def upload_document(
if doc.status == "processing":
response_data["message"] = "🤖 Robot 1 megkezdte a dokumentum elemzését. Értesítjük, ha kész!"
else:
response_data["message"] = "Dokumentum sikeresen archiválva a széfben."
response_data["message"] = "Dokumentum sikeresen archiválva a garázsban."
return response_data

View File

@@ -12,7 +12,7 @@ from sqlalchemy import select
from app.db.session import get_db
from app.api.deps import get_current_user
from app.schemas.organization import CorpOnboardIn, CorpOnboardResponse
from app.schemas.organization import CorpOnboardIn, CorpOnboardResponse, OrganizationUpdate, OrganizationResponse
from app.models.marketplace.organization import Organization, OrgType, OrganizationMember, Branch
from app.models.identity import User # JAVÍTVA: Központi Identity modell
from app.core.config import settings
@@ -39,13 +39,13 @@ async def onboard_organization(
detail="Érvénytelen magyar adószám formátum!"
)
# 2. Duplikáció ellenőrzés
# 2. Duplikáció ellenőrzés adószám alapján
stmt_exist = select(Organization).where(Organization.tax_number == org_in.tax_number)
result_exist = await db.execute(stmt_exist)
if result_exist.scalar_one_or_none():
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Ezzel az adószámmal már regisztráltak céget!"
detail="Ez a cég (adószám) már regisztrálva van a rendszerben."
)
# 3. KÖTELEZŐ MEZŐ: folder_slug generálása
@@ -121,6 +121,56 @@ async def onboard_organization(
return {"organization_id": new_org.id, "status": new_org.status}
@router.get("/lookup-tax/{tax_number}")
async def lookup_tax_number(
tax_number: str,
db: AsyncSession = Depends(get_db),
):
"""
Adószám alapú cégadat lekérdezés a hivatalos NAV Online Számla API v3 rendszerén keresztül.
A queryTaxpayer végpontot használja valós idejű cégadatok lekérésére.
Duplikáció ellenőrzés: Mielőtt a NAV-hoz fordulnánk, ellenőrizzük, hogy az adószám
első 8 számjegye (törzsszám) alapján létezik-e már aktív cég az adatbázisban.
Hibakezelés:
- 409: Az adószám már regisztrálva van a rendszerben
- 503: NAV rendszer nem elérhető (hálózati hiba, DNS, timeout)
- 404: Adószám nem található a NAV adatbázisában
"""
from app.services.nav_service import NavService, NavServiceUnavailableError
# Duplikáció ellenőrzés: adószám első 8 számjegye (törzsszám) alapján
tax_core = tax_number.strip().replace("-", "").replace(" ", "")[:8]
stmt_existing = select(Organization).where(
Organization.tax_number.like(f"{tax_core}%"),
Organization.is_deleted == False,
)
result_existing = await db.execute(stmt_existing)
existing_org = result_existing.scalar_one_or_none()
if existing_org:
logger.warning(f"Duplikáció észlelve: adószám {tax_core} már létezik (org_id={existing_org.id})")
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Ez az adószám már regisztrálva van a rendszerben."
)
try:
result = await NavService.query_taxpayer(tax_number)
except NavServiceUnavailableError as e:
logger.error(f"NAV szolgáltatás hiba: {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="A NAV rendszere jelenleg nem elérhető."
)
if result is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cég nem található a NAV adatbázisában"
)
return result
@router.get("/my", response_model=List[dict])
async def get_my_organizations(
db: AsyncSession = Depends(get_db),
@@ -147,10 +197,84 @@ async def get_my_organizations(
"country_code": o.country_code,
"is_active": o.is_active,
"is_deleted": o.is_deleted,
"subscription_plan": o.subscription_plan
"subscription_plan": o.subscription_plan,
"org_type": o.org_type.value if hasattr(o.org_type, 'value') else str(o.org_type),
"visual_settings": o.visual_settings if hasattr(o, 'visual_settings') else None
}
for o in orgs
]
@router.patch("/{org_id}/visual-settings", response_model=OrganizationResponse)
async def update_organization_visual_settings(
org_id: int,
update_data: OrganizationUpdate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Szervezet vizuális beállításainak részleges frissítése (JSONB merge).
A frontend küldhet csak egyetlen kulcsot is (pl. {"theme": "dark"}),
és az nem írja felül null-lal a többi mezőt. A meglévő visual_settings
objektum mélyen merge-elődik a beérkező adatokkal.
Csak OWNER vagy ADMIN jogosultságú felhasználó módosíthatja.
"""
# 1. Jogosultság ellenőrzése
stmt_member = select(OrganizationMember).where(
(OrganizationMember.organization_id == org_id) &
(OrganizationMember.user_id == current_user.id) &
(OrganizationMember.role.in_(["OWNER", "ADMIN"]))
)
member = (await db.execute(stmt_member)).scalar_one_or_none()
if not member:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Nincs jogosultságod a szervezet beállításainak módosításához (csak OWNER/ADMIN)."
)
# 2. Szervezet lekérése
stmt_org = select(Organization).where(
Organization.id == org_id,
Organization.is_deleted == False
)
result = await db.execute(stmt_org)
org = result.scalar_one_or_none()
if not org:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Szervezet nem található."
)
# 3. JSONB merge: csak a kapott kulcsokat frissítjük, a többit megtartjuk
update_dict = update_data.dict(exclude_unset=True)
if "visual_settings" in update_dict and update_dict["visual_settings"] is not None:
incoming_vs = update_dict["visual_settings"]
current_vs = dict(org.visual_settings) if org.visual_settings else {}
# Mély merge: a meglévő kulcsok megmaradnak, csak a kapottak frissülnek
current_vs.update(incoming_vs)
org.visual_settings = current_vs
del update_dict["visual_settings"]
# 4. Egyéb mezők frissítése (display_name, language, default_currency)
for field, value in update_dict.items():
if hasattr(org, field) and value is not None:
setattr(org, field, value)
try:
await db.commit()
await db.refresh(org)
except Exception as e:
await db.rollback()
logger.error(f"Hiba a szervezet frissítésekor (org_id={org_id}): {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Adatbázis hiba: {str(e)}"
)
return OrganizationResponse.model_validate(org)
# --- B2B MEGHÍVÓ LOGIKA ---
from pydantic import BaseModel, EmailStr

View File

@@ -402,8 +402,8 @@ async def update_active_organization(
detail="You are not a member of this organization"
)
# Update user's scope_id
current_user.scope_id = org_id
# Update user's scope_id (stored as string in DB, convert from int)
current_user.scope_id = str(org_id) if org_id is not None else None
try:
await db.commit()
@@ -419,7 +419,7 @@ async def update_active_organization(
"role": role_key,
"rank": DEFAULT_RANK_MAP.get(role_key, "user"),
"scope_level": "organization" if org_id else "personal",
"scope_id": org_id,
"scope_id": str(org_id) if org_id is not None else None,
"person_id": str(current_user.person_id) if current_user.person_id else None,
}