Merge pull request #22342 from civicrm/5.45
[civicrm-core.git] / CRM / Price / Form / Set.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * Form to process actions on Price Sets.
20 */
21 class CRM_Price_Form_Set extends CRM_Core_Form {
22
23 use CRM_Core_Form_EntityFormTrait;
24
25 /**
26 * The set id saved to the session for an update.
27 *
28 * @var int
29 */
30 protected $_sid;
31
32 /**
33 * Get the entity id being edited.
34 *
35 * @return int|null
36 */
37 public function getEntityId() {
38 return $this->_sid;
39 }
40
41 /**
42 * Explicitly declare the entity api name.
43 */
44 public function getDefaultEntity() {
45 return 'PriceSet';
46 }
47
48 /**
49 * Fields for the entity to be assigned to the template.
50 *
51 * Fields may have keys
52 * - name (required to show in tpl from the array)
53 * - description (optional, will appear below the field)
54 * - not-auto-addable - this class will not attempt to add the field using addField.
55 * (this will be automatically set if the field does not have html in it's metadata
56 * or is not a core field on the form's entity).
57 * - help (option) add help to the field - e.g ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact']]
58 * - template - use a field specific template to render this field
59 * @var array
60 */
61 protected $entityFields = [];
62
63 /**
64 * Set entity fields to be assigned to the form.
65 */
66 protected function setEntityFields() {
67 $this->entityFields = [
68 'title' => [
69 'required' => 'TRUE',
70 'name' => 'title',
71 ],
72 'min_amount' => ['name' => 'min_amount'],
73 'help_pre' => ['name' => 'help_pre'],
74 'help_post' => ['name' => 'help_post'],
75 'is_active' => ['name' => 'is_active'],
76 ];
77 }
78
79 /**
80 * Deletion message to be assigned to the form.
81 *
82 * @var string
83 */
84 protected $deleteMessage;
85
86 /**
87 * Set the delete message.
88 *
89 * We do this from the constructor in order to do a translation.
90 */
91 public function setDeleteMessage() {}
92
93 /**
94 * Set variables up before form is built.
95 */
96 public function preProcess() {
97 // current set id
98 $this->_sid = $this->get('sid');
99
100 // setting title for html page
101 $title = ts('New Price Set');
102 if ($this->getEntityId()) {
103 $title = CRM_Price_BAO_PriceSet::getTitle($this->getEntityId());
104 }
105 if ($this->_action & CRM_Core_Action::UPDATE) {
106 $title = ts('Edit %1', [1 => $title]);
107 }
108 elseif ($this->_action & CRM_Core_Action::VIEW) {
109 $title = ts('Preview %1', [1 => $title]);
110 }
111 $this->setTitle($title);
112
113 $url = CRM_Utils_System::url('civicrm/admin/price', 'reset=1');
114 $breadCrumb = [
115 [
116 'title' => ts('Price Sets'),
117 'url' => $url,
118 ],
119 ];
120 CRM_Utils_System::appendBreadCrumb($breadCrumb);
121 }
122
123 /**
124 * Global form rule.
125 *
126 * @param array $fields
127 * The input form values.
128 * @param array $files
129 * The uploaded files if any.
130 * @param array $options
131 * Additional user data.
132 *
133 * @return bool|array
134 * true if no errors, else array of errors
135 */
136 public static function formRule($fields, $files, $options) {
137 $errors = [];
138 $count = count(CRM_Utils_Array::value('extends', $fields, []));
139 //price sets configured for membership
140 if ($count > 1 && array_key_exists(CRM_Core_Component::getComponentID('CiviMember'), $fields['extends'])) {
141 $errors['extends'] = ts('If you plan on using this price set for membership signup and renewal, you can not also use it for Events or Contributions. However, a membership price set may include additional fields for non-membership options that require an additional fee (e.g. magazine subscription).');
142 }
143 // Checks the given price set does not start with a digit
144 if (strlen($fields['title']) && is_numeric($fields['title'][0])) {
145 $errors['title'] = ts('Name cannot not start with a digit');
146 }
147 return empty($errors) ? TRUE : $errors;
148 }
149
150 /**
151 * Build the form object.
152 */
153 public function buildQuickForm() {
154 $this->buildQuickEntityForm();
155 $this->assign('sid', $this->getEntityId());
156
157 $this->addRule('title', ts('Name already exists in Database.'),
158 'objectExists', ['CRM_Price_DAO_PriceSet', $this->getEntityId(), 'title']
159 );
160
161 $priceSetUsedTables = $extends = [];
162 if ($this->_action == CRM_Core_Action::UPDATE && $this->getEntityId()) {
163 $priceSetUsedTables = CRM_Price_BAO_PriceSet::getUsedBy($this->getEntityId(), 'table');
164 }
165
166 $enabledComponents = CRM_Core_Component::getEnabledComponents();
167
168 foreach ($enabledComponents as $name => $compObj) {
169 switch ($name) {
170 case 'CiviEvent':
171 $option = $this->createElement('checkbox', $compObj->componentID, NULL, ts('Event'));
172 if (!empty($priceSetUsedTables)) {
173 foreach (['civicrm_event', 'civicrm_participant'] as $table) {
174 if (in_array($table, $priceSetUsedTables)) {
175 $option->freeze();
176 break;
177 }
178 }
179 }
180 $extends[] = $option;
181 break;
182
183 case 'CiviContribute':
184 $option = $this->createElement('checkbox', $compObj->componentID, NULL, ts('Contribution'));
185 if (!empty($priceSetUsedTables)) {
186 foreach (['civicrm_contribution', 'civicrm_contribution_page'] as $table) {
187 if (in_array($table, $priceSetUsedTables)) {
188 $option->freeze();
189 break;
190 }
191 }
192 }
193 $extends[] = $option;
194 break;
195
196 case 'CiviMember':
197 $option = $this->createElement('checkbox', $compObj->componentID, NULL, ts('Membership'));
198 if (!empty($priceSetUsedTables)) {
199 foreach (['civicrm_membership', 'civicrm_contribution_page'] as $table) {
200 if (in_array($table, $priceSetUsedTables)) {
201 $option->freeze();
202 break;
203 }
204 }
205 }
206 $extends[] = $option;
207 break;
208 }
209 }
210
211 if (CRM_Utils_System::isNull($extends)) {
212 $this->assign('extends', FALSE);
213 }
214 else {
215 $this->assign('extends', TRUE);
216 }
217
218 $this->addGroup($extends, 'extends', ts('Used For'), '&nbsp;', TRUE);
219
220 $this->addRule('extends', ts('%1 is a required field.', [1 => ts('Used For')]), 'required');
221
222 // financial type
223 $financialType = CRM_Financial_BAO_FinancialType::getIncomeFinancialType();
224
225 $this->add('select', 'financial_type_id',
226 ts('Default Financial Type'),
227 ['' => ts('- select -')] + $financialType, 'required'
228 );
229
230 $this->addFormRule(['CRM_Price_Form_Set', 'formRule']);
231
232 // views are implemented as frozen form
233 if ($this->_action & CRM_Core_Action::VIEW) {
234 $this->freeze();
235 }
236 }
237
238 /**
239 * Set default values for the form. Note that in edit/view mode.
240 *
241 * The default values are retrieved from the database.
242 *
243 * @return array
244 * array of default values
245 */
246 public function setDefaultValues() {
247 $defaults = ['is_active' => TRUE];
248 if ($this->getEntityId()) {
249 $params = ['id' => $this->getEntityId()];
250 CRM_Price_BAO_PriceSet::retrieve($params, $defaults);
251 $extends = explode(CRM_Core_DAO::VALUE_SEPARATOR, $defaults['extends']);
252 unset($defaults['extends']);
253 foreach ($extends as $compId) {
254 $defaults['extends'][$compId] = 1;
255 }
256 }
257
258 return $defaults;
259 }
260
261 /**
262 * Process the form.
263 */
264 public function postProcess() {
265 // get the submitted form values.
266 $params = $this->controller->exportValues('Set');
267 $nameLength = CRM_Core_DAO::getAttribute('CRM_Price_DAO_PriceSet', 'name');
268 $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
269 $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params, FALSE);
270
271 $compIds = [];
272 $extends = $params['extends'] ?? NULL;
273 if (is_array($extends)) {
274 foreach ($extends as $compId => $selected) {
275 if ($selected) {
276 $compIds[] = $compId;
277 }
278 }
279 }
280 $params['extends'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, $compIds);
281
282 if ($this->_action & CRM_Core_Action::UPDATE) {
283 $params['id'] = $this->getEntityId();
284 }
285 else {
286 $params['name'] = CRM_Utils_String::titleToVar($params['title'],
287 CRM_Utils_Array::value('maxlength', $nameLength));
288 }
289
290 $set = CRM_Price_BAO_PriceSet::create($params);
291 if ($this->_action & CRM_Core_Action::UPDATE) {
292 CRM_Core_Session::setStatus(ts('The Set \'%1\' has been saved.', [1 => $set->title]), ts('Saved'), 'success');
293 }
294 else {
295 // Jump directly to adding a field if popups are disabled
296 $action = CRM_Core_Resources::singleton()->ajaxPopupsEnabled ? 'browse' : 'add';
297 $url = CRM_Utils_System::url('civicrm/admin/price/field', [
298 'reset' => 1,
299 'action' => $action,
300 'sid' => $set->id,
301 'new' => 1,
302 ]);
303 CRM_Core_Session::setStatus(ts("Your Set '%1' has been added. You can add fields to this set now.",
304 [1 => $set->title]
305 ), ts('Saved'), 'success');
306 $session = CRM_Core_Session::singleton();
307 $session->replaceUserContext($url);
308 }
309 }
310
311 }