Skip to content

Commit

Permalink
[REF] Standardise validation of mapped fields in imports
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed Sep 1, 2022
1 parent 957773e commit bfabad9
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 112 deletions.
2 changes: 1 addition & 1 deletion CRM/Activity/Import/Parser/Activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public function getMappedRow(array $values): array {
* @return array
*/
protected function getRequiredFields(): array {
return [['activity_type_id' => ts('Activity Type'), 'activity_date_time' => ts('Activity Date')]];
return [['activity_type_id', 'activity_date_time']];
}

/**
Expand Down
60 changes: 12 additions & 48 deletions CRM/Contribute/Import/Form/MapField.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,16 @@ class CRM_Contribute_Import_Form_MapField extends CRM_Import_Form_MapField {
protected static function checkRequiredFields($self, string $contactORContributionId, array $importKeys, array $errors, int $weightSum, $threshold, string $fieldMessage): array {
// FIXME: should use the schema titles, not redeclare them
$requiredFields = [
$contactORContributionId == 'contribution_id' ? 'contribution_id' : 'contribution_contact_id' => $contactORContributionId == 'contribution_id' ? ts('Contribution ID') : ts('Contact ID'),
'total_amount' => ts('Total Amount'),
'financial_type_id' => ts('Financial Type'),
'contribution_contact_id' => ts('Contact ID'),
];

foreach ($requiredFields as $field => $title) {
if (!in_array($field, $importKeys)) {
if (empty($errors['_qf_default'])) {
$errors['_qf_default'] = '';
}
if ($field == $contactORContributionId) {
if (!($weightSum >= $threshold || in_array('external_identifier', $importKeys)) &&
!$self->isUpdateExisting()
if ($field == 'contribution_contact_id') {
if (!($weightSum >= $threshold || in_array('external_identifier', $importKeys))
) {
$errors['_qf_default'] .= ts('Missing required contact matching fields.') . " $fieldMessage " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', [1 => $threshold]) . '<br />';
}
elseif ($self->isUpdateExisting() &&
!(in_array('invoice_id', $importKeys) || in_array('trxn_id', $importKeys) ||
in_array('contribution_id', $importKeys)
)
) {
$errors['_qf_default'] .= ts('Invoice ID or Transaction ID or Contribution ID are required to match to the existing contribution records in Update mode.') . '<br />';
}
}
else {
$errors['_qf_default'] .= ts('Missing required field: %1', [1 => $title]) . '<br />';
}
}
}
Expand Down Expand Up @@ -210,38 +194,18 @@ public static function formRule($fields, $files, $self) {
foreach ($ruleFields as $field => $weight) {
$fieldMessage .= ' ' . $field . '(weight ' . $weight . ')';
}
$errors = self::checkRequiredFields($self, $contactORContributionId, $importKeys, $errors, $weightSum, $threshold, $fieldMessage);

//at least one field should be mapped during update.
if ($self->isUpdateExisting()) {
$atleastOne = FALSE;
foreach ($self->_mapperFields as $key => $field) {
if (in_array($key, $importKeys) &&
!in_array($key, [
'doNotImport',
'contribution_id',
'invoice_id',
'trxn_id',
])
) {
$atleastOne = TRUE;
break;
}
}
if (!$atleastOne) {
$errors['_qf_default'] .= ts('At least one contribution field needs to be mapped for update during update mode.') . '<br />';
}
try {
$parser = $self->getParser();
$parser->validateMapping($fields['mapper']);
}
}

if (!empty($errors)) {
if (!empty($errors['_qf_default'])) {
CRM_Core_Session::setStatus($errors['_qf_default'], ts("Error"), "error");
return $errors;
catch (CRM_Core_Exception $e) {
$errors['_qf_default'] = $e->getMessage();
}
if (!$self->isUpdateExisting()) {
$errors = self::checkRequiredFields($self, $contactORContributionId, $importKeys, $errors, $weightSum, $threshold, $fieldMessage);
}
}

return TRUE;
return !empty($errors) ? $errors : TRUE;
}

/**
Expand Down
81 changes: 79 additions & 2 deletions CRM/Contribute/Import/Parser/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use Civi\Api4\Contact;
use Civi\Api4\Contribution;
use Civi\Api4\ContributionSoft;
use Civi\Api4\Email;
use Civi\Api4\Note;

Expand All @@ -32,6 +33,8 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Import_Parser {
*/
protected $_newContributions;

protected $baseEntity = 'Contribution';

/**
* Get information about the provided job.
* - name
Expand Down Expand Up @@ -129,7 +132,6 @@ public static function getUserJobInfo(): array {
* Also 'im_provider_id' is mapped to the 'real' field name 'provider_id'
*
* @return array
* @throws \API_Exception
*/
protected function getFieldMappings(): array {
$mappedFields = [];
Expand All @@ -148,7 +150,25 @@ protected function getFieldMappings(): array {
* @return array
*/
public function getRequiredFields(): array {
return ['id' => ts('Contribution ID'), ['financial_type_id' => ts('Financial Type'), 'total_amount' => ts('Total Amount')]];
return array_merge([$this->getRequiredFieldsForMatch(), $this->getRequiredFieldsForCreate()]);
}

/**
* Get required fields to create a contribution.
*
* @return array
*/
public function getRequiredFieldsForCreate(): array {
return ['financial_type_id', 'total_amount'];
}

/**
* Get required fields to match a contribution.
*
* @return array
*/
public function getRequiredFieldsForMatch(): array {
return [['id', 'invoice_id', 'trxn_id']];
}

/**
Expand Down Expand Up @@ -273,6 +293,63 @@ protected function setFieldMetadata(): void {
}
}

/**
* Get a list of entities this import supports.
*
* @return array
* @throws \API_Exception
*/
public function getImportEntities() : array {
$softCreditTypes = ContributionSoft::getFields()
->setLoadOptions(TRUE)
->addWhere('name', '=', 'soft_credit_type_id')
->selectRowCount()
->addSelect('options')->execute();
return [
'Contribution' => [
'text' => ts('Contribution Fields'),
'required_fields_update' => $this->getRequiredFieldsForMatch(),
'required_fields_create' => $this->getRequiredFieldsForCreate(),
'is_base_entity' => TRUE,
// For now we stick with the action selected on the DataSource page.
'actions' => $this->isUpdateExisting() ?
[['id' => 'update', 'text' => ts('Update existing'), 'description' => ts('Skip if no match found')]] :
[['id' => 'create', 'text' => ts('Create'), 'description' => ts('Skip if already exists')]],
'default_action' => $this->isUpdateExisting() ? 'update' : 'create',
'entity_name' => 'Contribution',
'entity_title' => ts('Contribution'),
],
'Contact' => [
'text' => ts('Contact Fields'),
'unique_fields' => ['external_identifier', 'id'],
'is_contact' => TRUE,
'actions' => [
['id' => 'select', 'text' => ts('Match existing')],
['id' => 'update', 'text' => ts('Update existing'), ts('Skip if not found')],
['id' => 'update_or_create', 'text' => ts('Update or Create')],
],
'default_action' => 'select',
'entity_name' => 'Contact',
'entity_title' => ts('Contribution Contact'),
],
'SoftCreditContact' => [
'text' => ts('Soft Credit Contact Fields'),
'maximum' => count($softCreditTypes),
'unique_fields' => ['external_identifier', 'id'],
'is_contact' => TRUE,
'actions' => [
['id' => 'select', 'text' => ts('Match existing')],
['id' => 'update', 'text' => ts('Update existing'), 'description' => ts('Skip if not found')],
['id' => 'update_or_create', 'text' => ts('Update or Create')],
],
'default_action' => 'select',
'entity_name' => 'SoftCreditContact',
'entity_title' => ts('Soft Credit Contact'),
'entity_data' => ['soft_credit_type_id' => ['required' => TRUE, 'options' => $softCreditTypes]],
],
];
}

/**
* Combine all the importable fields from the lower levels object.
*
Expand Down
2 changes: 1 addition & 1 deletion CRM/Custom/Import/Parser/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public function setFieldMetadata(): void {
* @return array
*/
public function getRequiredFields(): array {
return ['contact_id' => ts('Contact ID'), 'external_identifier' => ts('External Identifier')];
return ['contact_id', 'external_identifier'];
}

/**
Expand Down
2 changes: 1 addition & 1 deletion CRM/Event/Import/Parser/Participant.php
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ protected function setFieldMetadata(): void {
* @return array
*/
protected function getRequiredFields(): array {
return [['event_id' => ts('Event'), 'status_id' => ts('Status')]];
return [['event_id', 'status_id']];
}

}
Loading

0 comments on commit bfabad9

Please sign in to comment.