Update
This commit is contained in:
212
app/Helpers/FirstParty/Credits/CreditsHelper.php
Normal file
212
app/Helpers/FirstParty/Credits/CreditsHelper.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
48
app/Helpers/FirstParty/Credits/CreditsService.php
Normal file
48
app/Helpers/FirstParty/Credits/CreditsService.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Credits;
|
||||
|
||||
use App\Models\UserCredit;
|
||||
|
||||
class CreditsService
|
||||
{
|
||||
public static function depositSubscription(int $userId, int $amount, ?string $description = null): bool
|
||||
{
|
||||
return CreditsHelper::deposit($userId, $amount, UserCredit::TYPE_SUBSCRIPTION, $description);
|
||||
}
|
||||
|
||||
public static function depositAlacarte(int $userId, int $amount, ?string $description = null): bool
|
||||
{
|
||||
return CreditsHelper::deposit($userId, $amount, UserCredit::TYPE_ALACARTE, $description);
|
||||
}
|
||||
|
||||
public static function spend(int $userId, int $amount, ?string $description = null, ?bool $overrideSubscriptionFirst = null): bool
|
||||
{
|
||||
return CreditsHelper::spend($userId, $amount, $description, $overrideSubscriptionFirst);
|
||||
}
|
||||
|
||||
public static function setSpendSubscriptionFirst(int $userId, bool $spendSubscriptionFirst): bool
|
||||
{
|
||||
return CreditsHelper::setSpendSubscriptionFirst($userId, $spendSubscriptionFirst);
|
||||
}
|
||||
|
||||
public static function balance(int $userId, ?string $type = null): int
|
||||
{
|
||||
return CreditsHelper::balance($userId, $type);
|
||||
}
|
||||
|
||||
public static function canSpend(int $userId, int $amount): bool
|
||||
{
|
||||
return CreditsHelper::canSpend($userId, $amount);
|
||||
}
|
||||
|
||||
public static function summary(int $userId): array
|
||||
{
|
||||
return CreditsHelper::summary($userId);
|
||||
}
|
||||
|
||||
public static function transactionHistory(int $userId, int $limit = 20): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return CreditsHelper::transactionHistory($userId, $limit);
|
||||
}
|
||||
}
|
||||
67
app/Helpers/FirstParty/Credits/UserCreditHelper.php
Normal file
67
app/Helpers/FirstParty/Credits/UserCreditHelper.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Credits;
|
||||
|
||||
use App\Helpers\FirstParty\Stripe\StripeHelper;
|
||||
use App\Models\PaymentWebhookProcessedLog;
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
|
||||
class UserCreditHelper
|
||||
{
|
||||
public static function handleStripeWebhook(WebhookReceived $event)
|
||||
{
|
||||
$payload = $event->payload;
|
||||
|
||||
switch ($payload['type']) {
|
||||
case 'checkout.session.completed':
|
||||
self::handleCheckoutSessionCompleted($payload['data']['object']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleCheckoutSessionCompleted($checkout_session)
|
||||
{
|
||||
// Check if the webhook has already been processed
|
||||
$payment_webhook_processed_log = PaymentWebhookProcessedLog::where('provider', 'stripe')
|
||||
->where('log_id', $checkout_session['id'])
|
||||
->where('log_type', 'checkout_session')
|
||||
->first();
|
||||
|
||||
if (! is_null($payment_webhook_processed_log)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the user associated with the checkout session
|
||||
$user = StripeHelper::getUserByStripeCustomerId($checkout_session['customer']);
|
||||
|
||||
if ($user) {
|
||||
|
||||
// Get the line items from the checkout session
|
||||
$lineItems = \Stripe\Checkout\Session::allLineItems($checkout_session['id']);
|
||||
|
||||
foreach ($lineItems->data as $lineItem) {
|
||||
$stripe_price_id = $lineItem->price->id;
|
||||
$stripe_product_id = $lineItem->price->product;
|
||||
|
||||
// Get the credit pack associated with the price ID
|
||||
$credit_pack = CreditsHelper::getCreditPackByStripePriceId($stripe_product_id, $stripe_price_id, get_stripe_env());
|
||||
|
||||
if (is_null($credit_pack)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$total_credits = $credit_pack['purchased_credits'] + $credit_pack['bonus_credits'];
|
||||
|
||||
// Deposit the credits to the user's account
|
||||
CreditsService::depositAlacarte($user->id, $total_credits, "Purchased {$credit_pack['name']}");
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the webhook as processed
|
||||
PaymentWebhookProcessedLog::create([
|
||||
'provider' => 'stripe',
|
||||
'log_id' => $checkout_session['id'],
|
||||
'log_type' => 'checkout_session',
|
||||
]);
|
||||
}
|
||||
}
|
||||
73
app/Helpers/FirstParty/Purchase/CreditsPurchaseHelper.php
Normal file
73
app/Helpers/FirstParty/Purchase/CreditsPurchaseHelper.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Purchase;
|
||||
|
||||
use App\Helpers\FirstParty\Credits\CreditsHelper;
|
||||
use App\Helpers\FirstParty\Credits\CreditsService;
|
||||
use App\Helpers\FirstParty\Stripe\StripeHelper;
|
||||
use App\Models\PaymentWebhookProcessedLog;
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
|
||||
class CreditsPurchaseHelper
|
||||
{
|
||||
public static function handleWebhookEvents(WebhookReceived $event)
|
||||
{
|
||||
|
||||
switch (StripeHelper::getEventType($event)) {
|
||||
case 'checkout.session.completed':
|
||||
self::handleCheckoutSessionCompleted($event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleCheckoutSessionCompleted($event)
|
||||
{
|
||||
|
||||
$object = StripeHelper::getEventObject($event);
|
||||
|
||||
// Check if the webhook has already been processed
|
||||
$payment_webhook_processed_log = PaymentWebhookProcessedLog::where('provider', 'stripe')
|
||||
->where('log_id', $object['id'])
|
||||
->where('log_type', 'checkout_session')
|
||||
->first();
|
||||
|
||||
if (! is_null($payment_webhook_processed_log)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the user associated with the checkout session
|
||||
$user = StripeHelper::getUserByStripeID($object['customer']);
|
||||
|
||||
if ($user) {
|
||||
|
||||
// Get the line items from the checkout session
|
||||
StripeHelper::setStripeApiKey();
|
||||
$lineItems = \Stripe\Checkout\Session::allLineItems($object['id']);
|
||||
|
||||
// dd($lineItems);
|
||||
|
||||
foreach ($lineItems->data as $lineItem) {
|
||||
$stripe_price_id = $lineItem->price->id;
|
||||
|
||||
// Get the credit pack associated with the price ID
|
||||
$credit_pack = CreditsHelper::getCreditPackByStripePriceId($stripe_price_id);
|
||||
|
||||
if (is_null($credit_pack)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$total_credits = PurchaseHelper::getPlanSystemProperty($credit_pack, 'credits');
|
||||
|
||||
// Deposit the credits to the user's account
|
||||
CreditsService::depositAlacarte($user->id, $total_credits, "Purchased {$credit_pack['name']}");
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the webhook as processed
|
||||
PaymentWebhookProcessedLog::create([
|
||||
'provider' => 'stripe',
|
||||
'log_id' => $object['id'],
|
||||
'log_type' => 'checkout_session',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public static function getPricingPageSubscriptions()
|
||||
|
||||
$subscriptions = self::filterShowInPricing($subscriptions);
|
||||
|
||||
$subscriptions = self::setSystemPlan($subscriptions, 'stripe.current_stripe_price_id.month');
|
||||
$subscriptions = self::setSystemPlan($subscriptions, 'stripe.current_stripe_price_id.month', 'stripe_monthly_price_id');
|
||||
|
||||
$subscriptions = self::filterUnsetSystem($subscriptions);
|
||||
|
||||
@@ -28,7 +28,7 @@ public static function getPricingPageOneTime()
|
||||
|
||||
$one_time = PurchaseHelper::filterShowInPricing($one_time);
|
||||
|
||||
$one_time = PurchaseHelper::setSystemPlan($one_time, 'stripe.current_stripe_price_id');
|
||||
$one_time = PurchaseHelper::setSystemPlan($one_time, 'stripe.current_stripe_price_id', 'stripe_price_id');
|
||||
|
||||
$one_time = PurchaseHelper::filterUnsetSystem($one_time);
|
||||
|
||||
@@ -136,11 +136,11 @@ public static function getOneTimePurchases(?bool $enabled, $system = false)
|
||||
return $tmp_otp;
|
||||
}
|
||||
|
||||
public static function setSystemPlan($arr, $property)
|
||||
public static function setSystemPlan($arr, $property, $key_name)
|
||||
{
|
||||
foreach ($arr as $key => $item) {
|
||||
|
||||
$arr[$key]['stripe_monthly_price_id'] = PurchaseHelper::getPlanSystemProperty($item, $property);
|
||||
$arr[$key][$key_name] = PurchaseHelper::getPlanSystemProperty($item, $property);
|
||||
|
||||
// $stripe_monthly_price_id = PurchaseHelper::getPlanSystemProperty($subscription, 'stripe.product_id.month');
|
||||
|
||||
@@ -173,7 +173,7 @@ public static function filterShowInPricing($arr)
|
||||
});
|
||||
}
|
||||
|
||||
private static function getStripeEnvironment()
|
||||
public static function getStripeEnvironment()
|
||||
{
|
||||
$env = App::environment();
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
class SubscriptionHelper
|
||||
{
|
||||
public static function handleSubscriptionWebhookEvents(WebhookReceived $event)
|
||||
public static function handleWebhookEvents(WebhookReceived $event)
|
||||
{
|
||||
switch ($event->payload['type']) {
|
||||
switch (StripeHelper::getEventType($event)) {
|
||||
case 'customer.subscription.created':
|
||||
case 'customer.subscription.updated':
|
||||
self::handleSubscriptionUpsert($event);
|
||||
@@ -25,7 +25,7 @@ public static function handleSubscriptionWebhookEvents(WebhookReceived $event)
|
||||
|
||||
private static function handleSubscriptionUpsert(WebhookReceived $event)
|
||||
{
|
||||
$object = $event->payload['data']['object'];
|
||||
$object = StripeHelper::getEventObject($event);
|
||||
|
||||
// dump($object);
|
||||
|
||||
@@ -83,6 +83,34 @@ private static function handleSubscriptionUpsert(WebhookReceived $event)
|
||||
|
||||
private static function handleSubscriptionDelete(WebhookReceived $event)
|
||||
{
|
||||
// /
|
||||
$object = StripeHelper::getEventObject($event);
|
||||
|
||||
$user = StripeHelper::getUserByStripeID($object['customer']);
|
||||
|
||||
if ($user) {
|
||||
|
||||
$plan = Plan::where('tier', 'free')->first();
|
||||
|
||||
if ($plan) {
|
||||
$user_plan = UserPlan::where('user_id', $user->id)->first();
|
||||
|
||||
if ($user_plan) {
|
||||
$user_plan->update([
|
||||
'plan_id' => $plan->id,
|
||||
'current_period_end' => null,
|
||||
'cancel_at' => null,
|
||||
'canceled_at' => null,
|
||||
]);
|
||||
} else {
|
||||
$user_plan = UserPlan::create([
|
||||
'user_id' => $user->id,
|
||||
'plan_id' => $plan->id,
|
||||
'current_period_end' => null,
|
||||
'cancel_at' => null,
|
||||
'canceled_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Helpers\FirstParty\Stripe;
|
||||
|
||||
use App\Models\User;
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
|
||||
class StripeHelper
|
||||
{
|
||||
@@ -10,4 +11,19 @@ public static function getUserByStripeID($customer_id)
|
||||
{
|
||||
return User::where('stripe_id', $customer_id)->first();
|
||||
}
|
||||
|
||||
public static function getEventObject(WebhookReceived $event)
|
||||
{
|
||||
return $event->payload['data']['object'];
|
||||
}
|
||||
|
||||
public static function getEventType(WebhookReceived $event)
|
||||
{
|
||||
return $event->payload['type'];
|
||||
}
|
||||
|
||||
public static function setStripeApiKey()
|
||||
{
|
||||
\Stripe\Stripe::setApiKey(config('services.stripe.secret'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\FirstParty\Credits\CreditsService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserAccountController extends Controller
|
||||
@@ -19,8 +20,8 @@ public function index()
|
||||
'user' => $user,
|
||||
'billing' => [
|
||||
'provider' => 'stripe',
|
||||
'portal' => Auth::user()->billingPortalUrl(route('home'))
|
||||
]
|
||||
],
|
||||
'credits' => CreditsService::balance(Auth::id()),
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -9,6 +9,17 @@
|
||||
|
||||
class UserPurchaseController extends Controller
|
||||
{
|
||||
public function billingPortal(Request $request)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => [
|
||||
'data' => [
|
||||
'redirect' => Auth::user()->billingPortalUrl(route('home')),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function pricingPage(Request $request)
|
||||
{
|
||||
|
||||
@@ -61,7 +72,7 @@ public function subscribeSuccess(Request $request)
|
||||
|
||||
Session::forget('checkout_session_id');
|
||||
|
||||
return redirect()->route('home')->with('success', 'Thank you for subscribing! Your subscription should be active momentarily. Please refresh the page if you do not see your plan.');
|
||||
return redirect()->route('home')->with('success', 'Purchase successful! Your purchase should be active momentarily. Please refresh if you did not see any changes.');
|
||||
}
|
||||
|
||||
public function subscribeCancelled(Request $request)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Helpers\FirstParty\Purchase\CreditsPurchaseHelper;
|
||||
use App\Helpers\FirstParty\Purchase\SubscriptionHelper;
|
||||
use App\Helpers\FirstParty\Purchase\WatermarkUsageHelper;
|
||||
use Laravel\Cashier\Events\WebhookReceived;
|
||||
@@ -21,7 +22,8 @@ public function __construct()
|
||||
*/
|
||||
public function handle(WebhookReceived $event): void
|
||||
{
|
||||
SubscriptionHelper::handleSubscriptionWebhookEvents($event);
|
||||
SubscriptionHelper::handleWebhookEvents($event);
|
||||
CreditsPurchaseHelper::handleWebhookEvents($event);
|
||||
WatermarkUsageHelper::handleWatermarkUsageWebhookEvents($event);
|
||||
}
|
||||
}
|
||||
|
||||
16
app/Models/PaymentWebhookProcessedLog.php
Normal file
16
app/Models/PaymentWebhookProcessedLog.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PaymentWebhookProcessedLog extends Model
|
||||
{
|
||||
protected $table = 'payment_webhook_processed_logs';
|
||||
|
||||
protected $fillable = [
|
||||
'provider',
|
||||
'log_id',
|
||||
'log_type',
|
||||
];
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class User extends Authenticatable
|
||||
protected function ids(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn($value, $attributes) => hashids_encode($attributes['id']),
|
||||
get: fn ($value, $attributes) => hashids_encode($attributes['id']),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
39
app/Models/UserCredit.php
Normal file
39
app/Models/UserCredit.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class UserCredit extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
const TYPE_SUBSCRIPTION = 'subscription';
|
||||
|
||||
const TYPE_ALACARTE = 'alacarte';
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'subscription_credits',
|
||||
'alacarte_credits',
|
||||
'spend_subscription_first',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'spend_subscription_first' => 'boolean',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function transactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserCreditTransaction::class, 'user_id', 'user_id')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
}
|
||||
57
app/Models/UserCreditTransaction.php
Normal file
57
app/Models/UserCreditTransaction.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserCreditTransaction extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'credit_type',
|
||||
'operation',
|
||||
'amount',
|
||||
'subscription_balance_after',
|
||||
'alacarte_balance_after',
|
||||
'description',
|
||||
'metadata',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'metadata' => 'array',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function userCredit(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserCredit::class, 'user_id', 'user_id');
|
||||
}
|
||||
|
||||
public function scopeDeposits($query)
|
||||
{
|
||||
return $query->where('operation', 'deposit');
|
||||
}
|
||||
|
||||
public function scopeSpending($query)
|
||||
{
|
||||
return $query->where('operation', 'spend');
|
||||
}
|
||||
|
||||
public function isCredit(): bool
|
||||
{
|
||||
return $this->amount > 0;
|
||||
}
|
||||
|
||||
public function isDebit(): bool
|
||||
{
|
||||
return $this->amount < 0;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class UserUsage extends Model
|
||||
protected function ids(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn($value, $attributes) => hashids_encode($attributes['id']),
|
||||
get: fn ($value, $attributes) => hashids_encode($attributes['id']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user