@aglyn/tenant-data-admin 1.0.0-beta.221 → 1.0.0-beta.223
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.
- package/package.json +7 -7
- package/src/lib/server/api-keys.js +3 -3
- package/src/lib/server/api-keys.js.map +1 -1
- package/src/lib/server/api-v1-resources.d.ts +44 -3
- package/src/lib/server/api-v1-resources.js +82 -5
- package/src/lib/server/api-v1-resources.js.map +1 -1
- package/src/lib/server/collection-live-pages.d.ts +2 -2
- package/src/lib/server/collection-live-pages.js +1 -1
- package/src/lib/server/collection-live-pages.js.map +1 -1
- package/src/lib/server/email-delivery-log.d.ts +17 -73
- package/src/lib/server/email-delivery-log.js +44 -222
- package/src/lib/server/email-delivery-log.js.map +1 -1
- package/src/lib/server/email-flow-gate.js +27 -38
- package/src/lib/server/email-flow-gate.js.map +1 -1
- package/src/lib/server/erase-person.d.ts +34 -54
- package/src/lib/server/erase-person.js +44 -239
- package/src/lib/server/erase-person.js.map +1 -1
- package/src/lib/server/ga4-measurement-protocol.js +41 -28
- package/src/lib/server/ga4-measurement-protocol.js.map +1 -1
- package/src/lib/server/host-visitor-records.d.ts +25 -4
- package/src/lib/server/host-visitor-records.js +39 -11
- package/src/lib/server/host-visitor-records.js.map +1 -1
- package/src/lib/server/hosted-page-review.js +52 -36
- package/src/lib/server/hosted-page-review.js.map +1 -1
- package/src/lib/server/link-reputation-review.d.ts +6 -2
- package/src/lib/server/link-reputation-review.js +61 -20
- package/src/lib/server/link-reputation-review.js.map +1 -1
- package/src/lib/server/live-page-drops.d.ts +67 -0
- package/src/lib/server/live-page-drops.js +57 -0
- package/src/lib/server/live-page-drops.js.map +1 -0
- package/src/lib/server/media-bandwidth-cap.d.ts +78 -0
- package/src/lib/server/media-bandwidth-cap.js +180 -0
- package/src/lib/server/media-bandwidth-cap.js.map +1 -0
- package/src/lib/server/media-cdn-icon.d.ts +77 -0
- package/src/lib/server/media-cdn-icon.js +140 -0
- package/src/lib/server/media-cdn-icon.js.map +1 -0
- package/src/lib/server/media-delivery-regeneration.d.ts +132 -0
- package/src/lib/server/media-delivery-regeneration.js +216 -0
- package/src/lib/server/media-delivery-regeneration.js.map +1 -0
- package/src/lib/server/media-delivery.d.ts +2 -0
- package/src/lib/server/media-delivery.js +2 -1
- package/src/lib/server/media-delivery.js.map +1 -1
- package/src/lib/server/media-serve-count.d.ts +50 -0
- package/src/lib/server/media-serve-count.js +62 -0
- package/src/lib/server/media-serve-count.js.map +1 -0
- package/src/lib/server/media-signing.d.ts +13 -2
- package/src/lib/server/media-signing.js +12 -8
- package/src/lib/server/media-signing.js.map +1 -1
- package/src/lib/server/media-tombstone.js +7 -5
- package/src/lib/server/media-tombstone.js.map +1 -1
- package/src/lib/server/media-variants.d.ts +151 -20
- package/src/lib/server/media-variants.js +204 -27
- package/src/lib/server/media-variants.js.map +1 -1
- package/src/lib/server/organizations.d.ts +102 -2
- package/src/lib/server/organizations.js +388 -58
- package/src/lib/server/organizations.js.map +1 -1
- package/src/lib/server/outbound-send-review.js +11 -7
- package/src/lib/server/outbound-send-review.js.map +1 -1
- package/src/lib/server/paged-sweeps.d.ts +51 -0
- package/src/lib/server/paged-sweeps.js +79 -0
- package/src/lib/server/paged-sweeps.js.map +1 -0
- package/src/lib/server/payment-fraud-signal.d.ts +49 -9
- package/src/lib/server/payment-fraud-signal.js +192 -48
- package/src/lib/server/payment-fraud-signal.js.map +1 -1
- package/src/lib/server/platform-marketing-consent.d.ts +0 -49
- package/src/lib/server/platform-marketing-consent.js +27 -11
- package/src/lib/server/platform-marketing-consent.js.map +1 -1
- package/src/lib/server/render-monitor.d.ts +166 -0
- package/src/lib/server/render-monitor.js +412 -0
- package/src/lib/server/render-monitor.js.map +1 -0
- package/src/lib/server/risk-notice.d.ts +7 -0
- package/src/lib/server/risk-notice.js +6 -0
- package/src/lib/server/risk-notice.js.map +1 -1
- package/src/lib/server/serve-media-cdn.d.ts +69 -1
- package/src/lib/server/serve-media-cdn.js +424 -70
- package/src/lib/server/serve-media-cdn.js.map +1 -1
- package/src/lib/server/site-icon-render.d.ts +68 -0
- package/src/lib/server/site-icon-render.js +157 -0
- package/src/lib/server/site-icon-render.js.map +1 -0
- package/src/lib/server/staff-seat.d.ts +50 -0
- package/src/lib/server/staff-seat.js +118 -0
- package/src/lib/server/staff-seat.js.map +1 -0
- package/src/lib/server/transfer-export.d.ts +46 -0
- package/src/lib/server/transfer-export.js +221 -0
- package/src/lib/server/transfer-export.js.map +1 -0
- package/src/lib/server/transfer-jobs.d.ts +385 -0
- package/src/lib/server/transfer-jobs.js +2368 -0
- package/src/lib/server/transfer-jobs.js.map +1 -0
- package/src/lib/server/transfer-packages.d.ts +127 -0
- package/src/lib/server/transfer-packages.js +1036 -0
- package/src/lib/server/transfer-packages.js.map +1 -0
- package/src/lib/server/upgrade-proposal.d.ts +97 -0
- package/src/lib/server/upgrade-proposal.js +312 -0
- package/src/lib/server/upgrade-proposal.js.map +1 -0
- package/src/lib/server/upsert-contact.d.ts +17 -8
- package/src/lib/server/upsert-contact.js +82 -16
- package/src/lib/server/upsert-contact.js.map +1 -1
- package/src/lib/server/web-risk.d.ts +50 -9
- package/src/lib/server/web-risk.js +290 -155
- package/src/lib/server/web-risk.js.map +1 -1
- package/src/tenancy.d.ts +3 -3
- package/src/tenancy.js +5 -3
- package/src/tenancy.js.map +1 -1
- package/src/lib/server/campaign-attribution-store.d.ts +0 -55
- package/src/lib/server/campaign-attribution-store.js +0 -95
- package/src/lib/server/campaign-attribution-store.js.map +0 -1
- package/src/lib/server/campaign-conversion-attribution.d.ts +0 -283
- package/src/lib/server/campaign-conversion-attribution.js +0 -450
- package/src/lib/server/campaign-conversion-attribution.js.map +0 -1
- package/src/lib/server/crm-email-activity.d.ts +0 -118
- package/src/lib/server/crm-email-activity.js +0 -148
- package/src/lib/server/crm-email-activity.js.map +0 -1
- package/src/lib/server/crm-next-activity.d.ts +0 -74
- package/src/lib/server/crm-next-activity.js +0 -194
- package/src/lib/server/crm-next-activity.js.map +0 -1
- package/src/lib/server/dataset-live-pages.d.ts +0 -179
- package/src/lib/server/dataset-live-pages.js +0 -421
- package/src/lib/server/dataset-live-pages.js.map +0 -1
- package/src/lib/server/email-revenue-attribution.d.ts +0 -185
- package/src/lib/server/email-revenue-attribution.js +0 -321
- package/src/lib/server/email-revenue-attribution.js.map +0 -1
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import { type ConsentGroup, type ContactFacet, type ContactInteraction, type ContactLifecycleStage, type ContactSource } from '@aglyn/aglyn/server';
|
|
18
|
-
import { type
|
|
18
|
+
import { type PluginConversionTouch } from '@aglyn/aglyn/plugin-manager/plugin-conversion-credit';
|
|
19
19
|
import { type MarketingConsentSource } from '@aglyn/aglyn/app-utils/marketing-consent';
|
|
20
20
|
import { getOrgForHost } from './organizations';
|
|
21
21
|
/**
|
|
@@ -53,7 +53,7 @@ export type UpsertHostContactVerdict = {
|
|
|
53
53
|
* a field the facet grows is a field this option may carry the moment the
|
|
54
54
|
* pick names it, and one it does not name is refused at compile time.
|
|
55
55
|
*/
|
|
56
|
-
export type UpsertHostContactFacet = Partial<Pick<ContactFacet, 'phone' | 'jobTitle' | 'leadSource' | 'companyId' | 'companyName' | 'address' | 'ownerUid' | 'lifecycleStage' | 'custom'>>;
|
|
56
|
+
export type UpsertHostContactFacet = Partial<Pick<ContactFacet, 'phone' | 'jobTitle' | 'leadSource' | 'companyId' | 'companyName' | 'address' | 'ownerUid' | 'lifecycleStage' | 'custom' | 'salutation' | 'firstName' | 'lastName' | 'department' | 'mobilePhone' | 'homePhone' | 'otherPhone' | 'fax' | 'birthdate' | 'assistantName' | 'assistantPhone' | 'otherAddress' | 'doNotCall'>>;
|
|
57
57
|
/**
|
|
58
58
|
* The profile fields a door may hand this function (AGL-2596): the parts of
|
|
59
59
|
* a person's record that no capture surface collects — the console's create
|
|
@@ -82,7 +82,7 @@ export type ContactProfileInput = UpsertHostContactFacet;
|
|
|
82
82
|
* Handed to {@link UpsertHostContactOptions.onCreated} once, on the create
|
|
83
83
|
* branch only. The merge branch is a visit by somebody the org already held,
|
|
84
84
|
* which is another interaction and not a new contact — the same line
|
|
85
|
-
* `
|
|
85
|
+
* `conversionTouch` draws for attribution. Scalars and one string array, so
|
|
86
86
|
* the runtime can flatten it into an event payload without inventing keys.
|
|
87
87
|
*/
|
|
88
88
|
export interface HostContactCreated {
|
|
@@ -184,17 +184,19 @@ export interface UpsertHostContactOptions {
|
|
|
184
184
|
*
|
|
185
185
|
* Absent everywhere today, because no order document carries a currency and
|
|
186
186
|
* every checkout door writes `currency: 'usd'` onto the Stripe line items.
|
|
187
|
-
*
|
|
187
|
+
* The plugin that credits orders defaults it on that basis and says so. The field
|
|
188
188
|
* exists so a door that ever charges in something else can pass it, and the
|
|
189
189
|
* campaign revenue report keeps it in its own bucket rather than adding it
|
|
190
190
|
* to the dollars.
|
|
191
191
|
*/
|
|
192
192
|
purchaseCurrency?: string;
|
|
193
193
|
/**
|
|
194
|
-
*
|
|
194
|
+
* Where this person arrived from, already resolved by the door through the
|
|
195
|
+
* plugin that credits outcomes (`plugin-conversion-credit`), and opaque
|
|
196
|
+
* here.
|
|
195
197
|
*
|
|
196
198
|
* ⛔ The ORDER path passes none, and must not start. An order already has
|
|
197
|
-
* its own
|
|
199
|
+
* its own credit one branch below — `creditOrderConversion`, keyed on the
|
|
198
200
|
* order id — and a second record for the same sale would be the same money
|
|
199
201
|
* counted twice under two rules. This is the door for the moments an order
|
|
200
202
|
* does NOT cover: a form submission, a membership sign-up, a booking, a
|
|
@@ -203,11 +205,11 @@ export interface UpsertHostContactOptions {
|
|
|
203
205
|
* Resolved rather than raw, for the reason `addHostLead` states: one
|
|
204
206
|
* visitor action reaches several writers and the touch lookup is paid once.
|
|
205
207
|
*/
|
|
206
|
-
|
|
208
|
+
conversionTouch?: PluginConversionTouch | null;
|
|
207
209
|
/**
|
|
208
210
|
* The campaigns the CAPTURE SURFACE is filed under.
|
|
209
211
|
*
|
|
210
|
-
* ⚠️ A different fact from {@link
|
|
212
|
+
* ⚠️ A different fact from {@link conversionTouch} beside it, and the two must
|
|
211
213
|
* never be folded together. A touch is where the visitor came FROM — an ad,
|
|
212
214
|
* a link, a browser-supplied label resolved through an allowlist. This is
|
|
213
215
|
* which campaigns the merchant put the form itself in, which is the
|
|
@@ -233,6 +235,13 @@ export interface UpsertHostContactOptions {
|
|
|
233
235
|
* phone and nothing else does not blank the title somebody typed.
|
|
234
236
|
*/
|
|
235
237
|
facet?: UpsertHostContactFacet;
|
|
238
|
+
/**
|
|
239
|
+
* Profile fields written only where THIS holder's facet has none
|
|
240
|
+
* (AGL-3493) — what a door learned in passing, like the phone a booking
|
|
241
|
+
* form asked for, which must not replace a number somebody typed on the
|
|
242
|
+
* record. A key {@link facet} also carries is `facet`'s to write.
|
|
243
|
+
*/
|
|
244
|
+
facetFill?: Pick<UpsertHostContactFacet, 'phone'>;
|
|
236
245
|
/**
|
|
237
246
|
* The EARLIEST stage that describes what this capture was (AGL-2612).
|
|
238
247
|
*
|
|
@@ -14,14 +14,13 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
14
14
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
|
-
*/ import { CAPTURED_BY_HOST_FIELD, checkCrmRecordsQuota, consentGroupScope, CONTACT_FACETS_FIELD, CONTACT_FORM_IDS_CAP, CONTACT_FORM_IDS_FIELD, marketingConsentFieldsForGroup, mergeContactInteraction, normalizeContainerIds, readContactFacet, normalizeContactEmail, ORG_SCOPE_TOKEN } from "@aglyn/aglyn/server";
|
|
17
|
+
*/ import { CAPTURED_BY_HOST_FIELD, checkCrmRecordsQuota, composeContactName, CONTACT_EXTRA_PHONE_FIELDS, consentGroupScope, CONTACT_FACETS_FIELD, CONTACT_FORM_IDS_CAP, CONTACT_FORM_IDS_FIELD, marketingConsentFieldsForGroup, mergeContactInteraction, normalizeContactBirthdate, normalizeContainerIds, readContactFacet, normalizeContactEmail, ORG_SCOPE_TOKEN } from "@aglyn/aglyn/server";
|
|
18
18
|
import { FieldValue } from "firebase-admin/firestore";
|
|
19
19
|
import { firebaseAdmin } from "./firebase-admin.js";
|
|
20
20
|
import { countCrmRecords, restampCrmListFieldsAt } from "./crm-records.js";
|
|
21
|
-
import { attributeOrderToEmail } from "./email-revenue-attribution.js";
|
|
22
21
|
import { hostErasedEmails, hostRefusesCaptureForErasure } from "./email-suppression.js";
|
|
23
22
|
import { scheduleCapturedEmailCheck } from "./capture-email-check.js";
|
|
24
|
-
import {
|
|
23
|
+
import { creditConversion, creditOrderConversion } from "@aglyn/aglyn/plugin-manager/plugin-conversion-credit";
|
|
25
24
|
import { nameSearchFields } from "@aglyn/aglyn/app-utils/name-search";
|
|
26
25
|
import { consentGroupForGrant } from "@aglyn/aglyn/app-utils/consent-groups";
|
|
27
26
|
import { declineMarketingConsentFields, MARKETING_CONSENT_SOURCE_FIELD } from "@aglyn/aglyn/app-utils/marketing-consent";
|
|
@@ -48,6 +47,44 @@ import { consentGroupForSite, getOrgForHost, orgDataCollectionForHost } from "./
|
|
|
48
47
|
*/ function storableProfile(input) {
|
|
49
48
|
if (!input) return {};
|
|
50
49
|
const out = {};
|
|
50
|
+
/*
|
|
51
|
+
* Salesforce's standard contact fields (AGL-3515), under the same rule as
|
|
52
|
+
* the rest: given keys only, each normalized, an unusable value dropped.
|
|
53
|
+
* The salutation is judged against the org's list by the door that took
|
|
54
|
+
* it and held here to the label's shape, like the lead source. Do not
|
|
55
|
+
* call is written only as `true`: a door may learn that a person asked
|
|
56
|
+
* not to be phoned, and no capture is the person taking it back.
|
|
57
|
+
*/ if (typeof input.salutation === 'string') {
|
|
58
|
+
const salutation = input.salutation.trim().replace(/\s+/g, ' ').slice(0, 120);
|
|
59
|
+
if (salutation) out.salutation = salutation;
|
|
60
|
+
}
|
|
61
|
+
if (input.firstName !== undefined) {
|
|
62
|
+
const firstName = composeContactName(input.firstName, '');
|
|
63
|
+
if (firstName) out.firstName = firstName;
|
|
64
|
+
}
|
|
65
|
+
if (input.lastName !== undefined) {
|
|
66
|
+
const lastName = composeContactName('', input.lastName);
|
|
67
|
+
if (lastName) out.lastName = lastName;
|
|
68
|
+
}
|
|
69
|
+
for (const key of [
|
|
70
|
+
'department',
|
|
71
|
+
'assistantName'
|
|
72
|
+
]){
|
|
73
|
+
if (typeof input[key] !== 'string') continue;
|
|
74
|
+
const value = input[key].trim().slice(0, 120);
|
|
75
|
+
if (value) out[key] = value;
|
|
76
|
+
}
|
|
77
|
+
for (const key of CONTACT_EXTRA_PHONE_FIELDS){
|
|
78
|
+
if (input[key] === undefined) continue;
|
|
79
|
+
const phone = normalizePhone(input[key]);
|
|
80
|
+
if (phone) out[key] = phone;
|
|
81
|
+
}
|
|
82
|
+
if (input.birthdate !== undefined) {
|
|
83
|
+
const birthdate = normalizeContactBirthdate(input.birthdate);
|
|
84
|
+
if (birthdate) out.birthdate = birthdate;
|
|
85
|
+
}
|
|
86
|
+
if (input.otherAddress !== undefined) out.otherAddress = normalizeAddress(input.otherAddress);
|
|
87
|
+
if (input.doNotCall === true) out.doNotCall = true;
|
|
51
88
|
if (input.phone !== undefined) {
|
|
52
89
|
const phone = normalizePhone(input.phone);
|
|
53
90
|
if (phone) out.phone = phone;
|
|
@@ -96,6 +133,17 @@ import { consentGroupForSite, getOrgForHost, orgDataCollectionForHost } from "./
|
|
|
96
133
|
}
|
|
97
134
|
return out;
|
|
98
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* A door's {@link UpsertHostContactOptions.facetFill}, folded into the
|
|
138
|
+
* profile it is about to write: each field only where neither the door's
|
|
139
|
+
* own profile nor the holder's stored facet holds one.
|
|
140
|
+
*/ function fillProfile(profile, fill, stored) {
|
|
141
|
+
var _ref;
|
|
142
|
+
const given = storableProfile(fill);
|
|
143
|
+
if (given.phone && !profile.phone && !String((_ref = stored == null ? void 0 : stored.phone) != null ? _ref : '').trim()) {
|
|
144
|
+
profile.phone = given.phone;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
99
147
|
/**
|
|
100
148
|
* The org's companies collection, beside its contacts one.
|
|
101
149
|
*
|
|
@@ -148,7 +196,7 @@ export async function upsertHostContact(options) {
|
|
|
148
196
|
* contact capture below it.
|
|
149
197
|
*=========================================*/ if (options.source === 'order' && options.interaction.refId) {
|
|
150
198
|
var _options_purchaseCents, _options_interaction_atMs1;
|
|
151
|
-
await
|
|
199
|
+
await creditOrderConversion(_extends({
|
|
152
200
|
hostId: options.hostId,
|
|
153
201
|
orderId: String(options.interaction.refId),
|
|
154
202
|
email,
|
|
@@ -249,7 +297,7 @@ export async function upsertHostContact(options) {
|
|
|
249
297
|
*=========================================*/ const prefetched = batch == null ? void 0 : batch.claim(email);
|
|
250
298
|
const docSnapshot = prefetched !== undefined ? prefetched : await findContactByEmail(contactsRef, email);
|
|
251
299
|
if (docSnapshot) {
|
|
252
|
-
var _facet_name, _profile_lifecycleStage, _ref5;
|
|
300
|
+
var _facet_name, _profile_firstName, _profile_lastName, _profile_lifecycleStage, _ref5;
|
|
253
301
|
var _contactsRef_parent1;
|
|
254
302
|
/*
|
|
255
303
|
* MERGED INTO THIS GROUP'S FACET, not into the top of the document.
|
|
@@ -283,6 +331,15 @@ export async function upsertHostContact(options) {
|
|
|
283
331
|
* named no stage and found none leaves the key absent, which reads as
|
|
284
332
|
* "no stage" rather than as a stage somebody picked.
|
|
285
333
|
*/ const profile = storableProfile(options.facet);
|
|
334
|
+
fillProfile(profile, options.facetFill, facet);
|
|
335
|
+
/*
|
|
336
|
+
* THE NAME FOLLOWS THE FIRST AND LAST NAMES (AGL-3515): a door that
|
|
337
|
+
* carried either writes the holder's name as their composition, over
|
|
338
|
+
* the name the facet held — the parts are the newer, structured
|
|
339
|
+
* statement of the same thing. A door that carried neither leaves the
|
|
340
|
+
* name to the rule above, where the existing name wins.
|
|
341
|
+
*/ const composedName = profile.firstName !== undefined || profile.lastName !== undefined ? composeContactName((_profile_firstName = profile.firstName) != null ? _profile_firstName : facet.firstName, (_profile_lastName = profile.lastName) != null ? _profile_lastName : facet.lastName) : '';
|
|
342
|
+
const facetName = composedName || merged.name;
|
|
286
343
|
const advanced = advanceContactLifecycleStage((_profile_lifecycleStage = profile.lifecycleStage) != null ? _profile_lifecycleStage : facet.lifecycleStage, options.initialLifecycleStage);
|
|
287
344
|
if (advanced) profile.lifecycleStage = advanced;
|
|
288
345
|
/*
|
|
@@ -308,7 +365,7 @@ export async function upsertHostContact(options) {
|
|
|
308
365
|
* merge-set, and the counts settle after it.
|
|
309
366
|
*/ const link = profile.companyId !== undefined ? planContactCompanyLink(readContactCompanyLink(docSnapshot.data(), group.groupId), profile.companyId) : null;
|
|
310
367
|
const mirror = link ? contactCompanyMirrorValue(link) : undefined;
|
|
311
|
-
await docSnapshot.ref.set(_extends({},
|
|
368
|
+
await docSnapshot.ref.set(_extends({}, facetName ? nameSearchFields(facetName) : {}, profile.phone ? {
|
|
312
369
|
phone: profile.phone
|
|
313
370
|
} : {}, profile.companyName ? {
|
|
314
371
|
companyName: profile.companyName
|
|
@@ -325,8 +382,8 @@ export async function upsertHostContact(options) {
|
|
|
325
382
|
[group.groupId]: _extends({
|
|
326
383
|
sources: merged.sources,
|
|
327
384
|
interactions: merged.interactions
|
|
328
|
-
},
|
|
329
|
-
name:
|
|
385
|
+
}, facetName ? {
|
|
386
|
+
name: facetName
|
|
330
387
|
} : {}, campaignIds.length ? {
|
|
331
388
|
campaignIds: FieldValue.arrayUnion(...campaignIds)
|
|
332
389
|
} : {}, tags.length ? {
|
|
@@ -437,9 +494,18 @@ export async function upsertHostContact(options) {
|
|
|
437
494
|
* a door that named one writes. A `null` address is dropped rather than
|
|
438
495
|
* written: there is nothing on a new document for it to clear.
|
|
439
496
|
*/ const profile = storableProfile(options.facet);
|
|
497
|
+
// A new person holds nothing yet, so the fill is written whole.
|
|
498
|
+
fillProfile(profile, options.facetFill, null);
|
|
440
499
|
const advanced = advanceContactLifecycleStage(profile.lifecycleStage, options.initialLifecycleStage);
|
|
441
500
|
if (advanced) profile.lifecycleStage = advanced;
|
|
442
501
|
if (profile.address === null) delete profile.address;
|
|
502
|
+
if (profile.otherAddress === null) delete profile.otherAddress;
|
|
503
|
+
// The holder's name is the first and last names' when the door gave
|
|
504
|
+
// either (AGL-3515); the canonical name is the one the door gave, or
|
|
505
|
+
// that composition for a door that gave only the parts.
|
|
506
|
+
const composedName = composeContactName(profile.firstName, profile.lastName);
|
|
507
|
+
const canonicalName = (options.name || composedName).slice(0, 120);
|
|
508
|
+
const holderName = (composedName || options.name || '').slice(0, 120);
|
|
443
509
|
const record = _extends({
|
|
444
510
|
hostId: options.hostId,
|
|
445
511
|
/*
|
|
@@ -474,7 +540,7 @@ export async function upsertHostContact(options) {
|
|
|
474
540
|
ORG_SCOPE_TOKEN
|
|
475
541
|
] : consentGroupScope(group),
|
|
476
542
|
email
|
|
477
|
-
},
|
|
543
|
+
}, canonicalName ? nameSearchFields(canonicalName) : {}, profile.phone ? {
|
|
478
544
|
phone: profile.phone
|
|
479
545
|
} : {}, profile.companyName ? {
|
|
480
546
|
companyName: profile.companyName
|
|
@@ -497,8 +563,8 @@ export async function upsertHostContact(options) {
|
|
|
497
563
|
tags
|
|
498
564
|
}, campaignIds.length ? {
|
|
499
565
|
campaignIds
|
|
500
|
-
} : {}, customFacet,
|
|
501
|
-
name:
|
|
566
|
+
} : {}, customFacet, holderName ? {
|
|
567
|
+
name: holderName
|
|
502
568
|
} : {}, profile, options.purchaseCents ? {
|
|
503
569
|
ltvCents: options.purchaseCents,
|
|
504
570
|
ordersCount: 1,
|
|
@@ -542,12 +608,12 @@ export async function upsertHostContact(options) {
|
|
|
542
608
|
* is the same rule `addHostLead` applies — an interaction appended to
|
|
543
609
|
* somebody the site already held is another visit, not a new person, and
|
|
544
610
|
* crediting it would let the most recent campaign re-earn the whole list.
|
|
545
|
-
*/ if (options.
|
|
546
|
-
await
|
|
611
|
+
*/ if (options.conversionTouch) {
|
|
612
|
+
await creditConversion({
|
|
547
613
|
hostId: options.hostId,
|
|
548
614
|
kind: 'contact',
|
|
549
615
|
refId: created.id,
|
|
550
|
-
touch: options.
|
|
616
|
+
touch: options.conversionTouch,
|
|
551
617
|
convertedAtMs: interaction.atMs
|
|
552
618
|
});
|
|
553
619
|
}
|
|
@@ -562,8 +628,8 @@ export async function upsertHostContact(options) {
|
|
|
562
628
|
contactId: created.id,
|
|
563
629
|
hostId: options.hostId,
|
|
564
630
|
email
|
|
565
|
-
},
|
|
566
|
-
name:
|
|
631
|
+
}, holderName ? {
|
|
632
|
+
name: holderName
|
|
567
633
|
} : {}, {
|
|
568
634
|
source: options.source,
|
|
569
635
|
campaignIds
|