changes 0230092025
This commit is contained in:
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Action;
|
||||
use App\Models\Client;
|
||||
use App\Models\Decision;
|
||||
use App\Models\Import;
|
||||
use App\Models\ImportTemplate;
|
||||
use App\Models\ImportTemplateMapping;
|
||||
use App\Models\Client;
|
||||
use App\Models\Segment;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -21,7 +24,7 @@ public function index()
|
||||
->get();
|
||||
|
||||
return Inertia::render('Imports/Templates/Index', [
|
||||
'templates' => $templates->map(fn($t) => [
|
||||
'templates' => $templates->map(fn ($t) => [
|
||||
'uuid' => $t->uuid,
|
||||
'name' => $t->name,
|
||||
'description' => $t->description,
|
||||
@@ -48,8 +51,22 @@ public function create()
|
||||
DB::raw('person.full_name as name'),
|
||||
]);
|
||||
|
||||
$segments = Segment::query()->orderBy('name')->get(['id', 'name']);
|
||||
$decisions = Decision::query()->orderBy('name')->get(['id', 'name']);
|
||||
$actions = Action::with(['decisions:id,name'])
|
||||
->orderBy('name')
|
||||
->get(['id', 'name'])
|
||||
->map(fn ($a) => [
|
||||
'id' => $a->id,
|
||||
'name' => $a->name,
|
||||
'decisions' => $a->decisions->map(fn ($d) => ['id' => $d->id, 'name' => $d->name])->values(),
|
||||
]);
|
||||
|
||||
return Inertia::render('Imports/Templates/Create', [
|
||||
'clients' => $clients,
|
||||
'segments' => $segments,
|
||||
'decisions' => $decisions,
|
||||
'actions' => $actions,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -57,8 +74,15 @@ public function store(Request $request)
|
||||
{
|
||||
// Normalize payload to be resilient to UI variations
|
||||
$raw = $request->all();
|
||||
// Allow passing default segment/decision either inside meta or as top-level
|
||||
if (isset($raw['segment_id']) && ! isset($raw['meta']['segment_id'])) {
|
||||
$raw['meta']['segment_id'] = $raw['segment_id'];
|
||||
}
|
||||
if (isset($raw['decision_id']) && ! isset($raw['meta']['decision_id'])) {
|
||||
$raw['meta']['decision_id'] = $raw['decision_id'];
|
||||
}
|
||||
// Resolve client by uuid if provided, or cast string numeric to int
|
||||
if (!empty($raw['client_uuid'] ?? null)) {
|
||||
if (! empty($raw['client_uuid'] ?? null)) {
|
||||
$raw['client_id'] = Client::where('uuid', $raw['client_uuid'])->value('id');
|
||||
} elseif (isset($raw['client_id']) && is_string($raw['client_id']) && ctype_digit($raw['client_id'])) {
|
||||
$raw['client_id'] = (int) $raw['client_id'];
|
||||
@@ -66,8 +90,13 @@ public function store(Request $request)
|
||||
// Normalize entities to array of strings
|
||||
if (isset($raw['entities']) && is_array($raw['entities'])) {
|
||||
$raw['entities'] = array_values(array_filter(array_map(function ($e) {
|
||||
if (is_string($e)) return $e;
|
||||
if (is_array($e) && array_key_exists('value', $e)) return (string) $e['value'];
|
||||
if (is_string($e)) {
|
||||
return $e;
|
||||
}
|
||||
if (is_array($e) && array_key_exists('value', $e)) {
|
||||
return (string) $e['value'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}, $raw['entities'])));
|
||||
}
|
||||
@@ -84,14 +113,29 @@ public function store(Request $request)
|
||||
'entities.*' => 'string|in:person,person_addresses,person_phones,emails,accounts,contracts',
|
||||
'mappings' => 'array',
|
||||
'mappings.*.source_column' => 'required|string',
|
||||
'mappings.*.entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts',
|
||||
'mappings.*.entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases',
|
||||
'mappings.*.target_field' => 'nullable|string',
|
||||
'mappings.*.transform' => 'nullable|string|max:50',
|
||||
'mappings.*.apply_mode' => 'nullable|string|in:insert,update,both',
|
||||
'mappings.*.options' => 'nullable|array',
|
||||
'mappings.*.position' => 'nullable|integer',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.segment_id' => 'nullable|integer|exists:segments,id',
|
||||
'meta.decision_id' => 'nullable|integer|exists:decisions,id',
|
||||
'meta.action_id' => 'nullable|integer|exists:actions,id',
|
||||
])->validate();
|
||||
|
||||
// Ensure decision belongs to action if both provided in meta
|
||||
$meta = $data['meta'] ?? [];
|
||||
if (! empty($meta['action_id']) && ! empty($meta['decision_id'])) {
|
||||
$belongs = \DB::table('action_decision')
|
||||
->where('action_id', $meta['action_id'])
|
||||
->where('decision_id', $meta['decision_id'])
|
||||
->exists();
|
||||
if (! $belongs) {
|
||||
return back()->withErrors(['meta.decision_id' => 'Selected decision is not associated with the chosen action.'])->withInput();
|
||||
}
|
||||
}
|
||||
$template = null;
|
||||
DB::transaction(function () use (&$template, $request, $data) {
|
||||
$template = ImportTemplate::create([
|
||||
@@ -104,9 +148,12 @@ public function store(Request $request)
|
||||
'user_id' => $request->user()?->id,
|
||||
'client_id' => $data['client_id'] ?? null,
|
||||
'is_active' => $data['is_active'] ?? true,
|
||||
'meta' => [
|
||||
'meta' => array_filter([
|
||||
'entities' => $data['entities'] ?? [],
|
||||
],
|
||||
'segment_id' => data_get($data, 'meta.segment_id'),
|
||||
'decision_id' => data_get($data, 'meta.decision_id'),
|
||||
'action_id' => data_get($data, 'meta.action_id'),
|
||||
], fn ($v) => ! is_null($v) && $v !== ''),
|
||||
]);
|
||||
|
||||
foreach (($data['mappings'] ?? []) as $m) {
|
||||
@@ -144,6 +191,17 @@ public function edit(ImportTemplate $template)
|
||||
DB::raw('person.full_name as name'),
|
||||
]);
|
||||
|
||||
$segments = Segment::query()->orderBy('name')->get(['id', 'name']);
|
||||
$decisions = Decision::query()->orderBy('name')->get(['id', 'name']);
|
||||
$actions = Action::with(['decisions:id,name'])
|
||||
->orderBy('name')
|
||||
->get(['id', 'name'])
|
||||
->map(fn ($a) => [
|
||||
'id' => $a->id,
|
||||
'name' => $a->name,
|
||||
'decisions' => $a->decisions->map(fn ($d) => ['id' => $d->id, 'name' => $d->name])->values(),
|
||||
]);
|
||||
|
||||
return Inertia::render('Imports/Templates/Edit', [
|
||||
'template' => [
|
||||
'uuid' => $template->uuid,
|
||||
@@ -155,9 +213,12 @@ public function edit(ImportTemplate $template)
|
||||
'client_uuid' => $template->client?->uuid,
|
||||
'sample_headers' => $template->sample_headers,
|
||||
'meta' => $template->meta,
|
||||
'mappings' => $template->mappings()->orderBy('position')->get(['id','entity','source_column','target_field','transform','apply_mode','options','position']),
|
||||
'mappings' => $template->mappings()->orderBy('position')->get(['id', 'entity', 'source_column', 'target_field', 'transform', 'apply_mode', 'options', 'position']),
|
||||
],
|
||||
'clients' => $clients,
|
||||
'segments' => $segments,
|
||||
'decisions' => $decisions,
|
||||
'actions' => $actions,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -171,7 +232,7 @@ public function addMapping(Request $request, ImportTemplate $template)
|
||||
}
|
||||
$data = validator($raw, [
|
||||
'source_column' => 'required|string',
|
||||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts',
|
||||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases',
|
||||
'target_field' => 'nullable|string',
|
||||
'transform' => 'nullable|string|in:trim,upper,lower',
|
||||
'apply_mode' => 'nullable|string|in:insert,update,both',
|
||||
@@ -193,6 +254,7 @@ public function addMapping(Request $request, ImportTemplate $template)
|
||||
'options' => $data['options'] ?? $existing->options,
|
||||
'position' => $data['position'] ?? $existing->position,
|
||||
]);
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('info', 'Mapping already existed. Updated existing mapping.');
|
||||
} else {
|
||||
@@ -207,6 +269,7 @@ public function addMapping(Request $request, ImportTemplate $template)
|
||||
'options' => $data['options'] ?? null,
|
||||
'position' => $position,
|
||||
]);
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('success', 'Mapping added');
|
||||
}
|
||||
@@ -216,7 +279,7 @@ public function addMapping(Request $request, ImportTemplate $template)
|
||||
public function update(Request $request, ImportTemplate $template)
|
||||
{
|
||||
$raw = $request->all();
|
||||
if (!empty($raw['client_uuid'] ?? null)) {
|
||||
if (! empty($raw['client_uuid'] ?? null)) {
|
||||
$raw['client_id'] = Client::where('uuid', $raw['client_uuid'])->value('id');
|
||||
}
|
||||
$data = validator($raw, [
|
||||
@@ -229,16 +292,35 @@ public function update(Request $request, ImportTemplate $template)
|
||||
'sample_headers' => 'nullable|array',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.delimiter' => 'nullable|string|max:4',
|
||||
'meta.segment_id' => 'nullable|integer|exists:segments,id',
|
||||
'meta.decision_id' => 'nullable|integer|exists:decisions,id',
|
||||
'meta.action_id' => 'nullable|integer|exists:actions,id',
|
||||
])->validate();
|
||||
|
||||
// Validate decision/action consistency on update as well
|
||||
$meta = $data['meta'] ?? [];
|
||||
if (! empty($meta['action_id']) && ! empty($meta['decision_id'])) {
|
||||
$belongs = \DB::table('action_decision')
|
||||
->where('action_id', $meta['action_id'])
|
||||
->where('decision_id', $meta['decision_id'])
|
||||
->exists();
|
||||
if (! $belongs) {
|
||||
return back()->withErrors(['meta.decision_id' => 'Selected decision is not associated with the chosen action.'])->withInput();
|
||||
}
|
||||
}
|
||||
// Merge meta safely, preserving existing keys when not provided
|
||||
$newMeta = $template->meta ?? [];
|
||||
if (array_key_exists('meta', $data) && is_array($data['meta'])) {
|
||||
$newMeta = array_merge($newMeta, $data['meta']);
|
||||
// Drop empty delimiter to allow auto-detect
|
||||
if (array_key_exists('delimiter', $newMeta) && (!is_string($newMeta['delimiter']) || trim((string) $newMeta['delimiter']) === '')) {
|
||||
if (array_key_exists('delimiter', $newMeta) && (! is_string($newMeta['delimiter']) || trim((string) $newMeta['delimiter']) === '')) {
|
||||
unset($newMeta['delimiter']);
|
||||
}
|
||||
foreach (['segment_id', 'decision_id', 'action_id'] as $k) {
|
||||
if (array_key_exists($k, $newMeta) && ($newMeta[$k] === '' || is_null($newMeta[$k]))) {
|
||||
unset($newMeta[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$template->update([
|
||||
@@ -266,14 +348,14 @@ public function bulkAddMappings(Request $request, ImportTemplate $template)
|
||||
}
|
||||
$data = validator($raw, [
|
||||
'sources' => 'required|string', // comma and/or newline separated
|
||||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts',
|
||||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases',
|
||||
'default_field' => 'nullable|string', // if provided, used as the field name for all entries
|
||||
'apply_mode' => 'nullable|string|in:insert,update,both',
|
||||
'transform' => 'nullable|string|in:trim,upper,lower',
|
||||
])->validate();
|
||||
|
||||
$list = preg_split('/\r?\n|,/', $data['sources']);
|
||||
$list = array_values(array_filter(array_map(fn($s) => trim($s), $list), fn($s) => $s !== ''));
|
||||
$list = array_values(array_filter(array_map(fn ($s) => trim($s), $list), fn ($s) => $s !== ''));
|
||||
|
||||
if (empty($list)) {
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
@@ -286,14 +368,15 @@ public function bulkAddMappings(Request $request, ImportTemplate $template)
|
||||
$entity = $data['entity'] ?? null;
|
||||
$defaultField = $data['default_field'] ?? null; // allows forcing a specific field for all
|
||||
|
||||
$created = 0; $updated = 0;
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
DB::transaction(function () use ($template, $list, $apply, $transform, $entity, $defaultField, $basePosition, &$created, &$updated) {
|
||||
foreach ($list as $idx => $source) {
|
||||
$targetField = null;
|
||||
if ($defaultField) {
|
||||
$targetField = $entity ? ($entity . '.' . $defaultField) : $defaultField;
|
||||
$targetField = $entity ? ($entity.'.'.$defaultField) : $defaultField;
|
||||
} elseif ($entity) {
|
||||
$targetField = $entity . '.' . $source;
|
||||
$targetField = $entity.'.'.$source;
|
||||
}
|
||||
|
||||
$existing = ImportTemplateMapping::where('import_template_id', $template->id)
|
||||
@@ -327,10 +410,17 @@ public function bulkAddMappings(Request $request, ImportTemplate $template)
|
||||
});
|
||||
|
||||
$msg = [];
|
||||
if ($created) $msg[] = "$created created";
|
||||
if ($updated) $msg[] = "$updated updated";
|
||||
if ($created) {
|
||||
$msg[] = "$created created";
|
||||
}
|
||||
if ($updated) {
|
||||
$msg[] = "$updated updated";
|
||||
}
|
||||
$text = 'Mappings processed';
|
||||
if (!empty($msg)) $text .= ': ' . implode(', ', $msg);
|
||||
if (! empty($msg)) {
|
||||
$text .= ': '.implode(', ', $msg);
|
||||
}
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('success', $text);
|
||||
}
|
||||
@@ -338,7 +428,9 @@ public function bulkAddMappings(Request $request, ImportTemplate $template)
|
||||
// Update an existing mapping
|
||||
public function updateMapping(Request $request, ImportTemplate $template, ImportTemplateMapping $mapping)
|
||||
{
|
||||
if ($mapping->import_template_id !== $template->id) abort(404);
|
||||
if ($mapping->import_template_id !== $template->id) {
|
||||
abort(404);
|
||||
}
|
||||
$raw = $request->all();
|
||||
if (array_key_exists('transform', $raw) && $raw['transform'] === '') {
|
||||
$raw['transform'] = null;
|
||||
@@ -361,6 +453,7 @@ public function updateMapping(Request $request, ImportTemplate $template, Import
|
||||
'options' => $data['options'] ?? null,
|
||||
'position' => $data['position'] ?? $mapping->position,
|
||||
]);
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('success', 'Mapping updated');
|
||||
}
|
||||
@@ -368,8 +461,11 @@ public function updateMapping(Request $request, ImportTemplate $template, Import
|
||||
// Delete a mapping
|
||||
public function deleteMapping(ImportTemplate $template, ImportTemplateMapping $mapping)
|
||||
{
|
||||
if ($mapping->import_template_id !== $template->id) abort(404);
|
||||
if ($mapping->import_template_id !== $template->id) {
|
||||
abort(404);
|
||||
}
|
||||
$mapping->delete();
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('success', 'Mapping deleted');
|
||||
}
|
||||
@@ -385,11 +481,14 @@ public function reorderMappings(Request $request, ImportTemplate $template)
|
||||
// Ensure all ids belong to template
|
||||
$validIds = ImportTemplateMapping::where('import_template_id', $template->id)
|
||||
->whereIn('id', $ids)->pluck('id')->all();
|
||||
if (count($validIds) !== count($ids)) abort(422, 'Invalid mapping ids');
|
||||
if (count($validIds) !== count($ids)) {
|
||||
abort(422, 'Invalid mapping ids');
|
||||
}
|
||||
// Apply new positions
|
||||
foreach ($ids as $idx => $id) {
|
||||
ImportTemplateMapping::where('id', $id)->update(['position' => $idx]);
|
||||
}
|
||||
|
||||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||||
->with('success', 'Mappings reordered');
|
||||
}
|
||||
@@ -422,7 +521,20 @@ public function applyToImport(Request $request, ImportTemplate $template, Import
|
||||
$copied++;
|
||||
}
|
||||
|
||||
$import->update(['import_template_id' => $template->id]);
|
||||
// Merge default actions (segment/decision) into import meta for processing
|
||||
$importMeta = $import->meta ?? [];
|
||||
$tplMeta = $template->meta ?? [];
|
||||
$merged = array_merge($importMeta, array_filter([
|
||||
'segment_id' => $tplMeta['segment_id'] ?? null,
|
||||
'decision_id' => $tplMeta['decision_id'] ?? null,
|
||||
'action_id' => $tplMeta['action_id'] ?? null,
|
||||
'template_name' => $template->name,
|
||||
], fn ($v) => ! is_null($v) && $v !== ''));
|
||||
|
||||
$import->update([
|
||||
'import_template_id' => $template->id,
|
||||
'meta' => $merged,
|
||||
]);
|
||||
});
|
||||
|
||||
return response()->json(['ok' => true, 'copied' => $copied, 'cleared' => $clear]);
|
||||
|
||||
Reference in New Issue
Block a user