@happyvertical/smrt-sales 0.55.0 → 0.55.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1888,6 +1888,7 @@ var LeadWorkflowService = class LeadWorkflowService {
1888
1888
  contactName: normalized.contactName,
1889
1889
  phone: normalized.phone,
1890
1890
  organizationName: normalized.organizationName,
1891
+ ...normalized.profileId ? { profileId: normalized.profileId } : {},
1891
1892
  sourceKind: normalized.sourceKind,
1892
1893
  sourceId: normalized.sourceId,
1893
1894
  acquisitionContext: stableStringify(normalized.acquisitionContext),
@@ -1967,6 +1968,44 @@ var LeadWorkflowService = class LeadWorkflowService {
1967
1968
  created: result.created
1968
1969
  };
1969
1970
  }
1971
+ /** Move an open Opportunity between nonterminal stages in one transaction. */
1972
+ async moveOpportunityToStage(input) {
1973
+ const actorProfileId = this.requireIdentifier(input.actorProfileId, "actorProfileId");
1974
+ if (!UUID_RE.test(input.opportunityId)) throw this.refusal("opportunity_unavailable", "Opportunity is unavailable in the active tenant");
1975
+ if (!UUID_RE.test(input.stageId)) throw this.refusal("stage_unavailable", "Opportunity stage is unavailable in the active tenant");
1976
+ if (input.probabilityOverride !== void 0 && (!Number.isFinite(input.probabilityOverride) || input.probabilityOverride < 0 || input.probabilityOverride > 1)) throw this.refusal("invalid_value", "Opportunity probability must be between 0 and 1");
1977
+ const tenantId = this.requireActiveTenant();
1978
+ const result = await this.runMutation(async (deps, activeTenantId) => {
1979
+ const opportunity = await this.lockOpportunity(deps, input.opportunityId, activeTenantId);
1980
+ if (opportunity.status !== "open") throw this.refusal("invalid_transition", `Opportunity cannot move stages while '${opportunity.status}'`);
1981
+ const stage = await this.lockPipelineStage(deps, input.stageId, activeTenantId);
1982
+ if (!stage || stage.tenantId !== activeTenantId || stage.pipelineId !== opportunity.pipelineId) throw this.refusal("stage_unavailable", "Opportunity stage is unavailable in the active tenant and pipeline");
1983
+ if (stage.isWon || stage.isLost) throw this.refusal("invalid_transition", "Terminal Opportunity stages must use closeOpportunity()");
1984
+ const probability = input.probabilityOverride ?? stage.probability;
1985
+ if (opportunity.stageId === input.stageId) {
1986
+ if (opportunity.probability !== probability) throw this.refusal("opportunity_replay_conflict", "Opportunity is already at this stage with a different probability");
1987
+ return {
1988
+ opportunityId: input.opportunityId,
1989
+ changed: false
1990
+ };
1991
+ }
1992
+ await deps.opportunities.moveToStage({
1993
+ opportunityId: input.opportunityId,
1994
+ stageId: input.stageId,
1995
+ actorProfileId,
1996
+ probabilityOverride: input.probabilityOverride,
1997
+ now: input.now
1998
+ });
1999
+ return {
2000
+ opportunityId: input.opportunityId,
2001
+ changed: true
2002
+ };
2003
+ });
2004
+ return {
2005
+ opportunity: await this.readOpportunity(result.opportunityId, tenantId),
2006
+ changed: result.changed
2007
+ };
2008
+ }
1970
2009
  /** Close an opportunity at its configured terminal stage and optionally link conversion. */
1971
2010
  async closeOpportunity(input) {
1972
2011
  const actorProfileId = this.requireIdentifier(input.actorProfileId, "actorProfileId");
@@ -2308,6 +2347,18 @@ var LeadWorkflowService = class LeadWorkflowService {
2308
2347
  }
2309
2348
  return await this.readOpportunityFrom(deps.opportunities, opportunityId, tenantId);
2310
2349
  }
