forked from admin/services_core
214 lines
9.1 KiB
PHP
214 lines
9.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Customer;
|
|
|
|
use App\Http\Controllers\ApiController;
|
|
use App\Http\Requests\Customer\ActivateCustomerRequest;
|
|
use App\Http\Requests\Customer\IndexCustomerRequest;
|
|
use App\Http\Requests\Customer\StoreCustomerRequest;
|
|
use App\Http\Requests\Customer\UpdateCustomerRequest;
|
|
use App\Http\Resources\Customer\CustomerResource;
|
|
use App\Services\Customer\CustomerService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class CustomerController extends ApiController
|
|
{
|
|
public function __construct(protected CustomerService $service) {}
|
|
|
|
public function index(IndexCustomerRequest $request)
|
|
{
|
|
return $this->successPaginated(
|
|
$this->service->list($this->scope($request), $request->validated(), $request->user(), $this->tenantId($request)),
|
|
CustomerResource::class,
|
|
'Daftar customer berhasil diambil'
|
|
);
|
|
}
|
|
|
|
public function options(Request $request)
|
|
{
|
|
return $this->success(
|
|
$this->service->options($request->user(), $this->tenantId($request)),
|
|
'Pilihan relasi customer berhasil diambil'
|
|
);
|
|
}
|
|
|
|
public function odpPorts(Request $request, int $node)
|
|
{
|
|
$data=$request->validate(['customer_id'=>['nullable','integer','exists:customers,id']]);
|
|
return $this->success($this->service->availableOdpPorts($node,$request->user(),$this->tenantId($request),$data['customer_id'] ?? null),'Port ODP tersedia berhasil diambil');
|
|
}
|
|
|
|
public function ocrKtp(Request $request)
|
|
{
|
|
$data = $request->validate([
|
|
'image' => ['required', 'image', 'mimes:jpeg,jpg,png,webp', 'max:5120'],
|
|
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
|
]);
|
|
$tenantId = $request->user()->isMasterAdmin()
|
|
? ($data['tenant_id'] ?? $request->attributes->get('tenant_id'))
|
|
: $request->attributes->get('tenant_id');
|
|
abort_unless($tenantId, 422, 'Tenant wajib dipilih sebelum menjalankan OCR.');
|
|
if (! $request->user()->isMasterAdmin()) {
|
|
abort_unless($request->user()->userTenants()->where('tenant_id', $tenantId)->exists(), 403);
|
|
}
|
|
$setting = \App\Models\TenantInstallationSetting::where('tenant_id', $tenantId)->first();
|
|
abort_unless($setting?->ktp_ocr_enabled, 422, 'OCR KTP belum diaktifkan untuk tenant ini.');
|
|
abort_unless($setting->ocr_provider && $setting->ocr_api_key, 422, 'Provider atau API key OCR belum dikonfigurasi.');
|
|
|
|
$file = $data['image'];
|
|
$mime = $file->getMimeType();
|
|
$base64 = base64_encode(file_get_contents($file->getRealPath()));
|
|
$prompt = 'Baca KTP Indonesia ini. Kembalikan hanya JSON valid tanpa markdown dengan field: nik, nama, alamat, rt_rw, kelurahan_desa, kecamatan, kabupaten_kota, provinsi. Gunakan null bila tidak terbaca.';
|
|
|
|
if ($setting->ocr_provider === 'openai') {
|
|
$response = Http::withToken($setting->ocr_api_key)->timeout(60)->post('https://api.openai.com/v1/chat/completions', [
|
|
'model' => 'gpt-4.1-mini',
|
|
'response_format' => ['type' => 'json_object'],
|
|
'messages' => [['role' => 'user', 'content' => [
|
|
['type' => 'text', 'text' => $prompt],
|
|
['type' => 'image_url', 'image_url' => ['url' => "data:{$mime};base64,{$base64}"]],
|
|
]]],
|
|
]);
|
|
$content = $response->successful() ? $response->json('choices.0.message.content') : null;
|
|
} else {
|
|
$response = Http::timeout(60)->post('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key='.urlencode($setting->ocr_api_key), [
|
|
'contents' => [['parts' => [['text' => $prompt], ['inline_data' => ['mime_type' => $mime, 'data' => $base64]]]]],
|
|
'generationConfig' => ['responseMimeType' => 'application/json'],
|
|
]);
|
|
$content = $response->successful() ? $response->json('candidates.0.content.parts.0.text') : null;
|
|
}
|
|
if (! $response->successful() || ! $content) {
|
|
throw ValidationException::withMessages(['image' => 'Provider AI gagal membaca KTP. Periksa API key, kuota, dan kualitas gambar.']);
|
|
}
|
|
$result = json_decode(trim(str_replace(['```json', '```'], '', $content)), true);
|
|
if (! is_array($result)) throw ValidationException::withMessages(['image' => 'Respons OCR tidak dapat diproses.']);
|
|
|
|
return $this->success($result, 'KTP berhasil dibaca');
|
|
}
|
|
|
|
public function store(StoreCustomerRequest $request)
|
|
{
|
|
return $this->created(
|
|
new CustomerResource($this->service->create($request->validated(), $request->user(), $this->tenantId($request))),
|
|
'Customer berhasil didaftarkan'
|
|
);
|
|
}
|
|
|
|
public function show(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id, $this->scope($request) === 'trash');
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->success(new CustomerResource($customer), 'Detail customer berhasil diambil');
|
|
}
|
|
|
|
public function update(UpdateCustomerRequest $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->updated(
|
|
new CustomerResource($this->service->update($customer, $request->validated(), $request->user())),
|
|
'Data customer berhasil diperbarui'
|
|
);
|
|
}
|
|
|
|
public function prepareActivation(UpdateCustomerRequest $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
$mode = \App\Models\TenantInstallationSetting::firstOrCreate(
|
|
['tenant_id' => $customer->tenant_id],
|
|
['activation_mode' => 'list_order']
|
|
)->activation_mode;
|
|
abort_unless($mode === 'list_order', 422, 'Tenant mengatur persiapan aktivasi melalui Ticket.');
|
|
|
|
$customer = $this->service->update($customer, $request->validated(), $request->user());
|
|
$customer = $this->service->ensureActivationCode($customer);
|
|
return $this->updated(
|
|
new CustomerResource($customer),
|
|
'Persiapan aktivasi berhasil disimpan'
|
|
);
|
|
}
|
|
|
|
public function updateRegistration(UpdateCustomerRequest $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->updated(
|
|
new CustomerResource($this->service->update($customer, $request->validated(), $request->user())),
|
|
'Data registrasi berhasil disimpan'
|
|
);
|
|
}
|
|
|
|
public function activate(ActivateCustomerRequest $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->updated(new CustomerResource($this->service->activate($customer, $request->validated(), $request->user())), 'Customer berhasil diaktifkan');
|
|
}
|
|
|
|
public function deactivate(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->updated(new CustomerResource($this->service->deactivate($customer)), 'Customer berhasil dinonaktifkan');
|
|
}
|
|
|
|
public function destroy(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
$this->service->trash($customer);
|
|
|
|
return $this->deleted('Customer dipindahkan ke Sampah');
|
|
}
|
|
|
|
public function cancelOrder(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
abort_unless($customer->status === 'order', 422, 'Hanya customer dalam List Order yang dapat dihapus melalui aksi ini.');
|
|
$this->service->trash($customer);
|
|
|
|
return $this->deleted('List Order dipindahkan ke Sampah');
|
|
}
|
|
|
|
public function restore(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id, true);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
|
|
return $this->updated(new CustomerResource($this->service->restore($customer)), 'Customer berhasil dipulihkan');
|
|
}
|
|
|
|
public function forceDelete(Request $request, int $id)
|
|
{
|
|
$customer = $this->service->find($id, true);
|
|
$this->authorizeTenant($request, $customer->tenant_id);
|
|
$this->service->forceDelete($customer);
|
|
|
|
return $this->deleted('Customer dihapus permanen');
|
|
}
|
|
|
|
private function scope(Request $request): string
|
|
{
|
|
return $request->route()->defaults['customer_scope'] ?? 'orders';
|
|
}
|
|
|
|
private function tenantId(Request $request): ?int
|
|
{
|
|
return $request->attributes->get('tenant_id');
|
|
}
|
|
|
|
private function authorizeTenant(Request $request, int $tenantId): void
|
|
{
|
|
abort_unless($request->user()->isMasterAdmin() || $tenantId === $this->tenantId($request), 403);
|
|
}
|
|
}
|