From 8e26e24f29bb8912ab2053def7ae785809851112 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 20:53:22 +0000 Subject: [PATCH 001/142] Bump tar from 6.1.4 to 6.1.11 Bumps [tar](https://github.com/npm/node-tar) from 6.1.4 to 6.1.11. - [Release notes](https://github.com/npm/node-tar/releases) - [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-tar/compare/v6.1.4...v6.1.11) --- updated-dependencies: - dependency-name: tar dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d8e831501..7211bf679 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8197,9 +8197,9 @@ tapable@^1.0.0, tapable@^1.1.3: integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tar@^6.0.2: - version "6.1.4" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.4.tgz#9f0722b772a5e00dba7d52e1923b37a7ec3799b3" - integrity sha512-kcPWrO8S5ABjuZ/v1xQHP8xCEvj1dQ1d9iAb6Qs4jLYzaAIYWwST2IQpz7Ud8VNYRI+fGhFjrnzRKmRggKWg3g== + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" From 4baa83f6b8a3674719fd63628d1337346f0311bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 06:43:31 +0000 Subject: [PATCH 002/142] Bump immer from 9.0.3 to 9.0.6 Bumps [immer](https://github.com/immerjs/immer) from 9.0.3 to 9.0.6. - [Release notes](https://github.com/immerjs/immer/releases) - [Commits](https://github.com/immerjs/immer/compare/v9.0.3...v9.0.6) --- updated-dependencies: - dependency-name: immer dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 15a72a917..44ffc4fba 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "i18next": "^19.8.3", "i18next-http-backend": "^1.0.21", "i18next-icu": "^1.4.2", - "immer": "^9.0.1", + "immer": "^9.0.6", "jasny-bootstrap": "3.1", "jquery": ">=3.5.0", "jquery-ujs": "^1.2.2", diff --git a/yarn.lock b/yarn.lock index d8e831501..467a3e42d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4507,10 +4507,10 @@ ignore@^5.1.1, ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -immer@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.3.tgz#146e2ba8b84d4b1b15378143c2345559915097f4" - integrity sha512-mONgeNSMuyjIe0lkQPa9YhdmTv8P19IeHV0biYhcXhbd5dhdB9HSK93zBpyKjp6wersSUgT5QyU0skmejUVP2A== +immer@^9.0.6: + version "9.0.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" + integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== import-cwd@^2.0.0: version "2.1.0" From cc4cf446a12f3163a28a8ea9dd22cf423431087e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 14:34:19 +0000 Subject: [PATCH 003/142] Bump url-parse from 1.5.1 to 1.5.3 Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3. - [Release notes](https://github.com/unshiftio/url-parse/releases) - [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3) --- updated-dependencies: - dependency-name: url-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d8e831501..9760328e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8530,9 +8530,9 @@ urix@^0.1.0: integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse@^1.4.3, url-parse@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b" - integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q== + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" From a1e024df15cd78822842bcaa865d15e83eb6ab98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 14:34:23 +0000 Subject: [PATCH 004/142] Bump axios from 0.21.1 to 0.21.2 Bumps [axios](https://github.com/axios/axios) from 0.21.1 to 0.21.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.21.1...v0.21.2) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ce32774a6..6ec4bd68d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "angular-ui-tour": "https://github.com/sleede/angular-ui-tour.git#master", "angular-unsavedchanges": "0.2", "angular-xeditable": "0.10", - "axios": "^0.21.1", + "axios": "^0.21.2", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "bootstrap-sass": "3.4.1", "checklist-model": "0.2", diff --git a/yarn.lock b/yarn.lock index d8e831501..5b468c14f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1924,12 +1924,12 @@ autoprefixer@^9.6.1: postcss "^7.0.32" postcss-value-parser "^4.1.0" -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== +axios@^0.21.2: + version "0.21.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017" + integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg== dependencies: - follow-redirects "^1.10.0" + follow-redirects "^1.14.0" babel-loader@^8.2.2: version "8.2.2" @@ -3962,10 +3962,10 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@^1.0.0, follow-redirects@^1.10.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" + integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== for-in@^1.0.2: version "1.0.2" From 98c65da1b45d61d00d85776f61d6d996d6a87f5b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 13 Sep 2021 16:40:29 +0200 Subject: [PATCH 005/142] New translations app.shared.en.yml (French) --- config/locales/app.shared.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index f99781860..b33ecd2fe 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -22,7 +22,7 @@ fr: you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page" you_will_lose_any_unsaved_modification_if_you_reload_this_page: "Vous perdrez les modifications non enregistrées si vous rechargez cette page" payment_card_error: "Un problème est survenu avec votre carte bancaire :" - payment_card_declined: "Votre carte a été refusée." + payment_card_declined: "Your card was declined." #user edition form user: man: "Homme" From 49a8905b44540667c990f1d3b49e314e94116d79 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 13 Sep 2021 16:40:33 +0200 Subject: [PATCH 006/142] New translations app.shared.en.yml (Zulu) --- config/locales/app.shared.zu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.shared.zu.yml b/config/locales/app.shared.zu.yml index 45ef638e6..70ffbf4d1 100644 --- a/config/locales/app.shared.zu.yml +++ b/config/locales/app.shared.zu.yml @@ -22,7 +22,7 @@ zu: you_will_lose_any_unsaved_modification_if_you_quit_this_page: "crwdns9405:0crwdne9405:0" you_will_lose_any_unsaved_modification_if_you_reload_this_page: "crwdns9407:0crwdne9407:0" payment_card_error: "crwdns9409:0crwdne9409:0" - payment_card_declined: "Your card was declined." + payment_card_declined: "crwdns22033:0crwdne22033:0" #user edition form user: man: "crwdns9411:0crwdne9411:0" From 6cf94576d82401c79fe83d08997b3872df2b652a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:25 +0200 Subject: [PATCH 007/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 023717e63..bf23eed6e 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1155,6 +1155,7 @@ fr: an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" prevent_booking: "Empêcher la réservation" + allow_booking: "Allow booking" default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." @@ -1208,6 +1209,9 @@ fr: display_invite_to_renew_pack: "Afficher l'invitation à renouveler les packs prépayés" packs_threshold_info_html: "Vous pouvez définir le nombre d'heures en dessous duquel l'utilisateur sera invité à acheter un nouveau pack prépayé, si son stock d'heures prépayées est inférieur à ce seuil.
Vous pouvez définir un nombre d'heures (par exemple. 5) ou un pourcentage de son pack actuel (par exemple 0,05 signifie 5%)." renew_pack_threshold: "seuil de renouvellement des packs" + 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" general: general: "Général" title: "Titre" From 4395032156c5326d475b9cf3c5494c39c76d9b45 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:26 +0200 Subject: [PATCH 008/142] New translations app.logged.en.yml (French) --- config/locales/app.logged.fr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.fr.yml b/config/locales/app.logged.fr.yml index 0f901e586..a48737d1f 100644 --- a/config/locales/app.logged.fr.yml +++ b/config/locales/app.logged.fr.yml @@ -196,6 +196,7 @@ fr: remaining_HOURS: "Il vous reste {HOURS} heures prépayées pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." no_hours: "Vous n'avez aucune heure prépayée pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." buy_a_new_pack: "Acheter un nouveau pack" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Planning formations" From c636103a4dbbfc98494390a09f238a111a431729 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:27 +0200 Subject: [PATCH 009/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index b95f8e1d0..465a8056f 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -1155,6 +1155,7 @@ es: an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" prevent_booking: "Impedir reservas" + allow_booking: "Allow booking" default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1208,6 +1209,9 @@ es: display_invite_to_renew_pack: "Display the invite to renew prepaid-packs" packs_threshold_info_html: "You can define under how many hours the user will be invited to buy a new prepaid-pack, if his stock of prepaid hours is under this threshold.
You can set a number of hours (eg. 5) or a percentage of his current pack pack (eg. 0.05 means 5%)." renew_pack_threshold: "threshold for packs renewal" + 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" general: general: "General" title: "Title" From ebea4969bf0589db0660c6e0c931bb2f8b191fc2 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:28 +0200 Subject: [PATCH 010/142] New translations app.logged.en.yml (Spanish) --- config/locales/app.logged.es.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.es.yml b/config/locales/app.logged.es.yml index 414615c06..ac536350d 100644 --- a/config/locales/app.logged.es.yml +++ b/config/locales/app.logged.es.yml @@ -196,6 +196,7 @@ es: remaining_HOURS: "You have {HOURS} prepaid hours remaining for this {ITEM, select, Machine{machine} Space{space} other{}}." no_hours: "You don't have any prepaid hours for this {ITEM, select, Machine{machine} Space{space} other{}}." buy_a_new_pack: "Buy a new pack" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Plan de curso" From ce7c40ea70d2b0de6d3c17c78dfb4cb73fa36c3c Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:30 +0200 Subject: [PATCH 011/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 17b4d2124..68873bdf0 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -1155,6 +1155,7 @@ de: an_error_occurred_saving_the_setting: "Beim Speichern der Einstellung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." book_overlapping_slots_info: "Erlauben / Verhindern der Reservierung von überlappenden Slots" prevent_booking: "Buchungen verhindern" + allow_booking: "Allow booking" default_slot_duration: "Standarddauer für Slots" duration_minutes: "Dauer (in Minuten)" default_slot_duration_info: "Die Verfügbarkeit von Maschinen und Räumen ist in mehrere Slots dieser Dauer aufgeteilt. Dieser Wert kann je Verfügbarkeit überschrieben werden." @@ -1208,6 +1209,9 @@ de: display_invite_to_renew_pack: "Display the invite to renew prepaid-packs" packs_threshold_info_html: "You can define under how many hours the user will be invited to buy a new prepaid-pack, if his stock of prepaid hours is under this threshold.
You can set a number of hours (eg. 5) or a percentage of his current pack pack (eg. 0.05 means 5%)." renew_pack_threshold: "threshold for packs renewal" + 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" general: general: "Allgemein" title: "Titel" From 734293891d21bcbb5e3baf80affba6f35036f07a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:31 +0200 Subject: [PATCH 012/142] New translations app.logged.en.yml (German) --- config/locales/app.logged.de.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.de.yml b/config/locales/app.logged.de.yml index 546671115..a9a68014f 100644 --- a/config/locales/app.logged.de.yml +++ b/config/locales/app.logged.de.yml @@ -196,6 +196,7 @@ de: remaining_HOURS: "You have {HOURS} prepaid hours remaining for this {ITEM, select, Machine{machine} Space{space} other{}}." no_hours: "You don't have any prepaid hours for this {ITEM, select, Machine{machine} Space{space} other{}}." buy_a_new_pack: "Buy a new pack" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Schulungsplanung" From f9bf77aabc7fd86d2c3d541d75e74e1e002619a0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:32 +0200 Subject: [PATCH 013/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index b5acc400d..692f595b2 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -1155,6 +1155,7 @@ an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" prevent_booking: "Prevent booking" + allow_booking: "Allow booking" default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1208,6 +1209,9 @@ display_invite_to_renew_pack: "Vis invitasjonen til å fornye forhånds-pakker" packs_threshold_info_html: "Du kan definere under hvor mange timer brukeren vil bli invitert til å kjøpe en ny prepaid-pakke, hvis hans beholdning av forhåndsbetalte timer er under denne grensen.
Du kan angi antall timer (f. eks. 5) eller en prosentenhet i sin nåværende pakningspakkef. eks. 0,05 betyr 5 %)." renew_pack_threshold: "terskel for fornyelse av pakker" + 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" general: general: "Generelt" title: "Tittel" From 2affcb04ad236f4d95f0067b69f9b39c92562f64 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:33 +0200 Subject: [PATCH 014/142] New translations app.logged.en.yml (Norwegian) --- config/locales/app.logged.no.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.no.yml b/config/locales/app.logged.no.yml index 2e9c8be68..8e1361bef 100644 --- a/config/locales/app.logged.no.yml +++ b/config/locales/app.logged.no.yml @@ -196,6 +196,7 @@ remaining_HOURS: "Du har {HOURS} forhåndsbetalte timer igjen for denne {ITEM, select, Machine{maskinen} Space{plassen/rommet} other{}}." no_hours: "Du har ikke noen forhåndsbetalt timer for {ITEM, select, Machine{maskinen} Space{plass/rom} other{}}." buy_a_new_pack: "Kjøp en ny pakke" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Planlegging, opplæring og kurs" From 1f5e1dea434cb19a105273be5808f7188f0f0823 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:34 +0200 Subject: [PATCH 015/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 23cce9858..7e557b690 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -1155,6 +1155,7 @@ pt: an_error_occurred_saving_the_setting: "Ocorreu um erro ao salvar a configuração. Por favor, tente novamente mais tarde." book_overlapping_slots_info: "Permitir / impedir a reserva de slots sobrepostos" prevent_booking: "Prevent booking" + allow_booking: "Allow booking" default_slot_duration: "Duração padrão para slots" duration_minutes: "Duração (em minutos)" default_slot_duration_info: "Máquina e espaço disponíveis são divididos em vários slots desta duração. Esse valor pode ser substituído por disponibilidade." @@ -1208,6 +1209,9 @@ pt: display_invite_to_renew_pack: "Display the invite to renew prepaid-packs" packs_threshold_info_html: "You can define under how many hours the user will be invited to buy a new prepaid-pack, if his stock of prepaid hours is under this threshold.
You can set a number of hours (eg. 5) or a percentage of his current pack pack (eg. 0.05 means 5%)." renew_pack_threshold: "threshold for packs renewal" + 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" general: general: "Geral" title: "Título" From deab5cd42d7eeed1cf10b755006ddf2544fe8073 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:35 +0200 Subject: [PATCH 016/142] New translations app.logged.en.yml (Portuguese) --- config/locales/app.logged.pt.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.pt.yml b/config/locales/app.logged.pt.yml index b08cf4928..4d7d9710e 100755 --- a/config/locales/app.logged.pt.yml +++ b/config/locales/app.logged.pt.yml @@ -196,6 +196,7 @@ pt: remaining_HOURS: "You have {HOURS} prepaid hours remaining for this {ITEM, select, Machine{machine} Space{space} other{}}." no_hours: "You don't have any prepaid hours for this {ITEM, select, Machine{machine} Space{space} other{}}." buy_a_new_pack: "Buy a new pack" + unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." #book a training trainings_reserve: trainings_planning: "Planos de treinamento" From b03b01784d0f000921fbb80ee9475d5521d17072 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:37 +0200 Subject: [PATCH 017/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 226622c87..bb88481e3 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -1155,6 +1155,7 @@ zu: an_error_occurred_saving_the_setting: "crwdns20380:0crwdne20380:0" book_overlapping_slots_info: "crwdns20642:0crwdne20642:0" prevent_booking: "crwdns21478:0crwdne21478:0" + allow_booking: "crwdns22035:0crwdne22035:0" default_slot_duration: "crwdns20646:0crwdne20646:0" duration_minutes: "crwdns20648:0crwdne20648:0" default_slot_duration_info: "crwdns20650:0crwdne20650:0" @@ -1208,6 +1209,9 @@ zu: display_invite_to_renew_pack: "crwdns22000:0crwdne22000:0" packs_threshold_info_html: "crwdns22030:0crwdne22030:0" renew_pack_threshold: "crwdns22004:0crwdne22004:0" + pack_only_for_subscription_info_html: "crwdns22037:0crwdne22037:0" + pack_only_for_subscription: "crwdns22039:0crwdne22039:0" + pack_only_for_subscription_info: "crwdns22041:0crwdne22041:0" general: general: "crwdns20726:0crwdne20726:0" title: "crwdns20728:0crwdne20728:0" From 115bdb277617228ee242ed0165d0c643b1fbaa66 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 21 Sep 2021 18:26:38 +0200 Subject: [PATCH 018/142] New translations app.logged.en.yml (Zulu) --- config/locales/app.logged.zu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.logged.zu.yml b/config/locales/app.logged.zu.yml index 6792e8c3e..374fb9027 100644 --- a/config/locales/app.logged.zu.yml +++ b/config/locales/app.logged.zu.yml @@ -196,6 +196,7 @@ zu: remaining_HOURS: "crwdns21934:0HOURS={HOURS}crwdnd21934:0ITEM={ITEM}crwdne21934:0" no_hours: "crwdns21936:0ITEM={ITEM}crwdne21936:0" buy_a_new_pack: "crwdns21938:0crwdne21938:0" + unable_to_use_pack_for_subsription_is_expired: "crwdns22043:0crwdne22043:0" #book a training trainings_reserve: trainings_planning: "crwdns8767:0crwdne8767:0" From a024d57c2b0c22bc6b53160ae51c79dc1a630154 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 20:41:52 +0000 Subject: [PATCH 019/142] Bump nokogiri from 1.11.4 to 1.12.5 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.4 to 1.12.5. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.4...v1.12.5) --- updated-dependencies: - dependency-name: nokogiri dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 00d4392af..0c360bb94 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -205,7 +205,7 @@ GEM rake mini_magick (4.10.1) mini_mime (1.1.0) - mini_portile2 (2.5.1) + mini_portile2 (2.6.1) minitest (5.14.4) minitest-reporters (1.4.2) ansi @@ -217,8 +217,8 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.4) - mini_portile2 (~> 2.5.0) + nokogiri (1.12.5) + mini_portile2 (~> 2.6.1) racc (~> 1.4) notify_with (0.0.2) jbuilder (~> 2.0) From 1f89fb6a3e90f1f5dd26681e85393b83d12054b5 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 30 Sep 2021 11:22:05 +0200 Subject: [PATCH 020/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index bf23eed6e..b84f978b7 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1155,7 +1155,7 @@ fr: an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" prevent_booking: "Empêcher la réservation" - allow_booking: "Allow booking" + allow_booking: "Autoriser la réservation" default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." @@ -1209,9 +1209,9 @@ fr: display_invite_to_renew_pack: "Afficher l'invitation à renouveler les packs prépayés" packs_threshold_info_html: "Vous pouvez définir le nombre d'heures en dessous duquel l'utilisateur sera invité à acheter un nouveau pack prépayé, si son stock d'heures prépayées est inférieur à ce seuil.
Vous pouvez définir un nombre d'heures (par exemple. 5) ou un pourcentage de son pack actuel (par exemple 0,05 signifie 5%)." renew_pack_threshold: "seuil de renouvellement des packs" - 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" + 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 avec un abonnement valide." + 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" general: general: "Général" title: "Titre" From 03f11bab4e320779d20f41b6c963fdcc4755671a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 30 Sep 2021 11:22:16 +0200 Subject: [PATCH 021/142] New translations app.shared.en.yml (French) --- config/locales/app.shared.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index b33ecd2fe..f99781860 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -22,7 +22,7 @@ fr: you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page" you_will_lose_any_unsaved_modification_if_you_reload_this_page: "Vous perdrez les modifications non enregistrées si vous rechargez cette page" payment_card_error: "Un problème est survenu avec votre carte bancaire :" - payment_card_declined: "Your card was declined." + payment_card_declined: "Votre carte a été refusée." #user edition form user: man: "Homme" From 6276944a5aa68c3ca5671c912678d8144e551f8b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 30 Sep 2021 11:22:21 +0200 Subject: [PATCH 022/142] New translations app.logged.en.yml (French) --- config/locales/app.logged.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.logged.fr.yml b/config/locales/app.logged.fr.yml index a48737d1f..9cfb9a368 100644 --- a/config/locales/app.logged.fr.yml +++ b/config/locales/app.logged.fr.yml @@ -196,7 +196,7 @@ fr: remaining_HOURS: "Il vous reste {HOURS} heures prépayées pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." no_hours: "Vous n'avez aucune heure prépayée pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." buy_a_new_pack: "Acheter un nouveau pack" - unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours." + unable_to_use_pack_for_subsription_is_expired: "Vous devez avoir un abonnement valide pour utiliser vos heures restantes." #book a training trainings_reserve: trainings_planning: "Planning formations" From 04703615bb94fc8287dac201e2b91ffd5f529452 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:03 +0200 Subject: [PATCH 023/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index b84f978b7..426dacb0c 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1154,7 +1154,6 @@ fr: error_SETTING_locked: "Impossible de mettre à jour le paramètre : {SETTING} est verrouillé. Veuillez contacter votre administrateur système." an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" - prevent_booking: "Empêcher la réservation" allow_booking: "Autoriser la réservation" default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" From a4fea0c331df8a8b5ba5f94ba9036b68b08a8c7b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:04 +0200 Subject: [PATCH 024/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 465a8056f..cbf9d90e3 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -1154,7 +1154,6 @@ es: error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" - prevent_booking: "Impedir reservas" allow_booking: "Allow booking" default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" From df710de25288bcfaa6b34a587364d333826363ab Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:05 +0200 Subject: [PATCH 025/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 68873bdf0..8a430a1ae 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -1154,7 +1154,6 @@ de: error_SETTING_locked: "Die Einstellung konnte nicht aktualisiert werden: {SETTING} ist gesperrt. Bitte kontaktieren Sie Ihren Systemadministrator." an_error_occurred_saving_the_setting: "Beim Speichern der Einstellung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." book_overlapping_slots_info: "Erlauben / Verhindern der Reservierung von überlappenden Slots" - prevent_booking: "Buchungen verhindern" allow_booking: "Allow booking" default_slot_duration: "Standarddauer für Slots" duration_minutes: "Dauer (in Minuten)" From 4052a555d8891f38e8fcfd37ffeda57d0426913b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:07 +0200 Subject: [PATCH 026/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 692f595b2..24b3fffeb 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -1154,7 +1154,6 @@ error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" - prevent_booking: "Prevent booking" allow_booking: "Allow booking" default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" From e61a30b6a9dc77744c826a0f53261aae774c1e6a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:08 +0200 Subject: [PATCH 027/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 7e557b690..2a33700e6 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -1154,7 +1154,6 @@ pt: error_SETTING_locked: "Não foi possível atualizar a configuração: {SETTING} está bloqueado. Por favor contate o administrador do sistema." an_error_occurred_saving_the_setting: "Ocorreu um erro ao salvar a configuração. Por favor, tente novamente mais tarde." book_overlapping_slots_info: "Permitir / impedir a reserva de slots sobrepostos" - prevent_booking: "Prevent booking" allow_booking: "Allow booking" default_slot_duration: "Duração padrão para slots" duration_minutes: "Duração (em minutos)" From b28a39425ff3e0c01387cb5314ecbb2c9ce637e8 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 11:03:09 +0200 Subject: [PATCH 028/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index bb88481e3..397bcdeb8 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -1154,7 +1154,6 @@ zu: error_SETTING_locked: "crwdns20640:0{SETTING}crwdne20640:0" an_error_occurred_saving_the_setting: "crwdns20380:0crwdne20380:0" book_overlapping_slots_info: "crwdns20642:0crwdne20642:0" - prevent_booking: "crwdns21478:0crwdne21478:0" allow_booking: "crwdns22035:0crwdne22035:0" default_slot_duration: "crwdns20646:0crwdne20646:0" duration_minutes: "crwdns20648:0crwdne20648:0" From 842c88e839c3cf68aed0b1b71b00ad622fa0dc45 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 12:09:31 +0200 Subject: [PATCH 029/142] [bug] upgrade script report invalid upgrde target --- CHANGELOG.md | 3 +++ setup/upgrade.sh | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4776c376..b22b7f448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog Fab-manager +- Fix a bug: the upgrade script report an invalid version to upgrade to + ## v5.1.10 2021 October 04 + - Fix a bug: the image of the about page is not using the image set in backoffice - Fix a bug: updated sassc to 2.4.0 to fix ruby runtime error on some CPU architectures (#270) - Fix a security issue: prevent HTML code edition in projects, to prevent XSS vulnerability (#293) diff --git a/setup/upgrade.sh b/setup/upgrade.sh index 1c9fb469d..e6fc7f26f 100644 --- a/setup/upgrade.sh +++ b/setup/upgrade.sh @@ -120,8 +120,8 @@ version_check() version_error "v4.0.4 first" elif verlt "$VERSION" 4.4.6 && verlt 4.4.6 "$TARGET"; then version_error "v4.4.6 first" - elif verlt "$VERSION" 4.7.13 && verlt 4.7.13 "$TARGET"; then - version_error "v4.7.13 first" + elif verlt "$VERSION" 4.7.14 && verlt 4.7.14 "$TARGET"; then + version_error "v4.7.14 first" elif verlt "$TARGET" "$VERSION"; then version_error "a version > $VERSION" fi From f2c436594aa8ad59871ce432f007cc64170ad02e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 16:45:54 +0200 Subject: [PATCH 030/142] check hub API access in upgrade script --- CHANGELOG.md | 2 ++ setup/upgrade.sh | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b22b7f448..756d26d09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog Fab-manager +- The upgrade script will check and report the ability to access the hub API - Fix a bug: the upgrade script report an invalid version to upgrade to +- Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) ## v5.1.10 2021 October 04 diff --git a/setup/upgrade.sh b/setup/upgrade.sh index e6fc7f26f..c1676b191 100644 --- a/setup/upgrade.sh +++ b/setup/upgrade.sh @@ -89,6 +89,11 @@ target_version() if [[ "$TAG" =~ ^:release-v[\.0-9]+$ ]]; then TARGET=$(echo "$TAG" | grep -Eo '[\.0-9]{5}') elif [ "$TAG" = ":latest" ] || [ "$TAG" = "" ]; then + HTTP_CODE=$(curl -I -s -w "%{http_code}\n" -o /dev/null https://hub.fab-manager.com/api/versions/latest) + if [ "$HTTP_CODE" != 200 ]; then + printf "\n\n\e[91m[ ❌ ] Unable to retrieve the last version of Fab-manager. Please check your internet connection or restart this script providing the \e[1m-t\e[0m\e[91m option\n\e[39m" + exit 3 + fi TARGET=$(\curl -sSL "https://hub.fab-manager.com/api/versions/latest" | jq -r '.semver') else TARGET='custom' From aa93ef189596d2d81bc1764b7da6213f3fdef852 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 16:48:18 +0200 Subject: [PATCH 031/142] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 756d26d09..b5211c93a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - The upgrade script will check and report the ability to access the hub API - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) +- Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) ## v5.1.10 2021 October 04 From c37f804b47d5c213f361dc824b6f1cce01861790 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 16:55:25 +0200 Subject: [PATCH 032/142] updated changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5211c93a..a4b90e33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,10 @@ - The upgrade script will check and report the ability to access the hub API - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) -- Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) +- Fix a security issue: updated immer to 9.0.6 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) +- Fix a security issue: updated url-parse to 1.5.3 to fix [CVE-2021-3664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3664) +- Fix a security issue: updated axios to 0.21.2 to fix [CVE-2021-3749](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3749) +- Fix a security issue: updated nokogiri to 1.12.5 to fix [CVE-2021-41098](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41098) ## v5.1.10 2021 October 04 From 888171d023301fba46d7e2b8d8316a9097388a51 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 17:03:50 +0200 Subject: [PATCH 033/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 426dacb0c..b622c6ed8 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1208,7 +1208,7 @@ fr: display_invite_to_renew_pack: "Afficher l'invitation à renouveler les packs prépayés" packs_threshold_info_html: "Vous pouvez définir le nombre d'heures en dessous duquel l'utilisateur sera invité à acheter un nouveau pack prépayé, si son stock d'heures prépayées est inférieur à ce seuil.
Vous pouvez définir un nombre d'heures (par exemple. 5) ou un pourcentage de son pack actuel (par exemple 0,05 signifie 5%)." renew_pack_threshold: "seuil de renouvellement des packs" - 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 avec un abonnement valide." + 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" general: From 838eab6b40aac0bcfb56163de888414a74f7a427 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 17:04:06 +0200 Subject: [PATCH 034/142] New translations app.logged.en.yml (French) --- config/locales/app.logged.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.logged.fr.yml b/config/locales/app.logged.fr.yml index 9cfb9a368..2d55864fb 100644 --- a/config/locales/app.logged.fr.yml +++ b/config/locales/app.logged.fr.yml @@ -196,7 +196,7 @@ fr: remaining_HOURS: "Il vous reste {HOURS} heures prépayées pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." no_hours: "Vous n'avez aucune heure prépayée pour {ITEM, select, Machine{cette machine} Space{cet espace} other{}}." buy_a_new_pack: "Acheter un nouveau pack" - unable_to_use_pack_for_subsription_is_expired: "Vous devez avoir un abonnement valide pour utiliser vos heures restantes." + unable_to_use_pack_for_subsription_is_expired: "Vous devez avoir un abonnement en cours de validité pour utiliser vos heures restantes." #book a training trainings_reserve: trainings_planning: "Planning formations" From 959d85eb6ff92e13719ca8c5aff1724ffdbe3e6a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 17:07:33 +0200 Subject: [PATCH 035/142] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b90e33d..ebfe8befe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager - The upgrade script will check and report the ability to access the hub API +- Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) - Fix a security issue: updated immer to 9.0.6 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) From 938b995db9de747937edcf0e4f779f289b0d9984 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 17:41:10 +0200 Subject: [PATCH 036/142] updated @rails/webpacker --- CHANGELOG.md | 1 + package.json | 2 +- yarn.lock | 554 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 416 insertions(+), 141 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebfe8befe..2fd4d96b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - The upgrade script will check and report the ability to access the hub API - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to +- Updated @rails/webpacker to 5.4.3 - Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) - Fix a security issue: updated immer to 9.0.6 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) - Fix a security issue: updated url-parse to 1.5.3 to fix [CVE-2021-3664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3664) diff --git a/package.json b/package.json index 01b3d27ba..83921dcdb 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@claviska/jquery-minicolors": "^2.3.5", "@fortawesome/fontawesome-free": "5.14.0", "@lyracom/embedded-form-glue": "^0.3.3", - "@rails/webpacker": "5.4.0", + "@rails/webpacker": "5.4.3", "@stripe/react-stripe-js": "^1.4.0", "@stripe/stripe-js": "^1.13.2", "@types/react": "^17.0.3", diff --git a/yarn.lock b/yarn.lock index fa3cabe34..fcdc29712 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,7 +14,12 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.5.tgz#8ef4c18e58e801c5c95d3c1c0f2874a2680fadea" integrity sha512-kixrYn4JwfAVPa0f2yfzc2AWti6WRRyO3XjWW5PJAvtE11qhSayrrcrEnee05KAtNaPC+EwehE8Qt1UedEVB8w== -"@babel/core@^7.0.0-0", "@babel/core@^7.14.3": +"@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + +"@babel/core@^7.0.0-0": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab" integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA== @@ -35,6 +40,27 @@ semver "^6.3.0" source-map "^0.5.0" +"@babel/core@^7.15.0": + version "7.15.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" + integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helpers" "^7.15.4" + "@babel/parser" "^7.15.5" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + "@babel/generator@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785" @@ -44,6 +70,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" + integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== + dependencies: + "@babel/types" "^7.15.4" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" @@ -51,6 +86,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-annotate-as-pure@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" + integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191" @@ -69,6 +111,16 @@ browserslist "^4.16.6" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" + integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.14.6": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz#f114469b6c06f8b5c59c6c4e74621f5085362542" @@ -81,6 +133,18 @@ "@babel/helper-replace-supers" "^7.14.5" "@babel/helper-split-export-declaration" "^7.14.5" +"@babel/helper-create-class-features-plugin@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" + integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-create-regexp-features-plugin@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" @@ -119,6 +183,15 @@ "@babel/template" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-function-name@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" + integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== + dependencies: + "@babel/helper-get-function-arity" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/helper-get-function-arity@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" @@ -126,6 +199,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-get-function-arity@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" + integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-hoist-variables@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" @@ -133,6 +213,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-hoist-variables@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" + integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-member-expression-to-functions@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.5.tgz#d5c70e4ad13b402c95156c7a53568f504e2fb7b8" @@ -140,6 +227,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-member-expression-to-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" + integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" @@ -147,6 +241,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-module-imports@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" + integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-module-transforms@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz#7de42f10d789b423eb902ebd24031ca77cb1e10e" @@ -161,6 +262,20 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-module-transforms@^7.15.4": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" + integrity sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw== + dependencies: + "@babel/helper-module-imports" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-simple-access" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.6" + "@babel/helper-optimise-call-expression@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c" @@ -168,6 +283,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-optimise-call-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" + integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" @@ -182,6 +304,15 @@ "@babel/helper-wrap-function" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-remap-async-to-generator@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f" + integrity sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-wrap-function" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/helper-replace-supers@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz#0ecc0b03c41cd567b4024ea016134c28414abb94" @@ -192,6 +323,16 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-replace-supers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" + integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/helper-simple-access@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz#66ea85cf53ba0b4e588ba77fc813f53abcaa41c4" @@ -199,6 +340,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-simple-access@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" + integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-skip-transparent-expression-wrappers@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4" @@ -206,6 +354,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-skip-transparent-expression-wrappers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz#707dbdba1f4ad0fa34f9114fc8197aec7d5da2eb" + integrity sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-split-export-declaration@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" @@ -213,11 +368,23 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-split-export-declaration@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" + integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== + dependencies: + "@babel/types" "^7.15.4" + "@babel/helper-validator-identifier@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== +"@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" @@ -233,6 +400,16 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-wrap-function@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz#6f754b2446cfaf3d612523e6ab8d79c27c3a3de7" + integrity sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw== + dependencies: + "@babel/helper-function-name" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/helpers@^7.14.6": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.6.tgz#5b58306b95f1b47e2a0199434fa8658fa6c21635" @@ -242,6 +419,15 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helpers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" + integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== + dependencies: + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" @@ -256,25 +442,30 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2" integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e" - integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ== +"@babel/parser@^7.15.4", "@babel/parser@^7.15.5": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" + integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz#dbdeabb1e80f622d9f0b583efb2999605e0a567e" + integrity sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog== dependencies: "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" "@babel/plugin-proposal-optional-chaining" "^7.14.5" -"@babel/plugin-proposal-async-generator-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz#4024990e3dd74181f4f426ea657769ff49a2df39" - integrity sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA== +"@babel/plugin-proposal-async-generator-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz#f82aabe96c135d2ceaa917feb9f5fca31635277e" + integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.15.4" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.14.5": +"@babel/plugin-proposal-class-properties@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== @@ -282,12 +473,12 @@ "@babel/helper-create-class-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681" - integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg== +"@babel/plugin-proposal-class-static-block@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz#3e7ca6128453c089e8b477a99f970c63fc1cb8d7" + integrity sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-class-static-block" "^7.14.5" @@ -339,16 +530,16 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.14.2", "@babel/plugin-proposal-object-rest-spread@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz#e581d5ccdfa187ea6ed73f56c6a21c1580b90fbf" - integrity sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A== +"@babel/plugin-proposal-object-rest-spread@^7.14.7", "@babel/plugin-proposal-object-rest-spread@^7.15.6": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" + integrity sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg== dependencies: - "@babel/compat-data" "^7.14.5" - "@babel/helper-compilation-targets" "^7.14.5" + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.15.4" "@babel/plugin-proposal-optional-catch-binding@^7.14.5": version "7.14.5" @@ -375,13 +566,13 @@ "@babel/helper-create-class-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636" - integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q== +"@babel/plugin-proposal-private-property-in-object@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz#55c5e3b4d0261fd44fe637e3f624cfb0f484e3e5" + integrity sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA== dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-create-class-features-plugin" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" @@ -528,24 +719,24 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-block-scoping@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz#8cc63e61e50f42e078e6f09be775a75f23ef9939" - integrity sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw== +"@babel/plugin-transform-block-scoping@^7.15.3": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-classes@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.5.tgz#0e98e82097b38550b03b483f9b51a78de0acb2cf" - integrity sha512-J4VxKAMykM06K/64z9rwiL6xnBHgB1+FVspqvlgCdwD1KUbQNfszeKVVOMh59w3sztHYIZDgnhOC4WbdEfHFDA== +"@babel/plugin-transform-classes@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz#50aee17aaf7f332ae44e3bce4c2e10534d5d3bf1" + integrity sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg== dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.14.5": @@ -555,10 +746,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-destructuring@^7.13.17", "@babel/plugin-transform-destructuring@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz#d32ad19ff1a6da1e861dc62720d80d9776e3bf35" - integrity sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww== +"@babel/plugin-transform-destructuring@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" + integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -585,10 +776,10 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-for-of@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb" - integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA== +"@babel/plugin-transform-for-of@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz#25c62cce2718cfb29715f416e75d5263fb36a8c2" + integrity sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -623,25 +814,25 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97" - integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A== +"@babel/plugin-transform-modules-commonjs@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz#8201101240eabb5a76c08ef61b2954f767b6b4c1" + integrity sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA== dependencies: - "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-module-transforms" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.14.5" + "@babel/helper-simple-access" "^7.15.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29" - integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA== +"@babel/plugin-transform-modules-systemjs@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz#b42890c7349a78c827719f1d2d0cd38c7d268132" + integrity sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw== dependencies: - "@babel/helper-hoist-variables" "^7.14.5" - "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-umd@^7.14.5": @@ -652,10 +843,10 @@ "@babel/helper-module-transforms" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-named-capturing-groups-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz#d537e8ee083ee6f6aa4f4eef9d2081d555746e4c" - integrity sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" + integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.14.5" @@ -674,10 +865,10 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.14.5" -"@babel/plugin-transform-parameters@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3" - integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA== +"@babel/plugin-transform-parameters@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz#5f2285cc3160bf48c8502432716b48504d29ed62" + integrity sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -721,7 +912,7 @@ "@babel/helper-annotate-as-pure" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-regenerator@^7.13.15", "@babel/plugin-transform-regenerator@^7.14.5": +"@babel/plugin-transform-regenerator@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== @@ -735,10 +926,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-runtime@^7.14.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" - integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg== +"@babel/plugin-transform-runtime@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3" + integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw== dependencies: "@babel/helper-module-imports" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" @@ -754,7 +945,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-spread@^7.14.5": +"@babel/plugin-transform-spread@^7.14.6": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== @@ -807,30 +998,30 @@ "@babel/helper-create-regexp-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@^7.14.2": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.5.tgz#c0c84e763661fd0e74292c3d511cb33b0c668997" - integrity sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA== +"@babel/preset-env@^7.15.0": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" + integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== dependencies: - "@babel/compat-data" "^7.14.5" - "@babel/helper-compilation-targets" "^7.14.5" + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-async-generator-functions" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" + "@babel/plugin-proposal-async-generator-functions" "^7.15.4" "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-class-static-block" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.15.4" "@babel/plugin-proposal-dynamic-import" "^7.14.5" "@babel/plugin-proposal-export-namespace-from" "^7.14.5" "@babel/plugin-proposal-json-strings" "^7.14.5" "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.15.6" "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" "@babel/plugin-proposal-optional-chaining" "^7.14.5" "@babel/plugin-proposal-private-methods" "^7.14.5" - "@babel/plugin-proposal-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.15.4" "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" @@ -849,41 +1040,41 @@ "@babel/plugin-transform-arrow-functions" "^7.14.5" "@babel/plugin-transform-async-to-generator" "^7.14.5" "@babel/plugin-transform-block-scoped-functions" "^7.14.5" - "@babel/plugin-transform-block-scoping" "^7.14.5" - "@babel/plugin-transform-classes" "^7.14.5" + "@babel/plugin-transform-block-scoping" "^7.15.3" + "@babel/plugin-transform-classes" "^7.15.4" "@babel/plugin-transform-computed-properties" "^7.14.5" - "@babel/plugin-transform-destructuring" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" "@babel/plugin-transform-dotall-regex" "^7.14.5" "@babel/plugin-transform-duplicate-keys" "^7.14.5" "@babel/plugin-transform-exponentiation-operator" "^7.14.5" - "@babel/plugin-transform-for-of" "^7.14.5" + "@babel/plugin-transform-for-of" "^7.15.4" "@babel/plugin-transform-function-name" "^7.14.5" "@babel/plugin-transform-literals" "^7.14.5" "@babel/plugin-transform-member-expression-literals" "^7.14.5" "@babel/plugin-transform-modules-amd" "^7.14.5" - "@babel/plugin-transform-modules-commonjs" "^7.14.5" - "@babel/plugin-transform-modules-systemjs" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.15.4" + "@babel/plugin-transform-modules-systemjs" "^7.15.4" "@babel/plugin-transform-modules-umd" "^7.14.5" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" "@babel/plugin-transform-new-target" "^7.14.5" "@babel/plugin-transform-object-super" "^7.14.5" - "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.15.4" "@babel/plugin-transform-property-literals" "^7.14.5" "@babel/plugin-transform-regenerator" "^7.14.5" "@babel/plugin-transform-reserved-words" "^7.14.5" "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.5" + "@babel/plugin-transform-spread" "^7.14.6" "@babel/plugin-transform-sticky-regex" "^7.14.5" "@babel/plugin-transform-template-literals" "^7.14.5" "@babel/plugin-transform-typeof-symbol" "^7.14.5" "@babel/plugin-transform-unicode-escapes" "^7.14.5" "@babel/plugin-transform-unicode-regex" "^7.14.5" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.6" babel-plugin-polyfill-corejs2 "^0.2.2" babel-plugin-polyfill-corejs3 "^0.2.2" babel-plugin-polyfill-regenerator "^0.2.2" - core-js-compat "^3.14.0" + core-js-compat "^3.16.0" semver "^6.3.0" "@babel/preset-modules@^0.1.4": @@ -918,13 +1109,20 @@ "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-transform-typescript" "^7.14.5" -"@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.14.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d" integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg== dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.15.3": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -934,6 +1132,15 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/template@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" + integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.5.tgz#c111b0f58afab4fea3d3385a406f692748c59870" @@ -949,6 +1156,21 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" + integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.14.5", "@babel/types@^7.4.4": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff" @@ -957,6 +1179,14 @@ "@babel/helper-validator-identifier" "^7.14.5" to-fast-properties "^2.0.0" +"@babel/types@^7.15.4", "@babel/types@^7.15.6": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" + integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + "@claviska/jquery-minicolors@^2.3.5": version "2.3.5" resolved "https://registry.yarnpkg.com/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.5.tgz#b802fcf2a7b75f169e68a7321d8a8d03f9fcd17c" @@ -1085,42 +1315,42 @@ schema-utils "^2.6.5" source-map "^0.7.3" -"@rails/webpacker@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-5.4.0.tgz#2c64a9ea7e85d2a33e50e86319fe6751df0c47e8" - integrity sha512-J973mzTUJbkbBu+sMwKgWRahoSfwdp5uHT80iDWr6hi8YAC7kj47HapQnn2SGPmv/onTT8WC3jFM62Hkh213yQ== +"@rails/webpacker@5.4.3": + version "5.4.3" + resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-5.4.3.tgz#cfe2d8faffe7db5001bad50a1534408b4f2efb2f" + integrity sha512-tEM8tpUtfx6FxKwcuQ9+v6pzgqM5LeAdhT6IJ4Te3BPKFO1xrGrXugqeRuZ+gE8ASDZRTOK6yuQkapOpuX5JdA== dependencies: - "@babel/core" "^7.14.3" - "@babel/plugin-proposal-class-properties" "^7.13.0" - "@babel/plugin-proposal-object-rest-spread" "^7.14.2" + "@babel/core" "^7.15.0" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.14.7" "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.13.17" - "@babel/plugin-transform-regenerator" "^7.13.15" - "@babel/plugin-transform-runtime" "^7.14.3" - "@babel/preset-env" "^7.14.2" - "@babel/runtime" "^7.14.0" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@babel/plugin-transform-regenerator" "^7.14.5" + "@babel/plugin-transform-runtime" "^7.15.0" + "@babel/preset-env" "^7.15.0" + "@babel/runtime" "^7.15.3" babel-loader "^8.2.2" babel-plugin-dynamic-import-node "^2.3.3" babel-plugin-macros "^2.8.0" case-sensitive-paths-webpack-plugin "^2.4.0" compression-webpack-plugin "^4.0.1" - core-js "^3.12.1" + core-js "^3.16.2" css-loader "^3.6.0" file-loader "^6.2.0" - flatted "^3.1.1" + flatted "^3.2.2" glob "^7.1.7" js-yaml "^3.14.1" mini-css-extract-plugin "^0.9.0" - optimize-css-assets-webpack-plugin "^5.0.6" + optimize-css-assets-webpack-plugin "^5.0.8" path-complete-extname "^1.0.0" - pnp-webpack-plugin "^1.6.4" + pnp-webpack-plugin "^1.7.0" postcss-flexbugs-fixes "^4.2.1" postcss-import "^12.0.1" postcss-loader "^3.0.0" postcss-preset-env "^6.7.0" postcss-safe-parser "^4.0.2" - regenerator-runtime "^0.13.7" - sass "^1.32.13" + regenerator-runtime "^0.13.9" + sass "^1.38.0" sass-loader "10.1.1" style-loader "^1.3.0" terser-webpack-plugin "^4.2.3" @@ -2202,6 +2432,17 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4 escalade "^3.1.1" node-releases "^1.1.71" +browserslist@^4.17.1: + version "4.17.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.2.tgz#aa15dbd2fab399a399fe4df601bb09363c5458a6" + integrity sha512-jSDZyqJmkKMEMi7SZAgX5UltFdR5NAO43vY0AwTpu4X3sGH7GLLQ83KiUomgrnvZRCeW0yPPnKqnxPqQOER9zQ== + dependencies: + caniuse-lite "^1.0.30001261" + electron-to-chromium "^1.3.854" + escalade "^3.1.1" + nanocolors "^0.2.12" + node-releases "^1.1.76" + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -2360,6 +2601,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, can resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz#66e8669985bb2cb84ccb10f68c25ce6dd3e4d2b8" integrity sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ== +caniuse-lite@^1.0.30001261: + version "1.0.30001264" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001264.tgz#88f625a60efb6724c7c62ac698bc8dbd9757e55b" + integrity sha512-Ftfqqfcs/ePiUmyaySsQ4PUsdcYyXG2rfoBVsk3iY1ahHaJEw65vfb7Suzqm+cEkwwPIv/XWkg27iCpRavH4zA== + case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" @@ -2699,10 +2945,18 @@ core-js-compat@^3.14.0: browserslist "^4.16.6" semver "7.0.0" -core-js@^3.12.1: - version "3.15.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.0.tgz#db9554ebce0b6fd90dc9b1f2465c841d2d055044" - integrity sha512-GUbtPllXMYRzIgHNZ4dTYTcUemls2cni83Q4Q/TrFONHfhcg9oEGOtaGHfb0cpzec60P96UKPvMkjX1jET8rUw== +core-js-compat@^3.16.0: + version "3.18.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.18.1.tgz#01942a0877caf9c6e5007c027183cf0bdae6a191" + integrity sha512-XJMYx58zo4W0kLPmIingVZA10+7TuKrMLPt83+EzDmxFJQUMcTVVmQ+n5JP4r6Z14qSzhQBRi3NSWoeVyKKXUg== + dependencies: + browserslist "^4.17.1" + semver "7.0.0" + +core-js@^3.16.2: + version "3.18.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.1.tgz#289d4be2ce0085d40fc1244c0b1a54c00454622f" + integrity sha512-vJlUi/7YdlCZeL6fXvWNaLUPh/id12WXj3MbkMw5uOyF0PfWPBNOCNbs53YqgrvtujLNlt9JQpruyIKkUZ+PKA== core-util-is@~1.0.0: version "1.0.2" @@ -3286,6 +3540,11 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz#0728587f1b9b970ec9ffad932496429aef750d09" integrity sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A== +electron-to-chromium@^1.3.854: + version "1.3.857" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.857.tgz#dcc239ff8a12b6e4b501e6a5ad20fd0d5a3210f9" + integrity sha512-a5kIr2lajm4bJ5E4D3fp8Y/BRB0Dx2VOcCRE5Gtb679mXIME/OFhWler8Gy2ksrf8gFX+EFCSIGA33FB3gqYpg== + elliptic@^6.5.3: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -3944,10 +4203,10 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flatted@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== +flatted@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== flatten@^1.0.2: version "1.0.3" @@ -5601,6 +5860,11 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nanocolors@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.2.12.tgz#4d05932e70116078673ea4cc6699a1c56cc77777" + integrity sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -5728,6 +5992,11 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== +node-releases@^1.1.76: + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== + nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -5932,10 +6201,10 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -optimize-css-assets-webpack-plugin@^5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.6.tgz#abad0c6c11a632201794f75ddba3ce13e32ae80e" - integrity sha512-JAYw7WrIAIuHWoKeSBB3lJ6ZG9PSDK3JJduv/FMpIY060wvbA8Lqn/TCtxNGICNlg0X5AGshLzIhpYrkltdq+A== +optimize-css-assets-webpack-plugin@^5.0.8: + version "5.0.8" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz#cbccdcf5a6ef61d4f8cc78cf083a67446e5f402a" + integrity sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q== dependencies: cssnano "^4.1.10" last-call-webpack-plugin "^3.0.0" @@ -6254,10 +6523,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pnp-webpack-plugin@^1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" - integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== +pnp-webpack-plugin@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz#65741384f6d8056f36e2255a8d67ffc20866f5c9" + integrity sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg== dependencies: ts-pnp "^1.1.6" @@ -7272,11 +7541,16 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: +regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== +regenerator-runtime@^0.13.9: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -7557,10 +7831,10 @@ sass-loader@10.1.1: schema-utils "^3.0.0" semver "^7.3.2" -sass@^1.32.13: - version "1.35.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.35.1.tgz#90ecf774dfe68f07b6193077e3b42fb154b9e1cd" - integrity sha512-oCisuQJstxMcacOPmxLNiLlj4cUyN2+8xJnG7VanRoh2GOLr9RqkvI4AxA4a6LHVg/rsu+PmxXeGhrdSF9jCiQ== +sass@^1.38.0: + version "1.42.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.42.1.tgz#5ab17bebc1cb1881ad2e0c9a932c66ad64e441e2" + integrity sha512-/zvGoN8B7dspKc5mC6HlaygyCBRvnyzzgD5khiaCfglWztY99cYoiTUksVx11NlnemrcfH5CEaCpsUKoW0cQqg== dependencies: chokidar ">=3.0.0 <4.0.0" From b32a20fb29b4aae3d9f84e3d6ce25c90fbb84a01 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 5 Oct 2021 17:06:41 +0200 Subject: [PATCH 037/142] added missing babel plugins + updated react-refresh + updated react-refresh-webpack-plugin --- CHANGELOG.md | 2 ++ package.json | 11 +++++-- yarn.lock | 87 ++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd4d96b6..90d131c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to - Updated @rails/webpacker to 5.4.3 +- Updated react-refresh-webpack-plugin to 0.5.1 +- Updated react-refresh to 0.10.0 - Fix a security issue: updated tar to 6.1.11 to fix [CVE-2021-37712](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37712), [CVE-2021-37701](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37701) and [CVE-2021-37713](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37713) - Fix a security issue: updated immer to 9.0.6 to fix [CVE-2021-3757](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3757) and [CVE-2021-23436](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-23436) - Fix a security issue: updated url-parse to 1.5.3 to fix [CVE-2021-3664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3664) diff --git a/package.json b/package.json index 83921dcdb..c5e158388 100644 --- a/package.json +++ b/package.json @@ -21,10 +21,17 @@ }, "license": "AGPL-3.0-only", "devDependencies": { - "@pmmmwh/react-refresh-webpack-plugin": "^0.4.2", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.15.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.14.7", + "@babel/plugin-transform-runtime": "^7.15.0", + "@babel/preset-env": "^7.15.6", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1", "@typescript-eslint/eslint-plugin": "^4.28.1", "@typescript-eslint/parser": "^4.28.1", "auto-ngtemplate-loader": "^3.1.0", + "babel-loader": "^8.2.2", "eslint": "~6.8.0", "eslint-config-standard": "~14.1.1", "eslint-plugin-import": "~2.20.1", @@ -36,7 +43,7 @@ "html-loader": "^1.3.0", "ngtemplate-loader": "^2.1.0", "rails-erb-loader": "^5.5.2", - "react-refresh": "^0.9.0", + "react-refresh": "^0.10.0", "resolve-url-loader": "^4.0.0", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.0" diff --git a/yarn.lock b/yarn.lock index fcdc29712..ca187b9e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -998,7 +998,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@^7.15.0": +"@babel/preset-env@^7.15.0", "@babel/preset-env@^7.15.6": version "7.15.6" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== @@ -1303,16 +1303,19 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@pmmmwh/react-refresh-webpack-plugin@^0.4.2": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz#1eec460596d200c0236bf195b078a5d1df89b766" - integrity sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ== +"@pmmmwh/react-refresh-webpack-plugin@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.1.tgz#7e98d6f22c360e1dd00909f5fa9d0f6ecc263292" + integrity sha512-ccap6o7+y5L8cnvkZ9h8UXCGyy2DqtwCD+/N3Yru6lxMvcdkPKtdx13qd7sAC9s5qZktOmWf9lfUjsGOvSdYhg== dependencies: - ansi-html "^0.0.7" + ansi-html-community "^0.0.8" + common-path-prefix "^3.0.0" + core-js-pure "^3.8.1" error-stack-parser "^2.0.6" - html-entities "^1.2.1" - native-url "^0.2.6" - schema-utils "^2.6.5" + find-up "^5.0.0" + html-entities "^2.1.0" + loader-utils "^2.0.0" + schema-utils "^3.0.0" source-map "^0.7.3" "@rails/webpacker@5.4.3": @@ -1941,7 +1944,12 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" -ansi-html@0.0.7, ansi-html@^0.0.7: +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= @@ -2815,6 +2823,11 @@ commander@^4.1.1: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2953,6 +2966,11 @@ core-js-compat@^3.16.0: browserslist "^4.17.1" semver "7.0.0" +core-js-pure@^3.8.1: + version "3.18.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.18.1.tgz#097d34d24484be45cea700a448d1e74622646c80" + integrity sha512-kmW/k8MaSuqpvA1xm2l3TVlBuvW+XBkcaOroFUpO3D4lsTGQWBTb/tBDCf/PNkkPLrwgrkQRIYNPB0CeqGJWGQ== + core-js@^3.16.2: version "3.18.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.1.tgz#289d4be2ce0085d40fc1244c0b1a54c00454622f" @@ -4179,6 +4197,14 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + findup-sync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" @@ -4600,11 +4626,16 @@ hsla-regex@^1.0.0: resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= -html-entities@^1.2.1, html-entities@^1.3.1: +html-entities@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== +html-entities@^2.1.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" + integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== + html-loader@^1.3.0, html-loader@~1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-1.3.2.tgz#5a72ebba420d337083497c9aba7866c9e1aee340" @@ -5429,6 +5460,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -5882,13 +5920,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -native-url@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" - integrity sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA== - dependencies: - querystring "^0.2.0" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -6285,6 +6316,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -7317,11 +7355,6 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -querystring@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -7414,10 +7447,10 @@ react-modal@^3.11.2: react-lifecycles-compat "^3.0.0" warning "^4.0.3" -react-refresh@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" - integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== +react-refresh@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.10.0.tgz#2f536c9660c0b9b1d500684d9e52a65e7404f7e3" + integrity sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ== react-select@^4.3.1: version "4.3.1" From a9f431a6a27e8cc281b78d2ab448ae98ff2f126c Mon Sep 17 00:00:00 2001 From: Du Peng Date: Thu, 30 Sep 2021 14:46:47 +0200 Subject: [PATCH 038/142] fix bug: offer and extends subscription --- app/models/payment_schedule.rb | 4 ++++ app/services/payment_gateway_service.rb | 4 ++++ app/services/subscriptions/subscribe.rb | 2 +- lib/pay_zen/service.rb | 4 ++++ lib/stripe/item.rb | 2 +- lib/stripe/service.rb | 15 ++++++++++++++- 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/app/models/payment_schedule.rb b/app/models/payment_schedule.rb index c3edf9758..0b3b4ec6f 100644 --- a/app/models/payment_schedule.rb +++ b/app/models/payment_schedule.rb @@ -85,6 +85,10 @@ class PaymentSchedule < PaymentDocument PaymentGatewayService.new.pay_subscription(self, gateway_method_id) end + def post_save_extend(gateway_method_id) + PaymentGatewayService.new.extend_subscription(self, gateway_method_id) + end + def render_resource { partial: 'api/payment_schedules/payment_schedule', locals: { payment_schedule: self } } end diff --git a/app/services/payment_gateway_service.rb b/app/services/payment_gateway_service.rb index ef98896e5..48a7940fa 100644 --- a/app/services/payment_gateway_service.rb +++ b/app/services/payment_gateway_service.rb @@ -27,6 +27,10 @@ class PaymentGatewayService @gateway.pay_subscription(payment_schedule, gateway_object_id) end + def extend_subscription(payment_schedule, gateway_object_id) + @gateway.extend_subscription(payment_schedule, gateway_object_id) + end + def create_user(user_id) @gateway.create_user(user_id) end diff --git a/app/services/subscriptions/subscribe.rb b/app/services/subscriptions/subscribe.rb index 806aa4d37..13dfac28b 100644 --- a/app/services/subscriptions/subscribe.rb +++ b/app/services/subscriptions/subscribe.rb @@ -54,7 +54,7 @@ class Subscriptions::Subscribe ) end payment.save - payment.post_save(schedule&.gateway_payment_mean&.id) + payment.post_save_extend(schedule&.gateway_payment_mean&.id) UsersCredits::Manager.new(user: new_sub.user).reset_credits return new_sub end diff --git a/lib/pay_zen/service.rb b/lib/pay_zen/service.rb index b09678bd8..b8158892c 100644 --- a/lib/pay_zen/service.rb +++ b/lib/pay_zen/service.rb @@ -48,6 +48,10 @@ class PayZen::Service < Payment::Service pgo_sub.save! end + def extend_subscription(payment_schedule, payment_method_id) + create_subscription(payment_schedule, payment_method_id) + end + def process_payment_schedule_item(payment_schedule_item) pz_order = payment_schedule_item.payment_schedule.gateway_order.retrieve transaction = pz_order['answer']['transactions'].last diff --git a/lib/stripe/item.rb b/lib/stripe/item.rb index 903ea497b..a81e2c671 100644 --- a/lib/stripe/item.rb +++ b/lib/stripe/item.rb @@ -15,7 +15,7 @@ class Stripe::Item < Payment::Item end def payment_mean? - klass == 'Stripe::SetupIntent' + klass == 'Stripe::PaymentMethod' end def subscription? diff --git a/lib/stripe/service.rb b/lib/stripe/service.rb index 71a0eeb2b..f904898a9 100644 --- a/lib/stripe/service.rb +++ b/lib/stripe/service.rb @@ -14,8 +14,11 @@ class Stripe::Service < Payment::Service handle_wallet_transaction(payment_schedule) stp_subscription = Stripe::Subscription.retrieve(subscription_id, api_key: stripe_key) + + payment_method_id = stp_subscription.default_payment_method + payment_method = Stripe::PaymentMethod.retrieve(payment_method_id, api_key: stripe_key) pgo = PaymentGatewayObject.new(item: payment_schedule) - pgo.gateway_object = stp_subscription + pgo.gateway_object = payment_method pgo.save! end @@ -56,6 +59,16 @@ class Stripe::Service < Payment::Service }, { api_key: stripe_key }) end + def extend_subscription(payment_schedule, payment_method_id) + stp_subscription = pay_subscription(payment_schedule, payment_method_id) + + handle_wallet_transaction(payment_schedule) + + pgo = PaymentGatewayObject.new(item: payment_schedule) + pgo.gateway_object = stp_subscription + pgo.save! + end + def create_user(user_id) StripeWorker.perform_async(:create_stripe_customer, user_id) end From 8b811a1b3ebca57b5336e12e379cb5ca8306b649 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 4 Oct 2021 10:10:44 +0200 Subject: [PATCH 039/142] improved syntax --- app/services/subscriptions/subscribe.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/subscriptions/subscribe.rb b/app/services/subscriptions/subscribe.rb index 13dfac28b..34cd6283c 100644 --- a/app/services/subscriptions/subscribe.rb +++ b/app/services/subscriptions/subscribe.rb @@ -14,7 +14,7 @@ class Subscriptions::Subscribe new_sub = Subscription.create( plan_id: subscription.plan_id, - statistic_profile_id: subscription.statistic_profile_id, + statistic_profile_id: subscription.statistic_profile_id ) new_sub.expiration_date = new_expiration_date if new_sub.save From d494b012d4cd213109e2d273bb3adeca1f968884 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 6 Oct 2021 09:42:58 +0200 Subject: [PATCH 040/142] [ongoing] refactoring stripe subscription --- app/controllers/api/stripe_controller.rb | 14 ++++---------- app/frontend/src/javascript/api/stripe.ts | 4 ++-- .../components/payment/stripe/stripe-form.tsx | 2 +- config/routes.rb | 2 +- lib/stripe/service.rb | 16 ++++++++++++++++ 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/stripe_controller.rb b/app/controllers/api/stripe_controller.rb index c5e92e1c6..6d4c71ace 100644 --- a/app/controllers/api/stripe_controller.rb +++ b/app/controllers/api/stripe_controller.rb @@ -69,19 +69,13 @@ class API::StripeController < API::PaymentsController render json: { id: @intent.id, client_secret: @intent.client_secret } end - def payment_schedule + def create_subscription cart = shopping_cart - Stripe.api_key = Setting.get('stripe_secret_key') - @intent = Stripe::PaymentMethod.attach( + intent = Stripe::Service.new.attach_method_as_default( params[:payment_method_id], - customer: cart.customer.payment_gateway_object.gateway_object_id + cart.customer.payment_gateway_object.gateway_object_id ) - # Set the default payment method on the customer - Stripe::Customer.update( - cart.customer.payment_gateway_object.gateway_object_id, - invoice_settings: { default_payment_method: params[:payment_method_id] } - ) - @res = cart.pay_schedule(@intent.id, @intent.class.name) + @res = cart.pay_schedule(intent.id, intent.class.name) render json: @res.to_json end diff --git a/app/frontend/src/javascript/api/stripe.ts b/app/frontend/src/javascript/api/stripe.ts index 2604e9e15..1c31bce7a 100644 --- a/app/frontend/src/javascript/api/stripe.ts +++ b/app/frontend/src/javascript/api/stripe.ts @@ -21,8 +21,8 @@ export default class StripeAPI { return res?.data; } - static async paymentSchedule (paymentMethodId: string, cartItems: ShoppingCart): Promise { - const res: AxiosResponse = await apiClient.post('/api/stripe/payment_schedule', { + static async createSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise { + const res: AxiosResponse = await apiClient.post('/api/stripe/create_subscription', { payment_method_id: paymentMethodId, cart_items: cartItems }); diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx index 180f98288..737afc21b 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx @@ -44,7 +44,7 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on await handleServerConfirmation(res); } else { const paymentMethodId = paymentMethod.id; - const subscription: StripeSubscription = await StripeAPI.paymentSchedule(paymentMethod.id, cart); + const subscription: StripeSubscription = await StripeAPI.createSubscription(paymentMethod.id, cart); if (subscription && subscription.status === 'active') { // Subscription is active, no customer actions required. const res = await StripeAPI.confirmPaymentSchedule(subscription.id, cart); diff --git a/config/routes.rb b/config/routes.rb index ce0f73fa8..c05b7ce1c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -180,7 +180,7 @@ Rails.application.routes.draw do # card payments handling ## Stripe gateway post 'stripe/confirm_payment' => 'stripe/confirm_payment' - post 'stripe/payment_schedule' => 'stripe/payment_schedule' + post 'stripe/create_subscription' => 'stripe/create_subscription' get 'stripe/online_payment_status' => 'stripe/online_payment_status' get 'stripe/setup_intent/:user_id' => 'stripe#setup_intent' post 'stripe/confirm_payment_schedule' => 'stripe#confirm_payment_schedule' diff --git a/lib/stripe/service.rb b/lib/stripe/service.rb index 71a0eeb2b..1927f4f94 100644 --- a/lib/stripe/service.rb +++ b/lib/stripe/service.rb @@ -145,6 +145,22 @@ class Stripe::Service < Payment::Service { status: stp_invoice.status, error: e } end + def attach_method_as_default(payment_method_id, customer_id) + Stripe.api_key = Setting.get('stripe_secret_key') + + # attach the payment method to the given customer + intent = Stripe::PaymentMethod.attach( + payment_method_id, + customer: customer_id + ) + # then set it as the default payment method for this customer + Stripe::Customer.update( + cart.customer.payment_gateway_object.gateway_object_id, + invoice_settings: { default_payment_method: params[:payment_method_id] } + ) + intent + end + private def subscription_invoice_items(payment_schedule, subscription, first_item, reservable_stp_id) From 3663f8ab865786b6cfea71ee73c56513682eeb8f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 6 Oct 2021 17:09:35 +0200 Subject: [PATCH 041/142] full stripe subscription code refacto TODO: test --- app/controllers/api/stripe_controller.rb | 25 ++-- app/frontend/src/javascript/api/stripe.ts | 8 +- .../components/payment/stripe/stripe-form.tsx | 49 +++----- app/frontend/src/javascript/models/payment.ts | 13 +- app/frontend/src/javascript/models/stripe.ts | 119 ++++++++++++++++++ app/models/payment_schedule.rb | 4 - app/models/shopping_cart.rb | 15 --- app/services/payment_gateway_service.rb | 4 - app/services/wallet_service.rb | 1 + config/routes.rb | 4 +- lib/stripe/service.rb | 78 ++++++------ 11 files changed, 197 insertions(+), 123 deletions(-) diff --git a/app/controllers/api/stripe_controller.rb b/app/controllers/api/stripe_controller.rb index 6d4c71ace..7ef820ccf 100644 --- a/app/controllers/api/stripe_controller.rb +++ b/app/controllers/api/stripe_controller.rb @@ -47,7 +47,7 @@ class API::StripeController < API::PaymentsController res = on_payment_success(intent, cart) if intent&.status == 'succeeded' - render generate_payment_response(intent, res) + render generate_payment_response(intent, 'payment', res) end def online_payment_status @@ -71,15 +71,24 @@ class API::StripeController < API::PaymentsController def create_subscription cart = shopping_cart - intent = Stripe::Service.new.attach_method_as_default( + cart.items.each do |item| + raise InvalidSubscriptionError unless item.valid?(@items) + raise InvalidSubscriptionError unless item.to_object.errors.empty? + end + + service = Stripe::Service.new + method = service.attach_method_as_default( params[:payment_method_id], cart.customer.payment_gateway_object.gateway_object_id ) - @res = cart.pay_schedule(intent.id, intent.class.name) - render json: @res.to_json + + stp_subscription = service.subscribe(method.id, cart) + + res = on_payment_success(stp_subscription, cart) if stp_subscription&.status == 'active' + render generate_payment_response(stp_subscription.latest_invoice.payment_intent, 'subscription', res, stp_subscription.id) end - def confirm_payment_schedule + def confirm_subscription key = Setting.get('stripe_secret_key') subscription = Stripe::Subscription.retrieve(params[:subscription_id], api_key: key) @@ -124,7 +133,7 @@ class API::StripeController < API::PaymentsController super(intent.id, intent.class.name, cart) end - def generate_payment_response(intent, res = nil) + def generate_payment_response(intent, type, res = nil, stp_subscription_id = nil) return res unless res.nil? if intent.status == 'requires_action' && intent.next_action.type == 'use_stripe_sdk' @@ -133,7 +142,9 @@ class API::StripeController < API::PaymentsController status: 200, json: { requires_action: true, - payment_intent_client_secret: intent.client_secret + payment_intent_client_secret: intent.client_secret, + type: type, + subscription_id: stp_subscription_id } } elsif intent.status == 'succeeded' diff --git a/app/frontend/src/javascript/api/stripe.ts b/app/frontend/src/javascript/api/stripe.ts index 1c31bce7a..b409019ed 100644 --- a/app/frontend/src/javascript/api/stripe.ts +++ b/app/frontend/src/javascript/api/stripe.ts @@ -1,6 +1,6 @@ import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; -import { ShoppingCart, IntentConfirmation, PaymentConfirmation, UpdateCardResponse, StripeSubscription } from '../models/payment'; +import { ShoppingCart, IntentConfirmation, PaymentConfirmation, UpdateCardResponse } from '../models/payment'; import { PaymentSchedule } from '../models/payment-schedule'; import { Invoice } from '../models/invoice'; @@ -21,7 +21,7 @@ export default class StripeAPI { return res?.data; } - static async createSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise { + static async createSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise { const res: AxiosResponse = await apiClient.post('/api/stripe/create_subscription', { payment_method_id: paymentMethodId, cart_items: cartItems @@ -34,8 +34,8 @@ export default class StripeAPI { return res?.data; } - static async confirmPaymentSchedule (subscriptionId: string, cartItems: ShoppingCart): Promise { - const res: AxiosResponse = await apiClient.post('/api/stripe/confirm_payment_schedule', { + static async confirmSubscription (subscriptionId: string, cartItems: ShoppingCart): Promise { + const res: AxiosResponse = await apiClient.post('/api/stripe/confirm_subscription', { subscription_id: subscriptionId, cart_items: cartItems }); diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx index 737afc21b..0c9ea6eff 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx @@ -2,9 +2,10 @@ import React, { FormEvent } from 'react'; import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js'; import { useTranslation } from 'react-i18next'; import { GatewayFormProps } from '../abstract-payment-modal'; -import { PaymentConfirmation, StripeSubscription } from '../../../models/payment'; +import { PaymentConfirmation } from '../../../models/payment'; import StripeAPI from '../../../api/stripe'; import { Invoice } from '../../../models/invoice'; +import { PaymentSchedule } from '../../../models/payment-schedule'; /** * A form component to collect the credit card details and to create the payment method on Stripe. @@ -43,36 +44,8 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on const res = await StripeAPI.confirmMethod(paymentMethod.id, cart); await handleServerConfirmation(res); } else { - const paymentMethodId = paymentMethod.id; - const subscription: StripeSubscription = await StripeAPI.createSubscription(paymentMethod.id, cart); - if (subscription && subscription.status === 'active') { - // Subscription is active, no customer actions required. - const res = await StripeAPI.confirmPaymentSchedule(subscription.id, cart); - onSuccess(res); - } - const paymentIntent = subscription.latest_invoice.payment_intent; - - if (paymentIntent.status === 'requires_action') { - return stripe - .confirmCardPayment(paymentIntent.client_secret, { - payment_method: paymentMethodId - }) - .then(async (result) => { - if (result.error) { - throw result.error; - } else { - if (result.paymentIntent.status === 'succeeded') { - const res = await StripeAPI.confirmPaymentSchedule(subscription.id, cart); - onSuccess(res); - } - } - }) - .catch((error) => { - onError(error.message); - }); - } else if (paymentIntent.status === 'requires_payment_method') { - onError(t('app.shared.messages.payment_card_declined')); - } + const res = await StripeAPI.createSubscription(paymentMethod.id, cart); + await handleServerConfirmation(res); } } catch (err) { // catch api errors @@ -83,10 +56,10 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on /** * Process the server response about the Strong-customer authentication (SCA) - * @param response can be a PaymentConfirmation, or an Invoice (if the payment succeeded) + * @param response can be a PaymentConfirmation, or an Invoice/PaymentSchedule (if the payment succeeded) * @see app/controllers/api/stripe_controller.rb#confirm_payment */ - const handleServerConfirmation = async (response: PaymentConfirmation|Invoice) => { + const handleServerConfirmation = async (response: PaymentConfirmation|Invoice|PaymentSchedule) => { if ('error' in response) { if (response.error.statusText) { onError(response.error.statusText); @@ -102,8 +75,14 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on // The card action has been handled // The PaymentIntent can be confirmed again on the server try { - const confirmation = await StripeAPI.confirmIntent(result.paymentIntent.id, cart); - await handleServerConfirmation(confirmation); + if (response.type === 'payment') { + const confirmation = await StripeAPI.confirmIntent(result.paymentIntent.id, cart); + await handleServerConfirmation(confirmation); + } + if (response.type === 'subscription') { + const confirmation = await StripeAPI.confirmSubscription(response.subscription_id, cart); + await handleServerConfirmation(confirmation); + } } catch (e) { onError(e); } diff --git a/app/frontend/src/javascript/models/payment.ts b/app/frontend/src/javascript/models/payment.ts index 3af792a35..f4580a79a 100644 --- a/app/frontend/src/javascript/models/payment.ts +++ b/app/frontend/src/javascript/models/payment.ts @@ -4,6 +4,8 @@ import { SubscriptionRequest } from './subscription'; export interface PaymentConfirmation { requires_action?: boolean, payment_intent_client_secret?: string, + type?: 'payment' | 'subscription', + subscription_id?: string, success?: boolean, error?: { statusText: string @@ -34,14 +36,3 @@ export interface UpdateCardResponse { updated: boolean, error?: string } - -export interface StripeSubscription { - id: string, - status: string, - latest_invoice: { - payment_intent: { - status: string, - client_secret: string - } - } -} diff --git a/app/frontend/src/javascript/models/stripe.ts b/app/frontend/src/javascript/models/stripe.ts index 06ee4a0ce..05766c7d7 100644 --- a/app/frontend/src/javascript/models/stripe.ts +++ b/app/frontend/src/javascript/models/stripe.ts @@ -1,3 +1,6 @@ +import { PaymentIntent } from '@stripe/stripe-js'; + +// https://stripe.com/docs/api/tokens/object export interface PIIToken { id: string, object: 'token', @@ -8,6 +11,7 @@ export interface PIIToken { used: boolean } +// https://stripe.com/docs/api/charges/object export interface Charge { id: string, object: 'charge', @@ -50,3 +54,118 @@ export interface ListCharges { has_more: boolean, data: Array } + +// https://stripe.com/docs/api/prices/object +export interface Price { + id: string, + object: 'price', + active: boolean, + billing_scheme: 'per_unit' | 'tiered', + created: Date, + currency: string, + livemode: boolean, + lookup_key: string, + metadata: Record, + nickname: string, + product: string, + recurring: { + aggregate_usage: 'sum' | 'last_during_period' | 'last_ever' | 'max', + interval: 'day' | 'week' | 'month' | 'year', + interval_count: number, + usage_type: 'metered' | 'licensed' + }, + tax_behavior: 'inclusive' | 'exclusive' | 'unspecified', + tiers: [ + { + flat_amount: number, + flat_amount_decimal: string, + unit_amount: number, + unit_amount_decimal: string, + up_to: number + } + ], + tiers_mode: 'graduated' | 'volume', + transform_quantity: { + divide_by: number, + round: 'up' | 'down' + }, + type: 'one_time' | 'recurring' + unit_amount: number, + unit_amount_decimal: string + +} + +// https://stripe.com/docs/api/tax_rates/object +export interface TaxRate { + id: string, + object: 'tax_rate', + active: boolean, + country: string, + description: string, + display_name: string, + inclusive: boolean, + jurisdiction: string, + metadata: Record, + percentage: number, + state: string, + created: Date, + livemode: boolean, + tax_type: 'vat' | 'sales_tax' | string +} + +// https://stripe.com/docs/api/subscription_items/object +export interface SubscriptionItem { + id: string, + object: 'subscription_item', + billing_thresholds: { + usage_gte: number, + }, + created: Date, + metadata: Record, + price: Price, + quantity: number, + subscription: string; + tax_rates: Array +} + +// https://stripe.com/docs/api/invoices/object +export interface Invoice { + id: string, + object: 'invoice', + auto_advance: boolean, + charge: string, + collection_method: 'charge_automatically' | 'send_invoice', + currency: string, + customer: string, + description: string, + hosted_invoice_url: string, + lines: [], + metadata: Record, + payment_intent: PaymentIntent, + period_end: Date, + period_start: Date, + status: 'draft' | 'open' | 'paid' | 'uncollectible' | 'void', + subscription: string, + total: number +} + +// https://stripe.com/docs/api/subscriptions/object +export interface Subscription { + id: string, + object: 'subscription', + cancel_at_period_end: boolean, + current_period_end: Date, + current_period_start: Date, + customer: string, + default_payment_method: string, + items: [ + { + object: 'list', + data: Array, + has_more: boolean, + url: string + } + ] + status: 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid', + latest_invoice: Invoice +} diff --git a/app/models/payment_schedule.rb b/app/models/payment_schedule.rb index c3edf9758..5d8fdb549 100644 --- a/app/models/payment_schedule.rb +++ b/app/models/payment_schedule.rb @@ -81,10 +81,6 @@ class PaymentSchedule < PaymentDocument PaymentGatewayService.new.create_subscription(self, gateway_method_id) end - def pay(gateway_method_id) - PaymentGatewayService.new.pay_subscription(self, gateway_method_id) - end - def render_resource { partial: 'api/payment_schedules/payment_schedule', locals: { payment_schedule: self } } end diff --git a/app/models/shopping_cart.rb b/app/models/shopping_cart.rb index 60d4f09bb..0a90a7161 100644 --- a/app/models/shopping_cart.rb +++ b/app/models/shopping_cart.rb @@ -69,21 +69,6 @@ class ShoppingCart { success: success, payment: payment, errors: errors } end - def pay_schedule(payment_id, payment_type) - price = total - objects = [] - items.each do |item| - raise InvalidSubscriptionError unless item.valid?(@items) - - object = item.to_object - objects.push(object) - raise InvalidSubscriptionError unless object.errors.empty? - end - payment = create_payment_document(price, objects, payment_id, payment_type) - WalletService.debit_user_wallet(payment, @customer, transaction: false) - payment.pay(payment_id) - end - private # Save the object associated with the provided item or raise and Rollback if something wrong append. diff --git a/app/services/payment_gateway_service.rb b/app/services/payment_gateway_service.rb index ef98896e5..b1ec6fb46 100644 --- a/app/services/payment_gateway_service.rb +++ b/app/services/payment_gateway_service.rb @@ -23,10 +23,6 @@ class PaymentGatewayService @gateway.create_subscription(payment_schedule, gateway_object_id) end - def pay_subscription(payment_schedule, gateway_object_id) - @gateway.pay_subscription(payment_schedule, gateway_object_id) - end - def create_user(user_id) @gateway.create_user(user_id) end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 362a7d239..73f2b31ee 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -94,6 +94,7 @@ class WalletService ## # Subtract the amount of the payment document (Invoice|PaymentSchedule) from the customer's wallet + # @param transaction, if false: the wallet is not debited, the transaction is only simulated on the payment document ## def self.debit_user_wallet(payment, user, transaction: true) wallet_amount = WalletService.wallet_amount_debit(payment, user) diff --git a/config/routes.rb b/config/routes.rb index c05b7ce1c..7fa9c69b0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -180,10 +180,10 @@ Rails.application.routes.draw do # card payments handling ## Stripe gateway post 'stripe/confirm_payment' => 'stripe/confirm_payment' - post 'stripe/create_subscription' => 'stripe/create_subscription' get 'stripe/online_payment_status' => 'stripe/online_payment_status' get 'stripe/setup_intent/:user_id' => 'stripe#setup_intent' - post 'stripe/confirm_payment_schedule' => 'stripe#confirm_payment_schedule' + post 'stripe/create_subscription' => 'stripe/create_subscription' + post 'stripe/confirm_subscription' => 'stripe#confirm_subscription' post 'stripe/update_card' => 'stripe#update_card' ## PayZen gateway diff --git a/lib/stripe/service.rb b/lib/stripe/service.rb index 1927f4f94..bb94db78f 100644 --- a/lib/stripe/service.rb +++ b/lib/stripe/service.rb @@ -8,33 +8,16 @@ module Stripe; end ## create remote objects on stripe class Stripe::Service < Payment::Service # Create the provided PaymentSchedule on Stripe, using the Subscription API - def create_subscription(payment_schedule, subscription_id) - stripe_key = Setting.get('stripe_secret_key') + def subscribe(payment_method_id, shopping_cart) + price_details = shopping_cart.total - handle_wallet_transaction(payment_schedule) - - stp_subscription = Stripe::Subscription.retrieve(subscription_id, api_key: stripe_key) - pgo = PaymentGatewayObject.new(item: payment_schedule) - pgo.gateway_object = stp_subscription - pgo.save! - end - - def pay_subscription(payment_schedule, payment_method_id) - stripe_key = Setting.get('stripe_secret_key') - first_item = payment_schedule.payment_schedule_items.min_by(&:due_date) - - main_object = payment_schedule.payment_schedule_objects.find(&:main) - case main_object.object_type - when Reservation.name - subscription = payment_schedule.payment_schedule_objects.find { |pso| pso.object_type == Subscription.name }.object - reservable_stp_id = main_object.object.reservable&.payment_gateway_object&.gateway_object_id - when Subscription.name - subscription = main_object.object - reservable_stp_id = nil - else - raise InvalidSubscriptionError - end + payment_schedule = price_details[:schedule][:payment_schedule] + first_item = price_details[:schedule][:items].min_by(&:due_date) + subscription = shopping_cart.items.find { |item| item.class == CartItem::Subscription } + reservable_stp_id = shopping_cart.items.find { |item| item.is_a?(CartItem::Reservation) }.to_object + .reservable&.payment_gateway_object&.gateway_object_id + WalletService.debit_user_wallet(payment_schedule, payment_schedule.invoicing_profile.user, transaction: false) handle_wallet_transaction(payment_schedule) price = create_price(first_item.details['recurring'], @@ -44,16 +27,27 @@ class Stripe::Service < Payment::Service items = subscription_invoice_items(payment_schedule, subscription, first_item, reservable_stp_id) Stripe::Subscription.create({ - customer: payment_schedule.invoicing_profile.user.payment_gateway_object.gateway_object_id, - cancel_at: (payment_schedule.payment_schedule_items.max_by(&:due_date).due_date + 1.month).to_i, - add_invoice_items: items, - coupon: payment_schedule.coupon&.code, - items: [ - { price: price[:id] } - ], - default_payment_method: payment_method_id, - expand: %w[latest_invoice.payment_intent] - }, { api_key: stripe_key }) + customer: payment_schedule.invoicing_profile.user.payment_gateway_object.gateway_object_id, + cancel_at: (payment_schedule.payment_schedule_items.max_by(&:due_date).due_date + 1.month).to_i, + add_invoice_items: items, + coupon: payment_schedule.coupon&.code, + items: [ + { price: price[:id] } + ], + default_payment_method: payment_method_id, + expand: %w[latest_invoice.payment_intent] + }, { api_key: stripe_key }) + end + + def create_subscription(payment_schedule, subscription_id) + stripe_key = Setting.get('stripe_secret_key') + + handle_wallet_transaction(payment_schedule) + + stp_subscription = Stripe::Subscription.retrieve(subscription_id, api_key: stripe_key) + pgo = PaymentGatewayObject.new(item: payment_schedule) + pgo.gateway_object = stp_subscription + pgo.save! end def create_user(user_id) @@ -146,19 +140,21 @@ class Stripe::Service < Payment::Service end def attach_method_as_default(payment_method_id, customer_id) - Stripe.api_key = Setting.get('stripe_secret_key') + stripe_key = Setting.get('stripe_secret_key') # attach the payment method to the given customer - intent = Stripe::PaymentMethod.attach( + method = Stripe::PaymentMethod.attach( payment_method_id, - customer: customer_id + { customer: customer_id }, + { api_key: stripe_key } ) # then set it as the default payment method for this customer Stripe::Customer.update( - cart.customer.payment_gateway_object.gateway_object_id, - invoice_settings: { default_payment_method: params[:payment_method_id] } + customer_id, + { invoice_settings: { default_payment_method: payment_method_id } }, + { api_key: stripe_key } ) - intent + method end private From 564b63181c53c2c1aedf523fa854ebb890b56a8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Oct 2021 23:15:31 +0000 Subject: [PATCH 042/142] Bump sidekiq from 6.0.7 to 6.2.1 Bumps [sidekiq](https://github.com/mperham/sidekiq) from 6.0.7 to 6.2.1. - [Release notes](https://github.com/mperham/sidekiq/releases) - [Changelog](https://github.com/mperham/sidekiq/blob/main/Changes.md) - [Commits](https://github.com/mperham/sidekiq/compare/v6.0.7...v6.2.1) --- updated-dependencies: - dependency-name: sidekiq dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 731af7df2..493c901d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,7 +89,7 @@ GEM coercible (1.0.0) descendants_tracker (~> 0.0.1) concurrent-ruby (1.1.8) - connection_pool (2.2.3) + connection_pool (2.2.5) coveralls_reborn (0.18.0) simplecov (>= 0.18.1, < 0.20.0) term-ansicolor (~> 1.6) @@ -271,8 +271,6 @@ GEM raabro (1.1.6) racc (1.5.2) rack (2.2.3) - rack-protection (2.0.8.1) - rack rack-proxy (0.6.5) rack rack-test (1.1.0) @@ -318,7 +316,7 @@ GEM recurrence (1.3.0) activesupport i18n - redis (4.1.4) + redis (4.4.0) repost (0.3.2) responders (2.4.1) actionpack (>= 4.2.0, < 6.0) @@ -348,11 +346,10 @@ GEM activesupport (>= 4) semantic_range (2.3.0) sha3 (1.0.1) - sidekiq (6.0.7) + sidekiq (6.2.1) connection_pool (>= 2.2.2) rack (~> 2.0) - rack-protection (>= 2.0.0) - redis (>= 4.1.0) + redis (>= 4.2.0) sidekiq-cron (1.1.0) fugit (~> 1.1) sidekiq (>= 4.2.1) From a3f680964c5407846299b9cc01c3bede04576114 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 7 Oct 2021 16:43:51 +0200 Subject: [PATCH 043/142] handle stripe errors while local payments --- app/frontend/src/javascript/api/stripe.ts | 4 +- .../payment/abstract-payment-modal.tsx | 20 ++++++--- .../local-payment/local-payment-modal.tsx | 10 +++-- .../components/payment/payment-modal.tsx | 2 + .../payment/payzen/payzen-modal.tsx | 4 +- .../components/payment/stripe/stripe-form.tsx | 41 ++++++++++++------- .../payment/stripe/stripe-modal.tsx | 4 +- .../prepaid-packs/propose-packs-modal.tsx | 1 + .../src/javascript/directives/cart.js | 8 ++++ app/frontend/templates/shared/_cart.html | 1 + 10 files changed, 67 insertions(+), 28 deletions(-) diff --git a/app/frontend/src/javascript/api/stripe.ts b/app/frontend/src/javascript/api/stripe.ts index b409019ed..e51b1c738 100644 --- a/app/frontend/src/javascript/api/stripe.ts +++ b/app/frontend/src/javascript/api/stripe.ts @@ -21,8 +21,8 @@ export default class StripeAPI { return res?.data; } - static async createSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise { - const res: AxiosResponse = await apiClient.post('/api/stripe/create_subscription', { + static async setupSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise { + const res: AxiosResponse = await apiClient.post('/api/stripe/setup_subscription', { payment_method_id: paymentMethodId, cart_items: cartItems }); diff --git a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx index 35b7199a0..fae7815e7 100644 --- a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent, ReactNode, useEffect, useState } from 'react'; +import React, { FunctionComponent, ReactNode, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import WalletLib from '../../lib/wallet'; import { WalletInfo } from '../wallet-info'; @@ -34,6 +34,7 @@ interface AbstractPaymentModalProps { isOpen: boolean, toggleModal: () => void, afterSuccess: (result: Invoice|PaymentSchedule) => void, + onError: (message: string) => void, cart: ShoppingCart, currentUser: User, schedule?: PaymentSchedule, @@ -55,7 +56,7 @@ interface AbstractPaymentModalProps { * This component must not be called directly but must be extended for each implemented payment gateway * @see https://reactjs.org/docs/composition-vs-inheritance.html */ -export const AbstractPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, cart, currentUser, schedule, customer, logoFooter, GatewayForm, formId, className, formClassName, title, preventCgv, preventScheduleInfo, modalSize }) => { +export const AbstractPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer, logoFooter, GatewayForm, formId, className, formClassName, title, preventCgv, preventScheduleInfo, modalSize }) => { // customer's wallet const [wallet, setWallet] = useState(null); // server-computed price with all details @@ -74,6 +75,8 @@ export const AbstractPaymentModal: React.FC = ({ isOp const [gateway, setGateway] = useState(null); // the sales conditions const [cgv, setCgv] = useState(null); + // is the component mounted + const mounted = useRef(false); const { t } = useTranslation('shared'); @@ -81,11 +84,14 @@ export const AbstractPaymentModal: React.FC = ({ isOp * When the component loads first, get the name of the currently active payment modal */ useEffect(() => { + mounted.current = true; CustomAssetAPI.get(CustomAssetName.CgvFile).then(asset => setCgv(asset)); SettingAPI.get(SettingName.PaymentGateway).then((setting) => { // we capitalize the first letter of the name setGateway(setting.value.replace(/^\w/, (c) => c.toUpperCase())); }); + + return () => { mounted.current = false; }; }, []); /** @@ -153,8 +159,12 @@ export const AbstractPaymentModal: React.FC = ({ isOp * When the payment form raises an error, it is handled by this callback which display it in the modal. */ const handleFormError = (message: string): void => { - setSubmitState(false); - setErrors(message); + if (mounted.current) { + setSubmitState(false); + setErrors(message); + } else { + onError(message); + } }; /** @@ -201,7 +211,7 @@ export const AbstractPaymentModal: React.FC = ({ isOp {errors} } {hasPaymentScheduleInfo() &&
- +
} {hasCgv() &&
diff --git a/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx b/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx index 069d0668b..939d1792f 100644 --- a/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx @@ -17,6 +17,7 @@ interface LocalPaymentModalProps { isOpen: boolean, toggleModal: () => void, afterSuccess: (result: Invoice|PaymentSchedule) => void, + onError: (message: string) => void, cart: ShoppingCart, currentUser: User, schedule?: PaymentSchedule, @@ -26,7 +27,7 @@ interface LocalPaymentModalProps { /** * This component enables a privileged user to confirm a local payments. */ -const LocalPaymentModalComponent: React.FC = ({ isOpen, toggleModal, afterSuccess, cart, currentUser, schedule, customer }) => { +const LocalPaymentModalComponent: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer }) => { const { t } = useTranslation('admin'); /** @@ -71,6 +72,7 @@ const LocalPaymentModalComponent: React.FC = ({ isOpen, cart={cart} customer={customer} afterSuccess={afterSuccess} + onError={onError} schedule={schedule} GatewayForm={renderForm} modalSize={schedule ? ModalSize.large : ModalSize.medium} @@ -79,12 +81,12 @@ const LocalPaymentModalComponent: React.FC = ({ isOpen, ); }; -export const LocalPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, currentUser, schedule, cart, customer }) => { +export const LocalPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer }) => { return ( - + ); }; -Application.Components.component('localPaymentModal', react2angular(LocalPaymentModal, ['isOpen', 'toggleModal', 'afterSuccess', 'currentUser', 'schedule', 'cart', 'customer'])); +Application.Components.component('localPaymentModal', react2angular(LocalPaymentModal, ['isOpen', 'toggleModal', 'afterSuccess', 'onError', 'currentUser', 'schedule', 'cart', 'customer'])); diff --git a/app/frontend/src/javascript/components/payment/payment-modal.tsx b/app/frontend/src/javascript/components/payment/payment-modal.tsx index a48f8a454..6ad9b52fb 100644 --- a/app/frontend/src/javascript/components/payment/payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/payment-modal.tsx @@ -47,6 +47,7 @@ const PaymentModalComponent: React.FC = ({ isOpen, toggleModa return = ({ isOpen, toggleModa return void, afterSuccess: (result: Invoice|PaymentSchedule) => void, + onError: (message: string) => void, cart: ShoppingCart, currentUser: User, schedule?: PaymentSchedule, @@ -27,7 +28,7 @@ interface PayZenModalProps { * This component should not be called directly. Prefer using which can handle the configuration * of a different payment gateway. */ -export const PayZenModal: React.FC = ({ isOpen, toggleModal, afterSuccess, cart, currentUser, schedule, customer }) => { +export const PayZenModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer }) => { /** * Return the logos, shown in the modal footer. */ @@ -71,6 +72,7 @@ export const PayZenModal: React.FC = ({ isOpen, toggleModal, a cart={cart} customer={customer} afterSuccess={afterSuccess} + onError={onError} schedule={schedule} GatewayForm={renderForm} /> ); diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx index 0c9ea6eff..3d017fb95 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx @@ -44,8 +44,8 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on const res = await StripeAPI.confirmMethod(paymentMethod.id, cart); await handleServerConfirmation(res); } else { - const res = await StripeAPI.createSubscription(paymentMethod.id, cart); - await handleServerConfirmation(res); + const res = await StripeAPI.setupSubscription(paymentMethod.id, cart); + await handleServerConfirmation(res, paymentMethod.id); } } catch (err) { // catch api errors @@ -57,9 +57,10 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on /** * Process the server response about the Strong-customer authentication (SCA) * @param response can be a PaymentConfirmation, or an Invoice/PaymentSchedule (if the payment succeeded) + * @param paymentMethodId ID of the payment method, required only when confirming a payment schedule * @see app/controllers/api/stripe_controller.rb#confirm_payment */ - const handleServerConfirmation = async (response: PaymentConfirmation|Invoice|PaymentSchedule) => { + const handleServerConfirmation = async (response: PaymentConfirmation|Invoice|PaymentSchedule, paymentMethodId?: string) => { if ('error' in response) { if (response.error.statusText) { onError(response.error.statusText); @@ -67,24 +68,34 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on onError(`${t('app.shared.messages.payment_card_error')} ${response.error}`); } } else if ('requires_action' in response) { - // Use Stripe.js to handle required card action - const result = await stripe.handleCardAction(response.payment_intent_client_secret); - if (result.error) { - onError(result.error.message); - } else { - // The card action has been handled - // The PaymentIntent can be confirmed again on the server - try { - if (response.type === 'payment') { + if (response.type === 'payment') { + // Use Stripe.js to handle required card action + const result = await stripe.handleCardAction(response.payment_intent_client_secret); + if (result.error) { + onError(result.error.message); + } else { + // The card action has been handled + // The PaymentIntent can be confirmed again on the server + try { const confirmation = await StripeAPI.confirmIntent(result.paymentIntent.id, cart); await handleServerConfirmation(confirmation); + } catch (e) { + onError(e); } - if (response.type === 'subscription') { + } + } else if (response.type === 'subscription') { + const result = await stripe.confirmCardPayment(response.payment_intent_client_secret, { + payment_method: paymentMethodId + }); + if (result.error) { + onError(result.error.message); + } else { + try { const confirmation = await StripeAPI.confirmSubscription(response.subscription_id, cart); await handleServerConfirmation(confirmation); + } catch (e) { + onError(e); } - } catch (e) { - onError(e); } } } else if ('id' in response) { diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx index 3e62a26af..96880b7ee 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx @@ -15,6 +15,7 @@ interface StripeModalProps { isOpen: boolean, toggleModal: () => void, afterSuccess: (result: Invoice|PaymentSchedule) => void, + onError: (message: string) => void, cart: ShoppingCart, currentUser: User, schedule?: PaymentSchedule, @@ -28,7 +29,7 @@ interface StripeModalProps { * This component should not be called directly. Prefer using which can handle the configuration * of a different payment gateway. */ -export const StripeModal: React.FC = ({ isOpen, toggleModal, afterSuccess, cart, currentUser, schedule, customer }) => { +export const StripeModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer }) => { /** * Return the logos, shown in the modal footer. */ @@ -75,6 +76,7 @@ export const StripeModal: React.FC = ({ isOpen, toggleModal, a cart={cart} customer={customer} afterSuccess={afterSuccess} + onError={onError} schedule={schedule} GatewayForm={renderForm} /> ); diff --git a/app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx b/app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx index 15b18b67d..bdd90ec6b 100644 --- a/app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx +++ b/app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx @@ -162,6 +162,7 @@ export const ProposePacksModal: React.FC = ({ isOpen, to diff --git a/app/frontend/src/javascript/directives/cart.js b/app/frontend/src/javascript/directives/cart.js index 3a69039d9..85cced6b2 100644 --- a/app/frontend/src/javascript/directives/cart.js +++ b/app/frontend/src/javascript/directives/cart.js @@ -362,6 +362,14 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', afterPayment(invoice); }; + /** + * Invoked when something wrong occurred after the payment dialog has been closed + * @param message {string} + */ + $scope.onLocalPaymentError = (message) => { + growl.error(message); + }; + /** * Invoked when something wrong occurred during the payment dialog initialization * @param message {string} diff --git a/app/frontend/templates/shared/_cart.html b/app/frontend/templates/shared/_cart.html index 93ad2aa57..e3df05503 100644 --- a/app/frontend/templates/shared/_cart.html +++ b/app/frontend/templates/shared/_cart.html @@ -214,6 +214,7 @@ Date: Thu, 7 Oct 2021 17:07:46 +0200 Subject: [PATCH 044/142] fix some errors about stp subscription refacto + improved error handling --- app/controllers/api/payments_controller.rb | 2 +- app/controllers/api/stripe_controller.rb | 13 ++++++++----- app/models/shopping_cart.rb | 3 ++- config/routes.rb | 2 +- lib/stripe/service.rb | 14 ++++++++------ 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/payments_controller.rb b/app/controllers/api/payments_controller.rb index 06e49ed47..ec3b2faa4 100644 --- a/app/controllers/api/payments_controller.rb +++ b/app/controllers/api/payments_controller.rb @@ -39,7 +39,7 @@ class API::PaymentsController < API::ApiController post_save(gateway_item_id, gateway_item_type, res[:payment]) res[:payment].render_resource.merge(status: :created) else - { json: res[:errors], status: :unprocessable_entity } + { json: res[:errors].drop_while(&:empty?), status: :unprocessable_entity } end end end diff --git a/app/controllers/api/stripe_controller.rb b/app/controllers/api/stripe_controller.rb index 7ef820ccf..c46f20e6d 100644 --- a/app/controllers/api/stripe_controller.rb +++ b/app/controllers/api/stripe_controller.rb @@ -69,10 +69,10 @@ class API::StripeController < API::PaymentsController render json: { id: @intent.id, client_secret: @intent.client_secret } end - def create_subscription + def setup_subscription cart = shopping_cart cart.items.each do |item| - raise InvalidSubscriptionError unless item.valid?(@items) + raise InvalidSubscriptionError unless item.valid?(cart.items) raise InvalidSubscriptionError unless item.to_object.errors.empty? end @@ -90,12 +90,15 @@ class API::StripeController < API::PaymentsController def confirm_subscription key = Setting.get('stripe_secret_key') - subscription = Stripe::Subscription.retrieve(params[:subscription_id], api_key: key) + subscription = Stripe::Subscription.retrieve( + { id: params[:subscription_id], expand: %w[latest_invoice.payment_intent] }, + { api_key: key } + ) cart = shopping_cart if subscription&.status == 'active' - res = on_payment_success(subscription, cart) - render generate_payment_response(subscription, res) + res = on_payment_success(subscription.latest_invoice.payment_intent, cart) + render generate_payment_response(subscription.latest_invoice.payment_intent, 'subscription', res) end rescue Stripe::InvalidRequestError => e render json: e, status: :unprocessable_entity diff --git a/app/models/shopping_cart.rb b/app/models/shopping_cart.rb index 0a90a7161..f586d3708 100644 --- a/app/models/shopping_cart.rb +++ b/app/models/shopping_cart.rb @@ -64,8 +64,9 @@ class ShoppingCart payment.post_save(payment_id) end - success = objects.map(&:errors).flatten.map(&:empty?).all? && items.map(&:errors).map(&:empty?).all? + success = !payment.nil? && objects.map(&:errors).flatten.map(&:empty?).all? && items.map(&:errors).map(&:empty?).all? errors = objects.map(&:errors).flatten.concat(items.map(&:errors)) + errors.push('Unable to create the PaymentDocument') if payment.nil? { success: success, payment: payment, errors: errors } end diff --git a/config/routes.rb b/config/routes.rb index 7fa9c69b0..fe1b8a66e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -182,7 +182,7 @@ Rails.application.routes.draw do post 'stripe/confirm_payment' => 'stripe/confirm_payment' get 'stripe/online_payment_status' => 'stripe/online_payment_status' get 'stripe/setup_intent/:user_id' => 'stripe#setup_intent' - post 'stripe/create_subscription' => 'stripe/create_subscription' + post 'stripe/setup_subscription' => 'stripe/setup_subscription' post 'stripe/confirm_subscription' => 'stripe#confirm_subscription' post 'stripe/update_card' => 'stripe#update_card' diff --git a/lib/stripe/service.rb b/lib/stripe/service.rb index bb94db78f..05a2dab67 100644 --- a/lib/stripe/service.rb +++ b/lib/stripe/service.rb @@ -12,12 +12,13 @@ class Stripe::Service < Payment::Service price_details = shopping_cart.total payment_schedule = price_details[:schedule][:payment_schedule] + payment_schedule.payment_schedule_items = price_details[:schedule][:items] first_item = price_details[:schedule][:items].min_by(&:due_date) subscription = shopping_cart.items.find { |item| item.class == CartItem::Subscription } reservable_stp_id = shopping_cart.items.find { |item| item.is_a?(CartItem::Reservation) }.to_object .reservable&.payment_gateway_object&.gateway_object_id - WalletService.debit_user_wallet(payment_schedule, payment_schedule.invoicing_profile.user, transaction: false) + WalletService.debit_user_wallet(payment_schedule, shopping_cart.customer, transaction: false) handle_wallet_transaction(payment_schedule) price = create_price(first_item.details['recurring'], @@ -26,8 +27,10 @@ class Stripe::Service < Payment::Service # other items (not recurring) items = subscription_invoice_items(payment_schedule, subscription, first_item, reservable_stp_id) + + stripe_key = Setting.get('stripe_secret_key') Stripe::Subscription.create({ - customer: payment_schedule.invoicing_profile.user.payment_gateway_object.gateway_object_id, + customer: shopping_cart.customer.payment_gateway_object.gateway_object_id, cancel_at: (payment_schedule.payment_schedule_items.max_by(&:due_date).due_date + 1.month).to_i, add_invoice_items: items, coupon: payment_schedule.coupon&.code, @@ -39,12 +42,11 @@ class Stripe::Service < Payment::Service }, { api_key: stripe_key }) end - def create_subscription(payment_schedule, subscription_id) + def create_subscription(payment_schedule, payment_intent_id) stripe_key = Setting.get('stripe_secret_key') - handle_wallet_transaction(payment_schedule) - - stp_subscription = Stripe::Subscription.retrieve(subscription_id, api_key: stripe_key) + pi = Stripe::PaymentIntent.retrieve({ id: payment_intent_id, expand: %w[invoice] }, { api_key: stripe_key }) + stp_subscription = Stripe::Subscription.retrieve(pi.invoice.subscription, api_key: stripe_key) pgo = PaymentGatewayObject.new(item: payment_schedule) pgo.gateway_object = stp_subscription pgo.save! From de7c0217164414aefe1d43bf603e7a4959907173 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 7 Oct 2021 17:41:38 +0200 Subject: [PATCH 045/142] updated production doc --- CHANGELOG.md | 2 ++ doc/production_readme.md | 44 +++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90d131c87..061dcbcea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog Fab-manager +- Updated production documentation +- Improved stripe subscription process with better error handling - The upgrade script will check and report the ability to access the hub API - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to diff --git a/doc/production_readme.md b/doc/production_readme.md index 741453936..180b14e85 100644 --- a/doc/production_readme.md +++ b/doc/production_readme.md @@ -13,7 +13,7 @@ You will need to be root through the rest of the setup. 1.3. [Connect through SSH](#connect-through-ssh)
1.4. [Prepare the server](#prepare-the-server)
2. [Install Fab-manager](#install-fab-manager)
-3. [Docker utils](#docker-utils) +3. [Useful commands](#useful-commands) 4. [Update Fab-manager](#update-fab-manager)
4.1. [Scripted update](#scripted-update)
4.2. [Update manually](#update-manually)
@@ -29,26 +29,25 @@ You will need to be root through the rest of the setup. ### Setup the server -There are many hosting providers on the internet, providing affordable virtual private serveurs (VPS). -Here's a non exhaustive list: -- [DigitalOcean](https://www.digitalocean.com/pricing/#droplet) -- [OVH](https://www.ovh.com/fr/vps/) -- [Amazon](https://aws.amazon.com/fr/ec2/) -- [Gandi](https://v4.gandi.net/hebergement/serveur/prix) -- [Ikoula](https://express.ikoula.com/fr/serveur-virtuel) -- [1&1](https://www.1and1.fr/serveurs-virtuels) -- [GoDaddy](https://fr.godaddy.com/hosting/vps-hosting) -- [and many others...](https://www.google.fr/search?q=vps+hosting) - +There are [many hosting providers](https://duckduckgo.com/?q=vps+hosting) on the internet, providing affordable virtual private serveurs (VPS). Choose one, depending on your budget, on the server's location, on the uptime guarantee, etc. -You will need at least 2GB of addressable memory (RAM + swap) to install and use Fab-manager. -We recommend 4 GB RAM for larger communities. +#### System requirements +##### Memory + +If you do not plan to use the statistics module, you will need at least 2 GB of addressable memory (RAM + swap) to install and use Fab-manager. +We recommend 4 GB of RAM to take full advantage of Fab-manager and be able to use the statistics module. +If you have a large community (~ 200 active membres), we recommend 4 GB of RAM, even without the statistics module. + +During the installation and the upgrades, the assets' compilation phase may fail if you do not have sufficient available memory. + +##### CPU and Operating system Supported operating systems are Ubuntu LTS 16.04+ and Debian 8+ with an x86 64-bits architecture. This might work on other linux systems, and CPU architectures but this is untested for now, and we do not recommend for production purposes. -Choose one and install docker on it: +#### Software requirements +First, you need to install docker: - Install [Docker on Debian](https://docs.docker.com/engine/installation/linux/docker-ce/debian/) - Install [Docker on Ubuntu](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/) @@ -57,8 +56,7 @@ Then install [Docker Compose](https://docs.docker.com/compose/install/) ### Set up the domain name -There are many domain name registrars on the internet, you may choose one that fit your needs. -You can find an exhaustive list [on the ICANN website](https://www.icann.org/registrar-reports/accredited-list.html) +There are [many domain name registrars](https://duckduckgo.com/?q=register+domain+name) on the internet, choose one that fit your needs. 1. Once done, buy a domain name on it 2. Replace the IP address of the domain with the IP address of your VPS (This is a DNS record of **type A**) @@ -113,8 +111,8 @@ docker-compose down && docker-compose up -d Disabling ElasticSearch will save up to 800 Mb of memory. - -## Docker utils + +## Useful commands Below, you'll find a collection of useful commands to control your instance with docker-compose. Before using any of these commands, you must first `cd` into the app directory. @@ -122,15 +120,19 @@ Before using any of these commands, you must first `cd` into the app directory. ```bash docker-compose down && docker-compose up -d ``` -- Open a bash prompt in the app context +- Open a bash prompt inside the app container ```bash docker-compose exec fabmanager bash ``` +- Open the ruby console in the application +```bash +\curl -sSL run.fab.mn | bash +``` - Show services status ```bash docker-compose ps ``` -- Example of command passing env variables +- Run a command and provide it environment variables ```bash docker-compose run --rm -e VAR1=xxx -e VAR2=xxx fabmanager bundle exec rails my:command ``` From e646eb8cb583f5a1643d29db7a8cc9884a67daa0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 8 Oct 2021 19:14:47 +0200 Subject: [PATCH 046/142] extend subscription UI --- .../api/subscriptions_controller.rb | 6 ++- .../javascript/controllers/admin/members.js | 44 ++++++++++++++++++- .../src/javascript/services/subscription.js | 4 ++ .../templates/admin/members/edit.html | 2 +- .../admin/subscriptions/expired_at_modal.html | 29 +++++++++--- app/policies/subscription_policy.rb | 4 ++ .../payment_details.json.jbuilder | 4 ++ config/locales/app.admin.en.yml | 18 +++++--- config/routes.rb | 4 +- 9 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 app/views/api/subscriptions/payment_details.json.jbuilder diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb index bca08d5e5..a8217c6b6 100644 --- a/app/controllers/api/subscriptions_controller.rb +++ b/app/controllers/api/subscriptions_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Subscription class API::SubscriptionsController < API::ApiController - before_action :set_subscription, only: %i[show edit update destroy] + before_action :set_subscription, only: %i[show payment_details edit update destroy] before_action :authenticate_user! def show @@ -26,6 +26,10 @@ class API::SubscriptionsController < API::ApiController end end + def payment_details + authorize @subscription + end + private # Use callbacks to share common setup or constraints between actions. diff --git a/app/frontend/src/javascript/controllers/admin/members.js b/app/frontend/src/javascript/controllers/admin/members.js index 1ad5f24b4..7a37fb3c3 100644 --- a/app/frontend/src/javascript/controllers/admin/members.js +++ b/app/frontend/src/javascript/controllers/admin/members.js @@ -762,9 +762,19 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', animation: true, templateUrl: '/admin/subscriptions/expired_at_modal.html', size: 'lg', - controller: ['$scope', '$uibModalInstance', 'Subscription', function ($scope, $uibModalInstance, Subscription) { - $scope.new_expired_at = angular.copy(subscription.expired_at); + resolve: { + paymentDetails () { + return Subscription.payment_details({ id: subscription.id }).$promise; + } + }, + controller: ['$scope', '$uibModalInstance', 'Subscription', 'paymentDetails', function ($scope, $uibModalInstance, Subscription, paymentDetails) { + /* PUBLIC SCOPE */ + + $scope.expire_at = subscription.expired_at; + $scope.new_expired_at = new Date(subscription.expired_at); $scope.free = free; + $scope.days = 0; + $scope.payment_details = paymentDetails; $scope.datePicker = { opened: false, format: Fablab.uibDateFormat, @@ -780,6 +790,11 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', return $scope.datePicker.opened = true; }; + $scope.$watch(scope => scope.expire_at + , () => refreshDays()); + $scope.$watch(scope => scope.new_expired_at + , () => refreshDays()); + $scope.ok = function () { Subscription.update( { id: subscription.id }, @@ -796,6 +811,31 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', }; $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); }; + + /* PRIVATE SCOPE */ + + /** + * Kind of constructor: these actions will be realized first when the controller is loaded + */ + function initialize () { + if (!free) { + $scope.new_expired_at = moment($scope.expire_at).add(subscription.plan.interval_count, subscription.plan.interval).toDate(); + } + } + + /** + * Refresh the number of free days depending on the original subscription expiration date and on the new selected date + */ + function refreshDays () { + if (!$scope.new_expired_at || !$scope.expire_at) { + return $scope.days = 0; + } + // 86400000 = 1000 * 3600 * 24 = number of ms per day + $scope.days = Math.round((new Date($scope.new_expired_at).getTime() - new Date($scope.expire_at).getTime()) / 86400000); + } + + // !!! MUST BE CALLED AT THE END of the controller + initialize(); }] }); // once the form was validated successfully ... diff --git a/app/frontend/src/javascript/services/subscription.js b/app/frontend/src/javascript/services/subscription.js index 6056283ea..b98eb5f91 100644 --- a/app/frontend/src/javascript/services/subscription.js +++ b/app/frontend/src/javascript/services/subscription.js @@ -5,6 +5,10 @@ Application.Services.factory('Subscription', ['$resource', function ($resource) { id: '@id' }, { update: { method: 'PUT' + }, + payment_details: { + url: '/api/subscriptions/:id/payment_details', + method: 'GET' } } ); diff --git a/app/frontend/templates/admin/members/edit.html b/app/frontend/templates/admin/members/edit.html index 7a314e282..78e8ea5ce 100644 --- a/app/frontend/templates/admin/members/edit.html +++ b/app/frontend/templates/admin/members/edit.html @@ -78,7 +78,7 @@

- +

{{ 'app.admin.members_edit.cannot_extend_own_subscription' }} diff --git a/app/frontend/templates/admin/subscriptions/expired_at_modal.html b/app/frontend/templates/admin/subscriptions/expired_at_modal.html index 02e0b71ac..7e94d692e 100644 --- a/app/frontend/templates/admin/subscriptions/expired_at_modal.html +++ b/app/frontend/templates/admin/subscriptions/expired_at_modal.html @@ -4,30 +4,49 @@

); }; + const PaymentScheduleSummaryWrapper: React.FC = ({ schedule }) => { return ( diff --git a/app/frontend/src/javascript/components/plans/plan-card.tsx b/app/frontend/src/javascript/components/plans/plan-card.tsx index 509ec8709..244e099fd 100644 --- a/app/frontend/src/javascript/components/plans/plan-card.tsx +++ b/app/frontend/src/javascript/components/plans/plan-card.tsx @@ -2,13 +2,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import moment from 'moment'; import _ from 'lodash'; -import { IFablab } from '../../models/fablab'; import { Plan } from '../../models/plan'; import { User, UserRole } from '../../models/user'; import { Loader } from '../base/loader'; import '../../lib/i18n'; - -declare let Fablab: IFablab; +import FormatLib from '../../lib/format'; interface PlanCardProps { plan: Plan, @@ -29,14 +27,14 @@ const PlanCardComponent: React.FC = ({ plan, userId, subscribedPl * Return the formatted localized amount of the given plan (eg. 20.5 => "20,50 €") */ const amount = () : string => { - return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(plan.amount); + return FormatLib.price(plan.amount); }; /** * Return the formatted localized amount, divided by the number of months (eg. 120 => "10,00 € / month") */ const monthlyAmount = (): string => { const monthly = plan.amount / moment.duration(plan.interval_count, plan.interval).asMonths(); - return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(monthly); + return FormatLib.price(monthly); }; /** * Return the formatted localized duration of te given plan (eg. Month/3 => "3 mois") diff --git a/app/frontend/src/javascript/components/pricing/machines-pricing.tsx b/app/frontend/src/javascript/components/pricing/machines-pricing.tsx index 4356913d7..cfde86d70 100644 --- a/app/frontend/src/javascript/components/pricing/machines-pricing.tsx +++ b/app/frontend/src/javascript/components/pricing/machines-pricing.tsx @@ -17,6 +17,7 @@ import { Price } from '../../models/price'; import PrepaidPackAPI from '../../api/prepaid-pack'; import { PrepaidPack } from '../../models/prepaid-pack'; import { useImmer } from 'use-immer'; +import FormatLib from '../../lib/format'; declare let Fablab: IFablab; declare const Application: IApplication; @@ -63,11 +64,11 @@ const MachinesPricing: React.FC = ({ onError, onSuccess }) const hourlyRate = 10; if (type === 'hourly_rate') { - return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(hourlyRate); + return FormatLib.price(hourlyRate); } const price = (hourlyRate / 60) * EXEMPLE_DURATION; - return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(price); + return FormatLib.price(price); }; /** @@ -111,7 +112,7 @@ const MachinesPricing: React.FC = ({ onError, onSuccess })

-

+

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

diff --git a/app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx b/app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx new file mode 100644 index 000000000..9f5b057f9 --- /dev/null +++ b/app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx @@ -0,0 +1,112 @@ +import React, { useEffect, useState } from 'react'; +import { Subscription } from '../../models/subscription'; +import { FabModal, ModalSize } from '../base/fab-modal'; +import { useTranslation } from 'react-i18next'; +import { FabAlert } from '../base/fab-alert'; +import { FabInput } from '../base/fab-input'; +import FormatLib from '../../lib/format'; +import { Loader } from '../base/loader'; +import { react2angular } from 'react2angular'; +import { IApplication } from '../../models/application'; +import SubscriptionAPI from '../../api/subscription'; + +declare const Application: IApplication; + +interface FreeExtendModalProps { + isOpen: boolean, + toggleModal: () => void, + subscription: Subscription, + onSuccess: (subscription: Subscription) => void, + onError: (message: string) => void, +} + +/** + * Modal dialog shown to extend the current subscription of a customer, for free + */ +const FreeExtendModal: React.FC = ({ isOpen, toggleModal, subscription, onError, onSuccess }) => { + const { t } = useTranslation('admin'); + + const [expirationDate, setExpirationDate] = useState(new Date(subscription.expired_at)); + const [freeDays, setFreeDays] = useState(0); + + // we update the number of free days when the new expiration date is updated + useEffect(() => { + if (!expirationDate || !subscription.expired_at) { + setFreeDays(0); + } + // 86400000 = 1000 * 3600 * 24 = number of ms per day + setFreeDays(Math.ceil((expirationDate.getTime() - new Date(subscription.expired_at).getTime()) / 86400000)); + }, [expirationDate]); + + /** + * Return the formatted localized date for the given date + */ + const formatDateTime = (date: Date): string => { + return t('app.admin.free_extend_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) }); + }; + + /** + * Return the given date formatted for the HTML input-date + */ + const formatDefaultDate = (date: Date): string => { + return date.toISOString().substr(0, 10); + }; + + /** + * Parse the given date and record it as the new expiration date of the subscription + */ + const handleDateUpdate = (date: string): void => { + setExpirationDate(new Date(Date.parse(date))); + }; + + /** + * Callback triggered when the user validates the free extent of the subscription + */ + const handleConfirmExtend = (): void => { + SubscriptionAPI.update({ + id: subscription.id, + expired_at: expirationDate, + free: true + }).then(res => onSuccess(res)) + .catch(err => onError(err)); + }; + + return ( + + +

{t('app.admin.free_extend_modal.offer_free_days_infos')}

+

{t('app.admin.free_extend_modal.credits_will_remain_unchanged')}

+
+
+ + + + + + + +
+ ); +}; + +const FreeExtendModalWrapper: React.FC = ({ toggleModal, subscription, isOpen, onSuccess, onError }) => { + return ( + + + + ); +}; + +Application.Components.component('freeExtendModal', react2angular(FreeExtendModalWrapper, ['toggleModal', 'subscription', 'isOpen', 'onError', 'onSuccess'])); diff --git a/app/frontend/src/javascript/controllers/admin/members.js b/app/frontend/src/javascript/controllers/admin/members.js index 7a37fb3c3..c7b1281b0 100644 --- a/app/frontend/src/javascript/controllers/admin/members.js +++ b/app/frontend/src/javascript/controllers/admin/members.js @@ -705,6 +705,9 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', // current active authentication provider $scope.activeProvider = activeProviderPromise; + // modal dialog to extend the current subscription for free + $scope.isOpenFreeExtendModal = false; + /** * Open a modal dialog asking for confirmation to change the role of the given user * @returns {*} @@ -752,6 +755,27 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', }); }; + /** + * Opens/closes the modal dialog to freely extend the subscription + */ + $scope.toggleFreeExtendModal = () => { + $scope.isOpenFreeExtendModal = !$scope.isOpenFreeExtendModal; + }; + + /** + * Callback triggered if the subscription was successfully extended + */ + $scope.onExtendSuccess = (subscription) => { + $scope.subscription = subscription; + }; + + /** + * Callback triggered in case of error + */ + $scope.onError = (message) => { + growl.error(message); + }; + /** * Open a modal dialog, allowing the admin to extend the current user's subscription (freely or not) * @param subscription {Object} User's subscription object @@ -772,7 +796,6 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', $scope.expire_at = subscription.expired_at; $scope.new_expired_at = new Date(subscription.expired_at); - $scope.free = free; $scope.days = 0; $scope.payment_details = paymentDetails; $scope.datePicker = { @@ -790,11 +813,6 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', return $scope.datePicker.opened = true; }; - $scope.$watch(scope => scope.expire_at - , () => refreshDays()); - $scope.$watch(scope => scope.new_expired_at - , () => refreshDays()); - $scope.ok = function () { Subscription.update( { id: subscription.id }, @@ -823,17 +841,6 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', } } - /** - * Refresh the number of free days depending on the original subscription expiration date and on the new selected date - */ - function refreshDays () { - if (!$scope.new_expired_at || !$scope.expire_at) { - return $scope.days = 0; - } - // 86400000 = 1000 * 3600 * 24 = number of ms per day - $scope.days = Math.round((new Date($scope.new_expired_at).getTime() - new Date($scope.expire_at).getTime()) / 86400000); - } - // !!! MUST BE CALLED AT THE END of the controller initialize(); }] diff --git a/app/frontend/src/javascript/lib/format.ts b/app/frontend/src/javascript/lib/format.ts index 1b0cda093..8ebb31aa7 100644 --- a/app/frontend/src/javascript/lib/format.ts +++ b/app/frontend/src/javascript/lib/format.ts @@ -11,6 +11,13 @@ export default class FormatLib { return Intl.DateTimeFormat().format(moment(date).toDate()); } + /** + * Return the formatted localized time for the given date + */ + static time = (date: Date): string => { + return Intl.DateTimeFormat(Fablab.intl_locale, { hour: 'numeric', minute: 'numeric' }).format(moment(date).toDate()); + }; + /** * Return the formatted localized amount for the given price (eg. 20.5 => "20,50 €") */ diff --git a/app/frontend/src/javascript/models/subscription.ts b/app/frontend/src/javascript/models/subscription.ts index c6148f7a9..d975c7727 100644 --- a/app/frontend/src/javascript/models/subscription.ts +++ b/app/frontend/src/javascript/models/subscription.ts @@ -5,10 +5,20 @@ export interface Subscription { plan_id: number, expired_at: Date, canceled_at?: Date, - stripe: boolean, plan: Plan } export interface SubscriptionRequest { plan_id: number } + +export interface UpdateSubscriptionRequest { + id: number, + expired_at: Date, + free: boolean +} + +export interface SubscriptionPaymentDetails { + payment_schedule: boolean, + card: boolean +} diff --git a/app/frontend/src/stylesheets/application.scss b/app/frontend/src/stylesheets/application.scss index 7f9c99754..84c0cee14 100644 --- a/app/frontend/src/stylesheets/application.scss +++ b/app/frontend/src/stylesheets/application.scss @@ -65,5 +65,6 @@ @import "modules/pricing/edit-pack"; @import "modules/prepaid-packs/propose-packs-modal"; @import "modules/prepaid-packs/packs-summary"; +@import "modules/subscriptions/free-extend-modal"; @import "app.responsive"; diff --git a/app/frontend/src/stylesheets/modules/subscriptions/free-extend-modal.scss b/app/frontend/src/stylesheets/modules/subscriptions/free-extend-modal.scss new file mode 100644 index 000000000..17a681cc0 --- /dev/null +++ b/app/frontend/src/stylesheets/modules/subscriptions/free-extend-modal.scss @@ -0,0 +1,18 @@ +.free-extend-modal { + .fab-modal-content { + padding: 30px; + + .configuration-form { + padding: 15px; + + .input-wrapper { + display: block; + } + + .free-days { + display: block; + @extend .fab-input--input; + } + } + } +} diff --git a/app/frontend/templates/admin/members/edit.html b/app/frontend/templates/admin/members/edit.html index 78e8ea5ce..55298bd8b 100644 --- a/app/frontend/templates/admin/members/edit.html +++ b/app/frontend/templates/admin/members/edit.html @@ -77,8 +77,14 @@ {{ 'app.admin.members_edit.price_' | translate }} {{ subscription.plan.amount | currency}}

- + + +

{{ 'app.admin.members_edit.cannot_extend_own_subscription' }} diff --git a/app/frontend/templates/admin/subscriptions/expired_at_modal.html b/app/frontend/templates/admin/subscriptions/expired_at_modal.html index 7e94d692e..38bf7b632 100644 --- a/app/frontend/templates/admin/subscriptions/expired_at_modal.html +++ b/app/frontend/templates/admin/subscriptions/expired_at_modal.html @@ -3,10 +3,6 @@

- + {showCustomer && } From f250f58317116093f81ee23a867d5a20f04fe2a1 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 18 Oct 2021 11:47:24 +0200 Subject: [PATCH 059/142] fix subscription renewal tests --- app/models/subscription.rb | 2 +- .../subscriptions/renew_as_admin_test.rb | 66 +- ...on_with_payment_schedule_coupon_wallet.yml | 2404 ++++++++++++++--- 3 files changed, 2050 insertions(+), 422 deletions(-) diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 2f73badf0..5c0e40dd1 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -110,7 +110,7 @@ class Subscription < ApplicationRecord end def set_expiration_date - start_at = DateTime.current.in_time_zone + start_at = self.start_at || DateTime.current.in_time_zone self.expiration_date = start_at + plan.duration end diff --git a/test/integration/subscriptions/renew_as_admin_test.rb b/test/integration/subscriptions/renew_as_admin_test.rb index a25d6e920..a454bacda 100644 --- a/test/integration/subscriptions/renew_as_admin_test.rb +++ b/test/integration/subscriptions/renew_as_admin_test.rb @@ -2,6 +2,9 @@ require 'test_helper' +module Subscriptions; end + + class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest setup do @admin = User.find_by(username: 'admin') @@ -81,29 +84,38 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest user = User.find_by(username: 'pdurand') subscription = user.subscription.clone new_date = (1.month.from_now - 4.days).utc + offer_days_count = OfferDay.count VCR.use_cassette('subscriptions_admin_offer_free_days') do - put "/api/subscriptions/#{subscription.id}", - params: { - subscription: { - expired_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z'), - free: true - } - }.to_json, headers: default_headers + post '/api/local_payment/confirm_payment', + params: { + customer_id: user.id, + items: [ + { + free_extension: { + end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') + } + } + ] + }.to_json, headers: default_headers end # Check response format & status - assert_equal 200, response.status, response.body + assert_equal 201, response.status, response.body assert_equal Mime[:json], response.content_type # Check that the subscribed plan was not altered - res_subscription = json_response(response.body) - assert_equal subscription.id, res_subscription[:id], 'subscription id has changed' - assert_equal subscription.plan_id, res_subscription[:plan_id], 'subscribed plan does not match' - assert_dates_equal new_date, res_subscription[:expired_at], 'subscription end date was not updated' + res = json_response(response.body) + assert_equal 'OfferDay', res[:main_object][:type] + assert_equal 0, res[:items][0][:amount] + + assert_equal subscription.id, user.subscription.id, 'subscription id has changed' + assert_equal subscription.plan_id, user.subscription.plan_id, 'subscribed plan does not match' + assert_dates_equal new_date, user.subscription.expired_at, 'subscription end date was not updated' # Check the subscription was correctly saved assert_equal 1, user.subscriptions.count + assert_equal offer_days_count + 1, OfferDay.count # Check notification was sent to the user notification = Notification.find_by( @@ -120,31 +132,39 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest test 'admin successfully extends a subscription' do user = User.find_by(username: 'pdurand') subscription = user.subscription.clone - new_date = (1.month.from_now - 4.days).utc + new_date = subscription.expired_at + subscription.plan.interval_count.send(subscription.plan.interval) VCR.use_cassette('subscriptions_admin_extends_subscription') do - put "/api/subscriptions/#{subscription.id}", - params: { - subscription: { - expired_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') - } - }.to_json, headers: default_headers + post '/api/local_payment/confirm_payment', + params: { + customer_id: user.id, + payment_method: 'check', + payment_schedule: false, + items: [ + { + subscription: { + start_at: subscription.expired_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z'), + plan_id: subscription.plan_id + } + } + ] + }.to_json, headers: default_headers end # Check response format & status assert_equal 201, response.status, response.body assert_equal Mime[:json], response.content_type - # Check that the subscribed plan is still the same res_subscription = json_response(response.body) - assert_equal subscription.plan_id, res_subscription[:plan_id], 'subscribed plan does not match' + assert_equal 'Subscription', res_subscription[:main_object][:type] + assert_equal subscription.plan.amount / 100.0, res_subscription[:items][0][:amount] # Check the subscription was correctly saved assert_equal 2, user.subscriptions.count # Check that the subscription is new - assert_not_equal subscription.id, res_subscription[:id], 'subscription id has not changed' - assert_dates_equal new_date, res_subscription[:expired_at], 'subscription end date does not match' + assert_not_equal subscription.id, user.subscription.id, 'subscription id has not changed' + assert_dates_equal new_date, user.subscription.expired_at, 'subscription end date does not match' # Check notification was sent to the user notification = Notification.find_by( diff --git a/test/vcr_cassettes/reservations_machine_subscription_with_payment_schedule_coupon_wallet.yml b/test/vcr_cassettes/reservations_machine_subscription_with_payment_schedule_coupon_wallet.yml index 8d12f5b20..774e662b9 100644 --- a/test/vcr_cassettes/reservations_machine_subscription_with_payment_schedule_coupon_wallet.yml +++ b/test/vcr_cassettes/reservations_machine_subscription_with_payment_schedule_coupon_wallet.yml @@ -13,6 +13,8 @@ http_interactions: - Bearer sk_test_testfaketestfaketestfake Content-Type: - application/x-www-form-urlencoded + X-Stripe-Client-Telemetry: + - '{"last_request_metrics":{"request_id":"req_TMXYBFdX8Zu0bv","request_duration_ms":6}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -31,7 +33,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:43 GMT + - Mon, 18 Oct 2021 08:44:41 GMT Content-Type: - application/json Content-Length: @@ -51,11 +53,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 1e3000e9-9e5d-4ab9-b4e4-01449d3a8b8a + - 192810f7-ee10-4430-bc3e-056f93c2123b Original-Request: - - req_rEpa6GQP79Jekg + - req_JEUZMg7gUSaXWN Request-Id: - - req_rEpa6GQP79Jekg + - req_JEUZMg7gUSaXWN Stripe-Should-Retry: - 'false' Stripe-Version: @@ -66,7 +68,7 @@ http_interactions: encoding: UTF-8 string: | { - "id": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "id": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "object": "payment_method", "billing_details": { "address": { @@ -106,17 +108,17 @@ http_interactions: }, "wallet": null }, - "created": 1634288083, + "created": 1634546681, "customer": null, "livemode": false, "metadata": { }, "type": "card" } - recorded_at: Fri, 15 Oct 2021 08:54:43 GMT + recorded_at: Mon, 18 Oct 2021 08:44:41 GMT - request: method: post - uri: https://api.stripe.com/v1/payment_methods/pm_1JkmBa2sOmf47Nz9ocFmIyBw/attach + uri: https://api.stripe.com/v1/payment_methods/pm_1JlrSX2sOmf47Nz9O4x8IvAt/attach body: encoding: UTF-8 string: customer=cus_8E2ys9zDZgetWX @@ -128,7 +130,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_rEpa6GQP79Jekg","request_duration_ms":779}}' + - '{"last_request_metrics":{"request_id":"req_JEUZMg7gUSaXWN","request_duration_ms":844}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -147,7 +149,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:44 GMT + - Mon, 18 Oct 2021 08:44:42 GMT Content-Type: - application/json Content-Length: @@ -167,11 +169,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 34249c8d-11bd-4302-9125-327f90f1dc45 + - 42aa9edc-e9f8-431a-b2ad-007b00df1560 Original-Request: - - req_A9E7DRCjsnh3Yq + - req_O04AJo622DNNGe Request-Id: - - req_A9E7DRCjsnh3Yq + - req_O04AJo622DNNGe Stripe-Should-Retry: - 'false' Stripe-Version: @@ -182,7 +184,7 @@ http_interactions: encoding: UTF-8 string: | { - "id": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "id": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "object": "payment_method", "billing_details": { "address": { @@ -222,20 +224,20 @@ http_interactions: }, "wallet": null }, - "created": 1634288083, + "created": 1634546681, "customer": "cus_8E2ys9zDZgetWX", "livemode": false, "metadata": { }, "type": "card" } - recorded_at: Fri, 15 Oct 2021 08:54:44 GMT + recorded_at: Mon, 18 Oct 2021 08:44:42 GMT - request: method: post uri: https://api.stripe.com/v1/customers/cus_8E2ys9zDZgetWX body: encoding: UTF-8 - string: invoice_settings[default_payment_method]=pm_1JkmBa2sOmf47Nz9ocFmIyBw + string: invoice_settings[default_payment_method]=pm_1JlrSX2sOmf47Nz9O4x8IvAt headers: User-Agent: - Stripe/v1 RubyBindings/5.29.0 @@ -244,7 +246,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_A9E7DRCjsnh3Yq","request_duration_ms":769}}' + - '{"last_request_metrics":{"request_id":"req_O04AJo622DNNGe","request_duration_ms":883}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -263,11 +265,11 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:45 GMT + - Mon, 18 Oct 2021 08:44:43 GMT Content-Type: - application/json Content-Length: - - '49769' + - '49799' Connection: - keep-alive Access-Control-Allow-Credentials: @@ -283,11 +285,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 4e7287cb-7714-4f75-816c-23ec5cf02a25 + - 0ca2d40b-08fe-4ea4-aabe-26ac0f9ffef0 Original-Request: - - req_z4BLEPOnkPLE8X + - req_ORMShp1iikLzR8 Request-Id: - - req_z4BLEPOnkPLE8X + - req_ORMShp1iikLzR8 Stripe-Should-Retry: - 'false' Stripe-Version: @@ -313,14 +315,14 @@ http_interactions: "invoice_prefix": "BCC32B8", "invoice_settings": { "custom_fields": null, - "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_payment_method": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "footer": null }, "livemode": false, "metadata": { }, "name": null, - "next_invoice_sequence": 509, + "next_invoice_sequence": 517, "phone": null, "preferred_locales": [ @@ -363,6 +365,152 @@ http_interactions: "subscriptions": { "object": "list", "data": [ + { + "id": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634288088, + "billing_thresholds": null, + "cancel_at": 1665824085, + "cancel_at_period_end": false, + "canceled_at": 1634288088, + "collection_method": "charge_automatically", + "created": 1634288088, + "current_period_end": 1636966488, + "current_period_start": 1634288088, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPbOBUeFMwAvpR", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634288088, + "metadata": { + }, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JkmBg2sOmf47Nz9MGXiiaqr" + }, + "latest_invoice": "in_1JkmBg2sOmf47Nz9yKTwqM67", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634288088, + "start_date": 1634288088, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, { "id": "sub_1JklFr2sOmf47Nz9JAPgZ9YT", "object": "subscription", @@ -1676,156 +1824,10 @@ http_interactions: "transfer_data": null, "trial_end": null, "trial_start": null - }, - { - "id": "sub_KDcYiLLbeDKj9g", - "object": "subscription", - "application_fee_percent": null, - "automatic_tax": { - "enabled": false - }, - "billing": "charge_automatically", - "billing_cycle_anchor": 1631524733, - "billing_thresholds": null, - "cancel_at": 1663060731, - "cancel_at_period_end": false, - "canceled_at": 1631524733, - "collection_method": "charge_automatically", - "created": 1631524733, - "current_period_end": 1636795133, - "current_period_start": 1634116733, - "customer": "cus_8E2ys9zDZgetWX", - "days_until_due": null, - "default_payment_method": "pm_1JZBJN2sOmf47Nz9xyv4Ze7i", - "default_source": null, - "default_tax_rates": [ - - ], - "discount": null, - "ended_at": null, - "invoice_customer_balance_settings": { - "consume_applied_balance_on_void": true - }, - "items": { - "object": "list", - "data": [ - { - "id": "si_KDcY9IkGJngPha", - "object": "subscription_item", - "billing_thresholds": null, - "created": 1631524734, - "metadata": { - }, - "plan": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "plan", - "active": true, - "aggregate_usage": null, - "amount": 9466, - "amount_decimal": "9466", - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "interval": "month", - "interval_count": 1, - "livemode": false, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "tiers": null, - "tiers_mode": null, - "transform_usage": null, - "trial_period_days": null, - "usage_type": "licensed" - }, - "price": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "price", - "active": true, - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "livemode": false, - "lookup_key": null, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "recurring": { - "aggregate_usage": null, - "interval": "month", - "interval_count": 1, - "trial_period_days": null, - "usage_type": "licensed" - }, - "tax_behavior": "unspecified", - "tiers_mode": null, - "transform_quantity": null, - "type": "recurring", - "unit_amount": 9466, - "unit_amount_decimal": "9466" - }, - "quantity": 1, - "subscription": "sub_KDcYiLLbeDKj9g", - "tax_rates": [ - - ] - } - ], - "has_more": false, - "total_count": 1, - "url": "/v1/subscription_items?subscription=sub_KDcYiLLbeDKj9g" - }, - "latest_invoice": "in_1Jk3cD2sOmf47Nz97iY44834", - "livemode": false, - "metadata": { - }, - "next_pending_invoice_item_invoice": null, - "pause_collection": null, - "payment_settings": { - "payment_method_options": null, - "payment_method_types": null - }, - "pending_invoice_item_interval": null, - "pending_setup_intent": null, - "pending_update": null, - "plan": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "plan", - "active": true, - "aggregate_usage": null, - "amount": 9466, - "amount_decimal": "9466", - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "interval": "month", - "interval_count": 1, - "livemode": false, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "tiers": null, - "tiers_mode": null, - "transform_usage": null, - "trial_period_days": null, - "usage_type": "licensed" - }, - "quantity": 1, - "schedule": null, - "start": 1631524733, - "start_date": 1631524733, - "status": "active", - "tax_percent": null, - "transfer_data": null, - "trial_end": null, - "trial_start": null } ], "has_more": true, - "total_count": 67, + "total_count": 68, "url": "/v1/customers/cus_8E2ys9zDZgetWX/subscriptions" }, "tax_exempt": "none", @@ -1841,13 +1843,13 @@ http_interactions: "tax_info": null, "tax_info_verification": null } - recorded_at: Fri, 15 Oct 2021 08:54:45 GMT + recorded_at: Mon, 18 Oct 2021 08:44:43 GMT - request: method: post uri: https://api.stripe.com/v1/customers/cus_8E2ys9zDZgetWX body: encoding: UTF-8 - string: balance=-10474 + string: balance=-10174 headers: User-Agent: - Stripe/v1 RubyBindings/5.29.0 @@ -1856,7 +1858,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_z4BLEPOnkPLE8X","request_duration_ms":856}}' + - '{"last_request_metrics":{"request_id":"req_ORMShp1iikLzR8","request_duration_ms":918}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -1875,11 +1877,11 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:46 GMT + - Mon, 18 Oct 2021 08:44:44 GMT Content-Type: - application/json Content-Length: - - '49779' + - '49809' Connection: - keep-alive Access-Control-Allow-Credentials: @@ -1895,11 +1897,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 13ed5e6b-7c38-463d-8454-02838714badd + - 98def57f-0c02-4de8-b2de-cb6fe8134d96 Original-Request: - - req_ubHLSPOsasYznU + - req_bFyrd7cFbTUqGK Request-Id: - - req_ubHLSPOsasYznU + - req_bFyrd7cFbTUqGK Stripe-Should-Retry: - 'false' Stripe-Version: @@ -1912,9 +1914,9 @@ http_interactions: { "id": "cus_8E2ys9zDZgetWX", "object": "customer", - "account_balance": -10474, + "account_balance": -10174, "address": null, - "balance": -10474, + "balance": -10174, "created": 1460026822, "currency": "usd", "default_source": "card_1Euc902sOmf47Nz9eZvNNyyQ", @@ -1925,14 +1927,14 @@ http_interactions: "invoice_prefix": "BCC32B8", "invoice_settings": { "custom_fields": null, - "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_payment_method": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "footer": null }, "livemode": false, "metadata": { }, "name": null, - "next_invoice_sequence": 509, + "next_invoice_sequence": 517, "phone": null, "preferred_locales": [ @@ -1975,6 +1977,152 @@ http_interactions: "subscriptions": { "object": "list", "data": [ + { + "id": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634288088, + "billing_thresholds": null, + "cancel_at": 1665824085, + "cancel_at_period_end": false, + "canceled_at": 1634288088, + "collection_method": "charge_automatically", + "created": 1634288088, + "current_period_end": 1636966488, + "current_period_start": 1634288088, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPbOBUeFMwAvpR", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634288088, + "metadata": { + }, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JkmBg2sOmf47Nz9MGXiiaqr" + }, + "latest_invoice": "in_1JkmBg2sOmf47Nz9yKTwqM67", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634288088, + "start_date": 1634288088, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, { "id": "sub_1JklFr2sOmf47Nz9JAPgZ9YT", "object": "subscription", @@ -3288,156 +3436,10 @@ http_interactions: "transfer_data": null, "trial_end": null, "trial_start": null - }, - { - "id": "sub_KDcYiLLbeDKj9g", - "object": "subscription", - "application_fee_percent": null, - "automatic_tax": { - "enabled": false - }, - "billing": "charge_automatically", - "billing_cycle_anchor": 1631524733, - "billing_thresholds": null, - "cancel_at": 1663060731, - "cancel_at_period_end": false, - "canceled_at": 1631524733, - "collection_method": "charge_automatically", - "created": 1631524733, - "current_period_end": 1636795133, - "current_period_start": 1634116733, - "customer": "cus_8E2ys9zDZgetWX", - "days_until_due": null, - "default_payment_method": "pm_1JZBJN2sOmf47Nz9xyv4Ze7i", - "default_source": null, - "default_tax_rates": [ - - ], - "discount": null, - "ended_at": null, - "invoice_customer_balance_settings": { - "consume_applied_balance_on_void": true - }, - "items": { - "object": "list", - "data": [ - { - "id": "si_KDcY9IkGJngPha", - "object": "subscription_item", - "billing_thresholds": null, - "created": 1631524734, - "metadata": { - }, - "plan": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "plan", - "active": true, - "aggregate_usage": null, - "amount": 9466, - "amount_decimal": "9466", - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "interval": "month", - "interval_count": 1, - "livemode": false, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "tiers": null, - "tiers_mode": null, - "transform_usage": null, - "trial_period_days": null, - "usage_type": "licensed" - }, - "price": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "price", - "active": true, - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "livemode": false, - "lookup_key": null, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "recurring": { - "aggregate_usage": null, - "interval": "month", - "interval_count": 1, - "trial_period_days": null, - "usage_type": "licensed" - }, - "tax_behavior": "unspecified", - "tiers_mode": null, - "transform_quantity": null, - "type": "recurring", - "unit_amount": 9466, - "unit_amount_decimal": "9466" - }, - "quantity": 1, - "subscription": "sub_KDcYiLLbeDKj9g", - "tax_rates": [ - - ] - } - ], - "has_more": false, - "total_count": 1, - "url": "/v1/subscription_items?subscription=sub_KDcYiLLbeDKj9g" - }, - "latest_invoice": "in_1Jk3cD2sOmf47Nz97iY44834", - "livemode": false, - "metadata": { - }, - "next_pending_invoice_item_invoice": null, - "pause_collection": null, - "payment_settings": { - "payment_method_options": null, - "payment_method_types": null - }, - "pending_invoice_item_interval": null, - "pending_setup_intent": null, - "pending_update": null, - "plan": { - "id": "price_1JZBJQ2sOmf47Nz9qqBlVAy2", - "object": "plan", - "active": true, - "aggregate_usage": null, - "amount": 9466, - "amount_decimal": "9466", - "billing_scheme": "per_unit", - "created": 1631524732, - "currency": "usd", - "interval": "month", - "interval_count": 1, - "livemode": false, - "metadata": { - }, - "nickname": null, - "product": "prod_IZQAhb9nLu4jfN", - "tiers": null, - "tiers_mode": null, - "transform_usage": null, - "trial_period_days": null, - "usage_type": "licensed" - }, - "quantity": 1, - "schedule": null, - "start": 1631524733, - "start_date": 1631524733, - "status": "active", - "tax_percent": null, - "transfer_data": null, - "trial_end": null, - "trial_start": null } ], "has_more": true, - "total_count": 67, + "total_count": 68, "url": "/v1/customers/cus_8E2ys9zDZgetWX/subscriptions" }, "tax_exempt": "none", @@ -3453,7 +3455,7 @@ http_interactions: "tax_info": null, "tax_info_verification": null } - recorded_at: Fri, 15 Oct 2021 08:54:46 GMT + recorded_at: Mon, 18 Oct 2021 08:44:44 GMT - request: method: post uri: https://api.stripe.com/v1/prices @@ -3468,7 +3470,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_ubHLSPOsasYznU","request_duration_ms":1027}}' + - '{"last_request_metrics":{"request_id":"req_bFyrd7cFbTUqGK","request_duration_ms":977}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -3487,7 +3489,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:46 GMT + - Mon, 18 Oct 2021 08:44:45 GMT Content-Type: - application/json Content-Length: @@ -3507,11 +3509,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 3f30c901-9abb-4224-9e80-860ba070f19d + - 26df7b66-f57c-4d60-a248-855135d50dde Original-Request: - - req_8ZuimZBld2bdVW + - req_LbSU9EMEk1rYLc Request-Id: - - req_8ZuimZBld2bdVW + - req_LbSU9EMEk1rYLc Stripe-Should-Retry: - 'false' Stripe-Version: @@ -3522,11 +3524,11 @@ http_interactions: encoding: UTF-8 string: | { - "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", "object": "price", "active": true, "billing_scheme": "per_unit", - "created": 1634288086, + "created": 1634546684, "currency": "usd", "livemode": false, "lookup_key": null, @@ -3548,7 +3550,7 @@ http_interactions: "unit_amount": 9466, "unit_amount_decimal": "9466" } - recorded_at: Fri, 15 Oct 2021 08:54:46 GMT + recorded_at: Mon, 18 Oct 2021 08:44:45 GMT - request: method: post uri: https://api.stripe.com/v1/prices @@ -3563,7 +3565,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_8ZuimZBld2bdVW","request_duration_ms":535}}' + - '{"last_request_metrics":{"request_id":"req_LbSU9EMEk1rYLc","request_duration_ms":439}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -3582,7 +3584,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:47 GMT + - Mon, 18 Oct 2021 08:44:45 GMT Content-Type: - application/json Content-Length: @@ -3602,11 +3604,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 0354d62f-eec7-4331-9235-bd503296a1bf + - 964a2694-c613-4e14-88bf-b89fe75a3924 Original-Request: - - req_VIZhdnwmWePRpn + - req_cpNb8X9GhXKyNc Request-Id: - - req_VIZhdnwmWePRpn + - req_cpNb8X9GhXKyNc Stripe-Should-Retry: - 'false' Stripe-Version: @@ -3617,11 +3619,11 @@ http_interactions: encoding: UTF-8 string: | { - "id": "price_1JkmBf2sOmf47Nz9VonJmtjT", + "id": "price_1JlrSb2sOmf47Nz9jgGVSuT7", "object": "price", "active": true, "billing_scheme": "per_unit", - "created": 1634288087, + "created": 1634546685, "currency": "usd", "livemode": false, "lookup_key": null, @@ -3637,7 +3639,7 @@ http_interactions: "unit_amount": 8, "unit_amount_decimal": "8" } - recorded_at: Fri, 15 Oct 2021 08:54:47 GMT + recorded_at: Mon, 18 Oct 2021 08:44:45 GMT - request: method: post uri: https://api.stripe.com/v1/prices @@ -3652,7 +3654,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_VIZhdnwmWePRpn","request_duration_ms":443}}' + - '{"last_request_metrics":{"request_id":"req_cpNb8X9GhXKyNc","request_duration_ms":417}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -3671,7 +3673,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:47 GMT + - Mon, 18 Oct 2021 08:44:45 GMT Content-Type: - application/json Content-Length: @@ -3691,11 +3693,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - f856850e-e035-4107-b36b-45fe3b29db70 + - 5215c542-fc7d-4796-85b0-08382858dde6 Original-Request: - - req_67lIXeb0nr04As + - req_TpG4aNhV8rTka0 Request-Id: - - req_67lIXeb0nr04As + - req_TpG4aNhV8rTka0 Stripe-Should-Retry: - 'false' Stripe-Version: @@ -3706,11 +3708,11 @@ http_interactions: encoding: UTF-8 string: | { - "id": "price_1JkmBf2sOmf47Nz9miP3WxTP", + "id": "price_1JlrSb2sOmf47Nz9qCInRHWn", "object": "price", "active": true, "billing_scheme": "per_unit", - "created": 1634288087, + "created": 1634546685, "currency": "usd", "livemode": false, "lookup_key": null, @@ -3726,13 +3728,13 @@ http_interactions: "unit_amount": 1000, "unit_amount_decimal": "1000" } - recorded_at: Fri, 15 Oct 2021 08:54:47 GMT + recorded_at: Mon, 18 Oct 2021 08:44:46 GMT - request: method: post uri: https://api.stripe.com/v1/subscriptions body: encoding: UTF-8 - string: customer=cus_8E2ys9zDZgetWX&cancel_at=1665824085&add_invoice_items[0][price]=price_1JkmBf2sOmf47Nz9VonJmtjT&add_invoice_items[1][price]=price_1JkmBf2sOmf47Nz9miP3WxTP&items[0][price]=price_1JkmBe2sOmf47Nz99Wrpiisc&default_payment_method=pm_1JkmBa2sOmf47Nz9ocFmIyBw&expand[0]=latest_invoice.payment_intent + string: customer=cus_8E2ys9zDZgetWX&cancel_at=1666082683&add_invoice_items[0][price]=price_1JlrSb2sOmf47Nz9jgGVSuT7&add_invoice_items[1][price]=price_1JlrSb2sOmf47Nz9qCInRHWn&coupon=GIME3EUR&items[0][price]=price_1JlrSa2sOmf47Nz9ZK9HcoJE&default_payment_method=pm_1JlrSX2sOmf47Nz9O4x8IvAt&expand[0]=latest_invoice.payment_intent headers: User-Agent: - Stripe/v1 RubyBindings/5.29.0 @@ -3741,7 +3743,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_67lIXeb0nr04As","request_duration_ms":407}}' + - '{"last_request_metrics":{"request_id":"req_TpG4aNhV8rTka0","request_duration_ms":427}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -3760,11 +3762,11 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:49 GMT + - Mon, 18 Oct 2021 08:44:48 GMT Content-Type: - application/json Content-Length: - - '12287' + - '13528' Connection: - keep-alive Access-Control-Allow-Credentials: @@ -3780,11 +3782,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - 5c6a4d0d-b4c3-4ffb-a223-4fca8d54e312 + - f1bf7ec1-ed73-4322-945d-6617fdf38971 Original-Request: - - req_jH8eY0zmweOaLs + - req_dV7qFlSzKcFLZu Request-Id: - - req_jH8eY0zmweOaLs + - req_dV7qFlSzKcFLZu Stripe-Should-Retry: - 'false' Stripe-Version: @@ -3794,11 +3796,11 @@ http_interactions: body: encoding: ASCII-8BIT string: !binary |- - ewogICJpZCI6ICJzdWJfMUprbUJnMnNPbWY0N056OU1HWGlpYXFyIiwKICAib2JqZWN0IjogInN1YnNjcmlwdGlvbiIsCiAgImFwcGxpY2F0aW9uX2ZlZV9wZXJjZW50IjogbnVsbCwKICAiYXV0b21hdGljX3RheCI6IHsKICAgICJlbmFibGVkIjogZmFsc2UKICB9LAogICJiaWxsaW5nIjogImNoYXJnZV9hdXRvbWF0aWNhbGx5IiwKICAiYmlsbGluZ19jeWNsZV9hbmNob3IiOiAxNjM0Mjg4MDg4LAogICJiaWxsaW5nX3RocmVzaG9sZHMiOiBudWxsLAogICJjYW5jZWxfYXQiOiAxNjY1ODI0MDg1LAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5jZWxlZF9hdCI6IDE2MzQyODgwODgsCiAgImNvbGxlY3Rpb25fbWV0aG9kIjogImNoYXJnZV9hdXRvbWF0aWNhbGx5IiwKICAiY3JlYXRlZCI6IDE2MzQyODgwODgsCiAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE2MzY5NjY0ODgsCiAgImN1cnJlbnRfcGVyaW9kX3N0YXJ0IjogMTYzNDI4ODA4OCwKICAiY3VzdG9tZXIiOiAiY3VzXzhFMnlzOXpEWmdldFdYIiwKICAiZGF5c191bnRpbF9kdWUiOiBudWxsLAogICJkZWZhdWx0X3BheW1lbnRfbWV0aG9kIjogInBtXzFKa21CYTJzT21mNDdOejlvY0ZtSXlCdyIsCiAgImRlZmF1bHRfc291cmNlIjogbnVsbCwKICAiZGVmYXVsdF90YXhfcmF0ZXMiOiBbCgogIF0sCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRfYXQiOiBudWxsLAogICJpbnZvaWNlX2N1c3RvbWVyX2JhbGFuY2Vfc2V0dGluZ3MiOiB7CiAgICAiY29uc3VtZV9hcHBsaWVkX2JhbGFuY2Vfb25fdm9pZCI6IHRydWUKICB9LAogICJpdGVtcyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAgICAgewogICAgICAgICJpZCI6ICJzaV9LUGJPQlVlRk13QXZwUiIsCiAgICAgICAgIm9iamVjdCI6ICJzdWJzY3JpcHRpb25faXRlbSIsCiAgICAgICAgImJpbGxpbmdfdGhyZXNob2xkcyI6IG51bGwsCiAgICAgICAgImNyZWF0ZWQiOiAxNjM0Mjg4MDg4LAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICB9LAogICAgICAgICJwbGFuIjogewogICAgICAgICAgImlkIjogInByaWNlXzFKa21CZTJzT21mNDdOejk5V3JwaWlzYyIsCiAgICAgICAgICAib2JqZWN0IjogInBsYW4iLAogICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICJhbW91bnQiOiA5NDY2LAogICAgICAgICAgImFtb3VudF9kZWNpbWFsIjogIjk0NjYiLAogICAgICAgICAgImJpbGxpbmdfc2NoZW1lIjogInBlcl91bml0IiwKICAgICAgICAgICJjcmVhdGVkIjogMTYzNDI4ODA4NiwKICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICAgICAgICJpbnRlcnZhbF9jb3VudCI6IDEsCiAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgIH0sCiAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAidGllcnMiOiBudWxsLAogICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgInRyYW5zZm9ybV91c2FnZSI6IG51bGwsCiAgICAgICAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsLAogICAgICAgICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgICAgICAgfSwKICAgICAgICAicHJpY2UiOiB7CiAgICAgICAgICAiaWQiOiAicHJpY2VfMUprbUJlMnNPbWY0N056OTlXcnBpaXNjIiwKICAgICAgICAgICJvYmplY3QiOiAicHJpY2UiLAogICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgImNyZWF0ZWQiOiAxNjM0Mjg4MDg2LAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICJsb29rdXBfa2V5IjogbnVsbCwKICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgIH0sCiAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAicmVjdXJyaW5nIjogewogICAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbCwKICAgICAgICAgICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgICAgICAgICB9LAogICAgICAgICAgInRheF9iZWhhdmlvciI6ICJ1bnNwZWNpZmllZCIsCiAgICAgICAgICAidGllcnNfbW9kZSI6IG51bGwsCiAgICAgICAgICAidHJhbnNmb3JtX3F1YW50aXR5IjogbnVsbCwKICAgICAgICAgICJ0eXBlIjogInJlY3VycmluZyIsCiAgICAgICAgICAidW5pdF9hbW91bnQiOiA5NDY2LAogICAgICAgICAgInVuaXRfYW1vdW50X2RlY2ltYWwiOiAiOTQ2NiIKICAgICAgICB9LAogICAgICAgICJxdWFudGl0eSI6IDEsCiAgICAgICAgInN1YnNjcmlwdGlvbiI6ICJzdWJfMUprbUJnMnNPbWY0N056OU1HWGlpYXFyIiwKICAgICAgICAidGF4X3JhdGVzIjogWwoKICAgICAgICBdCiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9zdWJzY3JpcHRpb25faXRlbXM/c3Vic2NyaXB0aW9uPXN1Yl8xSmttQmcyc09tZjQ3Tno5TUdYaWlhcXIiCiAgfSwKICAibGF0ZXN0X2ludm9pY2UiOiB7CiAgICAiaWQiOiAiaW5fMUprbUJnMnNPbWY0N056OXlLVHdxTTY3IiwKICAgICJvYmplY3QiOiAiaW52b2ljZSIsCiAgICAiYWNjb3VudF9jb3VudHJ5IjogIkZSIiwKICAgICJhY2NvdW50X25hbWUiOiAiU2xlZWRlIiwKICAgICJhY2NvdW50X3RheF9pZHMiOiBudWxsLAogICAgImFtb3VudF9kdWUiOiAwLAogICAgImFtb3VudF9wYWlkIjogMCwKICAgICJhbW91bnRfcmVtYWluaW5nIjogMCwKICAgICJhcHBsaWNhdGlvbl9mZWVfYW1vdW50IjogbnVsbCwKICAgICJhdHRlbXB0X2NvdW50IjogMCwKICAgICJhdHRlbXB0ZWQiOiB0cnVlLAogICAgImF1dG9fYWR2YW5jZSI6IGZhbHNlLAogICAgImF1dG9tYXRpY190YXgiOiB7CiAgICAgICJlbmFibGVkIjogZmFsc2UsCiAgICAgICJzdGF0dXMiOiBudWxsCiAgICB9LAogICAgImJpbGxpbmciOiAiY2hhcmdlX2F1dG9tYXRpY2FsbHkiLAogICAgImJpbGxpbmdfcmVhc29uIjogInN1YnNjcmlwdGlvbl9jcmVhdGUiLAogICAgImNoYXJnZSI6IG51bGwsCiAgICAiY29sbGVjdGlvbl9tZXRob2QiOiAiY2hhcmdlX2F1dG9tYXRpY2FsbHkiLAogICAgImNyZWF0ZWQiOiAxNjM0Mjg4MDg4LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiY3VzdG9tX2ZpZWxkcyI6IG51bGwsCiAgICAiY3VzdG9tZXIiOiAiY3VzXzhFMnlzOXpEWmdldFdYIiwKICAgICJjdXN0b21lcl9hZGRyZXNzIjogbnVsbCwKICAgICJjdXN0b21lcl9lbWFpbCI6ICJsdWNpbGUuc2VndWluQGxpdmUuZnIiLAogICAgImN1c3RvbWVyX25hbWUiOiBudWxsLAogICAgImN1c3RvbWVyX3Bob25lIjogbnVsbCwKICAgICJjdXN0b21lcl9zaGlwcGluZyI6IG51bGwsCiAgICAiY3VzdG9tZXJfdGF4X2V4ZW1wdCI6ICJub25lIiwKICAgICJjdXN0b21lcl90YXhfaWRzIjogWwoKICAgIF0sCiAgICAiZGVmYXVsdF9wYXltZW50X21ldGhvZCI6IG51bGwsCiAgICAiZGVmYXVsdF9zb3VyY2UiOiBudWxsLAogICAgImRlZmF1bHRfdGF4X3JhdGVzIjogWwoKICAgIF0sCiAgICAiZGVzY3JpcHRpb24iOiBudWxsLAogICAgImRpc2NvdW50IjogbnVsbCwKICAgICJkaXNjb3VudHMiOiBbCgogICAgXSwKICAgICJkdWVfZGF0ZSI6IG51bGwsCiAgICAiZW5kaW5nX2JhbGFuY2UiOiAwLAogICAgImZvb3RlciI6IG51bGwsCiAgICAiaG9zdGVkX2ludm9pY2VfdXJsIjogImh0dHBzOi8vaW52b2ljZS5zdHJpcGUuY29tL2kvYWNjdF8xMDNyRTYyc09tZjQ3Tno5L3Rlc3RfWVdOamRGOHhNRE55UlRZeWMwOXRaalEzVG5vNUxGOUxVR0pQWm14TVV6QkJkMDgxUjJwQk5XTTFiMmhFVTI1amMyMXNRV1ppMDEwMElKWmprb2pBIiwKICAgICJpbnZvaWNlX3BkZiI6ICJodHRwczovL3BheS5zdHJpcGUuY29tL2ludm9pY2UvYWNjdF8xMDNyRTYyc09tZjQ3Tno5L3Rlc3RfWVdOamRGOHhNRE55UlRZeWMwOXRaalEzVG5vNUxGOUxVR0pQWm14TVV6QkJkMDgxUjJwQk5XTTFiMmhFVTI1amMyMXNRV1ppMDEwMElKWmprb2pBL3BkZiIsCiAgICAibGFzdF9maW5hbGl6YXRpb25fZXJyb3IiOiBudWxsLAogICAgImxpbmVzIjogewogICAgICAib2JqZWN0IjogImxpc3QiLAogICAgICAiZGF0YSI6IFsKICAgICAgICB7CiAgICAgICAgICAiaWQiOiAiaWlfMUprbUJnMnNPbWY0N056OU5sYWljWWJFIiwKICAgICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAgICJhbW91bnQiOiAxMDAwLAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiZGVzY3JpcHRpb24iOiAiRMOpY291cGV1c2UgbGFzZXIiLAogICAgICAgICAgImRpc2NvdW50X2Ftb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJkaXNjb3VudGFibGUiOiB0cnVlLAogICAgICAgICAgImRpc2NvdW50cyI6IFsKCiAgICAgICAgICBdLAogICAgICAgICAgImludm9pY2VfaXRlbSI6ICJpaV8xSmttQmcyc09tZjQ3Tno5TmxhaWNZYkUiLAogICAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICB9LAogICAgICAgICAgInBlcmlvZCI6IHsKICAgICAgICAgICAgImVuZCI6IDE2MzY5NjY0ODgsCiAgICAgICAgICAgICJzdGFydCI6IDE2MzQyODgwODgKICAgICAgICAgIH0sCiAgICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAgICAicHJpY2UiOiB7CiAgICAgICAgICAgICJpZCI6ICJwcmljZV8xSmttQmYyc09tZjQ3Tno5bWlQM1d4VFAiLAogICAgICAgICAgICAib2JqZWN0IjogInByaWNlIiwKICAgICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAgICJiaWxsaW5nX3NjaGVtZSI6ICJwZXJfdW5pdCIsCiAgICAgICAgICAgICJjcmVhdGVkIjogMTYzNDI4ODA4NywKICAgICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgICAibG9va3VwX2tleSI6IG51bGwsCiAgICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgIm5pY2tuYW1lIjogIlJlc2VydmF0aW9ucyBmb3IgcGF5bWVudCBzY2hlZHVsZSIsCiAgICAgICAgICAgICJwcm9kdWN0IjogInByb2RfSVpQeUhwTUNsMzhpUWwiLAogICAgICAgICAgICAicmVjdXJyaW5nIjogbnVsbCwKICAgICAgICAgICAgInRheF9iZWhhdmlvciI6ICJ1bnNwZWNpZmllZCIsCiAgICAgICAgICAgICJ0aWVyc19tb2RlIjogbnVsbCwKICAgICAgICAgICAgInRyYW5zZm9ybV9xdWFudGl0eSI6IG51bGwsCiAgICAgICAgICAgICJ0eXBlIjogIm9uZV90aW1lIiwKICAgICAgICAgICAgInVuaXRfYW1vdW50IjogMTAwMCwKICAgICAgICAgICAgInVuaXRfYW1vdW50X2RlY2ltYWwiOiAiMTAwMCIKICAgICAgICAgIH0sCiAgICAgICAgICAicHJvcmF0aW9uIjogZmFsc2UsCiAgICAgICAgICAicXVhbnRpdHkiOiAxLAogICAgICAgICAgInN1YnNjcmlwdGlvbiI6ICJzdWJfMUprbUJnMnNPbWY0N056OU1HWGlpYXFyIiwKICAgICAgICAgICJ0YXhfYW1vdW50cyI6IFsKCiAgICAgICAgICBdLAogICAgICAgICAgInRheF9yYXRlcyI6IFsKCiAgICAgICAgICBdLAogICAgICAgICAgInR5cGUiOiAiaW52b2ljZWl0ZW0iLAogICAgICAgICAgInVuaXF1ZV9pZCI6ICJpbF8xSmttQmcyc09tZjQ3Tno5MHhPQjZEOGEiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAiaWQiOiAiaWlfMUprbUJnMnNPbWY0N056OXBQT09vT3NDIiwKICAgICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAgICJhbW91bnQiOiA4LAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiZGVzY3JpcHRpb24iOiAiQWJvbm5lbWVudCBtZW5zdWFsaXNhYmxlIC0gc3RhbmRhcmQsIGFzc29jaWF0aW9uLCB5ZWFyIiwKICAgICAgICAgICJkaXNjb3VudF9hbW91bnRzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAiZGlzY291bnRhYmxlIjogdHJ1ZSwKICAgICAgICAgICJkaXNjb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJpbnZvaWNlX2l0ZW0iOiAiaWlfMUprbUJnMnNPbWY0N056OXBQT09vT3NDIiwKICAgICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICAgfSwKICAgICAgICAgICJwZXJpb2QiOiB7CiAgICAgICAgICAgICJlbmQiOiAxNjM2OTY2NDg4LAogICAgICAgICAgICAic3RhcnQiOiAxNjM0Mjg4MDg4CiAgICAgICAgICB9LAogICAgICAgICAgInBsYW4iOiBudWxsLAogICAgICAgICAgInByaWNlIjogewogICAgICAgICAgICAiaWQiOiAicHJpY2VfMUprbUJmMnNPbWY0N056OVZvbkptdGpUIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJwcmljZSIsCiAgICAgICAgICAgICJhY3RpdmUiOiB0cnVlLAogICAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgICAiY3JlYXRlZCI6IDE2MzQyODgwODcsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgImxvb2t1cF9rZXkiOiBudWxsLAogICAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJuaWNrbmFtZSI6ICJQcmljZSBhZGp1c3RtZW50IGZvciBwYXltZW50IHNjaGVkdWxlIiwKICAgICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAgICJyZWN1cnJpbmciOiBudWxsLAogICAgICAgICAgICAidGF4X2JlaGF2aW9yIjogInVuc3BlY2lmaWVkIiwKICAgICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgICAidHJhbnNmb3JtX3F1YW50aXR5IjogbnVsbCwKICAgICAgICAgICAgInR5cGUiOiAib25lX3RpbWUiLAogICAgICAgICAgICAidW5pdF9hbW91bnQiOiA4LAogICAgICAgICAgICAidW5pdF9hbW91bnRfZGVjaW1hbCI6ICI4IgogICAgICAgICAgfSwKICAgICAgICAgICJwcm9yYXRpb24iOiBmYWxzZSwKICAgICAgICAgICJxdWFudGl0eSI6IDEsCiAgICAgICAgICAic3Vic2NyaXB0aW9uIjogInN1Yl8xSmttQmcyc09tZjQ3Tno5TUdYaWlhcXIiLAogICAgICAgICAgInRheF9hbW91bnRzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidGF4X3JhdGVzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidHlwZSI6ICJpbnZvaWNlaXRlbSIsCiAgICAgICAgICAidW5pcXVlX2lkIjogImlsXzFKa21CZzJzT21mNDdOejlRS3RpQTN3byIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJpZCI6ICJzbGlfMTcyNWIwMnNPbWY0N056OWMzNWYyNmJlIiwKICAgICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAgICJhbW91bnQiOiA5NDY2LAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiZGVzY3JpcHRpb24iOiAiMSDDlyBBYm9ubmVtZW50IG1lbnN1YWxpc2FibGUgLSBzdGFuZGFyZCwgYXNzb2NpYXRpb24sIHllYXIgKGF0ICQ5NC42NiAvIG1vbnRoKSIsCiAgICAgICAgICAiZGlzY291bnRfYW1vdW50cyI6IFsKCiAgICAgICAgICBdLAogICAgICAgICAgImRpc2NvdW50YWJsZSI6IHRydWUsCiAgICAgICAgICAiZGlzY291bnRzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgIH0sCiAgICAgICAgICAicGVyaW9kIjogewogICAgICAgICAgICAiZW5kIjogMTYzNjk2NjQ4OCwKICAgICAgICAgICAgInN0YXJ0IjogMTYzNDI4ODA4OAogICAgICAgICAgfSwKICAgICAgICAgICJwbGFuIjogewogICAgICAgICAgICAiaWQiOiAicHJpY2VfMUprbUJlMnNPbWY0N056OTlXcnBpaXNjIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJwbGFuIiwKICAgICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAgICJhZ2dyZWdhdGVfdXNhZ2UiOiBudWxsLAogICAgICAgICAgICAiYW1vdW50IjogOTQ2NiwKICAgICAgICAgICAgImFtb3VudF9kZWNpbWFsIjogIjk0NjYiLAogICAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgICAiY3JlYXRlZCI6IDE2MzQyODgwODYsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAiaW50ZXJ2YWwiOiAibW9udGgiLAogICAgICAgICAgICAiaW50ZXJ2YWxfY291bnQiOiAxLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICAgICB9LAogICAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgICAicHJvZHVjdCI6ICJwcm9kX0laUUFoYjluTHU0amZOIiwKICAgICAgICAgICAgInRpZXJzIjogbnVsbCwKICAgICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgICAidHJhbnNmb3JtX3VzYWdlIjogbnVsbCwKICAgICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbCwKICAgICAgICAgICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgICAgICAgICB9LAogICAgICAgICAgInByaWNlIjogewogICAgICAgICAgICAiaWQiOiAicHJpY2VfMUprbUJlMnNPbWY0N056OTlXcnBpaXNjIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJwcmljZSIsCiAgICAgICAgICAgICJhY3RpdmUiOiB0cnVlLAogICAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgICAiY3JlYXRlZCI6IDE2MzQyODgwODYsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgImxvb2t1cF9rZXkiOiBudWxsLAogICAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJuaWNrbmFtZSI6IG51bGwsCiAgICAgICAgICAgICJwcm9kdWN0IjogInByb2RfSVpRQWhiOW5MdTRqZk4iLAogICAgICAgICAgICAicmVjdXJyaW5nIjogewogICAgICAgICAgICAgICJhZ2dyZWdhdGVfdXNhZ2UiOiBudWxsLAogICAgICAgICAgICAgICJpbnRlcnZhbCI6ICJtb250aCIsCiAgICAgICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAgICAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsLAogICAgICAgICAgICAgICJ1c2FnZV90eXBlIjogImxpY2Vuc2VkIgogICAgICAgICAgICB9LAogICAgICAgICAgICAidGF4X2JlaGF2aW9yIjogInVuc3BlY2lmaWVkIiwKICAgICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgICAidHJhbnNmb3JtX3F1YW50aXR5IjogbnVsbCwKICAgICAgICAgICAgInR5cGUiOiAicmVjdXJyaW5nIiwKICAgICAgICAgICAgInVuaXRfYW1vdW50IjogOTQ2NiwKICAgICAgICAgICAgInVuaXRfYW1vdW50X2RlY2ltYWwiOiAiOTQ2NiIKICAgICAgICAgIH0sCiAgICAgICAgICAicHJvcmF0aW9uIjogZmFsc2UsCiAgICAgICAgICAicXVhbnRpdHkiOiAxLAogICAgICAgICAgInN1YnNjcmlwdGlvbiI6ICJzdWJfMUprbUJnMnNPbWY0N056OU1HWGlpYXFyIiwKICAgICAgICAgICJzdWJzY3JpcHRpb25faXRlbSI6ICJzaV9LUGJPQlVlRk13QXZwUiIsCiAgICAgICAgICAidGF4X2Ftb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJ0YXhfcmF0ZXMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJ0eXBlIjogInN1YnNjcmlwdGlvbiIsCiAgICAgICAgICAidW5pcXVlX2lkIjogImlsXzFKa21CZzJzT21mNDdOejlsdTVBVkNMaiIKICAgICAgICB9CiAgICAgIF0sCiAgICAgICJoYXNfbW9yZSI6IGZhbHNlLAogICAgICAidG90YWxfY291bnQiOiAzLAogICAgICAidXJsIjogIi92MS9pbnZvaWNlcy9pbl8xSmttQmcyc09tZjQ3Tno5eUtUd3FNNjcvbGluZXMiCiAgICB9LAogICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAibWV0YWRhdGEiOiB7CiAgICB9LAogICAgIm5leHRfcGF5bWVudF9hdHRlbXB0IjogbnVsbCwKICAgICJudW1iZXIiOiAiQkNDMzJCOC0wNTA5IiwKICAgICJvbl9iZWhhbGZfb2YiOiBudWxsLAogICAgInBhaWQiOiB0cnVlLAogICAgInBheW1lbnRfaW50ZW50IjogbnVsbCwKICAgICJwYXltZW50X3NldHRpbmdzIjogewogICAgICAicGF5bWVudF9tZXRob2Rfb3B0aW9ucyI6IG51bGwsCiAgICAgICJwYXltZW50X21ldGhvZF90eXBlcyI6IG51bGwKICAgIH0sCiAgICAicGVyaW9kX2VuZCI6IDE2MzQyODgwODgsCiAgICAicGVyaW9kX3N0YXJ0IjogMTYzNDI4ODA4OCwKICAgICJwb3N0X3BheW1lbnRfY3JlZGl0X25vdGVzX2Ftb3VudCI6IDAsCiAgICAicHJlX3BheW1lbnRfY3JlZGl0X25vdGVzX2Ftb3VudCI6IDAsCiAgICAicXVvdGUiOiBudWxsLAogICAgInJlY2VpcHRfbnVtYmVyIjogbnVsbCwKICAgICJzdGFydGluZ19iYWxhbmNlIjogLTEwNDc0LAogICAgInN0YXRlbWVudF9kZXNjcmlwdG9yIjogbnVsbCwKICAgICJzdGF0dXMiOiAicGFpZCIsCiAgICAic3RhdHVzX3RyYW5zaXRpb25zIjogewogICAgICAiZmluYWxpemVkX2F0IjogMTYzNDI4ODA4OCwKICAgICAgIm1hcmtlZF91bmNvbGxlY3RpYmxlX2F0IjogbnVsbCwKICAgICAgInBhaWRfYXQiOiAxNjM0Mjg4MDg4LAogICAgICAidm9pZGVkX2F0IjogbnVsbAogICAgfSwKICAgICJzdWJzY3JpcHRpb24iOiAic3ViXzFKa21CZzJzT21mNDdOejlNR1hpaWFxciIsCiAgICAic3VidG90YWwiOiAxMDQ3NCwKICAgICJ0YXgiOiBudWxsLAogICAgInRheF9wZXJjZW50IjogbnVsbCwKICAgICJ0b3RhbCI6IDEwNDc0LAogICAgInRvdGFsX2Rpc2NvdW50X2Ftb3VudHMiOiBbCgogICAgXSwKICAgICJ0b3RhbF90YXhfYW1vdW50cyI6IFsKCiAgICBdLAogICAgInRyYW5zZmVyX2RhdGEiOiBudWxsLAogICAgIndlYmhvb2tzX2RlbGl2ZXJlZF9hdCI6IDE2MzQyODgwODgKICB9LAogICJsaXZlbW9kZSI6IGZhbHNlLAogICJtZXRhZGF0YSI6IHsKICB9LAogICJuZXh0X3BlbmRpbmdfaW52b2ljZV9pdGVtX2ludm9pY2UiOiBudWxsLAogICJwYXVzZV9jb2xsZWN0aW9uIjogbnVsbCwKICAicGF5bWVudF9zZXR0aW5ncyI6IHsKICAgICJwYXltZW50X21ldGhvZF9vcHRpb25zIjogbnVsbCwKICAgICJwYXltZW50X21ldGhvZF90eXBlcyI6IG51bGwKICB9LAogICJwZW5kaW5nX2ludm9pY2VfaXRlbV9pbnRlcnZhbCI6IG51bGwsCiAgInBlbmRpbmdfc2V0dXBfaW50ZW50IjogbnVsbCwKICAicGVuZGluZ191cGRhdGUiOiBudWxsLAogICJwbGFuIjogewogICAgImlkIjogInByaWNlXzFKa21CZTJzT21mNDdOejk5V3JwaWlzYyIsCiAgICAib2JqZWN0IjogInBsYW4iLAogICAgImFjdGl2ZSI6IHRydWUsCiAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICJhbW91bnQiOiA5NDY2LAogICAgImFtb3VudF9kZWNpbWFsIjogIjk0NjYiLAogICAgImJpbGxpbmdfc2NoZW1lIjogInBlcl91bml0IiwKICAgICJjcmVhdGVkIjogMTYzNDI4ODA4NiwKICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICJpbnRlcnZhbF9jb3VudCI6IDEsCiAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICJtZXRhZGF0YSI6IHsKICAgIH0sCiAgICAibmlja25hbWUiOiBudWxsLAogICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAidGllcnMiOiBudWxsLAogICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgInRyYW5zZm9ybV91c2FnZSI6IG51bGwsCiAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsLAogICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgfSwKICAicXVhbnRpdHkiOiAxLAogICJzY2hlZHVsZSI6IG51bGwsCiAgInN0YXJ0IjogMTYzNDI4ODA4OCwKICAic3RhcnRfZGF0ZSI6IDE2MzQyODgwODgsCiAgInN0YXR1cyI6ICJhY3RpdmUiLAogICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgInRyYW5zZmVyX2RhdGEiOiBudWxsLAogICJ0cmlhbF9lbmQiOiBudWxsLAogICJ0cmlhbF9zdGFydCI6IG51bGwKfQo= - recorded_at: Fri, 15 Oct 2021 08:54:49 GMT + ewogICJpZCI6ICJzdWJfMUpsclNjMnNPbWY0N056OWlHbzJzdkFCIiwKICAib2JqZWN0IjogInN1YnNjcmlwdGlvbiIsCiAgImFwcGxpY2F0aW9uX2ZlZV9wZXJjZW50IjogbnVsbCwKICAiYXV0b21hdGljX3RheCI6IHsKICAgICJlbmFibGVkIjogZmFsc2UKICB9LAogICJiaWxsaW5nIjogImNoYXJnZV9hdXRvbWF0aWNhbGx5IiwKICAiYmlsbGluZ19jeWNsZV9hbmNob3IiOiAxNjM0NTQ2Njg2LAogICJiaWxsaW5nX3RocmVzaG9sZHMiOiBudWxsLAogICJjYW5jZWxfYXQiOiAxNjY2MDgyNjgzLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5jZWxlZF9hdCI6IDE2MzQ1NDY2ODYsCiAgImNvbGxlY3Rpb25fbWV0aG9kIjogImNoYXJnZV9hdXRvbWF0aWNhbGx5IiwKICAiY3JlYXRlZCI6IDE2MzQ1NDY2ODYsCiAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE2MzcyMjUwODYsCiAgImN1cnJlbnRfcGVyaW9kX3N0YXJ0IjogMTYzNDU0NjY4NiwKICAiY3VzdG9tZXIiOiAiY3VzXzhFMnlzOXpEWmdldFdYIiwKICAiZGF5c191bnRpbF9kdWUiOiBudWxsLAogICJkZWZhdWx0X3BheW1lbnRfbWV0aG9kIjogInBtXzFKbHJTWDJzT21mNDdOejlPNHg4SXZBdCIsCiAgImRlZmF1bHRfc291cmNlIjogbnVsbCwKICAiZGVmYXVsdF90YXhfcmF0ZXMiOiBbCgogIF0sCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRfYXQiOiBudWxsLAogICJpbnZvaWNlX2N1c3RvbWVyX2JhbGFuY2Vfc2V0dGluZ3MiOiB7CiAgICAiY29uc3VtZV9hcHBsaWVkX2JhbGFuY2Vfb25fdm9pZCI6IHRydWUKICB9LAogICJpdGVtcyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAgICAgewogICAgICAgICJpZCI6ICJzaV9LUWl1QW1CUWRQUUo1cyIsCiAgICAgICAgIm9iamVjdCI6ICJzdWJzY3JpcHRpb25faXRlbSIsCiAgICAgICAgImJpbGxpbmdfdGhyZXNob2xkcyI6IG51bGwsCiAgICAgICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg2LAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICB9LAogICAgICAgICJwbGFuIjogewogICAgICAgICAgImlkIjogInByaWNlXzFKbHJTYTJzT21mNDdOejlaSzlIY29KRSIsCiAgICAgICAgICAib2JqZWN0IjogInBsYW4iLAogICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICJhbW91bnQiOiA5NDY2LAogICAgICAgICAgImFtb3VudF9kZWNpbWFsIjogIjk0NjYiLAogICAgICAgICAgImJpbGxpbmdfc2NoZW1lIjogInBlcl91bml0IiwKICAgICAgICAgICJjcmVhdGVkIjogMTYzNDU0NjY4NCwKICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICAgICAgICJpbnRlcnZhbF9jb3VudCI6IDEsCiAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgIH0sCiAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAidGllcnMiOiBudWxsLAogICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgInRyYW5zZm9ybV91c2FnZSI6IG51bGwsCiAgICAgICAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsLAogICAgICAgICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgICAgICAgfSwKICAgICAgICAicHJpY2UiOiB7CiAgICAgICAgICAiaWQiOiAicHJpY2VfMUpsclNhMnNPbWY0N056OVpLOUhjb0pFIiwKICAgICAgICAgICJvYmplY3QiOiAicHJpY2UiLAogICAgICAgICAgImFjdGl2ZSI6IHRydWUsCiAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg0LAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICJsb29rdXBfa2V5IjogbnVsbCwKICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgIH0sCiAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAicmVjdXJyaW5nIjogewogICAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbCwKICAgICAgICAgICAgInVzYWdlX3R5cGUiOiAibGljZW5zZWQiCiAgICAgICAgICB9LAogICAgICAgICAgInRheF9iZWhhdmlvciI6ICJ1bnNwZWNpZmllZCIsCiAgICAgICAgICAidGllcnNfbW9kZSI6IG51bGwsCiAgICAgICAgICAidHJhbnNmb3JtX3F1YW50aXR5IjogbnVsbCwKICAgICAgICAgICJ0eXBlIjogInJlY3VycmluZyIsCiAgICAgICAgICAidW5pdF9hbW91bnQiOiA5NDY2LAogICAgICAgICAgInVuaXRfYW1vdW50X2RlY2ltYWwiOiAiOTQ2NiIKICAgICAgICB9LAogICAgICAgICJxdWFudGl0eSI6IDEsCiAgICAgICAgInN1YnNjcmlwdGlvbiI6ICJzdWJfMUpsclNjMnNPbWY0N056OWlHbzJzdkFCIiwKICAgICAgICAidGF4X3JhdGVzIjogWwoKICAgICAgICBdCiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9zdWJzY3JpcHRpb25faXRlbXM/c3Vic2NyaXB0aW9uPXN1Yl8xSmxyU2Myc09tZjQ3Tno5aUdvMnN2QUIiCiAgfSwKICAibGF0ZXN0X2ludm9pY2UiOiB7CiAgICAiaWQiOiAiaW5fMUpsclNjMnNPbWY0N056OW40bk1yVGdjIiwKICAgICJvYmplY3QiOiAiaW52b2ljZSIsCiAgICAiYWNjb3VudF9jb3VudHJ5IjogIkZSIiwKICAgICJhY2NvdW50X25hbWUiOiAiU2xlZWRlIiwKICAgICJhY2NvdW50X3RheF9pZHMiOiBudWxsLAogICAgImFtb3VudF9kdWUiOiAwLAogICAgImFtb3VudF9wYWlkIjogMCwKICAgICJhbW91bnRfcmVtYWluaW5nIjogMCwKICAgICJhcHBsaWNhdGlvbl9mZWVfYW1vdW50IjogbnVsbCwKICAgICJhdHRlbXB0X2NvdW50IjogMCwKICAgICJhdHRlbXB0ZWQiOiB0cnVlLAogICAgImF1dG9fYWR2YW5jZSI6IGZhbHNlLAogICAgImF1dG9tYXRpY190YXgiOiB7CiAgICAgICJlbmFibGVkIjogZmFsc2UsCiAgICAgICJzdGF0dXMiOiBudWxsCiAgICB9LAogICAgImJpbGxpbmciOiAiY2hhcmdlX2F1dG9tYXRpY2FsbHkiLAogICAgImJpbGxpbmdfcmVhc29uIjogInN1YnNjcmlwdGlvbl9jcmVhdGUiLAogICAgImNoYXJnZSI6IG51bGwsCiAgICAiY29sbGVjdGlvbl9tZXRob2QiOiAiY2hhcmdlX2F1dG9tYXRpY2FsbHkiLAogICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg2LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiY3VzdG9tX2ZpZWxkcyI6IG51bGwsCiAgICAiY3VzdG9tZXIiOiAiY3VzXzhFMnlzOXpEWmdldFdYIiwKICAgICJjdXN0b21lcl9hZGRyZXNzIjogbnVsbCwKICAgICJjdXN0b21lcl9lbWFpbCI6ICJsdWNpbGUuc2VndWluQGxpdmUuZnIiLAogICAgImN1c3RvbWVyX25hbWUiOiBudWxsLAogICAgImN1c3RvbWVyX3Bob25lIjogbnVsbCwKICAgICJjdXN0b21lcl9zaGlwcGluZyI6IG51bGwsCiAgICAiY3VzdG9tZXJfdGF4X2V4ZW1wdCI6ICJub25lIiwKICAgICJjdXN0b21lcl90YXhfaWRzIjogWwoKICAgIF0sCiAgICAiZGVmYXVsdF9wYXltZW50X21ldGhvZCI6IG51bGwsCiAgICAiZGVmYXVsdF9zb3VyY2UiOiBudWxsLAogICAgImRlZmF1bHRfdGF4X3JhdGVzIjogWwoKICAgIF0sCiAgICAiZGVzY3JpcHRpb24iOiBudWxsLAogICAgImRpc2NvdW50IjogewogICAgICAiaWQiOiAiZGlfMUpsclNjMnNPbWY0N056OXJ4TlJqOFczIiwKICAgICAgIm9iamVjdCI6ICJkaXNjb3VudCIsCiAgICAgICJjaGVja291dF9zZXNzaW9uIjogbnVsbCwKICAgICAgImNvdXBvbiI6IHsKICAgICAgICAiaWQiOiAiR0lNRTNFVVIiLAogICAgICAgICJvYmplY3QiOiAiY291cG9uIiwKICAgICAgICAiYW1vdW50X29mZiI6IDMwMCwKICAgICAgICAiY3JlYXRlZCI6IDE2MDk3NTc5NjQsCiAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgImR1cmF0aW9uIjogIm9uY2UiLAogICAgICAgICJkdXJhdGlvbl9pbl9tb250aHMiOiBudWxsLAogICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICJtYXhfcmVkZW1wdGlvbnMiOiBudWxsLAogICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICB9LAogICAgICAgICJuYW1lIjogbnVsbCwKICAgICAgICAicGVyY2VudF9vZmYiOiBudWxsLAogICAgICAgICJyZWRlZW1fYnkiOiAxNjQxMjkxOTU5LAogICAgICAgICJ0aW1lc19yZWRlZW1lZCI6IDc5LAogICAgICAgICJ2YWxpZCI6IHRydWUKICAgICAgfSwKICAgICAgImN1c3RvbWVyIjogImN1c184RTJ5czl6RFpnZXRXWCIsCiAgICAgICJlbmQiOiBudWxsLAogICAgICAiaW52b2ljZSI6IG51bGwsCiAgICAgICJpbnZvaWNlX2l0ZW0iOiBudWxsLAogICAgICAicHJvbW90aW9uX2NvZGUiOiBudWxsLAogICAgICAic3RhcnQiOiAxNjM0NTQ2Njg2LAogICAgICAic3Vic2NyaXB0aW9uIjogInN1Yl8xSmxyU2Myc09tZjQ3Tno5aUdvMnN2QUIiCiAgICB9LAogICAgImRpc2NvdW50cyI6IFsKICAgICAgImRpXzFKbHJTYzJzT21mNDdOejlyeE5SajhXMyIKICAgIF0sCiAgICAiZHVlX2RhdGUiOiBudWxsLAogICAgImVuZGluZ19iYWxhbmNlIjogMCwKICAgICJmb290ZXIiOiBudWxsLAogICAgImhvc3RlZF9pbnZvaWNlX3VybCI6ICJodHRwczovL2ludm9pY2Uuc3RyaXBlLmNvbS9pL2FjY3RfMTAzckU2MnNPbWY0N056OS90ZXN0X1lXTmpkRjh4TUROeVJUWXljMDl0WmpRM1RubzVMRjlMVVdsMVRHaHlhVGhtUzNSRVQxWnJkMFZ3TTNaWWJYVnBVVXRsU1VkaDAxMDB6OTM1bWxPViIsCiAgICAiaW52b2ljZV9wZGYiOiAiaHR0cHM6Ly9wYXkuc3RyaXBlLmNvbS9pbnZvaWNlL2FjY3RfMTAzckU2MnNPbWY0N056OS90ZXN0X1lXTmpkRjh4TUROeVJUWXljMDl0WmpRM1RubzVMRjlMVVdsMVRHaHlhVGhtUzNSRVQxWnJkMFZ3TTNaWWJYVnBVVXRsU1VkaDAxMDB6OTM1bWxPVi9wZGYiLAogICAgImxhc3RfZmluYWxpemF0aW9uX2Vycm9yIjogbnVsbCwKICAgICJsaW5lcyI6IHsKICAgICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICAgImRhdGEiOiBbCiAgICAgICAgewogICAgICAgICAgImlkIjogImlpXzFKbHJTYzJzT21mNDdOejlORjREVzZsciIsCiAgICAgICAgICAib2JqZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgICAiYW1vdW50IjogMTAwMCwKICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgImRlc2NyaXB0aW9uIjogIkTDqWNvdXBldXNlIGxhc2VyIiwKICAgICAgICAgICJkaXNjb3VudF9hbW91bnRzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgImFtb3VudCI6IDI4LAogICAgICAgICAgICAgICJkaXNjb3VudCI6ICJkaV8xSmxyU2Myc09tZjQ3Tno5cnhOUmo4VzMiCiAgICAgICAgICAgIH0KICAgICAgICAgIF0sCiAgICAgICAgICAiZGlzY291bnRhYmxlIjogdHJ1ZSwKICAgICAgICAgICJkaXNjb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJpbnZvaWNlX2l0ZW0iOiAiaWlfMUpsclNjMnNPbWY0N056OU5GNERXNmxyIiwKICAgICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICAgfSwKICAgICAgICAgICJwZXJpb2QiOiB7CiAgICAgICAgICAgICJlbmQiOiAxNjM3MjI1MDg2LAogICAgICAgICAgICAic3RhcnQiOiAxNjM0NTQ2Njg2CiAgICAgICAgICB9LAogICAgICAgICAgInBsYW4iOiBudWxsLAogICAgICAgICAgInByaWNlIjogewogICAgICAgICAgICAiaWQiOiAicHJpY2VfMUpsclNiMnNPbWY0N056OXFDSW5SSFduIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJwcmljZSIsCiAgICAgICAgICAgICJhY3RpdmUiOiB0cnVlLAogICAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgICAiY3JlYXRlZCI6IDE2MzQ1NDY2ODUsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgImxvb2t1cF9rZXkiOiBudWxsLAogICAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJuaWNrbmFtZSI6ICJSZXNlcnZhdGlvbnMgZm9yIHBheW1lbnQgc2NoZWR1bGUiLAogICAgICAgICAgICAicHJvZHVjdCI6ICJwcm9kX0laUHlIcE1DbDM4aVFsIiwKICAgICAgICAgICAgInJlY3VycmluZyI6IG51bGwsCiAgICAgICAgICAgICJ0YXhfYmVoYXZpb3IiOiAidW5zcGVjaWZpZWQiLAogICAgICAgICAgICAidGllcnNfbW9kZSI6IG51bGwsCiAgICAgICAgICAgICJ0cmFuc2Zvcm1fcXVhbnRpdHkiOiBudWxsLAogICAgICAgICAgICAidHlwZSI6ICJvbmVfdGltZSIsCiAgICAgICAgICAgICJ1bml0X2Ftb3VudCI6IDEwMDAsCiAgICAgICAgICAgICJ1bml0X2Ftb3VudF9kZWNpbWFsIjogIjEwMDAiCiAgICAgICAgICB9LAogICAgICAgICAgInByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICAgInF1YW50aXR5IjogMSwKICAgICAgICAgICJzdWJzY3JpcHRpb24iOiAic3ViXzFKbHJTYzJzT21mNDdOejlpR28yc3ZBQiIsCiAgICAgICAgICAidGF4X2Ftb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJ0YXhfcmF0ZXMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJ0eXBlIjogImludm9pY2VpdGVtIiwKICAgICAgICAgICJ1bmlxdWVfaWQiOiAiaWxfMUpsclNjMnNPbWY0N056OXBRYkhFajBZIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIjogImlpXzFKbHJTYzJzT21mNDdOejlDZTA5cGpOaiIsCiAgICAgICAgICAib2JqZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgICAiYW1vdW50IjogOCwKICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgImRlc2NyaXB0aW9uIjogIkFib25uZW1lbnQgbWVuc3VhbGlzYWJsZSAtIHN0YW5kYXJkLCBhc3NvY2lhdGlvbiwgeWVhciIsCiAgICAgICAgICAiZGlzY291bnRfYW1vdW50cyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJhbW91bnQiOiAwLAogICAgICAgICAgICAgICJkaXNjb3VudCI6ICJkaV8xSmxyU2Myc09tZjQ3Tno5cnhOUmo4VzMiCiAgICAgICAgICAgIH0KICAgICAgICAgIF0sCiAgICAgICAgICAiZGlzY291bnRhYmxlIjogdHJ1ZSwKICAgICAgICAgICJkaXNjb3VudHMiOiBbCgogICAgICAgICAgXSwKICAgICAgICAgICJpbnZvaWNlX2l0ZW0iOiAiaWlfMUpsclNjMnNPbWY0N056OUNlMDlwak5qIiwKICAgICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICAgfSwKICAgICAgICAgICJwZXJpb2QiOiB7CiAgICAgICAgICAgICJlbmQiOiAxNjM3MjI1MDg2LAogICAgICAgICAgICAic3RhcnQiOiAxNjM0NTQ2Njg2CiAgICAgICAgICB9LAogICAgICAgICAgInBsYW4iOiBudWxsLAogICAgICAgICAgInByaWNlIjogewogICAgICAgICAgICAiaWQiOiAicHJpY2VfMUpsclNiMnNPbWY0N056OWpnR1ZTdVQ3IiwKICAgICAgICAgICAgIm9iamVjdCI6ICJwcmljZSIsCiAgICAgICAgICAgICJhY3RpdmUiOiB0cnVlLAogICAgICAgICAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgICAgICAgICAiY3JlYXRlZCI6IDE2MzQ1NDY2ODUsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgImxvb2t1cF9rZXkiOiBudWxsLAogICAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJuaWNrbmFtZSI6ICJQcmljZSBhZGp1c3RtZW50IGZvciBwYXltZW50IHNjaGVkdWxlIiwKICAgICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAgICJyZWN1cnJpbmciOiBudWxsLAogICAgICAgICAgICAidGF4X2JlaGF2aW9yIjogInVuc3BlY2lmaWVkIiwKICAgICAgICAgICAgInRpZXJzX21vZGUiOiBudWxsLAogICAgICAgICAgICAidHJhbnNmb3JtX3F1YW50aXR5IjogbnVsbCwKICAgICAgICAgICAgInR5cGUiOiAib25lX3RpbWUiLAogICAgICAgICAgICAidW5pdF9hbW91bnQiOiA4LAogICAgICAgICAgICAidW5pdF9hbW91bnRfZGVjaW1hbCI6ICI4IgogICAgICAgICAgfSwKICAgICAgICAgICJwcm9yYXRpb24iOiBmYWxzZSwKICAgICAgICAgICJxdWFudGl0eSI6IDEsCiAgICAgICAgICAic3Vic2NyaXB0aW9uIjogInN1Yl8xSmxyU2Myc09tZjQ3Tno5aUdvMnN2QUIiLAogICAgICAgICAgInRheF9hbW91bnRzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidGF4X3JhdGVzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidHlwZSI6ICJpbnZvaWNlaXRlbSIsCiAgICAgICAgICAidW5pcXVlX2lkIjogImlsXzFKbHJTYzJzT21mNDdOejlkOURoeHdxUyIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJpZCI6ICJzbGlfMTgyODg1MnNPbWY0N056OTVjYzlmOWFhIiwKICAgICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAgICJhbW91bnQiOiA5NDY2LAogICAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiZGVzY3JpcHRpb24iOiAiMSDDlyBBYm9ubmVtZW50IG1lbnN1YWxpc2FibGUgLSBzdGFuZGFyZCwgYXNzb2NpYXRpb24sIHllYXIgKGF0ICQ5NC42NiAvIG1vbnRoKSIsCiAgICAgICAgICAiZGlzY291bnRfYW1vdW50cyI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJhbW91bnQiOiAyNzIsCiAgICAgICAgICAgICAgImRpc2NvdW50IjogImRpXzFKbHJTYzJzT21mNDdOejlyeE5SajhXMyIKICAgICAgICAgICAgfQogICAgICAgICAgXSwKICAgICAgICAgICJkaXNjb3VudGFibGUiOiB0cnVlLAogICAgICAgICAgImRpc2NvdW50cyI6IFsKCiAgICAgICAgICBdLAogICAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAibWV0YWRhdGEiOiB7CiAgICAgICAgICB9LAogICAgICAgICAgInBlcmlvZCI6IHsKICAgICAgICAgICAgImVuZCI6IDE2MzcyMjUwODYsCiAgICAgICAgICAgICJzdGFydCI6IDE2MzQ1NDY2ODYKICAgICAgICAgIH0sCiAgICAgICAgICAicGxhbiI6IHsKICAgICAgICAgICAgImlkIjogInByaWNlXzFKbHJTYTJzT21mNDdOejlaSzlIY29KRSIsCiAgICAgICAgICAgICJvYmplY3QiOiAicGxhbiIsCiAgICAgICAgICAgICJhY3RpdmUiOiB0cnVlLAogICAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICAgImFtb3VudCI6IDk0NjYsCiAgICAgICAgICAgICJhbW91bnRfZGVjaW1hbCI6ICI5NDY2IiwKICAgICAgICAgICAgImJpbGxpbmdfc2NoZW1lIjogInBlcl91bml0IiwKICAgICAgICAgICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg0LAogICAgICAgICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAgICAgICAgICAgImludGVydmFsIjogIm1vbnRoIiwKICAgICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAgICJtZXRhZGF0YSI6IHsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgIm5pY2tuYW1lIjogbnVsbCwKICAgICAgICAgICAgInByb2R1Y3QiOiAicHJvZF9JWlFBaGI5bkx1NGpmTiIsCiAgICAgICAgICAgICJ0aWVycyI6IG51bGwsCiAgICAgICAgICAgICJ0aWVyc19tb2RlIjogbnVsbCwKICAgICAgICAgICAgInRyYW5zZm9ybV91c2FnZSI6IG51bGwsCiAgICAgICAgICAgICJ0cmlhbF9wZXJpb2RfZGF5cyI6IG51bGwsCiAgICAgICAgICAgICJ1c2FnZV90eXBlIjogImxpY2Vuc2VkIgogICAgICAgICAgfSwKICAgICAgICAgICJwcmljZSI6IHsKICAgICAgICAgICAgImlkIjogInByaWNlXzFKbHJTYTJzT21mNDdOejlaSzlIY29KRSIsCiAgICAgICAgICAgICJvYmplY3QiOiAicHJpY2UiLAogICAgICAgICAgICAiYWN0aXZlIjogdHJ1ZSwKICAgICAgICAgICAgImJpbGxpbmdfc2NoZW1lIjogInBlcl91bml0IiwKICAgICAgICAgICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg0LAogICAgICAgICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAgICAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAgICJsb29rdXBfa2V5IjogbnVsbCwKICAgICAgICAgICAgIm1ldGFkYXRhIjogewogICAgICAgICAgICB9LAogICAgICAgICAgICAibmlja25hbWUiOiBudWxsLAogICAgICAgICAgICAicHJvZHVjdCI6ICJwcm9kX0laUUFoYjluTHU0amZOIiwKICAgICAgICAgICAgInJlY3VycmluZyI6IHsKICAgICAgICAgICAgICAiYWdncmVnYXRlX3VzYWdlIjogbnVsbCwKICAgICAgICAgICAgICAiaW50ZXJ2YWwiOiAibW9udGgiLAogICAgICAgICAgICAgICJpbnRlcnZhbF9jb3VudCI6IDEsCiAgICAgICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbCwKICAgICAgICAgICAgICAidXNhZ2VfdHlwZSI6ICJsaWNlbnNlZCIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgInRheF9iZWhhdmlvciI6ICJ1bnNwZWNpZmllZCIsCiAgICAgICAgICAgICJ0aWVyc19tb2RlIjogbnVsbCwKICAgICAgICAgICAgInRyYW5zZm9ybV9xdWFudGl0eSI6IG51bGwsCiAgICAgICAgICAgICJ0eXBlIjogInJlY3VycmluZyIsCiAgICAgICAgICAgICJ1bml0X2Ftb3VudCI6IDk0NjYsCiAgICAgICAgICAgICJ1bml0X2Ftb3VudF9kZWNpbWFsIjogIjk0NjYiCiAgICAgICAgICB9LAogICAgICAgICAgInByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICAgInF1YW50aXR5IjogMSwKICAgICAgICAgICJzdWJzY3JpcHRpb24iOiAic3ViXzFKbHJTYzJzT21mNDdOejlpR28yc3ZBQiIsCiAgICAgICAgICAic3Vic2NyaXB0aW9uX2l0ZW0iOiAic2lfS1FpdUFtQlFkUFFKNXMiLAogICAgICAgICAgInRheF9hbW91bnRzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidGF4X3JhdGVzIjogWwoKICAgICAgICAgIF0sCiAgICAgICAgICAidHlwZSI6ICJzdWJzY3JpcHRpb24iLAogICAgICAgICAgInVuaXF1ZV9pZCI6ICJpbF8xSmxyU2Myc09tZjQ3Tno5NUVLT21KT1ciCiAgICAgICAgfQogICAgICBdLAogICAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICAgInRvdGFsX2NvdW50IjogMywKICAgICAgInVybCI6ICIvdjEvaW52b2ljZXMvaW5fMUpsclNjMnNPbWY0N056OW40bk1yVGdjL2xpbmVzIgogICAgfSwKICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjogewogICAgfSwKICAgICJuZXh0X3BheW1lbnRfYXR0ZW1wdCI6IG51bGwsCiAgICAibnVtYmVyIjogIkJDQzMyQjgtMDUxNyIsCiAgICAib25fYmVoYWxmX29mIjogbnVsbCwKICAgICJwYWlkIjogdHJ1ZSwKICAgICJwYXltZW50X2ludGVudCI6IG51bGwsCiAgICAicGF5bWVudF9zZXR0aW5ncyI6IHsKICAgICAgInBheW1lbnRfbWV0aG9kX29wdGlvbnMiOiBudWxsLAogICAgICAicGF5bWVudF9tZXRob2RfdHlwZXMiOiBudWxsCiAgICB9LAogICAgInBlcmlvZF9lbmQiOiAxNjM0NTQ2Njg2LAogICAgInBlcmlvZF9zdGFydCI6IDE2MzQ1NDY2ODYsCiAgICAicG9zdF9wYXltZW50X2NyZWRpdF9ub3Rlc19hbW91bnQiOiAwLAogICAgInByZV9wYXltZW50X2NyZWRpdF9ub3Rlc19hbW91bnQiOiAwLAogICAgInF1b3RlIjogbnVsbCwKICAgICJyZWNlaXB0X251bWJlciI6IG51bGwsCiAgICAic3RhcnRpbmdfYmFsYW5jZSI6IC0xMDE3NCwKICAgICJzdGF0ZW1lbnRfZGVzY3JpcHRvciI6IG51bGwsCiAgICAic3RhdHVzIjogInBhaWQiLAogICAgInN0YXR1c190cmFuc2l0aW9ucyI6IHsKICAgICAgImZpbmFsaXplZF9hdCI6IDE2MzQ1NDY2ODYsCiAgICAgICJtYXJrZWRfdW5jb2xsZWN0aWJsZV9hdCI6IG51bGwsCiAgICAgICJwYWlkX2F0IjogMTYzNDU0NjY4NiwKICAgICAgInZvaWRlZF9hdCI6IG51bGwKICAgIH0sCiAgICAic3Vic2NyaXB0aW9uIjogInN1Yl8xSmxyU2Myc09tZjQ3Tno5aUdvMnN2QUIiLAogICAgInN1YnRvdGFsIjogMTA0NzQsCiAgICAidGF4IjogbnVsbCwKICAgICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgICAidG90YWwiOiAxMDE3NCwKICAgICJ0b3RhbF9kaXNjb3VudF9hbW91bnRzIjogWwogICAgICB7CiAgICAgICAgImFtb3VudCI6IDMwMCwKICAgICAgICAiZGlzY291bnQiOiAiZGlfMUpsclNjMnNPbWY0N056OXJ4TlJqOFczIgogICAgICB9CiAgICBdLAogICAgInRvdGFsX3RheF9hbW91bnRzIjogWwoKICAgIF0sCiAgICAidHJhbnNmZXJfZGF0YSI6IG51bGwsCiAgICAid2ViaG9va3NfZGVsaXZlcmVkX2F0IjogMTYzNDU0NjY4NgogIH0sCiAgImxpdmVtb2RlIjogZmFsc2UsCiAgIm1ldGFkYXRhIjogewogIH0sCiAgIm5leHRfcGVuZGluZ19pbnZvaWNlX2l0ZW1faW52b2ljZSI6IG51bGwsCiAgInBhdXNlX2NvbGxlY3Rpb24iOiBudWxsLAogICJwYXltZW50X3NldHRpbmdzIjogewogICAgInBheW1lbnRfbWV0aG9kX29wdGlvbnMiOiBudWxsLAogICAgInBheW1lbnRfbWV0aG9kX3R5cGVzIjogbnVsbAogIH0sCiAgInBlbmRpbmdfaW52b2ljZV9pdGVtX2ludGVydmFsIjogbnVsbCwKICAicGVuZGluZ19zZXR1cF9pbnRlbnQiOiBudWxsLAogICJwZW5kaW5nX3VwZGF0ZSI6IG51bGwsCiAgInBsYW4iOiB7CiAgICAiaWQiOiAicHJpY2VfMUpsclNhMnNPbWY0N056OVpLOUhjb0pFIiwKICAgICJvYmplY3QiOiAicGxhbiIsCiAgICAiYWN0aXZlIjogdHJ1ZSwKICAgICJhZ2dyZWdhdGVfdXNhZ2UiOiBudWxsLAogICAgImFtb3VudCI6IDk0NjYsCiAgICAiYW1vdW50X2RlY2ltYWwiOiAiOTQ2NiIsCiAgICAiYmlsbGluZ19zY2hlbWUiOiAicGVyX3VuaXQiLAogICAgImNyZWF0ZWQiOiAxNjM0NTQ2Njg0LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiaW50ZXJ2YWwiOiAibW9udGgiLAogICAgImludGVydmFsX2NvdW50IjogMSwKICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjogewogICAgfSwKICAgICJuaWNrbmFtZSI6IG51bGwsCiAgICAicHJvZHVjdCI6ICJwcm9kX0laUUFoYjluTHU0amZOIiwKICAgICJ0aWVycyI6IG51bGwsCiAgICAidGllcnNfbW9kZSI6IG51bGwsCiAgICAidHJhbnNmb3JtX3VzYWdlIjogbnVsbCwKICAgICJ0cmlhbF9wZXJpb2RfZGF5cyI6IG51bGwsCiAgICAidXNhZ2VfdHlwZSI6ICJsaWNlbnNlZCIKICB9LAogICJxdWFudGl0eSI6IDEsCiAgInNjaGVkdWxlIjogbnVsbCwKICAic3RhcnQiOiAxNjM0NTQ2Njg2LAogICJzdGFydF9kYXRlIjogMTYzNDU0NjY4NiwKICAic3RhdHVzIjogImFjdGl2ZSIsCiAgInRheF9wZXJjZW50IjogbnVsbCwKICAidHJhbnNmZXJfZGF0YSI6IG51bGwsCiAgInRyaWFsX2VuZCI6IG51bGwsCiAgInRyaWFsX3N0YXJ0IjogbnVsbAp9Cg== + recorded_at: Mon, 18 Oct 2021 08:44:48 GMT - request: method: get - uri: https://api.stripe.com/v1/subscriptions/sub_1JkmBg2sOmf47Nz9MGXiiaqr + uri: https://api.stripe.com/v1/subscriptions/sub_1JlrSc2sOmf47Nz9iGo2svAB body: encoding: US-ASCII string: '' @@ -3810,7 +3812,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_jH8eY0zmweOaLs","request_duration_ms":1834}}' + - '{"last_request_metrics":{"request_id":"req_dV7qFlSzKcFLZu","request_duration_ms":2117}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -3829,7 +3831,7 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:50 GMT + - Mon, 18 Oct 2021 08:44:48 GMT Content-Type: - application/json Content-Length: @@ -3849,7 +3851,7 @@ http_interactions: Cache-Control: - no-cache, no-store Request-Id: - - req_YwajQrzGbIjeAO + - req_RPx14pHT5PJgSk Stripe-Version: - '2019-08-14' Strict-Transport-Security: @@ -3858,25 +3860,25 @@ http_interactions: encoding: UTF-8 string: | { - "id": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "id": "sub_1JlrSc2sOmf47Nz9iGo2svAB", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "enabled": false }, "billing": "charge_automatically", - "billing_cycle_anchor": 1634288088, + "billing_cycle_anchor": 1634546686, "billing_thresholds": null, - "cancel_at": 1665824085, + "cancel_at": 1666082683, "cancel_at_period_end": false, - "canceled_at": 1634288088, + "canceled_at": 1634546686, "collection_method": "charge_automatically", - "created": 1634288088, - "current_period_end": 1636966488, - "current_period_start": 1634288088, + "created": 1634546686, + "current_period_end": 1637225086, + "current_period_start": 1634546686, "customer": "cus_8E2ys9zDZgetWX", "days_until_due": null, - "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_payment_method": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "default_source": null, "default_tax_rates": [ @@ -3890,21 +3892,21 @@ http_interactions: "object": "list", "data": [ { - "id": "si_KPbOBUeFMwAvpR", + "id": "si_KQiuAmBQdPQJ5s", "object": "subscription_item", "billing_thresholds": null, - "created": 1634288088, + "created": 1634546686, "metadata": { }, "plan": { - "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", "object": "plan", "active": true, "aggregate_usage": null, "amount": 9466, "amount_decimal": "9466", "billing_scheme": "per_unit", - "created": 1634288086, + "created": 1634546684, "currency": "usd", "interval": "month", "interval_count": 1, @@ -3920,11 +3922,11 @@ http_interactions: "usage_type": "licensed" }, "price": { - "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", "object": "price", "active": true, "billing_scheme": "per_unit", - "created": 1634288086, + "created": 1634546684, "currency": "usd", "livemode": false, "lookup_key": null, @@ -3947,7 +3949,7 @@ http_interactions: "unit_amount_decimal": "9466" }, "quantity": 1, - "subscription": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "subscription": "sub_1JlrSc2sOmf47Nz9iGo2svAB", "tax_rates": [ ] @@ -3955,9 +3957,9 @@ http_interactions: ], "has_more": false, "total_count": 1, - "url": "/v1/subscription_items?subscription=sub_1JkmBg2sOmf47Nz9MGXiiaqr" + "url": "/v1/subscription_items?subscription=sub_1JlrSc2sOmf47Nz9iGo2svAB" }, - "latest_invoice": "in_1JkmBg2sOmf47Nz9yKTwqM67", + "latest_invoice": "in_1JlrSc2sOmf47Nz9n4nMrTgc", "livemode": false, "metadata": { }, @@ -3971,14 +3973,14 @@ http_interactions: "pending_setup_intent": null, "pending_update": null, "plan": { - "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", "object": "plan", "active": true, "aggregate_usage": null, "amount": 9466, "amount_decimal": "9466", "billing_scheme": "per_unit", - "created": 1634288086, + "created": 1634546684, "currency": "usd", "interval": "month", "interval_count": 1, @@ -3995,18 +3997,18 @@ http_interactions: }, "quantity": 1, "schedule": null, - "start": 1634288088, - "start_date": 1634288088, + "start": 1634546686, + "start_date": 1634546686, "status": "active", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } - recorded_at: Fri, 15 Oct 2021 08:54:50 GMT + recorded_at: Mon, 18 Oct 2021 08:44:48 GMT - request: method: get - uri: https://api.stripe.com/v1/payment_methods/pm_1JkmBa2sOmf47Nz9ocFmIyBw + uri: https://api.stripe.com/v1/customers/cus_8E2ys9zDZgetWX body: encoding: US-ASCII string: '' @@ -4018,7 +4020,7 @@ http_interactions: Content-Type: - application/x-www-form-urlencoded X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_YwajQrzGbIjeAO","request_duration_ms":375}}' + - '{"last_request_metrics":{"request_id":"req_RPx14pHT5PJgSk","request_duration_ms":377}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: @@ -4037,7 +4039,1613 @@ http_interactions: Server: - nginx Date: - - Fri, 15 Oct 2021 08:54:50 GMT + - Mon, 18 Oct 2021 08:44:49 GMT + Content-Type: + - application/json + Content-Length: + - '49829' + Connection: + - keep-alive + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET, POST, HEAD, OPTIONS, DELETE + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required + Access-Control-Max-Age: + - '300' + Cache-Control: + - no-cache, no-store + Request-Id: + - req_MBGVAfIALU7GkX + Stripe-Version: + - '2019-08-14' + Strict-Transport-Security: + - max-age=31556926; includeSubDomains; preload + body: + encoding: UTF-8 + string: | + { + "id": "cus_8E2ys9zDZgetWX", + "object": "customer", + "account_balance": 0, + "address": null, + "balance": 0, + "created": 1460026822, + "currency": "usd", + "default_source": "card_1Euc902sOmf47Nz9eZvNNyyQ", + "delinquent": false, + "description": "Lucile Seguin", + "discount": null, + "email": "lucile.seguin@live.fr", + "invoice_prefix": "BCC32B8", + "invoice_settings": { + "custom_fields": null, + "default_payment_method": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", + "footer": null + }, + "livemode": false, + "metadata": { + }, + "name": null, + "next_invoice_sequence": 518, + "phone": null, + "preferred_locales": [ + + ], + "shipping": null, + "sources": { + "object": "list", + "data": [ + { + "id": "card_1Euc902sOmf47Nz9eZvNNyyQ", + "object": "card", + "address_city": null, + "address_country": null, + "address_line1": null, + "address_line1_check": null, + "address_line2": null, + "address_state": null, + "address_zip": null, + "address_zip_check": null, + "brand": "Visa", + "country": "US", + "customer": "cus_8E2ys9zDZgetWX", + "cvc_check": "unchecked", + "dynamic_last4": null, + "exp_month": 4, + "exp_year": 2020, + "fingerprint": "o52jybR7bnmNn6AT", + "funding": "credit", + "last4": "4242", + "metadata": { + }, + "name": null, + "tokenization_method": null + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/customers/cus_8E2ys9zDZgetWX/sources" + }, + "subscriptions": { + "object": "list", + "data": [ + { + "id": "sub_1JlrSc2sOmf47Nz9iGo2svAB", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634546686, + "billing_thresholds": null, + "cancel_at": 1666082683, + "cancel_at_period_end": false, + "canceled_at": 1634546686, + "collection_method": "charge_automatically", + "created": 1634546686, + "current_period_end": 1637225086, + "current_period_start": 1634546686, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KQiuAmBQdPQJ5s", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634546686, + "metadata": { + }, + "plan": { + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634546684, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634546684, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JlrSc2sOmf47Nz9iGo2svAB", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JlrSc2sOmf47Nz9iGo2svAB" + }, + "latest_invoice": "in_1JlrSc2sOmf47Nz9n4nMrTgc", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JlrSa2sOmf47Nz9ZK9HcoJE", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634546684, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634546686, + "start_date": 1634546686, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634288088, + "billing_thresholds": null, + "cancel_at": 1665824085, + "cancel_at_period_end": false, + "canceled_at": 1634288088, + "collection_method": "charge_automatically", + "created": 1634288088, + "current_period_end": 1636966488, + "current_period_start": 1634288088, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPbOBUeFMwAvpR", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634288088, + "metadata": { + }, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JkmBg2sOmf47Nz9MGXiiaqr", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JkmBg2sOmf47Nz9MGXiiaqr" + }, + "latest_invoice": "in_1JkmBg2sOmf47Nz9yKTwqM67", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JkmBe2sOmf47Nz99Wrpiisc", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634288086, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634288088, + "start_date": 1634288088, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_1JklFr2sOmf47Nz9JAPgZ9YT", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634284503, + "billing_thresholds": null, + "cancel_at": 1665820500, + "cancel_at_period_end": false, + "canceled_at": 1634284503, + "collection_method": "charge_automatically", + "created": 1634284503, + "current_period_end": 1636962903, + "current_period_start": 1634284503, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JklFm2sOmf47Nz9zXEuYdNz", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPaQHXj6njZcgk", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634284503, + "metadata": { + }, + "plan": { + "id": "price_1JklFp2sOmf47Nz9VscUWcco", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634284501, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JklFp2sOmf47Nz9VscUWcco", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634284501, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JklFr2sOmf47Nz9JAPgZ9YT", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JklFr2sOmf47Nz9JAPgZ9YT" + }, + "latest_invoice": "in_1JklFr2sOmf47Nz9iDXxFP7P", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JklFp2sOmf47Nz9VscUWcco", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634284501, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634284503, + "start_date": 1634284503, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_1JkWe12sOmf47Nz937vcnagn", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634228340, + "billing_thresholds": null, + "cancel_at": 1665764338, + "cancel_at_period_end": false, + "canceled_at": 1634228340, + "collection_method": "charge_automatically", + "created": 1634228340, + "current_period_end": 1636906740, + "current_period_start": 1634228340, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JkWdv2sOmf47Nz9cmQRMuk3", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPLKMa1jO2CS4F", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634228341, + "metadata": { + }, + "plan": { + "id": "price_1JkWdz2sOmf47Nz9os0MVSDB", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634228339, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JkWdz2sOmf47Nz9os0MVSDB", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634228339, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JkWe12sOmf47Nz937vcnagn", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JkWe12sOmf47Nz937vcnagn" + }, + "latest_invoice": "in_1JkWe12sOmf47Nz9m0Su80Lj", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JkWdz2sOmf47Nz9os0MVSDB", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634228339, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634228340, + "start_date": 1634228340, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_1JkWOC2sOmf47Nz9FTXocHRk", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1634227359, + "billing_thresholds": null, + "cancel_at": 1665763357, + "cancel_at_period_end": false, + "canceled_at": 1634227359, + "collection_method": "charge_automatically", + "created": 1634227359, + "current_period_end": 1636905759, + "current_period_start": 1634227359, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JkWO62sOmf47Nz9wbRCcazs", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KPL4QikDwY0073", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1634227360, + "metadata": { + }, + "plan": { + "id": "price_1JkWOA2sOmf47Nz979LjCXIX", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634227358, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JkWOA2sOmf47Nz979LjCXIX", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1634227358, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_1JkWOC2sOmf47Nz9FTXocHRk", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_1JkWOC2sOmf47Nz9FTXocHRk" + }, + "latest_invoice": "in_1JkWOC2sOmf47Nz9f0lRIjGY", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JkWOA2sOmf47Nz979LjCXIX", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1634227358, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1634227359, + "start_date": 1634227359, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_KDebaXSRtYU9Pw", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1631532350, + "billing_thresholds": null, + "cancel_at": 1663068348, + "cancel_at_period_end": false, + "canceled_at": 1631532350, + "collection_method": "charge_automatically", + "created": 1631532350, + "current_period_end": 1636802750, + "current_period_start": 1634124350, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JZDIE2sOmf47Nz941MJycRQ", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KDeblpdKaaH201", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1631532351, + "metadata": { + }, + "plan": { + "id": "price_1JZDII2sOmf47Nz9Wb0IfchE", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631532350, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JZDII2sOmf47Nz9Wb0IfchE", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1631532350, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_KDebaXSRtYU9Pw", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_KDebaXSRtYU9Pw" + }, + "latest_invoice": "in_1Jk5cC2sOmf47Nz9TnIGCjbZ", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JZDII2sOmf47Nz9Wb0IfchE", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631532350, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1631532350, + "start_date": 1631532350, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_KDeOOxKFukSOFq", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1631531544, + "billing_thresholds": null, + "cancel_at": 1663067542, + "cancel_at_period_end": false, + "canceled_at": 1631531544, + "collection_method": "charge_automatically", + "created": 1631531544, + "current_period_end": 1636801944, + "current_period_start": 1634123544, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JZD5E2sOmf47Nz9spRv1Hzv", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KDeO7ibOLIHrd2", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1631531545, + "metadata": { + }, + "plan": { + "id": "price_1JZD5H2sOmf47Nz9RE9xYVzW", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631531543, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JZD5H2sOmf47Nz9RE9xYVzW", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1631531543, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_KDeOOxKFukSOFq", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_KDeOOxKFukSOFq" + }, + "latest_invoice": "in_1Jk5Nv2sOmf47Nz9ovvmvGqC", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JZD5H2sOmf47Nz9RE9xYVzW", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631531543, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1631531544, + "start_date": 1631531544, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_KDeL49sskbLJn5", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1631531384, + "billing_thresholds": null, + "cancel_at": 1663067382, + "cancel_at_period_end": false, + "canceled_at": 1631531384, + "collection_method": "charge_automatically", + "created": 1631531384, + "current_period_end": 1636801784, + "current_period_start": 1634123384, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JZD2e2sOmf47Nz9cm1GFlt9", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KDeLVc4MXPXjat", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1631531385, + "metadata": { + }, + "plan": { + "id": "price_1JZD2i2sOmf47Nz9HgfbKryk", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631531384, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JZD2i2sOmf47Nz9HgfbKryk", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1631531384, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_KDeL49sskbLJn5", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_KDeL49sskbLJn5" + }, + "latest_invoice": "in_1Jk5M52sOmf47Nz9dRn4fitQ", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JZD2i2sOmf47Nz9HgfbKryk", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631531384, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1631531384, + "start_date": 1631531384, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_KDddMFRwup6SeD", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1631528772, + "billing_thresholds": null, + "cancel_at": 1663064770, + "cancel_at_period_end": false, + "canceled_at": 1631528772, + "collection_method": "charge_automatically", + "created": 1631528772, + "current_period_end": 1636799172, + "current_period_start": 1634120772, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JZCMW2sOmf47Nz9Av5ineIY", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KDddHFLKMC8QAW", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1631528773, + "metadata": { + }, + "plan": { + "id": "price_1JZCMa2sOmf47Nz9WZCd7fSB", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631528772, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JZCMa2sOmf47Nz9WZCd7fSB", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1631528772, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_KDddMFRwup6SeD", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_KDddMFRwup6SeD" + }, + "latest_invoice": "in_1Jk4fL2sOmf47Nz9CBaxQiwW", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JZCMa2sOmf47Nz9WZCd7fSB", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631528772, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1631528772, + "start_date": 1631528772, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + }, + { + "id": "sub_KDcr7oTexO2Zqj", + "object": "subscription", + "application_fee_percent": null, + "automatic_tax": { + "enabled": false + }, + "billing": "charge_automatically", + "billing_cycle_anchor": 1631525872, + "billing_thresholds": null, + "cancel_at": 1663061870, + "cancel_at_period_end": false, + "canceled_at": 1631525872, + "collection_method": "charge_automatically", + "created": 1631525872, + "current_period_end": 1636796272, + "current_period_start": 1634117872, + "customer": "cus_8E2ys9zDZgetWX", + "days_until_due": null, + "default_payment_method": "pm_1JZBbj2sOmf47Nz9tbdhvlLv", + "default_source": null, + "default_tax_rates": [ + + ], + "discount": null, + "ended_at": null, + "invoice_customer_balance_settings": { + "consume_applied_balance_on_void": true + }, + "items": { + "object": "list", + "data": [ + { + "id": "si_KDcrMC54ieiESF", + "object": "subscription_item", + "billing_thresholds": null, + "created": 1631525873, + "metadata": { + }, + "plan": { + "id": "price_1JZBbn2sOmf47Nz9gTKOj3St", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631525871, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "price": { + "id": "price_1JZBbn2sOmf47Nz9gTKOj3St", + "object": "price", + "active": true, + "billing_scheme": "per_unit", + "created": 1631525871, + "currency": "usd", + "livemode": false, + "lookup_key": null, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "recurring": { + "aggregate_usage": null, + "interval": "month", + "interval_count": 1, + "trial_period_days": null, + "usage_type": "licensed" + }, + "tax_behavior": "unspecified", + "tiers_mode": null, + "transform_quantity": null, + "type": "recurring", + "unit_amount": 9466, + "unit_amount_decimal": "9466" + }, + "quantity": 1, + "subscription": "sub_KDcr7oTexO2Zqj", + "tax_rates": [ + + ] + } + ], + "has_more": false, + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_KDcr7oTexO2Zqj" + }, + "latest_invoice": "in_1Jk3w02sOmf47Nz9fg2j5ghV", + "livemode": false, + "metadata": { + }, + "next_pending_invoice_item_invoice": null, + "pause_collection": null, + "payment_settings": { + "payment_method_options": null, + "payment_method_types": null + }, + "pending_invoice_item_interval": null, + "pending_setup_intent": null, + "pending_update": null, + "plan": { + "id": "price_1JZBbn2sOmf47Nz9gTKOj3St", + "object": "plan", + "active": true, + "aggregate_usage": null, + "amount": 9466, + "amount_decimal": "9466", + "billing_scheme": "per_unit", + "created": 1631525871, + "currency": "usd", + "interval": "month", + "interval_count": 1, + "livemode": false, + "metadata": { + }, + "nickname": null, + "product": "prod_IZQAhb9nLu4jfN", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 1, + "schedule": null, + "start": 1631525872, + "start_date": 1631525872, + "status": "active", + "tax_percent": null, + "transfer_data": null, + "trial_end": null, + "trial_start": null + } + ], + "has_more": true, + "total_count": 69, + "url": "/v1/customers/cus_8E2ys9zDZgetWX/subscriptions" + }, + "tax_exempt": "none", + "tax_ids": { + "object": "list", + "data": [ + + ], + "has_more": false, + "total_count": 0, + "url": "/v1/customers/cus_8E2ys9zDZgetWX/tax_ids" + }, + "tax_info": null, + "tax_info_verification": null + } + recorded_at: Mon, 18 Oct 2021 08:44:49 GMT +- request: + method: get + uri: https://api.stripe.com/v1/payment_methods/pm_1JlrSX2sOmf47Nz9O4x8IvAt + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Stripe/v1 RubyBindings/5.29.0 + Authorization: + - Bearer sk_test_testfaketestfaketestfake + Content-Type: + - application/x-www-form-urlencoded + X-Stripe-Client-Telemetry: + - '{"last_request_metrics":{"request_id":"req_MBGVAfIALU7GkX","request_duration_ms":639}}' + Stripe-Version: + - '2019-08-14' + X-Stripe-Client-User-Agent: + - '{"bindings_version":"5.29.0","lang":"ruby","lang_version":"2.6.7 p197 (2021-04-05)","platform":"x86_64-linux","engine":"ruby","publisher":"stripe","uname":"Linux + version 5.14.11-arch1-1 (linux@archlinux) (gcc (GCC) 11.1.0, GNU ld (GNU Binutils) + 2.36.1) #1 SMP PREEMPT Sun, 10 Oct 2021 00:48:26 +0000","hostname":"Sylvain-desktop"}' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx + Date: + - Mon, 18 Oct 2021 08:44:49 GMT Content-Type: - application/json Content-Length: @@ -4057,7 +5665,7 @@ http_interactions: Cache-Control: - no-cache, no-store Request-Id: - - req_U4hkBCkFQ5NbiG + - req_RmcFNPXaqrPUG5 Stripe-Version: - '2019-08-14' Strict-Transport-Security: @@ -4066,7 +5674,7 @@ http_interactions: encoding: UTF-8 string: | { - "id": "pm_1JkmBa2sOmf47Nz9ocFmIyBw", + "id": "pm_1JlrSX2sOmf47Nz9O4x8IvAt", "object": "payment_method", "billing_details": { "address": { @@ -4106,12 +5714,12 @@ http_interactions: }, "wallet": null }, - "created": 1634288083, + "created": 1634546681, "customer": "cus_8E2ys9zDZgetWX", "livemode": false, "metadata": { }, "type": "card" } - recorded_at: Fri, 15 Oct 2021 08:54:50 GMT + recorded_at: Mon, 18 Oct 2021 08:44:49 GMT recorded_with: VCR 6.0.0 From d0eebddceed22f3aaee06a10b1b552fb7a4d78b6 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 18 Oct 2021 12:14:51 +0200 Subject: [PATCH 060/142] [bug] payzen amount for non 2-decimals currencies --- CHANGELOG.md | 1 + app/controllers/api/payzen_controller.rb | 2 +- lib/pay_zen/service.rb | 21 +++++++++++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6f918ee..7112194c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - The upgrade script will check and report the ability to access the hub API - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to +- Fix a bug: invalid amount provided to the PayZen payment gateway when using a currency with anything else than 2 decimals - Updated @rails/webpacker to 5.4.3 - Updated react-refresh-webpack-plugin to 0.5.1 - Updated react-refresh to 0.10.0 diff --git a/app/controllers/api/payzen_controller.rb b/app/controllers/api/payzen_controller.rb index 07653f854..524bff3a3 100644 --- a/app/controllers/api/payzen_controller.rb +++ b/app/controllers/api/payzen_controller.rb @@ -25,7 +25,7 @@ class API::PayzenController < API::PaymentsController @id = PayZen::Helper.generate_ref(params[:cart_items], params[:customer_id]) client = PayZen::Charge.new - @result = client.create_payment(amount: amount[:amount], + @result = client.create_payment(amount: PayZen::Service.new.payzen_amount(amount[:amount]), order_id: @id, customer: PayZen::Helper.generate_customer(params[:customer_id], current_user.id, params[:cart_items])) rescue PayzenError => e diff --git a/lib/pay_zen/service.rb b/lib/pay_zen/service.rb index b09678bd8..367b71499 100644 --- a/lib/pay_zen/service.rb +++ b/lib/pay_zen/service.rb @@ -18,14 +18,14 @@ class PayZen::Service < Payment::Service token_id = order['answer']['transactions'].first['paymentMethodToken'] params = { - amount: first_item.details['recurring'].to_i, + amount: payzen_amount(first_item.details['recurring'].to_i), effect_date: first_item.due_date.iso8601, payment_method_token: token_id, rrule: rrule(payment_schedule), order_id: order_id } unless first_item.details['adjustment']&.zero? && first_item.details['other_items']&.zero? - params[:initial_amount] = first_item.amount + params[:initial_amount] = payzen_amount(first_item.amount) params[:initial_amount_number] = 1 end pz_subscription = client.create_subscription(params) @@ -81,6 +81,14 @@ class PayZen::Service < Payment::Service end end + def payzen_amount(amount) + currency = Setting.get('payzen_currency') + return amount / 100 if zero_decimal_currencies.any? { |s| s.casecmp(currency).zero? } + return amount * 10 if three_decimal_currencies.any? { |s| s.casecmp(currency).zero? } + + amount + end + private def rrule(payment_schedule) @@ -96,4 +104,13 @@ class PayZen::Service < Payment::Service transaction_date >= payment_schedule_item.due_date.to_date && transaction_date <= payment_schedule_item.due_date.to_date + 7.days end + + # @see https://payzen.io/en-EN/payment-file/ips/list-of-supported-currencies.html + def zero_decimal_currencies + %w[KHR JPY KRW XOF XPF] + end + + def three_decimal_currencies + %w[KWD TND] + end end From 1a672b064477699bf8176aab804c2ad39514d07d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 18 Oct 2021 15:19:58 +0200 Subject: [PATCH 061/142] stave start date in subscription schedule --- .rubocop.yml | 1 - app/services/payment_schedule_service.rb | 1 + ...121822_add_start_at_to_payment_schedule.rb | 9 ++++++++ db/schema.rb | 21 ++++++++++--------- lib/stripe/service.rb | 8 +++---- 5 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 db/migrate/20211018121822_add_start_at_to_payment_schedule.rb diff --git a/.rubocop.yml b/.rubocop.yml index c5b1a7062..2eca3bfc2 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,7 +18,6 @@ Metrics/BlockLength: - 'app/pdfs/pdf/*.rb' - 'test/**/*.rb' Metrics/ParameterLists: - Max: 6 CountKeywordArgs: false Style/BracesAroundHashParameters: EnforcedStyle: context_dependent diff --git a/app/services/payment_schedule_service.rb b/app/services/payment_schedule_service.rb index 32158976a..14dd6e078 100644 --- a/app/services/payment_schedule_service.rb +++ b/app/services/payment_schedule_service.rb @@ -47,6 +47,7 @@ class PaymentScheduleService details: details ) end + ps.start_at = start_at ps.total = items.map(&:amount).reduce(:+) ps.invoicing_profile = customer.invoicing_profile ps.statistic_profile = customer.statistic_profile diff --git a/db/migrate/20211018121822_add_start_at_to_payment_schedule.rb b/db/migrate/20211018121822_add_start_at_to_payment_schedule.rb new file mode 100644 index 000000000..942d2a845 --- /dev/null +++ b/db/migrate/20211018121822_add_start_at_to_payment_schedule.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# From this migration, we allow PaymentSchedules to start later, previously the started +# as soon as they were created. +class AddStartAtToPaymentSchedule < ActiveRecord::Migration[5.2] + def change + add_column :payment_schedules, :start_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 6a089334a..406fda14c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_10_14_135151) do +ActiveRecord::Schema.define(version: 2021_10_18_121822) do # These are extensions that must be enabled in order to support this database enable_extension "fuzzystrmatch" @@ -19,8 +19,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do enable_extension "unaccent" create_table "abuses", id: :serial, force: :cascade do |t| - t.string "signaled_type" t.integer "signaled_id" + t.string "signaled_type" t.string "first_name" t.string "last_name" t.string "email" @@ -49,8 +49,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do t.string "locality" t.string "country" t.string "postal_code" - t.string "placeable_type" t.integer "placeable_id" + t.string "placeable_type" t.datetime "created_at" t.datetime "updated_at" end @@ -64,8 +64,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do end create_table "assets", id: :serial, force: :cascade do |t| - t.string "viewable_type" t.integer "viewable_id" + t.string "viewable_type" t.string "attachment" t.string "type" t.datetime "created_at" @@ -133,8 +133,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do end create_table "credits", id: :serial, force: :cascade do |t| - t.string "creditable_type" t.integer "creditable_id" + t.string "creditable_type" t.integer "plan_id" t.integer "hours" t.datetime "created_at" @@ -356,15 +356,15 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do create_table "notifications", id: :serial, force: :cascade do |t| t.integer "receiver_id" - t.string "attached_object_type" t.integer "attached_object_id" + t.string "attached_object_type" t.integer "notification_type_id" t.boolean "is_read", default: false t.datetime "created_at" t.datetime "updated_at" t.string "receiver_type" t.boolean "is_send", default: false - t.jsonb "meta_data", default: "{}" + t.jsonb "meta_data", default: {} t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id" t.index ["receiver_id"], name: "index_notifications_on_receiver_id" end @@ -479,6 +479,7 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do t.bigint "operator_profile_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "start_at" t.index ["coupon_id"], name: "index_payment_schedules_on_coupon_id" t.index ["invoicing_profile_id"], name: "index_payment_schedules_on_invoicing_profile_id" t.index ["operator_profile_id"], name: "index_payment_schedules_on_operator_profile_id" @@ -548,8 +549,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do create_table "prices", id: :serial, force: :cascade do |t| t.integer "group_id" t.integer "plan_id" - t.string "priceable_type" t.integer "priceable_id" + t.string "priceable_type" t.integer "amount" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -658,8 +659,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do t.text "message" t.datetime "created_at" t.datetime "updated_at" - t.string "reservable_type" t.integer "reservable_id" + t.string "reservable_type" t.integer "nb_reserve_places" t.integer "statistic_profile_id" t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id" @@ -668,8 +669,8 @@ ActiveRecord::Schema.define(version: 2021_10_14_135151) do create_table "roles", id: :serial, force: :cascade do |t| t.string "name" - t.string "resource_type" t.integer "resource_id" + t.string "resource_type" t.datetime "created_at" t.datetime "updated_at" t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" diff --git a/lib/stripe/service.rb b/lib/stripe/service.rb index a14ef503b..65744e2db 100644 --- a/lib/stripe/service.rb +++ b/lib/stripe/service.rb @@ -28,7 +28,7 @@ class Stripe::Service < Payment::Service # other items (not recurring) items = subscription_invoice_items(payment_schedule, subscription, first_item, reservable_stp_id) - create_remote_subscription(shopping_cart, payment_schedule, items, price, payment_method_id, subscription) + create_remote_subscription(shopping_cart, payment_schedule, items, price, payment_method_id) end def create_subscription(payment_schedule, stp_object_id, stp_object_type) @@ -154,9 +154,9 @@ class Stripe::Service < Payment::Service # Create the provided PaymentSchedule on Stripe, using the Subscription API - def create_remote_subscription(shopping_cart, payment_schedule, items, price, payment_method_id, subscription) + def create_remote_subscription(shopping_cart, payment_schedule, items, price, payment_method_id) stripe_key = Setting.get('stripe_secret_key') - if subscription.start_at.nil? + if payment_schedule.start_at.nil? Stripe::Subscription.create({ customer: shopping_cart.customer.payment_gateway_object.gateway_object_id, cancel_at: (payment_schedule.payment_schedule_items.max_by(&:due_date).due_date + 1.month).to_i, @@ -171,7 +171,7 @@ class Stripe::Service < Payment::Service else Stripe::SubscriptionSchedule.create({ customer: shopping_cart.customer.payment_gateway_object.gateway_object_id, - start_date: subscription.start_at.to_i, + start_date: payment_schedule.start_at.to_i, end_behavior: 'cancel', phases: [ { From 4b41b29b9d8c04551df33074034316eeb675ac77 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 18 Oct 2021 16:34:53 +0200 Subject: [PATCH 062/142] fix using payzen with scheduled subscriptions --- .../src/javascript/components/payment/payzen/payzen-form.tsx | 3 ++- lib/pay_zen/service.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx index 9c3ab42fd..d1d15f231 100644 --- a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx +++ b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx @@ -40,7 +40,8 @@ export const PayzenForm: React.FC = ({ onSubmit, onSuccess, onE .then(({ KR, result }) => KR.showForm(result.formId)) .then(({ KR }) => KR.onFormReady(handleFormReady)) .then(({ KR }) => KR.onFormCreated(handleFormCreated)) - .then(({ KR }) => { PayZenKR.current = KR; }); + .then(({ KR }) => { PayZenKR.current = KR; }) + .catch(error => onError(error)); }).catch(error => onError(error)); }); }, [cart, paymentSchedule, customer]); diff --git a/lib/pay_zen/service.rb b/lib/pay_zen/service.rb index 367b71499..35f2fc4a2 100644 --- a/lib/pay_zen/service.rb +++ b/lib/pay_zen/service.rb @@ -10,7 +10,7 @@ module PayZen; end ## create remote objects on PayZen class PayZen::Service < Payment::Service - def create_subscription(payment_schedule, order_id) + def create_subscription(payment_schedule, order_id, *args) first_item = payment_schedule.ordered_items.first order = PayZen::Order.new.get(order_id, operation_type: 'VERIFICATION') From 6ec7ecca9abcf87480a0f99277940e516c2e7d27 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 18 Oct 2021 17:15:06 +0200 Subject: [PATCH 063/142] [WIP] create subscription modal --- .../subscriptions/subscribe-modal.tsx | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx diff --git a/app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx b/app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx new file mode 100644 index 000000000..3d2ba5f54 --- /dev/null +++ b/app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useState } from 'react'; +import Select from 'react-select'; +import { useTranslation } from 'react-i18next'; +import { Subscription } from '../../models/subscription'; +import { User } from '../../models/user'; +import { PaymentMethod } from '../../models/payment'; +import { FabModal } from '../base/fab-modal'; +import LocalPaymentAPI from '../../api/local-payment'; +import SubscriptionAPI from '../../api/subscription'; +import { Plan } from '../../models/plan'; +import PlanAPI from '../../api/plan'; +import { Loader } from '../base/loader'; +import { react2angular } from 'react2angular'; +import { IApplication } from '../../models/application'; + +declare const Application: IApplication; + +interface SubscribeModalProps { + isOpen: boolean, + toggleModal: () => void, + customer: User, + onSuccess: (message: string, subscription: Subscription) => void, + onError: (message: string) => void, +} + +/** + * Option format, expected by react-select + * @see https://github.com/JedWatson/react-select + */ +type selectOption = { value: number, label: string }; + +/** + * Modal dialog shown to create a subscription for teh given customer + */ +const SubscribeModal: React.FC = ({ isOpen, toggleModal, customer, onError, onSuccess }) => { + const { t } = useTranslation('admin'); + + const [plan, setPlan] = useState(null); + const [plans, setPlans] = useState>(null); + + // fetch all plans from the API on component mount + useEffect(() => { + PlanAPI.index() + .then(allPlans => setPlans(allPlans)) + .catch(error => onError(error)); + }, []); + + /** + * Callback triggered when the user validates the subscription + */ + const handleConfirmSubscribe = (): void => { + LocalPaymentAPI.confirmPayment({ + customer_id: customer.id, + payment_method: PaymentMethod.Other, + items: [ + { + subscription: { + plan_id: plan + } + } + ] + }).then(res => { + SubscriptionAPI.get(res.main_object.id).then(subscription => { + onSuccess(t('app.admin.subscribe_modal.subscription_success'), subscription); + toggleModal(); + }).catch(error => onError(error)); + }).catch(err => onError(err)); + }; + + /** + * Callback triggered when the user selects a group in the dropdown list + */ + const handlePlanSelect = (option: selectOption): void => { + setPlan(option.value); + }; + + /** + * Convert all groups to the react-select format + */ + const buildOptions = (): Array => { + return plans.filter(p => !p.disabled).map(p => { + return { value: p.id, label: p.base_name }; + }); + }; + + return ( + + + +
+ + - -
-
- - -
- - - diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 8122f5a0e..b9018c68f 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -925,6 +925,13 @@ en: pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + # take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Add an administrator" From 8689fa8cd311166dbbadfdbc4ebd320661ffd38f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:05 +0200 Subject: [PATCH 084/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 6abd79e25..0bf4b52a6 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -925,6 +925,13 @@ fr: pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + #take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Ajouter un administrateur" From 58db85118a32ce82e69a22d959d2cbed3eb55183 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:07 +0200 Subject: [PATCH 085/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 38d93aeb1..5ae3ebcc0 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -925,6 +925,13 @@ es: pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + #take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Agregar un administrador" From 3f3a809002bcd6166c2237513ead3ba220eb5d52 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:08 +0200 Subject: [PATCH 086/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 1139bda7b..8619681fe 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -925,6 +925,13 @@ de: pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + #take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Administrator hinzufügen" From db8004ace7370020b7939711b2625a38acf3e50e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:10 +0200 Subject: [PATCH 087/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 287a9cd84..3b71f07e7 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -925,6 +925,13 @@ pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + #take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Legg til administrator" From 40f1ab0cc8d66b12d81e9f98235f87642e23c8d5 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:11 +0200 Subject: [PATCH 088/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index a3d7beca4..3be57eea0 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -925,6 +925,13 @@ pt: pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" + #take a new subscription + subscribe_modal: + subscribe_USER: "Subscribe for {USER}" + subscribe: "Subscribe" + select_plan: "Please select a plan" + pay_in_one_go: "Pay in one go" + subscription_success: "" #add a new administrator to the platform admins_new: add_an_administrator: "Adicionar administrador" From 853b70ed11b85479d60ddfa4923a30e76e3594fb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 Oct 2021 15:45:12 +0200 Subject: [PATCH 089/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 0f4034d2b..127336f79 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -925,6 +925,13 @@ zu: pay_in_one_go: "crwdns22085:0crwdne22085:0" renew: "crwdns22087:0crwdne22087:0" renew_success: "crwdns22089:0crwdne22089:0" + #take a new subscription + subscribe_modal: + subscribe_USER: "crwdns22097:0{USER}crwdne22097:0" + subscribe: "crwdns22099:0crwdne22099:0" + select_plan: "crwdns22101:0crwdne22101:0" + pay_in_one_go: "crwdns22103:0crwdne22103:0" + subscription_success: "crwdns22105:0crwdne22105:0" #add a new administrator to the platform admins_new: add_an_administrator: "crwdns8027:0crwdne8027:0" From a28a3ad6511dae20571e7022194c108c9ad38033 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 Oct 2021 17:19:07 +0200 Subject: [PATCH 090/142] [bug] upgrade script add env var already present --- CHANGELOG.md | 3 +++ setup/upgrade.sh | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7112194c4..75c9bc346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Changelog Fab-manager +- Refactored subscription new/renew/free extend interfaces and API - Updated production documentation - Updated SSO documentation - Improved stripe subscription process with better error handling - The upgrade script will check and report the ability to access the hub API +- Fix a bug: the upgrade script won't add environment variables that are already present anymore +- Fix a bug: admin cannot take or renew a subscription for a member from member/edit interface - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a bug: invalid amount provided to the PayZen payment gateway when using a currency with anything else than 2 decimals diff --git a/setup/upgrade.sh b/setup/upgrade.sh index c1676b191..ab0f9c48f 100644 --- a/setup/upgrade.sh +++ b/setup/upgrade.sh @@ -136,8 +136,14 @@ add_environments() { for ENV in "${ENVIRONMENTS[@]}"; do if [[ "$ENV" =~ ^[A-Z0-9_]+=.*$ ]]; then - printf "\e[91m::\e[0m \e[1mInserting variable %s..\e[0m.\n" "$ENV" - printf "# added on %s\n%s\n" "$(date +%Y-%m-%d\ %R)" "$ENV" >> "config/env" + local var=$(echo "$ENV" | cut -d '=' -f1) + grep "$var" ./config/env + if [[ "$?" = 1 ]]; then + printf "\e[91m::\e[0m \e[1mInserting variable %s..\e[0m.\n" "$ENV" + printf "# added on %s\n%s\n" "$(date +%Y-%m-%d\ %R)" "$ENV" >> "config/env" + else + printf "\e[93m[ ⚠ ] %s is already defined in config/env, ignoring...\e[39m\n" "$var" + fi else printf "\e[93m[ ⚠ ] Ignoring invalid option: -e %s.\e[39m\n Given value is not valid environment variable, please see http://env.doc.fab.mn\n" "$ENV" fi From e9740ebf69f6f35cce4461bd666918b88ebe8da2 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 Oct 2021 17:31:30 +0200 Subject: [PATCH 091/142] validate birth date must be in the past --- app/models/statistic_profile.rb | 8 ++++++++ config/locales/en.yml | 2 ++ 2 files changed, 10 insertions(+) diff --git a/app/models/statistic_profile.rb b/app/models/statistic_profile.rb index b67a790e0..502376e0e 100644 --- a/app/models/statistic_profile.rb +++ b/app/models/statistic_profile.rb @@ -28,6 +28,8 @@ class StatisticProfile < ApplicationRecord # Projects that the current user is the author has_many :my_projects, foreign_key: :author_statistic_profile_id, class_name: 'Project', dependent: :destroy + validates :check_birthday_in_past + def str_gender gender ? 'male' : 'female' end @@ -40,4 +42,10 @@ class StatisticProfile < ApplicationRecord '' end end + + private + + def check_birthday_in_past + errors.add(:birthday, I18n.t('statistic_profile.birthday_in_past')) if birthday.present? && birthday > DateTime.current + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 83bbf729c..2e846f23c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -418,6 +418,8 @@ en: admins: 'Administrators' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "the setting is locked." about_title: "\"About\" page title" From bbf512f67406f9d67aefa8e59d5b9f7109ca2d4e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 21 Oct 2021 09:28:41 +0200 Subject: [PATCH 092/142] validate birthday in past --- CHANGELOG.md | 1 + app/frontend/src/javascript/controllers/application.js.erb | 3 ++- app/models/statistic_profile.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64838cc9a..1923150b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Updated SSO documentation - Improved stripe subscription process with better error handling - The upgrade script will check and report the ability to access the hub API +- Fix a bug: users can set their birthdate in the future - Fix a bug: the upgrade script won't add environment variables that are already present anymore - Fix a bug: admin cannot take or renew a subscription for a member from member/edit interface - Fix a bug: missing translations diff --git a/app/frontend/src/javascript/controllers/application.js.erb b/app/frontend/src/javascript/controllers/application.js.erb index e3dd67d92..f40702504 100644 --- a/app/frontend/src/javascript/controllers/application.js.erb +++ b/app/frontend/src/javascript/controllers/application.js.erb @@ -100,7 +100,8 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco format: Fablab.uibDateFormat, opened: false, options: { - startingDay: Fablab.weekStartingDay + startingDay: Fablab.weekStartingDay, + maxDate: new Date() } }; diff --git a/app/models/statistic_profile.rb b/app/models/statistic_profile.rb index 502376e0e..30a79ab50 100644 --- a/app/models/statistic_profile.rb +++ b/app/models/statistic_profile.rb @@ -28,7 +28,7 @@ class StatisticProfile < ApplicationRecord # Projects that the current user is the author has_many :my_projects, foreign_key: :author_statistic_profile_id, class_name: 'Project', dependent: :destroy - validates :check_birthday_in_past + validate :check_birthday_in_past def str_gender gender ? 'male' : 'female' From 7ffcd68fb7911accd8efb0ba83493e4bfab78985 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 21 Oct 2021 10:31:21 +0200 Subject: [PATCH 093/142] [bug] canceled training reservation in admin/edit member --- CHANGELOG.md | 1 + app/frontend/templates/admin/members/edit.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1923150b7..614564e39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Updated SSO documentation - Improved stripe subscription process with better error handling - The upgrade script will check and report the ability to access the hub API +- Fix a bug: canceled training reservation is not marked as this in admin/edit members/trainings - Fix a bug: users can set their birthdate in the future - Fix a bug: the upgrade script won't add environment variables that are already present anymore - Fix a bug: admin cannot take or renew a subscription for a member from member/edit interface diff --git a/app/frontend/templates/admin/members/edit.html b/app/frontend/templates/admin/members/edit.html index 79579bd6a..cae9e1471 100644 --- a/app/frontend/templates/admin/members/edit.html +++ b/app/frontend/templates/admin/members/edit.html @@ -128,7 +128,7 @@
    -
  • +
  • {{r.reservable.name}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}
From 9c55b9d61f0a7e937c5d874c0e13b7e03da6b46f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 21 Oct 2021 15:07:18 +0200 Subject: [PATCH 094/142] [bug] incorrect behavior for the setting 'email confirmation required' - when enabled: the user was still logged-in in the backend (F5 and he was logged in the frontend) - when disabled: the user was not logged in the frontend and received a message to confirm his/her email --- CHANGELOG.md | 1 + app/controllers/registrations_controller.rb | 2 +- app/frontend/src/javascript/controllers/application.js.erb | 2 +- app/mailers/notifications_mailer.rb | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 614564e39..b34e9aef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Fix a bug: missing translations - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a bug: invalid amount provided to the PayZen payment gateway when using a currency with anything else than 2 decimals +- Fix a bug: incorrect behavior for the setting "email confirmation required" - Updated @rails/webpacker to 5.4.3 - Updated react-refresh-webpack-plugin to 0.5.1 - Updated react-refresh to 0.10.0 diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 5ffe4e481..7ceee313d 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -20,7 +20,7 @@ class RegistrationsController < Devise::RegistrationsController # Allows sending the confirmation email without blocking the access to the dashboard resource.send_confirmation_instructions - sign_up(resource_name, resource) + sign_up(resource_name, resource) unless Setting.get('confirmation_required') respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format? diff --git a/app/frontend/src/javascript/controllers/application.js.erb b/app/frontend/src/javascript/controllers/application.js.erb index f40702504..d456361d8 100644 --- a/app/frontend/src/javascript/controllers/application.js.erb +++ b/app/frontend/src/javascript/controllers/application.js.erb @@ -180,7 +180,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco }] }).result['finally'](null).then(function (res) { // when the account was created successfully, set the session to the newly created account - if(res.settings.confirmation_required) { + if(res.settings.confirmation_required === 'true') { Auth._currentUser = null; growl.info(_t('app.public.common.you_will_receive_confirmation_instructions_by_email_detailed')); } else { diff --git a/app/mailers/notifications_mailer.rb b/app/mailers/notifications_mailer.rb index 6e49d9d85..0dc51d356 100644 --- a/app/mailers/notifications_mailer.rb +++ b/app/mailers/notifications_mailer.rb @@ -24,6 +24,8 @@ class NotificationsMailer < NotifyWith::NotificationsMailer end send(notification.notification_type) + rescue StandardError => e + STDERR.puts "[NotificationsMailer] notification cannot be sent: #{e}" end def helpers From a51dec9c728d78b1613bab043176e06742103ec6 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 21 Oct 2021 15:11:47 +0200 Subject: [PATCH 095/142] removed ourdated comment --- app/models/invoice.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 3e0e6a108..1b138151c 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -129,7 +129,6 @@ class Invoice < PaymentDocument def prevent_refund? return true if user.nil? - # workaround for reservation saved after invoice if main_item.object_type == 'Reservation' && main_item.object&.reservable_type == 'Training' user.trainings.include?(main_item.object.reservable_id) else From 36086f93dff0862f42f444a93de652dabc86d61c Mon Sep 17 00:00:00 2001 From: Sylvain Date: Thu, 21 Oct 2021 18:09:36 +0200 Subject: [PATCH 096/142] [WIP] ability to select categories of slots for computing overlapping slots --- .../settings/check-list-setting.tsx | 75 +++++++++++++++++++ .../javascript/controllers/admin/settings.js | 14 ++++ .../admin/settings/reservations.html | 21 ++++-- app/models/setting.rb | 3 +- 4 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 app/frontend/src/javascript/components/settings/check-list-setting.tsx diff --git a/app/frontend/src/javascript/components/settings/check-list-setting.tsx b/app/frontend/src/javascript/components/settings/check-list-setting.tsx new file mode 100644 index 000000000..ab0905868 --- /dev/null +++ b/app/frontend/src/javascript/components/settings/check-list-setting.tsx @@ -0,0 +1,75 @@ +import React, { BaseSyntheticEvent, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { SettingName } from '../../models/setting'; +import { IApplication } from '../../models/application'; +import { react2angular } from 'react2angular'; +import SettingAPI from '../../api/setting'; +import { Loader } from '../base/loader'; + +declare const Application: IApplication; + +interface CheckListSettingProps { + name: SettingName, + label: string, + className?: string, + allSettings: Record, + availableOptions: Array, + onSuccess: (message: string) => void, + onError: (message: string) => void, +} + +const CheckListSetting: React.FC = ({ name, label, className, allSettings, availableOptions, onSuccess, onError }) => { + const { t } = useTranslation('admin'); + + const [value, setValue] = useState(null); + + useEffect(() => { + if (!allSettings) return; + + setValue(allSettings[name]); + }, [allSettings]); + + const toggleCheckbox = (option: string) => { + return (event: BaseSyntheticEvent) => { + if (event.target.checked) { + let newValue = value ? `${value},` : ''; + newValue += option; + setValue(newValue); + } else { + const regex = new RegExp(`,?${option}`, 'g'); + setValue(value.replace(regex, '')); + } + }; + }; + + const handleSave = () => { + SettingAPI.update(name, value) + .then(() => onSuccess(t('app.admin.check_list_setting.customization_of_SETTING_successfully_saved', { SETTING: t(`app.admin.settings.${name}`) }))) + .catch(err => onError(err)); + }; + + const isChecked = (option) => { + return value?.includes(option); + }; + + return ( +
+ {label} + {availableOptions.map(option =>
+ + +
)} + +
+ ); +}; + +const CheckListSettingWrapper: React.FC = ({ allSettings, availableOptions, onSuccess, onError, label, className, name }) => { + return ( + + + + ); +}; + +Application.Components.component('checkListSetting', react2angular(CheckListSettingWrapper, ['allSettings', 'className', 'name', 'label', 'availableOptions', 'onSuccess', 'onError'])); diff --git a/app/frontend/src/javascript/controllers/admin/settings.js b/app/frontend/src/javascript/controllers/admin/settings.js index 249af097a..0d668b7b1 100644 --- a/app/frontend/src/javascript/controllers/admin/settings.js +++ b/app/frontend/src/javascript/controllers/admin/settings.js @@ -314,6 +314,20 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' $scope.codeMirrorEditor = editor; }; + /** + * Shows a success message forwarded from a child react component + */ + $scope.onSuccess = function (message) { + growl.success(message); + }; + + /** + * Callback triggered by react components + */ + $scope.onError = function (message) { + growl.error(message); + }; + /** * Setup the feature-tour for the admin/settings page. * This is intended as a contextual help (when pressing F1) diff --git a/app/frontend/templates/admin/settings/reservations.html b/app/frontend/templates/admin/settings/reservations.html index ee40a9f81..2eaa947ed 100644 --- a/app/frontend/templates/admin/settings/reservations.html +++ b/app/frontend/templates/admin/settings/reservations.html @@ -85,11 +85,22 @@

{{ 'app.admin.settings.book_overlapping_slots_info' }}

- - +
+ + +
+
+ + +
diff --git a/app/models/setting.rb b/app/models/setting.rb index 1ee8b4623..65dc85786 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -120,7 +120,8 @@ class Setting < ApplicationRecord payzen_currency public_agenda_module renew_pack_threshold - pack_only_for_subscription] } + pack_only_for_subscription + overlapping_categories] } # WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist # and in config/locales/en.yml#settings From b1245a5248ab9f11d98fc8b17c73cde41ac1dd1d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 10:41:15 +0200 Subject: [PATCH 097/142] updated setup instructions with new prepare-vps script --- doc/production_readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/production_readme.md b/doc/production_readme.md index 180b14e85..cb76da9b8 100644 --- a/doc/production_readme.md +++ b/doc/production_readme.md @@ -47,11 +47,11 @@ Supported operating systems are Ubuntu LTS 16.04+ and Debian 8+ with an x86 64-b This might work on other linux systems, and CPU architectures but this is untested for now, and we do not recommend for production purposes. #### Software requirements -First, you need to install docker: -- Install [Docker on Debian](https://docs.docker.com/engine/installation/linux/docker-ce/debian/) -- Install [Docker on Ubuntu](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/) +`curl` and `bash` are needed to retrieve and run the automated deployment scripts. +Then the various scripts will check for their own dependencies. -Then install [Docker Compose](https://docs.docker.com/compose/install/) +Moreover, the main software dependencies to run fab-manager are [Docker](https://docs.docker.com/engine/installation/linux/docker-ce/debian/) and [Docker Compose](https://docs.docker.com/compose/install/) +They can be easily installed using the [`prepare-vps.sleede.com` script below](#prepare-the-server). ### Set up the domain name From 840c536c75ec5c148b4a7226b963c47c7951403c Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 14:50:02 +0200 Subject: [PATCH 098/142] Ability to configure data sources for preventing booking on overlapping slots --- CHANGELOG.md | 4 +- .../settings/check-list-setting.tsx | 47 +++++++++++++------ .../javascript/controllers/admin/settings.js | 10 ++++ .../src/javascript/directives/cart.js | 7 +-- app/frontend/src/javascript/models/setting.ts | 1 + app/frontend/src/javascript/router.js | 10 ++-- app/frontend/src/stylesheets/application.scss | 1 + .../modules/settings/check-list-setting.scss | 14 ++++++ .../admin/settings/reservations.html | 10 ++-- app/models/setting.rb | 7 ++- app/policies/setting_policy.rb | 2 +- config/locales/app.admin.en.yml | 10 ++++ config/locales/en.yml | 1 + db/seeds.rb | 4 ++ 14 files changed, 94 insertions(+), 34 deletions(-) create mode 100644 app/frontend/src/stylesheets/modules/settings/check-list-setting.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index b34e9aef1..63df22b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager -- Refactored subscription new/renew/free extend interfaces and API +- Refactored subscription new/renew/free extend interfaces and API +- Ability to configure data sources for preventing booking on overlapping slots - Updated production documentation - Updated SSO documentation - Improved stripe subscription process with better error handling @@ -23,6 +24,7 @@ - Fix a security issue: updated nokogiri to 1.12.5 to fix [CVE-2021-41098](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41098) - Fix a security issue: updated puma to 4.3.9 to fix [CVE-2021-41136](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41136) - Fix a security issue: updated sidekiq to 6.2.1 to fix [CVE-2021-30151](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30151) +- [TODO DEPLOY] `rails db:seed` ## v5.1.10 2021 October 04 diff --git a/app/frontend/src/javascript/components/settings/check-list-setting.tsx b/app/frontend/src/javascript/components/settings/check-list-setting.tsx index ab0905868..909509e58 100644 --- a/app/frontend/src/javascript/components/settings/check-list-setting.tsx +++ b/app/frontend/src/javascript/components/settings/check-list-setting.tsx @@ -5,6 +5,7 @@ import { IApplication } from '../../models/application'; import { react2angular } from 'react2angular'; import SettingAPI from '../../api/setting'; import { Loader } from '../base/loader'; +import { FabButton } from '../base/fab-button'; declare const Application: IApplication; @@ -12,23 +13,32 @@ interface CheckListSettingProps { name: SettingName, label: string, className?: string, - allSettings: Record, - availableOptions: Array, + // availableOptions must be like this [['option1', 'label 1'], ['option2', 'label 2']] + availableOptions: Array>, onSuccess: (message: string) => void, onError: (message: string) => void, } -const CheckListSetting: React.FC = ({ name, label, className, allSettings, availableOptions, onSuccess, onError }) => { +/** + * This component allows to configure multiples values for a setting, like a check list. + * The result is stored as a string, composed of the checked values, e.g. 'option1,option2' + */ +const CheckListSetting: React.FC = ({ name, label, className, availableOptions, onSuccess, onError }) => { const { t } = useTranslation('admin'); const [value, setValue] = useState(null); + // on component load, we retrieve the current value of the list from the API useEffect(() => { - if (!allSettings) return; - - setValue(allSettings[name]); - }, [allSettings]); + SettingAPI.get(name) + .then(res => setValue(res.value)) + .catch(err => onError(err)); + }, []); + /** + * Callback triggered when a checkbox is ticked or unticked. + * This function construct the resulting string, by adding or deleting the provided option identifier. + */ const toggleCheckbox = (option: string) => { return (event: BaseSyntheticEvent) => { if (event.target.checked) { @@ -42,34 +52,41 @@ const CheckListSetting: React.FC = ({ name, label, classN }; }; + /** + * Callback triggered when the 'save' button is clicked. + * Save the built string to the Setting API + */ const handleSave = () => { SettingAPI.update(name, value) .then(() => onSuccess(t('app.admin.check_list_setting.customization_of_SETTING_successfully_saved', { SETTING: t(`app.admin.settings.${name}`) }))) .catch(err => onError(err)); }; + /** + * Verify if the provided option is currently ticked (i.e. included in the value string) + */ const isChecked = (option) => { return value?.includes(option); }; return (
- {label} - {availableOptions.map(option =>
- - +

{label}

+ {availableOptions.map(option =>
+ +
)} - + {t('app.admin.check_list_setting.save')}
); }; -const CheckListSettingWrapper: React.FC = ({ allSettings, availableOptions, onSuccess, onError, label, className, name }) => { +const CheckListSettingWrapper: React.FC = ({ availableOptions, onSuccess, onError, label, className, name }) => { return ( - + ); }; -Application.Components.component('checkListSetting', react2angular(CheckListSettingWrapper, ['allSettings', 'className', 'name', 'label', 'availableOptions', 'onSuccess', 'onError'])); +Application.Components.component('checkListSetting', react2angular(CheckListSettingWrapper, ['className', 'name', 'label', 'availableOptions', 'onSuccess', 'onError'])); diff --git a/app/frontend/src/javascript/controllers/admin/settings.js b/app/frontend/src/javascript/controllers/admin/settings.js index 0d668b7b1..380eeee03 100644 --- a/app/frontend/src/javascript/controllers/admin/settings.js +++ b/app/frontend/src/javascript/controllers/admin/settings.js @@ -328,6 +328,16 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' growl.error(message); }; + /** + * Options for allow/prevent book overlapping slots: which kind of slots are used in the overlapping computation + */ + $scope.availableOverlappingOptions = [ + ['training_reservations', _t('app.admin.settings.overlapping_options.training_reservations')], + ['machine_reservations', _t('app.admin.settings.overlapping_options.machine_reservations')], + ['space_reservations', _t('app.admin.settings.overlapping_options.space_reservations')], + ['events_reservations', _t('app.admin.settings.overlapping_options.events_reservations')] + ]; + /** * Setup the feature-tour for the admin/settings page. * This is intended as a contextual help (when pressing F1) diff --git a/app/frontend/src/javascript/directives/cart.js b/app/frontend/src/javascript/directives/cart.js index 3c08a0cda..5fabc96ad 100644 --- a/app/frontend/src/javascript/directives/cart.js +++ b/app/frontend/src/javascript/directives/cart.js @@ -456,12 +456,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', * @param callback {function} */ const validateSameTimeReservations = function (slot, callback) { - let sameTimeReservations = [ - 'training_reservations', - 'machine_reservations', - 'space_reservations', - 'events_reservations' - ].map(function (k) { + $scope.settings.overlapping_categories.split(',').map(function (k) { return _.filter($scope.user[k], function (r) { return slot.start.isSame(r.start_at) || (slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) || diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts index 439f211c5..e92dff2b7 100644 --- a/app/frontend/src/javascript/models/setting.ts +++ b/app/frontend/src/javascript/models/setting.ts @@ -111,6 +111,7 @@ export enum SettingName { PublicAgendaModule = 'public_agenda_module', RenewPackThreshold = 'renew_pack_threshold', PackOnlyForSubscription = 'pack_only_for_subscription', + OverlappingCategories = 'overlapping_categories' } export type SettingValue = string|boolean|number; diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index cad2f9a5b..394a64ce1 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -365,7 +365,7 @@ angular.module('application.router', ['ui.router']) return Setting.query({ names: "['machine_explications_alert', 'booking_window_start', 'booking_window_end', 'booking_move_enable', " + "'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', " + - "'online_payment_module', 'payment_gateway']" + "'online_payment_module', 'payment_gateway', 'overlapping_categories']" }).$promise; }] } @@ -451,7 +451,7 @@ angular.module('application.router', ['ui.router']) return Setting.query({ names: "['booking_window_start', 'booking_window_end', 'booking_move_enable', 'booking_move_delay', " + "'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', " + - "'space_explications_alert', 'online_payment_module', 'payment_gateway']" + "'space_explications_alert', 'online_payment_module', 'payment_gateway', 'overlapping_categories']" }).$promise; }] } @@ -505,7 +505,7 @@ angular.module('application.router', ['ui.router']) names: "['booking_window_start', 'booking_window_end', 'booking_move_enable', 'booking_move_delay', " + "'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', " + "'training_explications_alert', 'training_information_message', 'online_payment_module', " + - "'payment_gateway']" + "'payment_gateway', 'overlapping_categories']" }).$promise; }] } @@ -534,7 +534,7 @@ angular.module('application.router', ['ui.router']) resolve: { subscriptionExplicationsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'subscription_explications_alert' }).$promise; }], groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], - settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['online_payment_module', 'payment_gateway']" }).$promise; }] + settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['online_payment_module', 'payment_gateway', 'overlapping_categories']" }).$promise; }] } }) @@ -1080,7 +1080,7 @@ angular.module('application.router', ['ui.router']) "'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', 'trainings_module', " + "'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " + "'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," + - "'renew_pack_threshold', 'pack_only_for_subscription']" + "'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories']" }).$promise; }], privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }], diff --git a/app/frontend/src/stylesheets/application.scss b/app/frontend/src/stylesheets/application.scss index 13203a952..fb8e6a6f3 100644 --- a/app/frontend/src/stylesheets/application.scss +++ b/app/frontend/src/stylesheets/application.scss @@ -63,6 +63,7 @@ @import "modules/pricing/pack-form"; @import "modules/pricing/delete-pack"; @import "modules/pricing/edit-pack"; +@import "modules/settings/check-list-setting"; @import "modules/prepaid-packs/propose-packs-modal"; @import "modules/prepaid-packs/packs-summary"; @import "modules/subscriptions/free-extend-modal"; diff --git a/app/frontend/src/stylesheets/modules/settings/check-list-setting.scss b/app/frontend/src/stylesheets/modules/settings/check-list-setting.scss new file mode 100644 index 000000000..e56fcefd3 --- /dev/null +++ b/app/frontend/src/stylesheets/modules/settings/check-list-setting.scss @@ -0,0 +1,14 @@ +.check-list-setting { + .check-list-title { + font-weight: 600; + } + + label { + margin-left: 1em; + } + + .save { + background-color: #999; + border-color: #999; + } +} diff --git a/app/frontend/templates/admin/settings/reservations.html b/app/frontend/templates/admin/settings/reservations.html index 2eaa947ed..05e599930 100644 --- a/app/frontend/templates/admin/settings/reservations.html +++ b/app/frontend/templates/admin/settings/reservations.html @@ -91,12 +91,14 @@ label="app.admin.settings.allow_booking" classes="m-l"> +
+ {{ 'app.admin.settings.overlapping_categories_info' }} +
-
- + diff --git a/app/models/setting.rb b/app/models/setting.rb index 65dc85786..d0742a62d 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -122,8 +122,11 @@ class Setting < ApplicationRecord renew_pack_threshold pack_only_for_subscription overlapping_categories] } - # WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist - # and in config/locales/en.yml#settings + # WARNING: when adding a new key, you may also want to add it in: + # - config/locales/en.yml#settings + # - app/frontend/src/javascript/models/setting.ts#SettingName + # - db/seeds.rb (to set the default value) + # - app/policies/setting_policy.rb#public_whitelist (if the setting can be read by anyone) def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).limit(1).first diff --git a/app/policies/setting_policy.rb b/app/policies/setting_policy.rb index e9496a6f8..0eabb57c6 100644 --- a/app/policies/setting_policy.rb +++ b/app/policies/setting_policy.rb @@ -40,7 +40,7 @@ class SettingPolicy < ApplicationPolicy recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default online_payment_module stripe_public_key confirmation_required wallet_module trainings_module address_required payment_gateway payzen_endpoint payzen_public_key public_agenda_module renew_pack_threshold statistics_module - pack_only_for_subscription] + pack_only_for_subscription overlapping_categories] end ## diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index b9018c68f..32e67a864 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1181,6 +1181,8 @@ en: an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" allow_booking: "Allow booking" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1237,6 +1239,11 @@ en: 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "General" title: "Title" @@ -1397,6 +1404,9 @@ en: card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines." check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments." online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: diff --git a/config/locales/en.yml b/config/locales/en.yml index 2e846f23c..688e92473 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -534,3 +534,4 @@ en: public_agenda_module: "Public agenda module" renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" diff --git a/db/seeds.rb b/db/seeds.rb index d25f4e9d6..73c9ff89e 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -901,6 +901,10 @@ Setting.set('renew_pack_threshold', 0.2) unless Setting.find_by(name: 'renew_pac Setting.set('pack_only_for_subscription', true) unless Setting.find_by(name: 'pack_only_for_subscription').try(:value) +unless Setting.find_by(name: 'overlapping_categories').try(:value) + Setting.set('overlapping_categories', 'training_reservations,machine_reservations,space_reservations,events_reservations') +end + if StatisticCustomAggregation.count.zero? # available reservations hours for machines machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2) From ab53042f21481eab8292d53b408c97b076062e34 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 14:59:57 +0200 Subject: [PATCH 099/142] fix undefined variable sameTimeReservations --- app/frontend/src/javascript/directives/cart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/frontend/src/javascript/directives/cart.js b/app/frontend/src/javascript/directives/cart.js index 5fabc96ad..da8865547 100644 --- a/app/frontend/src/javascript/directives/cart.js +++ b/app/frontend/src/javascript/directives/cart.js @@ -456,7 +456,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', * @param callback {function} */ const validateSameTimeReservations = function (slot, callback) { - $scope.settings.overlapping_categories.split(',').map(function (k) { + let sameTimeReservations = $scope.settings.overlapping_categories.split(',').map(function (k) { return _.filter($scope.user[k], function (r) { return slot.start.isSame(r.start_at) || (slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) || From ca603f85af47cb1be9b6e4eadb31c4d718abb1cf Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:12:25 +0200 Subject: [PATCH 100/142] fix uninitialized constant PayZen::Service --- app/controllers/api/payzen_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/api/payzen_controller.rb b/app/controllers/api/payzen_controller.rb index 524bff3a3..76d60980f 100644 --- a/app/controllers/api/payzen_controller.rb +++ b/app/controllers/api/payzen_controller.rb @@ -7,6 +7,7 @@ class API::PayzenController < API::PaymentsController require 'pay_zen/token' require 'pay_zen/transaction' require 'pay_zen/helper' + require 'pay_zen/service' def sdk_test str = 'fab-manager' From 4a59f6faed708238028e77838b4dc0b3cc4e9a37 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:43:33 +0200 Subject: [PATCH 101/142] [bug] invalid text shown when a member confirms a free cart --- CHANGELOG.md | 1 + .../payment/abstract-payment-modal.tsx | 3 ++- .../local-payment/local-payment-form.tsx | 19 ++++++++++++++++++- .../local-payment/local-payment-modal.tsx | 13 +++++++++++-- config/locales/app.admin.en.yml | 2 ++ config/locales/app.shared.en.yml | 1 + 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63df22b6b..f04bd76d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Fix a bug: the upgrade script report an invalid version to upgrade to - Fix a bug: invalid amount provided to the PayZen payment gateway when using a currency with anything else than 2 decimals - Fix a bug: incorrect behavior for the setting "email confirmation required" +- Fix a bug: invalid text shown when a member confirms a free cart - Updated @rails/webpacker to 5.4.3 - Updated react-refresh-webpack-plugin to 0.5.1 - Updated react-refresh to 0.10.0 diff --git a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx index 77fe27991..c526be301 100644 --- a/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx @@ -229,7 +229,8 @@ export const AbstractPaymentModal: React.FC = ({ isOp disabled={!canSubmit()} form={formId} className="validate-btn"> - {t('app.shared.payment.confirm_payment_of_', { AMOUNT: FormatLib.price(remainingPrice) })} + {remainingPrice > 0 && t('app.shared.payment.confirm_payment_of_', { AMOUNT: FormatLib.price(remainingPrice) })} + {remainingPrice === 0 && t('app.shared.payment.validate')} } {submitState &&
diff --git a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx index 6f779bcea..9a320f677 100644 --- a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx +++ b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx @@ -109,9 +109,26 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce onSuccess(document); }; + /** + * Generally, this form component is only shown to admins or to managers when they book for someone else. + * If this is not the case, then it is shown to validate a free (or prepaid by wallet) cart. + * This function will return `true` in the later case. + */ + const isFreeOfCharge = (): boolean => { + return (customer.id === operator.id); + }; + + /** + * Get the type of the main item in the cart compile + */ + const mainItemType = (): string => { + return Object.keys(cart.items[0])[0]; + }; + return (
- {!paymentSchedule &&

{t('app.admin.local_payment.about_to_cash')}

} + {!paymentSchedule && !isFreeOfCharge &&

{t('app.admin.local_payment.about_to_cash')}

} + {!paymentSchedule && isFreeOfCharge &&

{t('app.admin.local_payment.about_to_confirm', { ITEM: mainItemType() })}

} {paymentSchedule &&
diff --git a/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx b/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx index 37690aad3..8f9a7dcf1 100644 --- a/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx @@ -3,7 +3,7 @@ import { AbstractPaymentModal, GatewayFormProps } from '../abstract-payment-moda import { LocalPaymentForm } from './local-payment-form'; import { ShoppingCart } from '../../../models/payment'; import { PaymentSchedule } from '../../../models/payment-schedule'; -import { User } from '../../../models/user'; +import { User, UserRole } from '../../../models/user'; import { Invoice } from '../../../models/invoice'; import { useTranslation } from 'react-i18next'; import { ModalSize } from '../../base/fab-modal'; @@ -42,6 +42,15 @@ const LocalPaymentModalComponent: React.FC = ({ isOpen, ); }; + /** + * Generally, this modal dialog is only shown to admins or to managers when they book for someone else. + * If this is not the case, then it is shown to validate a free (or prepaid by wallet) cart. + * This function will return `true` in the later case. + */ + const isFreeOfCharge = (): boolean => { + return (customer.id === currentUser.id); + }; + /** * Integrates the LocalPaymentForm into the parent AbstractPaymentModal */ @@ -67,7 +76,7 @@ const LocalPaymentModalComponent: React.FC = ({ isOpen, isOpen={isOpen} toggleModal={toggleModal} logoFooter={logoFooter()} - title={t('app.admin.local_payment.offline_payment')} + title={isFreeOfCharge() ? t('app.admin.local_payment.validate_cart') : t('app.admin.local_payment.offline_payment')} formId="local-payment-form" formClassName="local-payment-form" currentUser={currentUser} diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 32e67a864..a97e27808 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1396,8 +1396,10 @@ en: category_deleted: "The category was successfully deleted" unable_to_delete: "Unable to delete the category: " local_payment: + validate_cart: "Validate my cart" offline_payment: "Payment on site" about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Payment method" method_card: "Online by card" method_check: "By check" diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index a75bc47ce..0e23b125a 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -125,6 +125,7 @@ en: _the_general_terms_and_conditions: "the general terms and conditions." payment_schedule_html: "

You're about to subscribe to a payment schedule of {DEADLINES} months.

By paying this bill, you agree to send instructions to the financial institution that issue your card, to take payments from your card account, for the whole duration of this subscription. This imply that your card data are saved by {GATEWAY} and a series of payments will be initiated on your behalf, conforming to the payment schedule previously shown.

" confirm_payment_of_: "Pay: {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Booking confirmation" From 64dc23a9332f149d2d8ba0db07c5f2b9c3e2bdbf Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:35 +0200 Subject: [PATCH 102/142] New translations en.yml (French) --- config/locales/fr.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 41cc457a9..4a5ea19c3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -418,6 +418,8 @@ fr: admins: 'Administrateurs' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "le paramètre est verrouillé." about_title: "Le titre de la page \"À propos\"" @@ -532,3 +534,4 @@ fr: public_agenda_module: "Module d'agenda public" renew_pack_threshold: "Seuil de renouvellement des packs" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" From bbcbb40cc0df8c6d555fba8c2f9c472d2f626526 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:50 +0200 Subject: [PATCH 103/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 0bf4b52a6..aba71b046 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1181,6 +1181,8 @@ fr: an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" allow_booking: "Autoriser la réservation" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." @@ -1237,6 +1239,11 @@ 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "Général" title: "Titre" @@ -1389,14 +1396,19 @@ fr: category_deleted: "La catégorie a bien été supprimée" unable_to_delete: "Impossible de supprimer la catégorie : " local_payment: + validate_cart: "Validate my cart" offline_payment: "Paiement sur place" about_to_cash: "Vous êtes sur le point de confirmer l'encaissement par un moyen de paiement externe. Veuillez ne pas cliquer sur le bouton ci-dessous tant que vous n'avez pas encaissé le paiement demandé." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Moyen de paiement" method_card: "Carte bancaire en ligne" method_check: "Par chèques" card_collection_info: "En validant, vous serez invité à saisir les informations de carte bancaire du membre. Cette carte sera prélevée automatiquement aux échéances." check_collection_info: "En validant, vous confirmez être en possession de {DEADLINES} chèques permettant d'encaisser l'ensemble des mensualité." online_payment_disabled: "Le paiement en ligne n'est pas disponible. Vous ne pouvez pas encaisser cet échéancier de paiement en utilisant la carte bancaire en ligne." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: From 50eb9dc364cf2964815f0a97f15d5520da1627da Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:52 +0200 Subject: [PATCH 104/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 3b71f07e7..69434bae3 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -1181,6 +1181,8 @@ an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" allow_booking: "Allow booking" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1237,6 +1239,11 @@ 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "Generelt" title: "Tittel" @@ -1389,14 +1396,19 @@ category_deleted: "The category was successfully deleted" unable_to_delete: "Unable to delete the category: " local_payment: + validate_cart: "Validate my cart" offline_payment: "Payment on site" about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Payment method" method_card: "Online by card" method_check: "By check" card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines." check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments." online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: From 45b6a20fe13628240ee4d45a8cf6eb8d53a5f889 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:53 +0200 Subject: [PATCH 105/142] New translations app.shared.en.yml (French) --- config/locales/app.shared.fr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index 86533b5fa..8314120a5 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -125,6 +125,7 @@ fr: _the_general_terms_and_conditions: "les conditions générales de vente." payment_schedule_html: "

Vous êtes sur le point de souscrire à un échéancier de paiement de {DEADLINES} mois.

En payant cette facture, vous vous engagez à l'envoi d'instructions vers l'institution financière émettrice de votre carte, afin de prélever des paiements sur votre compte, pendant toute la durée de cet abonnement. Cela implique que les données de votre carte soient enregistrées par {GATEWAY} et qu'une série de paiements sera initiée en votre nom, conformément à l'échéancier de paiement précédemment affiché.

" confirm_payment_of_: "Payer : {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Validation réservation" From ee849d3446311a9bebe0ed86a3c032eaa2456981 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:54 +0200 Subject: [PATCH 106/142] New translations en.yml (Spanish) --- config/locales/es.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/es.yml b/config/locales/es.yml index c01081d27..6ac0679a4 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -418,6 +418,8 @@ es: admins: 'Administradores' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "the setting is locked." about_title: "\"About\" page title" @@ -532,3 +534,4 @@ es: public_agenda_module: "Public agenda module" renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" From c566e61eb0519fcd841fd3ad153549130617edcb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:55 +0200 Subject: [PATCH 107/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 5ae3ebcc0..f25a68d92 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -1181,6 +1181,8 @@ es: an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" allow_booking: "Allow booking" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." @@ -1237,6 +1239,11 @@ 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "General" title: "Title" @@ -1389,14 +1396,19 @@ es: category_deleted: "The category was successfully deleted" unable_to_delete: "Unable to delete the category: " local_payment: + validate_cart: "Validate my cart" offline_payment: "Payment on site" about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Payment method" method_card: "Online by card" method_check: "By check" card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines." check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments." online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: From 065391637b715f90c5b0b626eec3863942a1d6cb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:56 +0200 Subject: [PATCH 108/142] New translations app.shared.en.yml (Spanish) --- config/locales/app.shared.es.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.es.yml b/config/locales/app.shared.es.yml index 95db263e2..166def91b 100644 --- a/config/locales/app.shared.es.yml +++ b/config/locales/app.shared.es.yml @@ -125,6 +125,7 @@ es: _the_general_terms_and_conditions: "los términos y condiciones." payment_schedule_html: "

You're about to subscribe to a payment schedule of {DEADLINES} months.

By paying this bill, you agree to send instructions to the financial institution that issue your card, to take payments from your card account, for the whole duration of this subscription. This imply that your card data are saved by {GATEWAY} and a series of payments will be initiated on your behalf, conforming to the payment schedule previously shown.

" confirm_payment_of_: "Pay: {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Confirmar reserva" From 511a6cd087f026fef5a18dedffc70b128636a1c0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:57 +0200 Subject: [PATCH 109/142] New translations en.yml (German) --- config/locales/de.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/de.yml b/config/locales/de.yml index d3aad8ec0..0d0db4abc 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -418,6 +418,8 @@ de: admins: 'Administratoren' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "the setting is locked." about_title: "\"About\" page title" @@ -532,3 +534,4 @@ de: public_agenda_module: "Public agenda module" renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" From 28777a024bd5257533c77e9f2d876bc8510126f0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:58 +0200 Subject: [PATCH 110/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 8619681fe..9014fa609 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -1181,6 +1181,8 @@ de: an_error_occurred_saving_the_setting: "Beim Speichern der Einstellung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." book_overlapping_slots_info: "Erlauben / Verhindern der Reservierung von überlappenden Slots" allow_booking: "Allow booking" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Standarddauer für Slots" duration_minutes: "Dauer (in Minuten)" default_slot_duration_info: "Die Verfügbarkeit von Maschinen und Räumen ist in mehrere Slots dieser Dauer aufgeteilt. Dieser Wert kann je Verfügbarkeit überschrieben werden." @@ -1237,6 +1239,11 @@ 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "Allgemein" title: "Titel" @@ -1389,14 +1396,19 @@ de: category_deleted: "The category was successfully deleted" unable_to_delete: "Unable to delete the category: " local_payment: + validate_cart: "Validate my cart" offline_payment: "Payment on site" about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Payment method" method_card: "Online by card" method_check: "By check" card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines." check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments." online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: From 746e4ead3196e8f31fe38da5d1c1b718fd27d290 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:51:59 +0200 Subject: [PATCH 111/142] New translations app.shared.en.yml (German) --- config/locales/app.shared.de.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.de.yml b/config/locales/app.shared.de.yml index df1d1b67e..14b3494b1 100644 --- a/config/locales/app.shared.de.yml +++ b/config/locales/app.shared.de.yml @@ -125,6 +125,7 @@ de: _the_general_terms_and_conditions: "die allgemeinen Nutzungs- und Geschäftsbedingungen." payment_schedule_html: "

You're about to subscribe to a payment schedule of {DEADLINES} months.

By paying this bill, you agree to send instructions to the financial institution that issue your card, to take payments from your card account, for the whole duration of this subscription. This imply that your card data are saved by {GATEWAY} and a series of payments will be initiated on your behalf, conforming to the payment schedule previously shown.

" confirm_payment_of_: "Bezahlen: {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Buchungsbestätigung" From fb6e76258b2388ea73eb9959f9bd099c0e42f4db Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:00 +0200 Subject: [PATCH 112/142] New translations en.yml (Norwegian) --- config/locales/no.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/no.yml b/config/locales/no.yml index 7d2828387..36a5b70d1 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -418,6 +418,8 @@ admins: 'Administratorer' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "innstillingen er låst." about_title: "\"Om\" sidetittel" @@ -532,3 +534,4 @@ public_agenda_module: "Public agenda module" renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" From 4c350afe35a039321f3a90742380711207b960ad Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:01 +0200 Subject: [PATCH 113/142] New translations app.shared.en.yml (Norwegian) --- config/locales/app.shared.no.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.no.yml b/config/locales/app.shared.no.yml index f50f98162..85e02cb87 100644 --- a/config/locales/app.shared.no.yml +++ b/config/locales/app.shared.no.yml @@ -125,6 +125,7 @@ _the_general_terms_and_conditions: "generelle vilkår og betingelser." payment_schedule_html: "

Du er i ferd med å abonnere på en betalingsplan på {DEADLINES} måneder.

Ved å betale denne regningen godtar du å sende instrukser til den finansielle institusjonen som utsteder kortet, for å ta betalinger fra din kortkonto, så lenge det varer i dette abonnementet. Dette antyder at kortdataene dine lagres av {GATEWAY} og en rekke betalinger vil bli satt i gang på dine vegne, i samsvar med betalingsplanen som tidligere er vist

" confirm_payment_of_: "Betal: {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Bestillingsbekreftelse" From e295fc0b8894542f9c3b16883baa5617b58c1614 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:03 +0200 Subject: [PATCH 114/142] New translations en.yml (Portuguese) --- config/locales/pt.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 0035c7e4e..fbec30fa9 100755 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -418,6 +418,8 @@ pt: admins: 'Administradores' cart_items: free_extension: "Free extension of a subscription, until %{DATE}" + statistic_profile: + birthday_in_past: "The date of birth must be in the past" settings: locked_setting: "the setting is locked." about_title: "\"About\" page title" @@ -532,3 +534,4 @@ pt: public_agenda_module: "Public agenda module" renew_pack_threshold: "Threshold for packs renewal" pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" From 74f12d7181ed2c5e8395fa8e8892824651e97908 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:04 +0200 Subject: [PATCH 115/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 3be57eea0..b1f2260f4 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -1181,6 +1181,8 @@ pt: an_error_occurred_saving_the_setting: "Ocorreu um erro ao salvar a configuração. Por favor, tente novamente mais tarde." book_overlapping_slots_info: "Permitir / impedir a reserva de slots sobrepostos" allow_booking: "Allow booking" + overlapping_categories: "Overlapping categories" + overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." default_slot_duration: "Duração padrão para slots" duration_minutes: "Duração (em minutos)" default_slot_duration_info: "Máquina e espaço disponíveis são divididos em vários slots desta duração. Esse valor pode ser substituído por disponibilidade." @@ -1237,6 +1239,11 @@ pt: 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" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" general: general: "Geral" title: "Título" @@ -1389,14 +1396,19 @@ pt: category_deleted: "The category was successfully deleted" unable_to_delete: "Unable to delete the category: " local_payment: + validate_cart: "Validate my cart" offline_payment: "Payment on site" about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment." + about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." payment_method: "Payment method" method_card: "Online by card" method_check: "By check" card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines." check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments." online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." #feature tour tour: conclusion: From e6f90b17495e55a33bd8afdb4ec7a282cb6eddcf Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:05 +0200 Subject: [PATCH 116/142] New translations app.shared.en.yml (Portuguese) --- config/locales/app.shared.pt.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.pt.yml b/config/locales/app.shared.pt.yml index 9ab2cd4d4..2120b312f 100755 --- a/config/locales/app.shared.pt.yml +++ b/config/locales/app.shared.pt.yml @@ -125,6 +125,7 @@ pt: _the_general_terms_and_conditions: "os termos e condições." payment_schedule_html: "

You're about to subscribe to a payment schedule of {DEADLINES} months.

By paying this bill, you agree to send instructions to the financial institution that issue your card, to take payments from your card account, for the whole duration of this subscription. This imply that your card data are saved by {GATEWAY} and a series of payments will be initiated on your behalf, conforming to the payment schedule previously shown.

" confirm_payment_of_: "Pay: {AMOUNT}" + validate: "Validate" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Confirmação de reserva" From a8d1e12b7c891c3ab70c22b756703affbb647b1b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:06 +0200 Subject: [PATCH 117/142] New translations en.yml (Zulu) --- config/locales/zu.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/locales/zu.yml b/config/locales/zu.yml index 8d32a07ef..b96924f49 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -418,6 +418,8 @@ zu: admins: 'crwdns3769:0crwdne3769:0' cart_items: free_extension: "crwdns22091:0%{DATE}crwdne22091:0" + statistic_profile: + birthday_in_past: "crwdns22127:0crwdne22127:0" settings: locked_setting: "crwdns21632:0crwdne21632:0" about_title: "crwdns21634:0crwdne21634:0" @@ -532,3 +534,4 @@ zu: public_agenda_module: "crwdns21874:0crwdne21874:0" renew_pack_threshold: "crwdns22032:0crwdne22032:0" pack_only_for_subscription: "crwdns22093:0crwdne22093:0" + overlapping_categories: "crwdns22129:0crwdne22129:0" From 86e25a0a53b022ed00f500b1ddc6d97882452b46 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:08 +0200 Subject: [PATCH 118/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 127336f79..fc2dbf738 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -1181,6 +1181,8 @@ zu: an_error_occurred_saving_the_setting: "crwdns20380:0crwdne20380:0" book_overlapping_slots_info: "crwdns20642:0crwdne20642:0" allow_booking: "crwdns22035:0crwdne22035:0" + overlapping_categories: "crwdns22107:0crwdne22107:0" + overlapping_categories_info: "crwdns22109:0crwdne22109:0" default_slot_duration: "crwdns20646:0crwdne20646:0" duration_minutes: "crwdns20648:0crwdne20648:0" default_slot_duration_info: "crwdns20650:0crwdne20650:0" @@ -1237,6 +1239,11 @@ 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" + overlapping_options: + training_reservations: "crwdns22111:0crwdne22111:0" + machine_reservations: "crwdns22113:0crwdne22113:0" + space_reservations: "crwdns22115:0crwdne22115:0" + events_reservations: "crwdns22117:0crwdne22117:0" general: general: "crwdns20726:0crwdne20726:0" title: "crwdns20728:0crwdne20728:0" @@ -1389,14 +1396,19 @@ zu: category_deleted: "crwdns21618:0crwdne21618:0" unable_to_delete: "crwdns21620:0crwdne21620:0" local_payment: + validate_cart: "crwdns22119:0crwdne22119:0" offline_payment: "crwdns22006:0crwdne22006:0" about_to_cash: "crwdns22008:0crwdne22008:0" + about_to_confirm: "crwdns22121:0ITEM={ITEM}crwdne22121:0" payment_method: "crwdns22010:0crwdne22010:0" method_card: "crwdns22012:0crwdne22012:0" method_check: "crwdns22014:0crwdne22014:0" card_collection_info: "crwdns22016:0crwdne22016:0" check_collection_info: "crwdns22018:0{DEADLINES}crwdne22018:0" online_payment_disabled: "crwdns22020:0crwdne22020:0" + check_list_setting: + save: 'crwdns22123:0crwdne22123:0' + customization_of_SETTING_successfully_saved: "crwdns22125:0{SETTING}crwdne22125:0" #feature tour tour: conclusion: From 3512d392276acae76cfb3fd1aed3af122ef82e99 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:52:09 +0200 Subject: [PATCH 119/142] New translations app.shared.en.yml (Zulu) --- config/locales/app.shared.zu.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/app.shared.zu.yml b/config/locales/app.shared.zu.yml index 9db95d3cc..5d9067c6a 100644 --- a/config/locales/app.shared.zu.yml +++ b/config/locales/app.shared.zu.yml @@ -125,6 +125,7 @@ zu: _the_general_terms_and_conditions: "crwdns21488:0crwdne21488:0" payment_schedule_html: "crwdns21490:0{DEADLINES}crwdnd21490:0{GATEWAY}crwdne21490:0" confirm_payment_of_: "crwdns21492:0{AMOUNT}crwdne21492:0" + validate: "crwdns22131:0crwdne22131:0" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "crwdns9587:0crwdne9587:0" From f273372682084e8596ea6cd435cf46264d1b8ed7 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 15:55:48 +0200 Subject: [PATCH 120/142] fix function call --- .../components/payment/local-payment/local-payment-form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx index 9a320f677..0192fd4b8 100644 --- a/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx +++ b/app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx @@ -127,8 +127,8 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce return ( - {!paymentSchedule && !isFreeOfCharge &&

{t('app.admin.local_payment.about_to_cash')}

} - {!paymentSchedule && isFreeOfCharge &&

{t('app.admin.local_payment.about_to_confirm', { ITEM: mainItemType() })}

} + {!paymentSchedule && !isFreeOfCharge() &&

{t('app.admin.local_payment.about_to_cash')}

} + {!paymentSchedule && isFreeOfCharge() &&

{t('app.admin.local_payment.about_to_confirm', { ITEM: mainItemType() })}

} {paymentSchedule &&
From f8e91ce5df992e7faf328a5f59da219dcdae8eea Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:02:28 +0200 Subject: [PATCH 121/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index aba71b046..886c93510 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -866,7 +866,7 @@ fr: expires_at: "Expire le :" price_: "Prix :" offer_free_days: "Offrir des jours gratuits" - renew_subscription: "Renew the subscription" + renew_subscription: "Renouveler l'abonnement" user_has_no_current_subscription: "L'utilisateur n'a pas d'abonnement en cours." subscribe_to_a_plan: "Souscrire à un abonnement" trainings: "Formations" @@ -901,23 +901,23 @@ fr: cannot_extend_own_subscription: "Vous ne pouvez pas prolonger votre propre abonnement. Veuillez demander à un autre gestionnaire ou à un administrateur de prolonger votre abonnement." #extend a subscription for free free_extend_modal: - extend_subscription: "Extend the subscription" - offer_free_days_infos: "You are about to extend the user's subscription by offering him free additional days." - credits_will_remain_unchanged: "The balance of free credits (training / machines / spaces) of the user will remain unchanged." - current_expiration: "Current subscription will expire at:" - DATE_TIME: "{DATE} {TIME}" - new_expiration_date: "New expiration date:" - number_of_free_days: "Number of free days:" - extend: "Extend" - extend_success: "The subscription was successfully extended for free" + extend_subscription: "Prolonger l'abonnement" + offer_free_days_infos: "Vous êtes sur le point de prolonger l'abonnement de l'utilisateur en lui offrant des jours supplémentaires gratuits." + credits_will_remain_unchanged: "Le solde de crédits gratuits (formations / machines / espaces) de l'utilisateur restera inchangé." + current_expiration: "L'abonnement actuel expirera le :" + DATE_TIME: "{DATE} à {TIME}" + new_expiration_date: "Nouvelle date d'expiration :" + number_of_free_days: "Nombre de jours gratuits :" + extend: "Prolonger" + extend_success: "L'abonnement a été prolongé gratuitement" #renew a subscription renew_subscription_modal: - renew_subscription: "Renew the subscription" - renew_subscription_info: "You are about to renew the user's subscription by charging him again for his current subscription." - credits_will_be_reset: "The balance of free credits (training / machines / spaces) of the user will be reset, unused credits will be lost." - current_expiration: "Current subscription will expire at:" - new_start: "The new subscription will start at:" - new_expiration_date: "The new subscription will expire at:" + renew_subscription: "Renouveler l'abonnement" + renew_subscription_info: "Vous êtes sur le point de renouveler l'abonnement de l'utilisateur en lui refacturant son abonnement actuel." + credits_will_be_reset: "Le solde de crédits gratuits (formations / machines / espaces) de l'utilisateur sera remis à zéro, ses crédits non utilisés seront perdu." + current_expiration: "L'abonnement actuel expirera le :" + new_start: "La nouvelle souscription commencera le :" + new_expiration_date: "Le nouvel abonnement expirera le :" payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." From d009381dabd96cb9d23a1d62053b8b18cb390b3b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:03:26 +0200 Subject: [PATCH 122/142] remove unused translations --- config/locales/app.admin.en.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index a97e27808..0753c022d 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -918,10 +918,6 @@ en: current_expiration: "Current subscription will expire at:" new_start: "The new subscription will start at:" new_expiration_date: "The new subscription will expire at:" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From 2b2ee29d92264faccbf7c53ffeec18d1307d1b96 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:08 +0200 Subject: [PATCH 123/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 886c93510..6c80f753b 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -918,10 +918,6 @@ fr: current_expiration: "L'abonnement actuel expirera le :" new_start: "La nouvelle souscription commencera le :" new_expiration_date: "Le nouvel abonnement expirera le :" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From a9059eee4e19878eb6b7048cb6e9d4ca2cbc50ec Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:09 +0200 Subject: [PATCH 124/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 69434bae3..45e99360f 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -918,10 +918,6 @@ current_expiration: "Current subscription will expire at:" new_start: "The new subscription will start at:" new_expiration_date: "The new subscription will expire at:" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From f5c47cf6098bfb888a880589a21891dbb02cdacd Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:11 +0200 Subject: [PATCH 125/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index f25a68d92..b133123c6 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -918,10 +918,6 @@ es: current_expiration: "Current subscription will expire at:" new_start: "The new subscription will start at:" new_expiration_date: "The new subscription will expire at:" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From a77729423166f93940be4814a79abec16a57fd31 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:14 +0200 Subject: [PATCH 126/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 9014fa609..3b007eb21 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -918,10 +918,6 @@ de: current_expiration: "Current subscription will expire at:" new_start: "The new subscription will start at:" new_expiration_date: "The new subscription will expire at:" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From 951b52cb0355f4c6f50d104efe3cf5a862b6915b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:18 +0200 Subject: [PATCH 127/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index b1f2260f4..b4cb20ebd 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -918,10 +918,6 @@ pt: current_expiration: "Current subscription will expire at:" new_start: "The new subscription will start at:" new_expiration_date: "The new subscription will expire at:" - payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month." - payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments." - one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now." - one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment." pay_in_one_go: "Pay in one go" renew: "Renew" renew_success: "The subscription was successfully renewed" From cc21a70500e967977a595e9ed551b4c9609c1b44 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:04:20 +0200 Subject: [PATCH 128/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index fc2dbf738..7abc1a135 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -918,10 +918,6 @@ zu: current_expiration: "crwdns22071:0crwdne22071:0" new_start: "crwdns22073:0crwdne22073:0" new_expiration_date: "crwdns22075:0crwdne22075:0" - payment_schedule_card: "crwdns22077:0crwdne22077:0" - payment_schedule_check: "crwdns22079:0crwdne22079:0" - one_payment_card: "crwdns22081:0crwdne22081:0" - one_payment_check: "crwdns22083:0crwdne22083:0" pay_in_one_go: "crwdns22085:0crwdne22085:0" renew: "crwdns22087:0crwdne22087:0" renew_success: "crwdns22089:0crwdne22089:0" From f11b6204117b94a05fffd4cb00dc897fadbb65a7 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:12:24 +0200 Subject: [PATCH 129/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 6c80f753b..98bb1c4bb 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -918,9 +918,9 @@ fr: current_expiration: "L'abonnement actuel expirera le :" new_start: "La nouvelle souscription commencera le :" new_expiration_date: "Le nouvel abonnement expirera le :" - pay_in_one_go: "Pay in one go" - renew: "Renew" - renew_success: "The subscription was successfully renewed" + pay_in_one_go: "Payer en une fois" + renew: "Renouveler" + renew_success: "L'abonnement a bien été renouvelé" #take a new subscription subscribe_modal: subscribe_USER: "Subscribe for {USER}" From affd96ddb3eda1f06f1bd470622f810247e3a13a Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:12:43 +0200 Subject: [PATCH 130/142] 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 0753c022d..570dd1a24 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -923,7 +923,7 @@ en: renew_success: "The subscription was successfully renewed" # take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From a9eaa46d1fe5a3c10982206a5c0422ab8d75da95 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:29 +0200 Subject: [PATCH 131/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 98bb1c4bb..989e23e0a 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -923,7 +923,7 @@ fr: renew_success: "L'abonnement a bien été renouvelé" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From b44030cf92e88dbbd82e244501f82662befa6862 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:31 +0200 Subject: [PATCH 132/142] New translations app.admin.en.yml (Norwegian) --- config/locales/app.admin.no.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 45e99360f..858780308 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -923,7 +923,7 @@ renew_success: "The subscription was successfully renewed" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From 10afbf0ce3c0e5c0d9e3eb9573b66f70b5365edc Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:34 +0200 Subject: [PATCH 133/142] New translations app.admin.en.yml (Spanish) --- config/locales/app.admin.es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index b133123c6..9f2a8426e 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -923,7 +923,7 @@ es: renew_success: "The subscription was successfully renewed" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From db4159f81a44816588aad15c2f227956f515e505 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:36 +0200 Subject: [PATCH 134/142] New translations app.admin.en.yml (German) --- config/locales/app.admin.de.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index 3b007eb21..aa500c49d 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -923,7 +923,7 @@ de: renew_success: "The subscription was successfully renewed" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From dde3d0614ca974a81084185230143884f993113e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:40 +0200 Subject: [PATCH 135/142] New translations app.admin.en.yml (Portuguese) --- config/locales/app.admin.pt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index b4cb20ebd..ad0859e89 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -923,7 +923,7 @@ pt: renew_success: "The subscription was successfully renewed" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe for {USER}" + subscribe_USER: "Subscribe {USER}" subscribe: "Subscribe" select_plan: "Please select a plan" pay_in_one_go: "Pay in one go" From 7332b7ff16affd52f0ffa6e3bfb96e1970a1ca89 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:14:42 +0200 Subject: [PATCH 136/142] New translations app.admin.en.yml (Zulu) --- config/locales/app.admin.zu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 7abc1a135..4a1156656 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -923,7 +923,7 @@ zu: renew_success: "crwdns22089:0crwdne22089:0" #take a new subscription subscribe_modal: - subscribe_USER: "crwdns22097:0{USER}crwdne22097:0" + subscribe_USER: "crwdns22133:0{USER}crwdne22133:0" subscribe: "crwdns22099:0crwdne22099:0" select_plan: "crwdns22101:0crwdne22101:0" pay_in_one_go: "crwdns22103:0crwdne22103:0" From 2fb78409498bd3004406fc2bf2b2f8510aa7eb73 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:19:38 +0200 Subject: [PATCH 137/142] New translations en.yml (French) --- config/locales/fr.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 4a5ea19c3..2dcf06c18 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -417,9 +417,9 @@ fr: #name of the user's group for administrators admins: 'Administrateurs' cart_items: - free_extension: "Free extension of a subscription, until %{DATE}" + free_extension: "Extension gratuite d'un abonnement, jusqu'au %{DATE}" statistic_profile: - birthday_in_past: "The date of birth must be in the past" + birthday_in_past: "La date de naissance doit être dans le passé" settings: locked_setting: "le paramètre est verrouillé." about_title: "Le titre de la page \"À propos\"" @@ -533,5 +533,5 @@ fr: payzen_currency: "Devise PayZen" public_agenda_module: "Module d'agenda public" renew_pack_threshold: "Seuil de renouvellement des packs" - pack_only_for_subscription: "Restrict packs for subscribers" - overlapping_categories: "Categories for overlapping booking prevention" + pack_only_for_subscription: "Restreindre les packs pour les abonnés" + overlapping_categories: "Catégories pour la prévention du chevauchement des réservations" From 89c046824c17772c06092a4a4f033b8fa5ed4b6f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:19:50 +0200 Subject: [PATCH 138/142] New translations app.admin.en.yml (French) --- config/locales/app.admin.fr.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 989e23e0a..0ff61d212 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -923,10 +923,10 @@ fr: renew_success: "L'abonnement a bien été renouvelé" #take a new subscription subscribe_modal: - subscribe_USER: "Subscribe {USER}" - subscribe: "Subscribe" - select_plan: "Please select a plan" - pay_in_one_go: "Pay in one go" + subscribe_USER: "Abonner {USER}" + subscribe: "Abonner" + select_plan: "Veuillez choisir une formule d'abonnement" + pay_in_one_go: "Payer en une fois" subscription_success: "" #add a new administrator to the platform admins_new: @@ -1177,8 +1177,8 @@ fr: an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" allow_booking: "Autoriser la réservation" - overlapping_categories: "Overlapping categories" - overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations." + overlapping_categories: "Catégories des chevauchements" + overlapping_categories_info: "Éviter la réservation de créneaux qui se chevauchent sera effectué en comparant la date et l'heure des catégories de réservations suivantes." default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." @@ -1236,10 +1236,10 @@ fr: 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" overlapping_options: - training_reservations: "Trainings" + training_reservations: "Formations" machine_reservations: "Machines" - space_reservations: "Spaces" - events_reservations: "Events" + space_reservations: "Espaces" + events_reservations: "Événements" general: general: "Général" title: "Titre" @@ -1392,10 +1392,10 @@ fr: category_deleted: "La catégorie a bien été supprimée" unable_to_delete: "Impossible de supprimer la catégorie : " local_payment: - validate_cart: "Validate my cart" + validate_cart: "Valider mon panier" offline_payment: "Paiement sur place" about_to_cash: "Vous êtes sur le point de confirmer l'encaissement par un moyen de paiement externe. Veuillez ne pas cliquer sur le bouton ci-dessous tant que vous n'avez pas encaissé le paiement demandé." - about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}." + about_to_confirm: "Vous êtes sur le point de confirmer votre {ITEM, select, subscription{abonnement} other{réservation}}." payment_method: "Moyen de paiement" method_card: "Carte bancaire en ligne" method_check: "Par chèques" @@ -1403,8 +1403,8 @@ fr: check_collection_info: "En validant, vous confirmez être en possession de {DEADLINES} chèques permettant d'encaisser l'ensemble des mensualité." online_payment_disabled: "Le paiement en ligne n'est pas disponible. Vous ne pouvez pas encaisser cet échéancier de paiement en utilisant la carte bancaire en ligne." check_list_setting: - save: 'Save' - customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." + save: 'Enregistrer' + customization_of_SETTING_successfully_saved: "La personnalisation de {SETTING} a bien été enregistrée." #feature tour tour: conclusion: From 72a73b3e248e811ca3f79a16afdd74adae4fb3eb Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:21:45 +0200 Subject: [PATCH 139/142] New translations app.shared.en.yml (French) --- config/locales/app.shared.fr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index 8314120a5..1283efb00 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -125,7 +125,7 @@ fr: _the_general_terms_and_conditions: "les conditions générales de vente." payment_schedule_html: "

Vous êtes sur le point de souscrire à un échéancier de paiement de {DEADLINES} mois.

En payant cette facture, vous vous engagez à l'envoi d'instructions vers l'institution financière émettrice de votre carte, afin de prélever des paiements sur votre compte, pendant toute la durée de cet abonnement. Cela implique que les données de votre carte soient enregistrées par {GATEWAY} et qu'une série de paiements sera initiée en votre nom, conformément à l'échéancier de paiement précédemment affiché.

" confirm_payment_of_: "Payer : {AMOUNT}" - validate: "Validate" + validate: "Valider" #dialog of on site payment for reservations valid_reservation_modal: booking_confirmation: "Validation réservation" @@ -418,7 +418,7 @@ fr: NUMBER_monthly_payment_of_AMOUNT: "{NUMBER} {NUMBER, plural, =1{mensualité} other{mensualités}} de {AMOUNT}" first_debit: "Premier prélèvement le jour de la commande." debit: "Prélèvement le jour de la commande." - view_full_schedule: "View the complete payment schedule" + view_full_schedule: "Voir tout l'échéancier de paiement" confirm_and_pay: "Valider et payer" you_have_settled_the_following_TYPE: "Vous avez réglé {TYPE, select, Machine{les créneaux machines suivants} Training{la formation suivante} other{les éléments suivants}} :" you_have_settled_a_: "Vous avez réglé un" From c1a9a4a0752bceac8f4c4ebdc06718b99ec1e6ca Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 16:50:18 +0200 Subject: [PATCH 140/142] reorganized documentation --- README.md | 52 ++++---------------------------------------- doc/README.md | 6 ++++- doc/open_projects.md | 18 +++++++++++++++ doc/plugins.md | 13 +++++++++++ 4 files changed, 40 insertions(+), 49 deletions(-) create mode 100644 doc/open_projects.md create mode 100644 doc/plugins.md diff --git a/README.md b/README.md index 7a108ee3b..0840d78b9 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,6 @@ Fab-manager is the Fab Lab management solution. It provides a comprehensive, web Please visit [fab-manager.com](https://www.fab-manager.com/) for more information about this software and its features. -##### Table of Contents -1. [Contributing](#contributing) -2. [Documentation](#documentation) -3. [Open Projects](#open-projects) -4. [Plugins](#plugins) -5. [Single Sign-On](#sso) - ## Contributing @@ -26,45 +19,8 @@ Contributions are welcome. Please read [the contribution guidelines](CONTRIBUTIN The full documentation is available at [doc.fab.mn](http://doc.fab.mn). - -## Open Projects + +## Copyright -**This configuration is optional.** - -You can configure your Fab-manager to synchronize every project with the [Open Projects platform](https://github.com/sleede/openlab-projects). -It's very simple and straightforward and in return, your users will be able to search over projects from all Fab-manager instances from within your platform. -The deal is fair, you share your projects and as reward you benefits from projects of the whole community. - -If you want to try it, you can visit [this Fab-manager](https://fablab.lacasemate.fr/#!/projects) and see projects from different Fab-managers. - -To start using this awesome feature, there are a few steps: -- send a mail to **contact@fab-manager.com** asking for your Open Projects client's credentials and giving them the name and the URL of your Fab-manager, they will give you an `App ID` and a `secret` -- fill in the value of the keys in Admin > Projects > Settings > Projects sharing -- export your projects to open-projects (if you already have projects created on your Fab-manager, unless you can skip that part) executing this command: `bundle exec rails fablab:openlab:bulk_export` - -**IMPORTANT: please run your server in production mode.** - -Go to your projects gallery and enjoy seeing your projects available from everywhere ! That's all. - - -## Plugins - -Fab-manager has a system of plugins mainly inspired by [Discourse](https://github.com/discourse/discourse) architecture. - -It enables you to write plugins which can: -- have its proper models and database tables -- have its proper assets (js & css) -- override existing behaviours of Fab-manager -- add features by adding views, controllers, ect... - -To install a plugin, you just have to copy the plugin folder which contains its code into the folder `plugins` of Fab-manager. - -You can see an example on the [repo of navinum gamification plugin](https://github.com/sleede/navinum-gamification) - - -## Single Sign-On - -Fab-manager can be connected to a [Single Sign-On](https://en.wikipedia.org/wiki/Single_sign-on) server which will provide its own authentication for the platform's users. -Currently, OAuth 2 is the only supported protocol for SSO authentication. - -For an example of how to use configure an SSO in Fab-manager, please read [sso_with_github.md](doc/sso_with_github.md). +This free software is available under the terms of the [GNU Affero General Public License](LICENSE.md). +Fab-manager is developed by [sleede](https://www.sleede.com/) and the [open-open contributors](https://github.com/sleede/fab-manager/graphs/contributors) of the community. diff --git a/doc/README.md b/doc/README.md index 8c6aa6266..8775de5ee 100644 --- a/doc/README.md +++ b/doc/README.md @@ -26,10 +26,12 @@ The following guides are designed for the people that perform software maintenan - [Advanced PostgreSQL usage](postgresql_readme.md) -- [Connecting a SSO using oAuth 2.0](sso_with_github.md) +- [Connecting an SSO using oAuth 2.0](sso_with_github.md) - [Upgrade from Fab-manager v1.0](upgrade_v1.md) +- [Configuring OpenProjects](open_projects.md) + #### Upgrades procedures - [PostgreSQL](postgres_upgrade.md) - [ElasticSearch](elastic_upgrade.md) @@ -43,6 +45,8 @@ The following guides should help those who want to contribute to the code. #### Architecture - [Code architecture](architecture.md) +- [Plugins](plugins.md) + #### How to setup a development environment - [With docker-compose](development_readme.md) diff --git a/doc/open_projects.md b/doc/open_projects.md new file mode 100644 index 000000000..cd8eab990 --- /dev/null +++ b/doc/open_projects.md @@ -0,0 +1,18 @@ +# Open Projects + +**This configuration is optional.** + +You can configure your Fab-manager to synchronize every project with the [Open Projects platform](https://github.com/sleede/openlab-projects). +It's very simple and straightforward and in return, your users will be able to search over projects from all Fab-manager instances from within your platform. +The deal is fair, you share your projects and as reward you benefits from projects of the whole community. + +If you want to try it, you can visit [this Fab-manager](https://fablab.lacasemate.fr/#!/projects) and see projects from different Fab-managers. + +To start using this awesome feature, there are a few steps: +- send a mail to **contact@fab-manager.com** asking for your Open Projects client's credentials and giving them the name and the URL of your Fab-manager, they will give you an `App ID` and a `secret` +- fill in the value of the keys in Admin > Projects > Settings > Projects sharing +- export your projects to open-projects (if you already have projects created on your Fab-manager, unless you can skip that part) executing this command: `bundle exec rails fablab:openlab:bulk_export` + +**IMPORTANT: please run your server in production mode.** + +Go to your projects gallery and enjoy seeing your projects available from everywhere ! That's all. diff --git a/doc/plugins.md b/doc/plugins.md new file mode 100644 index 000000000..7c87f9ca9 --- /dev/null +++ b/doc/plugins.md @@ -0,0 +1,13 @@ +# Plugins + +Fab-manager has a system of plugins mainly inspired by [Discourse](https://github.com/discourse/discourse) architecture. + +It enables you to write plugins which can: +- have its proper models and database tables +- have its proper assets (js & css) +- override existing behaviours of Fab-manager +- add features by adding views, controllers, ect... + +To install a plugin, you just have to copy the plugin folder which contains its code into the folder `plugins` of Fab-manager. + +You can see an example on the [repo of navinum gamification plugin](https://github.com/sleede/navinum-gamification) From 9be0dcddd2bfe3a0bd2a429fdb6da8db117212b8 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 17:53:02 +0200 Subject: [PATCH 141/142] [bug] 3DS confirmation is not asked when an admin is subscribing a user through a payment schedule using PayZen --- CHANGELOG.md | 1 + .../src/javascript/components/payment/payzen/payzen-form.tsx | 1 + .../src/javascript/components/payment/stripe/stripe-form.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f04bd76d7..2b7d35be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Fix a bug: invalid amount provided to the PayZen payment gateway when using a currency with anything else than 2 decimals - Fix a bug: incorrect behavior for the setting "email confirmation required" - Fix a bug: invalid text shown when a member confirms a free cart +- Fix a bug: 3DS confirmation is not asked when an admin is subscribing a user through a payment schedule using PayZen - Updated @rails/webpacker to 5.4.3 - Updated react-refresh-webpack-plugin to 0.5.1 - Updated react-refresh to 0.10.0 diff --git a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx index d1d15f231..2e82865e9 100644 --- a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx +++ b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx @@ -126,6 +126,7 @@ export const PayzenForm: React.FC = ({ onSubmit, onSuccess, onE */ const handleSubmit = async (event: FormEvent): Promise => { event.preventDefault(); + event.stopPropagation(); onSubmit(); try { diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx index 3d017fb95..3b62d3a89 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx @@ -23,6 +23,7 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, on */ const handleSubmit = async (event: FormEvent): Promise => { event.preventDefault(); + event.stopPropagation(); onSubmit(); // Stripe.js has not loaded yet From 72421f99a5536494d2e18bd7e4f605b18fb27297 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Fri, 22 Oct 2021 17:54:31 +0200 Subject: [PATCH 142/142] Version 5.1.11 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7d35be9..f293f98dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog Fab-manager +## v5.1.11 2021 October 22 + - Refactored subscription new/renew/free extend interfaces and API - Ability to configure data sources for preventing booking on overlapping slots - Updated production documentation diff --git a/package.json b/package.json index c5e158388..c967a2f55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.1.10", + "version": "5.1.11", "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",
{expandCollapseIcon(p.id)} {p.reference}{FormatLib.date(p.created_at)}{FormatLib.date(_.minBy(p.items, 'due_date').due_date)} {FormatLib.price(p.total)}{p.user.name}{downloadButton(TargetType.PaymentSchedule, p.id)}