707 lines
20 KiB
TypeScript
707 lines
20 KiB
TypeScript
import { Prisma, type IntakeNonIntegratedProduct, type IntakeNonIntegratedProductProfile } from '@prisma/client'
|
|
import { AppError, ErrorCode } from '@/server/core/errors'
|
|
import type { AuthUser } from '@/server/core/types'
|
|
import {
|
|
canUploadNonIntegratedDetachedAsset,
|
|
canCreateNonIntegratedProductFromIntake,
|
|
canDeleteNonIntegratedProductRecordByIntakePermission,
|
|
isIntakeNonIntegratedDesignDepartmentUser,
|
|
canEditAnyNonIntegratedWorkspace,
|
|
canEditNonIntegratedWorkspace,
|
|
canDownloadNonIntegratedWorkspace,
|
|
canPushNonIntegratedProductPricingToJushuitan,
|
|
isIntakeNonIntegratedFullEditor,
|
|
type IntakeNonIntegratedPermissionProduct,
|
|
} from '@/lib/non-integrated-permissions'
|
|
import {
|
|
isExternalIntakeRecordOwner,
|
|
isExternalIntakeUser,
|
|
} from '@/lib/non-integrated-external-entry-permissions'
|
|
import {
|
|
getIntakeNodePermissionTargetKeyByWorkspaceCategory,
|
|
resolveIntakeNodePermissionAccess,
|
|
resolveIntakeNodePermissionSubjectKeys,
|
|
} from '@/lib/intake-node-permission-settings'
|
|
import { intakeNodePermissionSettingsService } from './intake-node-permission-settings.service'
|
|
import { intakeProductPhotoAccessService } from './intake-product-photo-access.service'
|
|
import {
|
|
OperationLogAction,
|
|
OperationLogStatus,
|
|
operationLogService,
|
|
} from './operation-log.service'
|
|
|
|
type IntakeNonIntegratedPermissionTarget = Pick<
|
|
IntakeNonIntegratedProduct,
|
|
| 'id'
|
|
| 'spu'
|
|
| 'createdBy'
|
|
| 'designer'
|
|
| 'purchaser'
|
|
| 'visibility'
|
|
| 'departmentId'
|
|
| 'teamId'
|
|
> & {
|
|
operator?: string | null
|
|
payload?: Prisma.JsonValue | null
|
|
profile?: IntakeNonIntegratedProductProfile | null
|
|
skuItems?: Array<{
|
|
skuItemId?: string | null
|
|
purchaseOwner?: string | null
|
|
manufacturerCode?: string | null
|
|
}>
|
|
}
|
|
|
|
const ADMIN_ROLES = new Set<AuthUser['role']>(['SUPER_ADMIN', 'ADMIN'])
|
|
const PRODUCT_FACTORY_WORKSPACE_CATEGORY = '\u4ea7\u54c1\u5b9a\u5382'
|
|
export const DEFAULT_NON_INTEGRATED_VISIBILITY = 'DEPARTMENT'
|
|
export const NON_INTEGRATED_SCOPE_ENABLED = false
|
|
export const PUBLIC_NON_INTEGRATED_DEMO_SPUS = ['CJ0267'] as const
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
}
|
|
|
|
function readText(value: unknown) {
|
|
return typeof value === 'string' ? value.trim() : ''
|
|
}
|
|
|
|
function findMissingTargetSkuItemIds(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
targetSkuItemIds?: readonly string[],
|
|
) {
|
|
const targetIds = Array.from(
|
|
new Set((targetSkuItemIds ?? []).map(readText).filter(Boolean)),
|
|
)
|
|
if (targetIds.length === 0) return []
|
|
|
|
const savedSkuItemIds = new Set(
|
|
(record.skuItems ?? []).map((item) => readText(item.skuItemId)).filter(Boolean),
|
|
)
|
|
return targetIds.filter((skuItemId) => !savedSkuItemIds.has(skuItemId))
|
|
}
|
|
|
|
function readPayloadField(payload: unknown, key: string) {
|
|
return isRecord(payload) ? readText(payload[key]) : ''
|
|
}
|
|
|
|
function readOpeningReferenceField(payload: unknown, key: string) {
|
|
if (!isRecord(payload)) return ''
|
|
const openingReference = payload.openingReference
|
|
return isRecord(openingReference) ? readText(openingReference[key]) : ''
|
|
}
|
|
|
|
function normalizeSupplierCode(value: unknown) {
|
|
return readText(value).toUpperCase()
|
|
}
|
|
|
|
export function isPublicNonIntegratedDemoSpu(spu: unknown) {
|
|
const normalizedSpu = readText(spu).toUpperCase()
|
|
return PUBLIC_NON_INTEGRATED_DEMO_SPUS.some((demoSpu) => demoSpu === normalizedSpu)
|
|
}
|
|
|
|
function buildPublicNonIntegratedDemoScopeWhere():
|
|
Prisma.IntakeNonIntegratedProductWhereInput {
|
|
return { spu: { in: [...PUBLIC_NON_INTEGRATED_DEMO_SPUS] } }
|
|
}
|
|
|
|
function buildSupplierRecordScopeWhere(
|
|
supplierCode: string,
|
|
): Prisma.IntakeNonIntegratedProductWhereInput {
|
|
return {
|
|
OR: [
|
|
{
|
|
skuItems: {
|
|
some: {
|
|
manufacturerCode: supplierCode,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
payload: {
|
|
path: ['factoryRows'],
|
|
array_contains: [{ supplierCode }],
|
|
},
|
|
},
|
|
],
|
|
}
|
|
}
|
|
|
|
function readPayloadFactoryRows(payload: unknown) {
|
|
if (!isRecord(payload)) return []
|
|
const rows = payload.factoryRows
|
|
return Array.isArray(rows)
|
|
? rows.filter((row): row is Record<string, unknown> => isRecord(row))
|
|
: []
|
|
}
|
|
|
|
async function recordIntakePermissionDenied(input: {
|
|
record: IntakeNonIntegratedPermissionTarget
|
|
user: AuthUser
|
|
category?: string | null
|
|
targetSkuItemIds?: readonly string[]
|
|
action: OperationLogAction
|
|
message: string
|
|
}) {
|
|
await operationLogService.record({
|
|
action: input.action,
|
|
status: OperationLogStatus.FAILED,
|
|
actorId: input.user.id,
|
|
actorName: input.user.name,
|
|
productId: input.record.id,
|
|
productSpu: input.record.spu,
|
|
workspaceCategory: input.category ?? null,
|
|
errorCode: ErrorCode.AUTH_PERMISSION_DENIED,
|
|
message: input.message,
|
|
details: {
|
|
targetSkuItemIds: input.targetSkuItemIds ?? [],
|
|
},
|
|
})
|
|
}
|
|
|
|
class IntakeNonIntegratedScopeService {
|
|
isScopeEnabled(): boolean {
|
|
return NON_INTEGRATED_SCOPE_ENABLED
|
|
}
|
|
|
|
isAdmin(user: AuthUser): boolean {
|
|
return ADMIN_ROLES.has(user.role)
|
|
}
|
|
|
|
isExternalIntakeScopeUser(user: AuthUser): boolean {
|
|
return !this.isAdmin(user) && isExternalIntakeUser(user)
|
|
}
|
|
|
|
isSupplierScopeUser(user: AuthUser): boolean {
|
|
return !this.isAdmin(user) && Boolean(user.businessRoles?.includes('SUPPLIER'))
|
|
}
|
|
|
|
getSupplierCode(user: AuthUser): string {
|
|
return normalizeSupplierCode(user.supplierCode)
|
|
}
|
|
|
|
buildSupplierRecordScopeWhere(user: AuthUser): Prisma.IntakeNonIntegratedProductWhereInput {
|
|
const supplierCode = this.getSupplierCode(user)
|
|
if (!supplierCode) {
|
|
return { id: '__unbound_supplier__' }
|
|
}
|
|
|
|
return buildSupplierRecordScopeWhere(supplierCode)
|
|
}
|
|
|
|
getScopedDepartmentId(user: AuthUser): string | undefined {
|
|
return user.managedDepartmentId ?? user.departmentId
|
|
}
|
|
|
|
getScopedTeamId(user: AuthUser): string | undefined {
|
|
return user.managedTeamId ?? user.teamId
|
|
}
|
|
|
|
buildReadScopeWhere(
|
|
user: AuthUser,
|
|
externalIntakeCreatorIds: readonly string[] = [],
|
|
): Prisma.IntakeNonIntegratedProductWhereInput | undefined {
|
|
const publicDemoScopeWhere = buildPublicNonIntegratedDemoScopeWhere()
|
|
|
|
if (this.isSupplierScopeUser(user)) {
|
|
return {
|
|
OR: [this.buildSupplierRecordScopeWhere(user), publicDemoScopeWhere],
|
|
}
|
|
}
|
|
|
|
if (this.isExternalIntakeScopeUser(user)) {
|
|
return {
|
|
OR: [{ createdBy: user.id }, publicDemoScopeWhere],
|
|
}
|
|
}
|
|
|
|
const externalIntakeRecordExclusion =
|
|
externalIntakeCreatorIds.length > 0
|
|
? {
|
|
OR: [
|
|
{
|
|
createdBy: {
|
|
notIn: Array.from(new Set(externalIntakeCreatorIds)),
|
|
},
|
|
},
|
|
publicDemoScopeWhere,
|
|
],
|
|
}
|
|
: undefined
|
|
|
|
if (!this.isScopeEnabled()) {
|
|
return externalIntakeRecordExclusion
|
|
}
|
|
|
|
if (this.isAdmin(user)) {
|
|
return undefined
|
|
}
|
|
|
|
const orConditions: Prisma.IntakeNonIntegratedProductWhereInput[] = [
|
|
{ createdBy: user.id },
|
|
{ visibility: 'PUBLIC' },
|
|
publicDemoScopeWhere,
|
|
]
|
|
|
|
const scopedDepartmentId = this.getScopedDepartmentId(user)
|
|
if (scopedDepartmentId) {
|
|
orConditions.push({
|
|
visibility: 'DEPARTMENT',
|
|
departmentId: scopedDepartmentId,
|
|
})
|
|
}
|
|
|
|
const scopedTeamId = this.getScopedTeamId(user)
|
|
if (scopedTeamId) {
|
|
orConditions.push({
|
|
visibility: 'TEAM',
|
|
teamId: scopedTeamId,
|
|
})
|
|
}
|
|
|
|
const standardScope = { OR: orConditions }
|
|
if (!externalIntakeRecordExclusion) {
|
|
return standardScope
|
|
}
|
|
|
|
return {
|
|
AND: [standardScope, externalIntakeRecordExclusion],
|
|
}
|
|
}
|
|
|
|
canReadRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
externalIntakeCreatorIds: readonly string[] = [],
|
|
): boolean {
|
|
if (isPublicNonIntegratedDemoSpu(record.spu)) return true
|
|
|
|
if (this.isSupplierScopeUser(user)) {
|
|
const supplierCode = this.getSupplierCode(user)
|
|
if (!supplierCode) return false
|
|
|
|
if (
|
|
record.skuItems?.some(
|
|
(item) => normalizeSupplierCode(item.manufacturerCode) === supplierCode,
|
|
)
|
|
) {
|
|
return true
|
|
}
|
|
|
|
return readPayloadFactoryRows(record.payload).some(
|
|
(row) => normalizeSupplierCode(row.supplierCode) === supplierCode,
|
|
)
|
|
}
|
|
|
|
if (this.isExternalIntakeScopeUser(user)) {
|
|
return isExternalIntakeRecordOwner(record, user)
|
|
}
|
|
|
|
if (this.isAdmin(user)) return true
|
|
if (externalIntakeCreatorIds.includes(record.createdBy)) return false
|
|
|
|
if (!this.isScopeEnabled()) return true
|
|
if (record.createdBy === user.id) return true
|
|
if (record.visibility === 'PUBLIC') return true
|
|
|
|
const scopedDepartmentId = this.getScopedDepartmentId(user)
|
|
if (
|
|
record.visibility === 'DEPARTMENT' &&
|
|
scopedDepartmentId &&
|
|
record.departmentId === scopedDepartmentId
|
|
) {
|
|
return true
|
|
}
|
|
|
|
const scopedTeamId = this.getScopedTeamId(user)
|
|
if (record.visibility === 'TEAM' && scopedTeamId && record.teamId === scopedTeamId) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
canCreateRecord(user: AuthUser): boolean {
|
|
return canCreateNonIntegratedProductFromIntake(user)
|
|
}
|
|
|
|
private buildPermissionProduct(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
skuItemIds?: readonly string[],
|
|
): IntakeNonIntegratedPermissionProduct {
|
|
const profile = record.profile ?? null
|
|
const readProfile = (key: keyof IntakeNonIntegratedProductProfile) => {
|
|
const value = profile?.[key]
|
|
return readText(value)
|
|
}
|
|
const payloadDesigner = readPayloadField(record.payload, 'designer')
|
|
const openingDesigner = readOpeningReferenceField(record.payload, 'designer')
|
|
const persistedDesigner = readText(record.designer)
|
|
const productPlanning = readProfile('productPlanning')
|
|
const targetSkuItemIds = new Set(
|
|
(skuItemIds ?? []).map(readText).filter(Boolean),
|
|
)
|
|
const fallbackPurchaseOwner =
|
|
readProfile('purchaseOwner') || readText(record.purchaser)
|
|
const scopedSkuItems = (record.skuItems ?? [])
|
|
.filter(
|
|
(item) =>
|
|
targetSkuItemIds.size === 0 ||
|
|
targetSkuItemIds.has(readText(item.skuItemId)),
|
|
)
|
|
const skuPurchaseOwners = scopedSkuItems
|
|
.map((item) => readText(item.purchaseOwner) || fallbackPurchaseOwner)
|
|
.filter(Boolean)
|
|
const nextOpeningReference = {
|
|
productName: readProfile('productName'),
|
|
productImage: readProfile('productImageUrl'),
|
|
productCategory: readProfile('productCategory'),
|
|
salesCategory: readProfile('salesCategory'),
|
|
currentStage: readProfile('productStatus'),
|
|
year: readProfile('productYear'),
|
|
designer: openingDesigner || payloadDesigner || persistedDesigner,
|
|
structureDesigner:
|
|
readProfile('structureDesigner') ||
|
|
readOpeningReferenceField(record.payload, 'structureDesigner'),
|
|
planningOwner: productPlanning,
|
|
}
|
|
|
|
return {
|
|
createdBy: record.createdBy,
|
|
designer: persistedDesigner || payloadDesigner || openingDesigner,
|
|
purchaser: readText(record.purchaser),
|
|
purchaseOwner: readProfile('purchaseOwner'),
|
|
brandPlanning: readProfile('brandPlanning'),
|
|
spuOwner: readProfile('spuOwner'),
|
|
operator: readText(record.operator),
|
|
operationsOwner: readProfile('operationsOwner'),
|
|
productPlanning,
|
|
visualPlanning: readProfile('visualPlanning'),
|
|
visualDirector: readProfile('visualDirector'),
|
|
skuPurchaseOwners,
|
|
openingReference: nextOpeningReference,
|
|
}
|
|
}
|
|
|
|
canWriteRecord(record: IntakeNonIntegratedPermissionTarget, user: AuthUser): boolean {
|
|
return canEditAnyNonIntegratedWorkspace(this.buildPermissionProduct(record), user)
|
|
}
|
|
|
|
canUploadDetachedAsset(record: IntakeNonIntegratedPermissionTarget, user: AuthUser): boolean {
|
|
return canUploadNonIntegratedDetachedAsset(this.buildPermissionProduct(record), user)
|
|
}
|
|
|
|
canPushProductPricing(record: IntakeNonIntegratedPermissionTarget, user: AuthUser): boolean {
|
|
return canPushNonIntegratedProductPricingToJushuitan(
|
|
this.buildPermissionProduct(record),
|
|
user,
|
|
)
|
|
}
|
|
|
|
canWriteWorkspaceRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
targetSkuItemIds?: readonly string[],
|
|
): boolean {
|
|
if (!category) {
|
|
return this.canWriteRecord(record, user)
|
|
}
|
|
|
|
const normalizedTargetSkuItemIds = Array.from(
|
|
new Set((targetSkuItemIds ?? []).map(readText).filter(Boolean)),
|
|
)
|
|
if (
|
|
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY &&
|
|
normalizedTargetSkuItemIds.length > 0
|
|
) {
|
|
const skuItemsById = new Map(
|
|
(record.skuItems ?? []).map((item) => [readText(item.skuItemId), item]),
|
|
)
|
|
if (
|
|
normalizedTargetSkuItemIds.some((skuItemId) => !skuItemsById.has(skuItemId))
|
|
) {
|
|
return false
|
|
}
|
|
|
|
return normalizedTargetSkuItemIds.every((skuItemId) =>
|
|
canEditNonIntegratedWorkspace(
|
|
this.buildPermissionProduct(record, [skuItemId]),
|
|
user,
|
|
category,
|
|
),
|
|
)
|
|
}
|
|
|
|
return canEditNonIntegratedWorkspace(this.buildPermissionProduct(record), user, category)
|
|
}
|
|
|
|
canDownloadWorkspaceRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
): boolean {
|
|
if (!category) {
|
|
return false
|
|
}
|
|
|
|
return canDownloadNonIntegratedWorkspace(
|
|
this.buildPermissionProduct(record),
|
|
user,
|
|
category,
|
|
)
|
|
}
|
|
|
|
async canWriteWorkspaceRecordWithSettings(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
targetSkuItemIds?: readonly string[],
|
|
): Promise<boolean> {
|
|
if (isIntakeNonIntegratedFullEditor(user)) {
|
|
console.info('[IntakeScope] write allowed: full editor', {
|
|
userId: user.id,
|
|
userName: user.name,
|
|
role: user.role,
|
|
category: category ?? null,
|
|
})
|
|
return true
|
|
}
|
|
|
|
const targetKey = getIntakeNodePermissionTargetKeyByWorkspaceCategory(category)
|
|
if (!targetKey) {
|
|
console.warn('[IntakeScope] write denied: category not found', {
|
|
userId: user.id,
|
|
userName: user.name,
|
|
role: user.role,
|
|
category: category ?? null,
|
|
})
|
|
return false
|
|
}
|
|
|
|
const { overrides } = await intakeNodePermissionSettingsService.getSettings()
|
|
const subjectKeys = resolveIntakeNodePermissionSubjectKeys(user)
|
|
const nodePermissionAccess = resolveIntakeNodePermissionAccess(
|
|
overrides,
|
|
targetKey,
|
|
subjectKeys,
|
|
user.id,
|
|
)
|
|
|
|
if (!nodePermissionAccess.edit) {
|
|
console.warn('[IntakeScope] write denied: no edit permission', {
|
|
userId: user.id,
|
|
userName: user.name,
|
|
role: user.role,
|
|
category: category ?? null,
|
|
targetKey,
|
|
subjectKeys,
|
|
})
|
|
return false
|
|
}
|
|
|
|
if (nodePermissionAccess.override.edit) {
|
|
console.info('[IntakeScope] write allowed: override', {
|
|
userId: user.id,
|
|
userName: user.name,
|
|
role: user.role,
|
|
category: category ?? null,
|
|
targetKey,
|
|
subjectKeys,
|
|
})
|
|
return true
|
|
}
|
|
|
|
const canWrite = await this.canWriteWorkspaceRecord(record, user, category, targetSkuItemIds)
|
|
if (canWrite) {
|
|
console.info('[IntakeScope] write allowed: workspace record', {
|
|
userId: user.id,
|
|
userName: user.name,
|
|
role: user.role,
|
|
category: category ?? null,
|
|
})
|
|
}
|
|
return canWrite
|
|
}
|
|
|
|
async canDownloadWorkspaceRecordWithSettings(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
): Promise<boolean> {
|
|
if (isIntakeNonIntegratedFullEditor(user)) {
|
|
return true
|
|
}
|
|
|
|
const targetKey = getIntakeNodePermissionTargetKeyByWorkspaceCategory(category)
|
|
if (!targetKey) {
|
|
return false
|
|
}
|
|
|
|
const { overrides } = await intakeNodePermissionSettingsService.getSettings()
|
|
const subjectKeys = resolveIntakeNodePermissionSubjectKeys(user)
|
|
const nodePermissionAccess = resolveIntakeNodePermissionAccess(
|
|
overrides,
|
|
targetKey,
|
|
subjectKeys,
|
|
user.id,
|
|
)
|
|
|
|
if (!nodePermissionAccess.download) {
|
|
return false
|
|
}
|
|
|
|
if (nodePermissionAccess.override.download) {
|
|
return true
|
|
}
|
|
|
|
return this.canDownloadWorkspaceRecord(record, user, category)
|
|
}
|
|
|
|
async canPreviewWorkspaceRecordWithSettings(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
): Promise<boolean> {
|
|
if (category === '产品实拍图' && await intakeProductPhotoAccessService.canUpload(record.id, user)) {
|
|
return true
|
|
}
|
|
if (isIntakeNonIntegratedFullEditor(user)) {
|
|
return true
|
|
}
|
|
|
|
const targetKey = getIntakeNodePermissionTargetKeyByWorkspaceCategory(category)
|
|
if (!targetKey) {
|
|
return false
|
|
}
|
|
|
|
const { overrides } = await intakeNodePermissionSettingsService.getSettings()
|
|
const subjectKeys = resolveIntakeNodePermissionSubjectKeys(user)
|
|
const nodePermissionAccess = resolveIntakeNodePermissionAccess(
|
|
overrides,
|
|
targetKey,
|
|
subjectKeys,
|
|
user.id,
|
|
)
|
|
|
|
if (!nodePermissionAccess.view) {
|
|
return false
|
|
}
|
|
|
|
if (nodePermissionAccess.override.view) {
|
|
return true
|
|
}
|
|
|
|
return this.canReadRecord(record, user)
|
|
}
|
|
|
|
async assertCanWriteRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
targetSkuItemIds?: readonly string[],
|
|
): Promise<void> {
|
|
// 先检查 SKU 是否已入库,不存在直接提示"SKU 尚未保存",不要报"没有权限"
|
|
const missingTargetSkuItemIds =
|
|
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
|
|
? findMissingTargetSkuItemIds(record, targetSkuItemIds)
|
|
: []
|
|
if (missingTargetSkuItemIds.length > 0) {
|
|
throw new AppError(
|
|
ErrorCode.VALIDATION_FAILED,
|
|
'SKU 尚未保存,请先保存基础信息后再确认产品定厂',
|
|
)
|
|
}
|
|
|
|
if (
|
|
await this.canWriteWorkspaceRecordWithSettings(
|
|
record,
|
|
user,
|
|
category,
|
|
targetSkuItemIds,
|
|
)
|
|
) {
|
|
return
|
|
}
|
|
|
|
const message = '没有权限编辑这条非集成产品记录'
|
|
await recordIntakePermissionDenied({
|
|
record,
|
|
user,
|
|
category,
|
|
targetSkuItemIds,
|
|
action: OperationLogAction.INTAKE_PRODUCT_WRITE,
|
|
message,
|
|
})
|
|
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED, message)
|
|
}
|
|
|
|
assertCanUploadDetachedAsset(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
): void {
|
|
if (this.canUploadDetachedAsset(record, user)) {
|
|
return
|
|
}
|
|
|
|
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED, '没有权限编辑这条非集成产品记录')
|
|
}
|
|
|
|
async assertCanDownloadWorkspaceRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
): Promise<void> {
|
|
if (await this.canDownloadWorkspaceRecordWithSettings(record, user, category)) {
|
|
return
|
|
}
|
|
|
|
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED, '没有权限下载这条非集成产品资料')
|
|
}
|
|
|
|
async assertCanPreviewWorkspaceRecord(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
category?: string | null,
|
|
): Promise<void> {
|
|
if (await this.canPreviewWorkspaceRecordWithSettings(record, user, category)) {
|
|
return
|
|
}
|
|
|
|
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED, '没有权限查看这条非集成产品资料')
|
|
}
|
|
|
|
assertCanPushProductPricing(
|
|
record: IntakeNonIntegratedPermissionTarget,
|
|
user: AuthUser,
|
|
): void {
|
|
if (this.canPushProductPricing(record, user)) {
|
|
return
|
|
}
|
|
|
|
const message = '没有权限推送这条非集成产品核价'
|
|
void recordIntakePermissionDenied({
|
|
record,
|
|
user,
|
|
action: OperationLogAction.JUSHUITAN_PRODUCT_PUSH,
|
|
message,
|
|
})
|
|
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED, message)
|
|
}
|
|
|
|
assertCanDeleteRecord(record: IntakeNonIntegratedPermissionTarget, user: AuthUser): void {
|
|
if (canDeleteNonIntegratedProductRecordByIntakePermission(user, record)) {
|
|
return
|
|
}
|
|
|
|
throw new AppError(
|
|
ErrorCode.AUTH_PERMISSION_DENIED,
|
|
isIntakeNonIntegratedDesignDepartmentUser(user)
|
|
? '设计师仅可删除自己创建的产品'
|
|
: '没有权限删除这条非集成产品记录',
|
|
)
|
|
}
|
|
}
|
|
|
|
export const intakeNonIntegratedScopeService = new IntakeNonIntegratedScopeService()
|
|
export { IntakeNonIntegratedScopeService }
|