feat: Implement client-facing service management API with UUID for services and bulk actions for product services.
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Database\UniqueConstraintViolationException;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
@@ -34,6 +36,18 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// Duplicate constraint
|
||||
$this->renderable(function (QueryException $e, $request) {
|
||||
|
||||
if ($e->errorInfo[1] == 1062) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Dữ liệu đã tồn tại'
|
||||
], 422);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$this->renderable(function (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e, $request) {
|
||||
if (!$request->expectsJson() && !$request->is('v1/*') && !$request->is('api/*')) {
|
||||
return null;
|
||||
|
||||
@@ -78,10 +78,10 @@ class ProductCategoryController extends Controller
|
||||
|
||||
$validated['slug'] = Str::slug($validated['name']);
|
||||
|
||||
// Ensure unique slug
|
||||
// Ensure unique slug (include soft-deleted to avoid DB unique constraint violation)
|
||||
$originalSlug = $validated['slug'];
|
||||
$count = 1;
|
||||
while (ProductCategories::where('slug', $validated['slug'])->exists()) {
|
||||
while (ProductCategories::withTrashed()->where('slug', $validated['slug'])->exists()) {
|
||||
$validated['slug'] = "{$originalSlug}-{$count}";
|
||||
$count++;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class ProductCategoryController extends Controller
|
||||
$slug = Str::slug($validated['name']);
|
||||
$originalSlug = $slug;
|
||||
$count = 1;
|
||||
while (ProductCategories::where('slug', $slug)->where('id', '!=', $id)->exists()) {
|
||||
while (ProductCategories::withTrashed()->where('slug', $slug)->where('id', '!=', $id)->exists()) {
|
||||
$slug = "{$originalSlug}-{$count}";
|
||||
$count++;
|
||||
}
|
||||
@@ -153,4 +153,118 @@ class ProductCategoryController extends Controller
|
||||
'message' => 'Xoá nhóm sản phẩm thành công.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function trashed(): JsonResponse
|
||||
{
|
||||
$items = ProductCategories::onlyTrashed()
|
||||
->withCount('products')
|
||||
->orderBy('deleted_at', 'desc')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => ProductCategoryResource::collection($items),
|
||||
]);
|
||||
}
|
||||
|
||||
public function restore(int $id): JsonResponse
|
||||
{
|
||||
$category = ProductCategories::onlyTrashed()->find($id);
|
||||
|
||||
if (!$category) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy nhóm trong thùng rác.'], 404);
|
||||
}
|
||||
|
||||
$category->restore();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Khôi phục nhóm sản phẩm thành công.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function forceDelete(int $id): JsonResponse
|
||||
{
|
||||
$category = ProductCategories::onlyTrashed()->find($id);
|
||||
|
||||
if (!$category) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy nhóm trong thùng rác.'], 404);
|
||||
}
|
||||
|
||||
$category->forceDelete();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Xoá vĩnh viễn nhóm sản phẩm thành công.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkUpdateStatus(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'ids' => 'required|array',
|
||||
'ids.*' => 'integer',
|
||||
'is_active' => 'required|boolean',
|
||||
]);
|
||||
|
||||
$updated = ProductCategories::whereIn('id', $validated['ids'])
|
||||
->update(['is_active' => $validated['is_active']]);
|
||||
|
||||
$label = $validated['is_active'] ? 'kích hoạt' : 'ẩn';
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã {$label} {$updated} nhóm sản phẩm.",
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkDestroy(Request $request): JsonResponse
|
||||
{
|
||||
$ids = $request->validate(['ids' => 'required|array', 'ids.*' => 'integer'])['ids'];
|
||||
|
||||
$blocked = ProductCategories::withCount('products')
|
||||
->whereIn('id', $ids)
|
||||
->get()
|
||||
->filter(fn ($c) => $c->products_count > 0);
|
||||
|
||||
if ($blocked->isNotEmpty()) {
|
||||
$names = $blocked->pluck('name')->implode(', ');
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => "Không thể xoá các nhóm đang chứa sản phẩm: {$names}.",
|
||||
], 422);
|
||||
}
|
||||
|
||||
$deleted = ProductCategories::whereIn('id', $ids)->delete();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã xoá {$deleted} nhóm sản phẩm.",
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkRestore(Request $request): JsonResponse
|
||||
{
|
||||
$ids = $request->validate(['ids' => 'required|array', 'ids.*' => 'integer'])['ids'];
|
||||
|
||||
$restored = ProductCategories::onlyTrashed()->whereIn('id', $ids)->restore();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã khôi phục {$restored} nhóm sản phẩm.",
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkForceDelete(Request $request): JsonResponse
|
||||
{
|
||||
$ids = $request->validate(['ids' => 'required|array', 'ids.*' => 'integer'])['ids'];
|
||||
|
||||
$count = ProductCategories::onlyTrashed()->whereIn('id', $ids)->count();
|
||||
ProductCategories::onlyTrashed()->whereIn('id', $ids)->forceDelete();
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => "Đã xoá vĩnh viễn {$count} nhóm sản phẩm.",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Client\Service;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\Client\Service\ServiceClientDetailResource;
|
||||
use \App\Http\Resources\Api\Client\Service\ServiceClientResource;
|
||||
use App\Repositories\Api\ServiceClient\ServiceClientRepository;
|
||||
use App\Services\Api\ServiceClient\ServiceClientService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
protected $serviceClientService;
|
||||
protected $serviceClientRepository;
|
||||
|
||||
public function __construct(
|
||||
ServiceClientService $serviceClientService,
|
||||
ServiceClientRepository $serviceClientRepository
|
||||
) {
|
||||
$this->serviceClientService = $serviceClientService;
|
||||
$this->serviceClientRepository = $serviceClientRepository;
|
||||
}
|
||||
|
||||
public function getService(Request $request)
|
||||
{
|
||||
$limit = $request->get('limit', 10);
|
||||
$services = $this->serviceClientService->getActiveServices($limit);
|
||||
|
||||
return ServiceClientResource::collection($services)->additional([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function getDetail(Request $request, string $uuid)
|
||||
{
|
||||
$service = $this->serviceClientService->getDetailService($uuid);
|
||||
|
||||
return (new ServiceClientDetailResource($service))->additional([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'page_type' => 'service',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -345,6 +345,74 @@ class OrderController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /v1/client/dich-vu/{uuid} — service detail by UUID
|
||||
*/
|
||||
public function getClientServiceDetail(Request $request, string $uuid): JsonResponse
|
||||
{
|
||||
try {
|
||||
$service = Service::query()
|
||||
->with(['product', 'addons', 'invoice', 'orderItem'])
|
||||
->where('uuid', $uuid)
|
||||
->where('customer_id', $request->user()->id)
|
||||
->first();
|
||||
|
||||
if (!$service) {
|
||||
return $this->notFound('Không tìm thấy dịch vụ.');
|
||||
}
|
||||
|
||||
$vmware = $service->vm_id
|
||||
? ModuleVmware::with(['ipAddress', 'os', 'vCenter'])->find((int) $service->vm_id)
|
||||
: null;
|
||||
|
||||
$data = [
|
||||
'id' => $service->id,
|
||||
'uuid' => $service->uuid,
|
||||
'service_name' => $service->product?->name ?? $service->server_name,
|
||||
'server_name' => $service->server_name,
|
||||
'product_type' => $service->product?->product_type,
|
||||
'billing_cycle' => $service->orderItem?->billing_cycle,
|
||||
'status' => $service->status,
|
||||
'status_text' => $service->status_label,
|
||||
'auto_renew' => (bool) $service->auto_renew,
|
||||
'started_at' => $this->isoDate($service->started_at),
|
||||
'expires_at' => $this->isoDate($service->expires_at),
|
||||
'note' => $service->note,
|
||||
'invoice_id' => $service->invoice_id,
|
||||
'invoice_number' => $service->invoice?->invoice_number,
|
||||
'product' => $service->product ? [
|
||||
'id' => $service->product->id,
|
||||
'uuid' => $service->product->uuid,
|
||||
'name' => $service->product->name,
|
||||
'product_type' => $service->product->product_type,
|
||||
'specs' => [
|
||||
'cpu' => $service->product->cpu,
|
||||
'ram' => $service->product->ram,
|
||||
'disk' => $service->product->disk,
|
||||
'bandwidth' => $service->product->bandwidth,
|
||||
],
|
||||
] : null,
|
||||
'addons' => $service->addons->map(fn($a) => [
|
||||
'type' => $a->addon_type,
|
||||
'value' => $a->addon_value,
|
||||
'price' => $a->price,
|
||||
])->all(),
|
||||
'vmware' => $vmware ? [
|
||||
'id' => $vmware->id,
|
||||
'name' => $vmware->name,
|
||||
'hostname' => $vmware->hostname,
|
||||
'ip_address' => $vmware->ipAddress?->ip,
|
||||
'os_name' => $vmware->os?->name,
|
||||
'status' => $vmware->status,
|
||||
] : null,
|
||||
];
|
||||
|
||||
return response()->json(['success' => true, 'data' => $data]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /v1/client/dich-vu/{id}/auto-renew — toggle auto-renewal on a service
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Models\OrderAddon;
|
||||
use App\Models\OrderItem;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductPricings;
|
||||
use App\Models\Service;
|
||||
use App\Repositories\Api\Service\ServiceRepository;
|
||||
use App\Services\Api\Service\ServiceService;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -190,6 +191,31 @@ class ServiceController extends Controller
|
||||
};
|
||||
}
|
||||
|
||||
public function getDetailServiceCustomer(Request $request, $uuid)
|
||||
{
|
||||
$service = Service::where('uuid', $uuid)->first();
|
||||
|
||||
if (!$service) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Dịch vụ không tồn tại'
|
||||
], 404);
|
||||
}
|
||||
|
||||
$service->load([
|
||||
'product.category',
|
||||
'orderItem.os.osGroup',
|
||||
'orderItem.pricing',
|
||||
'invoice',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Lấy dữ liệu thành công',
|
||||
'data' => new ServiceResource($service),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get addons for a specific product
|
||||
* GET /v1/products/{productId}/addons
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api\Client\Service;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ServiceClientDetailResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'uuid' => $this->uuid,
|
||||
'server_name' => $this->server_name,
|
||||
'status' => $this->status,
|
||||
'auto_renew' => $this->auto_renew,
|
||||
'started_at' => $this->started_at?->toISOString(),
|
||||
'expires_at' => $this->expires_at?->toISOString(),
|
||||
'os' => [
|
||||
'version' => $this->orderItem?->os?->version,
|
||||
'group' => $this->orderItem?->os?->os_group?->name,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api\Client\Service;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ServiceClientResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'uuid' => $this->uuid,
|
||||
'vm_id' => $this->vm_id,
|
||||
'status' => $this->status,
|
||||
'auto_renew' => $this->auto_renew,
|
||||
'started_at' => $this->started_at?->toISOString(),
|
||||
'expires_at' => $this->expires_at?->toISOString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -65,4 +65,9 @@ class Order extends Model
|
||||
{
|
||||
return $this->hasMany(ModuleVmware::class, 'order_id');
|
||||
}
|
||||
|
||||
public function vmWare()
|
||||
{
|
||||
return $this->hasMany(ModuleVmware::class, 'order_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\View\Components\Module\OsVersion;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
@@ -385,6 +385,12 @@ class RepositoryProvider extends ServiceProvider
|
||||
\App\Repositories\Api\Service\ServiceRepository::class
|
||||
);
|
||||
|
||||
// Service Client API
|
||||
$this->app->bind(
|
||||
\App\Repositories\Api\ServiceClient\ServiceClientRepositoryInterface::class,
|
||||
\App\Repositories\Api\ServiceClient\ServiceClientRepository::class
|
||||
);
|
||||
|
||||
// DNS Manager
|
||||
$this->app->bind(DnsManagerServerRepositoryInterface::class, DnsManagerServerRepository::class);
|
||||
$this->app->bind(DnsDomainRepositoryInterface::class, DnsDomainRepository::class);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories\Api\ServiceClient;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\Repositories\Api\BaseApiRepository;
|
||||
|
||||
class ServiceClientRepository extends BaseApiRepository implements ServiceClientRepositoryInterface
|
||||
{
|
||||
public function getModel()
|
||||
{
|
||||
return Service::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lấy danh sách sản phẩm đang hoạt động
|
||||
*/
|
||||
public function getActiveServices(int $limit = 10)
|
||||
{
|
||||
return $this->model
|
||||
->with(['orderItem' => fn($q) => $q->with('product')])
|
||||
->where('status', 'active')
|
||||
->orderBy('started_at', 'asc')
|
||||
->paginate($limit);
|
||||
}
|
||||
|
||||
public function findActiveBySlug(string $slug)
|
||||
{
|
||||
return $this->model
|
||||
->with(['osVersions.osGroup', 'category', 'pricings' => fn ($q) => $q->where('is_active', 1)])
|
||||
->where('slug', $slug)
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function getPricing(int $productId, string $billingCycle)
|
||||
{
|
||||
$pricing = $this->model->find($productId)
|
||||
->pricings()
|
||||
->where('billing_cycle', $billingCycle)
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
|
||||
return $pricing ? $pricing->price : null;
|
||||
}
|
||||
|
||||
public function getDetailService(string $uuid)
|
||||
{
|
||||
return $this->model
|
||||
->with(['orderItem.os.osGroup.host.datacenter.vCenter'])
|
||||
->where('uuid', $uuid)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories\Api\ServiceClient;
|
||||
|
||||
use App\Repositories\BaseRepositoryInterface;
|
||||
|
||||
interface ServiceClientRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Lấy danh sách sản phẩm đang hoạt động
|
||||
*/
|
||||
public function getActiveServices(int $limit = 10);
|
||||
|
||||
public function findActiveBySlug(string $slug);
|
||||
|
||||
public function getPricing(int $productId, string $billingCycle);
|
||||
|
||||
public function getDetailService(string $uuid);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Api\ServiceClient;
|
||||
|
||||
use App\Repositories\Api\ServiceClient\ServiceClientRepositoryInterface;
|
||||
|
||||
class ServiceClientService
|
||||
{
|
||||
protected $serviceClientRepository;
|
||||
|
||||
public function __construct(ServiceClientRepositoryInterface $serviceClientRepository)
|
||||
{
|
||||
$this->serviceClientRepository = $serviceClientRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lấy danh sách dịch vụ đang hoạt động
|
||||
*/
|
||||
public function getActiveServices(int $limit = 10)
|
||||
{
|
||||
return $this->serviceClientRepository->getActiveServices($limit);
|
||||
}
|
||||
|
||||
public function findActiveBySlug(string $slug)
|
||||
{
|
||||
return $this->serviceClientRepository->findActiveBySlug($slug);
|
||||
}
|
||||
|
||||
public function getDetailService(string $uuid)
|
||||
{
|
||||
return $this->serviceClientRepository->getDetailService($uuid);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('services', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid()->unique();
|
||||
|
||||
$table->unsignedBigInteger('customer_id')->index();
|
||||
$table->unsignedBigInteger('product_id')->nullable()->index();
|
||||
|
||||
@@ -117,9 +117,16 @@ Route::prefix('v1')
|
||||
->group(function () {
|
||||
Route::get('/', 'index')->middleware('perm:product-service.view')->name('index');
|
||||
Route::post('/', 'store')->middleware('perm:product-service.create')->name('store');
|
||||
Route::get('trashed', 'trashed')->middleware('perm:product-service.view')->name('trashed');
|
||||
Route::post('bulk-update-status', 'bulkUpdateStatus')->middleware('perm:product-service.edit')->name('bulk-update-status');
|
||||
Route::post('bulk-destroy', 'bulkDestroy')->middleware('perm:product-service.destroy')->name('bulk-destroy');
|
||||
Route::post('bulk-restore', 'bulkRestore')->middleware('perm:product-service.edit')->name('bulk-restore');
|
||||
Route::post('bulk-force-delete', 'bulkForceDelete')->middleware('perm:product-service.destroy')->name('bulk-force-delete');
|
||||
Route::get('{id}', 'show')->middleware('perm:product-service.view')->name('show');
|
||||
Route::put('{id}', 'update')->middleware('perm:product-service.edit')->name('update');
|
||||
Route::delete('{id}', 'destroy')->middleware('perm:product-service.destroy')->name('destroy');
|
||||
Route::post('{id}/restore', 'restore')->middleware('perm:product-service.edit')->name('restore');
|
||||
Route::delete('{id}/force', 'forceDelete')->middleware('perm:product-service.destroy')->name('force-delete');
|
||||
});
|
||||
|
||||
// Orders (module: order)
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Http\Controllers\Api\Client\ClientController;
|
||||
use App\Http\Controllers\Api\Service\OrderController;
|
||||
use App\Http\Controllers\Api\Service\ProductCategoryController;
|
||||
use App\Http\Controllers\Api\Service\ServiceController;
|
||||
use App\Http\Controllers\Api\Client\Service\ServiceController as ServiceClientController;
|
||||
use App\Http\Controllers\Api\Transaction\TransactionController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -34,6 +35,18 @@ Route::prefix('v1')->as('api.')->group(function () {
|
||||
Route::patch('dich-vu/{id}/auto-renew', 'updateClientServiceAutoRenew')->name('services.autoRenew.update');
|
||||
});
|
||||
|
||||
|
||||
Route::middleware(['api.auth'])->prefix('client-service')->controller(ServiceClientController::class)->as('client-service.')->group(function () {
|
||||
Route::get('/', 'getService')->name('list');
|
||||
Route::get('{uuid}', 'getDetail')->name('detail');
|
||||
});
|
||||
|
||||
|
||||
Route::middleware(['api.auth'])->prefix('service')->controller(ServiceController::class)->as('service.')->group(function () {
|
||||
Route::get('/', 'getService')->name('list');
|
||||
Route::get('{uuid}', 'getDetailServiceCustomer')->name('detail');
|
||||
});
|
||||
|
||||
Route::middleware(['api.auth'])->controller(TransactionController::class)->group(function () {
|
||||
Route::get('payment-history', 'getClientPaymentHistory')->name('payment-history.list');
|
||||
});
|
||||
@@ -103,6 +116,8 @@ Route::prefix('v1')->as('api.')->group(function () {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
Route::middleware(['api.auth'])->prefix('orders')->as('orders.')->group(function () {
|
||||
Route::controller(OrderController::class)->group(function () {
|
||||
Route::get('/', 'getList')->name('list');
|
||||
|
||||
Reference in New Issue
Block a user