1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

refactored free subscription extending

This commit is contained in:
Sylvain 2021-10-12 14:07:35 +02:00
parent 70f0e21543
commit 17a0baac7e
15 changed files with 110 additions and 48 deletions

View File

@ -12,10 +12,8 @@ class API::SubscriptionsController < API::ApiController
def update
authorize @subscription
free_days = params[:subscription][:free] || false
res = Subscriptions::Subscribe.new(current_user.invoicing_profile.id)
.extend_subscription(@subscription, subscription_update_params[:expired_at], free_days)
.extend_subscription(@subscription, subscription_update_params[:expired_at])
if res.is_a?(Subscription)
@subscription = res
render status: :created

View File

@ -8,7 +8,8 @@ import FormatLib from '../../lib/format';
import { Loader } from '../base/loader';
import { react2angular } from 'react2angular';
import { IApplication } from '../../models/application';
import SubscriptionAPI from '../../api/subscription';
import LocalPaymentAPI from '../../api/local-payment';
import { PaymentMethod } from '../../models/payment';
declare const Application: IApplication;
@ -16,14 +17,15 @@ interface FreeExtendModalProps {
isOpen: boolean,
toggleModal: () => void,
subscription: Subscription,
onSuccess: (subscription: Subscription) => void,
customerId: number,
onSuccess: (message: string, newExpirationDate: Date) => void,
onError: (message: string) => void,
}
/**
* Modal dialog shown to extend the current subscription of a customer, for free
*/
const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal, subscription, onError, onSuccess }) => {
const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => {
const { t } = useTranslation('admin');
const [expirationDate, setExpirationDate] = useState<Date>(new Date(subscription.expired_at));
@ -63,12 +65,20 @@ const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal,
* 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));
LocalPaymentAPI.confirmPayment({
customer_id: customerId,
payment_method: PaymentMethod.Other,
items: [
{
free_extension: {
end_at: expirationDate
}
}
]
}).then(() => {
onSuccess(t('app.admin.free_extend_modal.extend_success'), expirationDate);
toggleModal();
}).catch(err => onError(err));
};
return (
@ -101,12 +111,12 @@ const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal,
);
};
const FreeExtendModalWrapper: React.FC<FreeExtendModalProps> = ({ toggleModal, subscription, isOpen, onSuccess, onError }) => {
const FreeExtendModalWrapper: React.FC<FreeExtendModalProps> = ({ toggleModal, subscription, customerId, isOpen, onSuccess, onError }) => {
return (
<Loader>
<FreeExtendModal toggleModal={toggleModal} subscription={subscription} isOpen={isOpen} onError={onError} onSuccess={onSuccess} />
<FreeExtendModal toggleModal={toggleModal} subscription={subscription} customerId={customerId} isOpen={isOpen} onError={onError} onSuccess={onSuccess} />
</Loader>
);
};
Application.Components.component('freeExtendModal', react2angular(FreeExtendModalWrapper, ['toggleModal', 'subscription', 'isOpen', 'onError', 'onSuccess']));
Application.Components.component('freeExtendModal', react2angular(FreeExtendModalWrapper, ['toggleModal', 'subscription', 'customerId', 'isOpen', 'onError', 'onSuccess']));

View File

@ -759,14 +759,18 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
* Opens/closes the modal dialog to freely extend the subscription
*/
$scope.toggleFreeExtendModal = () => {
setTimeout(() => {
$scope.isOpenFreeExtendModal = !$scope.isOpenFreeExtendModal;
$scope.$apply();
}, 50);
};
/**
* Callback triggered if the subscription was successfully extended
*/
$scope.onExtendSuccess = (subscription) => {
$scope.subscription = subscription;
$scope.onExtendSuccess = (message, newExpirationDate) => {
growl.success(message);
$scope.subscription.expired_at = newExpirationDate;
};
/**

View File

@ -21,7 +21,10 @@ export enum PaymentMethod {
Other = ''
}
export type CartItem = { reservation: Reservation }|{ subscription: SubscriptionRequest }|{ prepaid_pack: { id: number } };
export type CartItem = { reservation: Reservation }|
{ subscription: SubscriptionRequest }|
{ prepaid_pack: { id: number } }|
{ free_extension: { end_at: Date } };
export interface ShoppingCart {
customer_id: number,

View File

@ -82,6 +82,7 @@
<free-extend-modal is-open="isOpenFreeExtendModal"
toggle-modal="toggleFreeExtendModal"
subscription="subscription"
customer-id="user.id"
on-error="onError"
on-success="onExtendSuccess">
</free-extend-modal>

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
# A subscription extended for free, added to the shopping cart
class CartItem::FreeExtension < CartItem::BaseItem
def initialize(customer, subscription, new_expiration_date)
raise TypeError unless subscription.is_a? Subscription
@customer = customer
@new_expiration_date = new_expiration_date
@subscription = subscription
super
end
def start_at
raise InvalidSubscriptionError if @subscription.nil?
raise InvalidSubscriptionError if @new_expiration_date <= @subscription.expired_at
@subscription.expired_at
end
def price
elements = { OfferDay: 0 }
{ elements: elements, amount: 0 }
end
def name
I18n.t('cart_items.free_extension', DATE: I18n.l(@new_expiration_date))
end
def to_object
::OfferDay.new(
subscription_id: @subscription.id,
start_at: start_at,
end_at: @new_expiration_date
)
end
end

View File

@ -7,6 +7,8 @@ class OfferDay < ApplicationRecord
has_many :invoice_items, as: :object, dependent: :destroy
belongs_to :subscription
after_create :notify_subscription_extended
# buying invoice
def original_invoice
invoice_items.select(:invoice_id)
@ -15,4 +17,20 @@ class OfferDay < ApplicationRecord
.map { |id| Invoice.find_by(id: id, type: nil) }
.first
end
private
def notify_subscription_extended
meta_data = { free_days: true }
NotificationCenter.call type: :notify_member_subscription_extended,
receiver: subscription.user,
attached_object: subscription,
meta_data: meta_data
NotificationCenter.call type: :notify_admin_subscription_extended,
receiver: User.admins_and_managers,
attached_object: subscription,
meta_data: meta_data
end
end

View File

@ -122,6 +122,7 @@ class Setting < ApplicationRecord
renew_pack_threshold
pack_only_for_subscription] }
# 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
def value
last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).limit(1).first

View File

@ -47,26 +47,6 @@ class Subscription < ApplicationRecord
expiration_date
end
def free_extend(expiration, operator_profile_id)
return false if expiration <= expired_at
od = offer_days.create(start_at: expired_at, end_at: expiration)
invoice = Invoice.new(
invoicing_profile: user.invoicing_profile,
statistic_profile: user.statistic_profile,
operator_profile_id: operator_profile_id,
total: 0
)
invoice.invoice_items.push InvoiceItem.new(amount: 0, description: plan.base_name, object: od)
invoice.save
if save
notify_subscription_extended(true)
return true
end
false
end
def user
statistic_profile.user
end
@ -116,9 +96,8 @@ class Subscription < ApplicationRecord
attached_object: self
end
def notify_subscription_extended(free_days)
meta_data = {}
meta_data[:free_days] = true if free_days
def notify_subscription_extended
meta_data = { free_days: false }
NotificationCenter.call type: :notify_member_subscription_extended,
receiver: user,
attached_object: self,

View File

@ -3,6 +3,9 @@
# Check the access policies for API::LocalPaymentsController
class LocalPaymentPolicy < ApplicationPolicy
def confirm_payment?
user.admin? || (user.manager? && record.shopping_cart.customer.id != user.id) || record.price.zero?
# only admins and managers can offer free extensions of a subscription
has_free_days = record.shopping_cart.items.any? { |item| item.is_a? CartItem::FreeExtension }
user.admin? || (user.manager? && record.shopping_cart.customer.id != user.id) || (record.price.zero? && !has_free_days)
end
end

View File

@ -22,6 +22,8 @@ class CartService
items.push(reservable_from_hash(item[:reservation], plan_info))
elsif ['prepaid_pack', :prepaid_pack].include?(item.keys.first)
items.push(CartItem::PrepaidPack.new(PrepaidPack.find(item[:prepaid_pack][:id]), @customer))
elsif ['free_extension', :free_extension].include?(item.keys.first)
items.push(CartItem::FreeExtension.new(@customer, plan_info[:subscription], item[:free_extension][:end_at]))
end
end
@ -70,18 +72,21 @@ class CartService
def plan(cart_items)
new_plan_being_bought = false
subscription = nil
plan = if cart_items[:items].any? { |item| ['subscription', :subscription].include?(item.keys.first) }
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])
end
elsif @customer.subscribed_plan
subscription = @customer.subscription unless @customer.subscription.expired_at < DateTime.current
@customer.subscribed_plan
else
nil
end
{ plan: plan, new_subscription: new_plan_being_bought }
{ plan: plan, subscription: subscription, new_subscription: new_plan_being_bought }
end
def customer(cart_items)

View File

@ -93,7 +93,7 @@ class InvoicesService
end
##
# Generate an array of {InvoiceItem} with the elements in provided reservation, price included.
# Generate an array of {InvoiceItem} with the provided elements, price included.
# @param invoice {Invoice} the parent invoice
# @param payment_details {Hash} as generated by ShoppingCart.total
# @param objects {Array<Reservation|Subscription|StatisticProfilePrepaidPack>}

View File

@ -9,9 +9,7 @@ class Subscriptions::Subscribe
@operator_profile_id = operator_profile_id
end
def extend_subscription(subscription, new_expiration_date, free_days)
return subscription.free_extend(new_expiration_date, @operator_profile_id) if free_days
def extend_subscription(subscription, new_expiration_date)
new_sub = Subscription.create(
plan_id: subscription.plan_id,
statistic_profile_id: subscription.statistic_profile_id

View File

@ -916,6 +916,7 @@ en:
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"
# renew a subscription
renew_subscription_modal:
renew_subscription: "Renew the subscription"

View File

@ -416,6 +416,8 @@ en:
group:
#name of the user's group for administrators
admins: 'Administrators'
cart_items:
free_extension: "Free extension of a subscription, until %{DATE}"
settings:
locked_setting: "the setting is locked."
about_title: "\"About\" page title"
@ -529,3 +531,4 @@ en:
payzen_currency: "PayZen currency"
public_agenda_module: "Public agenda module"
renew_pack_threshold: "Threshold for packs renewal"
pack_only_for_subscription: "Restrict packs for subscribers"