This commit is contained in:
Simon Pocrnjič
2025-09-28 00:30:18 +02:00
parent 7227c888d4
commit a913cfc381
44 changed files with 2123 additions and 587 deletions
@@ -0,0 +1,56 @@
<?php
namespace App\Http\Controllers;
use App\Models\CaseObject;
use App\Models\ClientCase;
use App\Models\Contract;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
class CaseObjectController extends Controller
{
public function store(ClientCase $clientCase, string $uuid, Request $request)
{
$contract = Contract::where('uuid', $uuid)->where('client_case_id', $clientCase->id)->firstOrFail();
$validated = $request->validate([
'reference' => 'nullable|string|max:125',
'name' => 'required|string|max:255',
'description' => 'nullable|string|max:255',
'type' => 'nullable|string|max:125',
]);
$contract->objects()->create($validated);
return to_route('clientCase.show', $clientCase)->with('success', 'Object created.');
}
public function update(ClientCase $clientCase, int $id, Request $request)
{
$object = CaseObject::where('id', $id)
->whereHas('contract', fn($q) => $q->where('client_case_id', $clientCase->id))
->firstOrFail();
$validated = $request->validate([
'reference' => 'nullable|string|max:125',
'name' => 'required|string|max:255',
'description' => 'nullable|string|max:255',
'type' => 'nullable|string|max:125',
]);
$object->update($validated);
return to_route('clientCase.show', $clientCase)->with('success', 'Object updated.');
}
public function destroy(ClientCase $clientCase, int $id)
{
$object = CaseObject::where('id', $id)
->whereHas('contract', fn($q) => $q->where('client_case_id', $clientCase->id))
->firstOrFail();
$object->delete();
return to_route('clientCase.show', $clientCase)->with('success', 'Object deleted.');
}
}
+53 -9
View File
@@ -98,13 +98,24 @@ public function storeContract(ClientCase $clientCase, Request $request)
\DB::transaction(function() use ($request, $clientCase){
//Create contract
$clientCase->contracts()->create([
// Create contract
$contract = $clientCase->contracts()->create([
'reference' => $request->input('reference'),
'start_date' => date('Y-m-d', strtotime($request->input('start_date'))),
'type_id' => $request->input('type_id')
'type_id' => $request->input('type_id'),
'description' => $request->input('description'),
]);
// Optionally create/update related account amounts
$initial = $request->input('initial_amount');
$balance = $request->input('balance_amount');
if (!is_null($initial) || !is_null($balance)) {
$contract->account()->create([
'initial_amount' => $initial ?? 0,
'balance_amount' => $balance ?? 0,
]);
}
});
return to_route('clientCase.show', $clientCase);
@@ -117,9 +128,25 @@ public function updateContract(ClientCase $clientCase, String $uuid, Request $re
\DB::transaction(function() use ($request, $contract){
$contract->update([
'reference' => $request->input('reference'),
'type_id' => $request->input('type_id')
'type_id' => $request->input('type_id'),
'description' => $request->input('description'),
'start_date' => $request->filled('start_date') ? date('Y-m-d', strtotime($request->input('start_date'))) : $contract->start_date,
]);
$initial = $request->input('initial_amount');
$balance = $request->input('balance_amount');
if (!is_null($initial) || !is_null($balance)) {
$accountData = [
'initial_amount' => $initial ?? 0,
'balance_amount' => $balance ?? 0,
];
if ($contract->account) {
$contract->account->update($accountData);
} else {
$contract->account()->create($accountData);
}
}
});
return to_route('clientCase.show', $clientCase);
@@ -132,11 +159,28 @@ public function storeActivity(ClientCase $clientCase, Request $request) {
'amount' => 'nullable|decimal:0,4',
'note' => 'nullable|string',
'action_id' => 'exists:\App\Models\Action,id',
'decision_id' => 'exists:\App\Models\Decision,id'
'decision_id' => 'exists:\App\Models\Decision,id',
'contract_uuid' => 'nullable|uuid',
]);
//Create activity
$row = $clientCase->activities()->create($attributes);
// Map contract_uuid to contract_id within the same client case, if provided
$contractId = null;
if (!empty($attributes['contract_uuid'])) {
$contract = $clientCase->contracts()->where('uuid', $attributes['contract_uuid'])->firstOrFail('id');
if ($contract) {
$contractId = $contract->id;
}
}
// Create activity
$row = $clientCase->activities()->create([
'due_date' => $attributes['due_date'] ?? null,
'amount' => $attributes['amount'] ?? null,
'note' => $attributes['note'] ?? null,
'action_id' => $attributes['action_id'],
'decision_id' => $attributes['decision_id'],
'contract_id' => $contractId,
]);
/*foreach ($activity->decision->events as $e) {
$class = '\\App\\Events\\' . $e->name;
event(new $class($clientCase));
@@ -296,9 +340,9 @@ public function show(ClientCase $clientCase)
'client' => $case->client()->with('person', fn($q) => $q->with(['addresses', 'phones']))->firstOrFail(),
'client_case' => $case,
'contracts' => $case->contracts()
->with(['type'])
->with(['type', 'account', 'objects'])
->orderByDesc('created_at')->get(),
'activities' => $case->activities()->with(['action', 'decision'])
'activities' => $case->activities()->with(['action', 'decision', 'contract:id,uuid,reference'])
->orderByDesc('created_at')
->paginate(20, ['*'], 'activities'),
'documents' => $case->documents()->orderByDesc('created_at')->get(),
+32 -6
View File
@@ -21,7 +21,11 @@ class ImportController extends Controller
public function index(Request $request)
{
$paginator = Import::query()
->with(['client:id,uuid', 'template:id,name'])
->with([
'client:id,uuid,person_id',
'client.person:id,uuid,full_name',
'template:id,name',
])
->orderByDesc('created_at')
->paginate(15);
@@ -52,8 +56,15 @@ public function index(Request $request)
'original_name' => $imp->original_name,
'size' => $imp->size,
'status' => $imp->status,
'client' => $imp->client ? [ 'id' => $imp->client_id, 'uuid' => $imp->client->uuid ] : null,
'template' => $imp->template ? [ 'id' => $imp->import_template_id, 'name' => $imp->template->name ] : null,
'client' => $imp->client ? [
'id' => $imp->client_id,
'uuid' => $imp->client->uuid,
'person' => $imp->client->person ? [
'uuid' => $imp->client->person->uuid,
'full_name' => $imp->client->person->full_name,
] : null,
] : null,
'template' => $imp->template ? [ 'id' => $imp->template->id, 'name' => $imp->template->name ] : null,
];
}, $imports['data']);
@@ -316,6 +327,7 @@ public function show(Import $import)
$templates = ImportTemplate::query()
->leftJoin('clients', 'clients.id', '=', 'import_templates.client_id')
->where('import_templates.is_active', true)
->where('import_templates.id', $import->import_template_id)
->orderBy('import_templates.name')
->get([
'import_templates.id',
@@ -324,18 +336,30 @@ public function show(Import $import)
'import_templates.source_type',
'import_templates.default_record_type',
'import_templates.client_id',
DB::raw('clients.uuid as client_uuid'),
'clients.uuid as client_uuid',
]);
$clients = Client::query()
->join('person', 'person.id', '=', 'clients.person_id')
->orderBy('person.full_name')
->where('clients.id', $import->client_id)
->get([
'clients.id',
'clients.uuid',
DB::raw('person.full_name as name'),
'person.full_name as name'
]);
// Import client
$client = Client::query()
->join('person', 'person.id', '=', 'clients.person_id')
->where('clients.id', $import->client_id)
->firstOrFail([
'clients.uuid as uuid',
'person.full_name as name',
]);
// Render a dedicated page to continue the import
return Inertia::render('Imports/Import', [
'import' => [
@@ -344,15 +368,17 @@ public function show(Import $import)
'status' => $import->status,
'meta' => $import->meta,
'client_id' => $import->client_id,
'client_uuid' => optional($client)->uuid,
'import_template_id' => $import->import_template_id,
'total_rows' => $import->total_rows,
'imported_rows' => $import->imported_rows,
'invalid_rows' => $import->invalid_rows,
'valid_rows' => $import->valid_rows,
'finished_at' => $import->finished_at,
'finished_at' => $import->finished_at
],
'templates' => $templates,
'clients' => $clients,
'client' => $client
]);
}
}
+77
View File
@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\Person\Person;
use App\Models\BankAccount;
use Illuminate\Http\Request;
use Inertia\Inertia;
@@ -78,6 +79,13 @@ public function updateAddress(Person $person, int $address_id, Request $request)
]);
}
public function deleteAddress(Person $person, int $address_id, Request $request)
{
$address = $person->addresses()->findOrFail($address_id);
$address->delete(); // soft delete
return response()->json(['status' => 'ok']);
}
public function createPhone(Person $person, Request $request)
{
$attributes = $request->validate([
@@ -116,6 +124,13 @@ public function updatePhone(Person $person, int $phone_id, Request $request)
]);
}
public function deletePhone(Person $person, int $phone_id, Request $request)
{
$phone = $person->phones()->findOrFail($phone_id);
$phone->delete(); // soft delete
return response()->json(['status' => 'ok']);
}
public function createEmail(Person $person, Request $request)
{
$attributes = $request->validate([
@@ -160,4 +175,66 @@ public function updateEmail(Person $person, int $email_id, Request $request)
'email' => $email
]);
}
public function deleteEmail(Person $person, int $email_id, Request $request)
{
$email = $person->emails()->findOrFail($email_id);
$email->delete();
return response()->json(['status' => 'ok']);
}
// TRR (bank account) CRUD
public function createTrr(Person $person, Request $request)
{
$attributes = $request->validate([
'iban' => 'nullable|string|max:34',
'bank_name' => 'required|string|max:100',
'bic_swift' => 'nullable|string|max:11',
'account_number' => 'nullable|string|max:34',
'routing_number' => 'nullable|string|max:20',
'currency' => 'required|string|size:3',
'country_code' => 'nullable|string|size:2',
'holder_name' => 'nullable|string|max:125',
'notes' => 'nullable|string',
'meta' => 'nullable|array',
]);
// Create without dedup (IBAN may be null or vary); could dedup by IBAN if provided
$trr = $person->bankAccounts()->create($attributes);
return response()->json([
'trr' => BankAccount::findOrFail($trr->id)
]);
}
public function updateTrr(Person $person, int $trr_id, Request $request)
{
$attributes = $request->validate([
'iban' => 'nullable|string|max:34',
'bank_name' => 'required|string|max:100',
'bic_swift' => 'nullable|string|max:11',
'account_number' => 'nullable|string|max:34',
'routing_number' => 'nullable|string|max:20',
'currency' => 'required|string|size:3',
'country_code' => 'nullable|string|size:2',
'holder_name' => 'nullable|string|max:125',
'notes' => 'nullable|string',
'meta' => 'nullable|array',
'is_active' => 'sometimes|boolean',
]);
$trr = $person->bankAccounts()->findOrFail($trr_id);
$trr->update($attributes);
return response()->json([
'trr' => $trr
]);
}
public function deleteTrr(Person $person, int $trr_id, Request $request)
{
$trr = $person->bankAccounts()->findOrFail($trr_id);
$trr->delete();
return response()->json(['status' => 'ok']);
}
}
+1
View File
@@ -18,6 +18,7 @@ class Account extends Model
'contract_id',
'type_id',
'active',
'initial_amount',
'balance_amount',
];
+2 -1
View File
@@ -19,7 +19,8 @@ class Activity extends Model
'note',
'action_id',
'user_id',
'decision_id'
'decision_id',
'contract_id'
];
protected $hidden = [
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class BankAccount extends Model
{
use HasFactory;
use SoftDeletes;
protected $table = 'bank_accounts';
protected $fillable = [
'person_id',
'bank_name',
'iban',
'bic_swift',
'account_number',
'routing_number',
'currency',
'country_code',
'holder_name',
'is_active',
'notes',
'meta',
];
protected $casts = [
'is_active' => 'boolean',
'meta' => 'array',
];
public function person(): BelongsTo
{
return $this->belongsTo(\App\Models\Person\Person::class, 'person_id');
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class CaseObject extends Model
{
use HasFactory;
use SoftDeletes;
protected $table = 'objects';
protected $fillable = [
'reference',
'name',
'description',
'type',
'contract_id',
];
public function contract(): BelongsTo
{
return $this->belongsTo(Contract::class, 'contract_id');
}
}
+12
View File
@@ -10,6 +10,7 @@
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOneOrManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -53,4 +54,15 @@ public function segments(): BelongsToMany {
->wherePivot('active', true);
}
public function account(): HasOne
{
return $this->hasOne(\App\Models\Account::class)
->with('type');
}
public function objects(): HasMany
{
return $this->hasMany(\App\Models\CaseObject::class, 'contract_id');
}
}
+3
View File
@@ -4,9 +4,12 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class Email extends Model
{
use SoftDeletes;
protected $fillable = [
'person_id',
'value',
+7
View File
@@ -100,6 +100,13 @@ public function emails(): HasMany
->orderBy('id');
}
public function bankAccounts(): HasMany
{
return $this->hasMany(\App\Models\BankAccount::class, 'person_id')
->where('is_active', '=', 1)
->orderBy('id');
}
public function group(): BelongsTo
{
return $this->belongsTo(\App\Models\Person\PersonGroup::class, 'group_id');
+2
View File
@@ -5,6 +5,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
class PersonAddress extends Model
@@ -12,6 +13,7 @@ class PersonAddress extends Model
/** @use HasFactory<\Database\Factories\Person/PersonAddressFactory> */
use HasFactory;
use Searchable;
use SoftDeletes;
protected $fillable = [
'address',
+2
View File
@@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
class PersonPhone extends Model
@@ -13,6 +14,7 @@ class PersonPhone extends Model
/** @use HasFactory<\Database\Factories\Person/PersonPhoneFactory> */
use HasFactory;
use Searchable;
use SoftDeletes;
protected $fillable = [
'nu',