Enable QueueRunner for membership import
[civicrm-core.git] / CRM / Member / Import / Form / MapField.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
19 * This class gets the name of the file to upload
20 */
b26295b8 21class CRM_Member_Import_Form_MapField extends CRM_Import_Form_MapField {
6a488035 22
6a488035 23 /**
fe482240 24 * Build the form object.
6a488035
TO
25 *
26 * @return void
6a488035
TO
27 */
28 public function buildQuickForm() {
22f90136 29 $this->buildSavedMappingFields($this->getSubmittedValue('savedMapping'));
6a488035
TO
30 $this->addFormRule(array('CRM_Member_Import_Form_MapField', 'formRule'), $this);
31
32 //-------- end of saved mapping stuff ---------
33
affcc9d2 34 $defaults = [];
22f90136
EM
35 $columnHeaders = $this->getColumnHeaders();
36 $hasHeaders = $this->getSubmittedValue('skipColumnHeader');
b584b608
EM
37 $headerPatterns = $this->getHeaderPatterns();
38 $dataPatterns = $this->getDataPatterns();
2238da0d
EM
39 // For most fields using the html label is a good thing
40 // but for contact ID we really want to specify ID.
41 $this->_mapperFields['membership_contact_id'] = ts('Contact ID');
6a488035 42 $sel1 = $this->_mapperFields;
22f90136 43 if (!$this->getSubmittedValue('onDuplicate')) {
2238da0d 44 // If not updating then do not allow membership id.
6a488035
TO
45 unset($sel1['membership_id']);
46 }
47
6a488035
TO
48 $js = "<script type='text/javascript'>\n";
49 $formName = 'document.forms.' . $this->_name;
50
7eebbdaa 51 $fieldMappings = $this->getFieldMappings();
6a488035 52
22f90136 53 foreach ($columnHeaders as $i => $columnHeader) {
6a488035
TO
54 $sel = &$this->addElement('hierselect', "mapper[$i]", ts('Mapper for Field %1', array(1 => $i)), NULL);
55 $jsSet = FALSE;
af05126d 56 if ($this->getSubmittedValue('savedMapping')) {
2238da0d
EM
57 $fieldMapping = $fieldMappings[$i] ?? NULL;
58 if (isset($fieldMappings[$i])) {
59 if ($fieldMapping['name'] != ts('do_not_import')) {
6a488035
TO
60 //When locationType is not set
61 $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
62
63 //When phoneType is not set
64 $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
65
66 $js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
67
2238da0d 68 $defaults["mapper[$i]"] = [$fieldMapping['name']];
6a488035
TO
69 $jsSet = TRUE;
70 }
71 else {
affcc9d2 72 $defaults["mapper[$i]"] = [];
6a488035
TO
73 }
74 if (!$jsSet) {
75 for ($k = 1; $k < 4; $k++) {
76 $js .= "{$formName}['mapper[$i][$k]'].style.display = 'none';\n";
77 }
78 }
79 }
80 else {
81 // this load section to help mapping if we ran out of saved columns when doing Load Mapping
82 $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_" . $i . "_');\n";
83
84 if ($hasHeaders) {
22f90136 85 $defaults["mapper[$i]"] = array($this->defaultFromHeader($columnHeader, $headerPatterns));
6a488035
TO
86 }
87 else {
88 $defaults["mapper[$i]"] = array($this->defaultFromData($dataPatterns, $i));
89 }
90 }
91 //end of load mapping
92 }
93 else {
94 $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_" . $i . "_');\n";
209cedd9 95 if ($this->getSubmittedValue('skipColumnHeader')) {
6a488035
TO
96 // Infer the default from the skipped headers if we have them
97 $defaults["mapper[$i]"] = array(
22f90136 98 $this->defaultFromHeader($columnHeader,
6a488035
TO
99 $headerPatterns
100 ),
101 // $defaultLocationType->id
102 0,
103 );
104 }
105 else {
106 // Otherwise guess the default from the form of the data
107 $defaults["mapper[$i]"] = array(
108 $this->defaultFromData($dataPatterns, $i),
109 // $defaultLocationType->id
110 0,
111 );
112 }
113 }
4ff86743 114 $sel->setOptions([$sel1]);
6a488035
TO
115 }
116 $js .= "</script>\n";
117 $this->assign('initHideBoxes', $js);
118
6a488035
TO
119 $this->setDefaults($defaults);
120
9b324cef 121 $this->addFormButtons();
6a488035
TO
122 }
123
124 /**
fe482240 125 * Global validation rules for the form.
6a488035 126 *
b2363ea8
TO
127 * @param array $fields
128 * Posted values of the form.
6a488035 129 *
fd31fa4c 130 * @param $files
e8cf95b4 131 * @param self $self
fd31fa4c 132 *
2238da0d 133 * @return array|bool
a6c01b45 134 * list of errors to be posted back to the form
6a488035 135 */
00be9182 136 public static function formRule($fields, $files, $self) {
affcc9d2 137 $errors = [];
6a488035 138
90ea7810
EM
139 $importKeys = [];
140 foreach ($fields['mapper'] as $mapperPart) {
141 $importKeys[] = $mapperPart[0];
142 }
143 // FIXME: should use the schema titles, not redeclare them
144 $requiredFields = array(
145 'membership_contact_id' => ts('Contact ID'),
146 'membership_type_id' => ts('Membership Type'),
147 'membership_start_date' => ts('Membership Start Date'),
148 );
b584b608
EM
149 $params = array(
150 'used' => 'Unsupervised',
151 'contact_type' => $self->getContactType(),
152 );
22f90136
EM
153 [$ruleFields, $threshold] = CRM_Dedupe_BAO_DedupeRuleGroup::dedupeRuleFieldsWeight($params);
154 $weightSum = 0;
155 foreach ($importKeys as $key => $val) {
156 if (array_key_exists($val, $ruleFields)) {
157 $weightSum += $ruleFields[$val];
6a488035 158 }
22f90136
EM
159 }
160 $fieldMessage = '';
161 foreach ($ruleFields as $field => $weight) {
162 $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')';
163 }
6a488035 164
90ea7810
EM
165 foreach ($requiredFields as $field => $title) {
166 if (!in_array($field, $importKeys)) {
2238da0d 167 if ($field === 'membership_contact_id') {
90ea7810 168 if ((($weightSum >= $threshold || in_array('external_identifier', $importKeys)) &&
22f90136 169 $self->getSubmittedValue('onDuplicate') != CRM_Import_Parser::DUPLICATE_UPDATE
90ea7810
EM
170 ) ||
171 in_array('membership_id', $importKeys)
172 ) {
173 continue;
6a488035 174 }
2238da0d
EM
175 if (!isset($errors['_qf_default'])) {
176 $errors['_qf_default'] = '';
6a488035 177 }
2238da0d
EM
178 $errors['_qf_default'] .= ts('Missing required contact matching fields.') . " $fieldMessage " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(
179 1 => $threshold,
180 )) . ' ' . ts('(OR Membership ID if update mode.)') . '<br />';
6a488035 181 }
90ea7810
EM
182 else {
183 if (!isset($errors['_qf_default'])) {
184 $errors['_qf_default'] = '';
185 }
186 $errors['_qf_default'] .= ts('Missing required field: %1', array(
187 1 => $title,
188 )) . '<br />';
189 }
6a488035
TO
190 }
191 }
192
a7488080 193 if (!empty($fields['saveMapping'])) {
9c1bc317 194 $nameField = $fields['saveMappingName'] ?? NULL;
6a488035
TO
195 if (empty($nameField)) {
196 $errors['saveMappingName'] = ts('Name is required to save Import Mapping');
197 }
198 else {
95f52e3b 199 if (CRM_Core_BAO_Mapping::checkMapping($nameField, CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Mapping', 'mapping_type_id', 'Import Membership'))) {
6a488035
TO
200 $errors['saveMappingName'] = ts('Duplicate Import Membership Mapping Name');
201 }
202 }
203 }
204
205 if (!empty($errors)) {
206 if (!empty($errors['saveMappingName'])) {
207 $_flag = 1;
208 $assignError = new CRM_Core_Page();
209 $assignError->assign('mappingDetailsError', $_flag);
210 }
211 return $errors;
212 }
213
214 return TRUE;
215 }
216
217 /**
22f90136 218 * Get the mapping name per the civicrm_mapping_field.type_id option group.
6a488035 219 *
22f90136 220 * @return string
6a488035 221 */
22f90136
EM
222 public function getMappingTypeName(): string {
223 return 'Import Membership';
6a488035 224 }
96025800 225
83a1c234
EM
226 /**
227 * @return \CRM_Member_Import_Parser_Membership
228 */
229 protected function getParser(): CRM_Member_Import_Parser_Membership {
230 if (!$this->parser) {
231 $this->parser = new CRM_Member_Import_Parser_Membership();
232 $this->parser->setUserJobID($this->getUserJobID());
233 $this->parser->init();
234 }
235 return $this->parser;
236 }
237
22f90136
EM
238 /**
239 * Get the fields to be highlighted in the UI.
240 *
241 * @return array
242 * @throws \CRM_Core_Exception
243 */
244 protected function getHighlightedFields(): array {
245 $highlightedFields = [];
2238da0d 246 //CRM-2219 removing other required fields since for update only
22f90136
EM
247 //membership id is required.
248 if ($this->getSubmittedValue('onDuplicate') == CRM_Import_Parser::DUPLICATE_UPDATE) {
249 $remove = [
250 'membership_contact_id',
251 'email',
252 'first_name',
253 'last_name',
254 'external_identifier',
255 ];
256 foreach ($remove as $value) {
257 unset($this->_mapperFields[$value]);
258 }
259 $highlightedFieldsArray = [
260 'membership_id',
261 'membership_start_date',
262 'membership_type_id',
263 ];
264 foreach ($highlightedFieldsArray as $name) {
265 $highlightedFields[] = $name;
266 }
267 }
268 elseif ($this->getSubmittedValue('onDuplicate') == CRM_Import_Parser::DUPLICATE_SKIP) {
269 unset($this->_mapperFields['membership_id']);
270 $highlightedFieldsArray = [
271 'membership_contact_id',
272 'email',
273 'external_identifier',
274 'membership_start_date',
275 'membership_type_id',
276 ];
277 foreach ($highlightedFieldsArray as $name) {
278 $highlightedFields[] = $name;
279 }
280 }
281 return $highlightedFields;
282 }
283
6a488035 284}