changes
This commit is contained in:
@@ -25,56 +25,71 @@ public function index(Request $request)
|
||||
optional($setting)->segment_id,
|
||||
])->filter()->unique()->values();
|
||||
|
||||
$contracts = Contract::query()
|
||||
->with(['clientCase.person', 'clientCase.client.person', 'type', 'account'])
|
||||
->when($segmentIds->isNotEmpty(), function ($q) use ($segmentIds) {
|
||||
$q->whereHas('segments', function ($sq) use ($segmentIds) {
|
||||
// Relation already filters on active pivots
|
||||
$sq->whereIn('segments.id', $segmentIds);
|
||||
});
|
||||
}, function ($q) {
|
||||
// No segments configured on FieldJobSetting -> return none
|
||||
$q->whereRaw('1 = 0');
|
||||
})
|
||||
$search = $request->input('search');
|
||||
$assignedUserId = $request->input('assigned_user_id');
|
||||
|
||||
$unassignedContracts = Contract::query()
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person', 'type', 'account'])
|
||||
->when($segmentIds->isNotEmpty(), fn($q) =>
|
||||
$q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
|
||||
fn($q) => $q->whereRaw('1 = 0')
|
||||
)
|
||||
->when( !empty($search), fn ($q) =>
|
||||
$q->where(fn($sq) =>
|
||||
$sq->where('reference', 'like', "%{$search}%")
|
||||
->orWhereHas('clientCase.person', fn($psq) =>
|
||||
$psq->where('full_name', 'ilike', "%{$search}%")
|
||||
)
|
||||
->orWhereHas('clientCase.person.addresses', fn ($ccpaq) =>
|
||||
$ccpaq->where('address', 'ilike', "%{$search}")
|
||||
)
|
||||
)
|
||||
)
|
||||
->whereDoesntHave('fieldJobs', fn ($q) =>
|
||||
$q->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
)
|
||||
->latest('id')
|
||||
->limit(50)
|
||||
->get();
|
||||
->paginate(
|
||||
$request->input('per_page_contracts', 10),
|
||||
['*'],
|
||||
'page_contracts',
|
||||
$request->input('page_contracts', 1)
|
||||
);
|
||||
|
||||
// Mirror client onto the contract for simpler frontend access: c.client.person.full_name
|
||||
$contracts->each(function (Contract $contract): void {
|
||||
if ($contract->relationLoaded('clientCase') && $contract->clientCase) {
|
||||
$contract->setRelation('client', $contract->clientCase->client);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Build active assignment map keyed by contract uuid for quicker UI checks
|
||||
$assignments = collect();
|
||||
if ($contracts->isNotEmpty()) {
|
||||
$activeJobs = FieldJob::query()
|
||||
->whereIn('contract_id', $contracts->pluck('id'))
|
||||
->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
->with(['assignedUser:id,name', 'user:id,name', 'contract:id,uuid'])
|
||||
->get();
|
||||
|
||||
$assignments = $activeJobs->mapWithKeys(function (FieldJob $job) {
|
||||
return [
|
||||
optional($job->contract)->uuid => [
|
||||
'assigned_to' => $job->assignedUser ? ['id' => $job->assignedUser->id, 'name' => $job->assignedUser->name] : null,
|
||||
'assigned_by' => $job->user ? ['id' => $job->user->id, 'name' => $job->user->name] : null,
|
||||
'assigned_at' => $job->assigned_at,
|
||||
],
|
||||
];
|
||||
})->filter();
|
||||
}
|
||||
$assignedContracts = Contract::query()
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person', 'type', 'account', 'lastFieldJobs', 'lastFieldJobs.assignedUser', 'lastFieldJobs.user'])
|
||||
->when($segmentIds->isNotEmpty(), fn($q) =>
|
||||
$q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
|
||||
fn($q) => $q->whereRaw('1 = 0')
|
||||
)
|
||||
->whereHas('lastFieldJobs', fn ($q) =>
|
||||
$q->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
->when($assignedUserId && $assignedUserId !== 'all', fn ($jq) =>
|
||||
$jq->where('assigned_user_id', $assignedUserId))
|
||||
)
|
||||
->latest('id')
|
||||
->paginate(
|
||||
$request->input('per_page_assignments', 10),
|
||||
['*'],
|
||||
'page_assignments',
|
||||
$request->input('page_assignments', 1)
|
||||
);
|
||||
|
||||
$users = User::query()->orderBy('name')->get(['id', 'name']);
|
||||
|
||||
return Inertia::render('FieldJob/Index', [
|
||||
'setting' => $setting,
|
||||
'contracts' => $contracts,
|
||||
'unassignedContracts' => $unassignedContracts,
|
||||
'assignedContracts' => $assignedContracts,
|
||||
'users' => $users,
|
||||
'assignments' => $assignments,
|
||||
'filters' => [
|
||||
'search' => $search,
|
||||
'assigned_user_id' => $assignedUserId,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
use App\Models\ImportEvent;
|
||||
use App\Models\ImportTemplate;
|
||||
use App\Services\CsvImportService;
|
||||
use App\Services\Import\ImportServiceV2;
|
||||
use App\Services\Import\ImportSimulationServiceV2;
|
||||
use App\Services\ImportProcessor;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -182,12 +184,27 @@ public function store(Request $request)
|
||||
}
|
||||
|
||||
// Kick off processing of an import - simple synchronous step for now
|
||||
public function process(Import $import, Request $request, ImportProcessor $processor)
|
||||
public function process(Import $import, Request $request, ImportServiceV2 $processor)
|
||||
{
|
||||
$import->update(['status' => 'validating', 'started_at' => now()]);
|
||||
$result = $processor->process($import, user: $request->user());
|
||||
|
||||
return response()->json($result);
|
||||
|
||||
try {
|
||||
$result = $processor->process($import, user: $request->user());
|
||||
return response()->json($result);
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error('Import processing failed', [
|
||||
'import_id' => $import->id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
$import->update(['status' => 'failed']);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Import processing failed: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze the uploaded file and return column headers or positional indices
|
||||
@@ -426,7 +443,7 @@ public function missingContracts(Import $import)
|
||||
|
||||
// Query active, non-archived contracts for this client that were not in import
|
||||
// Include person full_name (owner of the client case) and aggregate active accounts' balance_amount
|
||||
$contractsQ = \App\Models\Contract::query()
|
||||
$contractsQ = Contract::query()
|
||||
->join('client_cases', 'contracts.client_case_id', '=', 'client_cases.id')
|
||||
->join('person', 'person.id', '=', 'client_cases.person_id')
|
||||
->leftJoin('accounts', function ($join) {
|
||||
@@ -514,7 +531,7 @@ public function getEvents(Import $import)
|
||||
public function missingKeyrefRows(Import $import)
|
||||
{
|
||||
// Identify row IDs from events. Prefer specific event key, fallback to message pattern
|
||||
$rowIds = \App\Models\ImportEvent::query()
|
||||
$rowIds = ImportEvent::query()
|
||||
->where('import_id', $import->id)
|
||||
->where(function ($q) {
|
||||
$q->where('event', 'contract_keyref_not_found')
|
||||
@@ -694,6 +711,10 @@ public function simulatePayments(Import $import, Request $request)
|
||||
* using the first N rows and current saved mappings. Works for both payments and non-payments
|
||||
* templates. For payments templates, payment-specific summaries/entities will be included
|
||||
* automatically by the simulation service when mappings contain the payment root.
|
||||
*
|
||||
* @param Import $import
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function simulate(Import $import, Request $request)
|
||||
{
|
||||
@@ -704,7 +725,7 @@ public function simulate(Import $import, Request $request)
|
||||
$limit = (int) ($validated['limit'] ?? 100);
|
||||
$verbose = (bool) ($validated['verbose'] ?? false);
|
||||
|
||||
$service = app(\App\Services\ImportSimulationService::class);
|
||||
$service = app(ImportSimulationServiceV2::class);
|
||||
$result = $service->simulate($import, $limit, $verbose);
|
||||
|
||||
return response()->json($result);
|
||||
|
||||
Reference in New Issue
Block a user