Merge remote-tracking branch 'upstream/4.4' into 4.4-master-2014-01-13-11-57-38
[civicrm-core.git] / templates / CRM / Batch / Form / Entry.tpl
1 {*
2 +--------------------------------------------------------------------+
3 | CiviCRM version 4.4 |
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC (c) 2004-2013 |
6 +--------------------------------------------------------------------+
7 | This file is a part of CiviCRM. |
8 | |
9 | CiviCRM is free software; you can copy, modify, and distribute it |
10 | under the terms of the GNU Affero General Public License |
11 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
12 | |
13 | CiviCRM is distributed in the hope that it will be useful, but |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
16 | See the GNU Affero General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Affero General Public |
19 | License and the CiviCRM Licensing Exception along |
20 | with this program; if not, contact CiviCRM LLC |
21 | at info[AT]civicrm[DOT]org. If you have questions about the |
22 | GNU Affero General Public License or the licensing of CiviCRM, |
23 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
24 +--------------------------------------------------------------------+
25 *}
26 <div class="batch-entry form-item">
27 <div id="help">
28 {ts}Click Validate & Process below when you've entered all items for the batch. You can also Save & Continue Later at any time. Go to Administer > Customize Data and Screens > Profiles > Reserved Profiles > to add, remove or change the order of columns.{/ts}
29 </div>
30 {if $batchAmountMismatch}
31 <div class="status message status-warning">
32 <div
33 class="icon alert-icon"></div> {ts}Total for amounts entered below does not match the expected batch total.{/ts}
34 </div>
35 <div class="crm-button crm-button_qf_Entry_upload_force-save">
36 {$form._qf_Entry_upload_force.html}
37 </div>
38 <div class="clear"></div>
39 {/if}
40 <table class="form-layout-compressed batch-totals">
41 <tr>
42 <td class="label">{ts}Total amount expected{/ts}</td>
43 <td class="right"><span class="batch-expected-total">{$batchTotal|crmMoney}</span></td>
44 </tr>
45 <tr>
46 <td class="label">{ts}Total amount entered{/ts}</td>
47 <td class="right">{$config->defaultCurrencySymbol} <span class="batch-actual-total"></span></td>
48 </tr>
49 </table>
50
51 <div class="crm-copy-fields crm-grid-table" id="crm-batch-entry-table">
52 <div class="crm-grid-header">
53 <div class="crm-grid-cell">&nbsp;</div>
54 <div class="crm-grid-cell">{ts}Contact{/ts}</div>
55 {if $batchType eq 2 }
56 <div class="crm-grid-cell">&nbsp;</div>
57 {/if}
58 {foreach from=$fields item=field key=fieldName}
59 <div class="crm-grid-cell">
60 <img src="{$config->resourceBase}i/copy.png"
61 alt="{ts 1=$field.title}Click to copy %1 from row one to all rows.{/ts}"
62 fname="{$field.name}" class="action-icon"
63 title="{ts}Click here to copy the value in row one to ALL rows.{/ts}"/>{$field.title}
64 </div>
65 {/foreach}
66 </div>
67
68 {section name='i' start=1 loop=$rowCount}
69 {assign var='rowNumber' value=$smarty.section.i.index}
70 <div class="{cycle values="odd-row,even-row"} selector-rows crm-grid-row" entity_id="{$rowNumber}">
71 <div class="compressed crm-grid-cell"><span class="batch-edit"></span></div>
72 {* contact select/create option*}
73 <div class="compressed crm-grid-cell">
74 {include file="CRM/Contact/Form/NewContact.tpl" blockNo = $rowNumber noLabel=true prefix="primary_" newContactCallback="updateContactInfo($rowNumber, 'primary_')"}
75 </div>
76
77 {if $batchType eq 2 }
78 {$form.member_option.$rowNumber.html}
79 {/if}
80
81 {foreach from=$fields item=field key=fieldName}
82 {assign var=n value=$field.name}
83 {if ( $fields.$n.data_type eq 'Date') or ( in_array( $n, array( 'thankyou_date', 'cancel_date', 'receipt_date', 'receive_date', 'join_date', 'membership_start_date', 'membership_end_date' ) ) ) }
84 <div class="compressed crm-grid-cell">
85 <span class="crm-batch-{$n}-{$rowNumber}">
86 {include file="CRM/common/jcalendar.tpl" elementName=$n elementIndex=$rowNumber batchUpdate=1}
87 </span>
88 </div>
89 {elseif $n eq 'soft_credit'}
90 <div class="compressed crm-grid-cell">
91 {include file="CRM/Contact/Form/NewContact.tpl" blockNo = $rowNumber noLabel=true prefix="soft_credit_"}
92 {$form.soft_credit_amount.$rowNumber.label}&nbsp;{$form.soft_credit_amount.$rowNumber.html|crmAddClass:eight}
93 </div>
94 {elseif in_array( $fields.$n.html_type, array('Radio', 'CheckBox'))}
95 <div class="compressed crm-grid-cell">&nbsp;{$form.field.$rowNumber.$n.html}</div>
96 {else}
97 <div class="compressed crm-grid-cell">{$form.field.$rowNumber.$n.html}</div>
98 {/if}
99 {/foreach}
100 </div>
101 {/section}
102 </div>
103 <div class="crm-submit-buttons">{if $fields}{$form._qf_Batch_refresh.html}{/if} &nbsp; {$form.buttons.html}</div>
104 </div>
105 {literal}
106 <script type="text/javascript">
107 cj(function () {
108 cj('.selector-rows').change(function () {
109 var options = {
110 'url': {/literal}"{crmURL p='civicrm/ajax/batch' h=0}"{literal}
111 };
112
113 cj("#Entry").ajaxSubmit(options);
114 });
115
116 cj('#crm-container').on('keyup change', '*.selector-rows', function () {
117 // validate rows
118 checkColumns(cj(this));
119 });
120
121 // validate rows
122 validateRow();
123
124 //calculate the actual total for the batch
125 calculateActualTotal();
126
127 cj('input[id*="_total_amount"]').bind('keyup change', function () {
128 calculateActualTotal();
129 });
130
131 {/literal}{if $batchType eq 1 }{literal}
132 // hide all dates if send receipt is checked
133 hideSendReceipt();
134
135 // hide the receipt date if send receipt is checked
136 cj('input[id*="][send_receipt]"]').change(function () {
137 showHideReceipt(cj(this));
138 });
139
140 {/literal}{else}{literal}
141 cj('select[id^="member_option_"]').each(function () {
142 if (cj(this).val() == 1) {
143 cj(this).prop('disabled', true);
144 }
145 });
146
147 // set payment info accord to membership type
148 cj('select[id*="_membership_type_0"]').change(function () {
149 setPaymentBlock(cj(this), null);
150 });
151
152 cj('select[id*="_membership_type_1"]').change(function () {
153 setPaymentBlock(cj(this), cj(this).val());
154 });
155
156 {/literal}{/if}{literal}
157
158 // line breaks between radio buttons and checkboxes
159 cj('input.form-radio').next().after('<br />');
160 cj('input.form-checkbox').next().after('<br />');
161
162 //set the focus on first element
163 cj('#primary_contact_1').focus();
164
165 });
166
167 function setPaymentBlock(form, memType) {
168 var rowID = form.closest('div.crm-grid-row').attr('entity_id');
169 var dataUrl = {/literal}"{crmURL p='civicrm/ajax/memType' h=0}"{literal};
170
171 if (!memType) {
172 memType = cj('select[id="field_' + rowID + '_membership_type_1"]').val();
173 }
174
175 cj.post(dataUrl, {mtype: memType}, function (data) {
176 cj('#field_' + rowID + '_financial_type').val(data.financial_type_id);
177 cj('#field_' + rowID + '_total_amount').val(data.total_amount).change();
178 }, 'json');
179 }
180
181 function hideSendReceipt() {
182 cj('input[id*="][send_receipt]"]').each(function () {
183 showHideReceipt(cj(this));
184 });
185 }
186
187 function showHideReceipt(elem) {
188 var rowID = elem.closest('div.crm-grid-row').attr('entity_id');
189 if (elem.prop('checked')) {
190 cj('.crm-batch-receipt_date-' + rowID).hide();
191 }
192 else {
193 cj('.crm-batch-receipt_date-' + rowID).show();
194 }
195 }
196
197 function validateRow() {
198 cj('.selector-rows').each(function () {
199 checkColumns(cj(this));
200 });
201 }
202
203 function checkColumns(parentRow) {
204 // show valid row icon if all required data is field
205 var validRow = 0;
206 var inValidRow = 0;
207 var errorExists = false;
208 var rowID = parentRow.closest('div.crm-grid-row').attr('entity_id');
209
210 parentRow.find('div .required').each(function () {
211 //special case to handle contact autocomplete select
212 var fieldId = cj(this).attr('id');
213 if (fieldId.substring(0, 16) == 'primary_contact_') {
214 // if display value is set then make sure we also check if contact id is set
215 if (!cj(this).val()) {
216 inValidRow++;
217 }
218 else {
219 var contactIdElement = cj('input[name="primary_contact_select_id[' + rowID + ']"]');
220 if (cj(this).val() && !contactIdElement.val()) {
221 inValidRow++;
222 errorExists = true;
223 }
224 else if (cj(this).val() && contactIdElement.val()) {
225 // this is hack to remove error span because we are skipping this for autocomplete fields
226 cj(this).next('span.crm-error').remove();
227 }
228 }
229 }
230 else {
231 if (!cj(this).val()) {
232 inValidRow++;
233 }
234 else {
235 if (cj(this).hasClass('error') && (cj(this).hasClass('valid') || cj(this).hasClass('required'))) {
236 errorExists = true;
237 }
238 else {
239 validRow++;
240 }
241 }
242 }
243 });
244
245 // this means user has entered some data
246 if (errorExists) {
247 parentRow.find("div:first span").prop('class', 'batch-invalid');
248 }
249 else {
250 if (inValidRow == 0 && validRow > 0) {
251 parentRow.find("div:first span").prop('class', 'batch-valid');
252 }
253 else {
254 parentRow.find("div:first span").prop('class', 'batch-edit');
255 }
256 }
257 }
258
259 function calculateActualTotal() {
260 var total = 0;
261 cj('input[id*="_total_amount"]').each(function () {
262 if (cj(this).val()) {
263 total += parseFloat(cj(this).val());
264 }
265 });
266
267 cj('.batch-actual-total').html(formatMoney(total));
268 }
269
270 //money formatting/localization
271 function formatMoney(amount) {
272 var c = 2;
273 var t = '{/literal}{$config->monetaryThousandSeparator}{literal}';
274 var d = '{/literal}{$config->monetaryDecimalPoint}{literal}';
275
276 var n = amount,
277 c = isNaN(c = Math.abs(c)) ? 2 : c,
278 d = d == undefined ? "," : d,
279 t = t == undefined ? "." : t, s = n < 0 ? "-" : "",
280 i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
281 j = (j = i.length) > 3 ? j % 3 : 0;
282
283 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) : "");
284 }
285
286 function updateContactInfo(blockNo, prefix) {
287 var contactHiddenElement = 'input[name="' + prefix + 'contact_select_id[' + blockNo + ']"]';
288 var contactId = cj(contactHiddenElement).val();
289
290 var returnProperties = '';
291 var profileFields = new Array();
292 {/literal}
293 {if $contactFields}
294 {foreach from=$contactFields item=val key=fldName}
295 var fldName = "{$fldName}";
296 {literal}
297 if (returnProperties) {
298 returnProperties = returnProperties + ',';
299 }
300 var fld = fldName.split('-');
301 returnProperties = returnProperties + fld[0];
302 profileFields[fld[0]] = fldName;
303 {/literal}
304 {/foreach}
305 {/if}
306 {literal}
307
308 CRM.api('Contact', 'get', {
309 'sequential': '1',
310 'contact_id': contactId,
311 'return': returnProperties },
312 { success: function (data) {
313 cj.each(data.values[0], function (key, value) {
314 // set the values
315 var actualFldName = profileFields[key];
316 if (key == 'country' || key == 'state_province') {
317 idFldName = key + '_id';
318 value = data.values[0][idFldName];
319 }
320 setFieldValue(actualFldName, value, blockNo)
321 });
322
323 // for membership batch entry based on contact we need to enable / disable
324 // add membership select
325 {/literal}{if $batchType eq 2}{literal}
326 CRM.api('Membership', 'get', {
327 'sequential': '1',
328 'contact_id': contactId,
329 },
330 { success: function (data) {
331 if (data.count > 0) {
332 //get the information on membership type
333 var membershipTypeId = data.values[0].membership_type_id;
334 var membershipJoinDate = data.values[0].join_date;
335 CRM.api('MembershipType', 'get', {
336 'sequential': '1',
337 'id': membershipTypeId
338 },
339 { success: function (data) {
340 var memTypeContactId = data.values[0].member_of_contact_id;
341 cj('select[id="member_option_' + blockNo + '"]').prop('disabled', false).val(2);
342 cj('select[id="field_' + blockNo + '_membership_type_0"]').val(memTypeContactId).change();
343 cj('select[id="field_' + blockNo + '_membership_type_1"]').val(membershipTypeId).change();
344 setDateFieldValue('join_date', membershipJoinDate, blockNo)
345 }
346 });
347 }
348 }
349 });
350 {/literal}{/if}{literal}
351 }
352 });
353 }
354
355 /**
356 * This function is use to setdefault elements via ajax
357 *
358 * @param fname string field name
359 * @return void
360 */
361 function setFieldValue(fname, fieldValue, blockNo) {
362 var elementId = cj('[name="field[' + blockNo + '][' + fname + ']"]');
363
364 if (elementId.length == 0) {
365 elementId = cj('input[type=checkbox][name^="field[' + blockNo + '][' + fname + ']"][type!=hidden]');
366 }
367
368 // if element not found than return
369 if (elementId.length == 0) {
370 return;
371 }
372
373 //check if it is date element
374 var isDateElement = elementId.attr('format');
375
376 // check if it is wysiwyg element
377 var editor = elementId.attr('editor');
378
379 //get the element type
380 var elementType = elementId.attr('type');
381
382 // set the value for all the elements, elements needs to be handled are
383 // select, checkbox, radio, date fields, text, textarea, multi-select
384 // wysiwyg editor, advanced multi-select ( to do )
385 if (elementType == 'radio') {
386 if (fieldValue) {
387 elementId.filter("[value=" + fieldValue + "]").prop("checked", true);
388 }
389 else {
390 elementId.removeProp('checked');
391 }
392 }
393 else {
394 if (elementType == 'checkbox') {
395 // handle checkbox
396 elementId.removeProp('checked');
397 if (fieldValue) {
398 cj.each(fieldValue, function (key, value) {
399 cj('input[name="field[' + blockNo + '][' + fname + '][' + value + ']"]').prop('checked', true);
400 });
401 }
402 }
403 else {
404 if (editor) {
405 switch (editor) {
406 case 'ckeditor':
407 var elemtId = elementId.attr('id');
408 oEditor = CKEDITOR.instances[elemtId];
409 oEditor.setData(htmlContent);
410 break;
411 case 'tinymce':
412 var elemtId = element.attr('id');
413 tinyMCE.get(elemtId).setContent(htmlContent);
414 break;
415 case 'joomlaeditor':
416 // TO DO
417 case 'drupalwysiwyg':
418 // TO DO
419 default:
420 elementId.val(fieldValue);
421 }
422 }
423 else {
424 elementId.val(fieldValue);
425 }
426 }
427 }
428
429 // since we use different display field for date we also need to set it.
430 // also check for date time field and set the value correctly
431 if (isDateElement && fieldValue) {
432 setDateFieldValue(fname, fieldValue, blockNo)
433 }
434 }
435
436 function setDateFieldValue(fname, fieldValue, blockNo) {
437 var dateValues = fieldValue.split(' ');
438
439 var actualDateElement = cj('#field_' + blockNo + '_' + fname);
440 var date_format = actualDateElement.attr('format');
441 var altDateFormat = 'yy-mm-dd';
442
443 var actualDateValue = cj.datepicker.parseDate(altDateFormat, dateValues[0]);
444
445 // format date according to display field
446 var hiddenDateValue = cj.datepicker.formatDate('mm/dd/yy', actualDateValue);
447
448 actualDateElement.val(hiddenDateValue);
449
450 var displayDateValue = actualDateElement.val();
451 if (date_format != 'mm/dd/yy') {
452 displayDateValue = cj.datepicker.formatDate(date_format, actualDateValue);
453 }
454
455 cj('#field_' + blockNo + '_' + fname + '_display').val(displayDateValue);
456
457 // need to fix time formatting
458 if (dateValues[1]) {
459 cj('#field_' + blockNo + '_' + fname + '_time').val(dateValues[1].substr(0, 5));
460 }
461 }
462
463 </script>
464 {/literal}
465
466 {*include batch copy js js file*}
467 {include file="CRM/common/batchCopy.tpl"}