// One policy for the administrative and operational gateways. Legacy admin means // company operations manager, never cross-company super administrator. function adminRoleSnapshot(current) { const read = key => typeof current.get === 'function' ? current.get(key) : current[key]; const roles = Array.isArray(read('roles')) ? read('roles').map(String) : []; const key = String(read('adminRoleKey') || ''); const valid = ['super-admin','ops-manager','ops-staff','ops-auditor']; let role = valid.includes(key) ? key : valid.find(value => roles.includes(value)) || ''; const legacy = read('isAdmin') === true || read('role') === 'admin' || roles.includes('admin'); if (!role && !key && !roles.some(value => value.startsWith('ops-')) && legacy) role = 'ops-manager'; return {roles:role ? [...new Set([...roles.filter(value=>!valid.includes(value)),role])] : roles,isSuperAdmin:role==='super-admin',operationsRole:role==='super-admin'?'ops-manager':role||'denied',roleKey:role,legacyRole:role==='ops-manager'&&!key&&!roles.some(value=>valid.includes(value)),isAdmin:Boolean(role)||legacy}; } // A store is an independent principal, never a company administrator. function storeAccountSnapshot(current) { const read = key => typeof current.get === 'function' ? current.get(key) : current[key]; const legacy = read('legacyUserData') || {}; const identity = String(read('identityType') || ''); const storeId = Number(read('legacyUserId') || legacy.UserID); const store = identity === 'store' || (!identity && Number(read('legacyGroupId') || legacy.GroupID) === 2); return store && Number.isSafeInteger(storeId) && storeId > 0 ? storeId : 0; } // Delegated logins never inherit headquarters roles. The binding is server-only. async function resolveStoreAccount(current) { if(current.get('identityType')!=='store-admin')return null; const company=current.get('company'),co=company&&(company.id||company.objectId); if(!co)fail(403,'门店管理员尚未分配帐套'); const row=await Psql.oneOrNone('SELECT "storeObjectId" FROM "StoreAdministrator" WHERE company=$1 AND "userId"=$2 AND enabled=true',[co,current.id]); if(!row)fail(403,'门店管理员未绑定有效门店'); const store=await new Parse.Query('_User').get(row.storeObjectId,{useMasterKey:true}); const sc=store.get('company'); if((sc&&(sc.id||sc.objectId))!==co||!storeAccountSnapshot(store)||store.get('isDisabled')===true||store.get('isDeleted')===true)fail(403,'绑定门店不存在或已停用'); return store; }