Add packages API endpoint
This commit is contained in:
25
app/DataTransferObjects/PackageData.php
Normal file
25
app/DataTransferObjects/PackageData.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\DataTransferObjects;
|
||||
|
||||
use App\DataTransferObjects\Support\Data;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class PackageData extends Data
|
||||
{
|
||||
public function __construct(
|
||||
// Add validation attributes to this class if we add additional API-endpoints.
|
||||
public int $id,
|
||||
public ?string $name,
|
||||
public ?int $maximum_servers,
|
||||
public ?int $maximum_sites,
|
||||
public float $price_hourly,
|
||||
public float $price_monthly,
|
||||
public float $price_yearly,
|
||||
public ?string $stripe_plan_id,
|
||||
public string $currency,
|
||||
public array $server_permissions,
|
||||
public array $site_permissions,
|
||||
public Carbon $created_at,
|
||||
) {}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class PackageResource extends Resource
|
||||
->helperText(__('Set to 0 for unlimited'))
|
||||
->integer()
|
||||
->required(),
|
||||
TextInput::make('plan_id')
|
||||
TextInput::make('stripe_plan_id')
|
||||
->helperText(__('Enter the pricing ID from Stripe here') . ' - <a href="https://docs.ploi-core.io/digging-deeper/using-stripe" target="ploi-docs-stripe" class="text-primary-500">How does this work?</a>')
|
||||
->label(__('Stripe ID'))
|
||||
->columnSpan(2),
|
||||
@@ -106,17 +106,17 @@ class PackageResource extends Resource
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label(__('Name'))
|
||||
->description(function (Package $record) {
|
||||
if (!$record->plan_id) {
|
||||
if ( ! $record->stripe_plan_id ) {
|
||||
return __('Not attached to Stripe.');
|
||||
}
|
||||
|
||||
return "Attached to stripe - {$record->price_monthly} {$record->currency}";
|
||||
}),
|
||||
Tables\Columns\TextColumn::make('maximum_sites')
|
||||
->formatStateUsing(fn(int $state) => $state === 0 ? __('Unlimited') : $state)
|
||||
->formatStateUsing(fn (int $state) => $state === 0 ? __('Unlimited') : $state)
|
||||
->label(__('Maximum sites')),
|
||||
Tables\Columns\TextColumn::make('maximum_servers')
|
||||
->formatStateUsing(fn(int $state) => $state === 0 ? __('Unlimited') : $state)
|
||||
->formatStateUsing(fn (int $state) => $state === 0 ? __('Unlimited') : $state)
|
||||
->label(__('Maximum servers')),
|
||||
Tables\Columns\TextColumn::make('users_count')
|
||||
->counts('users'),
|
||||
|
||||
15
app/Http/Controllers/Api/PackageController.php
Normal file
15
app/Http/Controllers/Api/PackageController.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\DataTransferObjects\PackageData;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Package;
|
||||
|
||||
class PackageController extends Controller
|
||||
{
|
||||
public function index(): mixed
|
||||
{
|
||||
return PackageData::collection(Package::paginate());
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
namespace App\Http\Controllers\Profile;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\User;
|
||||
use App\Models\Package;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Package;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Stripe\Exception\InvalidRequestException;
|
||||
|
||||
class ProfileBillingController extends Controller
|
||||
@@ -20,39 +22,39 @@ class ProfileBillingController extends Controller
|
||||
$sortByType = array_key_first($request->input('sortBy', []));
|
||||
|
||||
$packages = Package::query()
|
||||
->where(function ($query) {
|
||||
->where(function (Builder $query) {
|
||||
return $query
|
||||
->where(function ($query) {
|
||||
->where(function (Builder $query) {
|
||||
return $query
|
||||
->where('price_monthly', '>', 0)
|
||||
->orWhere('price_yearly', '>', 0);
|
||||
})
|
||||
->whereNotNull('plan_id');
|
||||
->whereNotNull('stripe_plan_id');
|
||||
})
|
||||
->when($request->input('sortBy.' . $sortByType), function ($query, $value) use ($sortByType) {
|
||||
if ($sortByType === 'price') {
|
||||
if ( $sortByType === 'price' ) {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('price_monthly', 'asc')
|
||||
: $query->orderBy('price_monthly', 'desc');
|
||||
}
|
||||
if ($sortByType === 'servers') {
|
||||
if ( $sortByType === 'servers' ) {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('maximum_servers', 'asc')
|
||||
: $query->orderBy('maximum_servers', 'desc');
|
||||
}
|
||||
if ($sortByType === 'sites') {
|
||||
if ( $sortByType === 'sites' ) {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('maximum_sites', 'asc')
|
||||
: $query->orderBy('maximum_sites', 'desc');
|
||||
}
|
||||
if ($sortByType === 'name') {
|
||||
if ( $sortByType === 'name' ) {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('name', 'asc')
|
||||
: $query->orderBy('name', 'desc');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}, function ($query) {
|
||||
}, function (Builder $query) {
|
||||
return $query->orderBy('price_monthly', 'asc');
|
||||
})
|
||||
->get()
|
||||
@@ -61,19 +63,19 @@ class ProfileBillingController extends Controller
|
||||
|
||||
$package->period = 'monthly';
|
||||
|
||||
if ($package->price_yearly > 0) {
|
||||
if ( $package->price_yearly > 0 ) {
|
||||
$package->period = 'yearly';
|
||||
}
|
||||
|
||||
$package->price_monthly = ($currency ?? '[Unknown currency]') . number_format($package->price_monthly, 2, ',', '.');
|
||||
$package->price_yearly = ($currency ?? '[Unknown currency]') . number_format($package->price_yearly, 2, ',', '.');
|
||||
$package->price_monthly = ( $currency ?? '[Unknown currency]' ) . number_format($package->price_monthly, 2, ',', '.');
|
||||
$package->price_yearly = ( $currency ?? '[Unknown currency]' ) . number_format($package->price_yearly, 2, ',', '.');
|
||||
|
||||
return $package;
|
||||
});
|
||||
|
||||
try {
|
||||
$clientSecret = $user->createSetupIntent()->client_secret;
|
||||
} catch (\Exception $exception) {
|
||||
} catch (Exception $exception) {
|
||||
return inertia('Profile/BillingError');
|
||||
}
|
||||
|
||||
@@ -88,13 +90,13 @@ class ProfileBillingController extends Controller
|
||||
'data_client_secret' => $clientSecret,
|
||||
'card' => [
|
||||
'last_four' => $user->card_last_four,
|
||||
'brand' => $user->card_brand
|
||||
'brand' => $user->card_brand,
|
||||
],
|
||||
'filters' => [
|
||||
'sort' => [
|
||||
$sortByType => $request->input('sortBy.' . $sortByType, 'asc'),
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -111,7 +113,7 @@ class ProfileBillingController extends Controller
|
||||
'postal_code' => $request->input('billing_details.address.postal_code'),
|
||||
'city' => $request->input('billing_details.address.city'),
|
||||
'country' => $request->input('billing_details.address.country'),
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($user->paymentMethods() as $paymentMethod) {
|
||||
@@ -140,25 +142,25 @@ class ProfileBillingController extends Controller
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
if (!$user->hasStripeId() || !$user->defaultPaymentMethod()) {
|
||||
if ( ! $user->hasStripeId() || ! $user->defaultPaymentMethod() ) {
|
||||
return redirect()->route('profile.billing.index')->with('error', 'You cannot change your plan without a valid creditcard, please update your billing details first');
|
||||
}
|
||||
|
||||
$plan = Package::query()->findOrFail($request->input('plan'));
|
||||
|
||||
$planId = $plan->plan_id;
|
||||
$planId = $plan->stripe_plan_id;
|
||||
|
||||
// Only do something if the user is not already subscribed to this plan.
|
||||
if ($user->subscribedToPlan($planId, 'default')) {
|
||||
if ( $user->subscribedToPlan($planId, 'default') ) {
|
||||
return redirect()->route('profile.billing.index')->with('error', 'You did not select a different plan');
|
||||
}
|
||||
|
||||
// If the user is already subscribed to the default plan, we have to swap it. Otherwise create a new one.
|
||||
try {
|
||||
if ($user->subscribed('default')) {
|
||||
if ( $user->subscribed('default') ) {
|
||||
$user->subscription('default')->swap($planId);
|
||||
} else {
|
||||
if ($coupon = $request->input('coupon')) {
|
||||
if ( $coupon = $request->input('coupon') ) {
|
||||
$user->newSubscription('default', $planId)
|
||||
->withCoupon($coupon)
|
||||
->create($user->defaultPaymentMethod()->id);
|
||||
@@ -180,7 +182,7 @@ class ProfileBillingController extends Controller
|
||||
|
||||
public function cancel(Request $request)
|
||||
{
|
||||
/* @var $user \App\Models\User */
|
||||
/* @var $user User */
|
||||
$user = $request->user();
|
||||
|
||||
$subscription = $user->subscription('default')->cancel();
|
||||
@@ -208,7 +210,7 @@ class ProfileBillingController extends Controller
|
||||
{
|
||||
return $request->user()->downloadInvoice($id, [
|
||||
'vendor' => setting('name'),
|
||||
'product' => 'Webhosting'
|
||||
'product' => 'Webhosting',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -223,7 +225,7 @@ class ProfileBillingController extends Controller
|
||||
Package::CURRENCY_GBP => 'GBP £',
|
||||
Package::CURRENCY_INR => 'INR ₹',
|
||||
Package::CURRENCY_THB => 'THB ',
|
||||
Package::CURRENCY_BRL=> 'BRL R$ ',
|
||||
Package::CURRENCY_BRL => 'BRL R$ ',
|
||||
];
|
||||
|
||||
return $currencies[strtolower($key)] ?? '$';
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class Package extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
||||
const CURRENCY_EURO = 'eur';
|
||||
const CURRENCY_USD = 'usd';
|
||||
const CURRENCY_NOK = 'nok';
|
||||
@@ -22,7 +22,7 @@ class Package extends Model
|
||||
|
||||
public $fillable = [
|
||||
'name',
|
||||
'plan_id', // This does not reflect a internal database relation, it reflects the plan ID from the PSP
|
||||
'stripe_plan_id', // This does not reflect an internal database relation, it reflects the plan ID from the PSP
|
||||
'currency',
|
||||
'price_hourly',
|
||||
'price_monthly',
|
||||
@@ -30,7 +30,7 @@ class Package extends Model
|
||||
'maximum_sites',
|
||||
'maximum_servers',
|
||||
'site_permissions',
|
||||
'server_permissions'
|
||||
'server_permissions',
|
||||
];
|
||||
|
||||
public $casts = [
|
||||
|
||||
Reference in New Issue
Block a user