forked from admin/services_core
Giant Update
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Billing;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Billing\IndexBillingRequest;
|
||||
use App\Http\Requests\Billing\StoreBillingProfileRequest;
|
||||
use App\Http\Requests\Billing\UpdateBillingProfileRequest;
|
||||
use App\Http\Resources\Billing\BillingProfileResource;
|
||||
use App\Services\Billing\BillingProfileService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BillingProfileController extends ApiController
|
||||
{
|
||||
public function __construct(protected BillingProfileService $service) {}
|
||||
|
||||
public function index(IndexBillingRequest $request)
|
||||
{
|
||||
return $this->successPaginated($this->service->list($request->validated(), $request->user(), $this->tenantId($request)), BillingProfileResource::class, 'Daftar profile tagihan berhasil diambil');
|
||||
}
|
||||
|
||||
public function store(StoreBillingProfileRequest $request)
|
||||
{
|
||||
return $this->created(new BillingProfileResource($this->service->create($request->validated(), $request->user(), $this->tenantId($request))), 'Profile tagihan berhasil dibuat');
|
||||
}
|
||||
|
||||
public function show(Request $request, int $id)
|
||||
{
|
||||
$profile = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $profile->tenant_id);
|
||||
|
||||
return $this->success(new BillingProfileResource($profile), 'Detail profile tagihan berhasil diambil');
|
||||
}
|
||||
|
||||
public function update(UpdateBillingProfileRequest $request, int $id)
|
||||
{
|
||||
$profile = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $profile->tenant_id);
|
||||
|
||||
return $this->updated(new BillingProfileResource($this->service->update($profile, $request->validated(), $request->user())), 'Profile tagihan berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $id)
|
||||
{
|
||||
$profile = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $profile->tenant_id);
|
||||
$this->service->delete($profile);
|
||||
|
||||
return $this->deleted('Profile tagihan berhasil dihapus');
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Billing;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Billing\IndexBillingRequest;
|
||||
use App\Http\Requests\Billing\PayInvoiceRequest;
|
||||
use App\Http\Requests\Billing\StoreInvoiceRequest;
|
||||
use App\Http\Requests\Billing\UpdateInvoiceRequest;
|
||||
use App\Http\Resources\Billing\InvoiceResource;
|
||||
use App\Services\Billing\InvoiceService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvoiceController extends ApiController
|
||||
{
|
||||
public function __construct(protected InvoiceService $service) {}
|
||||
|
||||
public function index(IndexBillingRequest $request)
|
||||
{
|
||||
return $this->successPaginated($this->service->list($this->scope($request), $request->validated(), $request->user(), $this->tenantId($request)), InvoiceResource::class, 'Daftar tagihan berhasil diambil');
|
||||
}
|
||||
|
||||
public function options(Request $request)
|
||||
{
|
||||
return $this->success($this->service->options($request->user(), $this->tenantId($request)), 'Pilihan tagihan berhasil diambil');
|
||||
}
|
||||
|
||||
public function store(StoreInvoiceRequest $request)
|
||||
{
|
||||
return $this->created(new InvoiceResource($this->service->create($request->validated(), $request->user(), $this->tenantId($request))), 'Tagihan berhasil dibuat');
|
||||
}
|
||||
|
||||
public function show(Request $request, int $id)
|
||||
{
|
||||
$invoice = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $invoice->tenant_id);
|
||||
|
||||
return $this->success(new InvoiceResource($invoice), 'Detail tagihan berhasil diambil');
|
||||
}
|
||||
|
||||
public function update(UpdateInvoiceRequest $request, int $id)
|
||||
{
|
||||
$invoice = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $invoice->tenant_id);
|
||||
|
||||
return $this->updated(new InvoiceResource($this->service->update($invoice, $request->validated(), $request->user())), 'Tagihan berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function pay(PayInvoiceRequest $request, int $id)
|
||||
{
|
||||
$invoice = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $invoice->tenant_id);
|
||||
|
||||
return $this->updated(new InvoiceResource($this->service->pay($invoice, $request->validated(), $request->user())), 'Pembayaran manual berhasil dicatat');
|
||||
}
|
||||
|
||||
public function cancel(Request $request, int $id)
|
||||
{
|
||||
$invoice = $this->service->find($id);
|
||||
$this->authorizeTenant($request, $invoice->tenant_id);
|
||||
|
||||
return $this->updated(new InvoiceResource($this->service->cancel($invoice, $request->user())), 'Tagihan berhasil dibatalkan');
|
||||
}
|
||||
|
||||
private function scope(Request $request): string
|
||||
{
|
||||
return $request->route()->defaults['invoice_scope'] ?? 'running';
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?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;
|
||||
|
||||
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 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 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())), '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 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Notification;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Notification\IndexNotificationRequest;
|
||||
use App\Http\Requests\Notification\SaveNotificationPreferencesRequest;
|
||||
use App\Http\Requests\Notification\StoreCustomerContactRequest;
|
||||
use App\Http\Requests\Notification\StoreNotificationBroadcastRequest;
|
||||
use App\Http\Requests\Notification\StoreNotificationChannelRequest;
|
||||
use App\Http\Requests\Notification\StoreNotificationTemplateRequest;
|
||||
use App\Http\Resources\Notification\NotificationDeliveryResource;
|
||||
use App\Models\Customer;
|
||||
use App\Models\CustomerContact;
|
||||
use App\Models\NotificationBroadcast;
|
||||
use App\Models\NotificationChannel;
|
||||
use App\Models\NotificationEvent;
|
||||
use App\Models\NotificationTemplate;
|
||||
use App\Services\Notification\NotificationService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NotificationController extends ApiController
|
||||
{
|
||||
public function __construct(protected NotificationService $service) {}
|
||||
|
||||
public function events()
|
||||
{
|
||||
return $this->success(NotificationEvent::where('enabled', true)->orderBy('category')->orderBy('name')->get(), 'Daftar event notifikasi berhasil diambil');
|
||||
}
|
||||
|
||||
public function channels(Request $request)
|
||||
{
|
||||
return $this->success($this->service->channels($this->channel($request), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil diambil');
|
||||
}
|
||||
|
||||
public function storeChannel(StoreNotificationChannelRequest $request)
|
||||
{
|
||||
abort_unless($request->validated('channel') === $this->channel($request), 422);
|
||||
|
||||
return $this->created($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil dibuat');
|
||||
}
|
||||
|
||||
public function updateChannel(StoreNotificationChannelRequest $request, NotificationChannel $notificationChannel)
|
||||
{
|
||||
$this->authorizeTenant($request, $notificationChannel->tenant_id);
|
||||
abort_unless($notificationChannel->channel === $this->channel($request), 404);
|
||||
|
||||
return $this->updated($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request), $notificationChannel), 'Konfigurasi channel berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function testChannel(Request $request, NotificationChannel $notificationChannel)
|
||||
{
|
||||
$this->authorizeTenant($request, $notificationChannel->tenant_id);
|
||||
abort_unless($notificationChannel->channel === $this->channel($request), 404);
|
||||
|
||||
return $this->success($this->service->testChannel($notificationChannel), 'Pengujian channel selesai');
|
||||
}
|
||||
|
||||
public function templates(Request $request)
|
||||
{
|
||||
return $this->success($this->service->templates($this->channel($request), $request->user(), $this->tenantId($request)), 'Daftar template berhasil diambil');
|
||||
}
|
||||
|
||||
public function storeTemplate(StoreNotificationTemplateRequest $request)
|
||||
{
|
||||
abort_unless($request->validated('channel') === $this->channel($request), 422);
|
||||
|
||||
return $this->created($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request)), 'Template berhasil dibuat');
|
||||
}
|
||||
|
||||
public function updateTemplate(StoreNotificationTemplateRequest $request, NotificationTemplate $notificationTemplate)
|
||||
{
|
||||
if ($notificationTemplate->tenant_id) {
|
||||
$this->authorizeTenant($request, $notificationTemplate->tenant_id);
|
||||
}
|
||||
abort_unless($notificationTemplate->channel === $this->channel($request), 404);
|
||||
|
||||
return $this->updated($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request), $notificationTemplate), 'Template berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function preferences(Request $request)
|
||||
{
|
||||
$tenantId = $request->user()->isMasterAdmin() && $request->integer('tenant_id')
|
||||
? $request->integer('tenant_id')
|
||||
: $this->tenantId($request);
|
||||
|
||||
return $this->success($this->service->preferences($request->user(), $tenantId), 'Preference notifikasi berhasil diambil');
|
||||
}
|
||||
|
||||
public function savePreferences(SaveNotificationPreferencesRequest $request)
|
||||
{
|
||||
$this->service->savePreferences($request->validated('preferences'), $request->user(), $this->tenantId($request));
|
||||
|
||||
return $this->updated(null, 'Preference notifikasi berhasil disimpan');
|
||||
}
|
||||
|
||||
public function deliveries(IndexNotificationRequest $request)
|
||||
{
|
||||
return $this->successPaginated(
|
||||
$this->service->deliveries($this->channel($request), $request->validated(), $request->user(), $this->tenantId($request)),
|
||||
NotificationDeliveryResource::class,
|
||||
'Log pesan berhasil diambil',
|
||||
);
|
||||
}
|
||||
|
||||
public function broadcasts(IndexNotificationRequest $request)
|
||||
{
|
||||
return $this->success($this->service->broadcasts($request->validated(), $request->user(), $this->tenantId($request)), 'Daftar pesan siaran berhasil diambil');
|
||||
}
|
||||
|
||||
public function previewBroadcast(StoreNotificationBroadcastRequest $request)
|
||||
{
|
||||
return $this->success($this->service->previewBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Preview penerima berhasil dihitung');
|
||||
}
|
||||
|
||||
public function storeBroadcast(StoreNotificationBroadcastRequest $request)
|
||||
{
|
||||
return $this->created($this->service->createBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Pesan siaran masuk antrean');
|
||||
}
|
||||
|
||||
public function showBroadcast(Request $request, NotificationBroadcast $notificationBroadcast)
|
||||
{
|
||||
$this->authorizeTenant($request, $notificationBroadcast->tenant_id);
|
||||
|
||||
return $this->success($notificationBroadcast->load(['template', 'channelConfig', 'recipients.customer:id,customer_code,name']), 'Detail siaran berhasil diambil');
|
||||
}
|
||||
|
||||
public function approveBroadcast(Request $request, NotificationBroadcast $notificationBroadcast)
|
||||
{
|
||||
$this->authorizeTenant($request, $notificationBroadcast->tenant_id);
|
||||
|
||||
return $this->updated($this->service->approveBroadcast($notificationBroadcast, $request->user()), 'Pesan siaran berhasil disetujui');
|
||||
}
|
||||
|
||||
public function myNotifications(IndexNotificationRequest $request)
|
||||
{
|
||||
return $this->success($this->service->userNotifications($request->user(), $request->validated()), 'Notifikasi aplikasi berhasil diambil');
|
||||
}
|
||||
|
||||
public function markRead(Request $request, string $uuid)
|
||||
{
|
||||
$notification = $request->user()->userNotifications()->where('uuid', $uuid)->firstOrFail();
|
||||
$notification->update(['read_at' => now()]);
|
||||
|
||||
return $this->updated($notification, 'Notifikasi ditandai sudah dibaca');
|
||||
}
|
||||
|
||||
public function contacts(Request $request, Customer $customer)
|
||||
{
|
||||
$this->authorizeTenant($request, $customer->tenant_id);
|
||||
|
||||
return $this->success($customer->contacts()->orderBy('type')->orderByDesc('is_primary')->get(), 'Kontak notifikasi berhasil diambil');
|
||||
}
|
||||
|
||||
public function storeContact(StoreCustomerContactRequest $request, Customer $customer)
|
||||
{
|
||||
$this->authorizeTenant($request, $customer->tenant_id);
|
||||
|
||||
return $this->created($this->service->saveContact($customer, $request->validated()), 'Kontak notifikasi berhasil dibuat');
|
||||
}
|
||||
|
||||
public function updateContact(StoreCustomerContactRequest $request, Customer $customer, CustomerContact $contact)
|
||||
{
|
||||
$this->authorizeTenant($request, $customer->tenant_id);
|
||||
|
||||
return $this->updated($this->service->saveContact($customer, $request->validated(), $contact), 'Kontak notifikasi berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function destroyContact(Request $request, Customer $customer, CustomerContact $contact)
|
||||
{
|
||||
$this->authorizeTenant($request, $customer->tenant_id);
|
||||
abort_unless((int) $contact->customer_id === (int) $customer->id, 404);
|
||||
$contact->delete();
|
||||
|
||||
return $this->deleted('Kontak notifikasi berhasil dihapus');
|
||||
}
|
||||
|
||||
private function channel(Request $request): string
|
||||
{
|
||||
return $request->route()->defaults['notification_channel'];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Notification;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\NotificationChannel;
|
||||
use App\Models\NotificationDelivery;
|
||||
use App\Models\NotificationWebhookLog;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NotificationWebhookController extends Controller
|
||||
{
|
||||
public function verify(Request $request, NotificationChannel $notificationChannel)
|
||||
{
|
||||
abort_unless(
|
||||
$request->query('hub.mode') === 'subscribe'
|
||||
&& hash_equals((string) data_get($notificationChannel->credentials, 'webhook_verify_token'), (string) $request->query('hub.verify_token')),
|
||||
403,
|
||||
);
|
||||
|
||||
return response($request->query('hub.challenge'), 200);
|
||||
}
|
||||
|
||||
public function handle(Request $request, NotificationChannel $notificationChannel)
|
||||
{
|
||||
$valid = $this->validSignature($request, $notificationChannel);
|
||||
$payload = $request->all();
|
||||
$updates = $this->updates($payload);
|
||||
$log = NotificationWebhookLog::create([
|
||||
'notification_channel_id' => $notificationChannel->id,
|
||||
'provider' => $notificationChannel->provider,
|
||||
'event_type' => data_get($payload, 'entry.0.changes.0.field') ?? data_get($payload, 'event'),
|
||||
'provider_message_id' => data_get($updates, '0.id'),
|
||||
'signature_valid' => $valid,
|
||||
'payload' => $payload,
|
||||
]);
|
||||
abort_unless($valid, 401);
|
||||
|
||||
foreach ($updates as $update) {
|
||||
$delivery = NotificationDelivery::where('provider_message_id', $update['id'] ?? null)->first();
|
||||
if (! $delivery) {
|
||||
continue;
|
||||
}
|
||||
$status = match ($update['status'] ?? null) {
|
||||
'delivered' => 'delivered',
|
||||
'read' => 'read',
|
||||
'failed' => 'failed',
|
||||
default => 'sent',
|
||||
};
|
||||
$delivery->update([
|
||||
'status' => $status,
|
||||
'delivered_at' => $status === 'delivered' ? now() : $delivery->delivered_at,
|
||||
'read_at' => $status === 'read' ? now() : $delivery->read_at,
|
||||
'failed_at' => $status === 'failed' ? now() : $delivery->failed_at,
|
||||
'error_code' => data_get($update, 'errors.0.code'),
|
||||
'error_message' => data_get($update, 'errors.0.title'),
|
||||
]);
|
||||
}
|
||||
$log->update(['processed_at' => now()]);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
private function validSignature(Request $request, NotificationChannel $channel): bool
|
||||
{
|
||||
if ($channel->channel === 'whatsapp_official') {
|
||||
$secret = data_get($channel->credentials, 'app_secret');
|
||||
$signature = $request->header('X-Hub-Signature-256');
|
||||
|
||||
return $secret && $signature && hash_equals('sha256='.hash_hmac('sha256', $request->getContent(), $secret), $signature);
|
||||
}
|
||||
$secret = data_get($channel->credentials, 'webhook_secret');
|
||||
|
||||
return $secret && hash_equals((string) $secret, (string) $request->header('X-Webhook-Secret'));
|
||||
}
|
||||
|
||||
private function updates(array $payload): array
|
||||
{
|
||||
$statuses = data_get($payload, 'entry.0.changes.0.value.statuses');
|
||||
if (is_array($statuses)) {
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
return [[
|
||||
'id' => data_get($payload, 'message_id') ?? data_get($payload, 'id'),
|
||||
'status' => data_get($payload, 'status') ?? data_get($payload, 'event'),
|
||||
'errors' => data_get($payload, 'errors', []),
|
||||
]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Payment;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Payment\IndexPaymentRequest;
|
||||
use App\Http\Requests\Payment\SaveTenantPaymentSettingRequest;
|
||||
use App\Http\Requests\Payment\StoreGatewayAccountRequest;
|
||||
use App\Http\Resources\Payment\PaymentTransactionResource;
|
||||
use App\Models\PaymentGatewayAccount;
|
||||
use App\Services\Payment\PaymentGatewayService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PaymentGatewayController extends ApiController
|
||||
{
|
||||
public function __construct(protected PaymentGatewayService $service) {}
|
||||
|
||||
public function providers()
|
||||
{
|
||||
return $this->success($this->service->providers(), 'Daftar provider berhasil diambil');
|
||||
}
|
||||
|
||||
public function settings(Request $request)
|
||||
{
|
||||
return $this->success($this->service->settings($request->user(), $this->tenantId($request)), 'Pengaturan payment gateway berhasil diambil');
|
||||
}
|
||||
|
||||
public function storeAccount(StoreGatewayAccountRequest $request)
|
||||
{
|
||||
return $this->created($this->service->saveAccount($request->validated(), $request->user(), $this->tenantId($request)), 'Akun gateway berhasil dibuat');
|
||||
}
|
||||
|
||||
public function updateAccount(StoreGatewayAccountRequest $request, PaymentGatewayAccount $account)
|
||||
{
|
||||
return $this->updated($this->service->saveAccount($request->validated(), $request->user(), $this->tenantId($request), $account), 'Akun gateway berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function saveSetting(SaveTenantPaymentSettingRequest $request)
|
||||
{
|
||||
return $this->updated($this->service->saveTenantSetting($request->validated(), $request->user(), $this->tenantId($request)), 'Mode pembayaran tenant berhasil disimpan');
|
||||
}
|
||||
|
||||
public function transactions(IndexPaymentRequest $request)
|
||||
{
|
||||
return $this->successPaginated($this->service->transactions($request->validated(), $request->user(), $this->tenantId($request)), PaymentTransactionResource::class, 'Log pembayaran berhasil diambil');
|
||||
}
|
||||
|
||||
private function tenantId(Request $request): ?int
|
||||
{
|
||||
return $request->attributes->get('tenant_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Topology;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Topology\IndexTopologyRequest;
|
||||
use App\Http\Requests\Topology\StoreCustomerConnectionRequest;
|
||||
use App\Http\Requests\Topology\StoreTopologyRequest;
|
||||
use App\Http\Requests\Topology\UpdateTopologyRequest;
|
||||
use App\Http\Resources\Topology\TopologyResource;
|
||||
use App\Models\Customer;
|
||||
use App\Models\TopologyNode;
|
||||
use App\Models\TopologyPort;
|
||||
use App\Services\Topology\TopologyService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TopologyController extends ApiController
|
||||
{
|
||||
public function __construct(protected TopologyService $service) {}
|
||||
|
||||
public function index(IndexTopologyRequest $request)
|
||||
{
|
||||
return $this->successPaginated(
|
||||
$this->service->list($this->resource($request), $request->validated(), $request->user(), $this->tenantId($request)),
|
||||
TopologyResource::class,
|
||||
'Daftar topologi berhasil diambil',
|
||||
);
|
||||
}
|
||||
|
||||
public function store(StoreTopologyRequest $request)
|
||||
{
|
||||
return $this->created(
|
||||
new TopologyResource($this->service->create($this->resource($request), $request->validated(), $request->user(), $this->tenantId($request))),
|
||||
'Data topologi berhasil dibuat',
|
||||
);
|
||||
}
|
||||
|
||||
public function show(Request $request, int $id)
|
||||
{
|
||||
$model = $this->service->find($this->resource($request), $id);
|
||||
$this->authorizeModel($request, $model);
|
||||
|
||||
return $this->success(new TopologyResource($model), 'Detail topologi berhasil diambil');
|
||||
}
|
||||
|
||||
public function update(UpdateTopologyRequest $request, int $id)
|
||||
{
|
||||
$resource = $this->resource($request);
|
||||
$model = $this->service->find($resource, $id);
|
||||
$this->authorizeModel($request, $model, true);
|
||||
|
||||
return $this->updated(
|
||||
new TopologyResource($this->service->update($resource, $model, $request->validated(), $request->user())),
|
||||
'Data topologi berhasil diperbarui',
|
||||
);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $id)
|
||||
{
|
||||
$resource = $this->resource($request);
|
||||
$model = $this->service->find($resource, $id);
|
||||
$this->authorizeModel($request, $model, true);
|
||||
$this->service->delete($resource, $model);
|
||||
|
||||
return $this->deleted('Data topologi berhasil dihapus');
|
||||
}
|
||||
|
||||
public function options(Request $request)
|
||||
{
|
||||
return $this->success($this->service->options($request->user(), $this->tenantId($request)), 'Pilihan topologi berhasil diambil');
|
||||
}
|
||||
|
||||
public function map(IndexTopologyRequest $request)
|
||||
{
|
||||
return $this->success($this->service->map($request->validated(), $request->user(), $this->tenantId($request)), 'Data peta topologi berhasil diambil');
|
||||
}
|
||||
|
||||
public function ports(Request $request, TopologyNode $node)
|
||||
{
|
||||
$this->authorizeTenant($request, $node->tenant_id);
|
||||
|
||||
return $this->success($this->service->ports($node), 'Daftar port berhasil diambil');
|
||||
}
|
||||
|
||||
public function storePort(StoreTopologyRequest $request, TopologyNode $node)
|
||||
{
|
||||
$this->authorizeTenant($request, $node->tenant_id);
|
||||
|
||||
return $this->created($this->service->createPort($node, $request->validated()), 'Port berhasil dibuat');
|
||||
}
|
||||
|
||||
public function updatePort(UpdateTopologyRequest $request, TopologyPort $port)
|
||||
{
|
||||
$this->authorizeTenant($request, $port->tenant_id);
|
||||
|
||||
return $this->updated($this->service->updatePort($port, $request->validated()), 'Port berhasil diperbarui');
|
||||
}
|
||||
|
||||
public function destroyPort(Request $request, TopologyPort $port)
|
||||
{
|
||||
$this->authorizeTenant($request, $port->tenant_id);
|
||||
$this->service->deletePort($port);
|
||||
|
||||
return $this->deleted('Port berhasil dihapus');
|
||||
}
|
||||
|
||||
public function trace(Request $request, TopologyNode $node, string $direction)
|
||||
{
|
||||
abort_unless(in_array($direction, ['upstream', 'downstream'], true), 404);
|
||||
$this->authorizeTenant($request, $node->tenant_id);
|
||||
|
||||
return $this->success($this->service->trace($node, $direction), 'Jalur topologi berhasil ditelusuri');
|
||||
}
|
||||
|
||||
public function connectCustomer(StoreCustomerConnectionRequest $request)
|
||||
{
|
||||
return $this->created(
|
||||
$this->service->connectCustomer($request->validated(), $request->user(), $this->tenantId($request)),
|
||||
'Customer berhasil dihubungkan ke ODP',
|
||||
);
|
||||
}
|
||||
|
||||
public function customerPath(Request $request, Customer $customer)
|
||||
{
|
||||
$this->authorizeTenant($request, $customer->tenant_id);
|
||||
|
||||
return $this->success($this->service->customerPath($customer), 'Jalur customer berhasil ditelusuri');
|
||||
}
|
||||
|
||||
private function resource(Request $request): string
|
||||
{
|
||||
return $request->route()->defaults['topology_resource'];
|
||||
}
|
||||
|
||||
private function tenantId(Request $request): ?int
|
||||
{
|
||||
return $request->attributes->get('tenant_id');
|
||||
}
|
||||
|
||||
private function authorizeModel(Request $request, $model, bool $write = false): void
|
||||
{
|
||||
if ($model->tenant_id === null) {
|
||||
abort_if($write && ! $request->user()->isMasterAdmin(), 403);
|
||||
|
||||
return;
|
||||
}
|
||||
$this->authorizeTenant($request, $model->tenant_id);
|
||||
}
|
||||
|
||||
private function authorizeTenant(Request $request, int $tenantId): void
|
||||
{
|
||||
abort_unless($request->user()->isMasterAdmin() || $tenantId === $this->tenantId($request), 403);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Wallet;
|
||||
|
||||
use App\Http\Controllers\ApiController;
|
||||
use App\Http\Requests\Wallet\StoreWithdrawalRequest;
|
||||
use App\Http\Requests\Wallet\TransferWalletRequest;
|
||||
use App\Models\Wallet;
|
||||
use App\Services\Wallet\WalletService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class WalletController extends ApiController
|
||||
{
|
||||
public function __construct(protected WalletService $service) {}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
return $this->success($this->service->wallets($request->user(), $this->tenantId($request)), 'Daftar dompet berhasil diambil');
|
||||
}
|
||||
|
||||
public function ledger(Request $request, Wallet $wallet)
|
||||
{
|
||||
return $this->success($this->service->ledger($wallet, $request->user(), $this->tenantId($request), $request->validate(['per_page' => ['nullable', 'integer', 'min:1', 'max:100']])), 'Mutasi dompet berhasil diambil');
|
||||
}
|
||||
|
||||
public function transfer(TransferWalletRequest $request, Wallet $wallet)
|
||||
{
|
||||
return $this->created($this->service->transfer($wallet, Wallet::findOrFail($request->integer('destination_wallet_id')), $request->float('amount'), $request->user(), $this->tenantId($request)), 'Saldo berhasil dipindahkan');
|
||||
}
|
||||
|
||||
public function withdraw(StoreWithdrawalRequest $request, Wallet $wallet)
|
||||
{
|
||||
return $this->created($this->service->requestWithdrawal($wallet, $request->validated(), $request->user(), $this->tenantId($request)), 'Permintaan penarikan berhasil dibuat');
|
||||
}
|
||||
|
||||
private function tenantId(Request $request): ?int
|
||||
{
|
||||
return $request->attributes->get('tenant_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class IndexBillingRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['nullable', 'string', 'max:255'],
|
||||
'status' => ['nullable', 'string', 'max:30'],
|
||||
'date_from' => ['nullable', 'date'],
|
||||
'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
|
||||
'page' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
'sort_by' => ['nullable', Rule::in(['id', 'name', 'invoice_number', 'issue_date', 'isolation_date', 'total', 'balance', 'status', 'created_at', 'paid_at'])],
|
||||
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class PayInvoiceRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'amount' => ['required', 'numeric', 'gt:0'],
|
||||
'payment_method' => ['nullable', 'string', 'max:50'],
|
||||
'payment_reference' => ['nullable', 'string', 'max:255'],
|
||||
'paid_at' => ['nullable', 'date'],
|
||||
'notes' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreBillingProfileRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'schedule_type' => ['required', Rule::in(['fixed_date', 'installation_date'])],
|
||||
'invoice_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28'],
|
||||
'send_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:invoice_day'],
|
||||
'warning_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:send_day'],
|
||||
'isolation_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:warning_day'],
|
||||
'invoice_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90'],
|
||||
'send_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90', 'lte:invoice_days_before'],
|
||||
'warning_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90', 'lte:send_days_before'],
|
||||
'isolation_days_after' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90'],
|
||||
'tax_type' => ['required', Rule::in(['inclusive', 'exclusive', 'non_tax'])],
|
||||
'tax_rate' => ['nullable', 'numeric', 'between:0,100'],
|
||||
'status' => ['nullable', Rule::in(['active', 'inactive'])],
|
||||
'notes' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreInvoiceRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'customer_id' => ['required', 'integer', 'exists:customers,id'],
|
||||
'invoice_number' => ['nullable', 'string', 'max:100'],
|
||||
'period_start' => ['required', 'date'],
|
||||
'period_end' => ['required', 'date', 'after_or_equal:period_start'],
|
||||
'issue_date' => ['required', 'date'],
|
||||
'send_date' => ['nullable', 'date', 'after_or_equal:issue_date'],
|
||||
'warning_date' => ['nullable', 'date', 'after_or_equal:send_date'],
|
||||
'isolation_date' => ['nullable', 'date', 'after_or_equal:warning_date'],
|
||||
'subtotal' => ['required', 'numeric', 'min:0'],
|
||||
'notes' => ['nullable', 'string'],
|
||||
'metadata' => ['nullable', 'array'],
|
||||
'status' => ['nullable', Rule::in(['draft', 'published', 'sent', 'warning', 'overdue', 'paid', 'cancelled'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
class UpdateBillingProfileRequest extends StoreBillingProfileRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return collect(parent::rules())->map(function ($rules) {
|
||||
$rules = is_array($rules) ? $rules : [$rules];
|
||||
if (($index = array_search('required', $rules, true)) !== false) {
|
||||
$rules[$index] = 'sometimes';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
})->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Billing;
|
||||
|
||||
class UpdateInvoiceRequest extends StoreInvoiceRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return collect(parent::rules())->map(function ($rules) {
|
||||
$rules = is_array($rules) ? $rules : [$rules];
|
||||
if (($index = array_search('required', $rules, true)) !== false) {
|
||||
$rules[$index] = 'sometimes';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
})->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Customer;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ActivateCustomerRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'package_profile_id' => ['required', 'integer', 'exists:nas_package_profiles,id'],
|
||||
'nas_mikrotik_id' => ['required', 'integer', 'exists:nas_mikrotiks,id'],
|
||||
'billing_profile_id' => ['required', 'integer', 'exists:billing_profiles,id'],
|
||||
'topology_id' => ['nullable', 'integer', 'min:1'],
|
||||
'external_username' => ['nullable', 'string', 'max:255'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Customer;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class IndexCustomerRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['nullable', 'string', 'max:255'],
|
||||
'source' => ['nullable', Rule::in(['manual', 'mikrotik', 'radius'])],
|
||||
'page' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
'sort_by' => ['nullable', Rule::in(['id', 'customer_code', 'name', 'email', 'whatsapp_number', 'status', 'order_stage', 'created_at', 'activated_at'])],
|
||||
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Customer;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreCustomerRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'user_id' => ['nullable', 'integer', 'exists:users,id'],
|
||||
'customer_code' => ['nullable', 'string', 'max:100'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'identity_number' => ['nullable', 'string', 'max:100'],
|
||||
'email' => ['nullable', 'email', 'max:255'],
|
||||
'whatsapp_number' => ['nullable', 'string', 'max:50'],
|
||||
'installation_address' => ['nullable', 'string'],
|
||||
'provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
|
||||
'kabupaten_id' => ['nullable', 'integer', 'exists:wilayah_kabupaten,id'],
|
||||
'kecamatan_id' => ['nullable', 'integer', 'exists:wilayah_kecamatan,id'],
|
||||
'desa_id' => ['nullable', 'integer', 'exists:wilayah_desa,id'],
|
||||
'latitude' => ['nullable', 'numeric', 'between:-90,90'],
|
||||
'longitude' => ['nullable', 'numeric', 'between:-180,180'],
|
||||
'package_profile_id' => ['nullable', 'integer', 'exists:nas_package_profiles,id'],
|
||||
'nas_mikrotik_id' => ['nullable', 'integer', 'exists:nas_mikrotiks,id'],
|
||||
'billing_profile_id' => ['nullable', 'integer', 'min:1'],
|
||||
'topology_id' => ['nullable', 'integer', 'min:1'],
|
||||
'external_username' => ['nullable', 'string', 'max:255'],
|
||||
'source' => ['nullable', Rule::in(['manual', 'mikrotik', 'radius'])],
|
||||
'order_stage' => ['nullable', Rule::in(['registration', 'data_completion', 'ready_activation', 'activation_failed'])],
|
||||
'notes' => ['nullable', 'string'],
|
||||
'images' => ['nullable', 'array', 'max:20'],
|
||||
'images.*.stored_file_id' => ['required', 'integer', 'exists:stored_files,id'],
|
||||
'images.*.category' => ['required', Rule::in(['house', 'installation', 'modem', 'odp', 'cable', 'identity', 'other'])],
|
||||
'images.*.caption' => ['nullable', 'string', 'max:255'],
|
||||
'images.*.is_cover' => ['nullable', 'boolean'],
|
||||
'images.*.sort_order' => ['nullable', 'integer', 'min:0', 'max:1000'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Customer;
|
||||
|
||||
class UpdateCustomerRequest extends StoreCustomerRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = parent::rules();
|
||||
$rules['name'] = ['sometimes', 'required', 'string', 'max:255'];
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,13 @@ class StoreFileRequest extends FormRequest
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
$maxSize = $this->input('category') === 'customer-image' ? 500 : 20480;
|
||||
|
||||
return [
|
||||
'file' => [
|
||||
'required',
|
||||
'file',
|
||||
'max:20480',
|
||||
"max:{$maxSize}",
|
||||
'mimes:jpg,jpeg,png,webp,gif,pdf,doc,docx,xls,xlsx,csv,txt,zip',
|
||||
],
|
||||
'category' => ['nullable', 'string', 'max:80', 'regex:/^[a-z0-9_-]+$/'],
|
||||
@@ -27,7 +29,9 @@ class StoreFileRequest extends FormRequest
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'file.max' => 'Ukuran file maksimal 20 MB.',
|
||||
'file.max' => $this->input('category') === 'customer-image'
|
||||
? 'Gambar customer maksimal 500 KB setelah kompresi.'
|
||||
: 'Ukuran file maksimal 20 MB.',
|
||||
'file.mimes' => 'Jenis file tidak didukung.',
|
||||
'category.regex' => 'Kategori hanya boleh berisi huruf kecil, angka, garis bawah, atau tanda hubung.',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class IndexNotificationRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['nullable', 'string', 'max:255'],
|
||||
'status' => ['nullable', 'string', 'max:30'],
|
||||
'unread' => ['nullable', 'boolean'],
|
||||
'page' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SaveNotificationPreferencesRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'preferences' => ['required', 'array'],
|
||||
'preferences.*.tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'preferences.*.notification_event_id' => ['required', 'integer', 'exists:notification_events,id'],
|
||||
'preferences.*.notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
|
||||
'preferences.*.channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
|
||||
'preferences.*.enabled' => ['required', 'boolean'],
|
||||
'preferences.*.priority' => ['nullable', 'integer', 'between:1,20'],
|
||||
'preferences.*.send_delay_minutes' => ['nullable', 'integer', 'between:0,10080'],
|
||||
'preferences.*.quiet_hours_start' => ['nullable', 'date_format:H:i'],
|
||||
'preferences.*.quiet_hours_end' => ['nullable', 'date_format:H:i'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreCustomerContactRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'type' => ['required', Rule::in(['email', 'whatsapp', 'telegram'])],
|
||||
'value' => ['required', 'string', 'max:255'],
|
||||
'label' => ['nullable', 'string', 'max:100'],
|
||||
'is_primary' => ['nullable', 'boolean'],
|
||||
'is_verified' => ['nullable', 'boolean'],
|
||||
'can_receive_transactional' => ['nullable', 'boolean'],
|
||||
'can_receive_broadcast' => ['nullable', 'boolean'],
|
||||
'opted_out_at' => ['nullable', 'date'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreNotificationBroadcastRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'name' => ['required_without:preview', 'string', 'max:255'],
|
||||
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
|
||||
'notification_template_id' => ['nullable', 'integer', 'exists:notification_templates,id'],
|
||||
'notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
|
||||
'subject' => ['nullable', 'string', 'max:255'],
|
||||
'body' => ['required_without:notification_template_id', 'nullable', 'string', 'max:20000'],
|
||||
'scheduled_at' => ['nullable', 'date'],
|
||||
'filters' => ['nullable', 'array'],
|
||||
'filters.customer_status' => ['nullable', 'array'],
|
||||
'filters.customer_status.*' => [Rule::in(['order', 'active', 'inactive', 'unmanaged'])],
|
||||
'filters.source' => ['nullable', Rule::in(['manual', 'nas'])],
|
||||
'filters.package_profile_id' => ['nullable', 'integer'],
|
||||
'filters.billing_profile_id' => ['nullable', 'integer'],
|
||||
'filters.topology_node_id' => ['nullable', 'integer', 'exists:topology_nodes,id'],
|
||||
'filters.provinsi_id' => ['nullable', 'integer'],
|
||||
'filters.kabupaten_id' => ['nullable', 'integer'],
|
||||
'filters.kecamatan_id' => ['nullable', 'integer'],
|
||||
'filters.desa_id' => ['nullable', 'integer'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreNotificationChannelRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
|
||||
'provider' => ['nullable', 'string', 'max:50'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'enabled' => ['nullable', 'boolean'],
|
||||
'is_default' => ['nullable', 'boolean'],
|
||||
'credentials' => ['nullable', 'array'],
|
||||
'credentials.*' => ['nullable', 'string', 'max:4000'],
|
||||
'settings' => ['nullable', 'array'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Notification;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreNotificationTemplateRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'notification_event_id' => ['required', 'integer', 'exists:notification_events,id'],
|
||||
'notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
|
||||
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'subject' => ['nullable', 'string', 'max:255'],
|
||||
'body' => ['required', 'string', 'max:20000'],
|
||||
'provider_template_name' => ['nullable', 'string', 'max:255'],
|
||||
'provider_template_id' => ['nullable', 'string', 'max:255'],
|
||||
'language' => ['nullable', 'string', 'max:10'],
|
||||
'approval_status' => ['nullable', Rule::in(['not_required', 'pending', 'approved', 'rejected'])],
|
||||
'enabled' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Payment;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class IndexPaymentRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['nullable', 'string', 'max:100'], 'status' => ['nullable', 'string', 'max:30'],
|
||||
'provider_code' => ['nullable', 'string', 'max:50'], 'purpose' => ['nullable', 'string', 'max:30'],
|
||||
'date_from' => ['nullable', 'date'], 'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
'sort_by' => ['nullable', Rule::in(['id', 'transaction_number', 'amount', 'status', 'created_at', 'paid_at'])],
|
||||
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Payment;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SaveTenantPaymentSettingRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'payment_mode' => ['required', Rule::in(['disabled', 'tenant_gateway', 'platform_gateway'])],
|
||||
'tenant_gateway_account_id' => ['nullable', 'integer', 'exists:payment_gateway_accounts,id'],
|
||||
'platform_gateway_account_id' => ['nullable', 'integer', 'exists:payment_gateway_accounts,id'],
|
||||
'fee_bearer' => ['required', Rule::in(['customer', 'tenant', 'platform'])],
|
||||
'default_expiry_minutes' => ['required', 'integer', 'min:5', 'max:10080'],
|
||||
'enabled_methods' => ['nullable', 'array'],
|
||||
'enabled_methods.*' => ['string', 'max:50'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Payment;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreGatewayAccountRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'payment_provider_id' => ['required', 'integer', 'exists:payment_providers,id'],
|
||||
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
|
||||
'scope' => ['required', Rule::in(['tenant', 'platform'])],
|
||||
'name' => ['required', 'string', 'max:150'],
|
||||
'environment' => ['required', Rule::in(['sandbox', 'production'])],
|
||||
'credentials' => ['nullable', 'array'],
|
||||
'credentials.*' => ['nullable', 'string', 'max:4000'],
|
||||
'webhook_secret' => ['nullable', 'string', 'max:4000'],
|
||||
'settings' => ['nullable', 'array'],
|
||||
'enabled' => ['sometimes', 'boolean'],
|
||||
'is_default' => ['sometimes', 'boolean'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Topology;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class IndexTopologyRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'search' => ['nullable', 'string', 'max:255'],
|
||||
'status' => ['nullable', 'string', 'max:30'],
|
||||
'device_type_id' => ['nullable', 'integer', 'exists:topology_device_types,id'],
|
||||
'link_type' => ['nullable', Rule::in(['fiber', 'wireless', 'ethernet', 'logical'])],
|
||||
'bbox' => ['nullable', 'regex:/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/'],
|
||||
'page' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
'sort_by' => ['nullable', Rule::in(['id', 'code', 'name', 'status', 'category', 'link_type', 'installed_at', 'created_at'])],
|
||||
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Topology;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreCustomerConnectionRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'customer_id' => ['required', 'integer', 'exists:customers,id'],
|
||||
'odp_node_id' => ['required', 'integer', 'exists:topology_nodes,id'],
|
||||
'odp_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
|
||||
'drop_cable_link_id' => ['nullable', 'integer', 'exists:topology_links,id'],
|
||||
'connected_at' => ['nullable', 'date'],
|
||||
'status' => ['nullable', Rule::in(['active', 'inactive'])],
|
||||
'metadata' => ['nullable', 'array'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Topology;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreTopologyRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return match ($this->route()->defaults['topology_resource'] ?? null) {
|
||||
'device-type' => [
|
||||
...$this->tenantRule(),
|
||||
'code' => ['required', 'string', 'max:50'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'category' => ['required', Rule::in(['site', 'termination', 'closure', 'distribution', 'splitter', 'other'])],
|
||||
'can_have_ports' => ['nullable', 'boolean'],
|
||||
'can_have_splitters' => ['nullable', 'boolean'],
|
||||
'icon' => ['nullable', 'string', 'max:100'],
|
||||
'color' => ['nullable', 'regex:/^#[0-9a-fA-F]{6}$/'],
|
||||
'status' => ['nullable', Rule::in(['active', 'inactive'])],
|
||||
],
|
||||
'node' => [
|
||||
...$this->tenantRule(),
|
||||
'device_type_id' => ['required', 'integer', 'exists:topology_device_types,id'],
|
||||
'parent_node_id' => ['nullable', 'integer', 'exists:topology_nodes,id'],
|
||||
'code' => ['required', 'string', 'max:100'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'status' => ['nullable', Rule::in(['active', 'inactive', 'maintenance', 'damaged'])],
|
||||
'latitude' => ['required', 'numeric', 'between:-90,90'],
|
||||
'longitude' => ['required', 'numeric', 'between:-180,180'],
|
||||
'address' => ['nullable', 'string'],
|
||||
'provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
|
||||
'kabupaten_id' => ['nullable', 'integer', 'exists:wilayah_kabupaten,id'],
|
||||
'kecamatan_id' => ['nullable', 'integer', 'exists:wilayah_kecamatan,id'],
|
||||
'desa_id' => ['nullable', 'integer', 'exists:wilayah_desa,id'],
|
||||
'capacity' => ['nullable', 'integer', 'min:0'],
|
||||
'installed_at' => ['nullable', 'date'],
|
||||
'diagram_x' => ['nullable', 'numeric'],
|
||||
'diagram_y' => ['nullable', 'numeric'],
|
||||
'metadata' => ['nullable', 'array'],
|
||||
],
|
||||
'link' => [
|
||||
...$this->tenantRule(),
|
||||
'source_node_id' => ['required', 'integer', 'exists:topology_nodes,id', 'different:target_node_id'],
|
||||
'source_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
|
||||
'target_node_id' => ['required', 'integer', 'exists:topology_nodes,id'],
|
||||
'target_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
|
||||
'code' => ['required', 'string', 'max:100'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'link_type' => ['required', Rule::in(['fiber', 'wireless', 'ethernet', 'logical'])],
|
||||
'fiber_type' => ['nullable', 'string', 'max:50'],
|
||||
'core_count' => ['nullable', 'integer', 'min:1'],
|
||||
'cable_length' => ['nullable', 'numeric', 'min:0'],
|
||||
'measured_length' => ['nullable', 'numeric', 'min:0'],
|
||||
'path_geojson' => ['nullable', 'array'],
|
||||
'path_geojson.type' => ['required_with:path_geojson', Rule::in(['LineString'])],
|
||||
'path_geojson.coordinates' => ['required_with:path_geojson', 'array', 'min:2'],
|
||||
'path_geojson.coordinates.*' => ['array', 'size:2'],
|
||||
'path_geojson.coordinates.*.*' => ['numeric'],
|
||||
'status' => ['nullable', Rule::in(['active', 'inactive', 'maintenance', 'damaged'])],
|
||||
'installed_at' => ['nullable', 'date'],
|
||||
'metadata' => ['nullable', 'array'],
|
||||
],
|
||||
'port' => [
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'port_number' => ['required', 'integer', 'min:1'],
|
||||
'port_type' => ['required', Rule::in(['fiber', 'ethernet', 'pon', 'uplink', 'splitter', 'other'])],
|
||||
'direction' => ['required', Rule::in(['input', 'output', 'bidirectional'])],
|
||||
'capacity' => ['nullable', 'integer', 'min:1'],
|
||||
'status' => ['nullable', Rule::in(['available', 'used', 'reserved', 'damaged'])],
|
||||
'metadata' => ['nullable', 'array'],
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
private function tenantRule(): array
|
||||
{
|
||||
return ['tenant_id' => ['nullable', 'integer', 'exists:tenants,id']];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Topology;
|
||||
|
||||
class UpdateTopologyRequest extends StoreTopologyRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return collect(parent::rules())->map(function ($rules) {
|
||||
$rules = is_array($rules) ? $rules : [$rules];
|
||||
if (($index = array_search('required', $rules, true)) !== false) {
|
||||
$rules[$index] = 'sometimes';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
})->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Wallet;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreWithdrawalRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'amount' => ['required', 'numeric', 'min:10000'], 'fee' => ['nullable', 'numeric', 'min:0'],
|
||||
'bank_code' => ['required', 'string', 'max:30'], 'account_number' => ['required', 'string', 'max:50'],
|
||||
'account_name' => ['required', 'string', 'max:150'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Wallet;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TransferWalletRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return ['destination_wallet_id' => ['required', 'integer', 'exists:wallets,id'], 'amount' => ['required', 'numeric', 'min:1']];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Billing;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BillingProfileResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [...parent::toArray($request), 'tenant' => $this->whenLoaded('tenant')];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Billing;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class InvoiceResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
...parent::toArray($request),
|
||||
'tenant' => $this->whenLoaded('tenant'),
|
||||
'customer' => $this->whenLoaded('customer'),
|
||||
'billing_profile' => $this->whenLoaded('billingProfile'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Customer;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CustomerResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$data = parent::toArray($request);
|
||||
unset($data['images'], $data['cover_image']);
|
||||
|
||||
return [
|
||||
...$data,
|
||||
'tenant' => $this->whenLoaded('tenant'),
|
||||
'provinsi' => $this->whenLoaded('provinsi'),
|
||||
'kabupaten' => $this->whenLoaded('kabupaten'),
|
||||
'kecamatan' => $this->whenLoaded('kecamatan'),
|
||||
'desa' => $this->whenLoaded('desa'),
|
||||
'package_profile' => $this->whenLoaded('packageProfile'),
|
||||
'nas_mikrotik' => $this->whenLoaded('nasMikrotik'),
|
||||
'billing_profile' => $this->whenLoaded('billingProfile'),
|
||||
'images' => $this->whenLoaded('images', fn () => $this->images->map(fn ($image) => [
|
||||
'id' => $image->id,
|
||||
'stored_file_id' => $image->stored_file_id,
|
||||
'uuid' => $image->file?->uuid,
|
||||
'original_name' => $image->file?->original_name,
|
||||
'category' => $image->category,
|
||||
'caption' => $image->caption,
|
||||
'is_cover' => $image->is_cover,
|
||||
'sort_order' => $image->sort_order,
|
||||
])->values()),
|
||||
'cover_image' => $this->whenLoaded('coverImage', fn () => $this->coverImage ? [
|
||||
'stored_file_id' => $this->coverImage->stored_file_id,
|
||||
'uuid' => $this->coverImage->file?->uuid,
|
||||
'original_name' => $this->coverImage->file?->original_name,
|
||||
'size' => $this->coverImage->file?->size,
|
||||
] : null),
|
||||
'full_installation_address' => collect([
|
||||
$this->installation_address,
|
||||
$this->desa?->nama,
|
||||
$this->kecamatan?->nama,
|
||||
$this->kabupaten?->nama,
|
||||
$this->provinsi?->nama,
|
||||
])->filter()->implode(', '),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Notification;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class NotificationDeliveryResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$destination = (string) $this->destination;
|
||||
$masked = strlen($destination) > 6
|
||||
? substr($destination, 0, 3).str_repeat('*', max(3, strlen($destination) - 6)).substr($destination, -3)
|
||||
: str_repeat('*', strlen($destination));
|
||||
|
||||
return [
|
||||
...parent::toArray($request),
|
||||
'destination' => $masked,
|
||||
'message' => $this->whenLoaded('message'),
|
||||
'channel_config' => $this->whenLoaded('channelConfig'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Payment;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class PaymentTransactionResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id, 'uuid' => $this->uuid, 'transaction_number' => $this->transaction_number,
|
||||
'tenant' => $this->whenLoaded('tenant'), 'user' => $this->whenLoaded('user'),
|
||||
'customer' => $this->whenLoaded('customer'), 'invoice' => $this->whenLoaded('invoice'),
|
||||
'provider' => $this->account?->provider, 'gateway_scope' => $this->gateway_scope,
|
||||
'purpose' => $this->purpose, 'method' => $this->method, 'amount' => $this->amount,
|
||||
'provider_fee' => $this->provider_fee, 'platform_fee' => $this->platform_fee,
|
||||
'total_amount' => $this->total_amount, 'currency' => $this->currency, 'status' => $this->status,
|
||||
'provider_status' => $this->provider_status, 'provider_reference' => $this->provider_reference,
|
||||
'expires_at' => $this->expires_at, 'paid_at' => $this->paid_at, 'created_at' => $this->created_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Topology;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class TopologyResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
...parent::toArray($request),
|
||||
'tenant' => $this->whenLoaded('tenant'),
|
||||
'device_type' => $this->whenLoaded('deviceType'),
|
||||
'parent' => $this->whenLoaded('parent'),
|
||||
'ports' => $this->whenLoaded('ports'),
|
||||
'source_node' => $this->whenLoaded('sourceNode'),
|
||||
'target_node' => $this->whenLoaded('targetNode'),
|
||||
'source_port' => $this->whenLoaded('sourcePort'),
|
||||
'target_port' => $this->whenLoaded('targetPort'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user