Skip to content

Commit

Permalink
Merge pull request #22850 from ixiam/dev_Issue#3080
Browse files Browse the repository at this point in the history
Fixes issue with duplicate is_billing on inline address forms.
  • Loading branch information
colemanw authored Apr 7, 2022
2 parents af5c675 + ba14f1a commit 495e2f9
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions CRM/Core/BAO/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public static function add(&$params, $fixAddress = FALSE) {
CRM_Utils_Hook::pre($hook, 'Address', CRM_Utils_Array::value('id', $params), $params);

CRM_Core_BAO_Block::handlePrimary($params, get_class());
CRM_Core_BAO_Block::handleBilling($params, get_class());

// (prevent chaining 1 and 3) CRM-21214
if (isset($params['master_id']) && !CRM_Utils_System::isNull($params['master_id'])) {
Expand Down
50 changes: 50 additions & 0 deletions CRM/Core/BAO/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,56 @@ public static function handlePrimary(&$params, $class) {
}
}

/**
* Handling for is_billing.
* This process is a variation of handlePrimary above
* Find other entries with is_billing = 1 and reset them to 0
*
* @param array $params
* @param $class
*
* @throws API_Exception
*/
public static function handleBilling(&$params, $class) {
if (isset($params['id']) && CRM_Utils_System::isNull($params['is_billing'] ?? NULL)) {
// if id is set & is_billing isn't we can assume no change)
return;
}
$table = CRM_Core_DAO_AllCoreTables::getTableForClass($class);
if (!$table) {
throw new API_Exception("Failed to locate table for class [$class]");
}

// contact_id in params might be empty or the string 'null' so cast to integer
$contactId = (int) ($params['contact_id'] ?? 0);
// If id is set & we haven't been passed a contact_id, retrieve it
if (!empty($params['id']) && !isset($params['contact_id'])) {
$entity = new $class();
$entity->id = $params['id'];
$entity->find(TRUE);
$contactId = $entity->contact_id;
}
// If entity is not associated with contact, concept of is_billing not relevant
if (!$contactId) {
return;
}

// if params is_billing then set all others to not be billing & exit out
// if is_billing = 1
if (!empty($params['is_billing'])) {
$sql = "UPDATE $table SET is_billing = 0 WHERE contact_id = %1";
$sqlParams = [1 => [$contactId, 'Integer']];
// we don't want to create unnecessary entries in the log_ tables so exclude the one we are working on
if (!empty($params['id'])) {
$sql .= " AND id <> %2";
$sqlParams[2] = [$params['id'], 'Integer'];
}
CRM_Core_DAO::executeQuery($sql, $sqlParams);
return;
}

}

/**
* Sort location array so primary element is first.
*
Expand Down
129 changes: 129 additions & 0 deletions tests/phpunit/CRM/Core/BAO/AddressTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,135 @@ public function testAdd() {
$this->contactDelete($contactId);
}

/**
* Add 2 billing addresses using the `CRM_Core_BAO_Address::legacyCreate` mode
* Only the first array will remain as primary/billing due to the nature of how `legacyCreate` works
*/
public function testMultipleBillingAddressesLegacymode() {
$contactId = $this->individualCreate();

$entityBlock = ['contact_id' => $contactId];
$params = [];
$params['contact_id'] = $contactId;
$params['address']['1'] = [
'street_address' => 'E 906N Pine Pl W',
'supplemental_address_1' => 'Editorial Dept',
'supplemental_address_2' => '',
'supplemental_address_3' => '',
'city' => 'El Paso',
'postal_code' => '88575',
'postal_code_suffix' => '',
'state_province_id' => '1001',
'country_id' => '1228',
'geo_code_1' => '31.694842',
'geo_code_2' => '-106.29998',
'location_type_id' => '1',
'is_primary' => '1',
'is_billing' => '1',
'contact_id' => $contactId,
];
$params['address']['2'] = [
'street_address' => '120 Terminal Road',
'supplemental_address_1' => 'A-wing:3037',
'supplemental_address_2' => 'Bandra',
'supplemental_address_3' => 'Somewhere',
'city' => 'Athens',
'postal_code' => '01903',
'state_province_id' => '1000',
'country_id' => '1228',
'geo_code_1' => '18.219023',
'geo_code_2' => '-105.00973',
'location_type_id' => '1',
'is_primary' => '1',
'is_billing' => '1',
'contact_id' => $contactId,
];

CRM_Core_BAO_Address::legacyCreate($params, $fixAddress = TRUE);

$address = CRM_Core_BAO_Address::getValues($entityBlock);

$this->assertEquals($address[1]['contact_id'], $contactId);
$this->assertEquals($address[1]['is_primary'], 1, 'In line ' . __LINE__);
$this->assertEquals($address[1]['is_billing'], 1, 'In line ' . __LINE__);

$this->assertEquals($address[2]['contact_id'], $contactId);
$this->assertEquals($address[2]['is_primary'], 0, 'In line ' . __LINE__);
$this->assertEquals($address[2]['is_billing'], 0, 'In line ' . __LINE__);

$this->contactDelete($contactId);
}

/**
* Add() 2 billing addresses, only the last one should be set as billing
* Using the `CRM_Core_BAO_Address::add` mode
*
*/
public function testMultipleBillingAddressesCurrentmode() {
$contactId = $this->individualCreate();

$entityBlock = ['contact_id' => $contactId];
$params = [];
$params['contact_id'] = $contactId;
$params['address']['1'] = [
'street_address' => 'E 906N Pine Pl W',
'supplemental_address_1' => 'Editorial Dept',
'supplemental_address_2' => '',
'supplemental_address_3' => '',
'city' => 'El Paso',
'postal_code' => '88575',
'postal_code_suffix' => '',
'state_province_id' => '1001',
'country_id' => '1228',
'geo_code_1' => '31.694842',
'geo_code_2' => '-106.29998',
'location_type_id' => '1',
'is_primary' => '1',
'is_billing' => '1',
'contact_id' => $contactId,
];

CRM_Core_BAO_Address::add($params['address']['1'], $fixAddress = TRUE);

// Add address 2
$params['address']['2'] = [
'street_address' => '120 Terminal Road',
'supplemental_address_1' => 'A-wing:3037',
'supplemental_address_2' => 'Bandra',
'supplemental_address_3' => 'Somewhere',
'city' => 'Athens',
'postal_code' => '01903',
'state_province_id' => '1000',
'country_id' => '1228',
'geo_code_1' => '18.219023',
'geo_code_2' => '-105.00973',
'location_type_id' => '1',
'is_primary' => '1',
'is_billing' => '1',
'contact_id' => $contactId,
];

CRM_Core_BAO_Address::add($params['address']['2'], $fixAddress = TRUE);

$addresses = CRM_Core_BAO_Address::getValues($entityBlock);

// Sort the multidimensional array by id
usort($addresses, function($a, $b) {
return $a['id'] <=> $b['id'];
});

// Validate both results, remember that the keys have been reset to 0 after usort
$this->assertEquals($addresses[0]['contact_id'], $contactId);
$this->assertEquals($addresses[0]['is_primary'], 0, 'In line ' . __LINE__);
$this->assertEquals($addresses[0]['is_billing'], 0, 'In line ' . __LINE__);

$this->assertEquals($addresses[1]['contact_id'], $contactId);
$this->assertEquals($addresses[1]['is_primary'], 1, 'In line ' . __LINE__);
$this->assertEquals($addresses[1]['is_billing'], 1, 'In line ' . __LINE__);

$this->contactDelete($contactId);
}

/**
* AllAddress() method ( )
*/
Expand Down

0 comments on commit 495e2f9

Please sign in to comment.