Commit 7554f95b by luoqi

feat(tenant): P0-5 by-id 守卫补品牌隔离

患者详情(reveal/timeline)、plan 详情/分配/回收、plan-aggregate 详情:
by-id 取数也按 patient.sourceUnit 圈品牌(findUnique→findFirst + patient 过滤,
命中不到→现有 NotFound 守卫接住)。sourceUnits 空=不限(集团级角色)。
至此 §4.4 数据范围在患者粒度的品牌隔离全覆盖(搜索/列表/by-id)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 62168f4f
......@@ -101,6 +101,7 @@ export class PatientService {
id: patientId,
hostId: scope.hostId,
tenantId: scope.tenantId,
...(scope.sourceUnits.length ? { sourceUnit: { in: scope.sourceUnits } } : {}),
},
select: { phone: true },
});
......@@ -120,6 +121,7 @@ export class PatientService {
id: patientId,
hostId: scope.hostId,
tenantId: scope.tenantId,
...(scope.sourceUnits.length ? { sourceUnit: { in: scope.sourceUnits } } : {}),
},
});
if (!patient) {
......
......@@ -28,8 +28,12 @@ export class PlanAggregateService {
* (app)/plans/[planId] 路由 + PlansAggregateController 的入口。
*/
async getPlanDetailByPlanId(scope: TenantScopeContext, planId: string) {
const plan = await this.prisma.followupPlan.findUnique({
where: { id: planId },
const plan = await this.prisma.followupPlan.findFirst({
// 集团模型:by-id 也按品牌圈(plan→patient.sourceUnit)
where: {
id: planId,
...(scope.sourceUnits.length ? { patient: { sourceUnit: { in: scope.sourceUnits } } } : {}),
},
include: { reasons: { orderBy: { priorityScore: 'desc' } } },
});
if (!plan) throw new NotFoundException(`Plan ${planId} not found`);
......
......@@ -351,8 +351,12 @@ export class PlanService {
// ─────────────────────────────────────────────
async detail(scope: TenantScopeContext, planId: string): Promise<PlanDetailResponse> {
const plan = await this.prisma.followupPlan.findUnique({
where: { id: planId },
const plan = await this.prisma.followupPlan.findFirst({
// 集团模型:by-id 取 plan 也按品牌圈(plan→patient.sourceUnit);命中不到→下方 NotFound
where: {
id: planId,
...(scope.sourceUnits.length ? { patient: { sourceUnit: { in: scope.sourceUnits } } } : {}),
},
include: { reasons: { orderBy: { priorityScore: 'desc' } } },
});
if (!plan || plan.hostId !== scope.hostId || plan.tenantId !== scope.tenantId) {
......@@ -400,8 +404,11 @@ export class PlanService {
assigneeUserId: string,
_assigneeRole?: string,
): Promise<void> {
const plan = await this.prisma.followupPlan.findUnique({
where: { id: planId },
const plan = await this.prisma.followupPlan.findFirst({
where: {
id: planId,
...(scope.sourceUnits.length ? { patient: { sourceUnit: { in: scope.sourceUnits } } } : {}),
},
select: { id: true, hostId: true, tenantId: true, status: true, assigneeUserId: true },
});
if (!plan || plan.hostId !== scope.hostId || plan.tenantId !== scope.tenantId) {
......@@ -431,8 +438,11 @@ export class PlanService {
// ─────────────────────────────────────────────
async recycle(scope: TenantScopeContext, planId: string): Promise<void> {
const plan = await this.prisma.followupPlan.findUnique({
where: { id: planId },
const plan = await this.prisma.followupPlan.findFirst({
where: {
id: planId,
...(scope.sourceUnits.length ? { patient: { sourceUnit: { in: scope.sourceUnits } } } : {}),
},
select: { id: true, hostId: true, tenantId: true, status: true },
});
if (!plan || plan.hostId !== scope.hostId || plan.tenantId !== scope.tenantId) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment