Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
[
  "IndividualId1",
  "IndividualId2"
]

Process:

EXPIRIENCE API:

  1. Required header “validator“ with value: rbesb

  2. Request Epsilon for a token (It is needed to be moved to middleware Mulesoft)

  3. For each individual id

    1. Get from CDP - Golden Individual - saved under “profile”

    2. Get from CDP - Contacts - export from its contact and save under “emails”, “phones”

    3. Map enrollments - if there are any children, gather all enrollments and save them under “enrollChildren”

    4. Sync process:

      1. Check Contact

        1. Query Object: Account with several conditions (SFSC)

          Code Block
          var boc = 
          	if 		(vars.profile.BrandOrgCode == 'MJNTHA') "TH_Household"
              else if (vars.profile.BrandOrgCode == 'MJNIDN') "ID_Household"
              else if (vars.profile.BrandOrgCode == 'MJNMYS') "MY_Household"
              else if (vars.profile.BrandOrgCode == 'MJNSGP') "MY_Household"
              else if (vars.profile.BrandOrgCode == 'MJNBRN') "MY_Household"
              else if (vars.profile.BrandOrgCode == 'MJNVNM') "VN_Household"
          	else null
          Code Block
          SELECT Id, OwnerId, Inactive__c FROM Account WHERE IsDeleted=false AND RecordMarket__c= ++ boc ++ AND ++ QUERIES EMAILS OR PHONES (Depending if values exists)

          It is saved later in a variable: “contactQueryResponse”

        2. If contacts do not exist = logger. If contacts exist then:

          1. Filter contacts if Inactive__c == “false”. If false then = logger, if true then:

            1. Load data from vars to payload

            2. Query data for parents (SFSC):

              Code Block
              SELECT Id, RecordMarket__c, Inactive__c FROM Contact WHERE Is_Primary_Contact__c=true AND IsDeleted=false AND AccountId='" + vars.'account_id' + "' 

              Data is saved into a variable: “contactQueryResponse”

            3. If parents exist: for each parent there are transformations made. If parents do not exist it just logs proper information.

        3. Mapping Household

          1. Prepare new_account variable: (Variables inside DW)

            Code Block
            fullname: profileFirstName ++ profileMiddleName ++ profileLastName
            Coutry_TXT mapping: {
            	"THA": "Thailand",
            	"VNM": "Vietnam",
            	"SGP": "Singapore",
            	"MYS": "Malaysia",
            	"BRN": "Brunei",
            	"IDN": "Indonesia",
            	"PHL": "Philippines",
            	"USA": "USA"
            }

            Mapping:

            Code Block
            First_Name__c: profileFirstName
            Last_Name__c: profileLastName
            Middle_Name__c: profileMiddleName
            Name: fullName
            Id: def_data.account_id
            RecordTypeId: profileBrandOrgCode
            Address_Line_1__c: profileAddressLine1
            Address_Line_2__c: profileAddressLine2
            Address_Remarks__c: profileJsonExternalData.AddressRemarks
            Mobile_Phone__c: profileMobilePhone
            Home_phone__c: profileHomePhone
            Home_phone__c: profileHomePhone splitBy("x"))[0]
            Home_Phone_Extension__c: (profileHomePhone splitBy("x"))[1]))
            Other_Phone_1__c: profileWorkPhone
            Other_Phone_1__c: profileOtherPhone
            Account_Email__c: profileEmailAddress
            Member_Country__c: COUNTRY_TXT[vars.profileCountryCode]

            If values are not blank then it is appended to the payload. In another case, the whole key is deleted from the request. All data are in vars. (It can cause memory issues later if data is larger).

          2. Prepare cityData variable:

            Code Block
            District__c: profileAddressLine3 -> with additonal logic of splitting data
            Region__c: profileAddressLine3 -> with additional logic of splitting data
            Name: profileCity
            State_Province__c: profileState
            Zip_Code__c: profilePostalCode
            Country__c: COUNTRY_TXT[vars.profileCountryCode] //This element should not work there is no COUNTRY_TXT in dataweave
          3. If Profile ID SF is equal to profile ID from CDP

            1. For each: JsonExternalData

            2. If payload profile id equals correctly and mom status is not empty and mom status is equal to first time then

            3. Mom_status equals: "1st Time"

            4. In other case logger

          4. if Profile ID SF is NOT equal to profile ID from CDP

            1. If ProfileSubscriptions and JsonExternalData are not empty for each profile subscription do:

            2. If optStatus is true and channelCode contains channelCode(??? payload.OptStatuss == true and !(payload.ChannelCode contains payload.ChannelCode) ???) prepare parse_subs which is currently empty object (question) in other case it also empty object (question)

              Code Block
              %dw 2.0
              output application/json
              var s_optstatus = payload.OptStatus
              var s_channel = payload.ChannelCode
              var upsert_channel = false
              ---
              {}
              	//		subscribes[s_channel] = subscriptions[s];
              	//		upsert_channel = true; 
          5. Prepare subscriptions in payload

            Code Block
            var most_recent = (vars.enrollChildren orderBy ((item, index) -> -item.enrollDate as DateTime as Number {unit: "milliseconds"}))[0]

            Adding to new_account object (and saving to payload)

            Code Block
            Mailing_Opt_Out__c: true (hardcoded)
            Account_Email_Opt_out__c: true (hardcoded)
            Do_not_SMS_Mobile__c: true (hardcoded)
            Do_Not_Call_Mobile__c: true (hardcoded)
            Do_Not_Call_Home_Phone__c: true (hardcoded)
            Do_Not_Call_Other_Phone_1__c: true (hardcoded)
            Enfa_Status__c: most_recent.'Enfa_Status__c' <- added if most_recent.'Enfa_Status__c' == "Active"
            Enfa_Date_Joined__c: most_recent.enrollDate <- added if most_recent.'Enfa_Status__c' == "Active"
            Sustagen_Status__c: most_recent.'Enfa_Status__c'
            Sustagen_Date_Joined__c: most_recent.enrollDate
            Mom_Status__c: vars.Mom_Status <- added if !isBlank(vars.Mom_Status)
        4. The query is being prepared for the city - Long logic - Object City__c

        5. Query City (SF)

          1. Does city query have at least 3 query conditions? if true then

            1. Query City

            2. if value is not empty it is appending additional data to vars with account

            3. In other cases it logs information

          2. If false then

            1. Creates/Updates a household data into SF (Object Account

        6. CDP - SFDC Sync - Upsert contact If parentIdQueryResponse is empty this one is skipped in other cases:

          1. Create def_data variable:

            Code Block
            if (vars.createContactParentResponse !=null)
            {
            	'contact_id': vars.createContactParentResponse.id,
            	'account_id': vars.def_data.account_id
            }
            else if (vars.updateContactParentResponse !=null)
            {
            	'contact_id': vars.updateContactParentResponse.id,
            	'account_id': vars.def_data.account_id
            }
            else "Parent Response not chosen"
          2. If a Child should be created - Sync children - (MAPPING ONLY)

            1. Mapping - Most data is from payload. Need to be validated when running

              Code Block
              var CHILD = {
              	'MJNTHA': "0129000000168Ip",
              	'MJNIDN': '0129000000168Ij',
              	'MJNBRN': '0129000000168Il',
              	'MJNMYS': '0129000000168Il',
              	'MJNSGP': '0129000000168Il',
              	'MJNPHL': '',
              	'MJNVNM': '0129000000168Ir'
              }
              ---
              Family_Relationship__c: CaregiverTypeCode
              FirstName: ChildFirstName
              LastName: ChildLastName
              Middle_Name__c: ChildMiddleName
              RecordTypeId: CHILD[vars.profile.BrandOrgCode]
              AccountId: 'def_data'.'acc_id'
              Gender__c: GenderCode
              Birthdate: BirthDueDate
              Last_Consumption_Brand__c: PreferredBrand
              prod_id: PreferredProduct 
              Feeding_Method__c: PreferredProduct
              Born_Hospital__c: HospitalId
              Baby_Hospital__c: HospitalId
              Attending_Doctor__c: HcpProfileId
          3. In this process, there are multiple for each using extra_data and even extra_data.Children (question) (Why not payload.Children)

        7. Big choice which contains

          1. !isEmpty(vars.new_children) and vars.create_child == true - only logger (Missing implementation?)

          2. isEmpty(vars.new_children) and vars.create_child == true - Only logger - no children to upsert

          3. !isBlank(vars.def_data.contact_id) - (question) Contains logger that it should be update updated but creates Contact Parent

          4. default - Creates Contact Parent (question) It is double the same logic

        8. Contains Logger TODO - What is missing (question) Syncing children? enrollments?

  4. End of the process

Python process: (I took all-singapore.py file)

  1. Checks files inside of SFTP

  2. Downloads them (PGP)

  3. Decrypt them and save them somewhere

  4. Runs process-singapore.py

Inside of process-singapore.py

  1. Basic variables are being saved like base URL, tokens, etc.

  2. Starts logging into file

  3. Calling function processFile

    1. Opening file and reading IndividualIDs and saving it into the IndividualIDS list

      1. Depending on the situation in data inside of the file it can skip if there is a blank row, if there are not enough fields or if there is an empty Individual ID

    2. Creating a token towards CDP

    3. Getting a golden record from CDP (function: cdpGetIndivGolden)

      1. Headers Authorization, Brand-Org-Code, Accept-Language.

      2. A request is made for '/profiles/individuals/golden/' + individualID

        1. It checks if in response there is correct status and if so then returns json data to previous method.

    4. Saves response in json file

    5. Getting a list of email addresses for processing record (cdpGetContacts) - Using goldenRecord (it is really emails and phone numbers)

      1. For each golden record - key: JsonExternalData and inside of it key: Profiles

        1. Gets profile ids

        2. Builds a headers Authorization, Brand-Org-Code, Account-Source, Source-Account-Number, Accept-Language

        3. Requests towards: '/profiles/' + profile['ProfileId']

        4. If everything is correct processes phones (adding it to list) and the same for emails

        5. If there is non values it provides null values.

          Code Block
          if len(emailLst) == 0 and len(phoneLst) != 0:
                  return 'null', ";".join(phoneLst)
              if len(emailLst) != 0 and len(phoneLst) == 0:
                  return ";".join(emailLst), 'null'
              if len(emailLst) != 0 and len(phoneLst) != 0:
                  return ";".join(emailLst), ";".join(phoneLst)
    6. Every time there is no match or any error it creates logs.

    7. if there is no profiles it logs it as an error

    8. Creates profile in SFDC (createInSFDC) (Parameters profiled, golden record, brand org code (MJNSGP), email list, mobile list, sf_token, sf_instance)

      1. Creates headers

      2. Build logic about mapping (cdpGetEnrollments)

        1. For each profile in golden record → json external data → profiles. For each json external data in profile. For each children in json external data. In each child enrollments in children.

          Code Block
          for profile in goldenRecord['JsonExternalData']['Profiles']:        
                  for jed in profile['JsonExternalData']:
                      for child in jed['Children']:
                          for cenroll in child['ChildEnrollments']:
          1. Puts data into variable

          2. Gathers enrollment subscription id and child ID

          3. Gathers data for birthDate of the child and child

          4. If a child is not in the parent variable (that we add values) we append it. In else, we check if the enrollment date of the current is newer than that saved if so we swap them:

            Code Block
            if keyenroll not in enrolled_child:
                                    enrolled_child[keyenroll] = enrollment
                                else:
                                    if enrollment['EnrollDate'] > enrolled_child[keyenroll]['EnrollDate']:
                                        enrolled_child[keyenroll] = enrollment
          5. After process it being returned back

      3. Builds body which is:

        Code Block
         {
                'cid' : cid,
                'emlid' : emlid,
                'mobileid' : mobileid,
                'profile_id' : profileID,
                'oid' : oid,
                #'dev' : dev,
                'sf_token' : sf_token,
                'sf_instance' : sf_instance,
                'op' : 'check_contact',
                'profile' : json.dumps(goldenRecord),
                'profile_mkt' : brandOrgCode,
                'boc' : brandOrgCode,
                'enrollment': json.dumps(enrollment),
                'all' : 'true',
                'tag' : 'oblist-add'
            }
      4. Creates request towards https://mjn-cdp-pop.navomi.com/ajax/sync_profile (This hits the JAVASCRIPT (https://bitbucket.org/rbdigital/navomi-pop-up-sync-profile/src/master/routes/ajax.js - You can find under /ajax/sync_profile)

        1. JAVASCRIPT /ajax/sync_profile

          1. Sets header content-type as application/json

          2. Creates a new current date

          3. Puts data into object API.setSession in which puts everything to an object.

          4. Runs salesforce lib with function sync_profile and in there is whole logic with additional checks and mappings (corresponding to mapping for this process is “check_contact”)

          5. In salesforce lib, there is an op check if is equal to this value and then process values query SF for Account details for emails and phones. If emails and phones exist then a query is made and a function is called: check_contact_cb. If there is no data then depending on condition it creates household.

            1. Inside function check_contact_cb

            2. First is the condition that checks if the result has a size > 0 (if it is 0 it creates a household (question)) LOWER YOU CAN FIND HOUSEHOLD OPERATION

            3. Next, it checks if accounts are not inactive and saves them into variable active_account

            4. If an active account exists then (if not there is another condition that creates a household or does nothing)

            5. JS makes a request again to SF to check if there are any Contact for this account (This seems that is searching for parent contact) (question) Why they did do this way they could gather all data by Python and then send it to JS (or simply only use Python) (question)

            6. If such parent contact exists it creates household

      5. Contains handler of error.

      6. That ends everything

ABOUT CREATE HOUSEHOLD (_create_household)

  1. In here we have mapping all details from body and additional queries to SF and syncing such object.

    1. It:

      Code Block
      Sets ID if exists, and puts flag for update as true
      First_Name__c = FirstName
      Middle_Name__c = MiddleName
      Last_Name__c = LastName
      Name = FirstName + MiddleName + LastName
      Address_Line_1__c = AddressLine1
      Address_Line_2__c = AddressLine2
      Address_Remarks__c = JsonExternalData.AddressRemarks
      Makes query for City_data for reqion, district if address line 3 exists (?)
      Then again does something with query according to field AddressLine5 (?)
      
      Mobile_Phone__c = MobilePhone
      Home_phone__c = HomePhone.split('x') [0]
      Home_Phone_Extension__c = HomePhone.split('x') [1]
      Other_Phone_1__c = WorkPhone
      Other_Phone_2__c = OtherPhone
      Account_Email__c = EmailAddress
      Member_Country__c = COUNTRY_TXT[profile.CountryCode]
      
      There are olso parse subscription
      After city query there is also appended: 
      SA_City__c = ret.records[0].Id
      Enfa_Status_Changed_NAV__c = false
      Sustagen_Status_Changed_NAV__c = false

And then sends it to SFSC.