172 lines
8.5 KiB
PHP
172 lines
8.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Activity;
|
|
use App\Models\Client;
|
|
use App\Models\ClientCase;
|
|
use App\Models\Contract;
|
|
use Illuminate\Http\Request;
|
|
use Inertia\Inertia;
|
|
|
|
class NotificationController extends Controller
|
|
{
|
|
public function unread(Request $request)
|
|
{
|
|
$user = $request->user();
|
|
if (! $user) {
|
|
abort(403);
|
|
}
|
|
|
|
$today = now()->toDateString();
|
|
$perPage = max(1, min(100, (int) $request->integer('perPage', 15)));
|
|
$search = trim((string) $request->input('search', ''));
|
|
$clientUuid = trim((string) $request->input('client', ''));
|
|
$clientId = null;
|
|
$clientCaseIdsForFilter = collect();
|
|
if ($clientUuid !== '') {
|
|
$clientId = Client::query()->where('uuid', $clientUuid)->value('id');
|
|
if ($clientId) {
|
|
$clientCaseIdsForFilter = ClientCase::query()->where('client_id', $clientId)->pluck('id');
|
|
}
|
|
}
|
|
|
|
$query = Activity::query()
|
|
->select(['id', 'due_date', 'amount', 'contract_id', 'client_case_id', 'created_at'])
|
|
->whereNotNull('due_date')
|
|
->whereDate('due_date', '<=', $today)
|
|
// Exclude activities that have been marked as read by this user
|
|
->whereNotExists(function ($q) use ($user, $today) {
|
|
$q->select(\DB::raw(1))
|
|
->from('activity_notification_reads')
|
|
->whereColumn('activity_notification_reads.activity_id', 'activities.id')
|
|
->where('activity_notification_reads.user_id', $user->id)
|
|
->whereDate('activity_notification_reads.due_date', '<=', $today)
|
|
->whereNotNull('activity_notification_reads.read_at');
|
|
})
|
|
->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) {
|
|
// Filter by clients: activities directly on any of the client's cases OR via contracts under those cases
|
|
$q->where(function ($qq) use ($clientCaseIdsForFilter) {
|
|
$qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter)
|
|
->orWhereIn('activities.contract_id', Contract::query()
|
|
->select('id')
|
|
->whereIn('client_case_id', $clientCaseIdsForFilter)
|
|
);
|
|
});
|
|
})
|
|
// allow simple search by contract reference or person name
|
|
->when($search !== '', function ($q) use ($search) {
|
|
$s = mb_strtolower($search);
|
|
$q->leftJoin('contracts', 'contracts.id', '=', 'activities.contract_id')
|
|
->leftJoin('client_cases', 'client_cases.id', '=', 'activities.client_case_id')
|
|
->leftJoin('person', 'person.id', '=', 'client_cases.person_id')
|
|
->where(function ($qq) use ($s) {
|
|
$qq->whereRaw('LOWER(COALESCE(contracts.reference, \'\')) LIKE ?', ['%'.$s.'%'])
|
|
->orWhereRaw('LOWER(COALESCE(person.full_name, \'\')) LIKE ?', ['%'.$s.'%']);
|
|
});
|
|
})
|
|
->with([
|
|
'contract' => function ($q) {
|
|
$q->select(['contracts.id', 'contracts.uuid', 'contracts.reference', 'contracts.client_case_id'])
|
|
->with([
|
|
'clientCase' => function ($qq) {
|
|
$qq->select(['client_cases.id', 'client_cases.uuid', 'client_cases.client_id'])
|
|
->with([
|
|
'client' => function ($qqq) {
|
|
$qqq->select(['clients.id', 'clients.uuid', 'clients.person_id'])
|
|
->with([
|
|
'person' => function ($qqqq) {
|
|
$qqqq->select(['person.id', 'person.full_name']);
|
|
},
|
|
]);
|
|
},
|
|
]);
|
|
},
|
|
'account' => function ($qq) {
|
|
$qq->select(['accounts.id', 'accounts.contract_id', 'accounts.balance_amount', 'accounts.initial_amount']);
|
|
},
|
|
]);
|
|
},
|
|
'clientCase' => function ($q) {
|
|
$q->select(['client_cases.id', 'client_cases.uuid', 'client_cases.person_id', 'client_cases.client_id'])
|
|
->with([
|
|
'person' => function ($qq) {
|
|
$qq->select(['person.id', 'person.full_name']);
|
|
},
|
|
'client' => function ($qq) {
|
|
$qq->select(['clients.id', 'clients.uuid', 'clients.person_id'])
|
|
->with([
|
|
'person' => function ($qqq) {
|
|
$qqq->select(['person.id', 'person.full_name']);
|
|
},
|
|
]);
|
|
},
|
|
]);
|
|
},
|
|
])
|
|
// force ordering by due_date DESC only
|
|
->orderByDesc('activities.due_date');
|
|
|
|
// Use a custom page parameter name to match the frontend DataTableServer
|
|
$activities = $query->paginate($perPage, ['*'], 'unread-page')->withQueryString();
|
|
|
|
// Build a distinct clients list for the filter (client UUID + client.person.full_name)
|
|
// Collect client_case_ids from both direct activities and via contracts
|
|
$baseForClients = Activity::query()
|
|
->select(['contract_id', 'client_case_id'])
|
|
->whereNotNull('due_date')
|
|
->whereDate('due_date', '<=', $today)
|
|
// Exclude activities that have been marked as read by this user
|
|
->whereNotExists(function ($q) use ($user, $today) {
|
|
$q->select(\DB::raw(1))
|
|
->from('activity_notification_reads')
|
|
->whereColumn('activity_notification_reads.activity_id', 'activities.id')
|
|
->where('activity_notification_reads.user_id', $user->id)
|
|
->whereDate('activity_notification_reads.due_date', '<=', $today)
|
|
->whereNotNull('activity_notification_reads.read_at');
|
|
})
|
|
->when($clientCaseIdsForFilter->isNotEmpty(), function ($q) use ($clientCaseIdsForFilter) {
|
|
$q->where(function ($qq) use ($clientCaseIdsForFilter) {
|
|
$qq->whereIn('activities.client_case_id', $clientCaseIdsForFilter)
|
|
->orWhereIn('activities.contract_id', Contract::query()->select('id')->whereIn('client_case_id', $clientCaseIdsForFilter));
|
|
});
|
|
})
|
|
->get();
|
|
|
|
$contractIds = $baseForClients->pluck('contract_id')->filter()->unique()->values();
|
|
$directCaseIds = $baseForClients->pluck('client_case_id')->filter()->unique()->values();
|
|
$mapContractToCase = $contractIds->isNotEmpty()
|
|
? Contract::query()->whereIn('id', $contractIds)->pluck('client_case_id', 'id')
|
|
: collect();
|
|
$caseIds = $directCaseIds
|
|
->merge($contractIds->map(fn ($cid) => $mapContractToCase->get($cid)))
|
|
->filter()
|
|
->unique()
|
|
->values();
|
|
|
|
// Map caseIds -> clientIds, then load clients and present as value(label)
|
|
$clientIds = $caseIds->isNotEmpty()
|
|
? ClientCase::query()->whereIn('id', $caseIds)->pluck('client_id')->filter()->unique()->values()
|
|
: collect();
|
|
|
|
$clients = $clientIds->isNotEmpty()
|
|
? Client::query()
|
|
->whereIn('id', $clientIds)
|
|
->with(['person:id,full_name'])
|
|
->get(['id', 'uuid', 'person_id'])
|
|
->map(fn ($c) => [
|
|
'value' => $c->uuid,
|
|
'label' => optional($c->person)->full_name ?: '(neznana stranka)',
|
|
])
|
|
->sortBy('label', SORT_NATURAL | SORT_FLAG_CASE)
|
|
->values()
|
|
: collect();
|
|
|
|
return Inertia::render('Notifications/Unread', [
|
|
'activities' => $activities,
|
|
'today' => $today,
|
|
'clients' => $clients,
|
|
]);
|
|
}
|
|
}
|