mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-05 18:23:48 +00:00
removed old subscription backend
This commit is contained in:
@@ -1,23 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Domain\Plans\Controllers\PlansController;
|
||||
use Domain\Admin\Controllers\Users\UserController;
|
||||
use Domain\Pages\Controllers\AdminPagesController;
|
||||
use Domain\Settings\Controllers\SetEmailController;
|
||||
use Domain\Settings\Controllers\SetStripeController;
|
||||
use Domain\Settings\Controllers\FlushCacheController;
|
||||
use Domain\Invoices\Controllers\AdminInvoiceController;
|
||||
use Domain\Localization\Controllers\LanguageController;
|
||||
use Domain\Plans\Controllers\PlanSubscribersController;
|
||||
use Domain\Admin\Controllers\Users\DeleteUserController;
|
||||
use Domain\Settings\Controllers\GetSettingsValueController;
|
||||
use Domain\Admin\Controllers\Dashboard\GetNewbiesController;
|
||||
use Domain\Admin\Controllers\Users\ChangeUserRoleController;
|
||||
use Domain\Settings\Controllers\UpdateSettingValueController;
|
||||
use Domain\Admin\Controllers\Users\ShowUserInvoicesController;
|
||||
use Domain\Admin\Controllers\Users\ResetUserPasswordController;
|
||||
use Domain\Admin\Controllers\Dashboard\GetWidgetsValuesController;
|
||||
use Domain\Admin\Controllers\Users\ShowUserSubscriptionController;
|
||||
use Domain\Localization\Controllers\UpdateLanguageStringController;
|
||||
use Domain\Admin\Controllers\Users\ShowUserStorageCapacityController;
|
||||
use Domain\Admin\Controllers\Users\ChangeUserStorageCapacityController;
|
||||
@@ -37,30 +31,25 @@ Route::group(['prefix' => 'users'], function () {
|
||||
Route::delete('/{user}/delete', DeleteUserController::class);
|
||||
|
||||
// Subscription
|
||||
Route::get('/{user}/subscription', ShowUserSubscriptionController::class);
|
||||
Route::get('/{user}/invoices', ShowUserInvoicesController::class);
|
||||
//Route::get('/{user}/subscription', ShowUserSubscriptionController::class);
|
||||
//Route::get('/{user}/invoices', ShowUserInvoicesController::class);
|
||||
});
|
||||
|
||||
Route::apiResource('/users', UserController::class);
|
||||
|
||||
// Plans
|
||||
Route::get('/plans/{id}/subscribers', PlanSubscribersController::class);
|
||||
Route::apiResource('/', PlansController::class);
|
||||
|
||||
// Pages
|
||||
Route::apiResource('/pages', AdminPagesController::class);
|
||||
|
||||
// Invoices
|
||||
Route::get('/invoices', [AdminInvoiceController::class, 'index']);
|
||||
|
||||
// Settings
|
||||
Route::group(['prefix' => 'settings'], function () {
|
||||
Route::patch('/', UpdateSettingValueController::class);
|
||||
Route::get('/', GetSettingsValueController::class);
|
||||
|
||||
Route::get('/flush-cache', FlushCacheController::class);
|
||||
Route::post('/stripe', SetStripeController::class);
|
||||
Route::post('/email', SetEmailController::class);
|
||||
|
||||
// TODO: stripe setup
|
||||
//Route::post('/stripe', SetStripeController::class);
|
||||
});
|
||||
|
||||
// Language
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Users\Controllers\ResetPasswordController;
|
||||
use Domain\Files\Controllers\UploadFileController;
|
||||
use App\Users\Controllers\ForgotPasswordController;
|
||||
use Domain\Folders\Controllers\FavouriteController;
|
||||
use Domain\Plans\Controllers\ActivePlansController;
|
||||
use Domain\Folders\Controllers\CreateFolderController;
|
||||
use Domain\Browsing\Controllers\BrowseFolderController;
|
||||
use Domain\Sharing\Controllers\ShareViaEmailController;
|
||||
@@ -30,7 +29,6 @@ Route::apiResource('/page', PagesController::class);
|
||||
|
||||
// Homepage
|
||||
Route::post('/contact', SendContactMessageController::class);
|
||||
Route::get('/pricing', ActivePlansController::class);
|
||||
Route::get('/settings', GetSettingsValueController::class);
|
||||
|
||||
// Register user
|
||||
|
||||
@@ -16,5 +16,4 @@ Route::group(['middleware' => ['auth:sanctum']], function () {
|
||||
Route::post('/folders/{folder}/convert', ConvertFolderIntoTeamFolderController::class);
|
||||
Route::delete('/folders/{folder}/leave', LeaveTeamFolderController::class);
|
||||
Route::get('/folders/{folder}/tree', NavigationTreeController::class);
|
||||
|
||||
});
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Domain\Payments\Controllers\PaymentMethodsController;
|
||||
use App\Users\Controllers\Account\AccountDetailsController;
|
||||
use App\Users\Controllers\Account\UpdatePasswordController;
|
||||
use App\Users\Controllers\Account\StorageCapacityController;
|
||||
use App\Users\Controllers\Verification\VerifyEmailController;
|
||||
use Domain\Invoices\Controllers\UserProfileInvoiceController;
|
||||
use Domain\Subscriptions\Controllers\GetSetupIntentController;
|
||||
use App\Users\Controllers\Verification\ResendVerificationEmail;
|
||||
use App\Users\Controllers\Authentication\CheckAccountController;
|
||||
use App\Users\Controllers\Account\UpdateProfileSettingsController;
|
||||
use Domain\Subscriptions\Controllers\SubscriptionCancelController;
|
||||
use Domain\Subscriptions\Controllers\SubscriptionResumeController;
|
||||
use Domain\Subscriptions\Controllers\SubscriptionDetailsController;
|
||||
use Domain\Subscriptions\Controllers\SubscriptionUpgradeController;
|
||||
use App\Users\Controllers\Authentication\AccountAccessTokenController;
|
||||
|
||||
Route::post('/check', CheckAccountController::class);
|
||||
@@ -34,17 +27,4 @@ Route::group(['middleware' => ['auth:sanctum']], function () {
|
||||
Route::post('/password', UpdatePasswordController::class);
|
||||
Route::get('/storage', StorageCapacityController::class);
|
||||
Route::get('/', AccountDetailsController::class);
|
||||
|
||||
// Subscription
|
||||
Route::group(['prefix' => 'subscription'], function () {
|
||||
Route::get('/setup-intent', GetSetupIntentController::class);
|
||||
|
||||
Route::apiResource('/payment-cards', PaymentMethodsController::class);
|
||||
Route::get('/invoices', UserProfileInvoiceController::class);
|
||||
Route::get('/', SubscriptionDetailsController::class);
|
||||
|
||||
Route::post('/upgrade', SubscriptionUpgradeController::class);
|
||||
Route::post('/cancel', SubscriptionCancelController::class);
|
||||
Route::post('/resume', SubscriptionResumeController::class);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Domain\Homepage\Controllers\IndexController;
|
||||
use Domain\Invoices\Controllers\AdminInvoiceController;
|
||||
use Domain\Sharing\Controllers\SharePublicIndexController;
|
||||
use Domain\Sharing\Controllers\WebCrawlerOpenGraphController;
|
||||
use Domain\Subscriptions\Controllers\StripeWebhookController;
|
||||
use Domain\Localization\Controllers\CurrentLocalizationController;
|
||||
|
||||
// Subscription Services
|
||||
//Route::post('/stripe/webhook', [StripeWebhookController::class, 'handleWebhook']);
|
||||
Route::get('/invoice/{customer}/{token}', [AdminInvoiceController::class, 'show'])->middleware(['auth:sanctum']);
|
||||
|
||||
// Translations
|
||||
Route::get('/translations/{lang}', CurrentLocalizationController::class);
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ use Kyslik\ColumnSortable\Sortable;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use App\Users\Notifications\ResetPassword;
|
||||
use Domain\Subscriptions\Traits\Subscription;
|
||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
@@ -39,7 +38,6 @@ use VueFileManager\Subscription\App\User\Traits\Billable;
|
||||
class User extends Authenticatable implements MustVerifyEmail
|
||||
{
|
||||
use TwoFactorAuthenticatable;
|
||||
use Subscription;
|
||||
use HasApiTokens;
|
||||
use Notifiable;
|
||||
use HasFactory;
|
||||
|
||||
@@ -21,9 +21,6 @@ class UserResource extends JsonResource
|
||||
'type' => 'user',
|
||||
'attributes' => [
|
||||
'storage_capacity' => $this->settings->storage_capacity,
|
||||
//'subscription' => $this->subscribed('main'),
|
||||
//'incomplete_payment' => $this->hasIncompletePayment('main') ? route('cashier.payment', $this->subscription('main')->latestPayment()->id) : null,
|
||||
'stripe_customer' => is_null($this->stripe_id) ? false : true,
|
||||
'email' => is_demo() ? obfuscate_email($this->email) : $this->email,
|
||||
'role' => $this->role,
|
||||
'two_factor_authentication' => $this->two_factor_secret ? true : false,
|
||||
|
||||
@@ -10,10 +10,6 @@ class GetWidgetsValuesController extends Controller
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
// Get total premium users
|
||||
$premium_users = Subscription::whereStripeStatus('active')
|
||||
->count();
|
||||
|
||||
// Get total storage usage
|
||||
$storage_usage = Metric::bytes(
|
||||
\DB::table('files')->sum('filesize')
|
||||
@@ -24,7 +20,6 @@ class GetWidgetsValuesController extends Controller
|
||||
'app_version' => config('vuefilemanager.version'),
|
||||
'total_users' => User::count(),
|
||||
'total_used_space' => $storage_usage,
|
||||
'total_premium_users' => $premium_users,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,10 @@ class DeleteUserController extends Controller
|
||||
return response('Done.', 204);
|
||||
}
|
||||
|
||||
if ($user->subscribed('main')) {
|
||||
// TODO: secure deletion
|
||||
/*if ($user->subscription) {
|
||||
abort(202, "You can\'t delete this account while user have active subscription.");
|
||||
}
|
||||
}*/
|
||||
|
||||
if ($user->id === Auth::id()) {
|
||||
abort(406, "You can\'t delete your account");
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Admin\Controllers\Users;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Invoices\Resources\InvoiceCollection;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
|
||||
class ShowUserInvoicesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private StripeService $stripe
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user storage details
|
||||
*/
|
||||
public function __invoke(User $user): InvoiceCollection
|
||||
{
|
||||
$invoices = $this->stripe->getUserInvoices($user);
|
||||
|
||||
return new InvoiceCollection($invoices);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Admin\Controllers\Users;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Users\Resources\UserSubscription;
|
||||
|
||||
class ShowUserSubscriptionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get user subscription details
|
||||
*/
|
||||
public function __invoke(User $user): UserSubscription | Response
|
||||
{
|
||||
if (! $user->stripeId() || ! $user->subscription('main')) {
|
||||
return response("User doesn't have any subscription.", 404);
|
||||
}
|
||||
|
||||
return new UserSubscription($user);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Admin\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class InvoiceAdminCollection extends ResourceCollection
|
||||
{
|
||||
public $collects = InvoiceAdminResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Admin\Resources;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Laravel\Cashier\Cashier;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class InvoiceAdminResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$user = User::where('stripe_id', $this['customer'])
|
||||
->first();
|
||||
|
||||
return [
|
||||
'data' => [
|
||||
'id' => $this['id'],
|
||||
'type' => 'invoices',
|
||||
'attributes' => [
|
||||
'customer' => $this['customer'],
|
||||
'total' => Cashier::formatAmount($this['total']),
|
||||
'currency' => $this['currency'],
|
||||
'created_at_formatted' => format_date($this['created']),
|
||||
'created_at' => $this['created'],
|
||||
'order' => $this['number'],
|
||||
'user_id' => $user->id ?? null,
|
||||
'client' => [
|
||||
'billing_address' => $this['customer_address'],
|
||||
'billing_name' => $this['customer_name'],
|
||||
'billing_phone_number' => $this['customer_phone'],
|
||||
],
|
||||
'bag' => [
|
||||
'amount' => $this['lines']['data'][0]['amount'],
|
||||
'currency' => $this['lines']['data'][0]['currency'],
|
||||
'type' => $this['lines']['data'][0]['type'],
|
||||
'description' => $this['lines']['data'][0]['description'],
|
||||
],
|
||||
'seller' => null,
|
||||
],
|
||||
$this->mergeWhen($user, function () use ($user) {
|
||||
return [
|
||||
'relationships' => [
|
||||
'user' => [
|
||||
'data' => [
|
||||
'id' => $user->id,
|
||||
'type' => 'user',
|
||||
'attributes' => [
|
||||
'name' => $user->settings->name,
|
||||
'avatar' => $user->settings->avatar,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Invoices\Controllers;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
use Domain\Admin\Resources\InvoiceAdminCollection;
|
||||
|
||||
class AdminInvoiceController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private StripeService $stripe
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all invoices
|
||||
*/
|
||||
public function index(): InvoiceAdminCollection
|
||||
{
|
||||
return new InvoiceAdminCollection(
|
||||
$this->stripe->getInvoices()['data']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single invoice by invoice $token
|
||||
*/
|
||||
public function show(string $customer, string $token): View
|
||||
{
|
||||
return view('vuefilemanager.invoice')
|
||||
->with('settings', get_settings_in_json())
|
||||
->with('invoice', $this->stripe->getUserInvoice($customer, $token));
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Invoices\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Domain\Invoices\Resources\InvoiceCollection;
|
||||
|
||||
class UserProfileInvoiceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get user invoices
|
||||
*/
|
||||
public function __invoke(): InvoiceCollection
|
||||
{
|
||||
$user = Auth::user()->invoices();
|
||||
|
||||
return new InvoiceCollection($user);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Invoices\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class InvoiceCollection extends ResourceCollection
|
||||
{
|
||||
public $collects = InvoiceResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Invoices\Resources;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class InvoiceResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$user = User::whereStripeId($this->customer)
|
||||
->first();
|
||||
|
||||
return [
|
||||
'data' => [
|
||||
'id' => $this->id,
|
||||
'type' => 'invoices',
|
||||
'attributes' => [
|
||||
'customer' => $this->customer,
|
||||
'total' => $this->total(),
|
||||
'currency' => $this->currency,
|
||||
'created_at_formatted' => format_date($this->date(), '%d. %B. %Y'),
|
||||
'created_at' => $this->created,
|
||||
'order' => $this->number,
|
||||
'user_id' => $user->id ?? null,
|
||||
'client' => [
|
||||
'billing_address' => $this->customer_address,
|
||||
'billing_name' => $this->customer_name,
|
||||
'billing_phone_number' => $this->customer_phone,
|
||||
],
|
||||
'seller' => null,
|
||||
'invoice_items' => $this->get_invoice_items(),
|
||||
'invoice_subscriptions' => $this->get_invoice_subscriptions(),
|
||||
],
|
||||
$this->mergeWhen($user, [
|
||||
'relationships' => [
|
||||
'user' => [
|
||||
'data' => [
|
||||
'id' => $user->id,
|
||||
'type' => 'user',
|
||||
'attributes' => [
|
||||
'name' => $user->settings->name,
|
||||
'avatar' => $user->settings->avatar,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_invoice_subscriptions(): array
|
||||
{
|
||||
$array = [];
|
||||
|
||||
foreach ($this->subscriptions() as $item) {
|
||||
array_push($array, [
|
||||
'amount' => $item->total(),
|
||||
'description' => $item->description,
|
||||
'currency' => $item->currency,
|
||||
'type' => $item->type,
|
||||
]);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_invoice_items(): array
|
||||
{
|
||||
$array = [];
|
||||
|
||||
foreach ($this->invoiceItems() as $item) {
|
||||
array_push($array, [
|
||||
'amount' => $item->total(),
|
||||
'description' => $item->description,
|
||||
'currency' => $item->currency,
|
||||
'type' => $item->type,
|
||||
]);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Cashier\PaymentMethod;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
use Domain\Payments\Resources\PaymentCardResource;
|
||||
use Domain\Payments\Resources\PaymentCardCollection;
|
||||
use Domain\Payments\Resources\PaymentDefaultCardResource;
|
||||
use Domain\Payments\Requests\RegisterNewPaymentMethodRequest;
|
||||
|
||||
class PaymentMethodsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private StripeService $stripe,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user payment methods grouped by default and others
|
||||
*/
|
||||
public function index(): array
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (! $user->hasPaymentMethod()) {
|
||||
return abort(204, 'User don\'t have any payment methods');
|
||||
}
|
||||
|
||||
$slug_payment_methods = 'payment-methods-user-' . $user->id;
|
||||
$slug_default_payment_method = 'default-payment-methods-user-' . $user->id;
|
||||
|
||||
if (Cache::has($slug_payment_methods) && Cache::has($slug_default_payment_method)) {
|
||||
$defaultPaymentMethod = Cache::get($slug_default_payment_method);
|
||||
$paymentMethodsMapped = Cache::get($slug_payment_methods);
|
||||
} else {
|
||||
// Get default payment method
|
||||
$defaultPaymentMethod = Cache::rememberForever($slug_default_payment_method, function () use ($user) {
|
||||
$defaultPaymentMethodObject = $user->defaultPaymentMethod();
|
||||
|
||||
return $defaultPaymentMethodObject instanceof PaymentMethod
|
||||
? $defaultPaymentMethodObject->asStripePaymentMethod()
|
||||
: $defaultPaymentMethodObject;
|
||||
});
|
||||
|
||||
// filter payment methods without default payment
|
||||
$paymentMethodsMapped = Cache::rememberForever($slug_payment_methods, function () use ($defaultPaymentMethod, $user) {
|
||||
$paymentMethods = $user->paymentMethods()->filter(fn ($paymentMethod) => $paymentMethod->id !== $defaultPaymentMethod->id);
|
||||
|
||||
// Get payment methods
|
||||
return $paymentMethods->map(fn ($paymentMethod) => $paymentMethod->asStripePaymentMethod())->values()->all();
|
||||
});
|
||||
}
|
||||
|
||||
if (! $user->card_brand || ! $user->stripe_id || is_null($paymentMethodsMapped) && is_null($paymentMethodsMapped)) {
|
||||
return [
|
||||
'default' => null,
|
||||
'others' => [],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'default' => $defaultPaymentMethod instanceof PaymentMethod
|
||||
? new PaymentCardResource($defaultPaymentMethod)
|
||||
: new PaymentDefaultCardResource($defaultPaymentMethod),
|
||||
'others' => new PaymentCardCollection($paymentMethodsMapped),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update default payment method
|
||||
*/
|
||||
public function update(string $id): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
abort_if(is_demo_account('howdy@hi5ve.digital'), 204, 'Done.');
|
||||
|
||||
// Update DefaultPayment Method
|
||||
$user->updateDefaultPaymentMethod($id);
|
||||
|
||||
// Sync default payment method
|
||||
$user->updateDefaultPaymentMethodFromStripe();
|
||||
|
||||
// Clear cached payment methods
|
||||
cache_forget_many([
|
||||
"payment-methods-user-{$user->id}",
|
||||
"default-payment-methods-user-{$user->id}",
|
||||
]);
|
||||
|
||||
return response('Done', 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new payment method for user
|
||||
*/
|
||||
public function store(RegisterNewPaymentMethodRequest $request): Response
|
||||
{
|
||||
// Get user
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
if (is_demo_account($user->email)) {
|
||||
return response('Done', 201);
|
||||
}
|
||||
|
||||
// Register new payment method
|
||||
$this->stripe->registerNewPaymentMethod($request, $user);
|
||||
|
||||
return response('Done', 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user payment method
|
||||
*/
|
||||
public function delete($id): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
abort_if(is_demo_account($user->email), 204, 'Done.');
|
||||
|
||||
// Get payment method
|
||||
$paymentMethod = $user->findPaymentMethod($id);
|
||||
|
||||
// Delete payment method
|
||||
$paymentMethod->delete();
|
||||
|
||||
// Sync default payment method
|
||||
$user->updateDefaultPaymentMethodFromStripe();
|
||||
|
||||
// Clear cached payment methods
|
||||
cache_forget_many([
|
||||
"payment-methods-user-{$user->id}",
|
||||
"default-payment-methods-user-{$user->id}",
|
||||
]);
|
||||
|
||||
return response('Done.', 204);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Notifications;
|
||||
|
||||
use Laravel\Cashier\Payment;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class ConfirmPayment extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* The PaymentIntent identifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $paymentId;
|
||||
|
||||
/**
|
||||
* The payment amount.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $amount;
|
||||
|
||||
/**
|
||||
* Create a new payment confirmation notification.
|
||||
*
|
||||
* @param \Laravel\Cashier\Payment $payment
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Payment $payment)
|
||||
{
|
||||
$this->paymentId = $payment->id;
|
||||
$this->amount = $payment->amount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
$url = route('cashier.payment', ['id' => $this->paymentId]);
|
||||
|
||||
return (new MailMessage)
|
||||
->subject(__('cashier.confirm_payment'))
|
||||
->greeting(__('cashier.confirm_amount', ['amount' => $this->amount]))
|
||||
->line(__('cashier.confirm_description'))
|
||||
->action(__('cashier.confirm_button'), $url);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class RegisterNewPaymentMethodRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'token' => 'required|string',
|
||||
'default' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class PaymentCardCollection extends ResourceCollection
|
||||
{
|
||||
public $collects = PaymentCardResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PaymentCardResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'id' => (string) $this['id'],
|
||||
'type' => 'payment_method',
|
||||
'attributes' => [
|
||||
'provider' => 'stripe',
|
||||
'card_id' => $this['id'],
|
||||
'brand' => strtolower($this['card']['brand']),
|
||||
'last4' => $this['card']['last4'],
|
||||
'exp_month' => $this['card']['exp_month'],
|
||||
'exp_year' => $this['card']['exp_year'],
|
||||
'created_at' => format_date($this['created_at'], '%d. %B. %Y'),
|
||||
'status' => 'active',
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Payments\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PaymentDefaultCardResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'id' => (string) $this['id'],
|
||||
'type' => 'payment_method',
|
||||
'attributes' => [
|
||||
'provider' => 'stripe',
|
||||
'card_id' => $this['id'],
|
||||
'brand' => isset($this['brand']) ? strtolower($this['brand']) : strtolower($this['card']['brand']),
|
||||
'last4' => isset($this['last4']) ? $this['last4'] : $this['card']['last4'],
|
||||
'exp_month' => isset($this['exp_month']) ? $this['exp_month'] : $this['card']['exp_month'],
|
||||
'exp_year' => isset($this['exp_year']) ? $this['exp_year'] : $this['card']['exp_year'],
|
||||
'created_at' => format_date($this['created_at'], '%d. %B. %Y'),
|
||||
'status' => 'active',
|
||||
'default' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Domain\Plans\Resources\PricingCollection;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
|
||||
class ActivePlansController
|
||||
{
|
||||
/**
|
||||
* Get all active storage plans
|
||||
*/
|
||||
public function __invoke(): PricingCollection
|
||||
{
|
||||
// Get pricing from cache
|
||||
$pricing = Cache::rememberForever('pricing', fn () => resolve(StripeService::class)->getActivePlans());
|
||||
|
||||
// Format pricing to collection
|
||||
$collection = new PricingCollection($pricing);
|
||||
|
||||
// Sort and return pricing
|
||||
return $collection
|
||||
->sortBy('product.metadata.capacity')
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Controllers;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Laravel\Cashier\Subscription;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Users\Resources\UsersCollection;
|
||||
|
||||
class PlanSubscribersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get plan subscriptions
|
||||
*/
|
||||
public function __invoke(string $id): UsersCollection
|
||||
{
|
||||
$subscribers = Subscription::whereStripePlan($id)
|
||||
->pluck('user_id');
|
||||
|
||||
$users = User::sortable()
|
||||
->findMany($subscribers);
|
||||
|
||||
return new UsersCollection($users);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Plans\Resources\PlanResource;
|
||||
use Domain\Plans\Resources\PlanCollection;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
|
||||
class PlansController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private StripeService $stripe,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all plans
|
||||
*/
|
||||
public function index(): Response
|
||||
{
|
||||
// Store or Get plans to cache
|
||||
$plans = cache()
|
||||
->rememberForever('plans', fn () => $this->stripe->getPlans());
|
||||
|
||||
return response(new PlanCollection($plans), 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plan record
|
||||
*/
|
||||
public function show(string $id): Response
|
||||
{
|
||||
// Store or Get plan to cache
|
||||
$plan = cache()
|
||||
->rememberForever("plan-$id", fn () => $this->stripe->getPlan($id));
|
||||
|
||||
return response(new PlanResource($plan), 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new plan
|
||||
* TODO: store request
|
||||
*/
|
||||
public function store(Request $request): Response | PlanResource
|
||||
{
|
||||
if (is_demo()) {
|
||||
$plan = cache()
|
||||
->rememberForever('plan-starter-pack', fn () => $this->stripe->getPlan('starter-pack'));
|
||||
|
||||
return new PlanResource($plan);
|
||||
}
|
||||
|
||||
$plan = new PlanResource(
|
||||
$this->stripe->createPlan($request)
|
||||
);
|
||||
|
||||
// Clear cached plans
|
||||
cache_forget_many(['plans', 'pricing']);
|
||||
|
||||
return response($plan, 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plan attribute
|
||||
*/
|
||||
public function update(Request $request, string $id): Response
|
||||
{
|
||||
// Abort in demo mode
|
||||
abort_if(is_demo(), 204, 'Done.');
|
||||
|
||||
// Update plan
|
||||
$this->stripe->updatePlan($request, $id);
|
||||
|
||||
// Clear cached plans
|
||||
cache_forget_many(['plans', 'pricing', "plan-$id"]);
|
||||
|
||||
return response('Saved!', 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete plan
|
||||
*/
|
||||
public function delete($id): Response
|
||||
{
|
||||
// Abort in demo mode
|
||||
abort_if(is_demo(), 204, 'Done.');
|
||||
|
||||
// Delete plan
|
||||
$this->stripe->deletePlan($id);
|
||||
|
||||
// Clear cached plans
|
||||
cache_forget_many(['plans', 'pricing']);
|
||||
|
||||
return response('Done.', 204);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class PlanCollection extends ResourceCollection
|
||||
{
|
||||
public $collects = PlanResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Resources;
|
||||
|
||||
use Laravel\Cashier\Cashier;
|
||||
use Laravel\Cashier\Subscription;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PlanResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
// Get subscribers
|
||||
$subscriber_count = Subscription::where('stripe_plan', $this['plan']['id'])->where('stripe_status', 'active')->get();
|
||||
|
||||
return [
|
||||
'data' => [
|
||||
'id' => $this['plan']['id'],
|
||||
'type' => 'plans',
|
||||
'attributes' => [
|
||||
'subscribers' => $subscriber_count->count(),
|
||||
'status' => $this['plan']['active'] ? 1 : 0,
|
||||
'name' => $this['product']['name'],
|
||||
'description' => $this['product']['description'],
|
||||
'price' => $this['plan']['amount'],
|
||||
'price_formatted' => Cashier::formatAmount($this['plan']['amount']),
|
||||
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
|
||||
'capacity' => (int) $this['product']['metadata']['capacity'],
|
||||
'created_at_formatted' => format_date($this['plan']['created']),
|
||||
'created_at' => $this['plan']['created'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class PricingCollection extends ResourceCollection
|
||||
{
|
||||
public $collects = PricingResource::class;
|
||||
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Plans\Resources;
|
||||
|
||||
use Laravel\Cashier\Cashier;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PricingResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'id' => $this['plan']['id'],
|
||||
'type' => 'plans',
|
||||
'attributes' => [
|
||||
'name' => $this['product']['name'],
|
||||
'description' => $this['product']['description'],
|
||||
'price' => Cashier::formatAmount($this['plan']['amount']),
|
||||
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
|
||||
'capacity' => (int) $this['product']['metadata']['capacity'],
|
||||
'currency' => config('cashier.currency'),
|
||||
'tax_rates' => resolve(StripeService::class)->get_tax_rates($this['plan']['amount']),
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
|
||||
/**
|
||||
* Generate setup intent
|
||||
*/
|
||||
class GetSetupIntentController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
public StripeService $stripe,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(): Response
|
||||
{
|
||||
return response(
|
||||
$this->stripe->getSetupIntent(Auth::user()),
|
||||
201
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
|
||||
|
||||
class StripeWebhookController extends CashierController
|
||||
{
|
||||
public function __construct(
|
||||
public StripeService $stripe
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a cancelled customer from a Stripe subscription.
|
||||
*
|
||||
* @param array $payload
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handleCustomerSubscriptionDeleted($payload)
|
||||
{
|
||||
if ($user = $this->getUserByStripeId($payload['data']['object']['customer'])) {
|
||||
$user->subscriptions->filter(fn ($subscription) => $subscription->stripe_id === $payload['data']['object']['id'])->each(function ($subscription) {
|
||||
$subscription->markAsCancelled();
|
||||
});
|
||||
}
|
||||
|
||||
// Get user
|
||||
$user = User::whereStripeId($payload['data']['object']['customer'])
|
||||
->firstOrFail();
|
||||
|
||||
// Update storage capacity
|
||||
$user
|
||||
->settings()
|
||||
->update([
|
||||
'storage_capacity' => get_settings('storage_default'),
|
||||
]);
|
||||
|
||||
return $this->successMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Invoice Payment Succeeded
|
||||
*
|
||||
* @param $payload
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handleInvoicePaymentSucceeded($payload)
|
||||
{
|
||||
// Get user
|
||||
$user = User::whereStripeId($payload['data']['object']['customer'])
|
||||
->firstOrFail();
|
||||
|
||||
// Get requested plan
|
||||
$plan = $this->stripe->getPlan($user->subscription('main')->stripe_plan);
|
||||
|
||||
// Update user storage limit
|
||||
$user
|
||||
->settings()
|
||||
->update([
|
||||
'storage_capacity' => $plan['product']['metadata']['capacity'],
|
||||
]);
|
||||
|
||||
return $this->successMethod();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class SubscriptionCancelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Cancel Subscription
|
||||
*/
|
||||
public function __invoke(): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
if (is_demo_account($user->email)) {
|
||||
return response('Done.', 204);
|
||||
}
|
||||
|
||||
// Cancel subscription
|
||||
$user->subscription('main')->cancel();
|
||||
|
||||
// Forget user subscription
|
||||
Cache::forget("subscription-user-{$user->id}");
|
||||
|
||||
return response('Done.', 204);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Users\Resources\UserSubscription;
|
||||
|
||||
class SubscriptionDetailsController extends Controller
|
||||
{
|
||||
public function __invoke(): mixed
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (! $user->subscription('main')) {
|
||||
return abort(204, "User don't have any subscription");
|
||||
}
|
||||
|
||||
$slug = "subscription-user-{$user->id}";
|
||||
|
||||
if (cache()->has($slug)) {
|
||||
return cache()->get($slug);
|
||||
}
|
||||
|
||||
return cache()->rememberForever(
|
||||
$slug,
|
||||
fn () => new UserSubscription($user)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class SubscriptionResumeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Resume Subscription
|
||||
*/
|
||||
public function __invoke(): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
if (is_demo_account($user->email)) {
|
||||
return response('Done.', 204);
|
||||
}
|
||||
|
||||
// Resume subscription
|
||||
$user->subscription('main')->resume();
|
||||
|
||||
// Forget user subscription
|
||||
Cache::forget("subscription-user-{$user->id}");
|
||||
|
||||
return response('Done.', 204);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
use Domain\Teams\Requests\StoreUpgradeAccountRequest;
|
||||
|
||||
/**
|
||||
* Upgrade account to subscription
|
||||
*/
|
||||
class SubscriptionUpgradeController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
public StripeService $stripe,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(StoreUpgradeAccountRequest $request): Response
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Check if is demo
|
||||
if (is_demo_account($user->email)) {
|
||||
return response('Done.', 204);
|
||||
}
|
||||
|
||||
// Forget user subscription
|
||||
Cache::forget("subscription-user-{$user->id}");
|
||||
|
||||
// Get requested plan
|
||||
$plan = $this->stripe->getPlan(
|
||||
$request->input('plan.data.id')
|
||||
);
|
||||
|
||||
// Set user billing
|
||||
$user->setBilling(
|
||||
$request->input('billing')
|
||||
);
|
||||
|
||||
// Update stripe customer billing info
|
||||
$this->stripe->updateCustomerDetails($user);
|
||||
|
||||
// Make subscription
|
||||
$this->stripe->createOrReplaceSubscription($request, $user);
|
||||
|
||||
// Update user storage limit
|
||||
$user
|
||||
->settings()
|
||||
->update([
|
||||
'storage_capacity' => $plan['product']['metadata']['capacity'],
|
||||
]);
|
||||
|
||||
return response('Done.', 204);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreUpgradeAccountRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
// Billings
|
||||
'billing' => 'required|array',
|
||||
'billing.billing_address' => 'required|string',
|
||||
'billing.billing_city' => 'required|string',
|
||||
'billing.billing_country' => 'required|string',
|
||||
'billing.billing_name' => 'required|string',
|
||||
'billing.billing_phone_number' => 'required|string',
|
||||
'billing.billing_postal_code' => 'required|string',
|
||||
'billing.billing_state' => 'required|string',
|
||||
|
||||
// Payment
|
||||
'payment' => 'required|array',
|
||||
'payment.type' => 'required|string',
|
||||
'payment.meta' => 'required|sometimes|array',
|
||||
'payment.meta.pm' => 'required|sometimes|string',
|
||||
|
||||
// Plan
|
||||
'plan.data' => 'required|array',
|
||||
'plan.data.attributes' => 'required|array',
|
||||
'plan.data.attributes.capacity' => 'required|digits_between:1,9',
|
||||
'plan.data.attributes.capacity_formatted' => 'required|string',
|
||||
'plan.data.attributes.currency' => 'required|string',
|
||||
'plan.data.attributes.description' => 'sometimes|string|nullable',
|
||||
'plan.data.attributes.name' => 'required|string',
|
||||
'plan.data.attributes.price' => 'required|string',
|
||||
'plan.data.id' => 'required|string',
|
||||
'plan.data.type' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,411 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Services;
|
||||
|
||||
use Stripe;
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Cashier\Cashier;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Laravel\Cashier\Exceptions\IncompletePayment;
|
||||
use Laravel\Cashier\Exceptions\PaymentActionRequired;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class StripeService
|
||||
{
|
||||
private \Cartalyst\Stripe\Stripe $stripe;
|
||||
|
||||
/**
|
||||
* Stripe Service constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->stripe = Stripe::make(config('cashier.secret'), '2020-03-02');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setup intent
|
||||
*
|
||||
* @param $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSetupIntent($user)
|
||||
{
|
||||
// Create stripe customer if not exist
|
||||
$user->createOrGetStripeCustomer();
|
||||
|
||||
// Return setup intent
|
||||
return $user->createSetupIntent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax rate ids
|
||||
* @return array
|
||||
*/
|
||||
public function getTaxRates()
|
||||
{
|
||||
return $this->stripe
|
||||
->taxRates()
|
||||
->all()['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plan tax rates
|
||||
*
|
||||
* @param $amount
|
||||
* @return array
|
||||
*/
|
||||
public function get_tax_rates($amount): array
|
||||
{
|
||||
$rates_public = [];
|
||||
|
||||
foreach ($this->getTaxRates() as $rate) {
|
||||
// Continue when is not active
|
||||
if (! $rate['active']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate tax
|
||||
$tax = $amount * ($rate['percentage'] / 100);
|
||||
|
||||
array_push($rates_public, [
|
||||
'id' => $rate['id'],
|
||||
'active' => $rate['active'],
|
||||
'country' => $rate['country'],
|
||||
'percentage' => $rate['percentage'],
|
||||
'plan_price_formatted' => Cashier::formatAmount(round($amount + $tax)),
|
||||
]);
|
||||
}
|
||||
|
||||
return $rates_public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default payment option or set new default payment
|
||||
*
|
||||
* @param $request
|
||||
* @param $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOrSetDefaultPaymentMethod($request, $user)
|
||||
{
|
||||
// Check payment method
|
||||
if (! $request->has('payment.meta.pm') && $user->hasDefaultPaymentMethod()) {
|
||||
// Get default payment
|
||||
return $user->defaultPaymentMethod()->paymentMethod;
|
||||
}
|
||||
|
||||
// Clear cached payment methods
|
||||
cache_forget_many([
|
||||
'payment-methods-user-' . $user->id,
|
||||
'default-payment-methods-user-' . $user->id,
|
||||
]);
|
||||
|
||||
if ($request->has('payment.meta.pm') && $user->hasDefaultPaymentMethod()) {
|
||||
// Set new payment
|
||||
return $user->addPaymentMethod($request->input('payment.meta.pm'))->paymentMethod;
|
||||
} elseif ($request->has('payment.meta.pm') && ! $user->hasDefaultPaymentMethod()) {
|
||||
// Set new payment
|
||||
return $user->updateDefaultPaymentMethod($request->input('payment.meta.pm'))->paymentMethod;
|
||||
}
|
||||
|
||||
throw new HttpException(400, 'Something went wrong.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new payment method
|
||||
*
|
||||
* @param $request
|
||||
* @param $user
|
||||
*/
|
||||
public function registerNewPaymentMethod($request, $user): void
|
||||
{
|
||||
// Clear cached payment methods
|
||||
cache_forget_many([
|
||||
'payment-methods-user-' . $user->id,
|
||||
'default-payment-methods-user-' . $user->id,
|
||||
]);
|
||||
|
||||
// Set new payment method
|
||||
$user->addPaymentMethod($request->token)->paymentMethod;
|
||||
|
||||
// Set new default payment
|
||||
if ($request->default) {
|
||||
$user->updateDefaultPaymentMethod($request->token)->paymentMethod;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new subscription or replace by new subscription
|
||||
*
|
||||
* @param $request
|
||||
* @param $user
|
||||
*/
|
||||
public function createOrReplaceSubscription($request, $user): void
|
||||
{
|
||||
try {
|
||||
// Get payment method
|
||||
$paymentMethod = $this->getOrSetDefaultPaymentMethod($request, $user);
|
||||
|
||||
// Check if user have subscription
|
||||
if ($user->subscribed('main')) {
|
||||
// Change subscription plan
|
||||
$user->subscription('main')->skipTrial()->swap($request->input('plan.data.id'));
|
||||
} else {
|
||||
// Create subscription
|
||||
$user->newSubscription('main', $request->input('plan.data.id'))->create($paymentMethod);
|
||||
}
|
||||
} catch (IncompletePayment $exception) {
|
||||
if ($exception instanceof PaymentActionRequired) {
|
||||
$cashier_route = route('cashier.payment', [$exception->payment->id, 'redirect' => url('/settings/subscription')]);
|
||||
|
||||
throw new HttpException(402, $cashier_route);
|
||||
}
|
||||
|
||||
throw new HttpException(400, $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update customer details
|
||||
*
|
||||
* @param $user
|
||||
*/
|
||||
public function updateCustomerDetails($user)
|
||||
{
|
||||
$user->updateStripeCustomer([
|
||||
'name' => $user->settings->name,
|
||||
'phone' => $user->settings->phone_number,
|
||||
'address' => [
|
||||
'line1' => $user->settings->address,
|
||||
'city' => $user->settings->city,
|
||||
'country' => $user->settings->country,
|
||||
'postal_code' => $user->settings->postal_code,
|
||||
'state' => $user->settings->state,
|
||||
],
|
||||
'preferred_locales' => [
|
||||
$user->settings->country, 'en',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all plans
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPlans()
|
||||
{
|
||||
// Get stripe plans
|
||||
$stripe_plans = $this->stripe->plans()->all([
|
||||
'limit' => 100,
|
||||
]);
|
||||
|
||||
// Plans container
|
||||
$plans = [];
|
||||
|
||||
foreach ($stripe_plans['data'] as $plan) {
|
||||
// Get stripe product
|
||||
$product = $this->stripe->products()->find($plan['product']);
|
||||
|
||||
// Push data to $plan container
|
||||
if ($product['active'] && isset($product['metadata']['capacity'])) {
|
||||
array_push($plans, [
|
||||
'plan' => $plan,
|
||||
'product' => $product,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all active plans
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActivePlans()
|
||||
{
|
||||
// Get stripe plans
|
||||
$stripe_plans = $this->stripe->plans()->all([
|
||||
'limit' => 100,
|
||||
]);
|
||||
|
||||
// Plans container
|
||||
$plans = [];
|
||||
|
||||
foreach ($stripe_plans['data'] as $plan) {
|
||||
if ($plan['active']) {
|
||||
// Get stripe product
|
||||
$product = $this->stripe->products()->find($plan['product']);
|
||||
|
||||
// Push data to $plan container
|
||||
if ($product['active'] && isset($product['metadata']['capacity'])) {
|
||||
array_push($plans, [
|
||||
'plan' => $plan,
|
||||
'product' => $product,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plan details
|
||||
*
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPlan($id)
|
||||
{
|
||||
if (Cache::has("plan-$id")) {
|
||||
return Cache::get("plan-$id");
|
||||
}
|
||||
|
||||
return Cache::rememberForever("plan-$id", function () use ($id) {
|
||||
$plan = $this->stripe->plans()->find($id);
|
||||
$product = $this->stripe->products()->find($plan['product']);
|
||||
|
||||
return [
|
||||
'plan' => $plan,
|
||||
'product' => $product,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plan
|
||||
*
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function createPlan($data)
|
||||
{
|
||||
if ($data instanceof Request) {
|
||||
$plan = [
|
||||
'name' => $data->input('attributes.name'),
|
||||
'description' => $data->input('attributes.description'),
|
||||
'price' => $data->input('attributes.price'),
|
||||
'capacity' => $data->input('attributes.capacity'),
|
||||
];
|
||||
} else {
|
||||
$plan = [
|
||||
'name' => $data['attributes']['name'],
|
||||
'description' => $data['attributes']['description'],
|
||||
'price' => $data['attributes']['price'],
|
||||
'capacity' => $data['attributes']['capacity'],
|
||||
];
|
||||
}
|
||||
|
||||
$product = $this->stripe->products()->create([
|
||||
'name' => $plan['name'],
|
||||
'description' => $plan['description'],
|
||||
'metadata' => [
|
||||
'capacity' => $plan['capacity'],
|
||||
],
|
||||
]);
|
||||
|
||||
$plan = $this->stripe->plans()->create([
|
||||
'id' => Str::slug($plan['name']),
|
||||
'amount' => $plan['price'],
|
||||
'currency' => config('cashier.currency'),
|
||||
'interval' => 'month',
|
||||
'product' => $product['id'],
|
||||
]);
|
||||
|
||||
return compact('plan', 'product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plan
|
||||
*
|
||||
* @param $request
|
||||
* @param $id
|
||||
*/
|
||||
public function updatePlan($request, $id)
|
||||
{
|
||||
$plan_colls = ['is_active', 'price'];
|
||||
$product_colls = ['name', 'description', 'capacity'];
|
||||
|
||||
$plan = $this->stripe->plans()->find($id);
|
||||
|
||||
// Update product
|
||||
if (in_array($request->name, $product_colls)) {
|
||||
if ($request->name === 'capacity') {
|
||||
$this->stripe->products()->update($plan['product'], ['metadata' => ['capacity' => $request->value]]);
|
||||
}
|
||||
|
||||
if ($request->name === 'name') {
|
||||
$this->stripe->products()->update($plan['product'], ['name' => $request->value]);
|
||||
}
|
||||
|
||||
if ($request->name === 'description') {
|
||||
$this->stripe->products()->update($plan['product'], ['description' => $request->value]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update plan
|
||||
if (in_array($request->name, $plan_colls)) {
|
||||
if ($request->name === 'is_active') {
|
||||
$this->stripe->plans()->update($id, ['active' => $request->value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete plan
|
||||
*
|
||||
* @param $slug
|
||||
*/
|
||||
public function deletePlan($slug)
|
||||
{
|
||||
$this
|
||||
->stripe
|
||||
->plans()
|
||||
->delete($slug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user invoices
|
||||
*
|
||||
* @param $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserInvoices($user)
|
||||
{
|
||||
return $user
|
||||
->invoices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user invoice by id
|
||||
*
|
||||
* @param $customer
|
||||
* @param $id
|
||||
* @return \Laravel\Cashier\Invoice|null
|
||||
*/
|
||||
public function getUserInvoice($customer, $id)
|
||||
{
|
||||
return User::whereStripeId($customer)
|
||||
->firstOrFail()
|
||||
->findInvoice($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all invoices
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInvoices()
|
||||
{
|
||||
return $this
|
||||
->stripe
|
||||
->invoices()
|
||||
->all([
|
||||
'limit' => 20,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Traits;
|
||||
|
||||
use App\Users\Models\UserSettings;
|
||||
use Domain\Subscriptions\Services\StripeService;
|
||||
|
||||
trait Subscription
|
||||
{
|
||||
/**
|
||||
* Get tax rate id for user
|
||||
*/
|
||||
public function userTaxRates(): array
|
||||
{
|
||||
// Get tax rates
|
||||
$rates = collect(
|
||||
resolve(StripeService::class)->getTaxRates()
|
||||
);
|
||||
|
||||
// Find tax rate
|
||||
$user_tax_rate = $rates->first(fn ($item) => $item['country'] === $this->settings->country && $item['active']);
|
||||
|
||||
return $user_tax_rate ? [$user_tax_rate['id']] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user billing info into user settings table
|
||||
*/
|
||||
public function setBilling($billing): UserSettings
|
||||
{
|
||||
$this->settings()->update([
|
||||
'address' => $billing['billing_address'],
|
||||
'city' => $billing['billing_city'],
|
||||
'country' => $billing['billing_country'],
|
||||
'name' => $billing['billing_name'],
|
||||
'phone_number' => $billing['billing_phone_number'],
|
||||
'postal_code' => $billing['billing_postal_code'],
|
||||
'state' => $billing['billing_state'],
|
||||
]);
|
||||
|
||||
return $this->settings;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use Domain\Zip\Actions\ZipAction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Traffic\Actions\RecordDownloadAction;
|
||||
use Domain\Zip\Actions\GetItemsListFromUrlParamAction;
|
||||
use ZipStream\ZipStream;
|
||||
|
||||
class ZipController extends Controller
|
||||
{
|
||||
@@ -18,7 +19,7 @@ class ZipController extends Controller
|
||||
|
||||
public function __invoke(
|
||||
Request $request,
|
||||
): \ZipStream\ZipStream {
|
||||
): ZipStream {
|
||||
// Get list of folders and files from requested url parameter
|
||||
list($folders, $files) = ($this->getItemsListFromUrlParam)(auth()->id());
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ class UserAccountTest extends TestCase
|
||||
Storage::disk('local')
|
||||
->assertExists('files/' . User::first()->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* todo: finish test
|
||||
*/
|
||||
@@ -140,9 +141,6 @@ class UserAccountTest extends TestCase
|
||||
'type' => 'user',
|
||||
'attributes' => [
|
||||
'storage_capacity' => '5',
|
||||
'subscription' => false,
|
||||
'incomplete_payment' => null,
|
||||
'stripe_customer' => false,
|
||||
'email' => $user->email,
|
||||
'role' => $user->role,
|
||||
'two_factor_authentication' => false,
|
||||
|
||||
@@ -59,7 +59,7 @@ class AdminTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* todo: complete test
|
||||
*/
|
||||
public function it_get_non_existed_user_subscription()
|
||||
{
|
||||
|
||||
@@ -27,14 +27,6 @@ class DashboardTest extends TestCase
|
||||
'value' => 'Regular',
|
||||
]);
|
||||
|
||||
DB::table('subscriptions')
|
||||
->insert([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'main',
|
||||
'stripe_id' => 'sub_Hp4jgdIpPDDWXw',
|
||||
'stripe_status' => 'active',
|
||||
]);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->getJson('/api/admin/dashboard')
|
||||
@@ -44,7 +36,6 @@ class DashboardTest extends TestCase
|
||||
'app_version' => config('vuefilemanager.version'),
|
||||
'total_users' => 1,
|
||||
'total_used_space' => '2.00MB',
|
||||
'total_premium_users' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Invoices;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Users\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
class UserInvoicesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_user_invoices()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$this->getJson('/api/user/subscription/invoices')
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'customer' => $this->user['stripe_id'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Plans;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
class AdminPlansTest extends TestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_single_plan_from_admin()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson('/api/admin/plans/' . $this->plan['data']['id'])
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_create_single_plan_from_admin()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$plan_name = 'test-plan-' . Str::random(16);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->postJson('/api/admin/plans', [
|
||||
'type' => 'plan',
|
||||
'attributes' => [
|
||||
'name' => $plan_name,
|
||||
'price' => (string) rand(1, 99),
|
||||
'description' => 'Some random description',
|
||||
'capacity' => rand(1, 999),
|
||||
],
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'name' => $plan_name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_update_single_plan_from_admin()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$plan_name = 'test-plan-' . Str::random(16);
|
||||
|
||||
$this->postJson('/api/admin/plans', [
|
||||
'type' => 'plan',
|
||||
'attributes' => [
|
||||
'name' => $plan_name,
|
||||
'price' => (string) rand(1, 99),
|
||||
'description' => 'Some random description',
|
||||
'capacity' => rand(1, 999),
|
||||
],
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'name' => $plan_name,
|
||||
]);
|
||||
|
||||
$this->patchJson('/api/admin/plans/' . strtolower($plan_name), [
|
||||
'name' => 'description',
|
||||
'value' => 'updated description',
|
||||
])->assertStatus(201);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_subscribers_from_plan_from_admin()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson('/api/admin/plans/' . $this->plan['data']['id'] . '/subscribers')
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'id' => $user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_all_invoices_from_admin()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson('/api/admin/invoices')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_single_user_invoice_page_from_admin()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
$invoices = $this
|
||||
->actingAs($user)
|
||||
->getJson('/api/user/subscription/invoices')
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'customer' => $this->user['stripe_id'],
|
||||
]);
|
||||
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$invoice_id = json_decode($invoices->content(), true)['data'][0]['data']['id'];
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->get("/invoice/{$this->user['stripe_id']}/$invoice_id")
|
||||
->assertStatus(200)
|
||||
->assertSee('Invoice');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_user_invoices_from_admin()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson("/api/admin/users/$user->id/invoices")
|
||||
->assertStatus(200)
|
||||
->assertJsonFragment([
|
||||
'customer' => $this->user['stripe_id'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_all_plans_from_admin()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson('/api/admin/plans')
|
||||
->assertStatus(200);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Plans;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
class PlansTest extends TestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_all_plans_for_index_page()
|
||||
{
|
||||
$this->getJson('/api/pricing')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_delete_single_plan()
|
||||
{
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
Sanctum::actingAs($admin);
|
||||
|
||||
$plan_name = 'test-plan-' . Str::random(16);
|
||||
|
||||
$this->postJson('/api/admin/plans', [
|
||||
'type' => 'plan',
|
||||
'attributes' => [
|
||||
'name' => $plan_name,
|
||||
'price' => (string) rand(1, 99),
|
||||
'description' => 'Some random description',
|
||||
'capacity' => rand(1, 999),
|
||||
],
|
||||
])
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'name' => $plan_name,
|
||||
]);
|
||||
|
||||
$this->deleteJson('/api/admin/plans/' . strtolower($plan_name))
|
||||
->assertStatus(204);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Plans;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SetupWizardPlansTest extends TestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_store_stripe_plans_via_setup_wizard()
|
||||
{
|
||||
$this->postJson('/api/setup/stripe-plans', [
|
||||
'plans' => [
|
||||
[
|
||||
'type' => 'plan',
|
||||
'attributes' => [
|
||||
'name' => 'test-plan-' . Str::random(),
|
||||
'price' => (string) rand(1, 99),
|
||||
'description' => 'Some random description',
|
||||
'capacity' => rand(1, 999),
|
||||
],
|
||||
],
|
||||
[
|
||||
'type' => 'plan',
|
||||
'attributes' => [
|
||||
'name' => 'test-plan-' . Str::random(),
|
||||
'price' => (string) rand(1, 99),
|
||||
'description' => 'Some random description',
|
||||
'capacity' => rand(1, 999),
|
||||
],
|
||||
],
|
||||
],
|
||||
])->assertStatus(204);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ class SettingsTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* TODO: complete test
|
||||
*/
|
||||
public function it_set_stripe()
|
||||
{
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Subscriptions;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Users\Models\User;
|
||||
|
||||
class AdminSubscriptionTest extends TestCase
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_user_subscription_from_admin()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$admin = User::factory(User::class)
|
||||
->create(['role' => 'admin']);
|
||||
|
||||
$this
|
||||
->actingAs($admin)
|
||||
->getJson("/api/admin/users/$user->id/subscription")
|
||||
->assertStatus(200)
|
||||
->assertExactJson([
|
||||
'data' => [
|
||||
'id' => 'business-pack',
|
||||
'type' => 'subscription',
|
||||
'attributes' => [
|
||||
'incomplete' => false,
|
||||
'active' => true,
|
||||
'canceled' => false,
|
||||
'name' => 'Business Packs',
|
||||
'capacity' => 1000,
|
||||
'capacity_formatted' => '1TB',
|
||||
'slug' => 'business-pack',
|
||||
'canceled_at' => format_date(now(), '%d. %B. %Y'),
|
||||
'created_at' => format_date(now(), '%d. %B. %Y'),
|
||||
'ends_at' => format_date(now()->addMonth(), '%d. %B. %Y'),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
<?php
|
||||
namespace Tests\Domain\Subscriptions;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Users\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
class SubscriptionTest extends TestCase
|
||||
{
|
||||
private User $user;
|
||||
|
||||
private array $plan;
|
||||
|
||||
private array $billing;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Define test user
|
||||
$this->user = [
|
||||
'email' => 'howdy@hi5ve.digital',
|
||||
'stripe_id' => 'cus_HgbhvNCbSwV8Qg',
|
||||
'card_brand' => 'visa',
|
||||
'card_last_four' => 4242,
|
||||
];
|
||||
|
||||
// Define test plan to subscribe
|
||||
$this->plan = [
|
||||
'data' => [
|
||||
'id' => 'business-pack',
|
||||
'type' => 'plans',
|
||||
'attributes' => [
|
||||
'name' => 'Business Packs',
|
||||
'description' => 'When your business start grow up.',
|
||||
'price' => '$44.99',
|
||||
'capacity' => 1000,
|
||||
'capacity_formatted' => '1TB',
|
||||
'currency' => 'USD',
|
||||
'tax_rates' => [],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Define test billing to subscribe
|
||||
$this->billing = [
|
||||
'billing_address' => '2794 Alfreda Mount Suite 467 East Crystalberg',
|
||||
'billing_city' => 'Christianfort',
|
||||
'billing_country' => 'SK',
|
||||
'billing_name' => 'Heidi Romaguera PhD',
|
||||
'billing_phone_number' => '+421',
|
||||
'billing_postal_code' => '59445',
|
||||
'billing_state' => 'SK',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_setup_intent()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create();
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->getJson('/api/user/subscription/setup-intent')
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment([
|
||||
'object' => 'setup_intent',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('users', [
|
||||
'stripe_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_upgrade_plan()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$this->assertDatabaseHas('subscriptions', [
|
||||
'stripe_status' => 'active',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('user_settings', [
|
||||
'storage_capacity' => 1000,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_cancel_subscription()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$this->postJson('/api/user/subscription/cancel')
|
||||
->assertStatus(204);
|
||||
|
||||
$this->assertDatabaseMissing('subscriptions', [
|
||||
'ends_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_resume_subscription()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$this->postJson('/api/user/subscription/cancel')
|
||||
->assertStatus(204);
|
||||
|
||||
$this->postJson('/api/user/subscription/resume')
|
||||
->assertStatus(204);
|
||||
|
||||
$this->assertDatabaseHas('subscriptions', [
|
||||
'ends_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function it_get_user_subscription_details()
|
||||
{
|
||||
$user = User::factory(User::class)
|
||||
->create($this->user);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->postJson('/api/user/subscription/upgrade', [
|
||||
'billing' => $this->billing,
|
||||
'plan' => $this->plan,
|
||||
'payment' => [
|
||||
'type' => 'stripe',
|
||||
],
|
||||
])->assertStatus(204);
|
||||
|
||||
$this->getJson('/api/user/subscription')
|
||||
->assertStatus(200)
|
||||
->assertExactJson([
|
||||
'data' => [
|
||||
'id' => 'business-pack',
|
||||
'type' => 'subscription',
|
||||
'attributes' => [
|
||||
'incomplete' => false,
|
||||
'active' => true,
|
||||
'canceled' => false,
|
||||
'name' => 'Business Packs',
|
||||
'capacity' => 1000,
|
||||
'capacity_formatted' => '1TB',
|
||||
'slug' => 'business-pack',
|
||||
'canceled_at' => format_date(now(), '%d. %B. %Y'),
|
||||
'created_at' => format_date(now(), '%d. %B. %Y'),
|
||||
'ends_at' => format_date(now()->addMonth(), '%d. %B. %Y'),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user