2350
+ async lockPipelineStage(deps, stageId, tenantId) {
2351
+ if (deps.supportsRowLocks) {
2352
+ const stage2 = (await deps.stages.query(`SELECT * FROM ${deps.stages.tableName}
2353
+ WHERE id = $1 AND tenant_id = $2
2354
+ FOR UPDATE`, [stageId, tenantId], { allowRawOnTenantScoped: true }))[0];
2355
+ if (stage2 && stage2.tenantId === tenantId) return stage2;
2356
+ throw this.refusal("stage_unavailable", "Opportunity stage is unavailable in the active tenant and pipeline");
2357
+ }
2358
+ const stage = await deps.stages.get({ id: stageId }, { cache: false });
2359
+ if (stage && stage.tenantId === tenantId) return stage;
2360
+ throw this.refusal("stage_unavailable", "Opportunity stage is unavailable in the active tenant and pipeline");
2361
+ }
2311
2362
  async lockOperationFence(deps, key) {
2312
2363
  if (!deps.supportsRowLocks) return;
2313
2364
  await deps.leads.db.query("SELECT pg_advisory_xact_lock(hashtext($1))", key);
@@ -2368,6 +2419,7 @@ var LeadWorkflowService = class LeadWorkflowService {
2368
2419
  const acquisitionContext = input.acquisitionContext ?? {};
2369
2420
  if (!isPlainJsonObject(acquisitionContext) || !isJsonValue(acquisitionContext, /* @__PURE__ */ new Set())) throw this.refusal("invalid_metadata", "Lead acquisitionContext must be a plain JSON object with JSON values");
2370
2421
  const ownerRepId = input.ownerRepId ? this.requireIdentifier(input.ownerRepId, "ownerRepId") : "";
2422
+ const profileId = input.profileId !== void 0 ? this.requireIdentifier(input.profileId, "profileId") : "";
2371
2423
  const actorProfileId = input.actorProfileId ? this.requireIdentifier(input.actorProfileId, "actorProfileId") : "";
2372
2424
  const now = input.now ?? /* @__PURE__ */ new Date();
2373
2425
  if (!Number.isFinite(now.getTime())) throw this.refusal("invalid_due_at", "Lead intake now must be valid");
@@ -2377,6 +2429,7 @@ var LeadWorkflowService = class LeadWorkflowService {
2377
2429
  contactName: input.contactName?.trim() ?? "",
2378
2430
  phone,
2379
2431
  organizationName: input.organizationName?.trim() ?? "",
2432
+ profileId,
2380
2433
  sourceKind,
2381
2434
  sourceId: input.sourceId?.trim() ?? "",
2382
2435
  acquisitionContext,
@@ -2394,6 +2447,7 @@ var LeadWorkflowService = class LeadWorkflowService {
2394
2447
  contactName: normalized.contactName,
2395
2448
  phone: normalized.phone,
2396
2449
  organizationName: normalized.organizationName,
2450
+ ...normalized.profileId ? { profileId: normalized.profileId } : {},
2397
2451
  sourceKind: normalized.sourceKind,
2398
2452
  sourceId: normalized.sourceId,
2399
2453
  acquisitionContext: normalized.acquisitionContext,
@@ -2555,4 +2609,4 @@ function uuidFromHash(hash) {
2555
2609
  //#endregion
2556
2610
  export { PIPELINE_STATUSES as C, Lead as D, SALES_REPRESENTATIVE_STATUSES as E, OPPORTUNITY_STATUSES as S, SALES_ACTIVITY_SUBJECT_KINDS as T, PipelineStage as _, projectLeadWorkQueue as a, DEFAULT_PIPELINE_STAGES as b, LeadCollection as c, PipelineDefinitionCollection as d, PipelineDefinition as f, PipelineStageCollection as g, SalesActivity as h, MAX_LEAD_WORKFLOW_TEXT_LENGTH as i, SalesRepresentativeCollection as l, SalesActivityCollection as m, LeadWorkflowService as n, OpportunityConversionCollection as o, OpportunityCollection as p, LeadWorkflowValidationError as r, OpportunityConversion as s, LEAD_HUMAN_ACTIVITY_KINDS as t, SalesRepresentative as u, Opportunity as v, SALES_ACTIVITY_KINDS as w, LEAD_STATUSES as x, DEFAULT_PIPELINE_KEY as y };
2557
2611
 
2558
- //# sourceMappingURL=crm-DfRKKvWV.js.map
2612
+ //# sourceMappingURL=crm-B-irXbbr.js.map