updates to UI and add archiving option
This commit is contained in:
@@ -159,6 +159,9 @@ public function storeContract(ClientCase $clientCase, StoreContractRequest $requ
|
||||
public function updateContract(ClientCase $clientCase, string $uuid, UpdateContractRequest $request)
|
||||
{
|
||||
$contract = Contract::where('uuid', $uuid)->firstOrFail();
|
||||
if (! $contract->active) {
|
||||
return back()->with('warning', __('contracts.edit_not_allowed_archived'));
|
||||
}
|
||||
|
||||
\DB::transaction(function () use ($request, $contract) {
|
||||
$contract->update([
|
||||
@@ -243,6 +246,10 @@ public function storeActivity(ClientCase $clientCase, Request $request)
|
||||
if (! empty($attributes['contract_uuid'])) {
|
||||
$contract = $clientCase->contracts()->where('uuid', $attributes['contract_uuid'])->firstOrFail('id');
|
||||
if ($contract) {
|
||||
// Prevent attaching a new activity specifically to an archived contract
|
||||
if (! $contract->active) {
|
||||
return back()->with('warning', __('contracts.activity_not_allowed_archived'));
|
||||
}
|
||||
$contractId = $contract->id;
|
||||
}
|
||||
}
|
||||
@@ -315,6 +322,11 @@ public function updateContractSegment(ClientCase $clientCase, string $uuid, Requ
|
||||
|
||||
$contract = $clientCase->contracts()->where('uuid', $uuid)->firstOrFail();
|
||||
|
||||
// Safety: Disallow segment change if contract archived (inactive)
|
||||
if (! $contract->active) {
|
||||
return back()->with('warning', __('contracts.segment_change_not_allowed_archived'));
|
||||
}
|
||||
|
||||
\DB::transaction(function () use ($contract, $validated) {
|
||||
// Deactivate current active relation(s)
|
||||
\DB::table('contract_segment')
|
||||
@@ -365,6 +377,10 @@ public function attachSegment(ClientCase $clientCase, Request $request)
|
||||
// Optionally make it active for a specific contract
|
||||
if (! empty($validated['contract_uuid']) && ($validated['make_active_for_contract'] ?? false)) {
|
||||
$contract = $clientCase->contracts()->where('uuid', $validated['contract_uuid'])->firstOrFail();
|
||||
if (! $contract->active) {
|
||||
// Prevent segment activation for archived contract
|
||||
return; // Silent; we still attach to case but do not alter archived contract
|
||||
}
|
||||
\DB::table('contract_segment')
|
||||
->where('contract_id', $contract->id)
|
||||
->where('active', true)
|
||||
@@ -402,6 +418,9 @@ public function storeDocument(ClientCase $clientCase, Request $request)
|
||||
$contract = null;
|
||||
if (! empty($validated['contract_uuid'])) {
|
||||
$contract = $clientCase->contracts()->where('uuid', $validated['contract_uuid'])->first();
|
||||
if ($contract && ! $contract->active) {
|
||||
return back()->with('warning', __('contracts.document_not_allowed_archived'));
|
||||
}
|
||||
}
|
||||
$directory = $contract
|
||||
? ('contracts/'.$contract->uuid.'/documents')
|
||||
@@ -1000,16 +1019,49 @@ public function show(ClientCase $clientCase)
|
||||
'phone_types' => \App\Models\Person\PhoneType::all(),
|
||||
];
|
||||
|
||||
// $active = false;
|
||||
|
||||
// Optional segment filter from query string
|
||||
$segmentId = request()->integer('segment');
|
||||
|
||||
// Prepare contracts and a reference map
|
||||
// Determine latest archive (non-reactivate) setting for this context to infer archive segment and related tables
|
||||
$latestArchiveSetting = \App\Models\ArchiveSetting::query()
|
||||
->where('enabled', true)
|
||||
->where(function ($q) {
|
||||
$q->whereNull('reactivate')->orWhere('reactivate', false);
|
||||
})
|
||||
->orderByDesc('id')
|
||||
->first();
|
||||
$archiveSegmentId = optional($latestArchiveSetting)->segment_id; // may be null
|
||||
$relatedArchiveTables = [];
|
||||
if ($latestArchiveSetting) {
|
||||
$entities = (array) $latestArchiveSetting->entities;
|
||||
foreach ($entities as $edef) {
|
||||
if (isset($edef['related']) && is_array($edef['related'])) {
|
||||
foreach ($edef['related'] as $rel) {
|
||||
$relatedArchiveTables[] = $rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
$relatedArchiveTables = array_values(array_unique($relatedArchiveTables));
|
||||
}
|
||||
|
||||
// Prepare contracts and a reference map.
|
||||
// Only apply active/inactive filtering IF a segment filter is provided.
|
||||
$contractsQuery = $case->contracts()
|
||||
->with(['type', 'account', 'objects', 'segments:id,name'])
|
||||
->orderByDesc('created_at');
|
||||
->with(['type', 'account', 'objects', 'segments:id,name']);
|
||||
|
||||
$contractsQuery->orderByDesc('created_at');
|
||||
|
||||
if (! empty($segmentId)) {
|
||||
// Filter to contracts that are in the provided segment and active on pivot
|
||||
if ($archiveSegmentId && $segmentId === $archiveSegmentId) {
|
||||
// Viewing the archive segment: only archived (inactive) contracts
|
||||
$contractsQuery->where('active', 0);
|
||||
} else {
|
||||
// Any other specific segment: only active contracts
|
||||
$contractsQuery->where('active', 1);
|
||||
}
|
||||
$contractsQuery->whereExists(function ($q) use ($segmentId) {
|
||||
$q->from('contract_segment')
|
||||
->whereColumn('contract_segment.contract_id', 'contracts.id')
|
||||
@@ -1019,6 +1071,7 @@ public function show(ClientCase $clientCase)
|
||||
}
|
||||
|
||||
$contracts = $contractsQuery->get();
|
||||
|
||||
$contractRefMap = [];
|
||||
foreach ($contracts as $c) {
|
||||
$contractRefMap[$c->id] = $c->reference;
|
||||
@@ -1062,6 +1115,10 @@ public function show(ClientCase $clientCase)
|
||||
'client' => $case->client()->with('person', fn ($q) => $q->with(['addresses', 'phones', 'bankAccounts']))->firstOrFail(),
|
||||
'client_case' => $case,
|
||||
'contracts' => $contracts,
|
||||
'archive_meta' => [
|
||||
'archive_segment_id' => $archiveSegmentId,
|
||||
'related_tables' => $relatedArchiveTables,
|
||||
],
|
||||
'activities' => tap(
|
||||
(function () use ($case, $segmentId, $contractIds) {
|
||||
$q = $case->activities()
|
||||
@@ -1090,7 +1147,11 @@ function ($p) {
|
||||
'documents' => $mergedDocs,
|
||||
'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(),
|
||||
'account_types' => \App\Models\AccountType::all(),
|
||||
'actions' => \App\Models\Action::with('decisions')->get(),
|
||||
'actions' => \App\Models\Action::with('decisions')
|
||||
/*->when($segmentId, function($q) use($segmentId) {
|
||||
$q->where('segment_id', $segmentId)->orWhereNull('segment_id');
|
||||
})*/
|
||||
->get(),
|
||||
'types' => $types,
|
||||
'segments' => $case->segments()->wherePivot('active', true)->get(['segments.id', 'segments.name']),
|
||||
'all_segments' => \App\Models\Segment::query()->where('active', true)->get(['id', 'name']),
|
||||
@@ -1170,4 +1231,184 @@ public function deleteContractDocument(Contract $contract, Document $document, R
|
||||
? response()->json(['status' => 'ok'])
|
||||
: back()->with('success', 'Document deleted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually archive a contract (flag active=0) and optionally its immediate financial relations.
|
||||
*/
|
||||
public function archiveContract(ClientCase $clientCase, string $uuid, Request $request)
|
||||
{
|
||||
$contract = Contract::query()->where('uuid', $uuid)->firstOrFail();
|
||||
if ($contract->client_case_id !== $clientCase->id) {
|
||||
abort(404);
|
||||
}
|
||||
$reactivateRequested = (bool) $request->boolean('reactivate');
|
||||
// Determine applicable settings based on intent (archive vs reactivate)
|
||||
if ($reactivateRequested) {
|
||||
$latestReactivate = \App\Models\ArchiveSetting::query()
|
||||
->where('enabled', true)
|
||||
->where('reactivate', true)
|
||||
->whereIn('strategy', ['immediate', 'manual'])
|
||||
->orderByDesc('id')
|
||||
->first();
|
||||
if (! $latestReactivate) {
|
||||
return back()->with('warning', __('contracts.reactivate_not_allowed'));
|
||||
}
|
||||
$settings = collect([$latestReactivate]);
|
||||
$hasReactivateRule = true;
|
||||
} else {
|
||||
$settings = \App\Models\ArchiveSetting::query()
|
||||
->where('enabled', true)
|
||||
->whereIn('strategy', ['immediate', 'manual'])
|
||||
->where(function ($q) { // exclude reactivate-only rules from archive run
|
||||
$q->whereNull('reactivate')->orWhere('reactivate', false);
|
||||
})
|
||||
->get();
|
||||
if ($settings->isEmpty()) {
|
||||
return back()->with('warning', __('contracts.no_archive_settings'));
|
||||
}
|
||||
$hasReactivateRule = false;
|
||||
}
|
||||
|
||||
$executor = app(\App\Services\Archiving\ArchiveExecutor::class);
|
||||
$context = [
|
||||
'contract_id' => $contract->id,
|
||||
'client_case_id' => $clientCase->id,
|
||||
];
|
||||
if ($contract->account) {
|
||||
$context['account_id'] = $contract->account->id;
|
||||
}
|
||||
|
||||
$overall = [];
|
||||
$hadAnyEffect = false;
|
||||
foreach ($settings as $setting) {
|
||||
$res = $executor->executeSetting($setting, $context, optional($request->user())->id);
|
||||
foreach ($res as $table => $count) {
|
||||
$overall[$table] = ($overall[$table] ?? 0) + $count;
|
||||
if ($count > 0) {
|
||||
$hadAnyEffect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($reactivateRequested && $hasReactivateRule) {
|
||||
// Reactivation path: ensure contract becomes active and soft-delete cleared.
|
||||
if ($contract->active == 0 || $contract->deleted_at) {
|
||||
$contract->forceFill(['active' => 1, 'deleted_at' => null])->save();
|
||||
$overall['contracts_reactivated'] = ($overall['contracts_reactivated'] ?? 0) + 1;
|
||||
$hadAnyEffect = true;
|
||||
}
|
||||
} else {
|
||||
// Ensure the contract itself is archived even if rule conditions would have excluded it
|
||||
if (! empty($contract->getAttributes()) && $contract->active) {
|
||||
if (! array_key_exists('contracts', $overall)) {
|
||||
$contract->update(['active' => 0]);
|
||||
$overall['contracts'] = ($overall['contracts'] ?? 0) + 1;
|
||||
} else {
|
||||
$contract->refresh();
|
||||
}
|
||||
$hadAnyEffect = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Create an Activity record logging this archive if an action or decision is tied to any setting
|
||||
if ($hadAnyEffect) {
|
||||
$activitySetting = $settings->first(fn ($s) => ! is_null($s->action_id) || ! is_null($s->decision_id));
|
||||
if ($activitySetting) {
|
||||
try {
|
||||
if ($reactivateRequested) {
|
||||
$note = 'Ponovna aktivacija pogodba '.$contract->reference;
|
||||
} else {
|
||||
$noteKey = 'contracts.archived_activity_note';
|
||||
$note = __($noteKey, ['reference' => $contract->reference]);
|
||||
if ($note === $noteKey) {
|
||||
$note = \Illuminate\Support\Facades\Lang::get($noteKey, ['reference' => $contract->reference], 'sl');
|
||||
}
|
||||
}
|
||||
$activityData = [
|
||||
'client_case_id' => $clientCase->id,
|
||||
'action_id' => $activitySetting->action_id,
|
||||
'decision_id' => $activitySetting->decision_id,
|
||||
'note' => $note,
|
||||
'active' => 1,
|
||||
'user_id' => optional($request->user())->id,
|
||||
];
|
||||
if ($reactivateRequested) {
|
||||
// Attach the contract_id when reactivated as per requirement
|
||||
$activityData['contract_id'] = $contract->id;
|
||||
}
|
||||
\App\Models\Activity::create($activityData);
|
||||
} catch (\Throwable $e) {
|
||||
logger()->warning('Failed to create archive/reactivate activity', [
|
||||
'error' => $e->getMessage(),
|
||||
'contract_id' => $contract->id,
|
||||
'setting_id' => optional($activitySetting)->id,
|
||||
'reactivate' => $reactivateRequested,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If any archive setting specifies a segment_id, move the contract to that segment (archive bucket)
|
||||
$segmentSetting = $settings->first(fn ($s) => ! is_null($s->segment_id)); // for reactivation this is the single reactivation setting if segment specified
|
||||
if ($segmentSetting && $segmentSetting->segment_id) {
|
||||
try {
|
||||
$segmentId = $segmentSetting->segment_id;
|
||||
\DB::transaction(function () use ($contract, $segmentId, $clientCase) {
|
||||
// Ensure the segment is attached to the client case (activate if previously inactive)
|
||||
$casePivot = \DB::table('client_case_segment')
|
||||
->where('client_case_id', $clientCase->id)
|
||||
->where('segment_id', $segmentId)
|
||||
->first();
|
||||
if (! $casePivot) {
|
||||
\DB::table('client_case_segment')->insert([
|
||||
'client_case_id' => $clientCase->id,
|
||||
'segment_id' => $segmentId,
|
||||
'active' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} elseif (! $casePivot->active) {
|
||||
\DB::table('client_case_segment')
|
||||
->where('id', $casePivot->id)
|
||||
->update(['active' => true, 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
// Deactivate all current active contract segments
|
||||
\DB::table('contract_segment')
|
||||
->where('contract_id', $contract->id)
|
||||
->where('active', true)
|
||||
->update(['active' => false, 'updated_at' => now()]);
|
||||
|
||||
// Attach or activate the archive segment for this contract
|
||||
$existing = \DB::table('contract_segment')
|
||||
->where('contract_id', $contract->id)
|
||||
->where('segment_id', $segmentId)
|
||||
->first();
|
||||
if ($existing) {
|
||||
\DB::table('contract_segment')
|
||||
->where('id', $existing->id)
|
||||
->update(['active' => true, 'updated_at' => now()]);
|
||||
} else {
|
||||
\DB::table('contract_segment')->insert([
|
||||
'contract_id' => $contract->id,
|
||||
'segment_id' => $segmentId,
|
||||
'active' => true,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
logger()->warning('Failed to move contract to archive segment', [
|
||||
'error' => $e->getMessage(),
|
||||
'contract_id' => $contract->id,
|
||||
'segment_id' => $segmentSetting->segment_id,
|
||||
'setting_id' => $segmentSetting->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$message = $reactivateRequested ? __('contracts.reactivated') : __('contracts.archived');
|
||||
|
||||
return back()->with('success', $message);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user