1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-29 10:24:20 +01:00
fab-manager/app/services/wallet_service.rb

113 lines
3.7 KiB
Ruby

# frozen_string_literal: true
# Provides methods to manage wallets
class WalletService
def initialize(user: nil, wallet: nil)
@user = user
@wallet = wallet
end
## credit an amount to wallet, if credit success then return a wallet transaction and notify to admin
def credit(amount)
transaction = nil
ActiveRecord::Base.transaction do
if @wallet&.credit(amount)
transaction = WalletTransaction.new(
invoicing_profile: @user&.invoicing_profile,
wallet: @wallet,
transaction_type: 'credit',
amount: amount
)
raise ActiveRecord::Rollback unless transaction.save
NotificationCenter.call type: 'notify_user_wallet_is_credited',
receiver: @wallet&.user,
attached_object: transaction
NotificationCenter.call type: 'notify_admin_user_wallet_is_credited',
receiver: User.admins_and_managers,
attached_object: transaction
end
end
transaction
end
## debit an amount to wallet, if debit success then return a wallet transaction
def debit(amount)
transaction = nil
ActiveRecord::Base.transaction do
if @wallet&.debit(amount)
transaction = WalletTransaction.new(
invoicing_profile: @user&.invoicing_profile,
wallet: @wallet,
transaction_type: 'debit',
amount: amount
)
raise ActiveRecord::Rollback unless transaction.save
end
end
transaction
end
## create a refund invoice associated with the given wallet transaction
def create_avoir(wallet_transaction, avoir_date, description)
avoir = Avoir.new
avoir.type = 'Avoir'
avoir.avoir_date = avoir_date
avoir.created_at = avoir_date
avoir.description = description
avoir.payment_method = 'wallet'
avoir.subscription_to_expire = false
avoir.invoicing_profile_id = wallet_transaction.wallet.user.invoicing_profile.id
avoir.statistic_profile_id = wallet_transaction.wallet.user.statistic_profile.id
avoir.total = wallet_transaction.amount * 100.0
ii = InvoiceItem.new
ii.amount = wallet_transaction.amount * 100.0
ii.description = I18n.t('invoices.wallet_credit')
ii.object = wallet_transaction
ii.main = true
avoir.invoice_items.push(ii)
avoir.save!
end
##
# Compute the amount decreased from the user's wallet, if applicable
# @param payment {Invoice|PaymentSchedule|Order}
# @param user {User} the customer
##
def self.wallet_amount_debit(payment, user)
total = if payment.is_a? PaymentSchedule
payment.payment_schedule_items.first.amount
else
payment.total
end
total = CouponService.new.apply(total, payment.coupon, user.id) if payment.coupon
wallet_amount = (user.wallet.amount * 100).to_i
wallet_amount >= total ? total : wallet_amount
end
##
# Subtract the amount of the payment document (Invoice|PaymentSchedule|Order) 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)
return unless wallet_amount.present? && wallet_amount != 0
amount = wallet_amount / 100.0
if transaction
wallet_transaction = WalletService.new(user: user, wallet: user.wallet).debit(amount)
# wallet debit success
raise DebitWalletError unless wallet_transaction
payment.set_wallet_transaction(wallet_amount, wallet_transaction.id)
else
payment.set_wallet_transaction(wallet_amount, nil)
end
end
end