{
  "apiVersion": 63,
  "status": "Active",
  "label": "HubSpot Deal Merge Reconcile",
  "description": "Reconciles HubSpot deal merge aliases into one canonical NexusCRM Opportunity by preserving one survivor, deleting merged-away aliases, and rekeying the survivor to the canonical HubSpot id.",
  "runAtomically": true,
  "start": {
    "locationX": 40,
    "locationY": 0,
    "connector": {
      "targetReference": "FindOpportunityByCanonicalHubSpotId"
    }
  },
  "variables": [
    {
      "name": "payload",
      "dataType": "Any",
      "isInput": true
    },
    {
      "name": "record",
      "dataType": "Any",
      "isInput": true
    },
    {
      "name": "sourceID",
      "dataType": "String",
      "isInput": true
    },
    {
      "name": "survivorOpportunityId",
      "dataType": "String"
    },
    {
      "name": "currentMergedHubSpotId",
      "dataType": "String"
    }
  ],
  "recordLookups": [
    {
      "name": "FindOpportunityByCanonicalHubSpotId",
      "label": "Find Opportunity already bound to the canonical HubSpot id",
      "locationX": 40,
      "locationY": 120,
      "object": "Opportunity",
      "filterLogic": "and",
      "filters": [
        {
          "field": "HubSpot_Id__c",
          "operator": "EqualTo",
          "value": {
            "elementReference": "effectiveCanonicalHubSpotId"
          }
        }
      ],
      "outputReference": "$canonicalOpportunity",
      "getFirstRecordOnly": true,
      "connector": {
        "targetReference": "ChooseCanonicalOpportunity"
      }
    },
    {
      "name": "FindOpportunityByPrimaryHubSpotId",
      "label": "Find Opportunity still bound to the merge-winner legacy HubSpot id",
      "locationX": 320,
      "locationY": 120,
      "object": "Opportunity",
      "filterLogic": "and",
      "filters": [
        {
          "field": "HubSpot_Id__c",
          "operator": "EqualTo",
          "value": {
            "elementReference": "effectivePrimaryHubSpotId"
          }
        }
      ],
      "outputReference": "$primaryOpportunity",
      "getFirstRecordOnly": true,
      "connector": {
        "targetReference": "HandlePrimaryOpportunity"
      }
    },
    {
      "name": "FindMergedOpportunityByHubSpotId",
      "label": "Find Opportunity by merged-away HubSpot id",
      "locationX": 600,
      "locationY": 360,
      "object": "Opportunity",
      "filterLogic": "and",
      "filters": [
        {
          "field": "HubSpot_Id__c",
          "operator": "EqualTo",
          "value": {
            "elementReference": "currentMergedHubSpotId"
          }
        }
      ],
      "outputReference": "$mergedOpportunity",
      "getFirstRecordOnly": true,
      "connector": {
        "targetReference": "HandleMergedOpportunity"
      }
    }
  ],
  "decisions": [
    {
      "name": "ChooseCanonicalOpportunity",
      "label": "Preserve an existing canonical Opportunity when one is already re-keyed",
      "locationX": 180,
      "locationY": 240,
      "rules": [
        {
          "name": "CanonicalOpportunityFound",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$canonicalOpportunity.Id",
              "operator": "IsNotBlank"
            }
          ],
          "connector": {
            "targetReference": "UseCanonicalOpportunityAsSurvivor"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "FindOpportunityByPrimaryHubSpotId"
      }
    },
    {
      "name": "HandlePrimaryOpportunity",
      "label": "Keep, delete, or skip the primary legacy deal mapping",
      "locationX": 460,
      "locationY": 240,
      "rules": [
        {
          "name": "PrimaryOpportunityMissing",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$primaryOpportunity.Id",
              "operator": "IsBlank"
            }
          ],
          "connector": {
            "targetReference": "LoopMergedObjectIds"
          }
        },
        {
          "name": "PrimaryOpportunityBecomesSurvivor",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$primaryOpportunity.Id",
              "operator": "IsNotBlank"
            },
            {
              "leftValueReference": "survivorOpportunityId",
              "operator": "IsBlank"
            }
          ],
          "connector": {
            "targetReference": "UsePrimaryOpportunityAsSurvivor"
          }
        },
        {
          "name": "PrimaryOpportunityAlreadySurvivor",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$primaryOpportunity.Id",
              "operator": "IsNotBlank"
            },
            {
              "leftValueReference": "$primaryOpportunity.Id",
              "operator": "EqualTo",
              "rightValue": {
                "elementReference": "survivorOpportunityId"
              }
            }
          ],
          "connector": {
            "targetReference": "LoopMergedObjectIds"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "DeletePrimaryOpportunityAlias"
      }
    },
    {
      "name": "HandleMergedOpportunity",
      "label": "Delete merged-away deal aliases after selecting a survivor",
      "locationX": 760,
      "locationY": 480,
      "rules": [
        {
          "name": "MergedOpportunityMissing",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$mergedOpportunity.Id",
              "operator": "IsBlank"
            }
          ],
          "connector": {
            "targetReference": "LoopMergedObjectIds"
          }
        },
        {
          "name": "MergedOpportunityBecomesSurvivor",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$mergedOpportunity.Id",
              "operator": "IsNotBlank"
            },
            {
              "leftValueReference": "survivorOpportunityId",
              "operator": "IsBlank"
            }
          ],
          "connector": {
            "targetReference": "UseMergedOpportunityAsSurvivor"
          }
        },
        {
          "name": "MergedOpportunityAlreadySurvivor",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$mergedOpportunity.Id",
              "operator": "IsNotBlank"
            },
            {
              "leftValueReference": "$mergedOpportunity.Id",
              "operator": "EqualTo",
              "rightValue": {
                "elementReference": "survivorOpportunityId"
              }
            }
          ],
          "connector": {
            "targetReference": "LoopMergedObjectIds"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "DeleteMergedOpportunityAlias"
      }
    },
    {
      "name": "FinalizeMerge",
      "label": "Retry until a local survivor exists; otherwise re-key the survivor to the canonical id",
      "locationX": 760,
      "locationY": 720,
      "rules": [
        {
          "name": "NoLocalOpportunityYet",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "survivorOpportunityId",
              "operator": "IsBlank"
            }
          ],
          "connector": {
            "targetReference": "RetryUntilLocalOpportunityLands"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "RekeySurvivorOpportunityToCanonicalId"
      }
    }
  ],
  "formulas": [
    {
      "name": "effectiveCanonicalHubSpotId",
      "dataType": "String",
      "expression": "TEXT(BLANKVALUE(payload.newObjectId, BLANKVALUE(payload.primaryObjectId, sourceID)))"
    },
    {
      "name": "effectivePrimaryHubSpotId",
      "dataType": "String",
      "expression": "TEXT(BLANKVALUE(payload.primaryObjectId, sourceID))"
    }
  ],
  "assignments": [
    {
      "name": "UseCanonicalOpportunityAsSurvivor",
      "label": "Preserve canonical Opportunity",
      "locationX": 180,
      "locationY": 360,
      "assignmentItems": [
        {
          "assignToReference": "survivorOpportunityId",
          "operator": "Assign",
          "value": {
            "elementReference": "$canonicalOpportunity.Id"
          }
        }
      ],
      "connector": {
        "targetReference": "FindOpportunityByPrimaryHubSpotId"
      }
    },
    {
      "name": "UsePrimaryOpportunityAsSurvivor",
      "label": "Preserve primary legacy Opportunity",
      "locationX": 460,
      "locationY": 360,
      "assignmentItems": [
        {
          "assignToReference": "survivorOpportunityId",
          "operator": "Assign",
          "value": {
            "elementReference": "$primaryOpportunity.Id"
          }
        }
      ],
      "connector": {
        "targetReference": "LoopMergedObjectIds"
      }
    },
    {
      "name": "UseMergedOpportunityAsSurvivor",
      "label": "Preserve first merged-away Opportunity when nothing else exists locally",
      "locationX": 760,
      "locationY": 600,
      "assignmentItems": [
        {
          "assignToReference": "survivorOpportunityId",
          "operator": "Assign",
          "value": {
            "elementReference": "$mergedOpportunity.Id"
          }
        }
      ],
      "connector": {
        "targetReference": "LoopMergedObjectIds"
      }
    }
  ],
  "loops": [
    {
      "name": "LoopMergedObjectIds",
      "label": "Loop merged-away HubSpot ids",
      "locationX": 600,
      "locationY": 240,
      "collectionReference": "payload.mergedObjectIds",
      "assignNextValueToReference": "currentMergedHubSpotId",
      "nextValueConnector": {
        "targetReference": "FindMergedOpportunityByHubSpotId"
      },
      "noMoreValuesConnector": {
        "targetReference": "FinalizeMerge"
      }
    }
  ],
  "recordUpdates": [
    {
      "name": "RekeySurvivorOpportunityToCanonicalId",
      "label": "Re-key survivor Opportunity to the canonical HubSpot id",
      "locationX": 760,
      "locationY": 840,
      "object": "Opportunity",
      "filterLogic": "and",
      "filters": [
        {
          "field": "Id",
          "operator": "EqualTo",
          "value": {
            "elementReference": "survivorOpportunityId"
          }
        }
      ],
      "inputAssignments": [
        {
          "field": "HubSpot_Id__c",
          "value": {
            "elementReference": "effectiveCanonicalHubSpotId"
          }
        }
      ]
    }
  ],
  "recordDeletes": [
    {
      "name": "DeletePrimaryOpportunityAlias",
      "label": "Delete primary legacy Opportunity alias after merge",
      "locationX": 460,
      "locationY": 360,
      "object": "Opportunity",
      "inputReference": "$primaryOpportunity",
      "connector": {
        "targetReference": "LoopMergedObjectIds"
      }
    },
    {
      "name": "DeleteMergedOpportunityAlias",
      "label": "Delete merged-away Opportunity alias after merge",
      "locationX": 940,
      "locationY": 600,
      "object": "Opportunity",
      "inputReference": "$mergedOpportunity",
      "connector": {
        "targetReference": "LoopMergedObjectIds"
      }
    }
  ],
  "actionCalls": [
    {
      "name": "RetryUntilLocalOpportunityLands",
      "label": "Retry until a local Opportunity exists for the merged HubSpot deal cluster",
      "locationX": 940,
      "locationY": 720,
      "actionName": "setRetriable",
      "actionType": "setRetriable",
      "inputParameters": [
        {
          "name": "reason",
          "value": {
            "stringValue": "deal merge arrived before any local Opportunity in the merged HubSpot id cluster existed; retrying until a survivor lands locally"
          }
        }
      ]
    }
  ]
}
