feat(tenancy): add profile editing in merchant team edit modal
Some checks failed
CI / ruff (push) Successful in 16s
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / pytest (push) Has been cancelled

Edit modal now has editable first_name, last_name, email fields with
a "Save Profile" button, alongside the existing per-store role management.

New:
- PUT /merchants/account/team/members/{user_id}/profile endpoint
- MerchantTeamProfileUpdate schema
- update_team_member_profile() service method with ownership validation
- 2 new i18n keys across 4 locales (personal_info, save_profile)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 13:31:23 +02:00
parent 211c46ebbc
commit 157b4c6ec3
9 changed files with 147 additions and 15 deletions

View File

@@ -26,6 +26,7 @@ from app.modules.tenancy.models.merchant import Merchant
from app.modules.tenancy.models.platform import Platform
from app.modules.tenancy.models.store import Role, Store
from app.modules.tenancy.models.store_platform import StorePlatform
from app.modules.tenancy.models.user import User
logger = logging.getLogger(__name__)
@@ -456,6 +457,58 @@ class MerchantStoreService:
raise StoreNotFoundException(store_id, identifier_type="id")
return store
def update_team_member_profile(
self,
db: Session,
merchant_id: int,
user_id: int,
update_data: dict,
) -> None:
"""
Update a team member's profile (first_name, last_name, email).
Validates that the user is a team member of one of the merchant's stores.
"""
from app.modules.tenancy.models.store import StoreUser
# Verify user is a team member in at least one of the merchant's stores
stores = (
db.query(Store)
.filter(Store.merchant_id == merchant_id)
.all()
)
store_ids = [s.id for s in stores]
membership = (
db.query(StoreUser)
.filter(
StoreUser.store_id.in_(store_ids),
StoreUser.user_id == user_id,
)
.first()
)
if not membership:
# Also allow updating the owner
merchant = db.query(Merchant).filter(Merchant.id == merchant_id).first()
if not merchant or merchant.owner_user_id != user_id:
from app.modules.tenancy.exceptions import UserNotFoundException
raise UserNotFoundException(str(user_id))
user = db.query(User).filter(User.id == user_id).first()
if not user:
from app.modules.tenancy.exceptions import UserNotFoundException
raise UserNotFoundException(str(user_id))
if "first_name" in update_data:
user.first_name = update_data["first_name"]
if "last_name" in update_data:
user.last_name = update_data["last_name"]
if "email" in update_data and update_data["email"]:
user.email = update_data["email"]
db.flush()
def get_merchant_team_members(self, db: Session, merchant_id: int) -> dict:
"""
Get team members across all merchant stores in a member-centric view.