Repository: SFDO-Tooling/CumulusCI
Pull request #3739 (2024-01-31 06:47:42)

Fix `is_person_type` `AttributeError` in record type handling
Fix for [issue](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XIPZMSA5) related to your recent PR ([3702](https://github.com/SFDO-Tooling/CumulusCI/pull/3702)).

**Error Message:** `AttributeError: is_person_type`

**Issue Reason:**
During load, the tasks expects the column `is+person_type` to be present in the record type table `rt_mapping_table`. This column is present for sql files which do extract after the new release of CumulusCI (v3.84.0) but will not be present for existing sql files.

**Fix:**
Previously the `outerjoins_to_add` function of the `AddRecordTypesToQuery` class checks if the combination of `is_person_type` and `developer_name` is unique. Now, if the `rt_mapping_table` does not have the `is_person_type` table, the task ignores the condition to check for record types based on `is_person_type` and only checks for `developer_name` (as it was previous to this PR [3702](https://github.com/SFDO-Tooling/CumulusCI/pull/3702))

yippie: Fixes https://github.com/SFDO-Tooling/CumulusCI/issues/3738

Patch:
diff --git a/cumulusci/tasks/bulkdata/query_transformers.py b/cumulusci/tasks/bulkdata/query_transformers.py
index cbc50e389..61d42cd8c 100644
--- a/cumulusci/tasks/bulkdata/query_transformers.py
+++ b/cumulusci/tasks/bulkdata/query_transformers.py
@@ -128,6 +128,18 @@ class AddRecordTypesToQuery(LoadQueryExtender):
             rt_dest_table = self.metadata.tables[
                 self.mapping.get_destination_record_type_table()
             ]
+
+            # Check if 'is_person_type' column exists in rt_source_table.columns
+            is_person_type_column = getattr(
+                rt_source_table.columns, "is_person_type", None
+            )
+            # If it does not exist, set condition to True
+            is_person_type_condition = (
+                rt_dest_table.columns.is_person_type == is_person_type_column
+                if is_person_type_column is not None
+                else True
+            )
+
             return [
                 (
                     rt_source_table,
@@ -140,8 +152,7 @@ class AddRecordTypesToQuery(LoadQueryExtender):
                     and_(
                         rt_dest_table.columns.developer_name
                         == rt_source_table.columns.developer_name,
-                        rt_dest_table.columns.is_person_type
-                        == rt_source_table.columns.is_person_type,
+                        is_person_type_condition,
                     ),
                 ),
             ]


Test patch:
diff --git a/cumulusci/tasks/bulkdata/tests/recordtypes.sql b/cumulusci/tasks/bulkdata/tests/recordtypes.sql
index be1f7f370..5d3e08c9d 100644
--- a/cumulusci/tasks/bulkdata/tests/recordtypes.sql
+++ b/cumulusci/tasks/bulkdata/tests/recordtypes.sql
@@ -2,11 +2,10 @@ BEGIN TRANSACTION;
 CREATE TABLE "Account_rt_mapping" (
 	record_type_id VARCHAR(18) NOT NULL, 
 	developer_name VARCHAR(255),
-	is_person_type BOOLEAN,
 	PRIMARY KEY (record_type_id)
 );
-INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCMdIAM','Organization',0);
-INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCQqIAM','Subsidiary',0);
+INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCMdIAM','Organization');
+INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCQqIAM','Subsidiary');
 CREATE TABLE accounts (
 	sf_id VARCHAR(255) NOT NULL, 
 	"Name" VARCHAR(255), 
diff --git a/cumulusci/tasks/bulkdata/tests/recordtypes_2.sql b/cumulusci/tasks/bulkdata/tests/recordtypes_2.sql
index 1d23fc4a8..9415a439e 100644
--- a/cumulusci/tasks/bulkdata/tests/recordtypes_2.sql
+++ b/cumulusci/tasks/bulkdata/tests/recordtypes_2.sql
@@ -2,11 +2,10 @@ BEGIN TRANSACTION;
 CREATE TABLE Beta_rt_mapping (
 	record_type_id VARCHAR(18) NOT NULL, 
 	developer_name VARCHAR(255),
-	is_person_type BOOLEAN,
 	PRIMARY KEY (record_type_id)
 );
-INSERT INTO "Beta_rt_mapping" VALUES('012H40000003jCoIAI','recordtype2',0);
-INSERT INTO "Beta_rt_mapping" VALUES('012H40000003jCZIAY','recordtype1',0);
+INSERT INTO "Beta_rt_mapping" VALUES('012H40000003jCoIAI','recordtype2');
+INSERT INTO "Beta_rt_mapping" VALUES('012H40000003jCZIAY','recordtype1');
 CREATE TABLE Beta (
 	id INTEGER NOT NULL, 
 	"Name" VARCHAR(255), 
diff --git a/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.sql b/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.sql
new file mode 100644
index 000000000..be1f7f370
--- /dev/null
+++ b/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.sql
@@ -0,0 +1,33 @@
+BEGIN TRANSACTION;
+CREATE TABLE "Account_rt_mapping" (
+	record_type_id VARCHAR(18) NOT NULL, 
+	developer_name VARCHAR(255),
+	is_person_type BOOLEAN,
+	PRIMARY KEY (record_type_id)
+);
+INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCMdIAM','Organization',0);
+INSERT INTO "Account_rt_mapping" VALUES('012P0000000bCQqIAM','Subsidiary',0);
+CREATE TABLE accounts (
+	sf_id VARCHAR(255) NOT NULL, 
+	"Name" VARCHAR(255), 
+	"Description" VARCHAR(255), 
+	"Street" VARCHAR(255), 
+	"City" VARCHAR(255), 
+	"State" VARCHAR(255), 
+	"PostalCode" VARCHAR(255), 
+	"Country" VARCHAR(255), 
+	"Phone" VARCHAR(255), 
+	"Fax" VARCHAR(255), 
+	"Website" VARCHAR(255), 
+	"NumberOfEmployees" VARCHAR(255), 
+	"AccountNumber" VARCHAR(255), 
+	"Site" VARCHAR(255), 
+	"Type" VARCHAR(255), 
+	"RecordTypeId" VARCHAR(255), 
+	parent_id VARCHAR(255), 
+	PRIMARY KEY (sf_id)
+);
+INSERT INTO "accounts" VALUES('001P000001ZgnJYIAZ','','This is the parent account.','111 Main St.','Nowhereton','NE','11111','USA','5055551212','5055551213','www.acme.com','100','1','Local','Prospect','012P0000000bCMdIAM','');
+INSERT INTO "accounts" VALUES('001P000001ZgnJZIAZ','','','','','','','','','','','','','','','012P0000000bCQqIAM','001P000001ZgnJYIAZ');
+INSERT INTO "accounts" VALUES('001P000001ZgnJaIAJ','','','','','','','','','','','','','','','','');
+INSERT INTO "accounts" VALUES('001P000001ZgnTHIAZ','','','','','','','','','','','','','','','012P0000000bCQqIAM','001P000001ZgnJZIAZ');
diff --git a/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml b/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml
new file mode 100644
index 000000000..5f8ec1fc6
--- /dev/null
+++ b/cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml
@@ -0,0 +1,8 @@
+Insert Accounts:
+    api: bulk
+    sf_object: Account
+    table: accounts
+    fields:
+        Id: sf_id
+        Name: Name
+        RecordTypeId: RecordTypeId
diff --git a/cumulusci/tasks/bulkdata/tests/test_load.py b/cumulusci/tasks/bulkdata/tests/test_load.py
index a4293910d..3be11dbda 100644
--- a/cumulusci/tasks/bulkdata/tests/test_load.py
+++ b/cumulusci/tasks/bulkdata/tests/test_load.py
@@ -1931,6 +1931,18 @@ FROM accounts LEFT OUTER JOIN accounts_sf_ids AS accounts_sf_ids_1 ON accounts_s
             sql_path="cumulusci/tasks/bulkdata/tests/recordtypes.sql",
             mapping="cumulusci/tasks/bulkdata/tests/recordtypes.yml",
             mapping_step_name="Insert Accounts",
+            expected="""SELECT accounts.sf_id AS accounts_sf_id, accounts."Name" AS "accounts_Name", "Account_rt_target_mapping".record_type_id AS "Account_rt_target_mapping_record_type_id"
+                FROM accounts
+                LEFT OUTER JOIN "Account_rt_mapping" ON "Account_rt_mapping".record_type_id = accounts."RecordTypeId"
+                LEFT OUTER JOIN "Account_rt_target_mapping" ON "Account_rt_target_mapping".developer_name = "Account_rt_mapping".developer_name
+        """,
+        )
+
+    def test_query_db__record_type_mapping__with_ispersontype(self):
+        _validate_query_for_mapping_step(
+            sql_path="cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.sql",
+            mapping="cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml",
+            mapping_step_name="Insert Accounts",
             expected="""SELECT accounts.sf_id AS accounts_sf_id, accounts."Name" AS "accounts_Name", "Account_rt_target_mapping".record_type_id AS "Account_rt_target_mapping_record_type_id"
                 FROM accounts
                 LEFT OUTER JOIN "Account_rt_mapping" ON "Account_rt_mapping".record_type_id = accounts."RecordTypeId"
@@ -1948,7 +1960,6 @@ FROM accounts LEFT OUTER JOIN accounts_sf_ids AS accounts_sf_ids_1 ON accounts_s
             FROM "Beta"
             LEFT OUTER JOIN "Beta_rt_mapping" ON "Beta_rt_mapping".record_type_id = "Beta"."RecordType"
             LEFT OUTER JOIN "Account_rt_target_mapping" ON "Account_rt_target_mapping".developer_name = "Beta_rt_mapping".developer_name
-            AND "Account_rt_target_mapping".is_person_type = "Beta_rt_mapping".is_person_type
         """,
         )