import getTokenHelper from "../../../utils/getTokenHelper" import refreshTokenHelper from "../../../utils/refreshTokenHelper" import fetchHelper from "../../../utils/fetchHelper" /** * Resolves the UI-restriction flags on the logged-in org's linked C_BPartner: * - isHideQty → hide stock quantities everywhere * - isDisallowExport → hide/disable all grid export buttons (CSV/Excel/PDF) * Returns { hideQty, disallowExport, orgId, bpartnerId } — plus resolved:false * when the check itself failed, so the client can fall back to a role-based * default instead of treating an outage as "show everything". * * Same pattern as materials/products/image-permission.get.ts: * - A limited customer role ('c') is denied/filtered on the admin tables * ad_user / ad_org / c_bpartner via REST, so read with the iDempiere * service token (system, role-independent). * - The org cookie is not a reliable source for limited users, so resolve * the org from the user record (ad_user.AD_Org_ID), falling back to the * org cookie when the user record has no usable org. */ const truthy = (v: any) => v === true || v === 'Y' || v === 'y' || v === 'true' || v === 'Yes' || v === 1 || v === '1' // iDempiere OData response casing varies by model, so match the flag keys // case-insensitively and accept every truthy representation it may return. const readFlag = (bpartner: any, lowerKey: string): boolean => { if (!bpartner || typeof bpartner !== 'object') return false for (const k of Object.keys(bpartner)) { if (k.toLowerCase() === lowerKey) return truthy(bpartner[k]) } return false } const handleFunc = async (event: any, authToken: string | null = null) => { const config = useRuntimeConfig() // Service token sees every org/column regardless of the caller's role; the // limited 'c' token cannot read these admin tables. Fall back to the user // token only if the env var is unset. const serviceToken = (config.api as any)?.idempieretoken const token = serviceToken || authToken || await getTokenHelper(event) const userId = getCookie(event, 'logship_user_id') const cookieOrgId = getCookie(event, 'logship_organization_id') // 1. Resolve the user's own org (reliable for limited roles); fall back to cookie. let orgId: any = cookieOrgId if (userId) { const userRes: any = await fetchHelper(event, `models/ad_user/${userId}?$select=AD_Org_ID`, 'GET', token, null) const userOrgId = userRes?.AD_Org_ID?.id if (userOrgId && Number(userOrgId) > 0) { orgId = userOrgId } } if (!orgId || Number(orgId) <= 0) { return { hideQty: false, disallowExport: false, orgId: orgId ? Number(orgId) : null, bpartnerId: null } } // 2. Pull the org's linked C_BPartner inline via $expand. const orgRes: any = await fetchHelper(event, `models/ad_org/${orgId}?$expand=C_BPartner_ID`, 'GET', token, null) const bpartner: any = orgRes?.C_BPartner_ID ?? null return { hideQty: readFlag(bpartner, 'ishideqty'), disallowExport: readFlag(bpartner, 'isdisallowexport'), orgId: Number(orgId), bpartnerId: bpartner?.id ?? null } } export default defineEventHandler(async (event) => { let data: any = { hideQty: false, disallowExport: false, resolved: false } try { data = await handleFunc(event) } catch (err: any) { try { const authToken: any = await refreshTokenHelper(event) data = await handleFunc(event, authToken) } catch (error: any) { // Check failed — signal it so the client keeps its role-based default // (staff unrestricted, limited customers restricted) instead of flashing. data = { hideQty: false, disallowExport: false, resolved: false } } } return data })