213 lines
6.9 KiB
PHP
213 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace App\Helpers\FirstParty\Credits;
|
|
|
|
use App\Helpers\FirstParty\Purchase\PurchaseHelper;
|
|
use App\Models\UserCredit;
|
|
use App\Models\UserCreditTransaction;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class CreditsHelper
|
|
{
|
|
public static function getCreditPackByStripePriceId($stripe_price_id)
|
|
{
|
|
$credit_packs = self::getCreditPacks(null, true);
|
|
|
|
foreach ($credit_packs as $credit_pack) {
|
|
|
|
$stripe_price_ids = PurchaseHelper::getPlanSystemProperty($credit_pack, 'stripe.stripe_price_ids');
|
|
|
|
if (in_array($stripe_price_id, $stripe_price_ids)) {
|
|
return $credit_pack;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static function getCreditsPackById($id, $enabled = true, $system = false)
|
|
{
|
|
$credits_packs = self::getCreditPacks($enabled, $system);
|
|
foreach ($credits_packs as $credits_pack) {
|
|
if ($credits_pack['id'] == $id) {
|
|
return $credits_pack;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static function getCreditPacks($enabled = null, $system = true)
|
|
{
|
|
|
|
$credit_packs = [];
|
|
|
|
$one_times = PurchaseHelper::getOneTimePurchases($enabled, $system);
|
|
|
|
foreach ($one_times as $one_time) {
|
|
|
|
if ($one_time['type'] == 'alacarte_credits') {
|
|
$credit_packs[] = $one_time;
|
|
}
|
|
}
|
|
|
|
return $credit_packs;
|
|
}
|
|
|
|
// ////
|
|
|
|
public static function getUserCredits(int $user_id): UserCredit
|
|
{
|
|
$user_credit = UserCredit::where('user_id', $user_id)->first();
|
|
|
|
if (! $user_credit) {
|
|
$user_credit = UserCredit::create([
|
|
'user_id' => $user_id,
|
|
'subscription_credits' => 0,
|
|
'alacarte_credits' => 0,
|
|
'spend_subscription_first' => true,
|
|
]);
|
|
}
|
|
|
|
return $user_credit;
|
|
}
|
|
|
|
// when user purchase annual subscription, need to 12x the deposit amount
|
|
public static function deposit(int $user_id, int $amount, string $type, ?string $description = null): bool
|
|
{
|
|
if ($amount <= 0) {
|
|
throw new \InvalidArgumentException('Amount must be positive');
|
|
}
|
|
|
|
if (! in_array($type, [UserCredit::TYPE_SUBSCRIPTION, UserCredit::TYPE_ALACARTE])) {
|
|
throw new \InvalidArgumentException('Type must be subscription or alacarte');
|
|
}
|
|
|
|
return DB::transaction(function () use ($user_id, $amount, $type, $description) {
|
|
$user_credit = self::getUserCredits($user_id);
|
|
|
|
if ($type === UserCredit::TYPE_SUBSCRIPTION) {
|
|
$user_credit->subscription_credits += $amount;
|
|
} else {
|
|
$user_credit->alacarte_credits += $amount;
|
|
}
|
|
|
|
$user_credit->save();
|
|
self::logTransaction($user_id, $type, 'deposit', $amount, $user_credit, $description);
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public static function spend(int $user_id, int $amount, ?string $description = null, ?bool $use_subscription_first = null): bool
|
|
{
|
|
if ($amount <= 0) {
|
|
throw new \InvalidArgumentException('Amount must be positive');
|
|
}
|
|
|
|
if (! self::canSpend($user_id, $amount)) {
|
|
return false;
|
|
}
|
|
|
|
return DB::transaction(function () use ($user_id, $amount, $description, $use_subscription_first) {
|
|
$user_credit = self::getUserCredits($user_id);
|
|
$remaining = $amount;
|
|
$subscription_first = $use_subscription_first ?? $user_credit->spend_subscription_first;
|
|
|
|
$spend_order = $subscription_first
|
|
? [UserCredit::TYPE_SUBSCRIPTION, UserCredit::TYPE_ALACARTE]
|
|
: [UserCredit::TYPE_ALACARTE, UserCredit::TYPE_SUBSCRIPTION];
|
|
|
|
foreach ($spend_order as $type) {
|
|
if ($remaining <= 0) {
|
|
break;
|
|
}
|
|
|
|
$available = $type === UserCredit::TYPE_SUBSCRIPTION
|
|
? $user_credit->subscription_credits
|
|
: $user_credit->alacarte_credits;
|
|
|
|
if ($available > 0) {
|
|
$to_spend = min($remaining, $available);
|
|
|
|
if ($type === UserCredit::TYPE_SUBSCRIPTION) {
|
|
$user_credit->subscription_credits -= $to_spend;
|
|
} else {
|
|
$user_credit->alacarte_credits -= $to_spend;
|
|
}
|
|
|
|
self::logTransaction($user_id, $type, 'spend', -$to_spend, $user_credit, $description);
|
|
$remaining -= $to_spend;
|
|
}
|
|
}
|
|
|
|
$user_credit->save();
|
|
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public static function canSpend(int $user_id, int $amount): bool
|
|
{
|
|
$user_credit = self::getUserCredits($user_id);
|
|
|
|
return self::_getTotalBalance($user_credit) >= $amount;
|
|
}
|
|
|
|
public static function summary(int $user_id): array
|
|
{
|
|
$user_credit = self::getUserCredits($user_id);
|
|
|
|
return [
|
|
'subscription' => $user_credit->subscription_credits,
|
|
'alacarte' => $user_credit->alacarte_credits,
|
|
'total' => self::_getTotalBalance($user_credit),
|
|
'preference' => $user_credit->spend_subscription_first ? 'subscription_first' : 'alacarte_first',
|
|
];
|
|
}
|
|
|
|
public static function balance(int $user_id, ?string $type = null): int
|
|
{
|
|
$user_credit = self::getUserCredits($user_id);
|
|
|
|
return match ($type) {
|
|
UserCredit::TYPE_SUBSCRIPTION => $user_credit->subscription_credits,
|
|
UserCredit::TYPE_ALACARTE => $user_credit->alacarte_credits,
|
|
default => self::_getTotalBalance($user_credit),
|
|
};
|
|
}
|
|
|
|
private static function _getTotalBalance(UserCredit $user_credit): int
|
|
{
|
|
return $user_credit->subscription_credits + $user_credit->alacarte_credits;
|
|
}
|
|
|
|
public static function setSpendSubscriptionFirst(int $user_id, bool $spendSubscriptionFirst): bool
|
|
{
|
|
$user_credit = self::getUserCredits($user_id);
|
|
$user_credit->spend_subscription_first = $spendSubscriptionFirst;
|
|
|
|
return $user_credit->save();
|
|
}
|
|
|
|
public static function transactionHistory(int $user_id, int $limit = 20): \Illuminate\Database\Eloquent\Collection
|
|
{
|
|
$user_credit = self::getUserCredits($user_id);
|
|
|
|
return $user_credit->transactions()->limit($limit)->get();
|
|
}
|
|
|
|
private static function logTransaction(int $user_id, string $type, string $operation, int $amount, UserCredit $user_credit, ?string $description = null): void
|
|
{
|
|
UserCreditTransaction::create([
|
|
'user_id' => $user_id,
|
|
'credit_type' => $type,
|
|
'operation' => $operation,
|
|
'amount' => $amount,
|
|
'subscription_balance_after' => $user_credit->subscription_credits,
|
|
'alacarte_balance_after' => $user_credit->alacarte_credits,
|
|
'description' => $description,
|
|
]);
|
|
}
|
|
}
|