\n"
@@ -18,9 +18,9 @@ msgid "activity"
msgstr "activité"
#: apps/activity/models.py:19 apps/activity/models.py:44
-#: apps/member/models.py:61 apps/member/models.py:112
-#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
-#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:202
+#: apps/member/models.py:63 apps/member/models.py:114
+#: apps/note/models/notes.py:188 apps/note/models/transactions.py:25
+#: apps/note/models/transactions.py:45 apps/note/models/transactions.py:232
#: templates/member/profile_detail.html:15
msgid "name"
msgstr "nom"
@@ -41,12 +41,13 @@ msgstr "type d'activité"
msgid "activity types"
msgstr "types d'activité"
-#: apps/activity/models.py:48 apps/note/models/transactions.py:69
+#: apps/activity/models.py:48 apps/note/models/transactions.py:70
+#: apps/permission/models.py:91
msgid "description"
msgstr "description"
#: apps/activity/models.py:54 apps/note/models/notes.py:164
-#: apps/note/models/transactions.py:62 apps/note/models/transactions.py:115
+#: apps/note/models/transactions.py:63
msgid "type"
msgstr "type"
@@ -114,11 +115,11 @@ msgstr "Nouvelles données"
msgid "create"
msgstr "Créer"
-#: apps/logs/models.py:61
+#: apps/logs/models.py:61 apps/note/tables.py:147
msgid "edit"
msgstr "Modifier"
-#: apps/logs/models.py:62
+#: apps/logs/models.py:62 apps/note/tables.py:151
msgid "delete"
msgstr "Supprimer"
@@ -138,61 +139,61 @@ msgstr "Les logs ne peuvent pas être détruits."
msgid "member"
msgstr "adhérent"
-#: apps/member/models.py:23
+#: apps/member/models.py:25
msgid "phone number"
msgstr "numéro de téléphone"
-#: apps/member/models.py:29 templates/member/profile_detail.html:28
+#: apps/member/models.py:31 templates/member/profile_detail.html:28
msgid "section"
msgstr "section"
-#: apps/member/models.py:30
+#: apps/member/models.py:32
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
-#: apps/member/models.py:36 templates/member/profile_detail.html:31
+#: apps/member/models.py:38 templates/member/profile_detail.html:31
msgid "address"
msgstr "adresse"
-#: apps/member/models.py:42
+#: apps/member/models.py:44
msgid "paid"
msgstr "payé"
-#: apps/member/models.py:47 apps/member/models.py:48
+#: apps/member/models.py:49 apps/member/models.py:50
msgid "user profile"
msgstr "profil utilisateur"
-#: apps/member/models.py:66
+#: apps/member/models.py:68
msgid "email"
msgstr "courriel"
-#: apps/member/models.py:71
+#: apps/member/models.py:73
msgid "membership fee"
msgstr "cotisation pour adhérer"
-#: apps/member/models.py:75
+#: apps/member/models.py:77
msgid "membership duration"
msgstr "durée de l'adhésion"
-#: apps/member/models.py:76
+#: apps/member/models.py:78
msgid "The longest time a membership can last (NULL = infinite)."
msgstr "La durée maximale d'une adhésion (NULL = infinie)."
-#: apps/member/models.py:81
+#: apps/member/models.py:83
msgid "membership start"
msgstr "début de l'adhésion"
-#: apps/member/models.py:82
+#: apps/member/models.py:84
msgid "How long after January 1st the members can renew their membership."
msgstr ""
"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
"adhésion."
-#: apps/member/models.py:87
+#: apps/member/models.py:89
msgid "membership end"
msgstr "fin de l'adhésion"
-#: apps/member/models.py:88
+#: apps/member/models.py:90
msgid ""
"How long the membership can last after January 1st of the next year after "
"members can renew their membership."
@@ -200,65 +201,65 @@ msgstr ""
"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
"suivante avant que les adhérents peuvent renouveler leur adhésion."
-#: apps/member/models.py:94 apps/note/models/notes.py:139
+#: apps/member/models.py:96 apps/note/models/notes.py:139
msgid "club"
msgstr "club"
-#: apps/member/models.py:95
+#: apps/member/models.py:97
msgid "clubs"
msgstr "clubs"
-#: apps/member/models.py:118
+#: apps/member/models.py:120 apps/permission/models.py:276
msgid "role"
msgstr "rôle"
-#: apps/member/models.py:119
+#: apps/member/models.py:121
msgid "roles"
msgstr "rôles"
-#: apps/member/models.py:143
+#: apps/member/models.py:145
msgid "membership starts on"
msgstr "l'adhésion commence le"
-#: apps/member/models.py:146
+#: apps/member/models.py:148
msgid "membership ends on"
msgstr "l'adhésion finie le"
-#: apps/member/models.py:150
+#: apps/member/models.py:152
msgid "fee"
msgstr "cotisation"
-#: apps/member/models.py:154
+#: apps/member/models.py:162
msgid "membership"
msgstr "adhésion"
-#: apps/member/models.py:155
+#: apps/member/models.py:163
msgid "memberships"
msgstr "adhésions"
-#: apps/member/views.py:69 templates/member/profile_detail.html:46
+#: apps/member/views.py:80 templates/member/profile_detail.html:46
msgid "Update Profile"
msgstr "Modifier le profil"
-#: apps/member/views.py:82
+#: apps/member/views.py:93
msgid "An alias with a similar name already exists."
msgstr "Un alias avec un nom similaire existe déjà."
-#: apps/member/views.py:132
+#: apps/member/views.py:146
#, python-format
msgid "Account #%(id)s: %(username)s"
msgstr "Compte n°%(id)s : %(username)s"
-#: apps/member/views.py:202
+#: apps/member/views.py:216
msgid "Alias successfully deleted"
msgstr "L'alias a bien été supprimé"
-#: apps/note/admin.py:120 apps/note/models/transactions.py:94
+#: apps/note/admin.py:120 apps/note/models/transactions.py:95
msgid "source"
msgstr "source"
#: apps/note/admin.py:128 apps/note/admin.py:156
-#: apps/note/models/transactions.py:53 apps/note/models/transactions.py:100
+#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:108
msgid "destination"
msgstr "destination"
@@ -309,7 +310,7 @@ msgstr ""
msgid "display image"
msgstr "image affichée"
-#: apps/note/models/notes.py:53 apps/note/models/transactions.py:103
+#: apps/note/models/notes.py:53 apps/note/models/transactions.py:118
msgid "created at"
msgstr "créée le"
@@ -383,116 +384,270 @@ msgstr "Un alias avec un nom similaire existe déjà : {}"
msgid "You can't delete your main alias."
msgstr "Vous ne pouvez pas supprimer votre alias principal."
-#: apps/note/models/transactions.py:30
+#: apps/note/models/transactions.py:31
msgid "transaction category"
msgstr "catégorie de transaction"
-#: apps/note/models/transactions.py:31
+#: apps/note/models/transactions.py:32
msgid "transaction categories"
msgstr "catégories de transaction"
-#: apps/note/models/transactions.py:47
+#: apps/note/models/transactions.py:48
msgid "A template with this name already exist"
msgstr "Un modèle de transaction avec un nom similaire existe déjà."
-#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:111
+#: apps/note/models/transactions.py:57 apps/note/models/transactions.py:126
msgid "amount"
msgstr "montant"
-#: apps/note/models/transactions.py:57
+#: apps/note/models/transactions.py:58
msgid "in centimes"
msgstr "en centimes"
-#: apps/note/models/transactions.py:75
+#: apps/note/models/transactions.py:76
msgid "transaction template"
msgstr "modèle de transaction"
-#: apps/note/models/transactions.py:76
+#: apps/note/models/transactions.py:77
msgid "transaction templates"
msgstr "modèles de transaction"
-#: apps/note/models/transactions.py:107
+#: apps/note/models/transactions.py:101 apps/note/models/transactions.py:114
+#: apps/note/tables.py:33 apps/note/tables.py:42
+msgid "used alias"
+msgstr "alias utilisé"
+
+#: apps/note/models/transactions.py:122
msgid "quantity"
msgstr "quantité"
-#: apps/note/models/transactions.py:117 templates/note/transaction_form.html:15
-msgid "Gift"
-msgstr "Don"
-
-#: apps/note/models/transactions.py:118 templates/base.html:90
-#: templates/note/transaction_form.html:19
-#: templates/note/transaction_form.html:126
-msgid "Transfer"
-msgstr "Virement"
-
-#: apps/note/models/transactions.py:119
-msgid "Template"
-msgstr "Bouton"
-
-#: apps/note/models/transactions.py:120 templates/note/transaction_form.html:23
-msgid "Credit"
-msgstr "Crédit"
-
-#: apps/note/models/transactions.py:121 templates/note/transaction_form.html:27
-msgid "Debit"
-msgstr "Retrait"
-
-#: apps/note/models/transactions.py:122 apps/note/models/transactions.py:230
-msgid "membership transaction"
-msgstr "transaction d'adhésion"
-
-#: apps/note/models/transactions.py:129
+#: apps/note/models/transactions.py:115
msgid "reason"
msgstr "raison"
-#: apps/note/models/transactions.py:133
+#: apps/note/models/transactions.py:119
msgid "valid"
msgstr "valide"
-#: apps/note/models/transactions.py:138
+#: apps/note/models/transactions.py:124
msgid "transaction"
msgstr "transaction"
-#: apps/note/models/transactions.py:139
+#: apps/note/models/transactions.py:125
msgid "transactions"
msgstr "transactions"
-#: apps/note/models/transactions.py:207
-msgid "first_name"
-msgstr "Prénom"
+#: apps/note/models/transactions.py:168 templates/base.html:98
+#: templates/note/transaction_form.html:19
+#: templates/note/transaction_form.html:145
+msgid "Transfer"
+msgstr "Virement"
-#: apps/note/models/transactions.py:212
+#: apps/note/models/transactions.py:188
+msgid "Template"
+msgstr "Bouton"
+
+#: apps/note/models/transactions.py:203
+msgid "first_name"
+msgstr "prénom"
+
+#: apps/note/models/transactions.py:208
msgid "bank"
-msgstr "Banque"
+msgstr "banque"
+
+#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:24
+msgid "Credit"
+msgstr "Crédit"
+
+#: apps/note/models/transactions.py:214 templates/note/transaction_form.html:28
+msgid "Debit"
+msgstr "Débit"
+
+#: apps/note/models/transactions.py:230 apps/note/models/transactions.py:235
+msgid "membership transaction"
+msgstr "transaction d'adhésion"
#: apps/note/models/transactions.py:231
msgid "membership transactions"
msgstr "transactions d'adhésion"
-#: apps/note/views.py:31
+#: apps/note/views.py:39
msgid "Transfer money"
-msgstr "Transferts d'argent"
+msgstr "Transférer de l'argent"
-#: apps/note/views.py:132 templates/base.html:78
+#: apps/note/views.py:145 templates/base.html:79
msgid "Consumptions"
msgstr "Consommations"
-#: note_kfet/settings/__init__.py:61
+#: apps/permission/models.py:69 apps/permission/models.py:262
+#, python-brace-format
+msgid "Can {type} {model}.{field} in {query}"
+msgstr ""
+
+#: apps/permission/models.py:71 apps/permission/models.py:264
+#, python-brace-format
+msgid "Can {type} {model} in {query}"
+msgstr ""
+
+#: apps/permission/models.py:84
+msgid "rank"
+msgstr "Rang"
+
+#: apps/permission/models.py:147
+msgid "Specifying field applies only to view and change permission types."
+msgstr ""
+
+#: apps/treasury/apps.py:11 templates/base.html:102
+msgid "Treasury"
+msgstr "Trésorerie"
+
+#: apps/treasury/forms.py:56 apps/treasury/forms.py:95
+#: templates/django_filters/rest_framework/form.html:5
+#: templates/member/club_form.html:10 templates/treasury/invoice_form.html:47
+msgid "Submit"
+msgstr "Envoyer"
+
+#: apps/treasury/forms.py:58
+msgid "Close"
+msgstr "Fermer"
+
+#: apps/treasury/forms.py:65
+msgid "Remittance is already closed."
+msgstr "La remise est déjà fermée."
+
+#: apps/treasury/forms.py:70
+msgid "You can't change the type of the remittance."
+msgstr "Vous ne pouvez pas changer le type de la remise."
+
+#: apps/treasury/forms.py:84
+msgid "Last name"
+msgstr "Nom de famille"
+
+#: apps/treasury/forms.py:86 templates/note/transaction_form.html:92
+msgid "First name"
+msgstr "Prénom"
+
+#: apps/treasury/forms.py:88 templates/note/transaction_form.html:98
+msgid "Bank"
+msgstr "Banque"
+
+#: apps/treasury/forms.py:90 apps/treasury/tables.py:40
+#: templates/note/transaction_form.html:128
+#: templates/treasury/remittance_form.html:18
+msgid "Amount"
+msgstr "Montant"
+
+#: apps/treasury/models.py:18
+msgid "Invoice identifier"
+msgstr "Numéro de facture"
+
+#: apps/treasury/models.py:32
+msgid "BDE"
+msgstr "BDE"
+
+#: apps/treasury/models.py:37
+msgid "Object"
+msgstr "Objet"
+
+#: apps/treasury/models.py:41
+msgid "Description"
+msgstr "Description"
+
+#: apps/treasury/models.py:46 templates/note/transaction_form.html:86
+msgid "Name"
+msgstr "Nom"
+
+#: apps/treasury/models.py:50
+msgid "Address"
+msgstr "Adresse"
+
+#: apps/treasury/models.py:55
+msgid "Place"
+msgstr "Lieu"
+
+#: apps/treasury/models.py:59
+msgid "Acquitted"
+msgstr "Acquittée"
+
+#: apps/treasury/models.py:75
+msgid "Designation"
+msgstr "Désignation"
+
+#: apps/treasury/models.py:79
+msgid "Quantity"
+msgstr "Quantité"
+
+#: apps/treasury/models.py:83
+msgid "Unit price"
+msgstr "Prix unitaire"
+
+#: apps/treasury/models.py:120
+msgid "Date"
+msgstr "Date"
+
+#: apps/treasury/models.py:126
+msgid "Type"
+msgstr "Type"
+
+#: apps/treasury/models.py:131
+msgid "Comment"
+msgstr "Commentaire"
+
+#: apps/treasury/models.py:136
+msgid "Closed"
+msgstr "Fermée"
+
+#: apps/treasury/models.py:159
+msgid "Remittance #{:d}: {}"
+msgstr "Remise n°{:d} : {}"
+
+#: apps/treasury/models.py:178 apps/treasury/tables.py:64
+#: apps/treasury/tables.py:72 templates/treasury/invoice_list.html:13
+#: templates/treasury/remittance_list.html:13
+msgid "Remittance"
+msgstr "Remise"
+
+#: apps/treasury/tables.py:16
+msgid "Invoice #{:d}"
+msgstr "Facture n°{:d}"
+
+#: apps/treasury/tables.py:19 templates/treasury/invoice_list.html:10
+#: templates/treasury/remittance_list.html:10
+msgid "Invoice"
+msgstr "Facture"
+
+#: apps/treasury/tables.py:38
+msgid "Transaction count"
+msgstr "Nombre de transactions"
+
+#: apps/treasury/tables.py:43 apps/treasury/tables.py:45
+msgid "View"
+msgstr "Voir"
+
+#: apps/treasury/tables.py:66
+msgid "Add"
+msgstr "Ajouter"
+
+#: apps/treasury/tables.py:74
+msgid "Remove"
+msgstr "supprimer"
+
+#: note_kfet/settings/__init__.py:63
msgid ""
"The Central Authentication Service grants you access to most of our websites "
"by authenticating only once, so you don't need to type your credentials "
"again unless your session expires or you logout."
msgstr ""
-#: note_kfet/settings/base.py:156
+#: note_kfet/settings/base.py:151
msgid "German"
msgstr ""
-#: note_kfet/settings/base.py:157
+#: note_kfet/settings/base.py:152
msgid "English"
msgstr ""
-#: note_kfet/settings/base.py:158
+#: note_kfet/settings/base.py:153
msgid "French"
msgstr ""
@@ -500,18 +655,14 @@ msgstr ""
msgid "The ENS Paris-Saclay BDE note."
msgstr "La note du BDE de l'ENS Paris-Saclay."
-#: templates/base.html:81
+#: templates/base.html:87
msgid "Clubs"
msgstr "Clubs"
-#: templates/base.html:84
+#: templates/base.html:92
msgid "Activities"
msgstr "Activités"
-#: templates/base.html:87
-msgid "Buttons"
-msgstr "Boutons"
-
#: templates/cas_server/base.html:7
msgid "Central Authentication Service"
msgstr ""
@@ -569,11 +720,6 @@ msgstr ""
msgid "Field filters"
msgstr ""
-#: templates/django_filters/rest_framework/form.html:5
-#: templates/member/club_form.html:10
-msgid "Submit"
-msgstr "Envoyer"
-
#: templates/member/club_detail.html:10
msgid "Membership starts on"
msgstr "L'adhésion commence le"
@@ -620,15 +766,15 @@ msgstr "Ajouter un alias"
#: templates/member/profile_detail.html:15
msgid "first name"
-msgstr ""
+msgstr "prénom"
#: templates/member/profile_detail.html:18
msgid "username"
-msgstr ""
+msgstr "pseudo"
#: templates/member/profile_detail.html:21
msgid "password"
-msgstr ""
+msgstr "mot de passe"
#: templates/member/profile_detail.html:24
msgid "Change password"
@@ -655,13 +801,13 @@ msgstr "Sauvegarder les changements"
msgid "Sign up"
msgstr "Inscription"
-#: templates/note/conso_form.html:28 templates/note/transaction_form.html:38
+#: templates/note/conso_form.html:28 templates/note/transaction_form.html:50
msgid "Select emitters"
msgstr "Sélection des émetteurs"
#: templates/note/conso_form.html:45
msgid "Select consumptions"
-msgstr "Consommations"
+msgstr "Sélection des consommations"
#: templates/note/conso_form.html:51
msgid "Consume!"
@@ -677,55 +823,59 @@ msgstr "Éditer"
#: templates/note/conso_form.html:126
msgid "Single consumptions"
-msgstr "Consos simples"
+msgstr "Consommations simples"
#: templates/note/conso_form.html:130
msgid "Double consumptions"
-msgstr "Consos doubles"
+msgstr "Consommations doubles"
-#: templates/note/conso_form.html:141
+#: templates/note/conso_form.html:141 templates/note/transaction_form.html:152
msgid "Recent transactions history"
msgstr "Historique des transactions récentes"
-#: templates/note/transaction_form.html:55
-msgid "External payment"
-msgstr "Paiement extérieur"
+#: templates/note/transaction_form.html:15
+msgid "Gift"
+msgstr "Don"
-#: templates/note/transaction_form.html:63
+#: templates/note/transaction_form.html:68
+msgid "External payment"
+msgstr "Paiement externe"
+
+#: templates/note/transaction_form.html:76
msgid "Transfer type"
msgstr "Type de transfert"
-#: templates/note/transaction_form.html:73
+#: templates/note/transaction_form.html:86
msgid "Name"
msgstr "Nom"
-#: templates/note/transaction_form.html:79
+#: templates/note/transaction_form.html:92
msgid "First name"
msgstr "Prénom"
-#: templates/note/transaction_form.html:85
+#: templates/note/transaction_form.html:98
msgid "Bank"
msgstr "Banque"
-#: templates/note/transaction_form.html:97
-#: templates/note/transaction_form.html:179
-#: templates/note/transaction_form.html:186
+#: templates/note/transaction_form.html:111
+#: templates/note/transaction_form.html:169
+#: templates/note/transaction_form.html:176
msgid "Select receivers"
msgstr "Sélection des destinataires"
-#: templates/note/transaction_form.html:114
+#: templates/note/transaction_form.html:128
msgid "Amount"
msgstr "Montant"
-#: templates/note/transaction_form.html:119
+#: templates/note/transaction_form.html:138
msgid "Reason"
msgstr "Raison"
-#: templates/note/transaction_form.html:193
+#: templates/note/transaction_form.html:183
msgid "Credit note"
-msgstr "Note à créditer"
+msgstr "Note à recharger"
-#: templates/note/transaction_form.html:200
+#: templates/note/transaction_form.html:190
msgid "Debit note"
msgstr "Note à débiter"
@@ -733,6 +883,22 @@ msgstr "Note à débiter"
msgid "Buttons list"
msgstr "Liste des boutons"
+#: templates/note/transactiontemplate_list.html:9
+msgid "search button"
+msgstr "Chercher un bouton"
+
+#: templates/note/transactiontemplate_list.html:20
+msgid "buttons listing "
+msgstr "Liste des boutons"
+
+#: templates/note/transactiontemplate_list.html:71
+msgid "button successfully deleted "
+msgstr "Le bouton a bien été supprimé"
+
+#: templates/note/transactiontemplate_list.html:75
+msgid "Unable to delete button "
+msgstr "Impossible de supprimer le bouton "
+
#: templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
@@ -742,7 +908,7 @@ msgid "Log in again"
msgstr ""
#: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:26
+#: templates/registration/login.html:28
#: templates/registration/password_reset_complete.html:10
msgid "Log in"
msgstr ""
@@ -754,7 +920,15 @@ msgid ""
"page. Would you like to login to a different account?"
msgstr ""
-#: templates/registration/login.html:27
+#: templates/registration/login.html:22
+msgid "You can also register via the central authentification server "
+msgstr ""
+
+#: templates/registration/login.html:23
+msgid "using this link "
+msgstr ""
+
+#: templates/registration/login.html:29
msgid "Forgotten your password or username?"
msgstr ""
@@ -810,3 +984,72 @@ msgstr ""
#: templates/registration/password_reset_form.html:11
msgid "Reset my password"
msgstr ""
+
+#: templates/treasury/invoice_form.html:6
+msgid "Invoices list"
+msgstr "Liste des factures"
+
+#: templates/treasury/invoice_form.html:42
+msgid "Add product"
+msgstr "Ajouter produit"
+
+#: templates/treasury/invoice_form.html:43
+msgid "Remove product"
+msgstr "Retirer produit"
+
+#: templates/treasury/invoice_list.html:21
+msgid "New invoice"
+msgstr "Nouvelle facture"
+
+#: templates/treasury/remittance_form.html:7
+msgid "Remittance #"
+msgstr "Remise n°"
+
+#: templates/treasury/remittance_form.html:9
+#: templates/treasury/specialtransactionproxy_form.html:7
+msgid "Remittances list"
+msgstr "Liste des remises"
+
+#: templates/treasury/remittance_form.html:12
+msgid "Count"
+msgstr "Nombre"
+
+#: templates/treasury/remittance_form.html:29
+msgid "Linked transactions"
+msgstr "Transactions liées"
+
+#: templates/treasury/remittance_form.html:34
+msgid "There is no transaction linked with this remittance."
+msgstr "Il n'y a pas de transaction liée à cette remise."
+
+#: templates/treasury/remittance_list.html:19
+msgid "Opened remittances"
+msgstr "Remises ouvertes"
+
+#: templates/treasury/remittance_list.html:24
+msgid "There is no opened remittance."
+msgstr "Il n'y a pas de remise ouverte."
+
+#: templates/treasury/remittance_list.html:28
+msgid "New remittance"
+msgstr "Nouvelle remise"
+
+#: templates/treasury/remittance_list.html:32
+msgid "Transfers without remittances"
+msgstr "Transactions sans remise associée"
+
+#: templates/treasury/remittance_list.html:37
+msgid "There is no transaction without any linked remittance."
+msgstr "Il n'y a pas de transactions sans remise associée."
+
+#: templates/treasury/remittance_list.html:43
+msgid "Transfers with opened remittances"
+msgstr "Transactions associées à une remise ouverte"
+
+#: templates/treasury/remittance_list.html:48
+msgid "There is no transaction with an opened linked remittance."
+msgstr "Il n'y a pas de transaction associée à une remise ouverte."
+
+#: templates/treasury/remittance_list.html:54
+msgid "Closed remittances"
+msgstr "Remises fermées"
diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py
index 216199de..d49b2542 100644
--- a/note_kfet/settings/base.py
+++ b/note_kfet/settings/base.py
@@ -59,6 +59,7 @@ INSTALLED_APPS = [
'activity',
'member',
'note',
+ 'treasury',
'permission',
'api',
'logs',
diff --git a/note_kfet/urls.py b/note_kfet/urls.py
index 9170c62e..40a9a614 100644
--- a/note_kfet/urls.py
+++ b/note_kfet/urls.py
@@ -15,6 +15,7 @@ urlpatterns = [
# Include project routers
path('note/', include('note.urls')),
+ path('treasury/', include('treasury.urls')),
# Include Django Contrib and Core routers
path('i18n/', include('django.conf.urls.i18n')),
diff --git a/requirements/production.txt b/requirements/production.txt
index f0b52228..fe939cce 100644
--- a/requirements/production.txt
+++ b/requirements/production.txt
@@ -1 +1 @@
-psycopg2==2.8.4
+psycopg2-binary==2.8.4
diff --git a/static/img/Finalist.png b/static/img/Finalist.png
new file mode 100644
index 00000000..1a3c41f3
Binary files /dev/null and b/static/img/Finalist.png differ
diff --git a/static/img/Kataclist.png b/static/img/Kataclist.png
new file mode 100644
index 00000000..97fc4115
Binary files /dev/null and b/static/img/Kataclist.png differ
diff --git a/static/img/Listorique.png b/static/img/Listorique.png
new file mode 100644
index 00000000..c5158324
Binary files /dev/null and b/static/img/Listorique.png differ
diff --git a/static/img/Monopolist.png b/static/img/Monopolist.png
new file mode 100644
index 00000000..2685b21e
Binary files /dev/null and b/static/img/Monopolist.png differ
diff --git a/static/img/Satellist.png b/static/img/Satellist.png
new file mode 100644
index 00000000..d2377f67
Binary files /dev/null and b/static/img/Satellist.png differ
diff --git a/static/js/base.js b/static/js/base.js
index d06c2fbe..d21bd433 100644
--- a/static/js/base.js
+++ b/static/js/base.js
@@ -70,11 +70,12 @@ function li(id, text) {
*/
function displayNote(note, alias, user_note_field=null, profile_pic_field=null) {
if (!note.display_image) {
- note.display_image = 'https://nk20.ynerant.fr/media/pic/default.png';
+ note.display_image = '/media/pic/default.png';
$.getJSON("/api/note/note/" + note.id + "/?format=json", function(new_note) {
note.display_image = new_note.display_image.replace("http:", "https:");
note.name = new_note.name;
note.balance = new_note.balance;
+ note.user = new_note.user;
displayNote(note, alias, user_note_field, profile_pic_field);
});
@@ -159,10 +160,13 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
let old_pattern = null;
- // When the user type "Enter", the first alias is clicked
+ // When the user type "Enter", the first alias is clicked, and the informations are displayed
field.keypress(function(event) {
- if (event.originalEvent.charCode === 13)
- $("#" + alias_matched_id + " li").first().trigger("click");
+ if (event.originalEvent.charCode === 13) {
+ let li_obj = $("#" + alias_matched_id + " li").first();
+ displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field);
+ li_obj.trigger("click");
+ }
});
// When the user type something, the matched aliases are refreshed
@@ -269,7 +273,16 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
}
// When a validate button is clicked, we switch the validation status
-function de_validate(id, validated) {
+function in_validate(id, validated) {
+
+ let invalidity_reason;
+ let reason_obj = $("#invalidity_reason_" + id);
+
+ if (validated)
+ invalidity_reason = reason_obj.val();
+ else
+ invalidity_reason = null;
+
$("#validate_" + id).html("⟳ ...");
// Perform a PATCH request to the API in order to update the transaction
@@ -282,12 +295,13 @@ function de_validate(id, validated) {
"X-CSRFTOKEN": CSRF_TOKEN
},
data: {
- "resourcetype": "RecurrentTransaction",
- valid: !validated
+ resourcetype: "RecurrentTransaction",
+ valid: !validated,
+ invalidity_reason: invalidity_reason,
},
success: function () {
// Refresh jQuery objects
- $(".validate").click(de_validate);
+ $(".validate").click(in_validate);
refreshBalance();
// error if this method doesn't exist. Please define it.
diff --git a/static/js/consos.js b/static/js/consos.js
index 27173365..20859933 100644
--- a/static/js/consos.js
+++ b/static/js/consos.js
@@ -167,7 +167,7 @@ function reset() {
function consumeAll() {
notes_display.forEach(function(note_display) {
buttons.forEach(function(button) {
- consume(note_display.id, button.dest, button.quantity * note_display.quantity, button.amount,
+ consume(note_display.id, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
button.name + " (" + button.category_name + ")", button.type, button.category_id, button.id);
});
});
@@ -176,6 +176,7 @@ function consumeAll() {
/**
* Create a new transaction from a button through the API.
* @param source The note that paid the item (type: int)
+ * @param source_alias The alias used for the source (type: str)
* @param dest The note that sold the item (type: int)
* @param quantity The quantity sold (type: int)
* @param amount The price of one item, in cents (type: int)
@@ -184,7 +185,7 @@ function consumeAll() {
* @param category The category id of the button (type: int)
* @param template The button id (type: int)
*/
-function consume(source, dest, quantity, amount, reason, type, category, template) {
+function consume(source, source_alias, dest, quantity, amount, reason, type, category, template) {
$.post("/api/note/transaction/transaction/",
{
"csrfmiddlewaretoken": CSRF_TOKEN,
@@ -195,11 +196,32 @@ function consume(source, dest, quantity, amount, reason, type, category, templat
"polymorphic_ctype": type,
"resourcetype": "RecurrentTransaction",
"source": source,
+ "source_alias": source_alias,
"destination": dest,
"category": category,
"template": template
}, reset).fail(function (e) {
- reset();
- errMsg(e.responseJSON);
+ $.post("/api/note/transaction/transaction/",
+ {
+ "csrfmiddlewaretoken": CSRF_TOKEN,
+ "quantity": quantity,
+ "amount": amount,
+ "reason": reason,
+ "valid": false,
+ "invalidity_reason": "Solde insuffisant",
+ "polymorphic_ctype": type,
+ "resourcetype": "RecurrentTransaction",
+ "source": source,
+ "source_alias": source_alias,
+ "destination": dest,
+ "category": category,
+ "template": template
+ }).done(function() {
+ reset();
+ addMsg("La transaction n'a pas pu être validée pour cause de solde insuffisant.", "danger");
+ }).fail(function () {
+ reset();
+ errMsg(e.responseJSON);
+ });
});
}
diff --git a/static/js/dynamic-formset.js b/static/js/dynamic-formset.js
index 87edfaae..c6ff3328 100644
--- a/static/js/dynamic-formset.js
+++ b/static/js/dynamic-formset.js
@@ -1,5 +1,5 @@
/**
- * jQuery Formset 1.3-pre
+ * jQuery Formset 1.5-pre
* @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
* @requires jQuery 1.2.6 or later
*
@@ -55,19 +55,26 @@
insertDeleteLink = function(row) {
var delCssSelector = $.trim(options.deleteCssClass).replace(/\s+/g, '.'),
addCssSelector = $.trim(options.addCssClass).replace(/\s+/g, '.');
- if (row.is('TR')) {
+
+ var delButtonHTML = '' + options.deleteText +'';
+ if (options.deleteContainerClass) {
+ // If we have a specific container for the remove button,
+ // place it as the last child of that container:
+ row.find('[class*="' + options.deleteContainerClass + '"]').append(delButtonHTML);
+ } else if (row.is('TR')) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
- row.children(':last').append('' + options.deleteText + '');
+ row.children('td:last').append(delButtonHTML);
} else if (row.is('UL') || row.is('OL')) {
// If they're laid out as an ordered/unordered list,
// insert an after the last list item:
- row.append('' + options.deleteText +'');
+ row.append('' + delButtonHTML + '');
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
- row.append('' + options.deleteText +'');
+ row.append(delButtonHTML);
}
+
// Check if we're under the minimum number of forms - not to display delete link at rendering
if (!showDeleteLinks()){
row.find('a.' + delCssSelector).hide();
@@ -156,6 +163,7 @@
} else {
// Otherwise, use the last form in the formset; this works much better if you've got
// extra (>= 1) forms (thnaks to justhamade for pointing this out):
+ if (options.hideLastAddForm) $('.' + options.formCssClass + ':last').hide();
template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
template.find('input:hidden[id $= "-DELETE"]').remove();
// Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
@@ -173,21 +181,28 @@
// FIXME: Perhaps using $.data would be a better idea?
options.formTemplate = template;
- if ($$.is('TR')) {
+ var addButtonHTML = '' + options.addText + '';
+ if (options.addContainerClass) {
+ // If we have a specific container for the "add" button,
+ // place it as the last child of that container:
+ var addContainer = $('[class*="' + options.addContainerClass + '"');
+ addContainer.append(addButtonHTML);
+ addButton = addContainer.find('[class="' + options.addCssClass + '"]');
+ } else if ($$.is('TR')) {
// If forms are laid out as table rows, insert the
// "add" button in a new table row:
var numCols = $$.eq(0).children().length, // This is a bit of an assumption :|
- buttonRow = $('' + options.addText + ' |
')
- .addClass(options.formCssClass + '-add');
+ buttonRow = $('' + addButtonHTML + ' |
').addClass(options.formCssClass + '-add');
$$.parent().append(buttonRow);
- if (hideAddButton) buttonRow.hide();
addButton = buttonRow.find('a');
} else {
// Otherwise, insert it immediately after the last form:
- $$.filter(':last').after('' + options.addText + '');
+ $$.filter(':last').after(addButtonHTML);
addButton = $$.filter(':last').next();
- if (hideAddButton) addButton.hide();
}
+
+ if (hideAddButton) addButton.hide();
+
addButton.click(function() {
var formCount = parseInt(totalForms.val()),
row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
@@ -220,12 +235,15 @@
formTemplate: null, // The jQuery selection cloned to generate new form instances
addText: 'add another', // Text for the add link
deleteText: 'remove', // Text for the delete link
- addCssClass: '', // CSS class applied to the add link
- deleteCssClass: '', // CSS class applied to the delete link
+ addContainerClass: null, // Container CSS class for the add link
+ deleteContainerClass: null, // Container CSS class for the delete link
+ addCssClass: 'add-row', // CSS class applied to the add link
+ deleteCssClass: 'delete-row', // CSS class applied to the delete link
formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
keepFieldValues: '', // jQuery selector for fields whose values should be kept when the form is cloned
added: null, // Function called each time a new form is added
- removed: null // Function called each time a form is deleted
+ removed: null, // Function called each time a form is deleted
+ hideLastAddForm: false // When set to true, hide last empty add form (becomes visible when clicking on add button)
};
})(jQuery);
diff --git a/static/js/transfer.js b/static/js/transfer.js
index c615f932..cf62e453 100644
--- a/static/js/transfer.js
+++ b/static/js/transfer.js
@@ -39,10 +39,21 @@ $(document).ready(function() {
last.quantity = 1;
- $.getJSON("/api/user/" + last.note.user + "/", function(user) {
- $("#last_name").val(user.last_name);
- $("#first_name").val(user.first_name);
- });
+ if (!last.note.user) {
+ $.getJSON("/api/note/note/" + last.note.id + "/?format=json", function(note) {
+ last.note.user = note.user;
+ $.getJSON("/api/user/" + last.note.user + "/", function(user) {
+ $("#last_name").val(user.last_name);
+ $("#first_name").val(user.first_name);
+ });
+ });
+ }
+ else {
+ $.getJSON("/api/user/" + last.note.user + "/", function(user) {
+ $("#last_name").val(user.last_name);
+ $("#first_name").val(user.first_name);
+ });
+ }
}
return true;
@@ -72,19 +83,41 @@ $("#transfer").click(function() {
"polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "Transaction",
"source": user_id,
- "destination": dest.id
- }, function () {
+ "destination": dest.id,
+ "destination_alias": dest.name
+ }).done(function () {
addMsg("Le transfert de "
+ pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
+ " vers la note " + dest.name + " a été fait avec succès !", "success");
reset();
- }).fail(function (err) {
- addMsg("Le transfert de "
- + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
- + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
+ }).fail(function () {
+ $.post("/api/note/transaction/transaction/",
+ {
+ "csrfmiddlewaretoken": CSRF_TOKEN,
+ "quantity": dest.quantity,
+ "amount": 100 * $("#amount").val(),
+ "reason": $("#reason").val(),
+ "valid": false,
+ "invalidity_reason": "Solde insuffisant",
+ "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
+ "resourcetype": "Transaction",
+ "source": user_id,
+ "destination": dest.id,
+ "destination_alias": dest.name
+ }).done(function () {
+ addMsg("Le transfert de "
+ + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
+ + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
- reset();
+ reset();
+ }).fail(function (err) {
+ addMsg("Le transfert de "
+ + pretty_money(dest.quantity * 100 * $("#amount").val()) + " de votre note "
+ + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
+
+ reset();
+ });
});
});
}
@@ -101,19 +134,43 @@ $("#transfer").click(function() {
"polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "Transaction",
"source": source.id,
- "destination": dest.id
- }, function () {
+ "source_alias": source.name,
+ "destination": dest.id,
+ "destination_alias": dest.name
+ }).done(function () {
addMsg("Le transfert de "
+ pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
+ " vers la note " + dest.name + " a été fait avec succès !", "success");
reset();
}).fail(function (err) {
- addMsg("Le transfert de "
- + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
- + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
+ $.post("/api/note/transaction/transaction/",
+ {
+ "csrfmiddlewaretoken": CSRF_TOKEN,
+ "quantity": source.quantity * dest.quantity,
+ "amount": 100 * $("#amount").val(),
+ "reason": $("#reason").val(),
+ "valid": false,
+ "invalidity_reason": "Solde insuffisant",
+ "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
+ "resourcetype": "Transaction",
+ "source": source.id,
+ "source_alias": source.name,
+ "destination": dest.id,
+ "destination_alias": dest.name
+ }).done(function () {
+ addMsg("Le transfert de "
+ + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
+ + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger");
- reset();
+ reset();
+ }).fail(function (err) {
+ addMsg("Le transfert de "
+ + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
+ + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
+
+ reset();
+ });
});
});
});
@@ -146,15 +203,17 @@ $("#transfer").click(function() {
"polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
"resourcetype": "SpecialTransaction",
"source": source,
+ "source_alias": source.name,
"destination": dest,
+ "destination_alias": dest.name,
"last_name": $("#last_name").val(),
"first_name": $("#first_name").val(),
"bank": $("#bank").val()
- }, function () {
+ }).done(function () {
addMsg("Le crédit/retrait a bien été effectué !", "success");
reset();
}).fail(function (err) {
- addMsg("Le crédit/transfert a échoué : " + err.responseText, "danger");
+ addMsg("Le crédit/retrait a échoué : " + err.responseText, "danger");
reset();
});
}
diff --git a/templates/base.html b/templates/base.html
index 4d39f9a1..6a688fc9 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -94,6 +94,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% trans 'Activities' %}
{% endif %}
+ {% if "treasury.invoice"|not_empty_model_change_list %}
+
+ {% trans 'Treasury' %}
+
+ {% endif %}
+
+
+{% endblock %}
+
+{% block extrajavascript %}
+
+{% endblock %}
diff --git a/templates/treasury/invoice_list.html b/templates/treasury/invoice_list.html
new file mode 100644
index 00000000..f14d278d
--- /dev/null
+++ b/templates/treasury/invoice_list.html
@@ -0,0 +1,23 @@
+{% extends "base.html" %}
+{% load render_table from django_tables2 %}
+{% load i18n %}
+{% block content %}
+
+
+
+{% render_table table %}
+
+{% trans "New invoice" %}
+
+{% endblock %}
diff --git a/templates/treasury/invoice_sample.tex b/templates/treasury/invoice_sample.tex
new file mode 100644
index 00000000..3c76403e
--- /dev/null
+++ b/templates/treasury/invoice_sample.tex
@@ -0,0 +1,186 @@
+\nonstopmode
+\documentclass[11pt]{article}
+
+\usepackage[french]{babel}
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage[a4paper]{geometry}
+\usepackage{units}
+\usepackage{bera}
+\usepackage{graphicx}
+\usepackage{fancyhdr}
+\usepackage{fp}
+\usepackage{transparent}
+\usepackage{eso-pic}
+
+\def\TVA{0} % Taux de la TVA
+
+\def\TotalHT{0}
+\def\TotalTVA{0}
+
+\newcommand{\AjouterProduit}[4]{% Arguments : Désignation, quantité, prix unitaire HT, prix total HT
+ \FPround{\prix}{#3}{2}
+ \FPround{\montant}{#4}{2}
+ \FPadd{\TotalHT}{\TotalHT}{\montant}
+
+ \eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr}
+}
+
+\newcommand{\AfficheResultat}{%
+ \ListeProduits
+
+ \FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
+ \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
+ \FPround{\TotalHT}{\TotalHT}{2}
+ \FPround{\TotalTVA}{\TotalTVA}{2}
+ \FPround{\TotalTTC}{\TotalTTC}{2}
+ \global\let\TotalHT\TotalHT
+ \global\let\TotalTVA\TotalTVA
+ \global\let\TotalTTC\TotalTTC
+
+ \cr \hline
+ Total HT & & & \TotalHT \cr
+ TVA \TVA~\% & & & \TotalTVA \cr
+ \hline \hline
+ \textbf{Total TTC} & & & \TotalTTC
+}
+
+\newcommand*\eaddto[2]{% version développée de \addto
+ \edef\tmp{#2}%
+ \expandafter\addto
+ \expandafter#1%
+ \expandafter{\tmp}%
+}
+
+\newcommand {\ListeProduits}{}
+
+% Logo du BDE
+\AddToShipoutPicture*{
+ \put(0,0){
+ \parbox[b][\paperheight]{\paperwidth}{%
+ \vfill
+ \centering
+ {\transparent{0.1}\includegraphics[width=\textwidth]{../../static/img/{{ obj.bde }}}}%
+ \vfill
+ }
+ }
+}
+
+
+%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%%
+% Infos Association
+\def\MonNom{{"{"}}{{ obj.my_name }}} % Nom de l'association
+\def\MonAdresseRue{{"{"}}{{ obj.my_address_street }}} % Adresse de l'association
+\def\MonAdresseVille{{"{"}}{{ obj.my_city }}}
+
+% Informations bancaires de l'association
+\def\CodeBanque{{"{"}}{{ obj.bank_code|stringformat:".05d" }}}
+\def\CodeGuichet{{"{"}}{{ obj.desk_code|stringformat:".05d" }}}
+\def\NCompte{{"{"}}{{ obj.account_number|stringformat:".011d" }}}
+\def\CleRib{{"{"}}{{ obj.rib_key|stringformat:".02d" }}}
+\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib}
+\def\CodeBic{{"{"}}{{ obj.bic }}}
+
+\def\FactureNum {{"{"}}{{obj.id}}} % Numéro de facture
+\def\FactureAcquittee {% if obj.acquitted %} {oui} {% else %} {non} {% endif %} % Facture acquittée : oui/non
+\def\FactureLieu {{"{"}}{{ obj.place }}} % Lieu de l'édition de la facture
+\def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture
+\def\FactureObjet {{"{"}}{{ obj.object|safe }} } % Objet du document
+% Description de la facture
+\def\FactureDescr {{"{"}}{{ obj.description|safe }}}
+
+% Infos Client
+\def\ClientNom{{"{"}}{{obj.name|safe}}} % Nom du client
+\def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client
+
+% Liste des produits facturés : Désignation, quantité, prix unitaire HT
+
+{% for product in products %}
+\AjouterProduit{ {{product.designation|safe}}} { {{product.quantity|safe}}} { {{product.amount_euros|safe}}} { {{product.total_euros|safe}}}
+{% endfor %}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em}
+\setlength{\parindent}{1pt}
+\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
+
+\thispagestyle{fancy}
+\pagestyle{fancy}
+\setlength{\parindent}{0pt}
+
+\renewcommand{\headrulewidth}{0pt}
+\cfoot{
+ \small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)6 89 88 56 50\newline
+ Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011
+ }
+}
+
+\begin{document}
+
+% Logo de la société
+% \includegraphics{logo.jpg}
+
+% Nom et adresse de la société
+\MonNom \\
+\MonAdresseRue \\
+\MonAdresseVille
+
+Facture n°\FactureNum
+
+
+{\addtolength{\leftskip}{10.5cm} %in ERT
+ \ClientNom \\
+ \ClientAdresse \\
+
+} %in ERT
+
+
+\hspace*{10.5cm}
+\FactureLieu, le \FactureDate
+
+~\\~\\
+
+\textbf{Objet : \FactureObjet \\}
+
+\textnormal{\FactureDescr}
+
+~\\
+
+\begin{center}
+ \begin{tabular}{lrrr}
+ \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\
+ \hline
+ \AfficheResultat{}
+ \end{tabular}
+\end{center}
+
+~\\
+
+\ifthenelse{\equal{\FactureAcquittee}{oui}}{
+ Facture acquittée.
+}{
+
+ À régler par chèque ou par virement bancaire :
+
+ \begin{center}
+ \begin{tabular}{|c c c c|}
+ \hline
+ \textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB}\\
+ \CodeBanque & \CodeGuichet & \NCompte & \CleRib \\
+ \hline
+ \textbf{IBAN N°} & \multicolumn{3}{|l|} \IBAN \\
+ \hline
+ \textbf{Code BIC} & \multicolumn{3}{|l|}\CodeBic \\
+ \hline
+ \end{tabular}
+ \end{center}
+
+}
+
+\begin{center}
+TVA non applicable, article 293 B du CGI.
+\end{center}
+
+\end{document}
diff --git a/templates/treasury/remittance_form.html b/templates/treasury/remittance_form.html
new file mode 100644
index 00000000..af4170f4
--- /dev/null
+++ b/templates/treasury/remittance_form.html
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+{% load static %}
+{% load i18n %}
+{% load crispy_forms_tags pretty_money %}
+{% load render_table from django_tables2 %}
+{% block content %}
+ {% trans "Remittance #" %}{{ object.pk }}
+
+ {% trans "Remittances list" %}
+
+ {% if object.pk %}
+
+
+
+ {% endif %}
+
+ {% crispy form %}
+
+
+
+ {% trans "Linked transactions" %}
+ {% if special_transactions.data %}
+ {% render_table special_transactions %}
+ {% else %}
+
+ {% trans "There is no transaction linked with this remittance." %}
+
+ {% endif %}
+{% endblock %}
diff --git a/templates/treasury/remittance_list.html b/templates/treasury/remittance_list.html
new file mode 100644
index 00000000..8bc634e4
--- /dev/null
+++ b/templates/treasury/remittance_list.html
@@ -0,0 +1,56 @@
+{% extends "base.html" %}
+{% load render_table from django_tables2 %}
+{% load i18n %}
+{% block content %}
+
+
+
+ {% trans "Opened remittances" %}
+ {% if opened_remittances.data %}
+ {% render_table opened_remittances %}
+ {% else %}
+
+ {% trans "There is no opened remittance." %}
+
+ {% endif %}
+
+ {% trans "New remittance" %}
+
+
+
+ {% trans "Transfers without remittances" %}
+ {% if special_transactions_no_remittance.data %}
+ {% render_table special_transactions_no_remittance %}
+ {% else %}
+
+ {% trans "There is no transaction without any linked remittance." %}
+
+ {% endif %}
+
+
+
+ {% trans "Transfers with opened remittances" %}
+ {% if special_transactions_with_remittance.data %}
+ {% render_table special_transactions_with_remittance %}
+ {% else %}
+
+ {% trans "There is no transaction with an opened linked remittance." %}
+
+ {% endif %}
+
+
+
+ {% trans "Closed remittances" %}
+ {% render_table closed_remittances %}
+{% endblock %}
diff --git a/templates/treasury/specialtransactionproxy_form.html b/templates/treasury/specialtransactionproxy_form.html
new file mode 100644
index 00000000..4e7758ae
--- /dev/null
+++ b/templates/treasury/specialtransactionproxy_form.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+{% load static %}
+{% load i18n %}
+{% load crispy_forms_tags pretty_money %}
+{% load render_table from django_tables2 %}
+{% block content %}
+ {% trans "Remittances list" %}
+ {% crispy form %}
+{% endblock %}
diff --git a/tox.ini b/tox.ini
index 0b5c20c9..01bf4edb 100644
--- a/tox.ini
+++ b/tox.ini
@@ -30,7 +30,7 @@ deps =
pep8-naming
pyflakes
commands =
- flake8 apps/activity apps/api apps/logs apps/member apps/note
+ flake8 apps/activity apps/api apps/logs apps/member apps/note apps/permission apps/treasury
[flake8]
# Ignore too many errors, should be reduced in the future