Metadata fix - phone_type_id, location_type_id, gender_id
[civicrm-core.git] / templates / CRM / Batch / Form / Entry.tpl
1 {*
2 +--------------------------------------------------------------------+
3 | Copyright CiviCRM LLC. All rights reserved. |
4 | |
5 | This work is published under the GNU AGPLv3 license with some |
6 | permitted exceptions and without any warranty. For full license |
7 | and copyright information, see https://civicrm.org/licensing |
8 +--------------------------------------------------------------------+
9 *}
10 <div class="batch-entry form-item">
11 <div class="help">
12 {ts}Click Validate & Process below when you've entered all items for the batch. You can also Save & Continue Later at any time.{/ts}
13 {if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM')}
14 {capture assign=batchEntryProfileURL}{crmURL p="civicrm/admin/uf/group" q="reset=1&selectedChild=reserved-profiles"}{/capture}
15 {ts 1=$batchEntryProfileURL}Add, remove or change the order of columns by editing the corresponding <a href="%1" target="_blank">Bulk Entry profile</a>.{/ts}
16 {if $batchType EQ 1}
17 {ts}Custom fields and a Personal Campaign Page field can be added if needed.{/ts}
18 {/if}
19 {/if}
20 </div>
21 {if $batchAmountMismatch}
22 <div class="status message status-warning">
23 <i class="crm-i fa-exclamation-triangle" aria-hidden="true"></i> {ts}Total for amounts entered below does not match the expected batch total.{/ts}
24 </div>
25 {$form._qf_Entry_upload_force.html}
26 <div class="clear"></div>
27 {/if}
28 <table class="form-layout-compressed batch-totals">
29 <tr>
30 <td class="label">
31 <label>{ts}Total amount expected{/ts}</label>
32 </td>
33 <td class="right"><span class="batch-expected-total">{$batchTotal|crmMoney}</span></td>
34 </tr>
35 <tr>
36 <td class="label">
37 <label>{ts}Total amount entered{/ts}</label>
38 </td>
39 <td class="right">{$defaultCurrencySymbol} <span class="batch-actual-total"></span></td>
40 </tr>
41 </table>
42
43 <div class="crm-copy-fields crm-grid-table" id="crm-batch-entry-table">
44 <div class="crm-grid-header">
45 <div class="crm-grid-cell">&nbsp;</div>
46 <div class="crm-grid-cell">{ts}Contact{/ts}</div>
47 {if $batchType eq 2}
48 <div class="crm-grid-cell">&nbsp;</div>
49 {/if}
50 {if $batchType eq 3}
51 <div class="crm-grid-cell">{ts}Open Pledges (Due Date - Amount){/ts}</div>
52 {/if}
53 {foreach from=$fields item=field key=fieldName}
54 <div class="crm-grid-cell">
55 {if $field.name|substr:0:11 ne 'soft_credit' and $field.name ne 'trxn_id'}
56 {copyIcon name=$field.name title=$field.title}
57 {/if}{$field.title}
58 </div>
59 {/foreach}
60 </div>
61
62 {section name='i' start=1 loop=$rowCount}
63 {assign var='rowNumber' value=$smarty.section.i.index}
64 <div class="{cycle values="odd-row,even-row"} selector-rows crm-grid-row" entity_id="{$rowNumber}">
65 <div class="compressed crm-grid-cell"><span class="batch-edit"></span></div>
66 {* contact select/create option*}
67 <div class="compressed crm-grid-cell">
68 {$form.primary_contact_id.$rowNumber.html|crmAddClass:big}
69 </div>
70
71 {if $batchType eq 2}
72 {$form.member_option.$rowNumber.html}
73 {/if}
74 {if $batchType eq 3}
75 {$form.open_pledges.$rowNumber.html}
76 {/if}
77 {foreach from=$fields item=field key=fieldName}
78 {assign var=n value=$field.name}
79 {if $n eq 'soft_credit'}
80 <div class="compressed crm-grid-cell">
81 {$form.soft_credit_contact_id.$rowNumber.html|crmAddClass:big}
82 {$form.soft_credit_amount.$rowNumber.label}&nbsp;{$form.soft_credit_amount.$rowNumber.html|crmAddClass:eight}
83 </div>
84 {elseif $n eq 'soft_credit_type'}
85 <div class="compressed crm-grid-cell">{$form.soft_credit_type.$rowNumber.html}</div>
86 {elseif $n eq 'contribution_soft_credit_pcp_id'}
87 <div class="compressed crm-grid-cell">
88 <div>{$form.pcp_made_through_id.$rowNumber.html}{$form.pcp_made_through.$rowNumber.html}</div>
89 <div>{$form.pcp_display_in_roll.$rowNumber.label}&nbsp;{$form.pcp_display_in_roll.$rowNumber.html}</div>
90 <div class="pcp_roll_display">{$form.pcp_roll_nickname.$rowNumber.label}&nbsp;{$form.pcp_roll_nickname.$rowNumber.html}</div>
91 <div class="pcp_roll_display">{$form.pcp_personal_note.$rowNumber.label}&nbsp;{$form.pcp_personal_note.$rowNumber.html}</div>
92 </div>
93 {elseif in_array( $fields.$n.html_type, array('Radio', 'CheckBox'))}
94 <div class="compressed crm-grid-cell">&nbsp;{$form.field.$rowNumber.$n.html}</div>
95 {elseif $n eq 'total_amount'}
96 <div class="compressed crm-grid-cell">
97 {$form.field.$rowNumber.$n.html}
98 {if $batchType eq 3 }
99 {ts}<span id={$rowNumber} class="pledge-adjust-option"><a href='#'>adjust payment amount</a></span>{/ts}
100 <span id="adjust-select-{$rowNumber}" class="adjust-selectbox">{$form.option_type.$rowNumber.html}</span>
101 {/if}
102 </div>
103 {else}
104 <div class="compressed crm-grid-cell">
105 {$form.field.$rowNumber.$n.html}
106 {if $fields.$n.html_type eq 'File' && !empty($form.field.$rowNumber.$fieldName.value.size)}
107 {ts}Attached{/ts}: {$form.field.$rowNumber.$fieldName.value.name}
108 {/if}
109 </div>
110 {/if}
111 {/foreach}
112 </div>
113 {/section}
114 </div>
115 <div class="crm-submit-buttons">{if $fields}{$form._qf_Batch_refresh.html}{/if} &nbsp; {$form.buttons.html}</div>
116 </div>
117 {literal}
118 <script type="text/javascript">
119 CRM.$(function($) {
120 var $form = $('form.{/literal}{$form.formClass}{literal}');
121 $('.selector-rows').change(function () {
122 var options = {
123 'url': {/literal}"{crmURL p='civicrm/ajax/batch' h=0}"{literal}
124 };
125 $($form).ajaxSubmit(options);
126 });
127
128 $('input[id*="primary_contact_"]').change(function() {
129 var temp = this.id.split('_');
130 var ROWID = temp[3];
131 if ($(this).val()) {
132 updateContactInfo(ROWID,'primary_');
133 }
134 });
135
136 $('select[id^="option_type_"]').each(function () {
137 if ($(this).val() == 1) {
138 $(this).attr('disabled', true);
139 $(this).hide();
140 }
141 });
142
143 $('#crm-container').on('keyup change', '*.selector-rows', function () {
144 // validate rows
145 checkColumns($(this));
146 });
147
148 // validate rows
149 validateRow();
150
151 //calculate the actual total for the batch
152 calculateActualTotal();
153
154 $('input[id*="_total_amount"]').bind('keyup change', function () {
155 calculateActualTotal();
156 });
157
158 {/literal}{if $batchType eq 1 }{literal}
159 // hide all dates if send receipt is checked
160 hideSendReceipt();
161
162 // hide the receipt date if send receipt is checked
163 $('input[id*="][send_receipt]"]').change(function () {
164 showHideReceipt($(this));
165 });
166
167 {/literal}{elseif $batchType eq 2}{literal}
168 $('select[id^="member_option_"]').each(function () {
169 if ($(this).val() == 1) {
170 $(this).prop('disabled', true);
171 }
172 });
173
174 // set payment info accord to membership type
175 $('select[id*="_membership_type_0"]').change(function () {
176 setPaymentBlock($(this), null);
177 });
178
179 $('select[id*="_membership_type_1"]').change(function () {
180 setPaymentBlock($(this), $(this).val());
181 });
182
183 {/literal}{/if}{literal}
184
185 // line breaks between radio buttons and checkboxes
186 $('input.form-radio').next().after('<br />');
187 $('input.form-checkbox').next().after('<br />');
188
189 //set the focus on first element
190 $('#primary_contact_1').focus();
191
192 });
193
194 function setPaymentBlock(form, memType) {
195 var rowID = form.closest('div.crm-grid-row').attr('entity_id');
196 var dataUrl = {/literal}"{crmURL p='civicrm/ajax/memType' h=0}"{literal};
197
198 if (!memType) {
199 memType = cj('select[id="field_' + rowID + '_membership_type_1"]').val();
200 }
201
202 cj.post(dataUrl, {mtype: memType}, function (data) {
203 cj('#field_' + rowID + '_financial_type').val(data.financial_type_id);
204 cj('#field_' + rowID + '_total_amount').val(data.total_amount).change();
205 }, 'json');
206 }
207
208 function hideSendReceipt() {
209 cj('input[id*="][send_receipt]"]').each(function () {
210 showHideReceipt(cj(this));
211 });
212 }
213
214 function showHideReceipt(elem) {
215 var rowID = elem.closest('div.crm-grid-row').attr('entity_id');
216 if (elem.prop('checked')) {
217 cj('.crm-batch-receipt_date-' + rowID).hide();
218 }
219 else {
220 cj('.crm-batch-receipt_date-' + rowID).show();
221 }
222 }
223
224 function validateRow() {
225 cj('.selector-rows').each(function () {
226 checkColumns(cj(this));
227 });
228 }
229
230 function checkColumns(parentRow) {
231 // show valid row icon if all required data is field
232 var validRow = 0;
233 var inValidRow = 0;
234 var errorExists = false;
235 var rowID = parentRow.closest('div.crm-grid-row').attr('entity_id');
236
237 parentRow.find('div .required').each(function () {
238 //special case to handle contact autocomplete select
239 var fieldId = cj(this).attr('id');
240 // datepicker hasTimeEntry would not have an id - not sure why.
241 if (typeof fieldId != 'undefined' && fieldId.substring(0, 16) == 'primary_contact_') {
242 // if display value is set then make sure we also check if contact id is set
243 if (!cj(this).val()) {
244 inValidRow++;
245 }
246 else {
247 var contactIdElement = cj('input[name="primary_contact_select_id[' + rowID + ']"]');
248 if (cj(this).val() && !contactIdElement.val()) {
249 inValidRow++;
250 errorExists = true;
251 }
252 else if (cj(this).val() && contactIdElement.val()) {
253 // this is hack to remove error span because we are skipping this for autocomplete fields
254 cj(this).next('span.crm-error').remove();
255 }
256 }
257 }
258 else {
259 if (!cj(this).val()) {
260 inValidRow++;
261 }
262 else {
263 if (cj(this).hasClass('error') && (cj(this).hasClass('valid') || cj(this).hasClass('required'))) {
264 errorExists = true;
265 }
266 else {
267 validRow++;
268 }
269 }
270 }
271 });
272
273 // this means user has entered some data
274 if (errorExists) {
275 parentRow.find("div:first span").prop('class', 'batch-invalid');
276 }
277 else {
278 if (inValidRow == 0 && validRow > 0) {
279 parentRow.find("div:first span").prop('class', 'batch-valid');
280 }
281 else {
282 parentRow.find("div:first span").prop('class', 'batch-edit');
283 }
284 }
285 }
286
287 function calculateActualTotal() {
288 var total = 0;
289 cj('input[id*="_total_amount"]').each(function () {
290 if (cj(this).val()) {
291 total += parseFloat(cj(this).val());
292 }
293 });
294
295 cj('.batch-actual-total').html(formatMoney(total));
296 }
297
298 //money formatting/localization
299 function formatMoney(amount) {
300 var c = 2;
301 var t = '{/literal}{$config->monetaryThousandSeparator}{literal}';
302 var d = '{/literal}{$config->monetaryDecimalPoint}{literal}';
303
304 var n = amount,
305 c = isNaN(c = Math.abs(c)) ? 2 : c,
306 d = d == undefined ? "," : d,
307 t = t == undefined ? "." : t, s = n < 0 ? "-" : "",
308 i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
309 j = (j = i.length) > 3 ? j % 3 : 0;
310
311 return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
312 }
313
314 function updateContactInfo(blockNo, prefix) {
315 var contactHiddenElement = 'input[id="' + prefix + 'contact_id_' + blockNo + '"]';
316 var contactId = cj(contactHiddenElement).val();
317
318 var returnProperties = '';
319 var profileFields = [];
320 {/literal}
321 {if $contactFields}
322 {foreach from=$contactFields item=val key=fldName}
323 var fldName = {$fldName|@json_encode};
324 {literal}
325 if (returnProperties) {
326 returnProperties = returnProperties + ',';
327 }
328 var fld = fldName.split('-');
329 returnProperties = returnProperties + fld[0];
330 profileFields[fld[0]] = fldName;
331 {/literal}
332 {/foreach}
333 {/if}
334 {literal}
335
336 CRM.api('Contact', 'get', {
337 'sequential': '1',
338 'contact_id': contactId,
339 'return': returnProperties },
340 { success: function (data) {
341 cj.each(data.values[0], function (key, value) {
342 // set the values
343 var actualFldName = profileFields[key];
344 if (key == 'country' || key == 'state_province') {
345 idFldName = key + '_id';
346 value = data.values[0][idFldName];
347 }
348 setFieldValue(actualFldName, value, blockNo)
349 });
350
351 // for membership batch entry based on contact we need to enable / disable
352 // add membership select
353 {/literal}{if $batchType eq 2}{literal}
354 CRM.api('Membership', 'get', {
355 'sequential': '1',
356 'contact_id': contactId,
357 },
358 { success: function (data) {
359 if (data.count > 0) {
360 //get the information on membership type
361 var membershipTypeId = data.values[0].membership_type_id;
362 var membershipJoinDate = data.values[0].join_date;
363 var membershipStartDate = data.values[0].start_date;
364 CRM.api('MembershipType', 'get', {
365 'sequential': '1',
366 'id': membershipTypeId
367 },
368 { success: function (data) {
369 var memTypeContactId = data.values[0].member_of_contact_id;
370 cj('select[id="member_option_' + blockNo + '"]').prop('disabled', false).val(2);
371 cj('select[id="field_' + blockNo + '_membership_type_0"]').val(memTypeContactId).change();
372 cj('select[id="field_' + blockNo + '_membership_type_1"]').val(membershipTypeId).change();
373 cj('#field_' + blockNo + '_' + 'membership_join_date').val(membershipJoinDate).trigger('change');
374 cj('#field_' + blockNo + '_' + 'membership_start_date').val(membershipStartDate).trigger('change');
375 }
376 });
377 }
378 }
379 });
380 {/literal}{elseif $batchType eq 3}{literal}
381 cj('#open_pledges_'+blockNo).empty();
382 cj('#open_pledges_'+blockNo).append(cj('<option>', {
383 value: '',
384 text: '-select-'
385 }));
386 CRM.api('Pledge', 'get', {
387 'sequential': 1,
388 'contact_id': contactId || 0
389 },
390 {success: function(data) {
391 cj.each(data['values'], function(key, value) {
392 if (value['pledge_status'] != 'Completed') {
393 var date = cj.datepicker.parseDate('yy-mm-dd', value['pledge_next_pay_date']);
394 var dateformat = "{/literal}{$config->dateInputFormat}{literal}";
395 cj('#open_pledges_'+ blockNo).append(cj('<option>', {
396 value: value['pledge_id'],
397 text: cj.datepicker.formatDate(dateformat, date) + ", " + value['pledge_next_pay_amount'] + ' ' + value['pledge_currency']
398 }));
399 }
400 });
401 }
402 });
403 {/literal}{/if}{literal}
404 }
405 });
406 }
407
408 /**
409 * This function is use to setdefault elements via ajax
410 *
411 * @param fname string field name
412 * @return void
413 */
414 function setFieldValue(fname, fieldValue, blockNo) {
415 var elementId = cj('[name="field[' + blockNo + '][' + fname + ']"]');
416
417 if (elementId.length == 0) {
418 elementId = cj('input[type=checkbox][name^="field[' + blockNo + '][' + fname + ']"][type!=hidden]');
419 }
420
421 // if element not found than return
422 if (elementId.length == 0) {
423 return;
424 }
425
426 //check if it is date element
427 var isDateElement = elementId.attr('format');
428
429 //get the element type
430 var elementType = elementId.attr('type');
431
432 // set the value for all the elements, elements needs to be handled are
433 // select, checkbox, radio, date fields, text, textarea, multi-select
434 // wysiwyg editor, advanced multi-select ( to do )
435 if (elementType == 'radio') {
436 if (fieldValue) {
437 elementId.filter("[value=" + fieldValue + "]").prop("checked", true);
438 }
439 else {
440 elementId.removeProp('checked');
441 }
442 }
443 else {
444 if (elementType == 'checkbox') {
445 // handle checkbox
446 elementId.removeProp('checked');
447 if (fieldValue) {
448 cj.each(fieldValue, function (key, value) {
449 cj('input[name="field[' + blockNo + '][' + fname + '][' + value + ']"]').prop('checked', true);
450 });
451 }
452 }
453 else {
454 if (elementId.is('textarea')) {
455 CRM.wysiwyg.setVal(elementId, fieldValue);
456 }
457 else {
458 elementId.val(fieldValue);
459 }
460 }
461 }
462
463 // since we use different display field for date we also need to set it.
464 // also check for date time field and set the value correctly
465 if (isDateElement && fieldValue) {
466 setDateFieldValue(fname, fieldValue, blockNo)
467 }
468 }
469
470 function setDateFieldValue(fname, fieldValue, blockNo) {
471 var dateValues = fieldValue.split(' ');
472
473 var actualDateElement = cj('#field_' + blockNo + '_' + fname);
474 var date_format = actualDateElement.attr('format');
475 var altDateFormat = 'yy-mm-dd';
476
477 var actualDateValue = cj.datepicker.parseDate(altDateFormat, dateValues[0]);
478
479 // format date according to display field
480 var hiddenDateValue = cj.datepicker.formatDate('mm/dd/yy', actualDateValue);
481
482 actualDateElement.val(hiddenDateValue);
483
484 var displayDateValue = actualDateElement.val();
485 if (date_format != 'mm/dd/yy') {
486 displayDateValue = cj.datepicker.formatDate(date_format, actualDateValue);
487 }
488 cj('[id^=field_' + blockNo + '_' + fname + '_display]').val(displayDateValue);
489
490 // need to fix time formatting
491 if (dateValues[1]) {
492 cj('#field_' + blockNo + '_' + fname + '_time').val(dateValues[1].substr(0, 5));
493 }
494 }
495
496 if (CRM.batch.type_id == 3){
497 cj('select[id*="open_pledges_"]').change(function () {
498 setPledgeAmount(cj(this), cj(this).val());
499 });
500 cj('.pledge-adjust-option').click(function(){
501 var blockNo = cj(this).attr('id');
502 cj('select[id="option_type_' + blockNo + '"]').show();
503 cj('select[id="option_type_' + blockNo + '"]').removeAttr('disabled');
504 cj('#field_' + blockNo + '_total_amount').removeAttr('readonly');
505 });
506 }
507
508 function setPledgeAmount(form, pledgeID) {
509 var rowID = form.closest('div.crm-grid-row').attr('entity_id');
510 var dataUrl = CRM.url('civicrm/ajax/pledgeAmount');
511 if (pledgeID) {
512 cj.post(dataUrl, {pid: pledgeID}, function (data) {
513 cj('#field_' + rowID + '_financial_type').val(data.financial_type_id).change();
514 cj('#field_' + rowID + '_total_amount').val(data.amount).change();
515 cj('#field_' + rowID + '_total_amount').attr('readonly', true);
516 }, 'json');
517 }
518 else {
519 cj('#field_' + rowID + '_total_amount').val('').change();
520 cj('#field_' + rowID + '_financial_type').val('').change();
521 cj('#field_' + rowID + '_total_amount').removeAttr('readonly');
522 }
523 }
524
525 //end for pledge amount
526 </script>
527 {/literal}
528 {*include batch copy js js file*}
529 {include file="CRM/common/batchCopy.tpl"}