From 193ee4ffe98a2fbc27f49a056566de7d924d411b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 12:00:23 +0100 Subject: [PATCH 1/9] (bug) case-sensitive emails - for sso code sending - for adminsys configuration --- CHANGELOG.md | 3 +++ app/controllers/api/auth_providers_controller.rb | 3 +-- app/models/user.rb | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 143d7b3a6..c43576ee5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog Fab-manager +- Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. +- Fix a bug: the adminsys email was case-sensitive. + # v5.3.1 2022 January 17 - Definition of extended prices for spaces is now made in hours (previously in minutes) diff --git a/app/controllers/api/auth_providers_controller.rb b/app/controllers/api/auth_providers_controller.rb index 6a4b5bea0..071b6a927 100644 --- a/app/controllers/api/auth_providers_controller.rb +++ b/app/controllers/api/auth_providers_controller.rb @@ -52,10 +52,9 @@ class API::AuthProvidersController < API::ApiController @previous = AuthProvider.previous end - def send_code authorize AuthProvider - user = User.find_by(email: params[:email]) + user = User.find_by('lower(email) = ?', params[:email]&.downcase) if user&.auth_token if AuthProvider.active.providable_type != DatabaseProvider.name diff --git a/app/models/user.rb b/app/models/user.rb index 4c0c2f36a..40efffd78 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -121,7 +121,7 @@ class User < ApplicationRecord def self.adminsys return unless Rails.application.secrets.adminsys_email.present? - User.find_by(email: Rails.application.secrets.adminsys_email) + User.find_by('lower(email) = ?', Rails.application.secrets.adminsys_email&.downcase) end def training_machine?(machine) From e4a0798b8af9ee704d568be8d6ced3ef83e58a83 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 14:01:34 +0100 Subject: [PATCH 2/9] (bug) statistics not built for instances with plans created before v4.3.3, the StatisticType.key does not match Plan.duration because of a behavior change in rails framework. (v4.3.3 introduces a framework upgrade) --- CHANGELOG.md | 2 ++ app/models/concerns/stat_concern.rb | 6 ++-- ...123741_fix_subscription_statistic_types.rb | 33 +++++++++++++++++++ db/schema.rb | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20220118123741_fix_subscription_statistic_types.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index c43576ee5..a4ace187c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # Changelog Fab-manager +- Fix a bug: statistics not built for instances with plans created before v4.3.3 - Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. - Fix a bug: the adminsys email was case-sensitive. +- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2020,04]` # v5.3.1 2022 January 17 diff --git a/app/models/concerns/stat_concern.rb b/app/models/concerns/stat_concern.rb index 6fb3bc224..58360ae3d 100644 --- a/app/models/concerns/stat_concern.rb +++ b/app/models/concerns/stat_concern.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StatConcern extend ActiveSupport::Concern @@ -12,7 +14,7 @@ module StatConcern attribute :group, String # has include Elasticsearch::Persistence::Model - index_name "stats" - document_type self.to_s.demodulize.underscore + index_name 'stats' + document_type to_s.demodulize&.underscore end end diff --git a/db/migrate/20220118123741_fix_subscription_statistic_types.rb b/db/migrate/20220118123741_fix_subscription_statistic_types.rb new file mode 100644 index 000000000..6aed85078 --- /dev/null +++ b/db/migrate/20220118123741_fix_subscription_statistic_types.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# From Fab-manager v4.3.3, the behavior of ActiveSupport::Duration#to_i has changed. +# Previously, a month = 30 days, from since a month = 30.436875 days. +# Also, previously a year = 365.25 days, from since a year = 365.2425 days. +# This introduced a bug due to the key of the statistic types for subscriptions were equal to +# the number of seconds of the plan duration, but this duration has changed due to the +# change reported above. +# This migration fixes the problem by changing the key of the statistic types for subscriptions +# to the new plans durations. +class FixSubscriptionStatisticTypes < ActiveRecord::Migration[5.2] + def up + one_month = 2_592_000 + (1..12).each do |n| + StatisticType.where(key: (one_month * n).to_s).update_all(key: n.months.to_i) + end + one_year = 31_557_600 + (1..10).each do |n| + StatisticType.where(key: (one_year * n).to_s).update_all(key: n.years.to_i) + end + end + + def down + one_month = 2_592_000 + (1..12).each do |n| + StatisticType.where(key: n.months.to_i.to_s).update_all(key: (one_month * n).to_i) + end + one_year = 31_557_600 + (1..10).each do |n| + StatisticType.where(key: n.years.to_i).update_all(key: (one_year * n).to_s) + end + end +end diff --git a/db/schema.rb b/db/schema.rb index efe44799d..eaef1c8e7 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: 2022_01_11_134253) do +ActiveRecord::Schema.define(version: 2022_01_18_123741) do # These are extensions that must be enabled in order to support this database enable_extension "fuzzystrmatch" From 5b69c0f46fe85667287ffdeb075df6569612dc8b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 15:34:21 +0100 Subject: [PATCH 3/9] test statistics generation --- CHANGELOG.md | 1 + test/fixtures/availabilities.yml | 10 ++++ test/fixtures/machines_availabilities.yml | 5 ++ test/services/statistic_service_test.rb | 61 +++++++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 test/services/statistic_service_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index a4ace187c..3d9cad46b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog Fab-manager +- Add a test for statistics generation - Fix a bug: statistics not built for instances with plans created before v4.3.3 - Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. - Fix a bug: the adminsys email was case-sensitive. diff --git a/test/fixtures/availabilities.yml b/test/fixtures/availabilities.yml index 24b340890..70ba0eb65 100644 --- a/test/fixtures/availabilities.yml +++ b/test/fixtures/availabilities.yml @@ -179,3 +179,13 @@ availability_18: updated_at: 2017-02-15 15:53:35.154433000 Z nb_total_places: 5 destroying: false + +availability_19: + id: 19 + start_at: <%= 1.day.from_now.utc.change({hour: 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + end_at: <%= 1.day.from_now.utc.change({hour: 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + available_type: machines + created_at: 2017-02-15 15:53:35.154433000 Z + updated_at: 2017-02-15 15:53:35.154433000 Z + nb_total_places: + destroying: false diff --git a/test/fixtures/machines_availabilities.yml b/test/fixtures/machines_availabilities.yml index 919de5bdf..1400c16a5 100644 --- a/test/fixtures/machines_availabilities.yml +++ b/test/fixtures/machines_availabilities.yml @@ -103,3 +103,8 @@ machines_availability_21: id: 21 machine_id: 2 availability_id: 16 + +machines_availability_22: + id: 22 + machine_id: 1 + availability_id: 19 diff --git a/test/services/statistic_service_test.rb b/test/services/statistic_service_test.rb new file mode 100644 index 000000000..680a10232 --- /dev/null +++ b/test/services/statistic_service_test.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'test_helper' + +class StatisticServiceTest < ActiveSupport::TestCase + setup do + @user = User.members.without_subscription.first + @admin = User.with_role(:admin).first + login_as(@admin, scope: :user) + end + + def test + machine_stats_count = Stats::Machine.all.count + subscription_stats_count = Stats::Subscription.all.count + + # Create a reservation to generate an invoice + machine = Machine.find(1) + availability = Availability.find(19) + post '/api/local_payment/confirm_payment', params: { + customer_id: @user.id, + items: [ + { + reservation: { + reservable_id: machine.id, + reservable_type: machine.class.name, + slots_attributes: [ + { + start_at: availability.start_at.to_s(:iso8601), + end_at: (availability.start_at + 1.hour).to_s(:iso8601), + availability_id: availability.id + } + ] + } + } + ] + }.to_json, headers: default_headers + + # Create a subscription to generate another invoice + plan = Plan.find_by(group_id: @user.group.id, type: 'Plan') + post '/api/local_payment/confirm_payment', + params: { + customer_id: @user.id, + items: [ + { + subscription: { + plan_id: plan.id + } + } + ] + }.to_json, headers: default_headers + + # Build the stats for today, we expect the above invoices (reservation+subscription) to appear in the resulting stats + StatisticService.new.generate_statistic( + start_date: DateTime.current.beginning_of_day, + end_date: DateTime.current.end_of_day + ) + + assert_equal machine_stats_count + 1, Stats::Machine.all.count + assert_equal subscription_stats_count + 1, Stats::Subscription.all.count + end +end From 8097e33ef465c9e517fe8e3f844b1ed8dfd46632 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 15:46:15 +0100 Subject: [PATCH 4/9] (bug) untranslated string if prepaid pack has no maximum validity --- CHANGELOG.md | 1 + .../javascript/components/prepaid-packs/propose-packs-modal.tsx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d9cad46b..b77f66ca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager - Add a test for statistics generation +- Fix a bug: do not display an untranslated string if a prepaid pack has no maximum validity - Fix a bug: statistics not built for instances with plans created before v4.3.3 - Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. - Fix a bug: the adminsys email was case-sensitive. 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 a228ccda2..74bae01bf 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 @@ -82,6 +82,8 @@ export const ProposePacksModal: React.FC = ({ isOpen, to * Return a user-friendly string for the validity of the provided pack */ const formatValidity = (pack: PrepaidPack): string => { + if (!pack.validity_interval) return null; + const period = t(`app.logged.propose_packs_modal.period.${pack.validity_interval}`, { COUNT: pack.validity_count }); return t('app.logged.propose_packs_modal.validity', { COUNT: pack.validity_count, PERIODS: period }); }; From adccc18193e220147b8e48fc46ea85060e5bbfc1 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 16:07:23 +0100 Subject: [PATCH 5/9] (bug) missing the Other payment method --- CHANGELOG.md | 1 + .../src/javascript/components/subscriptions/renew-modal.tsx | 1 - app/frontend/src/javascript/lib/wallet.ts | 2 +- app/frontend/src/javascript/models/payment.ts | 3 ++- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b77f66ca2..b461284ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager - Add a test for statistics generation +- Fix a bug: missing the Other payment method - Fix a bug: do not display an untranslated string if a prepaid pack has no maximum validity - Fix a bug: statistics not built for instances with plans created before v4.3.3 - Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. diff --git a/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx b/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx index 3b9fca1db..725eefe15 100644 --- a/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx +++ b/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx @@ -35,7 +35,6 @@ interface RenewModalProps { * Modal dialog shown to renew the current subscription of a customer, for free */ const RenewModal: React.FC = ({ isOpen, toggleModal, subscription, customer, operator, onError, onSuccess }) => { - // we do not render the modal if the subscription was not provided if (!subscription) return null; diff --git a/app/frontend/src/javascript/lib/wallet.ts b/app/frontend/src/javascript/lib/wallet.ts index 57338f20d..11393e03b 100644 --- a/app/frontend/src/javascript/lib/wallet.ts +++ b/app/frontend/src/javascript/lib/wallet.ts @@ -8,7 +8,7 @@ export default class WalletLib { } /** - * Return the price remaining to pay, after we have used the maximum possible amount in the wallet + * Return the price remaining to pay, after we have used the maximum possible amount in the wallet. */ computeRemainingPrice = (price: number): number => { if (this.wallet.amount > price) { diff --git a/app/frontend/src/javascript/models/payment.ts b/app/frontend/src/javascript/models/payment.ts index 8212b6aaf..a3bcd5424 100644 --- a/app/frontend/src/javascript/models/payment.ts +++ b/app/frontend/src/javascript/models/payment.ts @@ -19,7 +19,8 @@ export interface IntentConfirmation { export enum PaymentMethod { Card = 'card', Check = 'check', - Transfer = 'transfer' + Transfer = 'transfer', + Other = '' } export type CartItem = { reservation: Reservation }| From 28489e112cdaed242ffff5185a309b740535ec2e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 16:27:12 +0100 Subject: [PATCH 6/9] renamed PaymentModal to CardPaymentModal --- ...ayment-modal.tsx => card-payment-modal.tsx} | 10 +++++----- .../local-payment/local-payment-form.tsx | 4 ++-- .../local-payment/local-payment-modal.tsx | 2 +- .../components/payment/payzen/payzen-modal.tsx | 2 +- .../components/payment/stripe/stripe-modal.tsx | 2 +- .../prepaid-packs/propose-packs-modal.tsx | 4 ++-- app/frontend/templates/events/show.html | 14 +++++++------- app/frontend/templates/shared/_cart.html | 16 ++++++++-------- .../shared/valid_reservation_modal.html | 18 +++++++++--------- 9 files changed, 36 insertions(+), 36 deletions(-) rename app/frontend/src/javascript/components/payment/{payment-modal.tsx => card-payment-modal.tsx} (78%) diff --git a/app/frontend/src/javascript/components/payment/payment-modal.tsx b/app/frontend/src/javascript/components/payment/card-payment-modal.tsx similarity index 78% rename from app/frontend/src/javascript/components/payment/payment-modal.tsx rename to app/frontend/src/javascript/components/payment/card-payment-modal.tsx index 6ad9b52fb..591eda71d 100644 --- a/app/frontend/src/javascript/components/payment/payment-modal.tsx +++ b/app/frontend/src/javascript/components/payment/card-payment-modal.tsx @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next'; declare const Application: IApplication; -interface PaymentModalProps { +interface CardPaymentModalProps { isOpen: boolean, toggleModal: () => void, afterSuccess: (result: Invoice|PaymentSchedule) => void, @@ -29,7 +29,7 @@ interface PaymentModalProps { * This component open a modal dialog for the configured payment gateway, allowing the user to input his card data * to process an online payment. */ -const PaymentModalComponent: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer }) => { +const CardPaymentModalComponent: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer }) => { const { t } = useTranslation('shared'); const [gateway, setGateway] = useState(null); @@ -89,12 +89,12 @@ const PaymentModalComponent: React.FC = ({ isOpen, toggleModa } }; -export const PaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer }) => { +export const CardPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer }) => { return ( - + ); }; -Application.Components.component('paymentModal', react2angular(PaymentModal, ['isOpen', 'toggleModal', 'afterSuccess', 'onError', 'currentUser', 'schedule', 'cart', 'customer'])); +Application.Components.component('cardPaymentModal', react2angular(CardPaymentModal, ['isOpen', 'toggleModal', 'afterSuccess', 'onError', 'currentUser', 'schedule', 'cart', 'customer'])); 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 dc3ded3aa..421637f0d 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 @@ -6,7 +6,7 @@ import LocalPaymentAPI from '../../../api/local-payment'; import FormatLib from '../../../lib/format'; import SettingAPI from '../../../api/setting'; import { SettingName } from '../../../models/setting'; -import { PaymentModal } from '../payment-modal'; +import { CardPaymentModal } from '../card-payment-modal'; import { PaymentSchedule } from '../../../models/payment-schedule'; import { HtmlTranslate } from '../../base/html-translate'; @@ -147,7 +147,7 @@ export const LocalPaymentForm: React.FC = ({ onSubmit, onSucce })} - which can handle the configuration + * 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, onError, cart, currentUser, schedule, customer }) => { 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 96880b7ee..1993b6206 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx @@ -26,7 +26,7 @@ interface StripeModalProps { * This component enables the user to input his card data or process payments, using the Stripe gateway. * Supports Strong-Customer Authentication (SCA). * - * This component should not be called directly. Prefer using which can handle the configuration + * 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, onError, cart, currentUser, schedule, customer }) => { 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 74bae01bf..2ddfd2e94 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 @@ -9,7 +9,7 @@ import { FabButton } from '../base/fab-button'; import PriceAPI from '../../api/price'; import { Price } from '../../models/price'; import { PaymentMethod, ShoppingCart } from '../../models/payment'; -import { PaymentModal } from '../payment/payment-modal'; +import { CardPaymentModal } from '../payment/card-payment-modal'; import UserLib from '../../lib/user'; import { LocalPaymentModal } from '../payment/local-payment/local-payment-modal'; import FormatLib from '../../lib/format'; @@ -154,7 +154,7 @@ export const ProposePacksModal: React.FC = ({ isOpen, to {packs?.map(p => renderPack(p))} {cart &&
-
- +
diff --git a/app/frontend/templates/shared/_cart.html b/app/frontend/templates/shared/_cart.html index 4b25aa4e2..3ae1ef504 100644 --- a/app/frontend/templates/shared/_cart.html +++ b/app/frontend/templates/shared/_cart.html @@ -200,14 +200,14 @@
- +
diff --git a/app/frontend/templates/shared/valid_reservation_modal.html b/app/frontend/templates/shared/valid_reservation_modal.html index 1558aa6fe..557183950 100644 --- a/app/frontend/templates/shared/valid_reservation_modal.html +++ b/app/frontend/templates/shared/valid_reservation_modal.html @@ -49,13 +49,13 @@ From 512828931f83f19e569d60e5eae2266868b5668e Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 17:03:16 +0100 Subject: [PATCH 7/9] (bug) members are unable to buy prepaid-packs by wallet --- CHANGELOG.md | 5 +- .../payment/stripe/payment-modal.tsx | 95 +++++++++++++++++++ .../prepaid-packs/propose-packs-modal.tsx | 30 +----- 3 files changed, 103 insertions(+), 27 deletions(-) create mode 100644 app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index b461284ef..fd4169879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,9 @@ - Fix a bug: missing the Other payment method - Fix a bug: do not display an untranslated string if a prepaid pack has no maximum validity - Fix a bug: statistics not built for instances with plans created before v4.3.3 -- Fix a bug: when requesting to send the sso migration code, the email was case-sensitive. -- Fix a bug: the adminsys email was case-sensitive. +- Fix a bug: when requesting to send the sso migration code, the email was case-sensitive +- Fix a bug: the adminsys email was case-sensitive +- Fix a bug: members are unable to buy prepaid-packs by wallet - [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2020,04]` # v5.3.1 2022 January 17 diff --git a/app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx b/app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx new file mode 100644 index 000000000..0acd1b28d --- /dev/null +++ b/app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx @@ -0,0 +1,95 @@ +import { Invoice } from '../../../models/invoice'; +import { PaymentSchedule } from '../../../models/payment-schedule'; +import { ShoppingCart } from '../../../models/payment'; +import { User } from '../../../models/user'; +import React, { useEffect, useState } from 'react'; +import WalletAPI from '../../../api/wallet'; +import { Wallet } from '../../../models/wallet'; +import WalletLib from '../../../lib/wallet'; +import UserLib from '../../../lib/user'; +import { LocalPaymentModal } from '../local-payment/local-payment-modal'; +import { CardPaymentModal } from '../card-payment-modal'; +import PriceAPI from '../../../api/price'; +import { ComputePriceResult } from '../../../models/price'; + +interface PaymentModalProps { + isOpen: boolean, + toggleModal: () => void, + afterSuccess: (result: Invoice|PaymentSchedule) => void, + onError: (message: string) => void, + cart: ShoppingCart, + updateCart: (cart: ShoppingCart) => void, + operator: User, + schedule?: PaymentSchedule, + customer: User +} + +/** + * This component is responsible for rendering the payment modal. + */ +export const PaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, updateCart, operator, schedule, customer }) => { + // the user's wallet + const [wallet, setWallet] = useState(null); + // the price of the cart + const [price, setPrice] = useState(null); + // the remaining price to pay, after the wallet was changed + const [remainingPrice, setRemainingPrice] = useState(null); + + // refresh the wallet when the customer changes + useEffect(() => { + WalletAPI.getByUser(customer.id).then(wallet => { + setWallet(wallet); + }); + }, [customer]); + + // refresh the price when the cart changes + useEffect(() => { + PriceAPI.compute(cart).then(price => { + setPrice(price); + }); + }, [cart]); + + // refresh the remaining price when the cart price was computed and the wallet was retrieved + useEffect(() => { + if (price && wallet) { + setRemainingPrice(new WalletLib(wallet).computeRemainingPrice(price?.price)); + } + }, [price, wallet]); + + /** + * Check the conditions for the local payment + */ + const isLocalPayment = (): boolean => { + return (new UserLib(operator).isPrivileged(customer) || remainingPrice === 0); + }; + + // do not render the modal until the real remaining price is computed + if (remainingPrice === null) return null; + + if (isLocalPayment()) { + return ( + + ); + } else { + return ( + + ); + } +}; 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 2ddfd2e94..0ad1fc892 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 @@ -9,10 +9,8 @@ import { FabButton } from '../base/fab-button'; import PriceAPI from '../../api/price'; import { Price } from '../../models/price'; import { PaymentMethod, ShoppingCart } from '../../models/payment'; -import { CardPaymentModal } from '../payment/card-payment-modal'; -import UserLib from '../../lib/user'; -import { LocalPaymentModal } from '../payment/local-payment/local-payment-modal'; import FormatLib from '../../lib/format'; +import { PaymentModal } from '../payment/stripe/payment-modal'; type PackableItem = Machine; @@ -38,7 +36,6 @@ export const ProposePacksModal: React.FC = ({ isOpen, to const [packs, setPacks] = useState>(null); const [cart, setCart] = useState(null); const [paymentModal, setPaymentModal] = useState(false); - const [localPaymentModal, setLocalPaymentModal] = useState(false); useEffect(() => { PrepaidPackAPI.index({ priceable_id: item.id, priceable_type: itemType, group_id: customer.group_id, disabled: false }) @@ -56,13 +53,6 @@ export const ProposePacksModal: React.FC = ({ isOpen, to setPaymentModal(!paymentModal); }; - /** - * Open/closes the local payment modal (for admins and managers) - */ - const toggleLocalPaymentModal = (): void => { - setLocalPaymentModal(!localPaymentModal); - }; - /** * Convert the hourly-based price of the given prive, to a total price, based on the duration of the given pack */ @@ -107,9 +97,6 @@ export const ProposePacksModal: React.FC = ({ isOpen, to { prepaid_pack: { id: pack.id } } ] }); - if (new UserLib(operator).isPrivileged(customer)) { - return toggleLocalPaymentModal(); - } togglePaymentModal(); }; }; @@ -154,21 +141,14 @@ export const ProposePacksModal: React.FC = ({ isOpen, to {packs?.map(p => renderPack(p))}
{cart &&
- - + operator={operator} + customer={customer} + updateCart={setCart} />
} ); From a46e3ae783bd1600e1317109f5922ce4964bbfae Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 18 Jan 2022 17:12:19 +0100 Subject: [PATCH 8/9] (bug) prepaid-packs without expiration date do not work --- CHANGELOG.md | 1 + app/models/prepaid_pack.rb | 4 +++- app/models/statistic_profile_prepaid_pack.rb | 2 ++ app/services/prepaid_pack_service.rb | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd4169879..2760ceb51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Fix a bug: when requesting to send the sso migration code, the email was case-sensitive - Fix a bug: the adminsys email was case-sensitive - Fix a bug: members are unable to buy prepaid-packs by wallet +- Fix a bug: prepaid-packs without expiration date do not work - [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2020,04]` # v5.3.1 2022 January 17 diff --git a/app/models/prepaid_pack.rb b/app/models/prepaid_pack.rb index aff5dc6c7..76f08aaa8 100644 --- a/app/models/prepaid_pack.rb +++ b/app/models/prepaid_pack.rb @@ -18,7 +18,9 @@ class PrepaidPack < ApplicationRecord validates :amount, :group_id, :priceable_id, :priceable_type, :minutes, presence: true def validity - validity_count.send(validity_interval) + return nil if validity_interval.nil? + + validity_count&.send(validity_interval) end def destroyable? diff --git a/app/models/statistic_profile_prepaid_pack.rb b/app/models/statistic_profile_prepaid_pack.rb index 913d9ccaf..eeee775bb 100644 --- a/app/models/statistic_profile_prepaid_pack.rb +++ b/app/models/statistic_profile_prepaid_pack.rb @@ -14,6 +14,8 @@ class StatisticProfilePrepaidPack < ApplicationRecord private def set_expiration_date + return unless prepaid_pack.validity + self.expires_at = DateTime.current + prepaid_pack.validity end end diff --git a/app/services/prepaid_pack_service.rb b/app/services/prepaid_pack_service.rb index 49ef7772c..c1896f85e 100644 --- a/app/services/prepaid_pack_service.rb +++ b/app/services/prepaid_pack_service.rb @@ -24,7 +24,7 @@ class PrepaidPackService .includes(:prepaid_pack) .references(:prepaid_packs) .where('statistic_profile_id = ?', user.statistic_profile.id) - .where('expires_at > ?', DateTime.current) + .where('expires_at > ? OR expires_at IS NULL', DateTime.current) .where('prepaid_packs.priceable_id = ?', priceable.id) .where('prepaid_packs.priceable_type = ?', priceable.class.name) .where('minutes_used < prepaid_packs.minutes') From 42a03dd0e658c1a1c58742ba302de0ca930c221d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 19 Jan 2022 15:39:12 +0100 Subject: [PATCH 9/9] Version 5.3.2 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2760ceb51..35c4243e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog Fab-manager +# v5.3.2 2022 January 19 + - Add a test for statistics generation - Fix a bug: missing the Other payment method - Fix a bug: do not display an untranslated string if a prepaid pack has no maximum validity diff --git a/package.json b/package.json index 6488a7a4f..b3722472b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.3.1", + "version": "5.3.2", "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",