feat: implement Customer API for creating customers, refactor existing CustomerController, and update routes for API integration

This commit is contained in:
Yoga Pangestu 2026-07-03 16:14:41 +07:00
parent 59d7f94d0f
commit bac44df627
7 changed files with 88 additions and 17 deletions

View File

@ -8,7 +8,6 @@
use App\Http\Requests\Admin\Master\CustomerRequest; use App\Http\Requests\Admin\Master\CustomerRequest;
use App\Models\Customer; use App\Models\Customer;
use App\Services\Master\CustomerService; use App\Services\Master\CustomerService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Inertia\Inertia; use Inertia\Inertia;
@ -58,14 +57,4 @@ public function destroy(Customer $customer): RedirectResponse
return redirect()->route('admin.master.customers.index'); return redirect()->route('admin.master.customers.index');
} }
public function storeApi(CustomerRequest $request): JsonResponse
{
$customer = $this->customerService->createAndReturn($request->validated());
return response()->json([
'id' => $customer->id,
'name' => $customer->name,
]);
}
} }

View File

@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Api\Master;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\CustomerRequest;
use App\Services\Master\CustomerService;
use Illuminate\Http\JsonResponse;
class CustomerApiController extends Controller
{
public function __construct(
private readonly CustomerService $customerService,
) {}
public function store(CustomerRequest $request): JsonResponse
{
$customer = $this->customerService->createAndReturn($request->validated());
return response()->json([
'id' => $customer->id,
'name' => $customer->name,
]);
}
}

View File

@ -16,6 +16,7 @@
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
web: __DIR__.'/../routes/web.php', web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php', commands: __DIR__.'/../routes/console.php',
health: '/up', health: '/up',
) )

View File

@ -22,7 +22,7 @@ import { FIELD_LIMITS } from '@/lib/field-limits';
import { Save } from '@lucide/vue'; import { Save } from '@lucide/vue';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { api } from '@/routes/admin/master/customers/store'; import { store } from '@/routes/api/master/customers';
const open = defineModel<boolean>('open', { default: false }); const open = defineModel<boolean>('open', { default: false });
@ -52,7 +52,7 @@ async function submit() {
try { try {
const customer = await apiFetch<{ id: number; name: string }>( const customer = await apiFetch<{ id: number; name: string }>(
api.url(), store.url(),
{ {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({

15
routes/api.php Normal file
View File

@ -0,0 +1,15 @@
<?php
use App\Enums\Permission;
use App\Http\Controllers\Api\Master\CustomerApiController;
use Illuminate\Support\Facades\Route;
Route::middleware(['web', 'auth'])->name('api.')->group(function () {
Route::prefix('master')->name('master.')->group(function () {
Route::prefix('customers')->name('customers.')->group(function () {
Route::post('/', [CustomerApiController::class, 'store'])
->middleware('permission:'.Permission::CUSTOMERS_CREATE->value)
->name('store');
});
});
});

View File

@ -203,10 +203,6 @@
->middleware('permission:'.Permission::CUSTOMERS_CREATE->value) ->middleware('permission:'.Permission::CUSTOMERS_CREATE->value)
->name('store'); ->name('store');
Route::post('api', [CustomerController::class, 'storeApi'])
->middleware('permission:'.Permission::CUSTOMERS_CREATE->value)
->name('store.api');
Route::put('{customer}', [CustomerController::class, 'update']) Route::put('{customer}', [CustomerController::class, 'update'])
->middleware('permission:'.Permission::CUSTOMERS_UPDATE->value) ->middleware('permission:'.Permission::CUSTOMERS_UPDATE->value)
->name('update'); ->name('update');

View File

@ -329,6 +329,51 @@ function createCustomerUserWithPermission(PermissionEnum ...$permissions): User
$this->assertDatabaseHas('customers', ['id' => $customer->id]); $this->assertDatabaseHas('customers', ['id' => $customer->id]);
}); });
}); });
// ─── Customer API Store ───────────────────────────────────
describe('Customer API Store', function () {
test('authenticated user with permission can create a customer via api', function () {
$user = createCustomerUserWithPermission(PermissionEnum::CUSTOMERS_VIEW, PermissionEnum::CUSTOMERS_CREATE);
$response = $this->actingAs($user)
->postJson(route('api.master.customers.store'), [
'name' => 'Ujang API',
'phone_number' => '081234567890',
'address' => 'Jl. Merdeka No. 1',
]);
$response->assertOk()
->assertJsonStructure(['id', 'name'])
->assertJson([
'name' => 'Ujang API',
]);
$this->assertDatabaseHas('customers', [
'name' => 'Ujang API',
'phone_number' => '081234567890',
'address' => 'Jl. Merdeka No. 1',
]);
});
test('guest cannot create a customer via api', function () {
$response = $this->postJson(route('api.master.customers.store'), [
'name' => 'Ujang API',
]);
$response->assertUnauthorized();
});
test('user without create permission is forbidden via api', function () {
$user = createCustomerUserWithPermission(PermissionEnum::CUSTOMERS_VIEW);
$response = $this->actingAs($user)
->postJson(route('api.master.customers.store'), [
'name' => 'Ujang API',
]);
$response->assertForbidden();
});
});
// ─── Customer Model ─────────────────────────────────────── // ─── Customer Model ───────────────────────────────────────