mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
(feat) cancel subscription
This commit is contained in:
parent
375f0bd137
commit
43f45c383f
@ -9,6 +9,7 @@
|
||||
- Accounting data is now built each night and saved in database
|
||||
- Ability to define multiple accounting journal codes
|
||||
- Ability to change the name of the VAT
|
||||
- Ability to cancel a running subscription from the member edition view for admin/managers
|
||||
- OpenAPI endpoint to fetch accounting data
|
||||
- Add reservation deadline parameter (#414)
|
||||
- Verify current password at server side when changing password
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# API Controller for resources of type Subscription
|
||||
class API::SubscriptionsController < API::ApiController
|
||||
before_action :set_subscription, only: %i[show payment_details]
|
||||
before_action :set_subscription, only: %i[show payment_details cancel]
|
||||
before_action :authenticate_user!
|
||||
|
||||
def show
|
||||
@ -13,6 +13,15 @@ class API::SubscriptionsController < API::ApiController
|
||||
authorize @subscription
|
||||
end
|
||||
|
||||
def cancel
|
||||
authorize @subscription
|
||||
if @subscription.expire(DateTime.current)
|
||||
render :show, status: :ok, location: @subscription
|
||||
else
|
||||
render json: { error: 'already expired' }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
|
@ -1,10 +1,10 @@
|
||||
import apiClient from './clients/api-client';
|
||||
import { Subscription, SubscriptionPaymentDetails, UpdateSubscriptionRequest } from '../models/subscription';
|
||||
import { Subscription, SubscriptionPaymentDetails } from '../models/subscription';
|
||||
import { AxiosResponse } from 'axios';
|
||||
|
||||
export default class SubscriptionAPI {
|
||||
static async update (request: UpdateSubscriptionRequest): Promise<Subscription> {
|
||||
const res: AxiosResponse<Subscription> = await apiClient.patch(`/api/subscriptions/${request.id}`, { subscription: request });
|
||||
static async cancel (id: number): Promise<Subscription> {
|
||||
const res: AxiosResponse<Subscription> = await apiClient.patch(`/api/subscriptions/${id}/cancel`);
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
import { IApplication } from '../../models/application';
|
||||
import { Subscription } from '../../models/subscription';
|
||||
import { FabModal } from '../base/fab-modal';
|
||||
import { Loader } from '../base/loader';
|
||||
import { react2angular } from 'react2angular';
|
||||
import * as React from 'react';
|
||||
import SubscriptionAPI from '../../api/subscription';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { HtmlTranslate } from '../base/html-translate';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface CancelSubscriptionModalProps {
|
||||
isOpen: boolean,
|
||||
toggleModal: () => void,
|
||||
subscription: Subscription,
|
||||
onSuccess: (message: string) => void,
|
||||
onError: (message: string) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* Modam dialog shown to confirm the cancelation of the current running subscription of a customer
|
||||
*/
|
||||
export const CancelSubscriptionModal: React.FC<CancelSubscriptionModalProps> = ({ isOpen, toggleModal, subscription, onError, onSuccess }) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
/**
|
||||
* Callback triggered when the user has confirmed the cancelation of the subscription
|
||||
*/
|
||||
const handleCancelConfirmed = () => {
|
||||
SubscriptionAPI.cancel(subscription.id).then(() => {
|
||||
toggleModal();
|
||||
onSuccess(t('app.admin.cancel_subscription_modal.subscription_canceled'));
|
||||
}).catch(onError);
|
||||
};
|
||||
|
||||
return (
|
||||
<FabModal isOpen={isOpen}
|
||||
toggleModal={toggleModal}
|
||||
confirmButton={t('app.admin.cancel_subscription_modal.confirm')}
|
||||
title={t('app.admin.cancel_subscription_modal.title')}
|
||||
onConfirm={handleCancelConfirmed}
|
||||
closeButton>
|
||||
<HtmlTranslate trKey={'app.admin.cancel_subscription_modal.confirmation_html'} options={{ NAME: subscription.plan.base_name }} />
|
||||
</FabModal>
|
||||
);
|
||||
};
|
||||
|
||||
const CancelSubscriptionModalWrapper: React.FC<CancelSubscriptionModalProps> = (props) => {
|
||||
return (
|
||||
<Loader>
|
||||
<CancelSubscriptionModal {...props} />
|
||||
</Loader>
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('cancelSubscriptionModal', react2angular(CancelSubscriptionModalWrapper, ['toggleModal', 'subscription', 'isOpen', 'onError', 'onSuccess']));
|
@ -727,6 +727,9 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
// modal dialog to change the user's role
|
||||
$scope.isOpenChangeRoleModal = false;
|
||||
|
||||
// modal dialog to cancel the current subscription
|
||||
$scope.isOpenCancelModal = false;
|
||||
|
||||
/**
|
||||
* Open a modal dialog asking for confirmation to change the role of the given user
|
||||
* @returns {*}
|
||||
@ -794,6 +797,16 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
}, 50);
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens/closes the modal dialog to cancel the current running subscription
|
||||
*/
|
||||
$scope.toggleCancelModal = () => {
|
||||
setTimeout(() => {
|
||||
$scope.isOpenCancelModal = !$scope.isOpenCancelModal;
|
||||
$scope.$apply();
|
||||
}, 50);
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens/closes the modal dialog to renew the subscription (with payment)
|
||||
*/
|
||||
@ -822,6 +835,16 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
||||
$scope.subscription.expired_at = newExpirationDate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback triggered when the subscription was successfully canceled
|
||||
*/
|
||||
$scope.onCancelSuccess = (message) => {
|
||||
growl.success(message);
|
||||
$scope.user.subscribed_plan = null;
|
||||
$scope.user.subscription = null;
|
||||
$scope.subscription = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback triggered if a new subscription was successfully taken
|
||||
*/
|
||||
|
@ -14,12 +14,6 @@ export interface SubscriptionRequest {
|
||||
start_at?: TDateISO
|
||||
}
|
||||
|
||||
export interface UpdateSubscriptionRequest {
|
||||
id: number,
|
||||
expired_at: TDateISO,
|
||||
free: boolean
|
||||
}
|
||||
|
||||
export interface SubscriptionPaymentDetails {
|
||||
payment_schedule: boolean,
|
||||
card: boolean
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
<section class="panel panel-default bg-light m-lg">
|
||||
<div class="panel-body m-r">
|
||||
<div class="" ng-show="subscription">
|
||||
<div class="" ng-if="subscription">
|
||||
<h3>{{ subscription.plan | humanReadablePlanName }}</h3>
|
||||
<p>
|
||||
{{ 'app.admin.members_edit.duration' | translate }} {{ subscription.plan.interval | planIntervalFilter: subscription.plan.interval_count }}
|
||||
@ -89,6 +89,7 @@
|
||||
<div ng-hide="user.id === currentUser.id">
|
||||
<button class="btn btn-default" ng-click="toggleFreeExtendModal()" translate>{{ 'app.admin.members_edit.offer_free_days' }}</button>
|
||||
<button class="btn btn-default" ng-click="toggleRenewModal()" translate>{{ 'app.admin.members_edit.renew_subscription' }}</button>
|
||||
<button class="btn btn-default" ng-click="toggleCancelModal()" translate>{{ 'app.admin.members_edit.cancel_subscription' }}</button>
|
||||
<free-extend-modal is-open="isOpenFreeExtendModal"
|
||||
toggle-modal="toggleFreeExtendModal"
|
||||
subscription="subscription"
|
||||
@ -104,6 +105,14 @@
|
||||
on-error="onError"
|
||||
on-success="onExtendSuccess">
|
||||
</renew-modal>
|
||||
<cancel-subscription-modal is-open="isOpenCancelModal"
|
||||
toggle-modal="toggleCancelModal"
|
||||
subscription="subscription"
|
||||
customer="user"
|
||||
operator="currentUser"
|
||||
on-error="onError"
|
||||
on-success="onCancelSuccess">
|
||||
</cancel-subscription-modal>
|
||||
</div>
|
||||
<p class="alert alert-info" ng-show="user.id === currentUser.id" translate>
|
||||
{{ 'app.admin.members_edit.cannot_extend_own_subscription' }}
|
||||
|
@ -9,4 +9,8 @@ class SubscriptionPolicy < ApplicationPolicy
|
||||
def payment_details?
|
||||
user.admin? || user.manager?
|
||||
end
|
||||
|
||||
def cancel?
|
||||
user.admin? || user.manager?
|
||||
end
|
||||
end
|
||||
|
@ -1134,6 +1134,7 @@ de:
|
||||
price_: "Preis:"
|
||||
offer_free_days: "Kostenlose Tage anbieten"
|
||||
renew_subscription: "Abonnement erneuern"
|
||||
cancel_subscription: "Cancel the subscription"
|
||||
user_has_no_current_subscription: "Benutzer hat kein aktuelles Abonnement."
|
||||
subscribe_to_a_plan: "Plan abonnieren"
|
||||
trainings: "Schulungen"
|
||||
@ -1208,6 +1209,12 @@ de:
|
||||
select_plan: "Bitte wählen Sie einen Plan"
|
||||
pay_in_one_go: "In einem Schritt bezahlen"
|
||||
subscription_success: "Subscription successfully subscribed"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation required"
|
||||
confirmation_html: "You are about to cancel the subscription <em>{NAME}</em> of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. <strong>Are your sure?</strong>"
|
||||
confirm: "Cancel this subscription"
|
||||
subscription_canceled: "The subscription was successfully canceled."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Administrator hinzufügen"
|
||||
|
@ -1134,6 +1134,7 @@ en:
|
||||
price_: "Price:"
|
||||
offer_free_days: "Offer free days"
|
||||
renew_subscription: "Renew the subscription"
|
||||
cancel_subscription: "Cancel the subscription"
|
||||
user_has_no_current_subscription: "User has no current subscription."
|
||||
subscribe_to_a_plan: "Subscribe to a plan"
|
||||
trainings: "Trainings"
|
||||
@ -1208,6 +1209,12 @@ en:
|
||||
select_plan: "Please select a plan"
|
||||
pay_in_one_go: "Pay in one go"
|
||||
subscription_success: "Subscription successfully subscribed"
|
||||
# cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation required"
|
||||
confirmation_html: "You are about to cancel the subscription <em>{NAME}</em> of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. <strong>Are your sure?</strong>"
|
||||
confirm: "Cancel this subscription"
|
||||
subscription_canceled: "The subscription was successfully canceled."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Add an administrator"
|
||||
|
@ -1134,6 +1134,7 @@ es:
|
||||
price_: "Precio:"
|
||||
offer_free_days: "Ofrecer días gratis"
|
||||
renew_subscription: "Renew the subscription"
|
||||
cancel_subscription: "Cancel the subscription"
|
||||
user_has_no_current_subscription: "El usuario no tiene una suscripción actual."
|
||||
subscribe_to_a_plan: "Suscribirse a un plan"
|
||||
trainings: "Trainings"
|
||||
@ -1208,6 +1209,12 @@ es:
|
||||
select_plan: "Please select a plan"
|
||||
pay_in_one_go: "Pay in one go"
|
||||
subscription_success: "Subscription successfully subscribed"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation required"
|
||||
confirmation_html: "You are about to cancel the subscription <em>{NAME}</em> of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. <strong>Are your sure?</strong>"
|
||||
confirm: "Cancel this subscription"
|
||||
subscription_canceled: "The subscription was successfully canceled."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Agregar un administrador"
|
||||
|
@ -1134,6 +1134,7 @@ fr:
|
||||
price_: "Prix :"
|
||||
offer_free_days: "Offrir des jours gratuits"
|
||||
renew_subscription: "Renouveler l'abonnement"
|
||||
cancel_subscription: "Annuler 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"
|
||||
@ -1208,6 +1209,12 @@ fr:
|
||||
select_plan: "Veuillez choisir une formule d'abonnement"
|
||||
pay_in_one_go: "Payer en une fois"
|
||||
subscription_success: "Abonnement souscrit avec succès"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation requise"
|
||||
confirmation_html: "Vous êtes sur le point d'annuler l'abonnement <em>{NAME}</em> de cet utilisateur. À partir de maintenant, il ne pourra plus bénéficier des avantages de cet abonnement et tous ses crédits inutilisés seront perdus. <strong>Êtes-vous sûr(e) ?</strong>"
|
||||
confirm: "Annuler cet abonnement"
|
||||
subscription_canceled: "L'abonnement a bien été annulé."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Ajouter un administrateur"
|
||||
|
@ -1134,6 +1134,7 @@
|
||||
price_: "Pris:"
|
||||
offer_free_days: "Tilby gratis dager"
|
||||
renew_subscription: "Forny abonnementet"
|
||||
cancel_subscription: "Cancel the subscription"
|
||||
user_has_no_current_subscription: "Brukeren har ikke noe gjeldende medlemskap."
|
||||
subscribe_to_a_plan: "Abonner på et medlemskap"
|
||||
trainings: "Opplæringer/kurs"
|
||||
@ -1208,6 +1209,12 @@
|
||||
select_plan: "Please select a plan"
|
||||
pay_in_one_go: "Pay in one go"
|
||||
subscription_success: "Subscription successfully subscribed"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation required"
|
||||
confirmation_html: "You are about to cancel the subscription <em>{NAME}</em> of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. <strong>Are your sure?</strong>"
|
||||
confirm: "Cancel this subscription"
|
||||
subscription_canceled: "The subscription was successfully canceled."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Legg til administrator"
|
||||
|
@ -1134,6 +1134,7 @@ pt:
|
||||
price_: "Preço:"
|
||||
offer_free_days: "Oferecer dias grátis"
|
||||
renew_subscription: "Renovar assinatura"
|
||||
cancel_subscription: "Cancel the subscription"
|
||||
user_has_no_current_subscription: "O usuário não possui inscrição."
|
||||
subscribe_to_a_plan: "Plano de inscrição"
|
||||
trainings: "Treinamentos"
|
||||
@ -1208,6 +1209,12 @@ pt:
|
||||
select_plan: "Por favor, selecione um plano"
|
||||
pay_in_one_go: "Paga á vista"
|
||||
subscription_success: "Assinatura assinada com sucesso"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "Confirmation required"
|
||||
confirmation_html: "You are about to cancel the subscription <em>{NAME}</em> of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. <strong>Are your sure?</strong>"
|
||||
confirm: "Cancel this subscription"
|
||||
subscription_canceled: "The subscription was successfully canceled."
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "Adicionar administrador"
|
||||
|
@ -1134,6 +1134,7 @@ zu:
|
||||
price_: "crwdns25854:0crwdne25854:0"
|
||||
offer_free_days: "crwdns25856:0crwdne25856:0"
|
||||
renew_subscription: "crwdns25858:0crwdne25858:0"
|
||||
cancel_subscription: "crwdns36255:0crwdne36255:0"
|
||||
user_has_no_current_subscription: "crwdns25860:0crwdne25860:0"
|
||||
subscribe_to_a_plan: "crwdns25862:0crwdne25862:0"
|
||||
trainings: "crwdns25864:0crwdne25864:0"
|
||||
@ -1208,6 +1209,12 @@ zu:
|
||||
select_plan: "crwdns25988:0crwdne25988:0"
|
||||
pay_in_one_go: "crwdns25990:0crwdne25990:0"
|
||||
subscription_success: "crwdns25992:0crwdne25992:0"
|
||||
#cancel the current subscription
|
||||
cancel_subscription_modal:
|
||||
title: "crwdns36257:0crwdne36257:0"
|
||||
confirmation_html: "crwdns36259:0{NAME}crwdne36259:0"
|
||||
confirm: "crwdns36261:0crwdne36261:0"
|
||||
subscription_canceled: "crwdns36263:0crwdne36263:0"
|
||||
#add a new administrator to the platform
|
||||
admins_new:
|
||||
add_an_administrator: "crwdns25994:0crwdne25994:0"
|
||||
|
@ -108,6 +108,7 @@ Rails.application.routes.draw do
|
||||
resources :groups, only: %i[index create update destroy]
|
||||
resources :subscriptions, only: %i[show] do
|
||||
get 'payment_details', action: 'payment_details', on: :member
|
||||
patch 'cancel', on: :member
|
||||
end
|
||||
resources :plan_categories
|
||||
resources :plans do
|
||||
|
Loading…
x
Reference in New Issue
Block a user