removed old subscription backend

This commit is contained in:
Čarodej
2021-11-19 16:18:27 +01:00
parent 34eaf3e411
commit f402141bfb
50 changed files with 13 additions and 2287 deletions
@@ -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;
}
}
+2 -1
View File
@@ -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());