diff --git a/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx b/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx index 865de5275..03d6b3f32 100644 --- a/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx +++ b/app/frontend/src/javascript/components/subscriptions/renew-modal.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Subscription, SubscriptionPaymentDetails } from '../../models/subscription'; +import { Subscription } from '../../models/subscription'; import { FabModal, ModalSize } from '../base/fab-modal'; import { useTranslation } from 'react-i18next'; import { FabAlert } from '../base/fab-alert'; @@ -8,12 +8,16 @@ import FormatLib from '../../lib/format'; import { Loader } from '../base/loader'; import { react2angular } from 'react2angular'; import { IApplication } from '../../models/application'; -import LocalPaymentAPI from '../../api/local-payment'; import { PaymentMethod, ShoppingCart } from '../../models/payment'; import moment from 'moment'; import { SelectSchedule } from '../payment-schedule/select-schedule'; import SubscriptionAPI from '../../api/subscription'; +import PriceAPI from '../../api/price'; +import { ComputePriceResult } from '../../models/price'; import { PaymentScheduleSummary } from '../payment-schedule/payment-schedule-summary'; +import { PaymentSchedule } from '../../models/payment-schedule'; +import { LocalPaymentModal } from '../payment/local-payment/local-payment-modal'; +import { User } from '../../models/user'; declare const Application: IApplication; @@ -21,7 +25,8 @@ interface RenewModalProps { isOpen: boolean, toggleModal: () => void, subscription?: Subscription, - customerId: number, + customer: User, + operator: User, onSuccess: (message: string, newExpirationDate: Date) => void, onError: (message: string) => void, } @@ -29,12 +34,13 @@ interface RenewModalProps { /** * Modal dialog shown to renew the current subscription of a customer, for free */ -const RenewModal: React.FC = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => { +const RenewModal: React.FC = ({ isOpen, toggleModal, subscription, customer, operator, onError, onSuccess }) => { const { t } = useTranslation('admin'); const [expirationDate, setExpirationDate] = useState(new Date()); const [localPaymentModal, setLocalPaymentModal] = useState(false); const [cart, setCart] = useState(null); + const [price, setPrice] = useState(null); const [scheduleRequired, setScheduleRequired] = useState(false); // on init, we compute the new expiration date @@ -49,6 +55,31 @@ const RenewModal: React.FC = ({ isOpen, toggleModal, subscripti .catch(err => onError(err)); }, []); + // when the payment schedule is toggled (requested/ignored), we update the cart accordingly + useEffect(() => { + if (!subscription) return; + + setCart({ + customer_id: customer.id, + items: [{ + subscription: { + plan_id: subscription.plan.id + } + }], + payment_method: PaymentMethod.Other, + payment_schedule: scheduleRequired + }); + }, [scheduleRequired]); + + // when the cart is updated, re-compute the price and the payment schedule + useEffect(() => { + if (!cart) return; + + PriceAPI.compute(cart) + .then(res => setPrice(res)) + .catch(err => onError(err)); + }, [cart]); + /** * Return the formatted localized date for the given date */ @@ -57,24 +88,18 @@ const RenewModal: React.FC = ({ isOpen, toggleModal, subscripti }; /** - * Callback triggered when the user validates the renew of the subscription + * Callback triggered when the payment of the subscription renewal was successful */ - const handleConfirmRenew = (): void => { - LocalPaymentAPI.confirmPayment({ - customer_id: customerId, - payment_method: PaymentMethod.Other, - items: [ - { - subscription: { - plan_id: subscription.plan_id - // start_at: subscription.expired_at - } - } - ] - }).then(() => { - onSuccess(t('app.admin.renew_subscription_modal.renew_success'), expirationDate); - toggleModal(); - }).catch(err => onError(err)); + const onPaymentSuccess = (): void => { + onSuccess(t('app.admin.renew_subscription_modal.renew_success'), expirationDate); + toggleModal(); + }; + + /** + * Open/closes the local payment modal + */ + const toggleLocalPaymentModal = (): void => { + setLocalPaymentModal(!localPaymentModal); }; // we do not render the modal if the subscription was not provided @@ -87,7 +112,7 @@ const RenewModal: React.FC = ({ isOpen, toggleModal, subscripti className="renew-modal" title={t('app.admin.renew_subscription_modal.renew_subscription')} confirmButton={t('app.admin.renew_subscription_modal.renew')} - onConfirm={handleConfirmRenew} + onConfirm={toggleLocalPaymentModal} closeButton>

{t('app.admin.renew_subscription_modal.renew_subscription_info')}

@@ -110,18 +135,31 @@ const RenewModal: React.FC = ({ isOpen, toggleModal, subscripti
+ {price?.schedule && } + {price && !price?.schedule &&
+

{t('app.admin.renew_subscription_modal.pay_in_one_go')}

+ {FormatLib.price(price.price)} +
}
+ ); }; -const RenewModalWrapper: React.FC = ({ toggleModal, subscription, customerId, isOpen, onSuccess, onError }) => { +const RenewModalWrapper: React.FC = ({ toggleModal, subscription, customer, operator, isOpen, onSuccess, onError }) => { return ( - + ); }; -Application.Components.component('renewModal', react2angular(RenewModalWrapper, ['toggleModal', 'subscription', 'customerId', 'isOpen', 'onError', 'onSuccess'])); +Application.Components.component('renewModal', react2angular(RenewModalWrapper, ['toggleModal', 'subscription', 'customer', 'operator', 'isOpen', 'onError', 'onSuccess'])); diff --git a/app/frontend/src/stylesheets/modules/subscriptions/renew-modal.scss b/app/frontend/src/stylesheets/modules/subscriptions/renew-modal.scss index 111a7909c..831d8b97f 100644 --- a/app/frontend/src/stylesheets/modules/subscriptions/renew-modal.scss +++ b/app/frontend/src/stylesheets/modules/subscriptions/renew-modal.scss @@ -18,6 +18,10 @@ border-radius: 2px; padding: 10px; width: 50%; + + .one-go-payment { + text-align: center; + } } } } diff --git a/app/frontend/templates/admin/members/edit.html b/app/frontend/templates/admin/members/edit.html index e75040114..ddf2e842a 100644 --- a/app/frontend/templates/admin/members/edit.html +++ b/app/frontend/templates/admin/members/edit.html @@ -89,7 +89,8 @@ diff --git a/app/services/cart_service.rb b/app/services/cart_service.rb index 29fffd1b2..ec6d974c7 100644 --- a/app/services/cart_service.rb +++ b/app/services/cart_service.rb @@ -77,8 +77,9 @@ class CartService index = cart_items[:items].index { |item| ['subscription', :subscription].include?(item.keys.first) } if cart_items[:items][index][:subscription][:plan_id] new_plan_being_bought = true - subscription = cart_items[:items][index][:subscription].to_object - Plan.find(cart_items[:items][index][:subscription][:plan_id]) + plan = Plan.find(cart_items[:items][index][:subscription][:plan_id]) + subscription = CartItem::Subscription.new(plan, @customer).to_object + plan end elsif @customer.subscribed_plan subscription = @customer.subscription unless @customer.subscription.expired_at < DateTime.current diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 31854678b..8122f5a0e 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -922,6 +922,7 @@ en: 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" #add a new administrator to the platform diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index 2d3fef2b1..a75bc47ce 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -417,7 +417,7 @@ en: NUMBER_monthly_payment_of_AMOUNT: "{NUMBER} monthly {NUMBER, plural, =1{payment} other{payments}} of {AMOUNT}" first_debit: "First debit on the day of the order." debit: "Debit on the day of the order." - view_full_schedule: "View the complete payement schedule" + view_full_schedule: "View the complete payment schedule" confirm_and_pay: "Confirm and pay" you_have_settled_the_following_TYPE: "You have settled the following {TYPE, select, Machine{machine slots} Training{training} other{elements}}:" you_have_settled_a_: "You have settled a"