feat: separate prior records behind an owner switch and count last-period questions

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-15 10:48:30 +03:30
co-authored by Cursor
parent 3a8a684aa4
commit 6bc5e1bec7
29 changed files with 775 additions and 77 deletions
+52 -21
View File
@@ -28,6 +28,7 @@ import { normalizeTags } from '../common/tags';
import { GamificationService } from '../gamification/gamification.service';
import { tehranDayKey } from '../routines/routine-dates';
import { buildSearchWhere, ci } from '../common/search';
import { activityPriorWhere } from '../common/prior-archive';
import { ActivityStagesService, type StageDefaults } from './activity-stages.service';
import {
ActivityTypesService,
@@ -37,7 +38,7 @@ import {
type DtoContext = { stages?: StageDefaults; types?: SystemTypes };
type ActivityActor = Pick<Actor, 'userId' | 'role'>;
type ActivityActor = Pick<Actor, 'userId' | 'role' | 'priorLens'>;
/** stageId = شناسهٔ مرحله یا 'all'؛ وقتی ست باشد فیلتر زمانی وضعیت را تحمیل نمی‌کند (جز عقب‌افتاده) */
type StageScope = { stageId: string };
@@ -63,6 +64,7 @@ type ActivityRow = {
reminderNotifySms: boolean;
reminderSentAt: Date | null;
completedAt: Date | null;
importSource?: string;
tags: string[];
createdAt: Date;
updatedAt: Date;
@@ -117,31 +119,47 @@ export class ActivitiesService {
): Promise<ActivitySummaryDto> {
const { start, end } = dayBounds();
const scope = activityAccessWhere(actor);
const prior = activityPriorWhere(actor.priorLens);
const [todayCount, overdueCount] = await Promise.all([
this.prisma.activity.count({
where: {
organizationId,
...scope,
status: 'open',
dueAt: { gte: start, lt: end },
AND: [
{
organizationId,
...scope,
status: 'open',
dueAt: { gte: start, lt: end },
},
prior,
],
},
}),
this.prisma.activity.count({
where: {
organizationId,
...scope,
status: 'open',
dueAt: { lt: start },
AND: [
{
organizationId,
...scope,
status: 'open',
dueAt: { lt: start },
},
prior,
],
},
}),
]);
const [today, overdue, upcoming] = await Promise.all([
this.prisma.activity.findMany({
where: {
organizationId,
...scope,
status: 'open',
dueAt: { gte: start, lt: end },
AND: [
{
organizationId,
...scope,
status: 'open',
dueAt: { gte: start, lt: end },
},
prior,
],
},
include,
orderBy: [{ dueAt: 'asc' }, { createdAt: 'desc' }],
@@ -149,10 +167,15 @@ export class ActivitiesService {
}),
this.prisma.activity.findMany({
where: {
organizationId,
...scope,
status: 'open',
dueAt: { lt: start },
AND: [
{
organizationId,
...scope,
status: 'open',
dueAt: { lt: start },
},
prior,
],
},
include,
orderBy: [{ dueAt: 'asc' }],
@@ -160,10 +183,15 @@ export class ActivitiesService {
}),
this.prisma.activity.findMany({
where: {
organizationId,
...scope,
status: 'open',
OR: [{ dueAt: { gte: end } }, { dueAt: null }],
AND: [
{
organizationId,
...scope,
status: 'open',
OR: [{ dueAt: { gte: end } }, { dueAt: null }],
},
prior,
],
},
include,
orderBy: [{ dueAt: 'asc' }, { createdAt: 'desc' }],
@@ -671,6 +699,8 @@ export class ActivitiesService {
...this.types.searchByName(typeRows, t),
]);
if (search) andParts.push(search);
const onRecord = Boolean(entity?.personId || entity?.companyId || entity?.dealId);
if (!onRecord) andParts.push(activityPriorWhere(actor.priorLens));
const base: Prisma.ActivityWhereInput = {
organizationId,
AND: andParts,
@@ -868,6 +898,7 @@ export class ActivitiesService {
reminderNotifySms: row.reminderNotifySms,
reminderSentAt: row.reminderSentAt?.toISOString() ?? null,
completedAt: row.completedAt?.toISOString() ?? null,
importSource: row.importSource ?? 'manual',
tags: row.tags ?? [],
person: row.person
? {