@mparticle/web-amplitude-kit 2.2.0 → 2.2.1

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.
@@ -57,6 +57,18 @@ var constants = {
57
57
  other10: 'other10',
58
58
  };
59
59
 
60
+ var MP_AMP_SPLIT = 'mparticle_amplitude_should_split',
61
+ TOTAL_AMOUNT = 'Total Amount',
62
+ TOTAL = 'Total',
63
+ PRODUCTS = 'products',
64
+ REFUND = 'Refund',
65
+ PURCHASE = 'Purchase',
66
+ TOTAL_PRODUCT_AMOUNT = 'Total Product Amount';
67
+
68
+ var includeIndividualProductEvents,
69
+ shouldSendSeparateAmplitudeRevenueEvent,
70
+ enableTempAmplitudeEcommerce;
71
+
60
72
  /* eslint-disable */
61
73
  // prettier-ignore
62
74
  var renderSnippet = function() {
@@ -341,7 +353,7 @@ var constructor = function () {
341
353
  function createEcommerceAttributes(attributes) {
342
354
  var updatedAttributes = {};
343
355
  for (var key in attributes) {
344
- if (key !== 'Total Amount' && key !== 'Total Product Amount') {
356
+ if (key !== TOTAL_AMOUNT && key !== TOTAL_PRODUCT_AMOUNT) {
345
357
  updatedAttributes[key] = attributes[key];
346
358
  }
347
359
  }
@@ -351,62 +363,263 @@ var constructor = function () {
351
363
 
352
364
  function logCommerce(event) {
353
365
  var expandedEvents = mParticle.eCommerce.expandCommerceEvent(event);
366
+ // if Product Action exists, it's a regular product action commerce event
354
367
  if (event.ProductAction) {
355
- var isRefund, isPurchase, logRevenue;
356
- isRefund =
357
- event.ProductAction.ProductActionType ===
358
- mParticle.ProductActionType.Refund;
359
- isPurchase =
360
- event.ProductAction.ProductActionType ===
361
- mParticle.ProductActionType.Purchase;
362
- logRevenue = isRefund || isPurchase;
368
+ if (enableTempAmplitudeEcommerce) {
369
+ return processTemporaryProductAction(event, expandedEvents);
370
+ } else {
371
+ // TODO: Remove this old code path when Amplitude is ready
372
+ var isRefund, isPurchase, logRevenue;
373
+ isRefund =
374
+ event.ProductAction.ProductActionType ===
375
+ mParticle.ProductActionType.Refund;
376
+ isPurchase =
377
+ event.ProductAction.ProductActionType ===
378
+ mParticle.ProductActionType.Purchase;
379
+ logRevenue = isRefund || isPurchase;
380
+ expandedEvents.forEach(function (expandedEvt) {
381
+ // Exclude Totals from the attributes as we log it in the revenue call
382
+ var updatedAttributes = createEcommerceAttributes(
383
+ expandedEvt.EventAttributes
384
+ );
385
+
386
+ // Purchase and Refund events generate an additional 'Total' event
387
+ if (
388
+ logRevenue &&
389
+ expandedEvt.EventName.indexOf('Total') > -1
390
+ ) {
391
+ var revenueAmount =
392
+ (expandedEvt.EventAttributes['Total Amount'] || 0) *
393
+ (isRefund ? -1 : 1);
394
+ var revenue = new window.amplitude.Revenue()
395
+ .setPrice(revenueAmount)
396
+ .setEventProperties(updatedAttributes);
397
+ getInstance().logRevenueV2(revenue);
398
+ } else {
399
+ getInstance().logEvent(
400
+ expandedEvt.EventName,
401
+ updatedAttributes
402
+ );
403
+ }
404
+ });
405
+
406
+ return true;
407
+ }
408
+ }
409
+
410
+ // if it is not a product action, it is an impression or promotion commerce event
411
+ if (isNotProductAction(event)) {
363
412
  expandedEvents.forEach(function (expandedEvt) {
364
413
  // Exclude Totals from the attributes as we log it in the revenue call
365
414
  var updatedAttributes = createEcommerceAttributes(
366
415
  expandedEvt.EventAttributes
367
416
  );
368
417
 
369
- // Purchase and Refund events generate an additional 'Total' event
370
- if (logRevenue && expandedEvt.EventName.indexOf('Total') > -1) {
371
- var revenueAmount =
372
- (expandedEvt.EventAttributes['Total Amount'] || 0) *
373
- (isRefund ? -1 : 1);
374
- var revenue = new window.amplitude.Revenue()
375
- .setPrice(revenueAmount)
376
- .setEventProperties(updatedAttributes);
377
- getInstance().logRevenueV2(revenue);
378
- } else {
379
- getInstance().logEvent(
380
- expandedEvt.EventName,
381
- updatedAttributes
382
- );
383
- }
418
+ getInstance().logEvent(
419
+ expandedEvt.EventName,
420
+ updatedAttributes
421
+ );
384
422
  });
385
423
 
386
424
  return true;
387
425
  }
388
426
 
427
+ console.warn(
428
+ 'Commerce event does not conform to our expectations and was not forwarded to Amplitude. Please double-check your code.'
429
+ );
430
+
431
+ return false;
432
+ }
433
+
434
+ /*
435
+ When we process a product action event, Amplitude has a very specific way of
436
+ sending events to them:
437
+
438
+ 1. Send a summary event with event attributes from the MP event.
439
+ a. Add a key of `products` with a value of JSON.stringify(productArray).
440
+ b. Add a key of mparticle_amplitude_should_split with a value of `false`.
441
+
442
+ 2. Determine if we send product level events or not.
443
+ a. If includeIndividualProductEvents === true, send product level events
444
+ b. If includeIndividualProductEvents === false, do not send product level events
445
+
446
+ 3. Determine if we send an Amplitude revenue event or not.
447
+ a. If shouldSendSeparateAmplitudeRevenueEvent === true, send an Amplitude revenue event.
448
+ b. If shouldSendSeparateAmplitudeRevenueEvent === true, the summary event attribute should be `revenue`.
449
+ c. If shouldSendSeparateAmplitudeRevenueEvent === false, the summary event attribute should be `$revenue`
450
+
451
+ See test/AmplitudeCommerceEvent.MD for examples of what the expectations of the payload are.
452
+
453
+ */
454
+ function processTemporaryProductAction(
455
+ unexpandedCommerceEvent,
456
+ expandedEvents
457
+ ) {
458
+ var summaryEvent, isRefund, isPurchase, isMPRevenueEvent;
459
+
460
+ isRefund =
461
+ unexpandedCommerceEvent.ProductAction.ProductActionType ===
462
+ mParticle.ProductActionType.Refund;
463
+ isPurchase =
464
+ unexpandedCommerceEvent.ProductAction.ProductActionType ===
465
+ mParticle.ProductActionType.Purchase;
466
+ isMPRevenueEvent = isRefund || isPurchase;
467
+
468
+ // if the event is a revenue event, then we set it to the expanded `Total` event for backwards compatibility
389
469
  if (
470
+ isMPRevenueEvent &&
471
+ expandedEvents[0].EventName.indexOf(TOTAL) > -1
472
+ ) {
473
+ summaryEvent = expandedEvents[0];
474
+ sendMPRevenueSummaryEvent(
475
+ summaryEvent,
476
+ unexpandedCommerceEvent.ProductAction.ProductList,
477
+ isRefund,
478
+ shouldSendSeparateAmplitudeRevenueEvent
479
+ );
480
+ }
481
+
482
+ if (!isMPRevenueEvent) {
483
+ sendSummaryEvent(unexpandedCommerceEvent);
484
+ }
485
+
486
+ if (includeIndividualProductEvents) {
487
+ sendIndividualProductEvents(
488
+ expandedEvents,
489
+ isMPRevenueEvent,
490
+ shouldSendSeparateAmplitudeRevenueEvent,
491
+ isRefund
492
+ );
493
+ }
494
+
495
+ return true;
496
+ }
497
+
498
+ // If event.ProductAction does not exist, the commerce event is a promotion or impression event
499
+ function isNotProductAction(event) {
500
+ return (
390
501
  event.EventCategory ===
391
502
  mParticle.CommerceEventType.ProductImpression ||
392
503
  event.EventCategory === mParticle.CommerceEventType.PromotionView ||
393
504
  event.EventCategory === mParticle.CommerceEventType.PromotionClick
394
- ) {
395
- expandedEvents.forEach(function (expandedEvt) {
396
- // Exclude Totals from the attributes as we log it in the revenue call
397
- var updatedAttributes = createEcommerceAttributes(
505
+ );
506
+ }
507
+
508
+ // this function does not use Amplitude's logRevenueV2, but rather sends custom event names
509
+ function sendMPRevenueSummaryEvent(
510
+ summaryEvent,
511
+ products,
512
+ isRefund,
513
+ shouldSendSeparateAmplitudeRevenueEvent
514
+ ) {
515
+ // send the ecommerce - purchase event
516
+ var updatedAttributes = createMPRevenueEcommerceAttributes(
517
+ summaryEvent.EventAttributes,
518
+ shouldSendSeparateAmplitudeRevenueEvent,
519
+ isRefund
520
+ );
521
+ updatedAttributes[MP_AMP_SPLIT] = false;
522
+
523
+ updatedAttributes[PRODUCTS] = products;
524
+ var revenueEventLabel = isRefund ? REFUND : PURCHASE;
525
+ getInstance().logEvent(
526
+ 'eCommerce - ' + revenueEventLabel,
527
+ updatedAttributes
528
+ );
529
+ }
530
+
531
+ // revenue summary event will either have $price/price or $revenue/revenue depending on if
532
+ function createMPRevenueEcommerceAttributes(
533
+ attributes,
534
+ shouldSendSeparateAmplitudeRevenueEvent,
535
+ isRefund
536
+ ) {
537
+ var updatedAttributes = {};
538
+ for (var key in attributes) {
539
+ if (key === TOTAL_AMOUNT) {
540
+ // A purchase is a positive amount and a refund is negative
541
+ var revenueAmount = attributes[key] * (isRefund ? -1 : 1);
542
+ // If we send a separate Amplitude Revenue Event, Amplitude's
543
+ // SDK prefixes price/revenue with a $ for calculating things
544
+ // like LTV, so we do not want to prepend it as part of the
545
+ // summary event to avoid double counting
546
+ var revenueKey = shouldSendSeparateAmplitudeRevenueEvent
547
+ ? 'revenue'
548
+ : '$revenue';
549
+
550
+ updatedAttributes[revenueKey] = revenueAmount;
551
+ } else if (key !== TOTAL_AMOUNT) {
552
+ updatedAttributes[key] = attributes[key];
553
+ }
554
+ }
555
+
556
+ return convertJsonAttrs(updatedAttributes);
557
+ }
558
+
559
+ function createAttrsForAmplitudeRevenueEvent(attributes) {
560
+ var updatedAttributes = {};
561
+ for (var key in attributes) {
562
+ if (key !== TOTAL_AMOUNT) {
563
+ updatedAttributes[key] = attributes[key];
564
+ }
565
+ }
566
+
567
+ return convertJsonAttrs(updatedAttributes);
568
+ }
569
+
570
+ function sendSummaryEvent(summaryEvent) {
571
+ var updatedAttributes = createEcommerceAttributes(
572
+ summaryEvent.EventAttributes
573
+ );
574
+ updatedAttributes[MP_AMP_SPLIT] = false;
575
+ try {
576
+ updatedAttributes[PRODUCTS] =
577
+ summaryEvent.ProductAction.ProductList;
578
+ } catch (e) {
579
+ console.error('error adding Product List to summary event');
580
+ }
581
+
582
+ getInstance().logEvent(summaryEvent.EventName, updatedAttributes);
583
+ }
584
+
585
+ function sendIndividualProductEvents(
586
+ expandedEvents,
587
+ isMPRevenueEvent,
588
+ shouldSendSeparateAmplitudeRevenueEvent,
589
+ isRefund
590
+ ) {
591
+ expandedEvents.forEach(function (expandedEvt) {
592
+ var updatedAttributes;
593
+ // `Total` exists on an expanded event if it is part of a revenue/purchase event
594
+ // but not on other commerce events. This only needs to be fired if shouldSendSeparateAmplitudeRevenueEvent === True
595
+ if (
596
+ isMPRevenueEvent &&
597
+ // A purchase is a positive amount and a refund is negative
598
+ (expandedEvt.EventName.indexOf(TOTAL) > -1) &
599
+ shouldSendSeparateAmplitudeRevenueEvent
600
+ ) {
601
+ var revenueAmount =
602
+ // A purchase is a positive amount and a refund is negative
603
+ (expandedEvt.EventAttributes[TOTAL_AMOUNT] || 0) *
604
+ (isRefund ? -1 : 1);
605
+ updatedAttributes = createAttrsForAmplitudeRevenueEvent(
398
606
  expandedEvt.EventAttributes
399
607
  );
400
608
 
609
+ var revenue = new window.amplitude.Revenue()
610
+ .setPrice(revenueAmount)
611
+ .setEventProperties(updatedAttributes);
612
+ getInstance().logRevenueV2(revenue);
613
+ } else if (expandedEvt.EventName.indexOf(TOTAL) === -1) {
614
+ updatedAttributes = createEcommerceAttributes(
615
+ expandedEvt.EventAttributes
616
+ );
401
617
  getInstance().logEvent(
402
618
  expandedEvt.EventName,
403
619
  updatedAttributes
404
620
  );
405
- });
406
- return true;
407
- }
408
-
409
- return false;
621
+ }
622
+ });
410
623
  }
411
624
 
412
625
  function convertJsonAttrs(customAttributes) {
@@ -434,6 +647,15 @@ var constructor = function () {
434
647
  forwarderSettings = settings;
435
648
  reportingService = service;
436
649
 
650
+ // Changing this setting from a negative action to a positive action for readability
651
+ includeIndividualProductEvents =
652
+ forwarderSettings.excludeIndividualProductEvents === 'False';
653
+ // Only send separate amplitude revenue events when we includeIndividualProductEvents,
654
+ // so create this variable for clarity
655
+ shouldSendSeparateAmplitudeRevenueEvent = includeIndividualProductEvents;
656
+
657
+ enableTempAmplitudeEcommerce =
658
+ forwarderSettings.enableTempAmplitudeEcommerce === 'True';
437
659
  try {
438
660
  if (!window.amplitude) {
439
661
  if (testMode !== true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-amplitude-kit",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "author": "mParticle Developers <developers@mparticle.com> (https://www.mparticle.com)",
5
5
  "description": "mParticle integration sdk for Amplitude",
6
6
  "main": "dist/Amplitude.common.js",
package/CHANGELOG.md DELETED
@@ -1,49 +0,0 @@
1
- ## Releases
2
-
3
- --
4
- #### 2.2.0 - 2021-11-03
5
-
6
- - feat: Support other5-other10 IDs
7
-
8
- #### 2.1.0 - 2021-08-30
9
-
10
- - feat: Add support for EU Data Center
11
-
12
- #### 2.0.8 - 2021-05-26
13
-
14
- - Generate bundle that was not included in 2.0.7 release
15
-
16
- #### 2.0.7 - 2021-05-26
17
-
18
- - fix: Map impression and promotion events to align with server
19
-
20
- #### 2.0.6 - 2021-04-06
21
-
22
- - feat: Add includeEmailAsUserProperty and no longer set userIdentities as user properties to align with server
23
-
24
- - Previously the web kit set non-customerid user identities as user properties. This was not consistent with the server, and so this functionality has been removed from web SDK v2.
25
-
26
- - build: Update eslint/prettier config, fix linting errors
27
-
28
- #### 2.0.5 - 2021-01-11
29
-
30
- - Update Amplitude SDK to 7.2.1
31
- - Bugfix - Check window for node environments
32
- - Remove build file from root directory
33
-
34
- #### 2.0.4 - 2020-11-04
35
-
36
- - Bugfix - remove isTesting variable
37
-
38
- #### 2.0.3 - 2020-06-30
39
-
40
- - Feat: Support sending objects as custom attributes to Amplitude
41
-
42
- #### 2.0.2 - 2020-06-03
43
-
44
- - Update Amplitude SDK version to 6.2.0
45
- - Update test configuration
46
-
47
- #### 2.0.1 - 2020-02-03
48
-
49
- - Modify rollup settings - build dist files