90
common/Billing/Products/Actions/CrupdateProduct.php
Executable file
90
common/Billing/Products/Actions/CrupdateProduct.php
Executable file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Billing\Products\Actions;
|
||||
|
||||
use Common\Auth\Permissions\Traits\SyncsPermissions;
|
||||
use Common\Billing\Gateways\Actions\SyncProductOnEnabledGateways;
|
||||
use Common\Billing\Models\Price;
|
||||
use Common\Billing\Models\Product;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CrupdateProduct
|
||||
{
|
||||
use SyncsPermissions;
|
||||
|
||||
public function execute(
|
||||
array $data,
|
||||
Product $originalProduct = null,
|
||||
$syncProduct = true,
|
||||
): Product {
|
||||
$product =
|
||||
$originalProduct?->load('prices') ?:
|
||||
app(Product::class)->newModelInstance([
|
||||
'uuid' => Str::uuid(),
|
||||
]);
|
||||
|
||||
$newData = [
|
||||
'name' => $data['name'],
|
||||
'description' => $data['description'] ?? null,
|
||||
'hidden' => $data['hidden'] ?? false,
|
||||
'free' => $data['free'] ?? false,
|
||||
'recommended' => $data['recommended'] ?? false,
|
||||
'position' => $data['position'] ?? 0,
|
||||
'available_space' => $data['available_space'] ?? null,
|
||||
'feature_list' => $data['feature_list'] ?? [],
|
||||
];
|
||||
|
||||
$product = $product->fill($newData);
|
||||
$product->save();
|
||||
|
||||
if (
|
||||
array_key_exists('permissions', $data) &&
|
||||
is_array($data['permissions'])
|
||||
) {
|
||||
$this->syncPermissions($product, $data['permissions']);
|
||||
}
|
||||
|
||||
$prices = Arr::get($data, 'prices') ?? [];
|
||||
|
||||
// delete old prices
|
||||
$originalProduct?->prices->each(function (Price $price) use ($prices) {
|
||||
if (
|
||||
!Arr::first(
|
||||
$prices,
|
||||
fn($p) => isset($p['id']) && $p['id'] === $price->id,
|
||||
)
|
||||
) {
|
||||
$price->delete();
|
||||
}
|
||||
});
|
||||
|
||||
// update existing prices and create new ones
|
||||
foreach ($prices as $price) {
|
||||
$isExistingPrice = isset($price['id']);
|
||||
$pricePayload = [
|
||||
'amount' => $price['amount'],
|
||||
'interval_count' => $price['interval_count'],
|
||||
'interval' => $price['interval'],
|
||||
'currency' => $price['currency'],
|
||||
];
|
||||
|
||||
// existing prices can't be updated for existing products, if it has active subscribers. We can add new price though.
|
||||
if ($isExistingPrice && $originalProduct?->subscriptions_count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isExistingPrice) {
|
||||
Price::where('id', $price['id'])->update($pricePayload);
|
||||
} else {
|
||||
$product->prices()->create($pricePayload);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$product->free && $syncProduct) {
|
||||
app(SyncProductOnEnabledGateways::class)->execute($product);
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
}
|
||||
121
common/Billing/Products/ProductsController.php
Executable file
121
common/Billing/Products/ProductsController.php
Executable file
@@ -0,0 +1,121 @@
|
||||
<?php namespace Common\Billing\Products;
|
||||
|
||||
use Common\Billing\Gateways\Paypal\Paypal;
|
||||
use Common\Billing\Gateways\Stripe\Stripe;
|
||||
use Common\Billing\Models\Product;
|
||||
use Common\Billing\Products\Actions\CrupdateProduct;
|
||||
use Common\Core\BaseController;
|
||||
use Common\Database\Datasource\Datasource;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ProductsController extends BaseController
|
||||
{
|
||||
public function __construct(
|
||||
protected Stripe $stripe,
|
||||
protected Paypal $paypal
|
||||
) {
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->authorize('index', Product::class);
|
||||
|
||||
$dataSource = new Datasource(
|
||||
Product::with(['permissions', 'prices']),
|
||||
request()->all(),
|
||||
);
|
||||
$dataSource->order = ['col' => 'position', 'dir' => 'asc'];
|
||||
|
||||
return $this->success(['pagination' => $dataSource->paginate()]);
|
||||
}
|
||||
|
||||
public function show(Product $product)
|
||||
{
|
||||
$this->authorize('show', $product);
|
||||
|
||||
$product->load([
|
||||
'permissions',
|
||||
'prices' => fn(HasMany $builder) => $builder->withCount(
|
||||
'subscriptions',
|
||||
),
|
||||
]);
|
||||
|
||||
return ['product' => $product];
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$this->authorize('store', Product::class);
|
||||
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|string|max:250',
|
||||
'permissions' => 'array',
|
||||
'recommended' => 'boolean',
|
||||
'position' => 'integer',
|
||||
'available_space' => 'nullable|integer|min:1',
|
||||
'prices' => ['array', Rule::requiredIf(!request('free'))],
|
||||
'prices.*.currency' => 'required|string|max:255',
|
||||
'prices.*.interval' => 'string|max:255',
|
||||
'prices.*.amount' => 'min:1',
|
||||
]);
|
||||
|
||||
$plan = app(CrupdateProduct::class)->execute(request()->all());
|
||||
|
||||
return $this->success(['plan' => $plan]);
|
||||
}
|
||||
|
||||
public function update(Product $product)
|
||||
{
|
||||
$this->authorize('update', $product);
|
||||
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|string|max:250',
|
||||
'permissions' => 'array',
|
||||
'recommended' => 'boolean',
|
||||
'prices' => ['array', Rule::requiredIf(!request('free'))],
|
||||
'prices.*.currency' => 'required|string|max:255',
|
||||
'prices.*.interval' => 'string|max:255',
|
||||
'prices.*.amount' => 'min:1',
|
||||
]);
|
||||
|
||||
$product = app(CrupdateProduct::class)->execute(
|
||||
request()->all(),
|
||||
$product,
|
||||
);
|
||||
|
||||
return $this->success(['product' => $product]);
|
||||
}
|
||||
|
||||
public function destroy(Product $product): Response|JsonResponse
|
||||
{
|
||||
$this->authorize('destroy', $product);
|
||||
|
||||
if ($product->subscriptions_count) {
|
||||
return $this->error(
|
||||
__(
|
||||
"Could not delete ':plan', because it has active subscriptions.",
|
||||
['plan' => $product->name],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->stripe->isEnabled()) {
|
||||
$this->stripe->deletePlan($product);
|
||||
}
|
||||
if ($this->paypal->isEnabled()) {
|
||||
$this->paypal->deletePlan($product);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
|
||||
$product->delete();
|
||||
|
||||
return $this->success();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user