Compare commits
3 Commits
091fb07646
...
ebf9f29200
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebf9f29200 | ||
|
|
7eaab16e30 | ||
|
|
6a2dd860fa |
|
|
@ -1079,6 +1079,156 @@ public function archiveContract(ClientCase $clientCase, string $uuid, Request $r
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Archive multiple contracts in a batch operation
|
||||||
|
*/
|
||||||
|
public function archiveBatch(Request $request)
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'contracts' => 'required|array',
|
||||||
|
'contracts.*' => 'required|uuid|exists:contracts,uuid',
|
||||||
|
'reactivate' => 'boolean',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$reactivate = $validated['reactivate'] ?? false;
|
||||||
|
|
||||||
|
// Get archive setting
|
||||||
|
$setting = \App\Models\ArchiveSetting::query()
|
||||||
|
->where('enabled', true)
|
||||||
|
->whereIn('strategy', ['immediate', 'manual'])
|
||||||
|
->where('reactivate', $reactivate)
|
||||||
|
->orderByDesc('id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (! $setting) {
|
||||||
|
\Log::warning('No archive settings found for batch archive');
|
||||||
|
return back()->with('flash', [
|
||||||
|
'error' => 'No archive settings found',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$executor = app(\App\Services\Archiving\ArchiveExecutor::class);
|
||||||
|
$successCount = 0;
|
||||||
|
$skippedCount = 0;
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
foreach ($validated['contracts'] as $contractUuid) {
|
||||||
|
try {
|
||||||
|
$contract = Contract::where('uuid', $contractUuid)->firstOrFail();
|
||||||
|
|
||||||
|
// Skip if contract is already archived (active = 0)
|
||||||
|
if (!$contract->active) {
|
||||||
|
$skippedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientCase = $contract->clientCase;
|
||||||
|
|
||||||
|
$context = [
|
||||||
|
'contract_id' => $contract->id,
|
||||||
|
'client_case_id' => $clientCase->id,
|
||||||
|
'account_id' => $contract->account->id ?? null,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Execute archive setting
|
||||||
|
$executor->executeSetting($setting, $context, \Auth::id());
|
||||||
|
|
||||||
|
// Transaction for segment updates and activity logging
|
||||||
|
\DB::transaction(function () use ($contract, $clientCase, $setting, $reactivate) {
|
||||||
|
// Create activity log
|
||||||
|
if ($setting->action_id && $setting->decision_id) {
|
||||||
|
$activityData = [
|
||||||
|
'client_case_id' => $clientCase->id,
|
||||||
|
'action_id' => $setting->action_id,
|
||||||
|
'decision_id' => $setting->decision_id,
|
||||||
|
'note' => ($reactivate)
|
||||||
|
? "Ponovno aktivirana pogodba $contract->reference"
|
||||||
|
: "Arhivirana pogodba $contract->reference",
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
\App\Models\Activity::create($activityData);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
\Log::warning('Activity could not be created during batch archive');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to archive segment if specified
|
||||||
|
if ($setting->segment_id) {
|
||||||
|
$segmentId = $setting->segment_id;
|
||||||
|
|
||||||
|
// Deactivate all current segments
|
||||||
|
$contract->segments()
|
||||||
|
->allRelatedIds()
|
||||||
|
->map(fn (int $val) => $contract->segments()->updateExistingPivot($val, [
|
||||||
|
'active' => false,
|
||||||
|
'updated_at' => now(),
|
||||||
|
]));
|
||||||
|
|
||||||
|
// Activate archive segment
|
||||||
|
if ($contract->attachedSegments()->find($segmentId)->pluck('id')->isNotEmpty()) {
|
||||||
|
$contract->attachedSegments()->updateExistingPivot($segmentId, [
|
||||||
|
'active' => true,
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$contract->segments()->attach($segmentId, [
|
||||||
|
'active' => true,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel pending field jobs
|
||||||
|
$contract->fieldJobs()
|
||||||
|
->whereNull('completed_at')
|
||||||
|
->whereNull('cancelled_at')
|
||||||
|
->update([
|
||||||
|
'cancelled_at' => date('Y-m-d'),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$successCount++;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
\Log::error('Error archiving contract in batch', [
|
||||||
|
'uuid' => $contractUuid,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
$errors[] = [
|
||||||
|
'uuid' => $contractUuid,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($errors) > 0) {
|
||||||
|
$message = "Archived $successCount contracts";
|
||||||
|
if ($skippedCount > 0) {
|
||||||
|
$message .= ", skipped $skippedCount already archived";
|
||||||
|
}
|
||||||
|
$message .= ", " . count($errors) . " failed";
|
||||||
|
|
||||||
|
return back()->with('flash', [
|
||||||
|
'error' => $message,
|
||||||
|
'details' => $errors,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $reactivate
|
||||||
|
? "Successfully reactivated $successCount contracts"
|
||||||
|
: "Successfully archived $successCount contracts";
|
||||||
|
|
||||||
|
if ($skippedCount > 0) {
|
||||||
|
$message .= " ($skippedCount already archived)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->with('flash', [
|
||||||
|
'success' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emergency: recreate a missing / soft-deleted person for a client case and re-link related data.
|
* Emergency: recreate a missing / soft-deleted person for a client case and re-link related data.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,11 @@ const exportDisabled = computed(
|
||||||
() => exportColumns.value.length === 0 || isExporting.value
|
() => exportColumns.value.length === 0 || isExporting.value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const canManageSettings = computed(() => {
|
||||||
|
const permissions = usePage().props?.auth?.user?.permissions || [];
|
||||||
|
return permissions.includes("mass-archive");
|
||||||
|
});
|
||||||
|
|
||||||
function toggleAllColumns(checked) {
|
function toggleAllColumns(checked) {
|
||||||
exportColumns.value = checked ? columns.map((col) => col.key) : [];
|
exportColumns.value = checked ? columns.map((col) => col.key) : [];
|
||||||
}
|
}
|
||||||
|
|
@ -311,6 +316,67 @@ function extractFilenameFromHeaders(headers) {
|
||||||
const asciiMatch = disposition.match(/filename="?([^";]+)"?/i);
|
const asciiMatch = disposition.match(/filename="?([^";]+)"?/i);
|
||||||
return asciiMatch?.[1] || null;
|
return asciiMatch?.[1] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleSelectAll() {
|
||||||
|
if (selectedRows.value.length === props.contracts.data.length) {
|
||||||
|
selectedRows.value = [];
|
||||||
|
} else {
|
||||||
|
selectedRows.value = props.contracts.data.map((row) => row.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleRowSelection(uuid) {
|
||||||
|
const index = selectedRows.value.indexOf(uuid);
|
||||||
|
if (index > -1) {
|
||||||
|
selectedRows.value.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
selectedRows.value.push(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRowSelected(uuid) {
|
||||||
|
return selectedRows.value.includes(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllSelected() {
|
||||||
|
return (
|
||||||
|
props.contracts.data.length > 0 &&
|
||||||
|
selectedRows.value.length === props.contracts.data.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIndeterminate() {
|
||||||
|
return (
|
||||||
|
selectedRows.value.length > 0 &&
|
||||||
|
selectedRows.value.length < props.contracts.data.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openArchiveModal() {
|
||||||
|
if (!selectedRows.value.length) return;
|
||||||
|
showConfirmDialog.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeConfirmDialog() {
|
||||||
|
showConfirmDialog.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitArchive() {
|
||||||
|
if (!selectedRows.value.length) return;
|
||||||
|
|
||||||
|
showConfirmDialog.value = false;
|
||||||
|
|
||||||
|
archiveForm.contracts = [...selectedRows.value];
|
||||||
|
archiveForm.reactivate = false;
|
||||||
|
|
||||||
|
archiveForm.post(route("contracts.archive-batch"), {
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => {
|
||||||
|
selectedRows.value = [];
|
||||||
|
router.reload({ only: ["contracts"] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -541,6 +607,19 @@ function extractFilenameFromHeaders(headers) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
:show="showConfirmDialog"
|
||||||
|
title="Arhiviraj pogodbe"
|
||||||
|
:message="`Ali ste prepričani, da želite arhivirati ${selectedRows.length} pogodb${
|
||||||
|
selectedRows.length === 1 ? 'o' : ''
|
||||||
|
}? Arhivirane pogodbe bodo odstranjene iz aktivnih segmentov.`"
|
||||||
|
confirm-text="Arhiviraj"
|
||||||
|
cancel-text="Prekliči"
|
||||||
|
:danger="true"
|
||||||
|
@close="closeConfirmDialog"
|
||||||
|
@confirm="submitArchive"
|
||||||
|
/>
|
||||||
|
|
||||||
<DialogModal :show="exportDialogOpen" max-width="3xl" @close="closeExportDialog">
|
<DialogModal :show="exportDialogOpen" max-width="3xl" @close="closeExportDialog">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@
|
||||||
Route::get('client-cases/{client_case:uuid}', [ClientCaseContoller::class, 'show'])->name('clientCase.show');
|
Route::get('client-cases/{client_case:uuid}', [ClientCaseContoller::class, 'show'])->name('clientCase.show');
|
||||||
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}/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/{client_case:uuid}/contracts/{uuid}/archive', [ClientCaseContoller::class, 'archiveContract'])->name('clientCase.contract.archive');
|
||||||
|
Route::post('contracts/archive-batch', [ClientCaseContoller::class, 'archiveBatch'])->name('contracts.archive-batch')->middleware('permission:mass-archive');
|
||||||
Route::post('client-cases', [ClientCaseContoller::class, 'store'])->name('clientCase.store');
|
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');
|
Route::post('client-cases/{client_case:uuid}/emergency-person', [ClientCaseContoller::class, 'emergencyCreatePerson'])->name('clientCase.emergencyPerson');
|
||||||
// client-case / contract
|
// client-case / contract
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user