Add packages API endpoint

This commit is contained in:
Ralph J. Smit
2022-08-12 22:20:56 +02:00
parent 8ef6e2b64c
commit 3388b4fdec
10 changed files with 188 additions and 44 deletions

View 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,
) {}
}

View File

@@ -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'),

View 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());
}
}

View File

@@ -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)] ?? '$';

View File

@@ -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 = [