@@ -407,19 +407,9 @@ Appboy.prototype.orderCompleted = function(track) {
407407 del ( purchaseProperties , 'currency' ) ;
408408
409409 // we have to make a separate call to appboy for each product
410- each ( function ( product ) {
411- var track = new Track ( { properties : product } ) ;
412- var productId = track . productId ( ) ;
413- var price = track . price ( ) ;
414- var quantity = track . quantity ( ) ;
415- window . appboy . logPurchase (
416- productId ,
417- price ,
418- currencyCode ,
419- quantity ,
420- purchaseProperties
421- ) ;
422- } , products ) ;
410+ for ( var i = 0 ; i < products . length ; i ++ ) {
411+ logProduct ( products [ i ] , currencyCode , purchaseProperties ) ;
412+ }
423413} ;
424414
425415/**
@@ -449,3 +439,92 @@ function getGender(gender) {
449439 if ( otherGenders . indexOf ( gender . toLowerCase ( ) ) > - 1 )
450440 return window . appboy . ab . User . Genders . OTHER ;
451441}
442+
443+ /**
444+ * Logs a Purchase containing a product as described in Braze's documentation:
445+ * https://js.appboycdn.com/web-sdk/latest/doc/module-appboy.html#.logPurchase
446+ *
447+ * @param {Object } product Product from the Order Completed call
448+ * @param {String } currencyCode Currency code
449+ * @param {Object } extraProperties Root properties from the track call
450+ */
451+ function logProduct ( product , currencyCode , extraProperties ) {
452+ var track = new Track ( { properties : product } ) ;
453+ var productId = track . productId ( ) ;
454+ var price = track . price ( ) ;
455+ var quantity = track . quantity ( ) ;
456+ var productProperties = track . properties ( ) ;
457+ var properties = { } ;
458+
459+ del ( productProperties , 'productId' ) ;
460+ del ( productProperties , 'price' ) ;
461+ del ( productProperties , 'quantity' ) ;
462+
463+ for ( var productProperty in productProperties ) {
464+ if ( ! productProperties . hasOwnProperty ( productProperty ) ) {
465+ continue ;
466+ }
467+
468+ var value = productProperties [ productProperty ] ;
469+ if ( isValidProperty ( productProperty , value ) ) {
470+ properties [ productProperty ] = value ;
471+ }
472+ }
473+
474+ for ( var property in extraProperties ) {
475+ if ( ! extraProperties . hasOwnProperty ( property ) ) {
476+ continue ;
477+ }
478+
479+ var val = extraProperties [ property ] ;
480+ if (
481+ ! productProperties . hasOwnProperty ( property ) &&
482+ isValidProperty ( property , val )
483+ ) {
484+ properties [ property ] = val ;
485+ }
486+ }
487+
488+ window . appboy . logPurchase (
489+ productId ,
490+ price ,
491+ currencyCode ,
492+ quantity ,
493+ properties
494+ ) ;
495+ }
496+
497+ /**
498+ * Validates a name and value of a property, following Braze's restrictions:
499+ *
500+ * Names are limited to 255 characters in length, cannot begin with a $, and
501+ * can only contain alphanumeric characters and punctuation. Values can be
502+ * numeric, boolean, Date objects, or strings 255 characters or shorter.
503+ *
504+ * @param {String } name Name of the property.
505+ * @param {* } value Value of the property.
506+ *
507+ * @return {boolean } <code>true</code> if the name and value are valid, <code>false</code> otherwise.
508+ */
509+ function isValidProperty ( name , value ) {
510+ if ( name . length > 255 || name . startsWith ( '$' ) ) {
511+ return false ;
512+ }
513+
514+ if ( typeof value === 'number' || typeof value === 'boolean' ) {
515+ return true ;
516+ }
517+
518+ if ( typeof value === 'object' && value instanceof Date ) {
519+ return true ;
520+ }
521+
522+ if (
523+ ( typeof value === 'string' || value instanceof String ) &&
524+ value . length <= 255
525+ ) {
526+ return true ;
527+ }
528+
529+ return false ;
530+ }
0 commit comments