Wire prior archive cutoff through API
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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
|
||||
? {
|
||||
|
||||
@@ -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: () =>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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] } : {}),
|
||||
};
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 },
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user