mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-31 07:49:57 +01:00 
			
		
		
		
	Credit/debit support
This commit is contained in:
		
				
					committed by
					
						 Bombar Maxime
						Bombar Maxime
					
				
			
			
				
	
			
			
			
						parent
						
							321927ba1e
						
					
				
				
					commit
					040bb27528
				
			| @@ -6,7 +6,7 @@ from rest_polymorphic.serializers import PolymorphicSerializer | |||||||
|  |  | ||||||
| from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias | from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias | ||||||
| from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \ | from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \ | ||||||
|     TemplateTransaction |     TemplateTransaction, SpecialTransaction | ||||||
|  |  | ||||||
|  |  | ||||||
| class NoteSerializer(serializers.ModelSerializer): | class NoteSerializer(serializers.ModelSerializer): | ||||||
| @@ -144,9 +144,21 @@ class MembershipTransactionSerializer(serializers.ModelSerializer): | |||||||
|         fields = '__all__' |         fields = '__all__' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SpecialTransactionSerializer(serializers.ModelSerializer): | ||||||
|  |     """ | ||||||
|  |     REST API Serializer for Special transactions. | ||||||
|  |     The djangorestframework plugin will analyse the model `SpecialTransaction` and parse all fields in the API. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     class Meta: | ||||||
|  |         model = SpecialTransaction | ||||||
|  |         fields = '__all__' | ||||||
|  |  | ||||||
|  |  | ||||||
| class TransactionPolymorphicSerializer(PolymorphicSerializer): | class TransactionPolymorphicSerializer(PolymorphicSerializer): | ||||||
|     model_serializer_mapping = { |     model_serializer_mapping = { | ||||||
|         Transaction: TransactionSerializer, |         Transaction: TransactionSerializer, | ||||||
|         TemplateTransaction: TemplateTransactionSerializer, |         TemplateTransaction: TemplateTransactionSerializer, | ||||||
|         MembershipTransaction: MembershipTransactionSerializer, |         MembershipTransaction: MembershipTransactionSerializer, | ||||||
|  |         SpecialTransaction: SpecialTransactionSerializer, | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -165,7 +165,6 @@ class Transaction(PolymorphicModel): | |||||||
| class TemplateTransaction(Transaction): | class TemplateTransaction(Transaction): | ||||||
|     """ |     """ | ||||||
|     Special type of :model:`note.Transaction` associated to a :model:`note.TransactionTemplate`. |     Special type of :model:`note.Transaction` associated to a :model:`note.TransactionTemplate`. | ||||||
|  |  | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     template = models.ForeignKey( |     template = models.ForeignKey( | ||||||
| @@ -183,6 +182,27 @@ class TemplateTransaction(Transaction): | |||||||
|         return _('template') |         return _('template') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SpecialTransaction(Transaction): | ||||||
|  |     """ | ||||||
|  |     Special type of :model:`note.Transaction` associated to transactions with special notes | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     last_name = models.CharField( | ||||||
|  |         max_length=255, | ||||||
|  |         verbose_name=_("name"), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     first_name = models.CharField( | ||||||
|  |         max_length=255, | ||||||
|  |         verbose_name=_("first_name"), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     bank = models.CharField( | ||||||
|  |         max_length=255, | ||||||
|  |         verbose_name=_("bank") | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class MembershipTransaction(Transaction): | class MembershipTransaction(Transaction): | ||||||
|     """ |     """ | ||||||
|     Special type of :model:`note.Transaction` associated to a :model:`member.Membership`. |     Special type of :model:`note.Transaction` associated to a :model:`member.Membership`. | ||||||
|   | |||||||
| @@ -37,20 +37,16 @@ class HistoryTable(tables.Table): | |||||||
|             .order_by(('-' if is_descending else '') + 'total') |             .order_by(('-' if is_descending else '') + 'total') | ||||||
|         return queryset, True |         return queryset, True | ||||||
|  |  | ||||||
|  |  | ||||||
|     def render_amount(self, value): |     def render_amount(self, value): | ||||||
|         return pretty_money(value) |         return pretty_money(value) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def render_total(self, value): |     def render_total(self, value): | ||||||
|         return pretty_money(value) |         return pretty_money(value) | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Django-tables escape strings. That's a wrong thing. |     # Django-tables escape strings. That's a wrong thing. | ||||||
|     def render_reason(self, value): |     def render_reason(self, value): | ||||||
|         return html.unescape(value) |         return html.unescape(value) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def render_valid(self, value): |     def render_valid(self, value): | ||||||
|         return "✔" if value else "✖" |         return "✔" if value else "✖" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,8 @@ from django.views.generic import CreateView, ListView, UpdateView, TemplateView | |||||||
| from django_tables2 import SingleTableView | from django_tables2 import SingleTableView | ||||||
|  |  | ||||||
| from .forms import TransactionTemplateForm | from .forms import TransactionTemplateForm | ||||||
| from .models import Transaction, TransactionTemplate, Alias, TemplateTransaction | from .models import Transaction, TransactionTemplate, Alias, TemplateTransaction, NoteSpecial | ||||||
|  | from .models.transactions import SpecialTransaction | ||||||
| from .tables import HistoryTable | from .tables import HistoryTable | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -30,6 +31,8 @@ class TransactionCreate(LoginRequiredMixin, TemplateView): | |||||||
|         context['title'] = _('Transfer money from your account ' |         context['title'] = _('Transfer money from your account ' | ||||||
|                              'to one or others') |                              'to one or others') | ||||||
|         context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk |         context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk | ||||||
|  |         context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk | ||||||
|  |         context['special_types'] = NoteSpecial.objects.order_by("special_type").all() | ||||||
|  |  | ||||||
|         return context |         return context | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,24 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|  |  | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|         <div class="col-xl-12"> |         <div class="col-xl-12"> | ||||||
|             <button id="switch_mode" class="form-control btn btn-secondary">Passer en mode transfert</button> |             <div class="btn-group btn-group-toggle" style="width: 100%" data-toggle="buttons"> | ||||||
|  |                 <label class="btn btn-sm btn-outline-primary active"> | ||||||
|  |                     <input type="radio" name="transaction_type" id="type_gift" checked> | ||||||
|  |                     Virement | ||||||
|  |                 </label> | ||||||
|  |                 <label class="btn btn-sm btn-outline-primary"> | ||||||
|  |                     <input type="radio" name="transaction_type" id="type_transfer"> | ||||||
|  |                     Transfert | ||||||
|  |                 </label> | ||||||
|  |                 <label class="btn btn-sm btn-outline-primary"> | ||||||
|  |                     <input type="radio" name="transaction_type" id="type_credit"> | ||||||
|  |                     Crédit | ||||||
|  |                 </label> | ||||||
|  |                 <label class="btn btn-sm btn-outline-primary"> | ||||||
|  |                     <input type="radio" name="transaction_type" id="type_debit"> | ||||||
|  |                     Retrait | ||||||
|  |                 </label> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| @@ -31,6 +48,48 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|  |         <div class="col-md-6" id="external_div" style="display: none;"> | ||||||
|  |             <div class="card border-success shadow mb-4"> | ||||||
|  |                 <div class="card-header"> | ||||||
|  |                     <p class="card-text font-weight-bold"> | ||||||
|  |                         Paiement externe | ||||||
|  |                     </p> | ||||||
|  |                 </div> | ||||||
|  |                 <ul class="list-group list-group-flush" id="source_note_list"> | ||||||
|  |                 </ul> | ||||||
|  |                 <div class="card-body"> | ||||||
|  |                     <div class="form-row"> | ||||||
|  |                         <div class="col-md-12"> | ||||||
|  |                             <label for="credit_type">Type de transfert :</label> | ||||||
|  |                             <select id="credit_type" class="custom-select"> | ||||||
|  |                                 {% for special_type in special_types %} | ||||||
|  |                                     <option value="{{ special_type.id }}">{{ special_type.special_type }}</option> | ||||||
|  |                                 {% endfor %} | ||||||
|  |                             </select> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="form-row"> | ||||||
|  |                         <div class="col-md-12"> | ||||||
|  |                             <label for="last_name">Nom :</label> | ||||||
|  |                             <input type="text" id="last_name" class="form-control" /> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="form-row"> | ||||||
|  |                         <div class="col-md-12"> | ||||||
|  |                             <label for="first_name">Prénom :</label> | ||||||
|  |                             <input type="text" id="first_name" class="form-control" /> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="form-row"> | ||||||
|  |                         <div class="col-md-12"> | ||||||
|  |                             <label for="bank">Banque :</label> | ||||||
|  |                             <input type="text" id="bank" class="form-control" /> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|         <div class="col-md-12" id="dests_div"> |         <div class="col-md-12" id="dests_div"> | ||||||
|             <div class="card border-info shadow mb-4"> |             <div class="card border-info shadow mb-4"> | ||||||
|                 <div class="card-header"> |                 <div class="card-header"> | ||||||
| @@ -75,7 +134,23 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|         sources_notes_display = []; |         sources_notes_display = []; | ||||||
|         dests = []; |         dests = []; | ||||||
|         dests_notes_display = []; |         dests_notes_display = []; | ||||||
|         transfer_mode = false; |  | ||||||
|  |         function reset() { | ||||||
|  |             sources_notes_display.length = 0; | ||||||
|  |             sources.length = 0; | ||||||
|  |             dests_notes_display.length = 0; | ||||||
|  |             dests.length = 0; | ||||||
|  |             $("#source_note_list").html(""); | ||||||
|  |             $("#dest_note_list").html(""); | ||||||
|  |             $("#source_alias_matched").html(""); | ||||||
|  |             $("#dest_alias_matched").html(""); | ||||||
|  |             $("#amount").val(""); | ||||||
|  |             $("#reason").val(""); | ||||||
|  |             $("#last_name").val(""); | ||||||
|  |             $("#first_name").val(""); | ||||||
|  |             $("#bank").val(""); | ||||||
|  |             refreshBalance(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $(document).ready(function() { |         $(document).ready(function() { | ||||||
|            autoCompleteNote("source_note", "source_alias_matched", "source_note_list", sources, sources_notes_display, |            autoCompleteNote("source_note", "source_alias_matched", "source_note_list", sources, sources_notes_display, | ||||||
| @@ -84,22 +159,32 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|                 "dest_alias", "dest_note"); |                 "dest_alias", "dest_note"); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         $("#switch_mode").click(function () { |         $("#type_gift").click(function() { | ||||||
|             transfer_mode ^= true; |  | ||||||
|             if (transfer_mode) { |  | ||||||
|                 $("#switch_mode").text("Passer en mode virement"); |  | ||||||
|                 $("#emitters_div").show(); |  | ||||||
|                 $("#dests_div").attr('class', 'col-md-6'); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 $("#switch_mode").text("Passer en mode transfert"); |  | ||||||
|             $("#emitters_div").hide(); |             $("#emitters_div").hide(); | ||||||
|  |             $("#external_div").hide(); | ||||||
|             $("#dests_div").attr('class', 'col-md-12'); |             $("#dests_div").attr('class', 'col-md-12'); | ||||||
|             } |         }); | ||||||
|  |  | ||||||
|  |         $("#type_transfer").click(function() { | ||||||
|  |             $("#emitters_div").show(); | ||||||
|  |             $("#external_div").hide(); | ||||||
|  |             $("#dests_div").attr('class', 'col-md-6'); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $("#type_credit").click(function() { | ||||||
|  |             $("#emitters_div").hide(); | ||||||
|  |             $("#external_div").show(); | ||||||
|  |             $("#dests_div").attr('class', 'col-md-6'); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $("#type_debit").click(function() { | ||||||
|  |             $("#emitters_div").hide(); | ||||||
|  |             $("#external_div").show(); | ||||||
|  |             $("#dests_div").attr('class', 'col-md-6'); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         $("#transfer").click(function() { |         $("#transfer").click(function() { | ||||||
|             if (sources_notes_display.length === 0) { |             if ($("#type_gift").is(':checked')) { | ||||||
|                 dests_notes_display.forEach(function (dest) { |                 dests_notes_display.forEach(function (dest) { | ||||||
|                     $.post("/api/note/transaction/transaction/", |                     $.post("/api/note/transaction/transaction/", | ||||||
|                         { |                         { | ||||||
| @@ -120,17 +205,7 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|                                 + " vers la note " + dest[0] + " a été fait avec succès !</div>\n"; |                                 + " vers la note " + dest[0] + " a été fait avec succès !</div>\n"; | ||||||
|                             msgDiv.html(html); |                             msgDiv.html(html); | ||||||
|  |  | ||||||
|                             sources_notes_display.length = 0; |                             reset(); | ||||||
|                             sources.length = 0; |  | ||||||
|                             dests_notes_display.length = 0; |  | ||||||
|                             dests.length = 0; |  | ||||||
|                             $("#source_note_list").html(""); |  | ||||||
|                             $("#dest_note_list").html(""); |  | ||||||
|                             $("#source_alias_matched").html(""); |  | ||||||
|                             $("#dest_alias_matched").html(""); |  | ||||||
|                             $("#amount").val(""); |  | ||||||
|                             $("#reason").val(""); |  | ||||||
|                             refreshBalance(); |  | ||||||
|                         }).fail(function (err) { |                         }).fail(function (err) { | ||||||
|                         let msgDiv = $("#messages"); |                         let msgDiv = $("#messages"); | ||||||
|                         let html = msgDiv.html(); |                         let html = msgDiv.html(); | ||||||
| @@ -139,21 +214,11 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|                             + " vers la note " + dest[0] + " a échoué : " + err.responseText + "</div>\n"; |                             + " vers la note " + dest[0] + " a échoué : " + err.responseText + "</div>\n"; | ||||||
|                         msgDiv.html(html); |                         msgDiv.html(html); | ||||||
|  |  | ||||||
|                         sources_notes_display.length = 0; |                         reset(); | ||||||
|                         sources.length = 0; |  | ||||||
|                         dests_notes_display.length = 0; |  | ||||||
|                         dests.length = 0; |  | ||||||
|                         $("#source_note_list").html(""); |  | ||||||
|                         $("#dest_note_list").html(""); |  | ||||||
|                         $("#source_alias_matched").html(""); |  | ||||||
|                         $("#dest_alias_matched").html(""); |  | ||||||
|                         $("#amount").val(""); |  | ||||||
|                         $("#reason").val(""); |  | ||||||
|                         refreshBalance(); |  | ||||||
|                     }); |                     }); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|             else { |             else if ($("#type_transfer").is(':checked')) { | ||||||
|                 sources_notes_display.forEach(function (source) { |                 sources_notes_display.forEach(function (source) { | ||||||
|                     dests_notes_display.forEach(function (dest) { |                     dests_notes_display.forEach(function (dest) { | ||||||
|                         $.post("/api/note/transaction/transaction/", |                         $.post("/api/note/transaction/transaction/", | ||||||
| @@ -175,17 +240,7 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|                                     + " vers la note " + dest[0] + " a été fait avec succès !</div>\n"; |                                     + " vers la note " + dest[0] + " a été fait avec succès !</div>\n"; | ||||||
|                                 msgDiv.html(html); |                                 msgDiv.html(html); | ||||||
|  |  | ||||||
|                                 sources_notes_display.length = 0; |                                 reset(); | ||||||
|                                 sources.length = 0; |  | ||||||
|                                 dests_notes_display.length = 0; |  | ||||||
|                                 dests.length = 0; |  | ||||||
|                                 $("#source_note_list").html(""); |  | ||||||
|                                 $("#dest_note_list").html(""); |  | ||||||
|                                 $("#source_alias_matched").html(""); |  | ||||||
|                                 $("#dest_alias_matched").html(""); |  | ||||||
|                                 $("#amount").val(""); |  | ||||||
|                                 $("#reason").val(""); |  | ||||||
|                                 refreshBalance(); |  | ||||||
|                             }).fail(function (err) { |                             }).fail(function (err) { | ||||||
|                                 let msgDiv = $("#messages"); |                                 let msgDiv = $("#messages"); | ||||||
|                                 let html = msgDiv.html(); |                                 let html = msgDiv.html(); | ||||||
| @@ -194,20 +249,53 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||||||
|                                     + " vers la note " + dest[0] + " a échoué : " + err.responseText + "</div>\n"; |                                     + " vers la note " + dest[0] + " a échoué : " + err.responseText + "</div>\n"; | ||||||
|                                 msgDiv.html(html); |                                 msgDiv.html(html); | ||||||
|  |  | ||||||
|                                 sources_notes_display.length = 0; |                                 reset(); | ||||||
|                                 sources.length = 0; |  | ||||||
|                                 dests_notes_display.length = 0; |  | ||||||
|                                 dests.length = 0; |  | ||||||
|                                 $("#source_note_list").html(""); |  | ||||||
|                                 $("#dest_note_list").html(""); |  | ||||||
|                                 $("#source_alias_matched").html(""); |  | ||||||
|                                 $("#dest_alias_matched").html(""); |  | ||||||
|                                 $("#amount").val(""); |  | ||||||
|                                 $("#reason").val(""); |  | ||||||
|                                 refreshBalance(); |  | ||||||
|                         }); |                         }); | ||||||
|                     }); |                     }); | ||||||
|                 }); |                 }); | ||||||
|  |             } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) { | ||||||
|  |                 let special_note = $("#credit_type").val(); | ||||||
|  |                 let user_note = dests_notes_display[0][1]; | ||||||
|  |                 let source, dest, reason; | ||||||
|  |                 if ($("#type_credit").is(':checked')) { | ||||||
|  |                     source = special_note; | ||||||
|  |                     dest = user_note; | ||||||
|  |                     reason = $("#reason").val() + " (Crédit " + $("#credit_type option:selected").text().toLowerCase() + ")"; | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     source = user_note; | ||||||
|  |                     dest = special_note; | ||||||
|  |                     reason = $("#reason").val() + " (Retrait " + $("#credit_type option:selected").text().toLowerCase() + ")"; | ||||||
|  |                 } | ||||||
|  |                 $.post("/api/note/transaction/transaction/", | ||||||
|  |                     { | ||||||
|  |                         "csrfmiddlewaretoken": CSRF_TOKEN, | ||||||
|  |                         "quantity": dest[3], | ||||||
|  |                         "amount": $("#amount").val(), | ||||||
|  |                         "reason": reason, | ||||||
|  |                         "valid": true, | ||||||
|  |                         "polymorphic_ctype": {{ special_polymorphic_ctype }}, | ||||||
|  |                         "resourcetype": "SpecialTransaction", | ||||||
|  |                         "source": source, | ||||||
|  |                         "destination": dest, | ||||||
|  |                         "last_name": $("#last_name").val(), | ||||||
|  |                         "first_name": $("#first_name").val(), | ||||||
|  |                         "bank": $("#bank").val() | ||||||
|  |                     }, function () { | ||||||
|  |                         let msgDiv = $("#messages"); | ||||||
|  |                         let html = msgDiv.html(); | ||||||
|  |                         html += "<div class=\"alert alert-success\">Le crédit/retrait a bien été effectué !</div>\n"; | ||||||
|  |                         msgDiv.html(html); | ||||||
|  |  | ||||||
|  |                         reset(); | ||||||
|  |                     }).fail(function (err) { | ||||||
|  |                     let msgDiv = $("#messages"); | ||||||
|  |                     let html = msgDiv.html(); | ||||||
|  |                     html += "<div class=\"alert alert-danger\">Le crédit/transfert a échoué : " + err.responseText + "</div>\n"; | ||||||
|  |                     msgDiv.html(html); | ||||||
|  |  | ||||||
|  |                     reset(); | ||||||
|  |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     </script> |     </script> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user