From 46c42303ee5df56dfbba80a9dccfea2d1e9dad08 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:25:56 +0100 Subject: [PATCH 01/59] New translations en.yml (French) --- config/locales/fr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 2dcf06c18..8f0dde0c2 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -535,3 +535,4 @@ fr: renew_pack_threshold: "Seuil de renouvellement des packs" pack_only_for_subscription: "Restreindre les packs pour les abonnés" overlapping_categories: "Catégories pour la prévention du chevauchement des réservations" + extended_prices_in_same_day: "Extended prices in the same day" From b31f9df37f6196d6ebd9c8b7fe414e97c8e54c24 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:25:58 +0100 Subject: [PATCH 02/59] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 0ff61d212..0ec43cec7 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -368,6 +368,8 @@ fr: status_enabled: "Actifs" status_disabled: "Désactivés" status_all: "Tous" + spaces_pricing: + price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Les tarifs ci-dessous correspondent à une heure d'utilisation machine, sans abonnement." prices_calculated_on_hourly_rate_html: "Tous les prix seront automatiquement calculés par rapport au tarif horaire défini ici.
Par exemple, si vous définissez un tarif horaire à {RATE} : un créneau de {DURATION} minutes, sera facturé {PRICE}." @@ -378,6 +380,11 @@ fr: packs: "Packs prépayés" no_packs: "Aucun pack pour le moment" pack_DURATION: "{DURATION} heures" + configure_extendedPrices_button: + extendedPrices: "Extended prices" + no_extendedPrices: "No extended price for now" + extended_prices_form: + amount: "Price" pack_form: hours: "Heures" amount: "Prix" @@ -404,6 +411,21 @@ fr: edit_pack: "Modifier le pack" confirm_changes: "Valider les modifications" pack_successfully_updated: "Le pack prépayé a bien été mis à jour." + create_extendedPrice: + new_extendedPrice: "New extended price" + new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." + create_extendedPrice: "Create extended price" + extendedPrice_successfully_created: "The new extended price was successfully created." + delete_extendedPrice: + extendedPrice_deleted: "The extended price was successfully deleted." + unable_to_delete: "Unable to delete the extended price: " + delete_extendedPrice: "Delete the extended price" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." + edit_extendedPrice: + edit_extendedPrice: "Edit the extended price" + confirm_changes: "Confirm changes" + extendedPrice_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Ajouter un code promotionnel" @@ -1235,6 +1257,9 @@ fr: pack_only_for_subscription_info_html: "Si cette option est activée, l'achat et l'utilisation d'un pack prépayé n'est possible que pour l'utilisateur possédant un abonnement en cours de validité." pack_only_for_subscription: "Abonnement valide pour l'achat et l'utilisation d'un pack prépayé" pack_only_for_subscription_info: "Rendre l'abonnement obligatoire pour les packs prépayés" + extended_prices: "Extended prices" + extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." + extended_prices_in_same_day: "Extended prices in the same day" overlapping_options: training_reservations: "Formations" machine_reservations: "Machines" From 6790a7861140a73b0640be873ed000f5b76fdbdb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:25:59 +0100 Subject: [PATCH 03/59] New translations en.yml (Spanish) --- config/locales/es.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/es.yml b/config/locales/es.yml index 6ac0679a4..d28f837b6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -535,3 +535,4 @@ es: renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" overlapping_categories: "Categories for overlapping booking prevention" + extended_prices_in_same_day: "Extended prices in the same day" From a2715d5c1b0b4118402a8005cea502d7d54606bb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:00 +0100 Subject: [PATCH 04/59] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 9f2a8426e..b575c36bc 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -368,6 +368,8 @@ es: status_enabled: "Enabled" status_disabled: "Disabled" status_all: "All" + spaces_pricing: + price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, without subscription." prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." @@ -378,6 +380,11 @@ es: packs: "Prepaid packs" no_packs: "No packs for now" pack_DURATION: "{DURATION} hours" + configure_extendedPrices_button: + extendedPrices: "Extended prices" + no_extendedPrices: "No extended price for now" + extended_prices_form: + amount: "Price" pack_form: hours: "Hours" amount: "Price" @@ -404,6 +411,21 @@ es: edit_pack: "Edit the pack" confirm_changes: "Confirm changes" pack_successfully_updated: "The prepaid pack was successfully updated." + create_extendedPrice: + new_extendedPrice: "New extended price" + new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." + create_extendedPrice: "Create extended price" + extendedPrice_successfully_created: "The new extended price was successfully created." + delete_extendedPrice: + extendedPrice_deleted: "The extended price was successfully deleted." + unable_to_delete: "Unable to delete the extended price: " + delete_extendedPrice: "Delete the extended price" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." + edit_extendedPrice: + edit_extendedPrice: "Edit the extended price" + confirm_changes: "Confirm changes" + extendedPrice_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Añadir un cupón" @@ -1235,6 +1257,9 @@ es: pack_only_for_subscription_info_html: "If this option is activated, the purchase and use of a prepaid pack is only possible for the user with a valid subscription." pack_only_for_subscription: "Subscription valid for purchase and use of a prepaid pack" pack_only_for_subscription_info: "Make subscription mandatory for prepaid packs" + extended_prices: "Extended prices" + extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." + extended_prices_in_same_day: "Extended prices in the same day" overlapping_options: training_reservations: "Trainings" machine_reservations: "Machines" From ccd1cea2a5744e2851a2d00924b34919470a58ef Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:02 +0100 Subject: [PATCH 05/59] New translations en.yml (German) --- config/locales/de.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/de.yml b/config/locales/de.yml index 0d0db4abc..bf58214a8 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -535,3 +535,4 @@ de: renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" overlapping_categories: "Categories for overlapping booking prevention" + extended_prices_in_same_day: "Extended prices in the same day" From 877b24b9ea5e9e15c997b8bb3bdb55da06d06941 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:03 +0100 Subject: [PATCH 06/59] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index aa500c49d..d892dd12b 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -368,6 +368,8 @@ de: status_enabled: "Aktiviert" status_disabled: "Deaktiviert" status_all: "Alle" + spaces_pricing: + price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Die unten aufgeführten Preise entsprechen einer Stunde Maschinengebrauch, ohne Abonnement." prices_calculated_on_hourly_rate_html: "Alle Preise werden automatisch nach dem hier definierten Stundensatz berechnet.
Zum Beispiel wird bei einem veranschlagten Stundensatz von {RATE} ein Slot von {DURATION} Minuten, zum Preis von {PRICE} berechnet." @@ -378,6 +380,11 @@ de: packs: "Prepaid packs" no_packs: "No packs for now" pack_DURATION: "{DURATION} hours" + configure_extendedPrices_button: + extendedPrices: "Extended prices" + no_extendedPrices: "No extended price for now" + extended_prices_form: + amount: "Price" pack_form: hours: "Hours" amount: "Price" @@ -404,6 +411,21 @@ de: edit_pack: "Edit the pack" confirm_changes: "Confirm changes" pack_successfully_updated: "The prepaid pack was successfully updated." + create_extendedPrice: + new_extendedPrice: "New extended price" + new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." + create_extendedPrice: "Create extended price" + extendedPrice_successfully_created: "The new extended price was successfully created." + delete_extendedPrice: + extendedPrice_deleted: "The extended price was successfully deleted." + unable_to_delete: "Unable to delete the extended price: " + delete_extendedPrice: "Delete the extended price" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." + edit_extendedPrice: + edit_extendedPrice: "Edit the extended price" + confirm_changes: "Confirm changes" + extendedPrice_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Gutschein hinzufügen" @@ -1235,6 +1257,9 @@ de: pack_only_for_subscription_info_html: "If this option is activated, the purchase and use of a prepaid pack is only possible for the user with a valid subscription." pack_only_for_subscription: "Subscription valid for purchase and use of a prepaid pack" pack_only_for_subscription_info: "Make subscription mandatory for prepaid packs" + extended_prices: "Extended prices" + extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." + extended_prices_in_same_day: "Extended prices in the same day" overlapping_options: training_reservations: "Trainings" machine_reservations: "Machines" From 9a9ed6538a16c12009819fdcc4adb1d106de1561 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:05 +0100 Subject: [PATCH 07/59] New translations en.yml (Norwegian) --- config/locales/no.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/no.yml b/config/locales/no.yml index 36a5b70d1..fddcda83a 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -535,3 +535,4 @@ renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" overlapping_categories: "Categories for overlapping booking prevention" + extended_prices_in_same_day: "Extended prices in the same day" From 278dacd6b57d2f1d177f2db27df26f2a27a06d71 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:06 +0100 Subject: [PATCH 08/59] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 38ea3eefe..7d18604af 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -368,6 +368,8 @@ status_enabled: "Aktivert" status_disabled: "Deaktivert" status_all: "Alle" + spaces_pricing: + price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Prisene under samsvarer med en time maskinbruk uten medlemskap." prices_calculated_on_hourly_rate_html: "Alle priser vil bli automatisk kalkulert basert på oppgitt timepris her.
For eksempel, hvis du definerer en timepris på {RATE}: en plass på {DURATION} minutter, vil bli belastet {PRICE}." @@ -378,6 +380,11 @@ packs: "Forhåndsbetalte pakker" no_packs: "Ingen pakker tilgjengelig nå" pack_DURATION: "{DURATION} timer" + configure_extendedPrices_button: + extendedPrices: "Extended prices" + no_extendedPrices: "No extended price for now" + extended_prices_form: + amount: "Price" pack_form: hours: "Timer" amount: "Pris" @@ -404,6 +411,21 @@ edit_pack: "Rediger pakken" confirm_changes: "Bekreft endringer" pack_successfully_updated: "Den forhåndsbetalte pakken ble oppdatert." + create_extendedPrice: + new_extendedPrice: "New extended price" + new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." + create_extendedPrice: "Create extended price" + extendedPrice_successfully_created: "The new extended price was successfully created." + delete_extendedPrice: + extendedPrice_deleted: "The extended price was successfully deleted." + unable_to_delete: "Unable to delete the extended price: " + delete_extendedPrice: "Delete the extended price" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." + edit_extendedPrice: + edit_extendedPrice: "Edit the extended price" + confirm_changes: "Confirm changes" + extendedPrice_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Legg til rabattkupong" @@ -1235,6 +1257,9 @@ pack_only_for_subscription_info_html: "If this option is activated, the purchase and use of a prepaid pack is only possible for the user with a valid subscription." pack_only_for_subscription: "Subscription valid for purchase and use of a prepaid pack" pack_only_for_subscription_info: "Make subscription mandatory for prepaid packs" + extended_prices: "Extended prices" + extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." + extended_prices_in_same_day: "Extended prices in the same day" overlapping_options: training_reservations: "Trainings" machine_reservations: "Machines" From 5b3c7228c80a0e35fc9bdf63d46494b10f027eaf Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:07 +0100 Subject: [PATCH 09/59] New translations en.yml (Portuguese) --- config/locales/pt.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 851f11eb6..2b0c5d7b1 100755 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -535,3 +535,4 @@ pt: renew_pack_threshold: "Limite para renovação de pacotes" pack_only_for_subscription: "Restringir pacotes para assinantes" overlapping_categories: "Categorias para prevenção de reservas sobrepostas" + extended_prices_in_same_day: "Extended prices in the same day" From a18e440504a57cd84493e724af6b4ad7442c2d31 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:09 +0100 Subject: [PATCH 10/59] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 390e7725c..f548b7cb8 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -368,6 +368,8 @@ pt: status_enabled: "Ativos" status_disabled: "Desabilitados" status_all: "Todos" + spaces_pricing: + price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Os preços abaixo correspondem a uma hora de uso de máquina, sem assinatura." prices_calculated_on_hourly_rate_html: "Todos os preços serão calculados automaticamente com base na taxa horária definida aqui.
Por exemplo, se você definir uma taxa horária em {RATE}: um slot de {DURATION} minutos, será cobrada a tarifa {PRICE}." @@ -378,6 +380,11 @@ pt: packs: "Pacotes pré-pagos" no_packs: "Não há pacotes no momento" pack_DURATION: "{DURATION} horas" + configure_extendedPrices_button: + extendedPrices: "Extended prices" + no_extendedPrices: "No extended price for now" + extended_prices_form: + amount: "Price" pack_form: hours: "Horas" amount: "Preço" @@ -404,6 +411,21 @@ pt: edit_pack: "Editar o pacote" confirm_changes: "Confirmar alterações" pack_successfully_updated: "O pacote pré-pago foi atualizado com sucesso." + create_extendedPrice: + new_extendedPrice: "New extended price" + new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." + create_extendedPrice: "Create extended price" + extendedPrice_successfully_created: "The new extended price was successfully created." + delete_extendedPrice: + extendedPrice_deleted: "The extended price was successfully deleted." + unable_to_delete: "Unable to delete the extended price: " + delete_extendedPrice: "Delete the extended price" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." + edit_extendedPrice: + edit_extendedPrice: "Edit the extended price" + confirm_changes: "Confirm changes" + extendedPrice_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Adicionar cupom" @@ -1235,6 +1257,9 @@ pt: pack_only_for_subscription_info_html: "Se esta opção estiver ativada, a compra e uso de um pacote pré-pago só é possível para o usuário com uma assinatura válida." pack_only_for_subscription: "Assinatura válida para compra e uso de um pacote pré-pago" pack_only_for_subscription_info: "Tornar obrigatória a assinatura para pacotes pré-pagos" + extended_prices: "Extended prices" + extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." + extended_prices_in_same_day: "Extended prices in the same day" overlapping_options: training_reservations: "Treinamentos" machine_reservations: "Máquinas" From d4fa3e4b73849675d6fc410513ee632de54cdc23 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:10 +0100 Subject: [PATCH 11/59] New translations en.yml (Zulu) --- config/locales/zu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/zu.yml b/config/locales/zu.yml index b96924f49..b238e8d90 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -535,3 +535,4 @@ zu: renew_pack_threshold: "crwdns22032:0crwdne22032:0" pack_only_for_subscription: "crwdns22093:0crwdne22093:0" overlapping_categories: "crwdns22129:0crwdne22129:0" + extended_prices_in_same_day: "crwdns22173:0crwdne22173:0" From 6d4f31c33bdccdc5cf28b798a1b9ada52dcfc848 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 23 Dec 2021 10:26:11 +0100 Subject: [PATCH 12/59] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 4a1156656..21c4b6cd2 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -368,6 +368,8 @@ zu: status_enabled: "crwdns7265:0crwdne7265:0" status_disabled: "crwdns7267:0crwdne7267:0" status_all: "crwdns7269:0crwdne7269:0" + spaces_pricing: + price_updated: "crwdns22135:0crwdne22135:0" machines_pricing: prices_match_machine_hours_rates_html: "crwdns21942:0crwdne21942:0" prices_calculated_on_hourly_rate_html: "crwdns22028:0{RATE}crwdnd22028:0{DURATION}crwdnd22028:0{PRICE}crwdne22028:0" @@ -378,6 +380,11 @@ zu: packs: "crwdns21952:0crwdne21952:0" no_packs: "crwdns21954:0crwdne21954:0" pack_DURATION: "crwdns21956:0{DURATION}crwdne21956:0" + configure_extendedPrices_button: + extendedPrices: "crwdns22137:0crwdne22137:0" + no_extendedPrices: "crwdns22139:0crwdne22139:0" + extended_prices_form: + amount: "crwdns22141:0crwdne22141:0" pack_form: hours: "crwdns21958:0crwdne21958:0" amount: "crwdns21960:0crwdne21960:0" @@ -404,6 +411,21 @@ zu: edit_pack: "crwdns21994:0crwdne21994:0" confirm_changes: "crwdns21996:0crwdne21996:0" pack_successfully_updated: "crwdns21998:0crwdne21998:0" + create_extendedPrice: + new_extendedPrice: "crwdns22143:0crwdne22143:0" + new_extendedPrice_info: "crwdns22145:0crwdne22145:0" + create_extendedPrice: "crwdns22147:0crwdne22147:0" + extendedPrice_successfully_created: "crwdns22149:0crwdne22149:0" + delete_extendedPrice: + extendedPrice_deleted: "crwdns22151:0crwdne22151:0" + unable_to_delete: "crwdns22153:0crwdne22153:0" + delete_extendedPrice: "crwdns22155:0crwdne22155:0" + confirm_delete: "crwdns22157:0crwdne22157:0" + delete_confirmation: "crwdns22159:0crwdne22159:0" + edit_extendedPrice: + edit_extendedPrice: "crwdns22161:0crwdne22161:0" + confirm_changes: "crwdns22163:0crwdne22163:0" + extendedPrice_successfully_updated: "crwdns22165:0crwdne22165:0" #ajouter un code promotionnel coupons_new: add_a_coupon: "crwdns7271:0crwdne7271:0" @@ -1235,6 +1257,9 @@ zu: pack_only_for_subscription_info_html: "crwdns22037:0crwdne22037:0" pack_only_for_subscription: "crwdns22039:0crwdne22039:0" pack_only_for_subscription_info: "crwdns22041:0crwdne22041:0" + extended_prices: "crwdns22167:0crwdne22167:0" + extended_prices_info_html: "crwdns22169:0crwdne22169:0" + extended_prices_in_same_day: "crwdns22171:0crwdne22171:0" overlapping_options: training_reservations: "crwdns22111:0crwdne22111:0" machine_reservations: "crwdns22113:0crwdne22113:0" From a319bf40b4144bc87df93576fde37368e47c0f77 Mon Sep 17 00:00:00 2001 From: vincent Date: Thu, 23 Dec 2021 14:36:20 +0100 Subject: [PATCH 13/59] Fix typo --- config/locales/app.admin.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index a2cac5534..09e41a07c 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -383,7 +383,7 @@ en: configure_extendedPrices_button: extendedPrices: "Extended prices" no_extendedPrices: "No extended price for now" - extended_prices_form: + extended_price_form: amount: "Price" pack_form: hours: "Hours" From db4230def14606263c7de81ec21ddabcfb422816 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 28 Dec 2021 09:47:44 +0100 Subject: [PATCH 14/59] Revert "Fix classes names" This reverts commit c394b3a2757493044e1589decd96fea90a33641a. --- app/frontend/src/javascript/api/space.ts | 1 + .../pricing/machines/configure-packs-button.tsx | 6 +++--- .../components/pricing/machines/delete-pack.tsx | 4 ++-- .../components/pricing/machines/edit-pack.tsx | 9 +++++---- .../components/pricing/machines/machines-pricing.tsx | 2 +- .../components/pricing/machines/pack-form.tsx | 2 +- .../pricing/spaces/configure-extended-price-button.tsx | 8 ++++---- .../pricing/spaces/delete-extended-price.tsx | 4 ++-- .../components/pricing/spaces/edit-extended-price.tsx | 9 +++++---- .../components/pricing/spaces/extended-price-form.tsx | 6 +++--- .../components/pricing/spaces/spaces-pricing.tsx | 8 ++++---- app/frontend/src/stylesheets/application.scss | 10 +++++----- ...e-group-button.scss => configure-packs-button.scss} | 6 +++--- .../pricing/{delete-group.scss => delete-pack.scss} | 4 ++-- .../pricing/{edit-group.scss => edit-pack.scss} | 2 +- .../{pricing-list.scss => machines-pricing.scss} | 4 ++-- .../pricing/{group-form.scss => pack-form.scss} | 2 +- 17 files changed, 45 insertions(+), 42 deletions(-) rename app/frontend/src/stylesheets/modules/pricing/{configure-group-button.scss => configure-packs-button.scss} (93%) rename app/frontend/src/stylesheets/modules/pricing/{delete-group.scss => delete-pack.scss} (65%) rename app/frontend/src/stylesheets/modules/pricing/{edit-group.scss => edit-pack.scss} (65%) rename app/frontend/src/stylesheets/modules/pricing/{pricing-list.scss => machines-pricing.scss} (95%) rename app/frontend/src/stylesheets/modules/pricing/{group-form.scss => pack-form.scss} (89%) diff --git a/app/frontend/src/javascript/api/space.ts b/app/frontend/src/javascript/api/space.ts index 5633bd658..6f1d9c9b9 100644 --- a/app/frontend/src/javascript/api/space.ts +++ b/app/frontend/src/javascript/api/space.ts @@ -12,4 +12,5 @@ export default class SpaceAPI { const res: AxiosResponse = await apiClient.get(`/api/spaces/${id}`); return res?.data; } + } diff --git a/app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx b/app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx index c5b1ff43c..ec3cbd2be 100644 --- a/app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx +++ b/app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx @@ -64,8 +64,8 @@ export const ConfigurePacksButton: React.FC = ({ pack }; return ( -
- {showList && @@ -73,7 +73,7 @@ export const ConfigurePacksButton: React.FC = ({ pack {packs?.map(p =>
  • {formatDuration(p.minutes)} - {FormatLib.price(p.amount)} - + diff --git a/app/frontend/src/javascript/components/pricing/machines/delete-pack.tsx b/app/frontend/src/javascript/components/pricing/machines/delete-pack.tsx index dc1d01089..bfd8a40a0 100644 --- a/app/frontend/src/javascript/components/pricing/machines/delete-pack.tsx +++ b/app/frontend/src/javascript/components/pricing/machines/delete-pack.tsx @@ -42,8 +42,8 @@ const DeletePackComponent: React.FC = ({ onSuccess, onError, pa }; return ( -
    - } onClick={toggleDeletionModal} /> +
    + } onClick={toggleDeletionModal} /> = ({ pack, onSuccess, onError }) }; return ( -
    - } onClick={handleRequestEdit} /> +
    + } onClick={handleRequestEdit} /> - {packData && } + onConfirmSendFormId="edit-pack"> + {packData && }
    ); diff --git a/app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx b/app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx index 5b3618b7d..80334aab0 100644 --- a/app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx +++ b/app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx @@ -107,7 +107,7 @@ const MachinesPricing: React.FC = ({ onError, onSuccess }) }; return ( -
    +

    diff --git a/app/frontend/src/javascript/components/pricing/machines/pack-form.tsx b/app/frontend/src/javascript/components/pricing/machines/pack-form.tsx index 831e0d899..ba4381c46 100644 --- a/app/frontend/src/javascript/components/pricing/machines/pack-form.tsx +++ b/app/frontend/src/javascript/components/pricing/machines/pack-form.tsx @@ -103,7 +103,7 @@ export const PackForm: React.FC = ({ formId, onSubmit, pack }) => }; return ( -
    + (false); /** - * Open/closes the popover listing the existing extended prices + * Open/closes the popover listing the existing packs */ const toggleShowList = (): void => { setShowList(!showList); @@ -57,8 +57,8 @@ export const ConfigureExtendedPriceButton: React.FC - {showList && @@ -66,7 +66,7 @@ export const ConfigureExtendedPriceButton: React.FC
  • {extendedPrice.duration} {t('app.admin.calendar.minutes')} - {FormatLib.price(extendedPrice.amount)} - + diff --git a/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx b/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx index 56af8784e..82307709f 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx @@ -41,8 +41,8 @@ export const DeleteExtendedPrice: React.FC = ({ onSucc }; return ( -
    - } onClick={toggleDeletionModal} /> +
    + } onClick={toggleDeletionModal} /> = ({ price, onS }; return ( -
    - } onClick={handleRequestEdit} /> +
    + } onClick={handleRequestEdit} /> - {extendedPriceData && } + onConfirmSendFormId="edit-pack"> + {extendedPriceData && }
    ); diff --git a/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx b/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx index 31445ee81..34e8e354c 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx @@ -7,7 +7,7 @@ import { IFablab } from '../../../models/fablab'; declare let Fablab: IFablab; -interface ExtendedPriceFormProps { +interface PackFormProps { formId: string, onSubmit: (pack: Price) => void, price?: Price, @@ -17,7 +17,7 @@ interface ExtendedPriceFormProps { * A form component to create/edit a extended price. * The form validation must be created elsewhere, using the attribute form={formId}. */ -export const ExtendedPriceForm: React.FC = ({ formId, onSubmit, price }) => { +export const ExtendedPriceForm: React.FC = ({ formId, onSubmit, price }) => { const [extendedPriceData, updateExtendedPriceData] = useImmer(price || {} as Price); const { t } = useTranslation('admin'); @@ -49,7 +49,7 @@ export const ExtendedPriceForm: React.FC = ({ formId, on }; return ( - + = ({ onError, onSuccess }) => // retrieve the initial data useEffect(() => { - SpaceAPI.index() + SpaceAPI.index(false) .then(data => setSpaces(data)) .catch(error => onError(error)); GroupAPI.index({ disabled: false, admins: false }) @@ -67,7 +67,7 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => * Find the default price (hourly rate) matching the given criterion */ const findPriceBy = (spaceId, groupId): Price => { - return prices.find(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration === 60); + return prices.find(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration == 60); }; /** @@ -101,7 +101,7 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => }; return ( -
    +

    @@ -118,7 +118,7 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => {spaces?.map(space => {space.name} {groups?.map(group => - {prices.length && } + {prices && } Date: Tue, 28 Dec 2021 11:25:10 +0100 Subject: [PATCH 15/59] refactor spaces/extended_prices code architecture to match the FM style guide --- app/controllers/api/prices_controller.rb | 2 +- .../configure-extended-price-button.tsx | 17 +++++-- .../pricing/spaces/create-extended-price.tsx | 14 +++--- .../pricing/spaces/delete-extended-price.tsx | 14 +++--- .../pricing/spaces/edit-extended-price.tsx | 14 +++--- .../pricing/spaces/extended-price-form.tsx | 10 ++-- .../pricing/spaces/spaces-pricing.tsx | 17 ++++--- app/frontend/src/stylesheets/application.scss | 16 ++++-- .../configure-packs-button.scss | 7 --- .../modules/pricing/machines/create-pack.scss | 7 +++ .../pricing/{ => machines}/delete-pack.scss | 0 .../pricing/{ => machines}/edit-pack.scss | 0 .../{ => machines}/machines-pricing.scss | 0 .../pricing/{ => machines}/pack-form.scss | 0 .../configure-extended-prices-button.scss | 49 +++++++++++++++++++ .../pricing/spaces/create-extended-price.scss | 7 +++ .../pricing/spaces/delete-extended-price.scss | 8 +++ .../pricing/spaces/edit-extended-price.scss | 3 ++ .../pricing/spaces/extended-price-form.scss | 10 ++++ .../pricing/spaces/spaces-pricing.scss | 31 ++++++++++++ app/models/price.rb | 4 ++ config/locales/app.admin.en.yml | 37 ++++++++------ 22 files changed, 200 insertions(+), 67 deletions(-) rename app/frontend/src/stylesheets/modules/pricing/{ => machines}/configure-packs-button.scss (90%) create mode 100644 app/frontend/src/stylesheets/modules/pricing/machines/create-pack.scss rename app/frontend/src/stylesheets/modules/pricing/{ => machines}/delete-pack.scss (100%) rename app/frontend/src/stylesheets/modules/pricing/{ => machines}/edit-pack.scss (100%) rename app/frontend/src/stylesheets/modules/pricing/{ => machines}/machines-pricing.scss (100%) rename app/frontend/src/stylesheets/modules/pricing/{ => machines}/pack-form.scss (100%) create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/configure-extended-prices-button.scss create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/create-extended-price.scss create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/delete-extended-price.scss create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/edit-extended-price.scss create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/extended-price-form.scss create mode 100644 app/frontend/src/stylesheets/modules/pricing/spaces/spaces-pricing.scss diff --git a/app/controllers/api/prices_controller.rb b/app/controllers/api/prices_controller.rb index de84774a2..fdcf6de1b 100644 --- a/app/controllers/api/prices_controller.rb +++ b/app/controllers/api/prices_controller.rb @@ -36,7 +36,7 @@ class API::PricesController < API::ApiController def destroy authorize @price - @price.destroy + @price.safe_destroy head :no_content end diff --git a/app/frontend/src/javascript/components/pricing/spaces/configure-extended-price-button.tsx b/app/frontend/src/javascript/components/pricing/spaces/configure-extended-price-button.tsx index 80c93ba1e..f0d1d1c76 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/configure-extended-price-button.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/configure-extended-price-button.tsx @@ -27,6 +27,13 @@ export const ConfigureExtendedPriceButton: React.FC>(prices); const [showList, setShowList] = useState(false); + /** + * Return the number of minutes, user-friendly formatted + */ + const formatDuration = (minutes: number): string => { + return t('app.admin.configure_extended_prices_button.extended_price_DURATION', { DURATION: minutes }); + }; + /** * Open/closes the popover listing the existing packs */ @@ -58,21 +65,21 @@ export const ConfigureExtendedPriceButton: React.FC - - {showList && + {showList &&
      {extendedPrices?.map(extendedPrice =>
    • - {extendedPrice.duration} {t('app.admin.calendar.minutes')} - {FormatLib.price(extendedPrice.amount)} - + {formatDuration(extendedPrice.duration)} - {FormatLib.price(extendedPrice.amount)} +
    • )}
    - {extendedPrices?.length === 0 && {t('app.admin.configure_extendedPrices_button.no_extendedPrices')}} + {extendedPrices?.length === 0 && {t('app.admin.configure_extended_prices_button.no_extended_prices')}}
    }
    ); diff --git a/app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx b/app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx index c01be253a..082cab8ad 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx @@ -43,24 +43,24 @@ export const CreateExtendedPrice: React.FC = ({ onSucc // create it on the API PriceAPI.create(newExtendedPrice) .then(() => { - onSuccess(t('app.admin.create_extendedPrice.extendedPrice_successfully_created')); + onSuccess(t('app.admin.create_extended_price.extended_price_successfully_created')); toggleModal(); }) .catch(error => onError(error)); }; return ( -
    - +
    + - {t('app.admin.create_extendedPrice.new_extendedPrice_info', { TYPE: priceableType })} + {t('app.admin.create_extended_price.new_extended_price_info', { TYPE: priceableType })} diff --git a/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx b/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx index 82307709f..75931d2b5 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx @@ -33,23 +33,23 @@ export const DeleteExtendedPrice: React.FC = ({ onSucc */ const onDeleteConfirmed = (): void => { PriceAPI.destroy(price.id).then(() => { - onSuccess(t('app.admin.delete_extendedPrice.extendedPrice_deleted')); + onSuccess(t('app.admin.delete_extended_price.extended_price_deleted')); }).catch((error) => { - onError(t('app.admin.delete_extendedPrice.unable_to_delete') + error); + onError(t('app.admin.delete_extended_price.unable_to_delete') + error); }); toggleDeletionModal(); }; return ( -
    - } onClick={toggleDeletionModal} /> - + } onClick={toggleDeletionModal} /> + - {t('app.admin.delete_extendedPrice.delete_confirmation')} + {t('app.admin.delete_extended_price.delete_confirmation')}
    ); diff --git a/app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx b/app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx index 2edd9abef..3b1608a29 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx @@ -42,7 +42,7 @@ export const EditExtendedPrice: React.FC = ({ price, onS const handleUpdate = (price: Price): void => { PriceAPI.update(price) .then(() => { - onSuccess(t('app.admin.edit_extendedPrice.extendedPrice_successfully_updated')); + onSuccess(t('app.admin.edit_extended_price.extended_price_successfully_updated')); setExtendedPriceData(price); toggleModal(); }) @@ -50,16 +50,16 @@ export const EditExtendedPrice: React.FC = ({ price, onS }; return ( -
    - } onClick={handleRequestEdit} /> +
    + } onClick={handleRequestEdit} /> - {extendedPriceData && } + confirmButton={t('app.admin.edit_extended_price.confirm_changes')} + onConfirmSendFormId="edit-extended-price"> + {extendedPriceData && }
    ); diff --git a/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx b/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx index 34e8e354c..eff0bcc45 100644 --- a/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx +++ b/app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx @@ -7,9 +7,9 @@ import { IFablab } from '../../../models/fablab'; declare let Fablab: IFablab; -interface PackFormProps { +interface ExtendedPriceFormProps { formId: string, - onSubmit: (pack: Price) => void, + onSubmit: (price: Price) => void, price?: Price, } @@ -17,7 +17,7 @@ interface PackFormProps { * A form component to create/edit a extended price. * The form validation must be created elsewhere, using the attribute form={formId}. */ -export const ExtendedPriceForm: React.FC = ({ formId, onSubmit, price }) => { +export const ExtendedPriceForm: React.FC = ({ formId, onSubmit, price }) => { const [extendedPriceData, updateExtendedPriceData] = useImmer(price || {} as Price); const { t } = useTranslation('admin'); @@ -49,8 +49,8 @@ export const ExtendedPriceForm: React.FC = ({ formId, onSubmit, p }; return ( - - + + = ({ onError, onSuccess }) => // retrieve the initial data useEffect(() => { - SpaceAPI.index(false) + SpaceAPI.index() .then(data => setSpaces(data)) .catch(error => onError(error)); GroupAPI.index({ disabled: false, admins: false }) @@ -67,7 +67,7 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => * Find the default price (hourly rate) matching the given criterion */ const findPriceBy = (spaceId, groupId): Price => { - return prices.find(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration == 60); + return prices.find(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration === 60); }; /** @@ -101,16 +101,17 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => }; return ( -
    +
    -

    -

    -

    {t('app.admin.pricing.you_can_override')}

    +

    +

    +

    {t('app.admin.spaces_pricing.you_can_override')}

    +

    {t('app.admin.spaces_pricing.extended_prices')}

    - + {groups?.map(group => )} @@ -118,7 +119,7 @@ const SpacesPricing: React.FC = ({ onError, onSuccess }) => {spaces?.map(space => {groups?.map(group => - - + + - + diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index 29083df38..705aad368 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -58,6 +58,7 @@ class VatHistoryService # {start: 0000-01-01, end: fab-manager initial setup date, enabled: false} # ] => VAT was enabled at some point, and disabled at some other point later + date_rates = [] if vat_rate_type.present? vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') first_vat_rate_by_type = vat_rate_by_type&.select { |v| v.value.present? }&.first @@ -87,7 +88,6 @@ class VatHistoryService end # Now we have all the rates history, we can build the final chronology, depending on whether VAT was enabled or not - date_rates = [] vat_rate_history_values.each do |rate| # when the VAT rate was enabled, set the date it was enabled and the rate range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index cac1dc920..5ac4ef33d 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -495,13 +495,14 @@ en: details: "Details" amount: "Amount" machine_booking-3D_printer: "Machine booking - 3D printer" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Total amount" total_including_all_taxes: "Total incl. all taxes" VAT_disabled: "VAT disabled" VAT_enabled: "VAT enabled" - including_VAT: "Including VAT" + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Including Total excl. taxes" - including_amount_payed_on_ordering: "Including Amount payed on ordering" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Settlement by debit card on {DATE} at {TIME}, for an amount of {AMOUNT}" important_notes: "Important notes" address_and_legal_information: "Address and legal information" From 00b9bce587a5b3a99152e0e7ae7e801cf7b982da Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 17:00:49 +0100 Subject: [PATCH 25/59] export collected VAT by rate --- app/controllers/api/exports_controller.rb | 2 + .../javascript/controllers/admin/invoices.js | 11 +++ .../admin/invoices/accountingExportModal.html | 10 +- app/models/invoice_item.rb | 4 +- app/services/accounting_export_service.rb | 1 - app/services/vat_export_service.rb | 97 +++++++++++++++++++ app/workers/accounting_export_worker.rb | 3 +- config/locales/app.admin.en.yml | 9 +- config/locales/en.yml | 6 ++ 9 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 app/services/vat_export_service.rb diff --git a/app/controllers/api/exports_controller.rb b/app/controllers/api/exports_controller.rb index 66dc270c3..2b8ab1980 100644 --- a/app/controllers/api/exports_controller.rb +++ b/app/controllers/api/exports_controller.rb @@ -70,6 +70,8 @@ class API::ExportsController < API::ApiController case type when 'acd' export = export.where('created_at > ?', Invoice.maximum('updated_at')) + when 'vat' + export = export.where('created_at > ?', Invoice.maximum('updated_at')) else raise ArgumentError, "Unknown type accounting/#{type}" end diff --git a/app/frontend/src/javascript/controllers/admin/invoices.js b/app/frontend/src/javascript/controllers/admin/invoices.js index e0b52eafc..960025762 100644 --- a/app/frontend/src/javascript/controllers/admin/invoices.js +++ b/app/frontend/src/javascript/controllers/admin/invoices.js @@ -1414,6 +1414,16 @@ Application.Controllers.controller('AccountingExportModalController', ['$scope', decimalSeparator: ',', exportInvoicesAtZero: false, columns: ['journal_code', 'date', 'account_code', 'account_label', 'piece', 'line_label', 'debit_origin', 'credit_origin', 'debit_euro', 'credit_euro', 'lettering'] + }, + vat: { + format: 'csv', + encoding: 'UTF-8', + separator: ';', + dateFormat: '%Y-%m-%d', + labelMaxLength: 'N/A', + decimalSeparator: '.', + exportInvoicesAtZero: false, + columns: ['start_date', 'end_date', 'vat_rate', 'amount'] } }; @@ -1433,6 +1443,7 @@ Application.Controllers.controller('AccountingExportModalController', ['$scope', // binding to radio button "export to" $scope.exportTarget = { + type: null, software: null, startDate: null, endDate: null, diff --git a/app/frontend/templates/admin/invoices/accountingExportModal.html b/app/frontend/templates/admin/invoices/accountingExportModal.html index 4c952b4c9..4d6f97523 100644 --- a/app/frontend/templates/admin/invoices/accountingExportModal.html +++ b/app/frontend/templates/admin/invoices/accountingExportModal.html @@ -42,11 +42,15 @@
    -

    {{ 'app.admin.invoices.export_to' }}

    +

    {{ 'app.admin.invoices.export_what' }}

    -
    diff --git a/app/models/invoice_item.rb b/app/models/invoice_item.rb index 7212a91f5..9d8cfe867 100644 --- a/app/models/invoice_item.rb +++ b/app/models/invoice_item.rb @@ -40,8 +40,10 @@ class InvoiceItem < Footprintable def invoice_item_type if object_type == Reservation.name object.try(:reservable_type) || '' - elsif object_type == Subscription.name + elsif [Subscription.name, OfferDay.name].include? object_type Subscription.name + elsif object_type == StatisticProfilePrepaidPack.name + object.prepaid_pack.priceable_type else '' end diff --git a/app/services/accounting_export_service.rb b/app/services/accounting_export_service.rb index b4451c13e..e9f15f302 100644 --- a/app/services/accounting_export_service.rb +++ b/app/services/accounting_export_service.rb @@ -16,7 +16,6 @@ class AccountingExportService @label_max_length = 50 @export_zeros = false @journal_code = Setting.get('accounting_journal_code') || '' - @date_format = date_format @columns = columns end diff --git a/app/services/vat_export_service.rb b/app/services/vat_export_service.rb new file mode 100644 index 000000000..a5a9ebcbf --- /dev/null +++ b/app/services/vat_export_service.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: false + +# Provides the routine to export the collected VAT data to a CSV file. +class VatExportService + include ActionView::Helpers::NumberHelper + + attr_reader :encoding, :format, :separator, :date_format, :columns, :decimal_separator + + def initialize(columns, encoding: 'UTF-8', format: 'CSV', separator: ';') + @encoding = encoding + @format = format + @separator = separator + @decimal_separator = '.' + @date_format = '%Y-%m-%d' + @columns = columns + end + + def set_options(decimal_separator: ',', date_format: '%d/%m/%Y', label_max_length: nil, export_zeros: nil) + @decimal_separator = decimal_separator + @date_format = date_format + end + + def export(start_date, end_date, file) + # build CSV content + content = header_row + invoices = Invoice.where('created_at >= ? AND created_at <= ?', start_date, end_date).order('created_at ASC') + vat_totals = compute_vat_totals(invoices) + content << generate_rows(vat_totals, start_date, end_date) + + # write content to file + File.open(file, "w:#{encoding}") { |f| f.puts content.encode(encoding, invalid: :replace, undef: :replace) } + end + + private + + def header_row + row = '' + columns.each do |column| + row << I18n.t("vat_export.#{column}") << separator + end + "#{row}\n" + end + + def generate_rows(vat_totals, start_date, end_date) + rows = '' + + vat_totals.each do |rate, total| + next if rate.zero? + + rows += "#{row( + start_date, + end_date, + rate, + total + )}\n" + end + + rows + end + + def compute_vat_totals(invoices) + vat_total = [] + service = VatHistoryService.new + invoices.each do |i| + puts "processing invoice #{i.id}..." unless Rails.env.test? + vat_total.push service.invoice_vat(i) + end + + vat_total.map(&:values).flatten.group_by { |tot| tot[:vat_rate] }.map { |k, v| [k, v.map { |t| t[:total_vat] }.reduce(:+)] }.to_h + end + + # Generate a row of the export, filling the configured columns with the provided values + def row(start_date, end_date, vat_rate, amount) + row = '' + columns.each do |column| + case column + when 'start_date' + row << DateTime.parse(start_date).strftime(date_format) + when 'end_date' + row << DateTime.parse(end_date).strftime(date_format) + when 'vat_rate' + row << vat_rate.to_s + when 'amount' + row << format_number(amount / 100.0) + else + puts "Unsupported column: #{column}" + end + row << separator + end + row + end + + # Format the given number as a string, using the configured separator + def format_number(num) + number_to_currency(num, unit: '', separator: decimal_separator, delimiter: '', precision: 2) + end +end diff --git a/app/workers/accounting_export_worker.rb b/app/workers/accounting_export_worker.rb index a0bd28c22..2fe5b217a 100644 --- a/app/workers/accounting_export_worker.rb +++ b/app/workers/accounting_export_worker.rb @@ -10,7 +10,8 @@ class AccountingExportWorker raise SecurityError, 'Not allowed to export' unless export.user.admin? data = JSON.parse(export.query) - service = AccountingExportService.new( + service = export.export_type == 'vat' ? VatExportService : AccountingExportService + service = service.new( data['columns'], encoding: data['encoding'], format: export.extension, separator: export.key ) diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 5ac4ef33d..5d1f85fe5 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -679,9 +679,10 @@ en: codes_customization_success: "Customization of the accounting codes successfully saved." unexpected_error_occurred: "An unexpected error occurred while saving the codes. Please try again later." export_accounting_data: "Export accounting data" - export_to: "Export to the accounting software" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "Export is running. You'll be notified when it's ready." - acd: "ACD" export_form_date: "Export from" export_to_date: "Export until" format: "File format" @@ -704,6 +705,10 @@ en: debit_euro: "Euro debit" credit_euro: "Euro credit" lettering: "Lettering" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Payment settings" online_payment: "Online payment" diff --git a/config/locales/en.yml b/config/locales/en.yml index a25312b9d..84e6745e2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -147,6 +147,11 @@ en: Event_reservation: "event reserv." Space_reservation: "space reserv." wallet: "wallet" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "I've reserved" @@ -331,6 +336,7 @@ en: users_reservations: "of the reservations' list" availabilities_index: "of the reservations availabilities" accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT" is_over: "is over." download_here: "Download here" notify_admin_import_complete: From 330b8c3ba4d320ae5e1e182583a92742e232e5b1 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 17:06:31 +0100 Subject: [PATCH 26/59] fix accounting export confirmation message by mail --- config/locales/mails.en.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 2063f8c60..f4d6d3f54 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -231,7 +231,8 @@ en: users_subscriptions: "of the subscriptions' list" users_reservations: "of the reservations' list" availabilities_index: "of the reservations availabilities" - accounting_accounting-software: "of the accounting data" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: "Excel file generated successfully. To download it, click" here: "here" file_type: From 61724192a5c05e8626720a895779933687ec13f7 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:25:24 +0100 Subject: [PATCH 27/59] updated changedlog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3813d3b4d..20b3f8a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog Fab-manager +- Ability to configure multiple VAT rates, per kind of invoiced item +- Refactored the extended prices frontend code to allow future customization +- Fix a bug: the amount label in not correctly shown in the extended prices modal + ## v5.2.0 2021 December 23 - Ability to configure prices for spaces by time slots different than the default hourly rate From 68e12c7b12cdc8a7358f63e451b41da2f9ef1008 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:21 +0100 Subject: [PATCH 28/59] New translations en.yml (French) --- config/locales/fr.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8f0dde0c2..4cf57486b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -90,7 +90,7 @@ fr: other: "%{count} places %{NAME}" coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total TTC" - including_VAT_RATE: "Dont TVA %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Dont total HT" including_amount_payed_on_ordering: "Dont montant payé à la commande" total_amount: "Montant total" @@ -147,6 +147,11 @@ fr: Event_reservation: "réserv. événement" Space_reservation: "réserv. espace" wallet: "porte-monnaie" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "J'ai réservé" @@ -331,6 +336,7 @@ fr: users_reservations: "de la liste des réservations" availabilities_index: "des disponibilités de réservations" accounting_acd: "des données comptables pour ACD" + accounting_vat: "of the collected VAT" is_over: "est terminé." download_here: "Téléchargez ici" notify_admin_import_complete: From d5407e042a2449618c1ddc0ce3f13ca9e7864cd1 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:28 +0100 Subject: [PATCH 29/59] New translations mails.en.yml (Portuguese) --- config/locales/mails.pt.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.pt.yml b/config/locales/mails.pt.yml index 16441aa50..8016798fd 100755 --- a/config/locales/mails.pt.yml +++ b/config/locales/mails.pt.yml @@ -231,7 +231,8 @@ pt: users_subscriptions: "da lista de assinaturas" users_reservations: "da lista de reservas" availabilities_index: "as reservas disponíveis" - accounting_accounting-software: "de dados contábeis" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: "Arquivo do Excel gerado com êxito. Para fazer o download, clique" here: "aqui" file_type: From d671e4995117977cea99cecd3449b3c6cd948bba Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:37 +0100 Subject: [PATCH 30/59] New translations mails.en.yml (Zulu) --- config/locales/mails.zu.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.zu.yml b/config/locales/mails.zu.yml index 462bdb743..b4942edd7 100644 --- a/config/locales/mails.zu.yml +++ b/config/locales/mails.zu.yml @@ -231,7 +231,8 @@ zu: users_subscriptions: "crwdns4157:0crwdne4157:0" users_reservations: "crwdns4159:0crwdne4159:0" availabilities_index: "crwdns4161:0crwdne4161:0" - accounting_accounting-software: "crwdns4163:0crwdne4163:0" + accounting_acd: "crwdns22269:0crwdne22269:0" + accounting_vat: "crwdns22271:0crwdne22271:0" click_to_download: "crwdns4165:0crwdne4165:0" here: "crwdns4167:0crwdne4167:0" file_type: From f5e1a166e6434672faebf8fd84851a84985beade Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:38 +0100 Subject: [PATCH 31/59] New translations mails.en.yml (Norwegian) --- config/locales/mails.no.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.no.yml b/config/locales/mails.no.yml index 39ff68286..890ed1d1c 100644 --- a/config/locales/mails.no.yml +++ b/config/locales/mails.no.yml @@ -231,7 +231,8 @@ users_subscriptions: "of the subscriptions' list" users_reservations: "of the reservations' list" availabilities_index: "of the reservations availabilities" - accounting_accounting-software: "of the accounting data" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: "Excel file generated successfully. To download it, click" here: "here" file_type: From 1841ba27f19f7125e2f3e6c47899e02d40cd0879 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:39 +0100 Subject: [PATCH 32/59] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 62 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 0ec43cec7..d483ce78f 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -369,6 +369,11 @@ fr: status_disabled: "Désactivés" status_all: "Tous" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Les tarifs ci-dessous correspondent à une heure d'utilisation machine, sans abonnement." @@ -380,10 +385,12 @@ fr: packs: "Packs prépayés" no_packs: "Aucun pack pour le moment" pack_DURATION: "{DURATION} heures" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" - extended_prices_form: + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" + extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Heures" @@ -411,21 +418,21 @@ fr: edit_pack: "Modifier le pack" confirm_changes: "Valider les modifications" pack_successfully_updated: "Le pack prépayé a bien été mis à jour." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Ajouter un code promotionnel" @@ -488,13 +495,14 @@ fr: details: "Détails" amount: "Montant" machine_booking-3D_printer: "Réservation Machine - Imprimante 3D" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Montant total" total_including_all_taxes: "Total TTC" VAT_disabled: "TVA désactivée" VAT_enabled: "TVA activée" - including_VAT: "Dont TVA" + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Dont total HT" - including_amount_payed_on_ordering: "Dont montant payé à la commande" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Règlement effectué par carte bancaire le {DATE} à {TIME}, pour un montant de {AMOUNT}" important_notes: "Informations importantes" address_and_legal_information: "Adresse et informations légales" @@ -544,6 +552,15 @@ fr: enable_VAT: "Activer la TVA" VAT_rate: "Taux de TVA" VAT_history: "Historique des taux de TVA" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Changé le" changed_by: "Par" deleted_user: "Utilisateur supprimé" @@ -662,9 +679,10 @@ fr: codes_customization_success: "La personnalisation des codes comptables a bien été enregistrée." unexpected_error_occurred: "Une erreur inattendue est survenue lors de l’enregistrement des codes. Veuillez réessayer plus tard." export_accounting_data: "Exporter les données comptables" - export_to: "Exporter vers le logiciel comptable" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "L'export est en cours. Vous serez notifié lorsqu'il sera prêt." - acd: "ACD" export_form_date: "Exporter depuis le" export_to_date: "Exporter jusqu'au" format: "Format de fichier" @@ -687,6 +705,10 @@ fr: debit_euro: "Débit euro" credit_euro: "Crédit euro" lettering: "Lettrage" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Paramètres de paiement" online_payment: "Paiement en ligne" From e5c665db4283ae2a39018e0ac30373c2c3853bd2 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:40 +0100 Subject: [PATCH 33/59] New translations en.yml (Zulu) --- config/locales/zu.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/zu.yml b/config/locales/zu.yml index b238e8d90..f8b93e30b 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -90,7 +90,7 @@ zu: other: "crwdns3327:5%{count}crwdnd3327:5%{NAME}crwdne3327:5" coupon_CODE_discount_of_DISCOUNT: "crwdns3331:0CODE={CODE}crwdnd3331:0DISCOUNT={DISCOUNT}crwdnd3331:0TYPE={TYPE}crwdne3331:0" #messageFormat interpolation total_including_all_taxes: "crwdns3333:0crwdne3333:0" - including_VAT_RATE: "crwdns3335:0%{RATE}crwdne3335:0" + including_VAT_RATE: "crwdns22257:0%{RATE}crwdnd22257:0%{AMOUNT}crwdne22257:0" including_total_excluding_taxes: "crwdns3337:0crwdne3337:0" including_amount_payed_on_ordering: "crwdns3339:0crwdne3339:0" total_amount: "crwdns3341:0crwdne3341:0" @@ -147,6 +147,11 @@ zu: Event_reservation: "crwdns3407:0crwdne3407:0" Space_reservation: "crwdns3409:0crwdne3409:0" wallet: "crwdns3411:0crwdne3411:0" + vat_export: + start_date: "crwdns22259:0crwdne22259:0" + end_date: "crwdns22261:0crwdne22261:0" + vat_rate: "crwdns22263:0crwdne22263:0" + amount: "crwdns22265:0crwdne22265:0" #training availabilities trainings: i_ve_reserved: "crwdns3413:0crwdne3413:0" @@ -331,6 +336,7 @@ zu: users_reservations: "crwdns3657:0crwdne3657:0" availabilities_index: "crwdns3659:0crwdne3659:0" accounting_acd: "crwdns3661:0crwdne3661:0" + accounting_vat: "crwdns22267:0crwdne22267:0" is_over: "crwdns3663:0crwdne3663:0" download_here: "crwdns3665:0crwdne3665:0" notify_admin_import_complete: From ef881144083f350fcc1a8df9a4abb1f71678a933 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:41 +0100 Subject: [PATCH 34/59] New translations en.yml (Spanish) --- config/locales/es.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/es.yml b/config/locales/es.yml index d28f837b6..597d0750a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -90,7 +90,7 @@ es: other: "%{count} %{NAME} entradas" coupon_CODE_discount_of_DISCOUNT: "Cupón {CODE}: descuento de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total impuestos incluidos" - including_VAT_RATE: "Incluyendo IVA %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Excluyendo IVA" including_amount_payed_on_ordering: "Incluyendo cantidad pagada en el pedido" total_amount: "Precio total" @@ -147,6 +147,11 @@ es: Event_reservation: "reserv. evento" Space_reservation: "reserv. espacio" wallet: "cartera" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "Reservé" @@ -331,6 +336,7 @@ es: users_reservations: "de la lista de reservas" availabilities_index: "de las reservas disponibles" accounting_acd: "de los datos contables para ACD" + accounting_vat: "of the collected VAT" is_over: "se ha acabado." download_here: "Descargar aquí" notify_admin_import_complete: From 569ca0e81ed022a50bddc73f658ca91cafbd523f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:42 +0100 Subject: [PATCH 35/59] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 62 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index b575c36bc..0635eb6b1 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -369,6 +369,11 @@ es: status_disabled: "Disabled" status_all: "All" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, without subscription." @@ -380,10 +385,12 @@ es: packs: "Prepaid packs" no_packs: "No packs for now" pack_DURATION: "{DURATION} hours" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" - extended_prices_form: + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" + extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Hours" @@ -411,21 +418,21 @@ es: edit_pack: "Edit the pack" confirm_changes: "Confirm changes" pack_successfully_updated: "The prepaid pack was successfully updated." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Añadir un cupón" @@ -488,13 +495,14 @@ es: details: "Detalles" amount: "Cantidad" machine_booking-3D_printer: "Reserva de la máquina- Impresora 3D" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Cantidad total" total_including_all_taxes: "Total incl. todos los impuestos" VAT_disabled: "IVA desactivado" VAT_enabled: "IVA activado" - including_VAT: "Incluido IVA" + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Incluido Total excl. impuestos" - including_amount_payed_on_ordering: "Incluido el monto pagado en el pedido" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Liquidación por tarjeta de débito el {DATE} a las {TIME}, por una cantidad de {AMOUNT}" important_notes: "Notas importantes" address_and_legal_information: "Dirección e información legal" @@ -544,6 +552,15 @@ es: enable_VAT: "Habilitar IVA" VAT_rate: "Ratio IVA" VAT_history: "Historial de ratios de IVA" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Cambiado en" changed_by: "Por" deleted_user: "Usario eliminado" @@ -662,9 +679,10 @@ es: codes_customization_success: "Customization of accounting codes successfully saved." unexpected_error_occurred: "An unexpected error occurred while saving the codes. Please try again later." export_accounting_data: "Export accounting data" - export_to: "Export to the accounting software" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "Exportando, será notificado cuando esté listo." - acd: "ACD" export_form_date: "Export from" export_to_date: "Export until" format: "File format" @@ -687,6 +705,10 @@ es: debit_euro: "Euro debit" credit_euro: "Euro credit" lettering: "Lettering" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Payment settings" online_payment: "Online payment" From 2a0a0a3e301b5b8b5fb890f70022434640f44cbc Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:43 +0100 Subject: [PATCH 36/59] New translations en.yml (German) --- config/locales/de.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index bf58214a8..3c9b17b18 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -90,7 +90,7 @@ de: other: "%{count} %{NAME}-Tickets" coupon_CODE_discount_of_DISCOUNT: "Gutschein {CODE}: Rabatt von {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Gesamtpreis inkl. Steuern" - including_VAT_RATE: "Inklusive MwSt. %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern" including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag" total_amount: "Gesamtbetrag" @@ -147,6 +147,11 @@ de: Event_reservation: "Veranstaltungsreservierung" Space_reservation: "Raumreservierung" wallet: "Guthabenkonto" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "Ich reservierte" @@ -331,6 +336,7 @@ de: users_reservations: "der Reservierungsliste" availabilities_index: "der Verfügbarkeit der Reservierungen" accounting_acd: "der Rechnungsdaten für ACD" + accounting_vat: "of the collected VAT" is_over: "ist beendet." download_here: "Hier herunterladen" notify_admin_import_complete: From d95c4f480b5b09b1b17f9d518dbd2626d9bf953f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:44 +0100 Subject: [PATCH 37/59] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 62 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index d892dd12b..37bc2820e 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -369,6 +369,11 @@ de: status_disabled: "Deaktiviert" status_all: "Alle" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Die unten aufgeführten Preise entsprechen einer Stunde Maschinengebrauch, ohne Abonnement." @@ -380,10 +385,12 @@ de: packs: "Prepaid packs" no_packs: "No packs for now" pack_DURATION: "{DURATION} hours" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" - extended_prices_form: + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" + extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Hours" @@ -411,21 +418,21 @@ de: edit_pack: "Edit the pack" confirm_changes: "Confirm changes" pack_successfully_updated: "The prepaid pack was successfully updated." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Gutschein hinzufügen" @@ -488,13 +495,14 @@ de: details: "Details" amount: "Betrag" machine_booking-3D_printer: "Maschinen-Buchung - 3D-Drucker" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Gesamtbetrag" total_including_all_taxes: "Gesamtpreis inkl. Steuern" VAT_disabled: "MwSt. deaktiviert" VAT_enabled: "MwSt. aktiviert" - including_VAT: "Inklusive MwSt." + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern" - including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Begleichung mit Debitkarte am {DATE} um {TIME}, über den Betrag von {AMOUNT}" important_notes: "Wichtige Hinweise" address_and_legal_information: "Adresse und rechtliche Informationen" @@ -544,6 +552,15 @@ de: enable_VAT: "MwSt. aktivieren" VAT_rate: "MwSt.-Satz" VAT_history: "MwSt.-Sätze Historie" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Geändert am" changed_by: "Von" deleted_user: "Gelöschter Nutzer" @@ -662,9 +679,10 @@ de: codes_customization_success: "Anpassung der Abrechnungscodes erfolgreich gespeichert." unexpected_error_occurred: "Beim Speichern der Codes ist ein unerwarteter Fehler aufgetreten. Bitte versuchen Sie es später erneut." export_accounting_data: "Abrechnungsdaten exportieren" - export_to: "In die Buchhaltungssoftware exportieren" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "Export wird ausgeführt. Sie werden nach Fertigstellung benachrichtigt." - acd: "ACD" export_form_date: "Exportieren ab" export_to_date: "Exportieren bis" format: "Dateiformat" @@ -687,6 +705,10 @@ de: debit_euro: "Soll in Euro" credit_euro: "Guthaben in Euro" lettering: "Beschriftung" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Bezahlungseinstellungen" online_payment: "Online-Bezahlung" From e33f0756840b06f4d90e0061a90d6f1112fc48a5 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:45 +0100 Subject: [PATCH 38/59] New translations en.yml (Norwegian) --- config/locales/no.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/no.yml b/config/locales/no.yml index fddcda83a..e5ed9f719 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -90,7 +90,7 @@ other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Kupong {CODE}: rabatt på {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Sum inkl. MVA" - including_VAT_RATE: "Inkludert MVA %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Inkludert total ekskl. MVA" including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling" total_amount: "Totalbeløp" @@ -147,6 +147,11 @@ Event_reservation: "arrangementetsreserv." Space_reservation: "reserv., plass/rom" wallet: "lommebok" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "Jeg har reservert" @@ -331,6 +336,7 @@ users_reservations: "fra reservasjonslisten" availabilities_index: "of the reservations availabilities" accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT" is_over: "is over." download_here: "Download here" notify_admin_import_complete: From 9d2069bc53fb6c475aa6057a2439a6a5984d657d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:47 +0100 Subject: [PATCH 39/59] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 62 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 7d18604af..87b303d91 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -369,6 +369,11 @@ status_disabled: "Deaktivert" status_all: "Alle" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Prisene under samsvarer med en time maskinbruk uten medlemskap." @@ -380,10 +385,12 @@ packs: "Forhåndsbetalte pakker" no_packs: "Ingen pakker tilgjengelig nå" pack_DURATION: "{DURATION} timer" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" - extended_prices_form: + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" + extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Timer" @@ -411,21 +418,21 @@ edit_pack: "Rediger pakken" confirm_changes: "Bekreft endringer" pack_successfully_updated: "Den forhåndsbetalte pakken ble oppdatert." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Legg til rabattkupong" @@ -488,13 +495,14 @@ details: "Detaljer" amount: "Beløp" machine_booking-3D_printer: "Reservere 3D-printer" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Totalbeløp" total_including_all_taxes: "Sum inkl. MVA" VAT_disabled: "MVA deaktivert" VAT_enabled: "MVA aktivert" - including_VAT: "Inkludert MVA" + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Totalpris, eks. MVA" - including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Oppgjør med betalingskort på {DATE} hos {TIME} for et beløp på {AMOUNT}" important_notes: "Viktige merknader" address_and_legal_information: "Adresse og juridisk informasjon" @@ -544,6 +552,15 @@ enable_VAT: "Aktiver MVA" VAT_rate: "MVA sats" VAT_history: "MVA-sats, historikk" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Endret" changed_by: "Av" deleted_user: "Slettet bruker" @@ -662,9 +679,10 @@ codes_customization_success: "Tilpasning av regnskapskodene ble lagret." unexpected_error_occurred: "Det oppstod en uventet feil under lagring av kodene. Prøv igjen senere." export_accounting_data: "Eksporter regnskapsdata" - export_to: "Eksporter til regnskapsprogramvare" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "Eksport er startet. Du vil bli varslet når den er klar." - acd: "ACD" export_form_date: "Eksporter fra" export_to_date: "Eksporter til" format: "Filformat" @@ -687,6 +705,10 @@ debit_euro: "Kreditt i Euro" credit_euro: "Kreditt i Euro" lettering: "Lettering" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Betalingsinnstillinger" online_payment: "Online betaling" From 68b097e6d45dd8ef7ab7e59006204ba80421c6ad Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:48 +0100 Subject: [PATCH 40/59] New translations en.yml (Portuguese) --- config/locales/pt.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 2b0c5d7b1..87c6053a4 100755 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -90,7 +90,7 @@ pt: other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Cupom {CODE}: desconto de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total de taxas inclusas" - including_VAT_RATE: "Incluindo VAT %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Incluindo total de faixas exclusas" including_amount_payed_on_ordering: "Incluindo o valor pago na encomenda" total_amount: "Montante total" @@ -147,6 +147,11 @@ pt: Event_reservation: "reserva de evento." Space_reservation: "reserva de espaço." wallet: "carteira" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" #training availabilities trainings: i_ve_reserved: "Eu reservei" @@ -331,6 +336,7 @@ pt: users_reservations: "da lista de reservas" availabilities_index: "de reservas disponíveis" accounting_acd: "de dados contábeis para ACD" + accounting_vat: "of the collected VAT" is_over: "está finalizado." download_here: "Baixe aqui" notify_admin_import_complete: From d38b8b85ef663bb410ad5efcb2c4b6d70cf7bb07 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:49 +0100 Subject: [PATCH 41/59] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 62 ++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index f548b7cb8..c29caf0d5 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -369,6 +369,11 @@ pt: status_disabled: "Desabilitados" status_all: "Todos" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "Os preços abaixo correspondem a uma hora de uso de máquina, sem assinatura." @@ -380,10 +385,12 @@ pt: packs: "Pacotes pré-pagos" no_packs: "Não há pacotes no momento" pack_DURATION: "{DURATION} horas" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" - extended_prices_form: + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" + extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Horas" @@ -411,21 +418,21 @@ pt: edit_pack: "Editar o pacote" confirm_changes: "Confirmar alterações" pack_successfully_updated: "O pacote pré-pago foi atualizado com sucesso." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Adicionar cupom" @@ -488,13 +495,14 @@ pt: details: "Detalhes" amount: "Montante" machine_booking-3D_printer: "Reserva de máquina - 3D printer" + training_booking-3D_print: "Training booking - initiation to 3d printing" total_amount: "Montante total" total_including_all_taxes: "Total incluindo todas as taxas" VAT_disabled: "IVA desativado" VAT_enabled: "IVA activado" - including_VAT: "Incluindo IVA" + including_VAT: "Including VAT {RATE}% of {AMOUNT}" including_total_excluding_taxes: "Incluindo o total de taxas excluidas" - including_amount_payed_on_ordering: "Incluindo o valor pago na compra" + including_amount_payed_on_ordering: "Including amount payed on ordering" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Pagamento por cartão de débito em {DATE} ás {TIME}, no valor de {AMOUNT}" important_notes: "Notas importantes" address_and_legal_information: "Endereço e informações legais" @@ -544,6 +552,15 @@ pt: enable_VAT: "Ativar VAT" VAT_rate: "VAT taxa" VAT_history: "Histórico de taxas" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Alterado em" changed_by: "Por" deleted_user: "Usuário deletado" @@ -662,9 +679,10 @@ pt: codes_customization_success: "Customization of accounting codes successfully saved." unexpected_error_occurred: "Ocorreu um erro inesperado ao salvar os códigos. Tente novamente mais tarde." export_accounting_data: "Exportar dados de contabilidade" - export_to: "Exportar para o software de contabilidade" + export_what: "What do you want to export?" + export_VAT: "Export the collected VAT" + export_to_ACD: "Export all data to the accounting software ACD" export_is_running: "A Exportação está em andamento. Você será notificado quando terminar." - acd: "ACD" export_form_date: "Exportar de" export_to_date: "Exportar até" format: "Formato do arquivo" @@ -687,6 +705,10 @@ pt: debit_euro: "Débito em euro" credit_euro: "Crédito em euro" lettering: "Letras" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" payment: payment_settings: "Configurações de pagamento" online_payment: "Pagamento Online" From ee8807a790e9c7aaee2771ff0386096c3bb162ed Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:50 +0100 Subject: [PATCH 42/59] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 70 ++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 21c4b6cd2..96f003ae8 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -369,6 +369,11 @@ zu: status_disabled: "crwdns7267:0crwdne7267:0" status_all: "crwdns7269:0crwdne7269:0" spaces_pricing: + prices_match_space_hours_rates_html: "crwdns22175:0crwdne22175:0" + prices_calculated_on_hourly_rate_html: "crwdns22177:0{RATE}crwdnd22177:0{DURATION}crwdnd22177:0{PRICE}crwdne22177:0" + you_can_override: "crwdns22179:0crwdne22179:0" + extended_prices: "crwdns22181:0crwdne22181:0" + spaces: "crwdns22183:0crwdne22183:0" price_updated: "crwdns22135:0crwdne22135:0" machines_pricing: prices_match_machine_hours_rates_html: "crwdns21942:0crwdne21942:0" @@ -380,11 +385,13 @@ zu: packs: "crwdns21952:0crwdne21952:0" no_packs: "crwdns21954:0crwdne21954:0" pack_DURATION: "crwdns21956:0{DURATION}crwdne21956:0" - configure_extendedPrices_button: - extendedPrices: "crwdns22137:0crwdne22137:0" - no_extendedPrices: "crwdns22139:0crwdne22139:0" - extended_prices_form: - amount: "crwdns22141:0crwdne22141:0" + configure_extended_prices_button: + extended_prices: "crwdns22185:0crwdne22185:0" + no_extended_prices: "crwdns22187:0crwdne22187:0" + extended_price_DURATION: "crwdns22189:0{DURATION}crwdne22189:0" + extended_price_form: + duration: "crwdns22191:0crwdne22191:0" + amount: "crwdns22193:0crwdne22193:0" pack_form: hours: "crwdns21958:0crwdne21958:0" amount: "crwdns21960:0crwdne21960:0" @@ -411,21 +418,21 @@ zu: edit_pack: "crwdns21994:0crwdne21994:0" confirm_changes: "crwdns21996:0crwdne21996:0" pack_successfully_updated: "crwdns21998:0crwdne21998:0" - create_extendedPrice: - new_extendedPrice: "crwdns22143:0crwdne22143:0" - new_extendedPrice_info: "crwdns22145:0crwdne22145:0" - create_extendedPrice: "crwdns22147:0crwdne22147:0" - extendedPrice_successfully_created: "crwdns22149:0crwdne22149:0" - delete_extendedPrice: - extendedPrice_deleted: "crwdns22151:0crwdne22151:0" - unable_to_delete: "crwdns22153:0crwdne22153:0" - delete_extendedPrice: "crwdns22155:0crwdne22155:0" - confirm_delete: "crwdns22157:0crwdne22157:0" - delete_confirmation: "crwdns22159:0crwdne22159:0" - edit_extendedPrice: - edit_extendedPrice: "crwdns22161:0crwdne22161:0" - confirm_changes: "crwdns22163:0crwdne22163:0" - extendedPrice_successfully_updated: "crwdns22165:0crwdne22165:0" + create_extended_price: + new_extended_price: "crwdns22195:0crwdne22195:0" + new_extended_price_info: "crwdns22197:0crwdne22197:0" + create_extended_price: "crwdns22199:0crwdne22199:0" + extended_price_successfully_created: "crwdns22201:0crwdne22201:0" + delete_extended_price: + extended_price_deleted: "crwdns22203:0crwdne22203:0" + unable_to_delete: "crwdns22205:0crwdne22205:0" + delete_extended_price: "crwdns22207:0crwdne22207:0" + confirm_delete: "crwdns22209:0crwdne22209:0" + delete_confirmation: "crwdns22211:0crwdne22211:0" + edit_extended_price: + edit_extended_price: "crwdns22213:0crwdne22213:0" + confirm_changes: "crwdns22215:0crwdne22215:0" + extended_price_successfully_updated: "crwdns22217:0crwdne22217:0" #ajouter un code promotionnel coupons_new: add_a_coupon: "crwdns7271:0crwdne7271:0" @@ -488,13 +495,14 @@ zu: details: "crwdns7363:0crwdne7363:0" amount: "crwdns7365:0crwdne7365:0" machine_booking-3D_printer: "crwdns7367:0crwdne7367:0" + training_booking-3D_print: "crwdns22219:0crwdne22219:0" total_amount: "crwdns7369:0crwdne7369:0" total_including_all_taxes: "crwdns7371:0crwdne7371:0" VAT_disabled: "crwdns7373:0crwdne7373:0" VAT_enabled: "crwdns7375:0crwdne7375:0" - including_VAT: "crwdns7377:0crwdne7377:0" + including_VAT: "crwdns22221:0{RATE}crwdnd22221:0{AMOUNT}crwdne22221:0" including_total_excluding_taxes: "crwdns7379:0crwdne7379:0" - including_amount_payed_on_ordering: "crwdns7381:0crwdne7381:0" + including_amount_payed_on_ordering: "crwdns22223:0crwdne22223:0" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "crwdns7383:0{DATE}crwdnd7383:0{TIME}crwdnd7383:0{AMOUNT}crwdne7383:0" important_notes: "crwdns7385:0crwdne7385:0" address_and_legal_information: "crwdns7387:0crwdne7387:0" @@ -544,6 +552,15 @@ zu: enable_VAT: "crwdns7469:0crwdne7469:0" VAT_rate: "crwdns7471:0crwdne7471:0" VAT_history: "crwdns7473:0crwdne7473:0" + VAT_notice: "crwdns22225:0crwdne22225:0" + edit_multi_VAT_button: "crwdns22227:0crwdne22227:0" + multiVAT: "crwdns22229:0crwdne22229:0" + multi_VAT_notice: "crwdns22231:0{RATE}crwdne22231:0" + VAT_rate_machine: "crwdns22233:0crwdne22233:0" + VAT_rate_space: "crwdns22235:0crwdne22235:0" + VAT_rate_training: "crwdns22237:0crwdne22237:0" + VAT_rate_event: "crwdns22239:0crwdne22239:0" + VAT_rate_subscription: "crwdns22241:0crwdne22241:0" changed_at: "crwdns7475:0crwdne7475:0" changed_by: "crwdns7477:0crwdne7477:0" deleted_user: "crwdns7479:0crwdne7479:0" @@ -662,9 +679,10 @@ zu: codes_customization_success: "crwdns7683:0crwdne7683:0" unexpected_error_occurred: "crwdns20578:0crwdne20578:0" export_accounting_data: "crwdns7685:0crwdne7685:0" - export_to: "crwdns7687:0crwdne7687:0" + export_what: "crwdns22243:0crwdne22243:0" + export_VAT: "crwdns22245:0crwdne22245:0" + export_to_ACD: "crwdns22247:0crwdne22247:0" export_is_running: "crwdns7689:0crwdne7689:0" - acd: "crwdns7691:0crwdne7691:0" export_form_date: "crwdns7693:0crwdne7693:0" export_to_date: "crwdns7695:0crwdne7695:0" format: "crwdns7697:0crwdne7697:0" @@ -687,6 +705,10 @@ zu: debit_euro: "crwdns7729:0crwdne7729:0" credit_euro: "crwdns7731:0crwdne7731:0" lettering: "crwdns7733:0crwdne7733:0" + start_date: "crwdns22249:0crwdne22249:0" + end_date: "crwdns22251:0crwdne22251:0" + vat_rate: "crwdns22253:0crwdne22253:0" + amount: "crwdns22255:0crwdne22255:0" payment: payment_settings: "crwdns20580:0crwdne20580:0" online_payment: "crwdns20582:0crwdne20582:0" From 5c16b33bffc92fe057651ddc9b2f10dee6383756 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:51 +0100 Subject: [PATCH 43/59] New translations mails.en.yml (German) --- config/locales/mails.de.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.de.yml b/config/locales/mails.de.yml index bf41169a2..c856e67e6 100644 --- a/config/locales/mails.de.yml +++ b/config/locales/mails.de.yml @@ -231,7 +231,8 @@ de: users_subscriptions: "der Abonnementliste" users_reservations: "der Reservierungsliste" availabilities_index: "der Verfügbarkeit der Reservierungen" - accounting_accounting-software: "der Buchhaltungsdaten" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: "Excel-Datei erfolgreich erstellt. Zum Herunterladen klicken Sie" here: "hier" file_type: From 1d5f880eb923531059a294f4aefd532f7e3b3627 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:55 +0100 Subject: [PATCH 44/59] New translations mails.en.yml (French) --- config/locales/mails.fr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.fr.yml b/config/locales/mails.fr.yml index 321ff4a2b..73b19c1e2 100644 --- a/config/locales/mails.fr.yml +++ b/config/locales/mails.fr.yml @@ -231,7 +231,8 @@ fr: users_subscriptions: "de la liste des abonnements" users_reservations: "de la liste des réservations" availabilities_index: "des disponibilités de réservations" - accounting_accounting-software: "des données comptables" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: "La génération est terminée. Pour télécharger le fichier %{TYPE}, cliquez" here: "ici" file_type: From 1ded66c6ecef2afcd3bf6f43d2e01669fa1de117 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:27:56 +0100 Subject: [PATCH 45/59] New translations mails.en.yml (Spanish) --- config/locales/mails.es.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/locales/mails.es.yml b/config/locales/mails.es.yml index 6eb051765..baf2bf100 100644 --- a/config/locales/mails.es.yml +++ b/config/locales/mails.es.yml @@ -231,7 +231,8 @@ es: users_subscriptions: "de la lista de suscripciones" users_reservations: "de la lista de reservas" availabilities_index: "de las reservas disponibles" - accounting_accounting-software: "de los datos contables" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" click_to_download: " archivo Excel generado correctamente. Para descargarlo, haga clic " here: "aquí" file_type: From 6ecff924d1e88b3ed74451bed70f2c36cb680c2d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:48:43 +0100 Subject: [PATCH 46/59] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 46 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index d483ce78f..8e97caf3b 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -369,12 +369,12 @@ fr: status_disabled: "Désactivés" status_all: "Tous" spaces_pricing: - prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." - prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." - you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." - extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." - spaces: "Spaces" - price_updated: "Price successfully updated" + prices_match_space_hours_rates_html: "Les tarifs ci-dessous correspondent à une heure de réservation d'espace, sans abonnement." + prices_calculated_on_hourly_rate_html: "Tous les prix seront automatiquement calculés par rapport au tarif horaire défini ici.
    Par exemple, si vous définissez un tarif horaire à {RATE} : un créneau de {DURATION} minutes, sera facturé {PRICE}." + you_can_override: "Vous pouvez surcharger cette durée pour chaque disponibilité que vous créez dans l'agenda. Le prix sera alors ajusté en conséquence." + extended_prices: "De plus, vous pouvez définir des prix étendus qui prévaudront sur le tarif horaire ci-dessous. Les prix étendus vous permettent, par exemple, de fixer un prix favorable pour une réservation de plusieurs heures." + spaces: "Espaces" + price_updated: "Le prix a bien été mis à jour" machines_pricing: prices_match_machine_hours_rates_html: "Les tarifs ci-dessous correspondent à une heure d'utilisation machine, sans abonnement." prices_calculated_on_hourly_rate_html: "Tous les prix seront automatiquement calculés par rapport au tarif horaire défini ici.
    Par exemple, si vous définissez un tarif horaire à {RATE} : un créneau de {DURATION} minutes, sera facturé {PRICE}." @@ -386,12 +386,12 @@ fr: no_packs: "Aucun pack pour le moment" pack_DURATION: "{DURATION} heures" configure_extended_prices_button: - extended_prices: "Extended prices" - no_extended_prices: "No extended price for now" + extended_prices: "Prix étendus" + no_extended_prices: "Aucun prix étendu pour l'instant" extended_price_DURATION: "{DURATION} minutes" extended_price_form: - duration: "Duration (minutes)" - amount: "Price" + duration: "Durée (minutes)" + amount: "Prix" pack_form: hours: "Heures" amount: "Prix" @@ -419,20 +419,20 @@ fr: confirm_changes: "Valider les modifications" pack_successfully_updated: "Le pack prépayé a bien été mis à jour." create_extended_price: - new_extended_price: "New extended price" - new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." - create_extended_price: "Create extended price" - extended_price_successfully_created: "The new extended price was successfully created." + new_extended_price: "Nouveau prix étendu" + new_extended_price_info: "Les prix étendus vous permettent de définir des prix basés sur des durées personnalisées, au lieu du tarif horaire par défaut." + create_extended_price: "Créer un prix étendu" + extended_price_successfully_created: "Le nouveau prix étendu a bien été créé." delete_extended_price: - extended_price_deleted: "The extended price was successfully deleted." - unable_to_delete: "Unable to delete the extended price: " - delete_extended_price: "Delete the extended price" - confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price?" + extended_price_deleted: "Le prix étendu a bien été supprimé." + unable_to_delete: "Impossible de supprimer le prix étendu : " + delete_extended_price: "Supprimer le prix étendu" + confirm_delete: "Supprimer" + delete_confirmation: "Êtes-vous sûr de vouloir supprimer ce prix étendu ?" edit_extended_price: - edit_extended_price: "Edit the extended price" - confirm_changes: "Confirm changes" - extended_price_successfully_updated: "The extended price was successfully updated." + edit_extended_price: "Modifier le prix étendu" + confirm_changes: "Valider les modifications" + extended_price_successfully_updated: "Le prix étendu a bien été mis à jour." #ajouter un code promotionnel coupons_new: add_a_coupon: "Ajouter un code promotionnel" @@ -495,7 +495,7 @@ fr: details: "Détails" amount: "Montant" machine_booking-3D_printer: "Réservation Machine - Imprimante 3D" - training_booking-3D_print: "Training booking - initiation to 3d printing" + training_booking-3D_print: "Réservation de formation - initiation à l'impression 3D" total_amount: "Montant total" total_including_all_taxes: "Total TTC" VAT_disabled: "TVA désactivée" From 4be86c436233c253f91f0a148b2205f68ab9d280 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:57:23 +0100 Subject: [PATCH 47/59] New translations en.yml (French) --- config/locales/fr.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 4cf57486b..66b114a9e 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -90,7 +90,7 @@ fr: other: "%{count} places %{NAME}" coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total TTC" - including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" + including_VAT_RATE: "Dont TVA %{RATE} % de %{AMOUNT}" including_total_excluding_taxes: "Dont total HT" including_amount_payed_on_ordering: "Dont montant payé à la commande" total_amount: "Montant total" @@ -148,10 +148,10 @@ fr: Space_reservation: "réserv. espace" wallet: "porte-monnaie" vat_export: - start_date: "Start date" - end_date: "End date" - vat_rate: "VAT rate" - amount: "Total amount" + start_date: "Date de début" + end_date: "Date de fin" + vat_rate: "Taux de TVA" + amount: "Montant total" #training availabilities trainings: i_ve_reserved: "J'ai réservé" @@ -336,7 +336,7 @@ fr: users_reservations: "de la liste des réservations" availabilities_index: "des disponibilités de réservations" accounting_acd: "des données comptables pour ACD" - accounting_vat: "of the collected VAT" + accounting_vat: "de la TVA collectée" is_over: "est terminé." download_here: "Téléchargez ici" notify_admin_import_complete: @@ -541,4 +541,4 @@ fr: renew_pack_threshold: "Seuil de renouvellement des packs" pack_only_for_subscription: "Restreindre les packs pour les abonnés" overlapping_categories: "Catégories pour la prévention du chevauchement des réservations" - extended_prices_in_same_day: "Extended prices in the same day" + extended_prices_in_same_day: "Prix étendus le même jour" From 73d3547294e4fc4b50108d180ad71e209fcc83d8 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:57:25 +0100 Subject: [PATCH 48/59] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 8e97caf3b..d85548e9e 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -500,9 +500,9 @@ fr: total_including_all_taxes: "Total TTC" VAT_disabled: "TVA désactivée" VAT_enabled: "TVA activée" - including_VAT: "Including VAT {RATE}% of {AMOUNT}" + including_VAT: "Dont TVA {RATE} % de {AMOUNT}" including_total_excluding_taxes: "Dont total HT" - including_amount_payed_on_ordering: "Including amount payed on ordering" + including_amount_payed_on_ordering: "Dont montant payé à la commande" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Règlement effectué par carte bancaire le {DATE} à {TIME}, pour un montant de {AMOUNT}" important_notes: "Informations importantes" address_and_legal_information: "Adresse et informations légales" @@ -552,15 +552,15 @@ fr: enable_VAT: "Activer la TVA" VAT_rate: "Taux de TVA" VAT_history: "Historique des taux de TVA" - VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." - edit_multi_VAT_button: "More options" - multiVAT: "Advanced VAT" - multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." - VAT_rate_machine: "Machine reservation" - VAT_rate_space: "Space reservation" - VAT_rate_training: "Training reservation" - VAT_rate_event: "Event reservation" - VAT_rate_subscription: "Subscription" + VAT_notice: "Ce paramètre configure le cas général du taux de TVA et s'applique à tout ce qui est vendu par le Fablab. Il est possible de surcharger ce paramètre en définissant un taux de TVA spécifique pour chaque objet." + edit_multi_VAT_button: "Plus d'options" + multiVAT: "TVA avancée" + multi_VAT_notice: "Veuillez noter : Le taux général actuel est de {RATE} %. Ici, vous pouvez définir des taux de TVA différents pour chaque catégorie.

    Par exemple, vous pouvez surcharger cette valeur, uniquement pour les réservations de machines, en remplissant le champ correspondant ci-dessous. Si aucune valeur n'est remplie, le tarif général s'appliquera." + VAT_rate_machine: "Réservation de machines" + VAT_rate_space: "Réservation d'espaces" + VAT_rate_training: "Réservation de formations" + VAT_rate_event: "Réservation d'événements" + VAT_rate_subscription: "Abonnements" changed_at: "Changé le" changed_by: "Par" deleted_user: "Utilisateur supprimé" @@ -679,9 +679,9 @@ fr: codes_customization_success: "La personnalisation des codes comptables a bien été enregistrée." unexpected_error_occurred: "Une erreur inattendue est survenue lors de l’enregistrement des codes. Veuillez réessayer plus tard." export_accounting_data: "Exporter les données comptables" - export_what: "What do you want to export?" - export_VAT: "Export the collected VAT" - export_to_ACD: "Export all data to the accounting software ACD" + export_what: "Que voulez-vous exporter ?" + export_VAT: "Exporter la TVA collectée" + export_to_ACD: "Exporter toutes les données vers le logiciel de comptabilité ACD" export_is_running: "L'export est en cours. Vous serez notifié lorsqu'il sera prêt." export_form_date: "Exporter depuis le" export_to_date: "Exporter jusqu'au" @@ -705,10 +705,10 @@ fr: debit_euro: "Débit euro" credit_euro: "Crédit euro" lettering: "Lettrage" - start_date: "Start date" - end_date: "End date" - vat_rate: "VAT rate" - amount: "Total amount" + start_date: "Date de début" + end_date: "Date de fin" + vat_rate: "Taux de TVA" + amount: "Montant total" payment: payment_settings: "Paramètres de paiement" online_payment: "Paiement en ligne" @@ -1279,9 +1279,9 @@ fr: pack_only_for_subscription_info_html: "Si cette option est activée, l'achat et l'utilisation d'un pack prépayé n'est possible que pour l'utilisateur possédant un abonnement en cours de validité." pack_only_for_subscription: "Abonnement valide pour l'achat et l'utilisation d'un pack prépayé" pack_only_for_subscription_info: "Rendre l'abonnement obligatoire pour les packs prépayés" - extended_prices: "Extended prices" - extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." - extended_prices_in_same_day: "Extended prices in the same day" + extended_prices: "Prix étendus" + extended_prices_info_html: "Les espaces peuvent avoir des prix différents selon la durée cumulée de la réservation. Vous pouvez choisir si cela s'applique à toutes les réservations ou seulement à celles qui commencent dans la même journée." + extended_prices_in_same_day: "Prix étendus le même jour" overlapping_options: training_reservations: "Formations" machine_reservations: "Machines" From 157605d8dec7a0e78687572be1503faedf515e39 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 21:57:26 +0100 Subject: [PATCH 49/59] New translations mails.en.yml (French) --- config/locales/mails.fr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/mails.fr.yml b/config/locales/mails.fr.yml index 73b19c1e2..ba166a987 100644 --- a/config/locales/mails.fr.yml +++ b/config/locales/mails.fr.yml @@ -231,8 +231,8 @@ fr: users_subscriptions: "de la liste des abonnements" users_reservations: "de la liste des réservations" availabilities_index: "des disponibilités de réservations" - accounting_acd: "of the accounting data to ACD" - accounting_vat: "of the collected VAT data" + accounting_acd: "des données comptables pour ACD" + accounting_vat: "des données de TVA collectée" click_to_download: "La génération est terminée. Pour télécharger le fichier %{TYPE}, cliquez" here: "ici" file_type: From b00bf958ccafea1a92f6132fe67b9774ad01148d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:07:28 +0100 Subject: [PATCH 50/59] [bug] extended_prices_in_same_day apply the extended prices to each days --- CHANGELOG.md | 1 + app/models/cart_item/reservation.rb | 31 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20b3f8a00..7bb65fa21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Ability to configure multiple VAT rates, per kind of invoiced item - Refactored the extended prices frontend code to allow future customization - Fix a bug: the amount label in not correctly shown in the extended prices modal +- Fix a bug: extended_prices_in_same_day apply the extended prices to each days ## v5.2.0 2021 December 23 diff --git a/app/models/cart_item/reservation.rb b/app/models/cart_item/reservation.rb index 9f97b1a45..6d4a22e5e 100644 --- a/app/models/cart_item/reservation.rb +++ b/app/models/cart_item/reservation.rb @@ -18,17 +18,19 @@ class CartItem::Reservation < CartItem::BaseItem def price is_privileged = @operator.privileged? && @operator.id != @customer.id prepaid = { minutes: PrepaidPackService.minutes_available(@customer, @reservable) } - prices = applicable_prices elements = { slots: [] } amount = 0 hours_available = credits - @slots.each_with_index do |slot, index| - amount += get_slot_price_from_prices(prices, slot, is_privileged, - elements: elements, - has_credits: (index < hours_available), - prepaid: prepaid) + grouped_slots.values.each do |slots| + prices = applicable_prices(slots) + slots.each_with_index do |slot, index| + amount += get_slot_price_from_prices(prices, slot, is_privileged, + elements: elements, + has_credits: (index < hours_available), + prepaid: prepaid) + end end { elements: elements, amount: amount } @@ -61,6 +63,15 @@ class CartItem::Reservation < CartItem::BaseItem 0 end + ## + # Group the slots by date, if the extended_prices_in_same_day option is set to true + ## + def grouped_slots + return { all: @slots } unless Setting.get('extended_prices_in_same_day') + + @slots.group_by { |slot| slot[:start_at].to_date } + end + ## # Compute the price of a single slot, according to the list of applicable prices. # @param prices {{ prices: Array<{price: Price, duration: number}> }} list of prices to use with the current reservation @@ -129,10 +140,8 @@ class CartItem::Reservation < CartItem::BaseItem # Eg. If the reservation is for 12 hours, and there are prices for 3 hours, 7 hours, # and the base price (1 hours), we use the 7 hours price, then 3 hours price, and finally the base price twice (7+3+1+1 = 12). # All these prices are returned to be applied to the reservation. - def applicable_prices - all_slots_in_same_day = @slots.map { |slot| slot[:start_at].to_date }.uniq.size == 1 - - total_duration = @slots.map { |slot| (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE }.reduce(:+) + def applicable_prices(slots) + total_duration = slots.map { |slot| (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE }.reduce(:+) rates = { prices: [] } remaining_duration = total_duration @@ -140,7 +149,7 @@ class CartItem::Reservation < CartItem::BaseItem max_duration = @reservable.prices.where(group_id: @customer.group_id, plan_id: @plan.try(:id)) .where(Price.arel_table[:duration].lteq(remaining_duration)) .maximum(:duration) - max_duration = 60 if max_duration.nil? || Setting.get('extended_prices_in_same_day') && !all_slots_in_same_day + max_duration = 60 if max_duration.nil? max_duration_price = @reservable.prices.find_by(group_id: @customer.group_id, plan_id: @plan.try(:id), duration: max_duration) current_duration = [remaining_duration, max_duration].min From f4aeeaeb720746659eb4d37dbeec0156d1c13d2a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:00 +0100 Subject: [PATCH 51/59] New translations en.yml (Spanish) --- config/locales/es.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/es.yml b/config/locales/es.yml index 597d0750a..e5e066a18 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -90,7 +90,7 @@ es: other: "%{count} %{NAME} entradas" coupon_CODE_discount_of_DISCOUNT: "Cupón {CODE}: descuento de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total impuestos incluidos" - including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" + including_VAT_RATE: "Incluido IVA %{RATE}% de %{AMOUNT}" including_total_excluding_taxes: "Excluyendo IVA" including_amount_payed_on_ordering: "Incluyendo cantidad pagada en el pedido" total_amount: "Precio total" @@ -123,7 +123,7 @@ es: subscription_of_NAME_for_DURATION_starting_from_DATE: "the subscription of %{NAME} for %{DURATION} starting from %{DATE}" deadlines: "Table of your deadlines" deadline_date: "Payment date" - deadline_amount: "Amount including tax" + deadline_amount: "Total Incluyendo Impuesto" total_amount: "Total amount" settlement_by_METHOD: "Debits will be made by {METHOD, select, card{card} other{check}} for each deadlines." settlement_by_wallet: "%{AMOUNT} will be debited from your wallet to settle the first deadline." From ccd6c0c50d01d7bf1b24d2221e99d442f4d8074a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:01 +0100 Subject: [PATCH 52/59] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 0635eb6b1..d91d8e9b0 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -500,9 +500,9 @@ es: total_including_all_taxes: "Total incl. todos los impuestos" VAT_disabled: "IVA desactivado" VAT_enabled: "IVA activado" - including_VAT: "Including VAT {RATE}% of {AMOUNT}" + including_VAT: "Incluido IVA {RATE}% de {AMOUNT}" including_total_excluding_taxes: "Incluido Total excl. impuestos" - including_amount_payed_on_ordering: "Including amount payed on ordering" + including_amount_payed_on_ordering: "Incluido el monto pagado en el pedido" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Liquidación por tarjeta de débito el {DATE} a las {TIME}, por una cantidad de {AMOUNT}" important_notes: "Notas importantes" address_and_legal_information: "Dirección e información legal" From f30d668f265bbd04b5429d733b14183dad6d7f14 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:03 +0100 Subject: [PATCH 53/59] New translations en.yml (German) --- config/locales/de.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 3c9b17b18..e8cf25528 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -90,7 +90,7 @@ de: other: "%{count} %{NAME}-Tickets" coupon_CODE_discount_of_DISCOUNT: "Gutschein {CODE}: Rabatt von {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Gesamtpreis inkl. Steuern" - including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" + including_VAT_RATE: "Inklusive MwSt. %{RATE}% von %{AMOUNT}" including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern" including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag" total_amount: "Gesamtbetrag" @@ -123,7 +123,7 @@ de: subscription_of_NAME_for_DURATION_starting_from_DATE: "the subscription of %{NAME} for %{DURATION} starting from %{DATE}" deadlines: "Table of your deadlines" deadline_date: "Payment date" - deadline_amount: "Amount including tax" + deadline_amount: "Betrag inklusive Steuern" total_amount: "Total amount" settlement_by_METHOD: "Debits will be made by {METHOD, select, card{card} other{check}} for each deadlines." settlement_by_wallet: "%{AMOUNT} will be debited from your wallet to settle the first deadline." From b8f1010b84a65e33c79416a7364f52a1ee6fffd3 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:04 +0100 Subject: [PATCH 54/59] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 37bc2820e..2d85dc47d 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -500,9 +500,9 @@ de: total_including_all_taxes: "Gesamtpreis inkl. Steuern" VAT_disabled: "MwSt. deaktiviert" VAT_enabled: "MwSt. aktiviert" - including_VAT: "Including VAT {RATE}% of {AMOUNT}" + including_VAT: "Inklusive MwSt. {RATE}% von {AMOUNT}" including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern" - including_amount_payed_on_ordering: "Including amount payed on ordering" + including_amount_payed_on_ordering: "Inklusive bei Bestellung gezahlter Betrag" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Begleichung mit Debitkarte am {DATE} um {TIME}, über den Betrag von {AMOUNT}" important_notes: "Wichtige Hinweise" address_and_legal_information: "Adresse und rechtliche Informationen" From e8e6922adf8228f674a9f9615b249930e026adf1 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:05 +0100 Subject: [PATCH 55/59] New translations en.yml (Norwegian) --- config/locales/no.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/no.yml b/config/locales/no.yml index e5ed9f719..166681d48 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -90,7 +90,7 @@ other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Kupong {CODE}: rabatt på {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Sum inkl. MVA" - including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" + including_VAT_RATE: "Inkludert MVA %{RATE}% av %{AMOUNT}" including_total_excluding_taxes: "Inkludert total ekskl. MVA" including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling" total_amount: "Totalbeløp" From d1b52746d6df1d738345178e4361fd0774826697 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:06 +0100 Subject: [PATCH 56/59] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 87b303d91..417d9c6e3 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -500,9 +500,9 @@ total_including_all_taxes: "Sum inkl. MVA" VAT_disabled: "MVA deaktivert" VAT_enabled: "MVA aktivert" - including_VAT: "Including VAT {RATE}% of {AMOUNT}" + including_VAT: "Inkludert MVA {RATE}% av {AMOUNT}" including_total_excluding_taxes: "Totalpris, eks. MVA" - including_amount_payed_on_ordering: "Including amount payed on ordering" + including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Oppgjør med betalingskort på {DATE} hos {TIME} for et beløp på {AMOUNT}" important_notes: "Viktige merknader" address_and_legal_information: "Adresse og juridisk informasjon" From 0b0df6d173139876bb6fee684243e4b83dee3573 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:07 +0100 Subject: [PATCH 57/59] New translations en.yml (Portuguese) --- config/locales/pt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 87c6053a4..e94500361 100755 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -90,7 +90,7 @@ pt: other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Cupom {CODE}: desconto de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total de taxas inclusas" - including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" + including_VAT_RATE: "Incluindo IVA %{RATE}% de %{AMOUNT}" including_total_excluding_taxes: "Incluindo total de faixas exclusas" including_amount_payed_on_ordering: "Incluindo o valor pago na encomenda" total_amount: "Montante total" From 84536c91768d1a9fe97ae21e2e4d65ecd9335514 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:18:08 +0100 Subject: [PATCH 58/59] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index c29caf0d5..48ccde624 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -500,9 +500,9 @@ pt: total_including_all_taxes: "Total incluindo todas as taxas" VAT_disabled: "IVA desativado" VAT_enabled: "IVA activado" - including_VAT: "Including VAT {RATE}% of {AMOUNT}" + including_VAT: "Incluindo IVA {RATE}% de {AMOUNT}" including_total_excluding_taxes: "Incluindo o total de taxas excluidas" - including_amount_payed_on_ordering: "Including amount payed on ordering" + including_amount_payed_on_ordering: "Incluindo o valor pago na compra" settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Pagamento por cartão de débito em {DATE} ás {TIME}, no valor de {AMOUNT}" important_notes: "Notas importantes" address_and_legal_information: "Endereço e informações legais" From 7a8b6ff0cf19b043bba4514f2f6e6cef3fd0d315 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 22:26:11 +0100 Subject: [PATCH 59/59] Version 5.3.0 --- CHANGELOG.md | 4 +++- package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bb65fa21..05434a27c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # Changelog Fab-manager +# v5.3.0 2021 December 29 + - Ability to configure multiple VAT rates, per kind of invoiced item - Refactored the extended prices frontend code to allow future customization - Fix a bug: the amount label in not correctly shown in the extended prices modal -- Fix a bug: extended_prices_in_same_day apply the extended prices to each days +- Fix a bug: `extended_prices_in_same_day` apply the extended prices to each days ## v5.2.0 2021 December 23 diff --git a/package.json b/package.json index bef8426e6..c9ae854d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.2.0", + "version": "5.3.0", "description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.", "keywords": [ "fablab",
    {t('app.admin.pricing.spaces')}{t('app.admin.spaces_pricing.spaces')}{group.name}
    {space.name} - {prices && } + {prices.length && } tr > th:first-child { + width: 20%; + } + + thead > tr > th.group-name { + width: 20%; + text-transform: uppercase; + font-size: 1.4rem; + } + + thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; + padding: 8px; + line-height: 1.5; + } + + tbody > tr > td { + padding: 8px; + line-height: 1.5; + vertical-align: top; + border-top: 1px solid #ddd; + } + } +} diff --git a/app/models/price.rb b/app/models/price.rb index 94e2dc5e9..b96d10406 100644 --- a/app/models/price.rb +++ b/app/models/price.rb @@ -8,4 +8,8 @@ class Price < ApplicationRecord validates :priceable, :group_id, :amount, presence: true validates :priceable_id, uniqueness: { scope: %i[priceable_type plan_id group_id duration] } + + def safe_destroy + destroy unless duration == 60 + end end diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 09e41a07c..d041ec00e 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -369,6 +369,11 @@ en: status_disabled: "Disabled" status_all: "All" spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
    For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours." + spaces: "Spaces" price_updated: "Price successfully updated" machines_pricing: prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, without subscription." @@ -380,10 +385,12 @@ en: packs: "Prepaid packs" no_packs: "No packs for now" pack_DURATION: "{DURATION} hours" - configure_extendedPrices_button: - extendedPrices: "Extended prices" - no_extendedPrices: "No extended price for now" + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} minutes" extended_price_form: + duration: "Duration (minutes)" amount: "Price" pack_form: hours: "Hours" @@ -411,21 +418,21 @@ en: edit_pack: "Edit the pack" confirm_changes: "Confirm changes" pack_successfully_updated: "The prepaid pack was successfully updated." - create_extendedPrice: - new_extendedPrice: "New extended price" - new_extendedPrice_info: "Extended prices allows you to define prices based on custom durations, intead on the default hourly rates." - create_extendedPrice: "Create extended price" - extendedPrice_successfully_created: "The new extended price was successfully created." - delete_extendedPrice: - extendedPrice_deleted: "The extended price was successfully deleted." + create_extended_price: + new_extended_price: "New extended price" + new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates." + create_extended_price: "Create extended price" + extended_price_successfully_created: "The new extended price was successfully created." + delete_extended_price: + extended_price_deleted: "The extended price was successfully deleted." unable_to_delete: "Unable to delete the extended price: " - delete_extendedPrice: "Delete the extended price" + delete_extended_price: "Delete the extended price" confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this extended price? This won't be possible if it was already bought by users." - edit_extendedPrice: - edit_extendedPrice: "Edit the extended price" + delete_confirmation: "Are you sure you want to delete this extended price?" + edit_extended_price: + edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" - extendedPrice_successfully_updated: "The extended price was successfully updated." + extended_price_successfully_updated: "The extended price was successfully updated." #ajouter un code promotionnel coupons_new: add_a_coupon: "Add a coupon" From 5e8c90458b9ddb81a9922c45370775abebc2a496 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Thu, 23 Dec 2021 09:25:48 +0100 Subject: [PATCH 16/59] vat history service receive invoice item param --- app/models/setting.rb | 5 ++++ app/services/vat_history_service.rb | 38 +++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/app/models/setting.rb b/app/models/setting.rb index e6ed14298..0f664503c 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -28,6 +28,11 @@ class Setting < ApplicationRecord invoice_order-nb invoice_VAT-active invoice_VAT-rate + invoice_VAT-rate_Machine + invoice_VAT-rate_Training + invoice_VAT-rate_Space + invoice_VAT-rate_Event + invoice_VAT-rate_Subscription invoice_text invoice_legals booking_window_start diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index 4c03cfe71..d0b354099 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -3,17 +3,17 @@ # Provides the VAT rate in use at the given date class VatHistoryService # return the VAT rate for the given Invoice/Avoir - def invoice_vat(invoice) - if invoice.is_a?(Avoir) - vat_rate(invoice.avoir_date) + def invoice_vat(invoice_item) + if invoice_item.invoice.is_a?(Avoir) + vat_rate(invoice.avoir_date, vat_type(invoice_item)) else - vat_rate(invoice.created_at) + vat_rate(invoice.created_at, vat_type(invoice_item)) end end # return the VAT rate for the given date - def vat_rate(date) - @vat_rates = vat_history if @vat_rates.nil? + def vat_rate(date, vat_rate_type) + @vat_rates = vat_history(vat_rate_type) if @vat_rates.nil? first_rate = @vat_rates.first return first_rate[:rate] if date < first_rate[:date] @@ -25,7 +25,13 @@ class VatHistoryService private - def vat_history + def vat_type(invoice_item) + return invoice_item.object.reservable_type if invoice_item.object_type == 'Reservation' + + 'Subscription' + end + + def vat_history(vat_rate_type) chronology = [] end_date = DateTime.current Setting.find_by(name: 'invoice_VAT-active').history_values.order(created_at: 'DESC').each do |v| @@ -34,7 +40,23 @@ class VatHistoryService end chronology.push(start: DateTime.new(0), end: end_date, enabled: false) date_rates = [] - Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').each do |rate| + vat_rate_history_values = [] + vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') + first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first + if first_vat_rate_by_type + vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a + vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC') + vat_rate_by_type.each do |rate| + if rate.value.blank? + vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first + rate.value = vat_rate.value + end + vat_rate_history_values.push(rate) + end + else + vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a + end + vat_rate_history_values.each do |rate| range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first date = range[:enabled] ? rate.created_at : range[:end] date_rates.push(date: date, rate: rate.value.to_i) From c5211e98e3f44df74ea30132bebd6f3c49bc4ef0 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Thu, 23 Dec 2021 19:36:23 +0100 Subject: [PATCH 17/59] generate invoice with multi vat --- app/models/invoice_item.rb | 17 +++++++- app/pdfs/pdf/invoice.rb | 38 ++++++++++------- app/services/vat_history_service.rb | 64 ++++++++++++++--------------- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/no.yml | 2 +- config/locales/pt.yml | 2 +- 9 files changed, 77 insertions(+), 54 deletions(-) diff --git a/app/models/invoice_item.rb b/app/models/invoice_item.rb index 3b9865100..4c5536fa4 100644 --- a/app/models/invoice_item.rb +++ b/app/models/invoice_item.rb @@ -27,7 +27,7 @@ class InvoiceItem < Footprintable def net_amount # deduct VAT vat_service = VatHistoryService.new - vat_rate = vat_service.invoice_vat(invoice) + vat_rate = vat_service.invoice_vat(self) Rational(amount_after_coupon / (vat_rate / 100.00 + 1)).round.to_f end @@ -36,6 +36,21 @@ class InvoiceItem < Footprintable amount_after_coupon - net_amount end + # return invoice item type (Matchine/Training/Space/Event/Subscription) + def invoice_item_type + if object_type == Reservation.name + reservable_type = object.try(:reservable_type) + if reservable_type + return reservable_type + else + return '' + end + elsif object_type == Subscription.name + return Subscription.name + end + '' + end + private def log_changes diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index 4065fe6b1..a4612ab3e 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -230,10 +230,18 @@ class PDF::Invoice < Prawn::Document # TVA vat_service = VatHistoryService.new - vat_rate = vat_service.invoice_vat(invoice) - if vat_rate != 0 + vat_rate_group = {} + invoice.invoice_items.each do |item| + vat_type = item.invoice_item_type + vat_rate_group[vat_type] = { vat_rate: vat_service.invoice_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type] + vat_rate_group[vat_type][:total_vat] += item.vat + vat_rate_group[vat_type][:amount] += item.amount.to_i + end + if total_vat != 0 data += [[I18n.t('invoices.total_including_all_taxes'), number_to_currency(total)]] - data += [[I18n.t('invoices.including_VAT_RATE', RATE: vat_rate), number_to_currency(total_vat / 100.00)]] + vat_rate_group.each do |_type, rate| + data += [[I18n.t('invoices.including_VAT_RATE', RATE: rate[:vat_rate], AMOUNT: number_to_currency(rate[:amount] / 100.00)), number_to_currency(rate[:total_vat] / 100.00)]] + end data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(total_ht / 100.00)]] data += [[I18n.t('invoices.including_amount_payed_on_ordering'), number_to_currency(total)]] @@ -252,23 +260,25 @@ class PDF::Invoice < Prawn::Document row(0).font_style = :bold column(1).style align: :right - if Setting.get('invoice_VAT-active') + if total_vat != 0 # Total incl. taxes row(-1).style align: :right row(-1).background_color = 'E4E4E4' row(-1).font_style = :bold - # including VAT xx% - row(-2).style align: :right - row(-2).background_color = 'E4E4E4' - row(-2).font_style = :italic + vat_rate_group.size.times do |i| + # including VAT xx% + row(-2 - i).style align: :right + row(-2 - i).background_color = 'E4E4E4' + row(-2 - i).font_style = :italic + end # including total excl. taxes - row(-3).style align: :right - row(-3).background_color = 'E4E4E4' - row(-3).font_style = :italic + row(-3 - vat_rate_group.size + 1).style align: :right + row(-3 - vat_rate_group.size + 1).background_color = 'E4E4E4' + row(-3 - vat_rate_group.size + 1).font_style = :italic # including amount payed on ordering - row(-4).style align: :right - row(-4).background_color = 'E4E4E4' - row(-4).font_style = :bold + row(-4 - vat_rate_group.size + 1).style align: :right + row(-4 - vat_rate_group.size + 1).background_color = 'E4E4E4' + row(-4 - vat_rate_group.size + 1).font_style = :bold end end diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index d0b354099..c072d0ac2 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -2,35 +2,29 @@ # Provides the VAT rate in use at the given date class VatHistoryService - # return the VAT rate for the given Invoice/Avoir + # return the VAT rate for the given InvoiceItem def invoice_vat(invoice_item) if invoice_item.invoice.is_a?(Avoir) - vat_rate(invoice.avoir_date, vat_type(invoice_item)) + vat_rate(invoice_item.invoice.avoir_date, invoice_item.invoice_item_type) else - vat_rate(invoice.created_at, vat_type(invoice_item)) + vat_rate(invoice_item.invoice.created_at, invoice_item.invoice_item_type) end end - # return the VAT rate for the given date + # return the VAT rate for the given date and vat type def vat_rate(date, vat_rate_type) - @vat_rates = vat_history(vat_rate_type) if @vat_rates.nil? + vat_rates = vat_history(vat_rate_type) - first_rate = @vat_rates.first + first_rate = vat_rates.first return first_rate[:rate] if date < first_rate[:date] - @vat_rates.each_index do |i| - return @vat_rates[i][:rate] if date >= @vat_rates[i][:date] && (@vat_rates[i + 1].nil? || date < @vat_rates[i + 1][:date]) + vat_rates.each_index do |i| + return vat_rates[i][:rate] if date >= vat_rates[i][:date] && (vat_rates[i + 1].nil? || date < vat_rates[i + 1][:date]) end end private - def vat_type(invoice_item) - return invoice_item.object.reservable_type if invoice_item.object_type == 'Reservation' - - 'Subscription' - end - def vat_history(vat_rate_type) chronology = [] end_date = DateTime.current @@ -41,28 +35,32 @@ class VatHistoryService chronology.push(start: DateTime.new(0), end: end_date, enabled: false) date_rates = [] vat_rate_history_values = [] - vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') - first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first - if first_vat_rate_by_type - vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a - vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC') - vat_rate_by_type.each do |rate| - if rate.value.blank? - vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first - rate.value = vat_rate.value + if vat_rate_type.present? + vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') + first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first + if first_vat_rate_by_type + vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a + vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC') + vat_rate_by_type.each do |rate| + if rate.value.blank? + vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first + rate.value = vat_rate.value + end + vat_rate_history_values.push(rate) end - vat_rate_history_values.push(rate) + else + vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a + end + vat_rate_history_values.each do |rate| + range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first + date = range[:enabled] ? rate.created_at : range[:end] + date_rates.push(date: date, rate: rate.value.to_i) + end + chronology.reverse_each do |period| + date_rates.push(date: period[:start], rate: 0) unless period[:enabled] end else - vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a - end - vat_rate_history_values.each do |rate| - range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first - date = range[:enabled] ? rate.created_at : range[:end] - date_rates.push(date: date, rate: rate.value.to_i) - end - chronology.reverse_each do |period| - date_rates.push(date: period[:start], rate: 0) unless period[:enabled] + date_rates.push(date: chronology[-1][:start], rate: 0) end date_rates.sort_by { |k| k[:date] } end diff --git a/config/locales/de.yml b/config/locales/de.yml index 0d0db4abc..dae2ebc68 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -90,7 +90,7 @@ de: other: "%{count} %{NAME}-Tickets" coupon_CODE_discount_of_DISCOUNT: "Gutschein {CODE}: Rabatt von {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Gesamtpreis inkl. Steuern" - including_VAT_RATE: "Inklusive MwSt. %{RATE}%" + including_VAT_RATE: "Inklusive MwSt. %{RATE} von %{AMOUNT}" including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern" including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag" total_amount: "Gesamtbetrag" diff --git a/config/locales/en.yml b/config/locales/en.yml index a6e36f3f4..a25312b9d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -90,7 +90,7 @@ en: other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Coupon {CODE}: discount of {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total incl. all taxes" - including_VAT_RATE: "Including VAT %{RATE}%" + including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}" including_total_excluding_taxes: "Including Total excl. taxes" including_amount_payed_on_ordering: "Including amount payed on ordering" total_amount: "Total amount" diff --git a/config/locales/es.yml b/config/locales/es.yml index 6ac0679a4..231aa31d2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -90,7 +90,7 @@ es: other: "%{count} %{NAME} entradas" coupon_CODE_discount_of_DISCOUNT: "Cupón {CODE}: descuento de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total impuestos incluidos" - including_VAT_RATE: "Incluyendo IVA %{RATE}%" + including_VAT_RATE: "Incluyendo IVA %{RATE}% de %{AMOUNT}" including_total_excluding_taxes: "Excluyendo IVA" including_amount_payed_on_ordering: "Incluyendo cantidad pagada en el pedido" total_amount: "Precio total" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 2dcf06c18..4da5c99c6 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -90,7 +90,7 @@ fr: other: "%{count} places %{NAME}" coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total TTC" - including_VAT_RATE: "Dont TVA %{RATE}%" + including_VAT_RATE: "Dont TVA %{RATE}% de %{AMOUNT}" including_total_excluding_taxes: "Dont total HT" including_amount_payed_on_ordering: "Dont montant payé à la commande" total_amount: "Montant total" diff --git a/config/locales/no.yml b/config/locales/no.yml index 36a5b70d1..3ff47f017 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -90,7 +90,7 @@ other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Kupong {CODE}: rabatt på {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Sum inkl. MVA" - including_VAT_RATE: "Inkludert MVA %{RATE}%" + including_VAT_RATE: "Inkludert MVA %{RATE}% %{AMOUNT}" including_total_excluding_taxes: "Inkludert total ekskl. MVA" including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling" total_amount: "Totalbeløp" diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 851f11eb6..a63dc2415 100755 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -90,7 +90,7 @@ pt: other: "%{count} %{NAME} tickets" coupon_CODE_discount_of_DISCOUNT: "Cupom {CODE}: desconto de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation total_including_all_taxes: "Total de taxas inclusas" - including_VAT_RATE: "Incluindo VAT %{RATE}%" + including_VAT_RATE: "Incluindo VAT %{RATE}% de %{AMOUNT}" including_total_excluding_taxes: "Incluindo total de faixas exclusas" including_amount_payed_on_ordering: "Incluindo o valor pago na encomenda" total_amount: "Montante total" From 6019767a3b63e9b3e1375118077f6afbc45b6858 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 24 Dec 2021 17:50:57 +0100 Subject: [PATCH 18/59] update multi VAT --- .../javascript/controllers/admin/invoices.js | 80 ++++++++++++++++++- app/frontend/src/javascript/models/setting.ts | 5 ++ app/frontend/src/javascript/router.js | 3 +- .../src/stylesheets/modules/invoice.scss | 4 + .../admin/invoices/settings/editMultiVAT.html | 57 +++++++++++++ .../admin/invoices/settings/editVAT.html | 7 ++ .../invoices/settings/multiVATHistory.html | 32 ++++++++ config/locales/app.admin.de.yml | 9 +++ config/locales/app.admin.en.yml | 9 +++ config/locales/app.admin.es.yml | 9 +++ config/locales/app.admin.fr.yml | 9 +++ config/locales/app.admin.no.yml | 9 +++ config/locales/app.admin.pt.yml | 9 +++ config/locales/app.admin.zu.yml | 9 +++ 14 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 app/frontend/templates/admin/invoices/settings/editMultiVAT.html create mode 100644 app/frontend/templates/admin/invoices/settings/multiVATHistory.html diff --git a/app/frontend/src/javascript/controllers/admin/invoices.js b/app/frontend/src/javascript/controllers/admin/invoices.js index 4cff1dc62..be1fb7244 100644 --- a/app/frontend/src/javascript/controllers/admin/invoices.js +++ b/app/frontend/src/javascript/controllers/admin/invoices.js @@ -92,6 +92,15 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I active: false, templateUrl: '/admin/invoices/settings/editVAT.html' }, + multiVAT: { + rateMachine: '', + rateSpace: '', + rateTraining: '', + rateEvent: '', + rateSubscription: '', + editTemplateUrl: '/admin/invoices/settings/editMultiVAT.html', + historyTemplateUrl: '/admin/invoices/settings/multiVATHistory.html' + }, text: { content: '' }, @@ -446,6 +455,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I active () { return $scope.invoice.VAT.active; }, + multiVAT () { + return $scope.invoice.multiVAT; + }, rateHistory () { return Setting.get({ name: 'invoice_VAT-rate', history: true }).$promise; }, @@ -453,13 +465,74 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I return Setting.get({ name: 'invoice_VAT-active', history: true }).$promise; } }, - controller: ['$scope', '$uibModalInstance', 'rate', 'active', 'rateHistory', 'activeHistory', function ($scope, $uibModalInstance, rate, active, rateHistory, activeHistory) { + controller: ['$scope', '$uibModalInstance', 'rate', 'active', 'rateHistory', 'activeHistory', 'multiVAT', function ($scope, $uibModalInstance, rate, active, rateHistory, activeHistory, multiVAT) { $scope.rate = rate; $scope.isSelected = active; $scope.history = []; $scope.ok = function () { $uibModalInstance.close({ rate: $scope.rate, active: $scope.isSelected }); }; $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; + $scope.editMultiVAT = function () { + const editMultiVATModalInstance = $uibModal.open({ + animation: true, + templateUrl: multiVAT.editTemplateUrl, + size: 'lg', + resolve: { + rate () { + return $scope.rate; + }, + multiVAT () { + return multiVAT; + } + }, + controller: ['$scope', '$uibModalInstance', 'rate', 'multiVAT', function ($scope, $uibModalInstance, rate, multiVAT) { + $scope.rate = rate; + $scope.multiVAT = multiVAT; + + $scope.ok = function () { $uibModalInstance.close({ multiVAT: $scope.multiVAT }); }; + $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; + + $scope.showMultiRateHistory = function (rateType) { + $uibModal.open({ + animation: true, + templateUrl: multiVAT.historyTemplateUrl, + size: 'lg', + resolve: { + rateHistory () { + return Setting.get({ name: `invoice_VAT-rate_${rateType}`, history: true }).$promise; + } + }, + controller: ['$scope', '$uibModalInstance', 'rateHistory', function ($scope, $uibModalInstance, rateHistory) { + $scope.history = []; + + $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; + + const initialize = function () { + rateHistory.setting.history.forEach(function (rate) { + $scope.history.push({ date: rate.created_at, rate: rate.value, user: rate.user }); + }); + }; + + initialize(); + }] + }); + }; + }] + }); + return editMultiVATModalInstance.result.then(function (result) { + ['Machine', 'Space', 'Training', 'Event', 'Subscription'].forEach(rateType => { + Setting.update({ name: `invoice_VAT-rate_${rateType}` }, { value: result.multiVAT[`rate${rateType}`] + '' }, function (data) { + return growl.success(_t('app.admin.invoices.VAT_rate_successfully_saved')); + } + , function (error) { + if (error.status === 304) return; + + growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_VAT_rate')); + console.error(error); + }); + }); + }); + }; const initialize = function () { rateHistory.setting.history.forEach(function (rate) { @@ -943,6 +1016,11 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I $scope.invoice.text.content = settings.invoice_text; $scope.invoice.VAT.rate = parseFloat(settings['invoice_VAT-rate']); $scope.invoice.VAT.active = (settings['invoice_VAT-active'] === 'true'); + $scope.invoice.multiVAT.rateMachine = settings['invoice_VAT-rate_Machine'] ? parseFloat(settings['invoice_VAT-rate_Machine']) : ''; + $scope.invoice.multiVAT.rateSpace = settings['invoice_VAT-rate_Space'] ? parseFloat(settings['invoice_VAT-rate_Space']) : ''; + $scope.invoice.multiVAT.rateTraining = settings['invoice_VAT-rate_Training'] ? parseFloat(settings['invoice_VAT-rate_Training']) : ''; + $scope.invoice.multiVAT.rateEvent = settings['invoice_VAT-rate_Event'] ? parseFloat(settings['invoice_VAT-rate_Event']) : ''; + $scope.invoice.multiVAT.rateSubscription = settings['invoice_VAT-rate_Subscription'] ? parseFloat(settings['invoice_VAT-rate_Subscription']) : ''; $scope.invoice.number.model = settings['invoice_order-nb']; $scope.invoice.code.model = settings['invoice_code-value']; $scope.invoice.code.active = (settings['invoice_code-active'] === 'true'); diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts index 08c01cd01..420d1f374 100644 --- a/app/frontend/src/javascript/models/setting.ts +++ b/app/frontend/src/javascript/models/setting.ts @@ -20,6 +20,11 @@ export enum SettingName { InvoiceOrderNb = 'invoice_order-nb', InvoiceVATActive = 'invoice_VAT-active', InvoiceVATRate = 'invoice_VAT-rate', + InvoiceVATRateMachine = 'invoice_VAT-rate_Machine', + InvoiceVATRateTraining = 'invoice_VAT-rate_Training', + InvoiceVATRateSpace = 'invoice_VAT-rate_Space', + InvoiceVATRateEvent = 'invoice_VAT-rate_Event', + InvoiceVATRateSubscription = 'invoice_VAT-rate_Subscription', InvoiceText = 'invoice_text', InvoiceLegals = 'invoice_legals', BookingWindowStart = 'booking_window_start', diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index 0f24a91b5..bb5a7d6c6 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -869,7 +869,8 @@ angular.module('application.router', ['ui.router']) resolve: { settings: ['Setting', function (Setting) { return Setting.query({ - names: "['invoice_legals', 'invoice_text', 'invoice_VAT-rate', 'invoice_VAT-active', 'invoice_order-nb', 'invoice_code-value', " + + names: "['invoice_legals', 'invoice_text', 'invoice_VAT-rate', 'invoice_VAT-rate_Machine', 'invoice_VAT-rate_Training', 'invoice_VAT-rate_Space', " + + "'invoice_VAT-rate_Event', 'invoice_VAT-rate_Subscription', 'invoice_VAT-active', 'invoice_order-nb', 'invoice_code-value', " + "'invoice_code-active', 'invoice_reference', 'invoice_logo', 'accounting_journal_code', 'accounting_card_client_code', " + "'accounting_card_client_label', 'accounting_wallet_client_code', 'accounting_wallet_client_label', 'invoicing_module', " + "'accounting_other_client_code', 'accounting_other_client_label', 'accounting_wallet_code', 'accounting_wallet_label', " + diff --git a/app/frontend/src/stylesheets/modules/invoice.scss b/app/frontend/src/stylesheets/modules/invoice.scss index dafdb538c..d81b08307 100644 --- a/app/frontend/src/stylesheets/modules/invoice.scss +++ b/app/frontend/src/stylesheets/modules/invoice.scss @@ -367,3 +367,7 @@ table.export-table-template { height: 30px; } } + +.multi-vat-rate-input { + width: 90% !important; +} diff --git a/app/frontend/templates/admin/invoices/settings/editMultiVAT.html b/app/frontend/templates/admin/invoices/settings/editMultiVAT.html new file mode 100644 index 000000000..d14f26bd8 --- /dev/null +++ b/app/frontend/templates/admin/invoices/settings/editMultiVAT.html @@ -0,0 +1,57 @@ +
    + + + +
    diff --git a/app/frontend/templates/admin/invoices/settings/editVAT.html b/app/frontend/templates/admin/invoices/settings/editVAT.html index 8ffd8ce9a..5423aa74c 100644 --- a/app/frontend/templates/admin/invoices/settings/editVAT.html +++ b/app/frontend/templates/admin/invoices/settings/editVAT.html @@ -22,6 +22,12 @@ + +

    + + {{ 'app.admin.invoices.VAT_notice' | translate }} +

    +

    {{ 'app.admin.invoices.VAT_history' }}

    @@ -48,6 +54,7 @@
    diff --git a/app/frontend/templates/admin/invoices/settings/multiVATHistory.html b/app/frontend/templates/admin/invoices/settings/multiVATHistory.html new file mode 100644 index 000000000..77f7e2e1a --- /dev/null +++ b/app/frontend/templates/admin/invoices/settings/multiVATHistory.html @@ -0,0 +1,32 @@ +
    + + + +
    diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index aa500c49d..cbbf9b1d8 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -522,6 +522,15 @@ de: enable_VAT: "MwSt. aktivieren" VAT_rate: "MwSt.-Satz" VAT_history: "MwSt.-Sätze Historie" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Geändert am" changed_by: "Von" deleted_user: "Gelöschter Nutzer" diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index d041ec00e..cac1dc920 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -551,6 +551,15 @@ en: enable_VAT: "Enable VAT" VAT_rate: "VAT rate" VAT_history: "VAT rates history" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Changed at" changed_by: "By" deleted_user: "Deleted user" diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 9f2a8426e..074838f16 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -522,6 +522,15 @@ es: enable_VAT: "Habilitar IVA" VAT_rate: "Ratio IVA" VAT_history: "Historial de ratios de IVA" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Cambiado en" changed_by: "Por" deleted_user: "Usario eliminado" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 0ff61d212..70679f69d 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -522,6 +522,15 @@ fr: enable_VAT: "Activer la TVA" VAT_rate: "Taux de TVA" VAT_history: "Historique des taux de TVA" + VAT_notice: "Ce paramètre configure le cas général du taux de TVA et s'applique à tout ce qui est vendu par le Fablab. Il est possible de surcharger ce paramètre en configurant un taux de TVA spécifique par chaque objet." + edit_multi_VAT_button: "Plus d'options" + multiVAT: "TVA avancée" + multi_VAT_notice: "Attention: Le taux général actuellement en vigueur est de {RATE}%. Vous pouvez définir ici des taux de TVA différents pour chaque catégorie.

    Par exemple, vous pouvez surcharger cette valeur, uniquement par les réservations de machines, en renseignant le champ correspondant ci-dessous. Si aucune valeur n'est renseignée, le taux général s'appliquera." + VAT_rate_machine: "Réservation de machines" + VAT_rate_space: "Réservation d'espaces" + VAT_rate_training: "Réservation de formations" + VAT_rate_event: "Réservation d'événements" + VAT_rate_subscription: "Abonnements" changed_at: "Changé le" changed_by: "Par" deleted_user: "Utilisateur supprimé" diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 38ea3eefe..2c25e6733 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -522,6 +522,15 @@ enable_VAT: "Aktiver MVA" VAT_rate: "MVA sats" VAT_history: "MVA-sats, historikk" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Endret" changed_by: "Av" deleted_user: "Slettet bruker" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 390e7725c..76c083a05 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -522,6 +522,15 @@ pt: enable_VAT: "Ativar VAT" VAT_rate: "VAT taxa" VAT_history: "Histórico de taxas" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "Alterado em" changed_by: "Por" deleted_user: "Usuário deletado" diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 4a1156656..dd3d982d4 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -522,6 +522,15 @@ zu: enable_VAT: "crwdns7469:0crwdne7469:0" VAT_rate: "crwdns7471:0crwdne7471:0" VAT_history: "crwdns7473:0crwdne7473:0" + VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object." + edit_multi_VAT_button: "More options" + multiVAT: "Advanced VAT" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

    For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply." + VAT_rate_machine: "Machine reservation" + VAT_rate_space: "Space reservation" + VAT_rate_training: "Training reservation" + VAT_rate_event: "Event reservation" + VAT_rate_subscription: "Subscription" changed_at: "crwdns7475:0crwdne7475:0" changed_by: "crwdns7477:0crwdne7477:0" deleted_user: "crwdns7479:0crwdne7479:0" From 0868cee6d924688d4fd523b96127834b56d6d0bf Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 24 Dec 2021 19:05:03 +0100 Subject: [PATCH 19/59] fix bug: multi VAT setting no exsit --- app/services/vat_history_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index c072d0ac2..1beb048cf 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -37,7 +37,7 @@ class VatHistoryService vat_rate_history_values = [] if vat_rate_type.present? vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') - first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first + first_vat_rate_by_type = vat_rate_by_type&.select { |v| v.value.present? }&.first if first_vat_rate_by_type vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC') From d52b8bde06aa1213cbd48a8416eef2c006b9cbf5 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 24 Dec 2021 19:37:43 +0100 Subject: [PATCH 20/59] fix bug: accounting period export --- app/models/accounting_period.rb | 9 +++++++-- app/services/accounting_export_service.rb | 4 ++-- app/views/archive/_accounting.json.jbuilder | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/models/accounting_period.rb b/app/models/accounting_period.rb index d068d5624..1126b58df 100644 --- a/app/models/accounting_period.rb +++ b/app/models/accounting_period.rb @@ -34,7 +34,12 @@ class AccountingPeriod < ApplicationRecord def invoices_with_vat(invoices) vat_service = VatHistoryService.new invoices.map do |i| - { invoice: i, vat_rate: vat_service.invoice_vat(i) / 100.0 } + vat_rate_group = {} + i.invoice_items.each do |item| + vat_type = item.invoice_item_type + vat_rate_group[vat_type] = vat_service.invoice_vat(item) / 100.0 unless vat_rate_group[vat_type] + end + { invoice: i, vat_rate: vat_rate_group } end end @@ -70,7 +75,7 @@ class AccountingPeriod < ApplicationRecord end def price_without_taxe(invoice) - invoice[:invoice].total - (invoice[:invoice].total * invoice[:vat_rate]) + invoice[:invoice].invoice_items.map(&:net_amount).sum end def compute_totals diff --git a/app/services/accounting_export_service.rb b/app/services/accounting_export_service.rb index b3c03feb6..b4451c13e 100644 --- a/app/services/accounting_export_service.rb +++ b/app/services/accounting_export_service.rb @@ -134,9 +134,9 @@ class AccountingExportService # Generate the "VAT" row, which contains the credit to the VAT account, with VAT amount only def vat_row(invoice) - rate = VatHistoryService.new.invoice_vat(invoice) + total = invoice.invoice_items.map(&:net_amount).sum # we do not render the VAT row if it was disabled for this invoice - return nil if rate.zero? + return nil if total == invoice.total row( invoice, diff --git a/app/views/archive/_accounting.json.jbuilder b/app/views/archive/_accounting.json.jbuilder index 48b024c44..124e1ff75 100644 --- a/app/views/archive/_accounting.json.jbuilder +++ b/app/views/archive/_accounting.json.jbuilder @@ -34,7 +34,7 @@ json.invoices do json.id item.object_id json.main item.main end - json.partial! 'archive/vat', price: item.amount, vat_rate: invoice[:vat_rate] + json.partial! 'archive/vat', price: item.amount, vat_rate: invoice[:vat_rate][item.invoice_item_type] end end end From 66cae9fb078d64e903c138f4d01a46d1e822954e Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 24 Dec 2021 19:38:29 +0100 Subject: [PATCH 21/59] fix test for multi vat --- test/test_helper.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 2f550685b..0b13ecc09 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -104,13 +104,15 @@ class ActiveSupport::TestCase end vat_service = VatHistoryService.new - vat_rate = vat_service.invoice_vat(invoice) - if vat_rate.positive? - computed_ht = sprintf('%.2f', (invoice.total / (vat_rate / 100.00 + 1)) / 100.00).to_f + invoice.invoice_items.each do |item| + vat_rate = vat_service.invoice_vat(item) + if vat_rate.positive? + computed_ht = sprintf('%.2f', (item.amount_after_coupon / (vat_rate / 100.00 + 1)) / 100.00).to_f - assert_equal computed_ht, ht_amount, 'Total excluding taxes rendered in the PDF file is not computed correctly' - else - assert_equal invoice.total, ht_amount, 'VAT information was rendered in the PDF file despite that VAT was disabled' + assert_equal computed_ht, item.net_amount / 100.00, 'Total excluding taxes rendered in the PDF file is not computed correctly' + else + assert_equal item.amount_after_coupon, item.net_amount, 'VAT information was rendered in the PDF file despite that VAT was disabled' + end end # check the recipient & the address From 44853930ed5d3d45e96eb6f3241d878c9d7baf78 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 28 Dec 2021 19:42:04 +0100 Subject: [PATCH 22/59] WIP: improve VatHistoryService --- app/models/accounting_period.rb | 2 +- app/models/invoice_item.rb | 16 ++++++---------- app/pdfs/pdf/invoice.rb | 2 +- app/services/vat_history_service.rb | 14 +++++++++++++- test/test_helper.rb | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/models/accounting_period.rb b/app/models/accounting_period.rb index 1126b58df..a0377c1d7 100644 --- a/app/models/accounting_period.rb +++ b/app/models/accounting_period.rb @@ -37,7 +37,7 @@ class AccountingPeriod < ApplicationRecord vat_rate_group = {} i.invoice_items.each do |item| vat_type = item.invoice_item_type - vat_rate_group[vat_type] = vat_service.invoice_vat(item) / 100.0 unless vat_rate_group[vat_type] + vat_rate_group[vat_type] = vat_service.invoice_item_vat(item) / 100.0 unless vat_rate_group[vat_type] end { invoice: i, vat_rate: vat_rate_group } end diff --git a/app/models/invoice_item.rb b/app/models/invoice_item.rb index 4c5536fa4..7212a91f5 100644 --- a/app/models/invoice_item.rb +++ b/app/models/invoice_item.rb @@ -27,7 +27,7 @@ class InvoiceItem < Footprintable def net_amount # deduct VAT vat_service = VatHistoryService.new - vat_rate = vat_service.invoice_vat(self) + vat_rate = vat_service.invoice_item_vat(self) Rational(amount_after_coupon / (vat_rate / 100.00 + 1)).round.to_f end @@ -36,19 +36,15 @@ class InvoiceItem < Footprintable amount_after_coupon - net_amount end - # return invoice item type (Matchine/Training/Space/Event/Subscription) + # return invoice item type (Machine/Training/Space/Event/Subscription) used to determine the VAT rate def invoice_item_type if object_type == Reservation.name - reservable_type = object.try(:reservable_type) - if reservable_type - return reservable_type - else - return '' - end + object.try(:reservable_type) || '' elsif object_type == Subscription.name - return Subscription.name + Subscription.name + else + '' end - '' end private diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index a4612ab3e..c96f5556c 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -233,7 +233,7 @@ class PDF::Invoice < Prawn::Document vat_rate_group = {} invoice.invoice_items.each do |item| vat_type = item.invoice_item_type - vat_rate_group[vat_type] = { vat_rate: vat_service.invoice_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type] + vat_rate_group[vat_type] = { vat_rate: vat_service.invoice_item_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type] vat_rate_group[vat_type][:total_vat] += item.vat vat_rate_group[vat_type][:amount] += item.amount.to_i end diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index 1beb048cf..9299a0172 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -2,8 +2,20 @@ # Provides the VAT rate in use at the given date class VatHistoryService + # @return the VAT rate for the given Invoice + def invoice_vat(invoice) + vat_rate_group = {} + invoice.invoice_items.each do |item| + vat_type = item.invoice_item_type + vat_rate_group[vat_type] = { vat_rate: invoice_item_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type] + vat_rate_group[vat_type][:total_vat] += item.vat + vat_rate_group[vat_type][:amount] += item.amount.to_i + end + vat_rate_group + end + # return the VAT rate for the given InvoiceItem - def invoice_vat(invoice_item) + def invoice_item_vat(invoice_item) if invoice_item.invoice.is_a?(Avoir) vat_rate(invoice_item.invoice.avoir_date, invoice_item.invoice_item_type) else diff --git a/test/test_helper.rb b/test/test_helper.rb index 0b13ecc09..c6930d66d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -105,7 +105,7 @@ class ActiveSupport::TestCase vat_service = VatHistoryService.new invoice.invoice_items.each do |item| - vat_rate = vat_service.invoice_vat(item) + vat_rate = vat_service.invoice_item_vat(item) if vat_rate.positive? computed_ht = sprintf('%.2f', (item.amount_after_coupon / (vat_rate / 100.00 + 1)) / 100.00).to_f From 9286738b69e56aefc7bbce35b2fe8fffa9da5f3c Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 10:57:59 +0100 Subject: [PATCH 23/59] add comments in complex VAT history function --- app/pdfs/pdf/invoice.rb | 8 +----- app/services/vat_history_service.rb | 40 +++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index c96f5556c..8036951b8 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -230,13 +230,7 @@ class PDF::Invoice < Prawn::Document # TVA vat_service = VatHistoryService.new - vat_rate_group = {} - invoice.invoice_items.each do |item| - vat_type = item.invoice_item_type - vat_rate_group[vat_type] = { vat_rate: vat_service.invoice_item_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type] - vat_rate_group[vat_type][:total_vat] += item.vat - vat_rate_group[vat_type][:amount] += item.amount.to_i - end + vat_rate_group = vat_service.invoice_vat(invoice) if total_vat != 0 data += [[I18n.t('invoices.total_including_all_taxes'), number_to_currency(total)]] vat_rate_group.each do |_type, rate| diff --git a/app/services/vat_history_service.rb b/app/services/vat_history_service.rb index 9299a0172..29083df38 100644 --- a/app/services/vat_history_service.rb +++ b/app/services/vat_history_service.rb @@ -45,35 +45,65 @@ class VatHistoryService end_date = v.created_at end chronology.push(start: DateTime.new(0), end: end_date, enabled: false) - date_rates = [] - vat_rate_history_values = [] + # now chronology contains something like one of the following: + # - [{start: 0000-01-01, end: now, enabled: false}] => VAT was never enabled + # - [ + # {start: fab-manager initial setup date, end: now, enabled: true}, + # {start: 0000-01-01, end: fab-manager initial setup date, enabled: false} + # ] => VAT was enabled from the beginning + # - [ + # {start: [date disabled], end: now, enabled: false}, + # {start: [date enable], end: [date disabled], enabled: true}, + # {start: fab-manager initial setup date, end: [date enabled], enabled: false}, + # {start: 0000-01-01, end: fab-manager initial setup date, enabled: false} + # ] => VAT was enabled at some point, and disabled at some other point later + if vat_rate_type.present? vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC') first_vat_rate_by_type = vat_rate_by_type&.select { |v| v.value.present? }&.first if first_vat_rate_by_type - vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a - vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC') + # before the first VAT rate was defined for the given type, the general VAT rate is used + vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate') + .history_values.where('created_at < ?', first_vat_rate_by_type.created_at) + .order(created_at: 'ASC').to_a + # after that, the VAT rate for the given type is used + vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}") + .history_values.where('created_at >= ?', first_vat_rate_by_type.created_at) + .order(created_at: 'ASC') vat_rate_by_type.each do |rate| if rate.value.blank? - vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first + # if, at some point in the history, a blank rate was set, the general VAT rate is used instead + vat_rate = Setting.find_by(name: 'invoice_VAT-rate') + .history_values.where('created_at < ?', rate.created_at) + .order(created_at: 'DESC') + .first rate.value = vat_rate.value end vat_rate_history_values.push(rate) end else + # if no VAT rate is defined for the given type, the general VAT rate is always used vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a end + + # Now we have all the rates history, we can build the final chronology, depending on whether VAT was enabled or not + date_rates = [] vat_rate_history_values.each do |rate| + # when the VAT rate was enabled, set the date it was enabled and the rate range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first date = range[:enabled] ? rate.created_at : range[:end] date_rates.push(date: date, rate: rate.value.to_i) end chronology.reverse_each do |period| + # when the VAT rate was disabled, set the date it was disabled and rate=0 date_rates.push(date: period[:start], rate: 0) unless period[:enabled] end else + # if no VAT rate type is given, we return rate=0 from 0000-01-01 date_rates.push(date: chronology[-1][:start], rate: 0) end + + # finally, we return the chronology, sorted by dates (ascending) date_rates.sort_by { |k| k[:date] } end end From 16242d21276ee53bdfaf6edd4df6df03e58fd94f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 29 Dec 2021 12:08:41 +0100 Subject: [PATCH 24/59] frontend invoice configuration page uses multiVAT --- app/frontend/src/javascript/controllers/admin/invoices.js | 8 ++++++++ app/frontend/templates/admin/invoices/settings.html | 6 +++--- app/services/vat_history_service.rb | 2 +- config/locales/app.admin.en.yml | 5 +++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/frontend/src/javascript/controllers/admin/invoices.js b/app/frontend/src/javascript/controllers/admin/invoices.js index be1fb7244..e0b52eafc 100644 --- a/app/frontend/src/javascript/controllers/admin/invoices.js +++ b/app/frontend/src/javascript/controllers/admin/invoices.js @@ -226,6 +226,14 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I // Is shown the modal dialog to select a payment gateway $scope.openSelectGatewayModal = false; + /** + * Return the VAT rate applicable to the machine reservations + * @return {number} + */ + $scope.getMachineExampleRate = function () { + return $scope.invoice.multiVAT.rateMachine || $scope.invoice.VAT.rate; + }; + /** * Change the invoices ordering criterion to the one provided * @param orderBy {string} ordering criterion diff --git a/app/frontend/templates/admin/invoices/settings.html b/app/frontend/templates/admin/invoices/settings.html index 83260986a..63554df1e 100644 --- a/app/frontend/templates/admin/invoices/settings.html +++ b/app/frontend/templates/admin/invoices/settings.html @@ -54,12 +54,12 @@
    {{ 'app.admin.invoices.including_VAT' | translate }} {{invoice.VAT.rate}} %{{30-(30/(invoice.VAT.rate/100+1)) | currency}}{{ 'app.admin.invoices.including_VAT' }}{{30-(30/(getMachineExampleRate()/100+1)) | currency}}
    {{ 'app.admin.invoices.including_total_excluding_taxes' }}{{30/(invoice.VAT.rate/100+1) | currency}}{{30/(getMachineExampleRate()/100+1) | currency}}
    {{ 'app.admin.invoices.including_amount_payed_on_ordering' }}