3 * Copyright © 2003-2024 The Galette Team
5 * This file is part of Galette (https://galette.eu).
7 * Galette is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Galette is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
21 {% extends (mode == 'ajax') ? "ajax.html.twig" : "page.html.twig" %}
24 {% if members.list is defined or require_mass %}
25 {% if mode != 'ajax' %}
26 <form action="{% if contribution.id %}{{ url_for("doEditContribution", {"type": type, "id": contribution.id}) }}{% else %}{{ url_for("doAddContribution", {"type": type}) }}{% endif %}" enctype="multipart/form-data" method="post" class="ui form">
28 <div class="ui styled fluid accordion field">
29 <div class="active title">
30 <i class="jsonly displaynone icon dropdown" aria-hidden="true"></i>
31 {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}
32 {{ _T("Select contributor and membership fee type") }}
34 {{ _T("Select contributor and donation type") }}
36 {% if contribution.isTransactionPart() %}
37 <span class="ui teal horizontal label">
38 {{ _T("Transaction related") }}
41 {% if contribution.hasSchedule() %}
42 <span class="ui teal horizontal label">
43 {{ _T("Has scheduled payments") }}
47 <div class="active content">
48 <div class="ui mobile reversed stackable grid">
49 <div class="{% if contribution.isTransactionPart() %}six wide {% endif %}column">
50 {% if not require_mass %}
51 <div class="inline field">
52 <label for="id_adh">{{ _T("Contributor:") }}</label>
53 <div id="id_adh" class="jsonly search-dropdown ui input paginated">
54 <input id="id_adh_input" type="hidden" name="id_adh" value="{{ contribution.member is not null ? contribution.member }}" placeholder="{{ _T("Member ID") }}">
55 <i class="jsonly displaynone dropdown icon" aria-hidden="true"></i>
56 <span class="ui mini compact icon disabled button prev-results"><i class="jsonly displaynone chevron circle left icon disabled button tooltip" title="{{ _T("Load previous members...") }}" aria-hidden="true"></i></span>
57 <span class="ui mini compact icon disabled button next-results"><i class="jsonly displaynone chevron circle right icon disabled button tooltip" title="{{ _T("Load following members...") }}" aria-hidden="true"></i></span>
58 <div class="jsonly displaynone default text">{{ _T("Search for name or ID and pick member") }}</div>
59 <div class="jsonly displaynone menu">
60 {% for k, v in members.list %}
61 <div class="item" data-value="{{ k }}">{{ v }}</div>
67 <div class="inline field{% if required.id_type_cotis is defined and required.id_type_cotis == 1 %} required{% endif %}">
68 <label for="id_type_cotis">{{ _T("Contribution type:") }}</label>
69 <div id="id_type_cotis" class="ui dropdown selection">
70 {% if contribution.type %}
71 {% set selectedid = contribution.type.id %}
73 {% set selectedid = null %}
75 <input id="id_type_cotis_input" type="hidden" name="id_type_cotis" value="{{ selectedid }}"{% if required.id_type_cotis is defined and required.id_type_cotis == 1 %} required="required"{% endif %}>
76 <i class="dropdown icon"></i>
77 <div class="text">{% for key, values in type_cotis_options %}{% if key == selectedid %}{{ values.label }}{% endif %}{% endfor %}</div>
79 {% for key, values in type_cotis_options %}
80 <div class="item{% if key == selectedid %} active selected{% endif %}" data-value="{{ key }}">{{ values.label }}</div>
86 {% if contribution.isTransactionPart() or contribution.hasSchedule() %}
87 <div class="ten wide column">
88 {% if contribution.isTransactionPart() %}
89 <div class="ui yellow segment">
90 <div class="ui tiny header">
92 href="{{ url_for("editTransaction", {"id": contribution.transaction.id}) }}"
93 class="ui mini icon blue compact button tooltip"
95 <i class="eye icon tooltip" aria-hidden="true"></i>
96 <span class="ui special popup">{{ _T("View transaction") }}</span>
98 {{ _T("Related transaction information") }}
100 <div class="content">
101 <div class="ui relaxed horizontal list">
103 <div class="content">
104 <div class="header">{{ _T("Date") }}</div>
105 {{ contribution.transaction.date }}
109 <div class="content">
110 <div class="header">{{ _T("Member") }}</div>
111 {{ memberName({'id': contribution.transaction.member}) }}
115 <div class="content">
116 <div class="header">{{ _T("Amount") }}</div>
117 {{ contribution.transaction.amount }}
120 {% if contribution.transaction.getMissingAmount() > 0 %}
122 <div class="content">
123 <div class="header">{{ _T("Not dispatched amount") }}</div>
124 {{ contribution.transaction.getMissingAmount() }}
125 {% if contribution.id != '' %}
127 href="{{ url_for("addContribution", {"type": constant('Galette\\Entity\\Contribution::TYPE_FEE')}) }}?trans_id={{ contribution.transaction.id }}"
128 class="ui mini icon green compact button tooltip"
129 title="{{ _T("Create a new fee that will be attached to the current transaction") }}"
131 <i class="plus tiny icon" aria-hidden="true"></i>
132 <i class="user check icon" aria-hidden="true"></i>
133 <span class="visually-hidden">{{ _T("Create a new fee that will be attached to the current transaction") }}</span>
136 href="{{ url_for("addContribution", {"type": constant('Galette\\Entity\\Contribution::TYPE_DONATION')}) }}?trans_id={{ contribution.transaction.id }}"
137 class="ui mini icon green compact button tooltip"
138 title="{{ _T("Create a new donation that will be attached to the current transaction") }}"
140 <i class="plus tiny icon" aria-hidden="true"></i>
141 <i class="gift icon" aria-hidden="true"></i>
142 <span class="visually-hidden">{{ _T("Create a new donation that will be attached to the current transaction") }}</span>
149 {% if contribution.id == '' %}
150 <div class="inline field">
151 <label>{{ _T("Dispatch type:") }}</label>
152 <i class="circular inverted primary small icon info tooltip" title="{{ _T("Select a contribution type to create for dispatch transaction") }}" aria-hidden="true"></i>
153 <input type="radio" name="contrib_type" id="contrib_type_fee" value="{{ constant('Galette\\Entity\\Contribution::TYPE_FEE') }}"{% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %} checked="checked"{% endif %}/> <label for="contrib_type_fee">{{ _T("Membership fee") }}</label>
154 <input type="radio" name="contrib_type" id="contrib_type_donation" value="{{ constant('Galette\\Entity\\Contribution::TYPE_DONATION') }}"{% if type == constant('Galette\\Entity\\Contribution::TYPE_DONATION') %} checked="checked"{% endif %}/> <label for="contrib_type_donation">{{ _T("Donation") }}</label>
160 {% if contribution.hasSchedule() %}
161 {% set scheduled_amount = scheduled.getAllocation(contribution.id) %}
162 <div class="ui yellow segment">
163 <div class="ui tiny header">
166 class="ui mini icon blue compact button tooltip"
169 <i class="eye icon tooltip" aria-hidden="true"></i>
170 <span class="ui special popup">{{ _T("View scheduled payments") }}</span>
172 {{ _T("Scheduled payments") }}
174 {% if not contribution.isScheduleFullyAllocated() %}
175 <div class="content">
176 <div class="ui relaxed horizontal list">
178 <div class="content">
179 <div class="header">{{ _T("Amount") }}</div>
180 {{ scheduled_amount }}
184 <div class="content">
185 <div class="header">{{ _T("Not dispatched amount") }}</div>
186 {{ contribution.amount - scheduled_amount }}
188 href="{{ url_for("addScheduledPayment", {"id_cotis": contribution.id}) }}"
189 class="ui mini icon green compact button tooltip"
190 title="{{ _T("Create a new scheduled payment") }}"
192 <i class="plus tiny icon" aria-hidden="true"></i>
193 <i class="money bill wave icon" aria-hidden="true"></i>
194 <span class="visually-hidden">{{ _T("Create a new scheduled payment") }}</span>
209 <div class="ui styled fluid accordion field">
210 <div class="active title">
211 <i class="jsonly displaynone icon dropdown" aria-hidden="true"></i>
212 {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}
213 {{ _T("Details of membership fee") }}
215 {{ _T("Details of donation") }}
218 <div class="active content field">
219 <div id="contribdetails" class="ui basic fitted segment">
220 <div class="two fields">
221 <div class="field{% if required.montant_cotis is defined and required.montant_cotis == 1 %} required{% endif %}">
222 <label for="montant_cotis">{{ _T("Amount:") }}</label>
223 <input type="text" name="montant_cotis" id="montant_cotis" value="{{ contribution.amount }}" maxlength="10"{% if required.montant_cotis is defined and required.montant_cotis == 1 %} required="required"{% endif %}/>
226 {% set ptype = contribution.payment_type %}
227 {% if ptype == null %}
228 {% set ptype = preferences.pref_default_paymenttype %}
230 {% include 'components/forms/payment_types.html.twig' with {
232 'varname': 'type_paiement_cotis',
233 'disabled': contribution.hasSchedule()
236 <div class="{% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}three{% else %}two{% endif %} fields">
237 <div class="field{% if required.date_enreg is defined and required.date_enreg == 1 %} required{% endif %}">
238 <label for="date_enreg">
239 {{ _T("Record date:") }}
241 <div class="ui calendar" id="contribution-rangestart">
242 <div class="ui input left icon">
243 <i class="calendar icon" aria-hidden="true"></i>
244 <input type="text" name="date_enreg" id="date_enreg" value="{{ contribution.date }}" maxlength="10"{% if required.date_enreg is defined and required.date_enreg == 1 %} required="required"{% endif %} placeholder="{{ _T('yyyy-mm-dd format') }}" />
248 <div class="field{% if required.date_debut_cotis is defined and required.date_debut_cotis == 1 %} required{% endif %}">
249 <label for="date_debut_cotis">
250 {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}
251 {{ _T("Start date of membership:") }}
253 {{ _T("Date of contribution:") }}
256 <div class="ui calendar" id="contribution-rangeend">
257 <div class="ui input left icon">
258 <i class="calendar icon" aria-hidden="true"></i>
259 <input type="text" name="date_debut_cotis" id="date_debut_cotis" value="{{ contribution.begin_date }}" maxlength="10"{% if required.date_debut_cotis == 1 %} required="required"{% endif %} placeholder="{{ _T('yyyy-mm-dd format') }}" />
263 {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}
264 <div class="field{% if required.date_fin_cotis is defined and required.date_fin_cotis == 1 %} required{% endif %}">
265 {% if preferences.pref_membership_ext != "" %}
266 <label for="duree_mois_cotis">{{ _T("Membership extension:") }}</label>
267 <input type="text" name="duree_mois_cotis" id="duree_mois_cotis" value="{{ contribution.duration }}" maxlength="3"{% if required.date_fin_cotis is defined and required.date_fin_cotis == 1 %} required="required"{% endif %}/>
268 <span class="exemple">{{ _T("months") }}</span>
270 <label for="date_fin_cotis">{{ _T("End date of membership:") }}</label>
271 <div class="ui calendar" id="membership-rangeend">
272 <div class="ui input left icon">
273 <i class="calendar icon" aria-hidden="true"></i>
274 <input type="text" name="date_fin_cotis" id="date_fin_cotis" value="{{ contribution.end_date }}" maxlength="10"{% if required.date_fin_cotis is defined and required.date_fin_cotis == 1 %} required="required"{% endif %} placeholder="{{ _T('yyyy-mm-dd format') }}" />
281 <div class="field{% if required.info_cotis is defined and required.info_cotis == 1 %} required{% endif %}">
282 <label for="info_cotis">{{ _T("Comments:") }}</label>
283 <textarea name="info_cotis" id="info_cotis" cols="61" rows="6"{% if required.info_cotis is defined and required.info_cotis == 1 %} required="required"{% endif %}>{{ contribution.info }}</textarea>
289 {% include 'components/dynamic_fields.html.twig' with {'object': contribution} %}
291 {% if not contribution.id and preferences.pref_mail_method != constant('Galette\\Core\\GaletteMail::METHOD_DISABLED') %}
292 {% if not require_mass %}
293 <div class="ui center aligned yellow segment">
294 <div class="inline field">
295 <div class="ui toggle checkbox">
296 <input type="checkbox" name="mail_confirm" id="mail_confirm" value="1"{% if preferences.pref_bool_mailowner or contribution.sendEMail() %} checked="checked"{% endif %}/>
297 <label for="mail_confirm">
298 {{ _T("Notify member") }}
301 <span class="exemple">
302 {{ _T("Member will receive a notification by email, if he has an address.") }}
309 {% if not require_mass %}
310 <div class="ui basic center aligned segment">
311 <button type="submit" name="valid" class="ui labeled icon primary button action">
312 <i class="save icon" aria-hidden="true"></i> {{ _T("Save") }}
314 <input type="hidden" name="id_cotis" value="{{ contribution.id }}"/>
315 <input type="hidden" name="valid" value="1"/>
316 <input type="hidden" name="trans_id" value="{% if contribution.transaction != NULL %}{{ contribution.transaction.id }}{% endif %}"/>
319 {% if mode != 'ajax' %}
320 {% include "components/forms/csrf.html.twig" %}
323 {% elseif mode != 'ajax' %} {# No members #}
324 <div class="ui warning message" id="warningbox">
325 <h3>{{ _T("No member registered!") }}</h3>
327 {{ _T("Unfortunately, there is no member in your database yet,") }}
329 <a href="{{ url_for("addMember") }}">{{ _T("please create a member") }}</a>
335 {% block javascripts %}
336 <script type="text/javascript">
337 {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') and not contribution.id %}
338 {% include "elements/js/choose_adh.js.twig" with {
339 new_contrib_onchange: true
342 {% include "elements/js/choose_adh.js.twig" %}
346 {% if not contribution.id -%}
347 var _types_amounts = {
348 {%- for key, values in type_cotis_options -%}
349 {%- if values.amount > 0 -%}
350 {{ key }}: {{ values.amount }},
354 $('#id_type_cotis').dropdown({
355 onChange: function(value) {
356 //change to predefined amout if there is one, and if user has not entered data himself
357 if ($('#montant_cotis').data('userset') != true && _types_amounts[value]) {
358 var _amount = _types_amounts[value];
359 alert('Changed to ' + _amount);
363 $('#montant_cotis').on('keyup', function() {
364 //keep trace of user entered data
365 if ($(this).val() == '') {
366 $(this).data('userset', false);
368 $(this).data('userset', true);
373 {% if contribution.isTransactionPart() and contribution.transaction.getMissingAmount() %}
374 $('#transaction_related').hide();
375 $('#montant_cotis').on('change', function() {
376 var _amount = {{ contribution.transaction.getMissingAmount() }};
377 var _current = $(this).val();
378 if (_current < _amount) {
379 $('#transaction_related').show();
380 } else if (_current > _amount) {
381 {% include "elements/js/modal.js.twig" with {
382 modal_title_twig: _T("Contribution amount should not be greater than %max")|replace({'%max': contribution.transaction.getMissingAmount()})|e("js"),
383 modal_without_content: true,
385 modal_deny_only: true,
386 modal_cancel_text: _T("Close")|e("js"),
387 modal_classname: "redalert",
390 $('#transaction_related').hide();
395 {% if contribution.hasSchedule() %}
396 {# Contributions popup #}
397 var _btnuser_mapping = function(){
398 $('#scheduledslist').click(function(){
400 url: '{{ url_for("scheduledPayments") }}',
404 id_cotis: '{{ contribution.id }}'
406 {% include "elements/js/loader.js.twig" with {
407 selector: '#scheduledslist',
410 success: function(res){
411 _contribs_dialog(res, '{{ contribution.id }}');
414 {% include "elements/js/modal.js.twig" with {
415 modal_title_twig: _T("An error occurred displaying scheduled payments :(")|e("js"),
416 modal_without_content: true,
418 modal_deny_only: true,
419 modal_cancel_text: _T("Close")|e("js"),
420 modal_classname: "redalert",
428 var _contribs_dialog = function(res, id_cotis){
429 {% include "elements/js/modal.js.twig" with {
430 modal_title_twig: _T("Scheduled payments")|e("js"),
431 modal_content: "res",
432 modal_class: "scheduledpayments fullscreen",
433 modal_content_class: "scrolling",
434 modal_deny_only: true,
435 modal_cancel_text: _T("Close")|e('js')
437 _contribs_ajax_mapper(res, id_cotis);
440 var _contribs_ajax_mapper = function(res, id_cotis){
441 /*$('.scheduledpayments .filter.icon').remove();
442 $('.scheduledpayments .infoline .button').remove();
443 $('.scheduledpayments .contribution_row input[type=checkbox]').hide();
445 //Initialize Fomantic components
446 $('.scheduledpayments .dropdown').dropdown();
447 {% include "elements/js/calendar.js.twig" %}
449 //Deactivate contributions list links
450 $('.scheduledpayments tbody a').click(function(){
451 //for links in body (members links), we de nothing
455 //Use JS to send forms
456 $('.scheduledpayments form').on('submit', function(){
459 url: _form.attr('action'),
461 data: _form.serialize(),
462 {% include "elements/js/loader.js.twig" with {
463 selector: '.scheduledpayments'
465 success: function(res){
466 $('#main-container').remove();
467 $('.scheduledpayments .content').append(res);
468 _contribs_ajax_mapper(res, max_amount);
471 {% include "elements/js/modal.js.twig" with {
472 modal_title_twig: _T("An error occurred displaying contributions :(")|e("js"),
473 modal_without_content: true,
475 modal_deny_only: true,
476 modal_cancel_text: _T("Close")|e("js"),
477 modal_classname: "redalert",
484 _bindDropdownsAutosubmit();*/
486 //Bind pagination and ordering links
487 /*$('.scheduledpayments .pagination a, .scheduledpayments thead a').click(function() {
493 max_amount: max_amount
495 {% include "elements/js/loader.js.twig" with {
496 selector: '.scheduledpayments'
498 success: function(res){
499 $('#main-container').remove();
500 $('.scheduledpayments .content').append(res);
501 _contribs_ajax_mapper(res, max_amount);
504 {% include "elements/js/modal.js.twig" with {
505 modal_title_twig: _T("An error occurred displaying contributions :(")|e("js"),
506 modal_without_content: true,
508 modal_deny_only: true,
509 modal_cancel_text: _T("Close")|e("js"),
510 modal_classname: "redalert",
517 //Bind reset filters button
518 /*$('#clear_filter').click(function(event) {
520 _this.closest('form').submit(function(event) {
523 url: _form.attr('action'),
528 {% include "elements/js/loader.js.twig" with {
529 selector: '.scheduledpayments'
531 success: function(res){
532 $('#main-container').remove();
533 $('.scheduledpayments .content').append(res);
534 _contribs_ajax_mapper(res, max_amount);
537 {% include "elements/js/modal.js.twig" with {
538 modal_title_twig: _T("An error occurred displaying contributions :(")|e("js"),
539 modal_without_content: true,
541 modal_deny_only: true,
542 modal_cancel_text: _T("Close")|e("js"),
543 modal_classname: "redalert",