Wire prior archive cutoff through API

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-17 16:52:20 +03:30
co-authored by Cursor
parent 02841a5b8c
commit 79ba146118
11 changed files with 74 additions and 34 deletions
@@ -65,6 +65,7 @@ type ActivityRow = {
reminderSentAt: Date | null;
completedAt: Date | null;
importSource?: string;
promotedFromPriorAt?: Date | null;
tags: string[];
createdAt: Date;
updatedAt: Date;
@@ -119,7 +120,7 @@ export class ActivitiesService {
): Promise<ActivitySummaryDto> {
const { start, end } = dayBounds();
const scope = activityAccessWhere(actor);
const prior = activityPriorWhere(actor.priorLens, new Date(), actor.priorCutoff);
const prior = activityPriorWhere(actor.priorLens, actor.priorCutoff);
const [todayCount, overdueCount] = await Promise.all([
this.prisma.activity.count({
where: {
@@ -701,7 +702,7 @@ export class ActivitiesService {
if (search) andParts.push(search);
const onRecord = Boolean(entity?.personId || entity?.companyId || entity?.dealId);
if (!onRecord) {
andParts.push(activityPriorWhere(actor.priorLens, new Date(), actor.priorCutoff));
andParts.push(activityPriorWhere(actor.priorLens, actor.priorCutoff));
}
const base: Prisma.ActivityWhereInput = {
organizationId,
@@ -901,6 +902,7 @@ export class ActivitiesService {
reminderSentAt: row.reminderSentAt?.toISOString() ?? null,
completedAt: row.completedAt?.toISOString() ?? null,
importSource: row.importSource ?? 'manual',
promotedFromPriorAt: row.promotedFromPriorAt?.toISOString() ?? null,
tags: row.tags ?? [],
person: row.person
? {
+2 -6
View File
@@ -48,9 +48,7 @@ import {
} from './ask-count';
import {
activityPriorWhere,
companyPriorWhere,
dealPriorWhere,
personPriorWhere,
} from '../common/prior-archive';
type CatalogItem = AskMentoSourceDto;
@@ -325,13 +323,11 @@ Rules:
where: {
...shared,
...(intent.mood ? { mood: intent.mood } : {}),
...(intent.personSource ? {} : personPriorWhere(actor.priorLens)),
},
})
: await this.prisma.company.count({
where: {
...shared,
...(intent.personSource ? {} : companyPriorWhere(actor.priorLens)),
},
});
const who = intent.entity === 'person' ? 'مشتری' : 'شرکت';
@@ -372,7 +368,7 @@ Rules:
? { status: 'open' as const, OR: [{ isStale: true }, { isRotten: true }] }
: {}),
},
dealPriorWhere(actor.priorLens),
dealPriorWhere(actor.priorLens, actor.priorCutoff),
],
};
const n = await this.prisma.deal.count({ where });
@@ -406,7 +402,7 @@ Rules:
organizationId: orgId,
...assigneeWhere(actor),
...created,
...activityPriorWhere(actor.priorLens, new Date(), actor.priorCutoff),
...activityPriorWhere(actor.priorLens, actor.priorCutoff),
},
}),
ticket: () =>
+9 -3
View File
@@ -658,7 +658,9 @@ export class AuthService {
const membership = await this.prisma.membership.findFirst({
where: { userId: user.id, organizationId, isActive: true },
include: {
organization: { select: { name: true, enabledModules: true } },
organization: {
select: { name: true, enabledModules: true, priorArchiveEnabledAt: true },
},
},
});
const role = membership?.role ?? user.role;
@@ -685,13 +687,17 @@ export class AuthService {
membership: {
priorArchiveEnabled?: boolean;
priorArchiveLens?: string;
organization?: { enabledModules?: string[] };
organization?: { enabledModules?: string[]; priorArchiveEnabledAt?: Date | null };
} | null,
): AuthUserDto['priorArchive'] {
if (!membership?.priorArchiveEnabled) return undefined;
const modules = this.billing.normalizeModules(membership.organization?.enabledModules);
if (!modules.includes('prior_data_archive')) return undefined;
return { lens: membership.priorArchiveLens === 'archive' ? 'archive' : 'current' };
const orgCutoff = membership.organization?.priorArchiveEnabledAt ?? null;
return {
lens: membership.priorArchiveLens === 'archive' ? 'archive' : 'current',
cutoffAt: orgCutoff ? orgCutoff.toISOString() : null,
};
}
private async throttleChallenges(
+4 -1
View File
@@ -107,7 +107,10 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
visibleUserIds,
scopes,
priorLens: priorGranted ? priorLens : 'off',
priorCutoff: priorGranted ? membership.organization.priorArchiveEnabledAt : null,
priorCutoff:
priorGranted && membership.organization.priorArchiveEnabledAt
? membership.organization.priorArchiveEnabledAt
: null,
};
}
+3 -5
View File
@@ -257,17 +257,15 @@ export class BillingService {
select: { priorArchiveEnabledAt: true },
});
const enablePrior = cleaned.includes('prior_data_archive');
const cutoff = prev?.priorArchiveEnabledAt ?? new Date();
await this.prisma.organization.update({
where: { id: organizationId },
data: {
enabledModules: cleaned,
...(enablePrior && !prev?.priorArchiveEnabledAt
? { priorArchiveEnabledAt: cutoff }
: {}),
},
});
if (enablePrior) await this.backfillPriorActivities(organizationId, cutoff);
if (enablePrior && prev?.priorArchiveEnabledAt) {
await this.backfillPriorActivities(organizationId, prev.priorArchiveEnabledAt);
}
return cleaned;
}
@@ -26,7 +26,6 @@ import {
import { normalizeTags } from '../common/tags';
import { normalizePersonImportSource } from './person-source';
import { buildSearchWhere, ci } from '../common/search';
import { companyPriorWhere, listPriorLens } from '../common/prior-archive';
import { GamificationService } from '../gamification/gamification.service';
function parseDateOrNull(raw?: string | null): Date | null {
@@ -98,7 +97,6 @@ export class CompaniesService {
const where: Prisma.CompanyWhereInput = {
organizationId: actor.organizationId,
...ownerWhere(actor),
...companyPriorWhere(listPriorLens(actor.priorLens, q, false)),
...(search ? { AND: [search] } : {}),
};
-2
View File
@@ -43,7 +43,6 @@ import { selectMonthBirthdays } from './birthday-month';
import { renderSmsText } from '../common/sms-text';
import { normalizeTags } from '../common/tags';
import { buildSearchWhere, ci } from '../common/search';
import { listPriorLens, personPriorWhere } from '../common/prior-archive';
import {
normalizePersonImportSource,
personImportSourceLabel,
@@ -138,7 +137,6 @@ export class PeopleService implements OnModuleInit {
...ownerWhere(actor),
...(opts?.mood ? { mood: opts.mood } : {}),
...(sourceFilter ? { importSource: sourceFilter } : {}),
...personPriorWhere(listPriorLens(actor.priorLens, q, Boolean(sourceFilter))),
...(search ? { AND: [search] } : {}),
};
@@ -114,7 +114,7 @@ export class DealsExcelService {
where: {
organizationId: actor.organizationId,
...dealAccessWhere(actor),
...dealPriorWhere(actor.priorLens),
...dealPriorWhere(actor.priorLens, actor.priorCutoff),
},
include: {
person: {
+9 -2
View File
@@ -44,6 +44,7 @@ type DealRow = {
expectedCloseAt: Date | null;
code: string | null;
importSource: string;
promotedFromPriorAt: Date | null;
sourceRef: string | null;
probability: number | null;
sourceDetail: string | null;
@@ -295,7 +296,12 @@ export class PipelinesService {
pipelineId?: string,
actor?: Pick<
Actor,
'userId' | 'role' | 'dataVisibility' | 'visibleUserIds' | 'priorLens'
| 'userId'
| 'role'
| 'dataVisibility'
| 'visibleUserIds'
| 'priorLens'
| 'priorCutoff'
>,
includePrior = false,
): Promise<PipelineBoardDto> {
@@ -323,7 +329,7 @@ export class PipelinesService {
organizationId,
pipelineId: resolved.id,
...(actor ? dealAccessWhere(actor) : {}),
...(includePrior ? {} : dealPriorWhere(actor?.priorLens)),
...(includePrior ? {} : dealPriorWhere(actor?.priorLens, actor?.priorCutoff)),
},
include: {
person: { select: { id: true, firstName: true, lastName: true } },
@@ -575,6 +581,7 @@ export class PipelinesService {
expectedCloseAt: row.expectedCloseAt?.toISOString() ?? null,
code: row.code,
importSource: row.importSource,
promotedFromPriorAt: row.promotedFromPriorAt?.toISOString() ?? null,
sourceRef: row.sourceRef,
probability: row.probability,
sourceDetail: row.sourceDetail,
+4 -10
View File
@@ -29,7 +29,6 @@ import { decimalToBase, loadOrgRates, toBaseAmount } from '../common/currency';
import {
activityPriorWhere,
dealPriorWhere,
personPriorWhere,
} from '../common/prior-archive';
import {
addJalaliMonths,
@@ -62,9 +61,8 @@ export class ReportsService {
const prevStart = new Date(prevEnd.getTime() - durationMs);
const now = new Date();
const peoplePrior = personPriorWhere(actor.priorLens);
const dealsPrior = dealPriorWhere(actor.priorLens, now);
const activitiesPrior = activityPriorWhere(actor.priorLens, now, actor.priorCutoff);
const dealsPrior = dealPriorWhere(actor.priorLens, actor.priorCutoff);
const activitiesPrior = activityPriorWhere(actor.priorLens, actor.priorCutoff);
const { jy, jm } = dateToJalali(now);
const sixAgo = addJalaliMonths(jy, jm, -5);
const sixMonthStart = startOfJalaliMonth(sixAgo.jy, sixAgo.jm);
@@ -160,7 +158,6 @@ export class ReportsService {
where: {
organizationId: orgId,
...personScope,
...peoplePrior,
},
select: { mood: true, createdAt: true },
}),
@@ -1551,9 +1548,8 @@ export class ReportsService {
const yesterdayEnd = endOfDay(yesterday);
const weekAgo = new Date(now);
weekAgo.setDate(weekAgo.getDate() - 7);
const peoplePrior = personPriorWhere(actor.priorLens);
const dealsPrior = dealPriorWhere(actor.priorLens, now);
const activitiesPrior = activityPriorWhere(actor.priorLens, now, actor.priorCutoff);
const dealsPrior = dealPriorWhere(actor.priorLens, actor.priorCutoff);
const activitiesPrior = activityPriorWhere(actor.priorLens, actor.priorCutoff);
const [
wonDeals,
@@ -1618,7 +1614,6 @@ export class ReportsService {
where: {
organizationId: orgId,
...personScope,
...peoplePrior,
createdAt: { gte: curMonthStart, lte: curMonthEnd },
},
}),
@@ -1626,7 +1621,6 @@ export class ReportsService {
where: {
organizationId: orgId,
...personScope,
...peoplePrior,
createdAt: { gte: prevMonthStart, lte: prevMonthEnd },
},
}),