Emergency button for missing persons
This commit is contained in:
parent
c177264b0b
commit
86898eac1a
|
|
@ -228,11 +228,12 @@ public function updateContract(ClientCase $clientCase, string $uuid, UpdateContr
|
|||
public function debugContractAccounts(ClientCase $clientCase, string $uuid, Request $request)
|
||||
{
|
||||
abort_unless(config('app.debug'), 404);
|
||||
$contract = $clientCase->contracts()->where('uuid', $uuid)->firstOrFail(['id','uuid','reference']);
|
||||
$contract = $clientCase->contracts()->where('uuid', $uuid)->firstOrFail(['id', 'uuid', 'reference']);
|
||||
$accounts = \DB::table('accounts')
|
||||
->where('contract_id', $contract->id)
|
||||
->orderBy('id')
|
||||
->get(['id','contract_id','initial_amount','balance_amount','type_id','created_at','updated_at']);
|
||||
->get(['id', 'contract_id', 'initial_amount', 'balance_amount', 'type_id', 'created_at', 'updated_at']);
|
||||
|
||||
return response()->json([
|
||||
'contract' => $contract,
|
||||
'accounts' => $accounts,
|
||||
|
|
@ -1108,7 +1109,7 @@ public function show(ClientCase $clientCase)
|
|||
logger()->info('Show contracts balances', [
|
||||
'case_id' => $case->id,
|
||||
'contract_count' => $contracts->count(),
|
||||
'contracts' => $contracts->map(fn($c) => [
|
||||
'contracts' => $contracts->map(fn ($c) => [
|
||||
'id' => $c->id,
|
||||
'uuid' => $c->uuid,
|
||||
'reference' => $c->reference,
|
||||
|
|
@ -1330,8 +1331,6 @@ public function archiveContract(ClientCase $clientCase, string $uuid, Request $r
|
|||
$hasReactivateRule = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$executor = app(\App\Services\Archiving\ArchiveExecutor::class);
|
||||
$context = [
|
||||
'contract_id' => $contract->id,
|
||||
|
|
@ -1475,4 +1474,70 @@ public function archiveContract(ClientCase $clientCase, string $uuid, Request $r
|
|||
|
||||
return back()->with('success', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emergency: recreate a missing / soft-deleted person for a client case and re-link related data.
|
||||
*/
|
||||
public function emergencyCreatePerson(ClientCase $clientCase, Request $request)
|
||||
{
|
||||
$oldPersonId = $clientCase->person_id;
|
||||
/** @var \App\Models\Person\Person|null $existing */
|
||||
$existing = \App\Models\Person\Person::withTrashed()->find($oldPersonId);
|
||||
if ($existing && ! $existing->trashed()) {
|
||||
return back()->with('flash', [
|
||||
'type' => 'info',
|
||||
'message' => 'Person already exists – emergency creation not needed.',
|
||||
]);
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'full_name' => ['nullable', 'string', 'max:255'],
|
||||
'first_name' => ['nullable', 'string', 'max:255'],
|
||||
'last_name' => ['nullable', 'string', 'max:255'],
|
||||
'tax_number' => ['nullable', 'string', 'max:99'],
|
||||
'social_security_number' => ['nullable', 'string', 'max:99'],
|
||||
'description' => ['nullable', 'string', 'max:500'],
|
||||
]);
|
||||
|
||||
$fullName = $data['full_name'] ?? trim(($data['first_name'] ?? '').' '.($data['last_name'] ?? ''));
|
||||
if ($fullName === '') {
|
||||
$fullName = 'Unknown Person';
|
||||
}
|
||||
|
||||
$newPerson = null;
|
||||
|
||||
\DB::transaction(function () use ($oldPersonId, $clientCase, $fullName, $data, &$newPerson) {
|
||||
$newPerson = \App\Models\Person\Person::create([
|
||||
'nu' => null,
|
||||
'first_name' => $data['first_name'] ?? null,
|
||||
'last_name' => $data['last_name'] ?? null,
|
||||
'full_name' => $fullName,
|
||||
'gender' => null,
|
||||
'birthday' => null,
|
||||
'tax_number' => $data['tax_number'] ?? null,
|
||||
'social_security_number' => $data['social_security_number'] ?? null,
|
||||
'description' => $data['description'] ?? 'Emergency recreated person (case)',
|
||||
'group_id' => 2,
|
||||
'type_id' => 1,
|
||||
]);
|
||||
|
||||
// Re-point related data referencing old person
|
||||
$tables = [
|
||||
'emails', 'person_phones', 'person_addresses', 'bank_accounts',
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
\DB::table($table)->where('person_id', $oldPersonId)->update(['person_id' => $newPerson->id]);
|
||||
}
|
||||
|
||||
// Update the client case
|
||||
$clientCase->person_id = $newPerson->id;
|
||||
$clientCase->save();
|
||||
});
|
||||
|
||||
return back()->with('flash', [
|
||||
'type' => 'success',
|
||||
'message' => 'New person created and case re-linked.',
|
||||
'person_uuid' => $newPerson?->uuid,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,4 +158,75 @@ public function update(Client $client, Request $request)
|
|||
|
||||
return to_route('client.show', $client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emergency endpoint: if the linked person record is missing (hard deleted) or soft deleted,
|
||||
* create a new minimal Person and re-point all related child records (emails, phones, addresses, bank accounts,
|
||||
* client cases) from the old person_id to the new one, then update the client itself.
|
||||
*/
|
||||
public function emergencyCreatePerson(Client $client, Request $request)
|
||||
{
|
||||
$oldPersonId = $client->person_id;
|
||||
|
||||
// If person exists and is not trashed, abort – nothing to do
|
||||
/** @var \App\Models\Person\Person|null $existing */
|
||||
$existing = \App\Models\Person\Person::withTrashed()->find($oldPersonId);
|
||||
if ($existing && ! $existing->trashed()) {
|
||||
return redirect()->back()->with('flash', [
|
||||
'type' => 'info',
|
||||
'message' => 'Person already exists – emergency creation not needed.',
|
||||
]);
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'full_name' => ['nullable', 'string', 'max:255'],
|
||||
'first_name' => ['nullable', 'string', 'max:255'],
|
||||
'last_name' => ['nullable', 'string', 'max:255'],
|
||||
'tax_number' => ['nullable', 'string', 'max:99'],
|
||||
'social_security_number' => ['nullable', 'string', 'max:99'],
|
||||
'description' => ['nullable', 'string', 'max:500'],
|
||||
]);
|
||||
|
||||
// Provide sensible fallbacks.
|
||||
$fullName = $data['full_name'] ?? trim(($data['first_name'] ?? '').' '.($data['last_name'] ?? ''));
|
||||
if ($fullName === '') {
|
||||
$fullName = 'Unknown Person';
|
||||
}
|
||||
|
||||
$newPerson = null;
|
||||
|
||||
\DB::transaction(function () use ($oldPersonId, $client, $fullName, $data, &$newPerson) {
|
||||
$newPerson = \App\Models\Person\Person::create([
|
||||
'nu' => null, // boot event will generate
|
||||
'first_name' => $data['first_name'] ?? null,
|
||||
'last_name' => $data['last_name'] ?? null,
|
||||
'full_name' => $fullName,
|
||||
'gender' => null,
|
||||
'birthday' => null,
|
||||
'tax_number' => $data['tax_number'] ?? null,
|
||||
'social_security_number' => $data['social_security_number'] ?? null,
|
||||
'description' => $data['description'] ?? 'Emergency recreated person',
|
||||
'group_id' => 1,
|
||||
'type_id' => 2,
|
||||
]);
|
||||
|
||||
// Re-point related records referencing the old (missing) person id
|
||||
$tables = [
|
||||
'emails', 'person_phones', 'person_addresses', 'bank_accounts', 'client_cases',
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
\DB::table($table)->where('person_id', $oldPersonId)->update(['person_id' => $newPerson->id]);
|
||||
}
|
||||
|
||||
// Finally update the client itself (only this one; avoid touching other potential clients)
|
||||
$client->person_id = $newPerson->id;
|
||||
$client->save();
|
||||
});
|
||||
|
||||
return redirect()->back()->with('flash', [
|
||||
'type' => 'success',
|
||||
'message' => 'New person created and related records re-linked.',
|
||||
'person_uuid' => $newPerson?->uuid,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,30 +3,35 @@
|
|||
namespace App\Models\Person;
|
||||
|
||||
use App\Traits\Uuid;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Laravel\Scout\Searchable;
|
||||
|
||||
class Person extends Model
|
||||
{
|
||||
use HasApiTokens;
|
||||
|
||||
/** @use HasFactory<\Database\Factories\Person/PersonFactory> */
|
||||
use HasFactory;
|
||||
use Uuid;
|
||||
use Searchable;
|
||||
|
||||
/**
|
||||
use Searchable;
|
||||
use SoftDeletes;
|
||||
use Uuid;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $table = 'person';
|
||||
|
||||
protected $fillable = [
|
||||
'nu',
|
||||
'first_name',
|
||||
|
|
@ -39,18 +44,19 @@ class Person extends Model
|
|||
'description',
|
||||
'group_id',
|
||||
'type_id',
|
||||
'user_id'
|
||||
'user_id',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'id',
|
||||
'deleted',
|
||||
'user_id'
|
||||
'user_id',
|
||||
];
|
||||
|
||||
protected static function booted(){
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (Person $person) {
|
||||
if(!isset($person->user_id)){
|
||||
if (! isset($person->user_id)) {
|
||||
$person->user_id = auth()->id();
|
||||
}
|
||||
// Ensure a unique 6-character alphanumeric 'nu' is set globally on create
|
||||
|
|
@ -72,16 +78,15 @@ public function toSearchableArray(): array
|
|||
'last_name' => '',
|
||||
'full_name' => '',
|
||||
'person_addresses.address' => '',
|
||||
'person_phones.nu' => ''
|
||||
'person_phones.nu' => '',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function phones(): HasMany
|
||||
{
|
||||
return $this->hasMany(\App\Models\Person\PersonPhone::class)
|
||||
->with(['type'])
|
||||
->where('active','=',1)
|
||||
->where('active', '=', 1)
|
||||
->orderBy('id');
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +94,7 @@ public function addresses(): HasMany
|
|||
{
|
||||
return $this->hasMany(\App\Models\Person\PersonAddress::class)
|
||||
->with(['type'])
|
||||
->where('active','=',1)
|
||||
->where('active', '=', 1)
|
||||
->orderBy('id');
|
||||
}
|
||||
|
||||
|
|
@ -135,6 +140,7 @@ protected static function generateUniqueNu(): string
|
|||
do {
|
||||
$nu = Str::random(6); // [A-Za-z0-9]
|
||||
} while (static::where('nu', $nu)->exists());
|
||||
|
||||
return $nu;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,18 @@ const fmtCurrency = (v) => {
|
|||
>
|
||||
{{ c.person?.full_name || "-" }}
|
||||
</Link>
|
||||
<button
|
||||
v-if="!c.person"
|
||||
@click.prevent="
|
||||
router.post(
|
||||
route('clientCase.emergencyPerson', { client_case: c.uuid })
|
||||
)
|
||||
"
|
||||
class="ml-2 inline-flex items-center rounded bg-red-50 px-2 py-0.5 text-xs font-semibold text-red-600 hover:bg-red-100 border border-red-200"
|
||||
title="Emergency: recreate missing person"
|
||||
>
|
||||
Add Person
|
||||
</button>
|
||||
</td>
|
||||
<td class="py-2 pr-4">{{ c.client?.person?.full_name || "-" }}</td>
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,17 @@ const fmtCurrency = (v) => {
|
|||
>
|
||||
{{ client.person?.full_name || "-" }}
|
||||
</Link>
|
||||
<div v-if="!client.person" class="mt-1">
|
||||
<PrimaryButton
|
||||
class="!py-0.5 !px-2 bg-red-500 hover:bg-red-600 text-xs"
|
||||
@click.prevent="
|
||||
router.post(
|
||||
route('client.emergencyPerson', { uuid: client.uuid })
|
||||
)
|
||||
"
|
||||
>Add Person</PrimaryButton
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-right">
|
||||
{{ client.cases_with_active_contracts_count ?? 0 }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
use App\Charts\ExampleChart;
|
||||
use App\Http\Controllers\AccountBookingController;
|
||||
use App\Http\Controllers\AccountPaymentController;
|
||||
use App\Http\Controllers\ArchiveSettingController;
|
||||
|
|
@ -19,7 +18,6 @@
|
|||
use App\Http\Controllers\SettingController;
|
||||
use App\Http\Controllers\WorkflowController;
|
||||
use App\Models\Person\Person;
|
||||
use ArielMejiaDev\LarapexCharts\LarapexChart;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Inertia\Inertia;
|
||||
|
|
@ -48,24 +46,26 @@
|
|||
Route::get('users', [\App\Http\Controllers\Admin\UserRoleController::class, 'index'])->name('users.index');
|
||||
Route::put('users/{user}', [\App\Http\Controllers\Admin\UserRoleController::class, 'update'])->name('users.update');
|
||||
|
||||
// Permissions management
|
||||
Route::get('permissions', [\App\Http\Controllers\Admin\PermissionController::class, 'index'])->name('permissions.index');
|
||||
Route::get('permissions/create', [\App\Http\Controllers\Admin\PermissionController::class, 'create'])->name('permissions.create');
|
||||
Route::post('permissions', [\App\Http\Controllers\Admin\PermissionController::class, 'store'])->name('permissions.store');
|
||||
// Permissions management
|
||||
Route::get('permissions', [\App\Http\Controllers\Admin\PermissionController::class, 'index'])->name('permissions.index');
|
||||
Route::get('permissions/create', [\App\Http\Controllers\Admin\PermissionController::class, 'create'])->name('permissions.create');
|
||||
Route::post('permissions', [\App\Http\Controllers\Admin\PermissionController::class, 'store'])->name('permissions.store');
|
||||
|
||||
// Document templates & global document settings
|
||||
Route::get('document-templates', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'index'])->name('document-templates.index');
|
||||
Route::post('document-templates', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'store'])->name('document-templates.store');
|
||||
Route::post('document-templates/{template}/toggle', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'toggleActive'])->name('document-templates.toggle');
|
||||
Route::put('document-templates/{template}/settings', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'updateSettings'])->name('document-templates.settings.update');
|
||||
Route::get('document-templates/{template}', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'show'])->name('document-templates.show');
|
||||
Route::get('document-templates/{template}/edit', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'edit'])->name('document-templates.edit');
|
||||
Route::get('document-templates/{template}', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'show'])->name('document-templates.show');
|
||||
Route::get('document-templates/{template}/edit', [\App\Http\Controllers\Admin\DocumentTemplateController::class, 'edit'])->name('document-templates.edit');
|
||||
Route::get('document-settings', [\App\Http\Controllers\Admin\DocumentSettingsController::class, 'edit'])->name('document-settings.index');
|
||||
Route::put('document-settings', [\App\Http\Controllers\Admin\DocumentSettingsController::class, 'update'])->name('document-settings.update');
|
||||
|
||||
// Mail profiles (dynamic outgoing mail configuration)
|
||||
Route::get('mail-profiles', [\App\Http\Controllers\Admin\MailProfileController::class, 'index'])->name('mail-profiles.index');
|
||||
Route::get('mail-profiles.json', function() { return \App\Models\MailProfile::query()->get(); })->name('mail-profiles.json');
|
||||
Route::get('mail-profiles.json', function () {
|
||||
return \App\Models\MailProfile::query()->get();
|
||||
})->name('mail-profiles.json');
|
||||
Route::post('mail-profiles', [\App\Http\Controllers\Admin\MailProfileController::class, 'store'])->name('mail-profiles.store');
|
||||
Route::put('mail-profiles/{mailProfile}', [\App\Http\Controllers\Admin\MailProfileController::class, 'update'])->name('mail-profiles.update');
|
||||
Route::post('mail-profiles/{mailProfile}/toggle', [\App\Http\Controllers\Admin\MailProfileController::class, 'toggle'])->name('mail-profiles.toggle');
|
||||
|
|
@ -208,6 +208,7 @@
|
|||
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
||||
Route::post('clients', [ClientController::class, 'store'])->name('client.store');
|
||||
Route::put('clients/{client:uuid}', [ClientController::class, 'update'])->name('client.update');
|
||||
Route::post('clients/{client:uuid}/emergency-person', [ClientController::class, 'emergencyCreatePerson'])->name('client.emergencyPerson');
|
||||
|
||||
// client-case
|
||||
Route::get('client-cases', [ClientCaseContoller::class, 'index'])->name('clientCase');
|
||||
|
|
@ -215,6 +216,7 @@
|
|||
Route::post('client-cases/{client_case:uuid}/contracts/{uuid}/segment', [ClientCaseContoller::class, 'updateContractSegment'])->name('clientCase.contract.updateSegment');
|
||||
Route::post('client-cases/{client_case:uuid}/contracts/{uuid}/archive', [ClientCaseContoller::class, 'archiveContract'])->name('clientCase.contract.archive');
|
||||
Route::post('client-cases', [ClientCaseContoller::class, 'store'])->name('clientCase.store');
|
||||
Route::post('client-cases/{client_case:uuid}/emergency-person', [ClientCaseContoller::class, 'emergencyCreatePerson'])->name('clientCase.emergencyPerson');
|
||||
// client-case / contract
|
||||
Route::post('client-cases/{client_case:uuid}/contract', [ClientCaseContoller::class, 'storeContract'])->name('clientCase.contract.store');
|
||||
Route::put('client-cases/{client_case:uuid}/contract/{uuid}', [ClientCaseContoller::class, 'updateContract'])->name('clientCase.contract.update');
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user