613 lines
27 KiB
PHP
613 lines
27 KiB
PHP
<?php
|
||
|
||
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\Segment;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Str;
|
||
use Inertia\Inertia;
|
||
|
||
class ImportTemplateController extends Controller
|
||
{
|
||
public function index()
|
||
{
|
||
$templates = ImportTemplate::query()
|
||
->with(['client:id,uuid,person_id', 'client.person:id,full_name'])
|
||
->orderBy('name')
|
||
->get();
|
||
|
||
return Inertia::render('Imports/Templates/Index', [
|
||
'templates' => $templates->map(fn ($t) => [
|
||
'uuid' => $t->uuid,
|
||
'name' => $t->name,
|
||
'description' => $t->description,
|
||
'source_type' => $t->source_type,
|
||
'is_active' => $t->is_active,
|
||
'client' => $t->client ? [
|
||
'uuid' => $t->client->uuid,
|
||
'name' => $t->client->person?->full_name,
|
||
] : null,
|
||
]),
|
||
]);
|
||
}
|
||
|
||
// Show the template creation page
|
||
public function create()
|
||
{
|
||
// Preload clients for optional association (global when null)
|
||
$clients = Client::query()
|
||
->join('person', 'person.id', '=', 'clients.person_id')
|
||
->orderBy('person.full_name')
|
||
->get([
|
||
'clients.id', // kept for compatibility, UI will use uuid
|
||
'clients.uuid',
|
||
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,
|
||
]);
|
||
}
|
||
|
||
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)) {
|
||
$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'];
|
||
}
|
||
// 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'];
|
||
}
|
||
|
||
return null;
|
||
}, $raw['entities'])));
|
||
}
|
||
|
||
$data = validator($raw, [
|
||
'name' => 'required|string|max:100',
|
||
'description' => 'nullable|string|max:255',
|
||
'source_type' => 'required|string|in:csv,xml,xls,xlsx,json',
|
||
'default_record_type' => 'nullable|string|max:50',
|
||
'sample_headers' => 'nullable|array',
|
||
'client_id' => 'nullable|integer|exists:clients,id',
|
||
'is_active' => 'boolean',
|
||
'reactivate' => 'boolean',
|
||
'entities' => 'nullable|array',
|
||
'entities.*' => 'string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases,payments',
|
||
'mappings' => 'array',
|
||
'mappings.*.source_column' => 'required|string',
|
||
'mappings.*.entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases,payments',
|
||
'mappings.*.target_field' => 'nullable|string',
|
||
'mappings.*.transform' => 'nullable|string|max:50',
|
||
'mappings.*.apply_mode' => 'nullable|string|in:insert,update,both,keyref',
|
||
'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',
|
||
'meta.payments_import' => 'nullable|boolean',
|
||
'meta.contract_key_mode' => 'nullable|string|in:reference',
|
||
])->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) {
|
||
$paymentsImport = (bool) (data_get($data, 'meta.payments_import') ?? false);
|
||
$entities = $data['entities'] ?? [];
|
||
if ($paymentsImport) {
|
||
$entities = ['contracts', 'accounts', 'payments'];
|
||
}
|
||
$template = ImportTemplate::create([
|
||
'uuid' => (string) Str::uuid(),
|
||
'name' => $data['name'],
|
||
'description' => $data['description'] ?? null,
|
||
'source_type' => $data['source_type'],
|
||
'default_record_type' => $data['default_record_type'] ?? null,
|
||
'sample_headers' => $data['sample_headers'] ?? null,
|
||
'user_id' => $request->user()?->id,
|
||
'client_id' => $data['client_id'] ?? null,
|
||
'is_active' => $data['is_active'] ?? true,
|
||
'reactivate' => $data['reactivate'] ?? false,
|
||
'meta' => array_filter([
|
||
'entities' => $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'),
|
||
'payments_import' => $paymentsImport ?: null,
|
||
'contract_key_mode' => data_get($data, 'meta.contract_key_mode'),
|
||
], fn ($v) => ! is_null($v) && $v !== ''),
|
||
]);
|
||
|
||
foreach (($data['mappings'] ?? []) as $m) {
|
||
ImportTemplateMapping::create([
|
||
'import_template_id' => $template->id,
|
||
'entity' => $m['entity'] ?? null,
|
||
'source_column' => $m['source_column'],
|
||
'target_field' => $m['target_field'] ?? null,
|
||
'transform' => $m['transform'] ?? null,
|
||
'apply_mode' => $m['apply_mode'] ?? 'both',
|
||
'options' => $m['options'] ?? null,
|
||
'position' => $m['position'] ?? null,
|
||
]);
|
||
}
|
||
});
|
||
|
||
// Redirect to edit page for the newly created template
|
||
return redirect()
|
||
->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', 'Template created successfully.');
|
||
}
|
||
|
||
// Edit template UI (by uuid)
|
||
public function edit(ImportTemplate $template)
|
||
{
|
||
// Eager-load mappings
|
||
$template->load(['mappings']);
|
||
|
||
// Preload clients list (uuid + name) for possible reassignment
|
||
$clients = Client::query()
|
||
->join('person', 'person.id', '=', 'clients.person_id')
|
||
->orderBy('person.full_name')
|
||
->get([
|
||
'clients.uuid',
|
||
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,
|
||
'name' => $template->name,
|
||
'description' => $template->description,
|
||
'source_type' => $template->source_type,
|
||
'default_record_type' => $template->default_record_type,
|
||
'is_active' => $template->is_active,
|
||
'reactivate' => $template->reactivate,
|
||
'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']),
|
||
],
|
||
'clients' => $clients,
|
||
'segments' => $segments,
|
||
'decisions' => $decisions,
|
||
'actions' => $actions,
|
||
]);
|
||
}
|
||
|
||
// Add a new mapping to a template (by uuid)
|
||
public function addMapping(Request $request, ImportTemplate $template)
|
||
{
|
||
// Normalize empty transform to null
|
||
$raw = $request->all();
|
||
if (array_key_exists('transform', $raw) && $raw['transform'] === '') {
|
||
$raw['transform'] = null;
|
||
}
|
||
$data = validator($raw, [
|
||
'source_column' => 'required|string',
|
||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases,payments',
|
||
'target_field' => 'nullable|string',
|
||
'transform' => 'nullable|string|in:trim,upper,lower',
|
||
'apply_mode' => 'nullable|string|in:insert,update,both,keyref',
|
||
'options' => 'nullable|array',
|
||
'position' => 'nullable|integer',
|
||
])->validate();
|
||
|
||
// Avoid duplicates by source_column within the same template: update if exists
|
||
$existing = ImportTemplateMapping::where('import_template_id', $template->id)
|
||
->where('source_column', $data['source_column'])
|
||
->first();
|
||
|
||
if ($existing) {
|
||
$existing->update([
|
||
'target_field' => $data['target_field'] ?? $existing->target_field,
|
||
'entity' => $data['entity'] ?? $existing->entity,
|
||
'transform' => $data['transform'] ?? $existing->transform,
|
||
'apply_mode' => $data['apply_mode'] ?? $existing->apply_mode ?? 'both',
|
||
'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 {
|
||
$position = $data['position'] ?? (int) (($template->mappings()->max('position') ?? 0) + 1);
|
||
ImportTemplateMapping::create([
|
||
'import_template_id' => $template->id,
|
||
'entity' => $data['entity'] ?? null,
|
||
'source_column' => $data['source_column'],
|
||
'target_field' => $data['target_field'] ?? null,
|
||
'transform' => $data['transform'] ?? null,
|
||
'apply_mode' => $data['apply_mode'] ?? 'both',
|
||
'options' => $data['options'] ?? null,
|
||
'position' => $position,
|
||
]);
|
||
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', 'Mapping added');
|
||
}
|
||
}
|
||
|
||
// Update template basic fields
|
||
public function update(Request $request, ImportTemplate $template)
|
||
{
|
||
$raw = $request->all();
|
||
if (! empty($raw['client_uuid'] ?? null)) {
|
||
$raw['client_id'] = Client::where('uuid', $raw['client_uuid'])->value('id');
|
||
}
|
||
// If template already has mappings, lock client assignment on backend as well
|
||
// to prevent accidental clearing when client_uuid/client_id not sent.
|
||
$hasMappings = $template->mappings()->exists();
|
||
if ($hasMappings) {
|
||
unset($raw['client_id'], $raw['client_uuid']);
|
||
}
|
||
$data = validator($raw, [
|
||
'name' => 'required|string|max:100',
|
||
'description' => 'nullable|string|max:255',
|
||
'source_type' => 'required|string|in:csv,xml,xls,xlsx,json',
|
||
'default_record_type' => 'nullable|string|max:50',
|
||
'client_id' => 'nullable|integer|exists:clients,id',
|
||
'is_active' => 'boolean',
|
||
'reactivate' => 'boolean',
|
||
'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',
|
||
'meta.payments_import' => 'nullable|boolean',
|
||
'meta.contract_key_mode' => 'nullable|string|in:reference',
|
||
])->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']) === '')) {
|
||
unset($newMeta['delimiter']);
|
||
}
|
||
foreach (['segment_id', 'decision_id', 'action_id', 'payments_import', 'contract_key_mode'] as $k) {
|
||
if (array_key_exists($k, $newMeta) && ($newMeta[$k] === '' || is_null($newMeta[$k]))) {
|
||
unset($newMeta[$k]);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Finalize meta (ensure payments entities forced if enabled)
|
||
$finalMeta = $newMeta;
|
||
if (! empty($finalMeta['payments_import'])) {
|
||
$finalMeta['entities'] = ['contracts', 'accounts', 'payments'];
|
||
}
|
||
|
||
$update = [
|
||
'name' => $data['name'],
|
||
'description' => $data['description'] ?? null,
|
||
'source_type' => $data['source_type'],
|
||
'default_record_type' => $data['default_record_type'] ?? null,
|
||
// Only set client_id if explicitly present and not locked, otherwise keep existing
|
||
'is_active' => $data['is_active'] ?? $template->is_active,
|
||
'reactivate' => $data['reactivate'] ?? $template->reactivate,
|
||
'sample_headers' => $data['sample_headers'] ?? $template->sample_headers,
|
||
'meta' => $finalMeta,
|
||
];
|
||
if (! $hasMappings && array_key_exists('client_id', $data)) {
|
||
$update['client_id'] = $data['client_id'];
|
||
}
|
||
// When locked, do not touch client_id (prevents clearing to null)
|
||
$template->update($update);
|
||
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', 'Template updated');
|
||
}
|
||
|
||
// Bulk add multiple mappings from a textarea input
|
||
public function bulkAddMappings(Request $request, ImportTemplate $template)
|
||
{
|
||
// Accept either commas or newlines as separators
|
||
$raw = $request->all();
|
||
if (array_key_exists('transform', $raw) && $raw['transform'] === '') {
|
||
$raw['transform'] = null;
|
||
}
|
||
$data = validator($raw, [
|
||
'sources' => 'required|string', // comma and/or newline separated
|
||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases,payments',
|
||
'default_field' => 'nullable|string', // if provided, used as the field name for all entries
|
||
'apply_mode' => 'nullable|string|in:insert,update,both,keyref',
|
||
'transform' => 'nullable|string|in:trim,upper,lower',
|
||
'options' => 'nullable|array',
|
||
'group' => 'nullable|string|max:50', // convenience: will be wrapped into options.group
|
||
])->validate();
|
||
|
||
// Accept commas, semicolons, and newlines; strip surrounding quotes/apostrophes and whitespace
|
||
$list = preg_split('/[\r\n,;]+/', $data['sources']);
|
||
$list = array_values(array_filter(array_map(function ($s) {
|
||
$s = trim((string) $s);
|
||
// remove surrounding double/single quotes if present
|
||
$s = preg_replace('/^([\"\'])|([\"\'])$/u', '', $s) ?? $s;
|
||
|
||
return $s;
|
||
}, $list), fn ($s) => $s !== ''));
|
||
|
||
if (empty($list)) {
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('warning', 'No valid source columns provided.');
|
||
}
|
||
|
||
$basePosition = (int) (($template->mappings()->max('position') ?? 0));
|
||
$apply = $data['apply_mode'] ?? 'both';
|
||
$transform = $data['transform'] ?? null;
|
||
$entity = $data['entity'] ?? null;
|
||
$defaultField = $data['default_field'] ?? null; // allows forcing a specific field for all
|
||
|
||
// Build options payload once
|
||
$opts = [];
|
||
if (isset($data['options']) && is_array($data['options'])) {
|
||
$opts = $data['options'];
|
||
}
|
||
if (! empty($data['group'])) {
|
||
$opts['group'] = (string) $data['group'];
|
||
}
|
||
|
||
$created = 0;
|
||
$updated = 0;
|
||
DB::transaction(function () use ($template, $list, $apply, $transform, $entity, $defaultField, $basePosition, $opts, &$created, &$updated) {
|
||
foreach ($list as $idx => $source) {
|
||
$targetField = null;
|
||
if ($defaultField) {
|
||
$targetField = $entity ? ($entity.'.'.$defaultField) : $defaultField;
|
||
} elseif ($entity) {
|
||
$targetField = $entity.'.'.$source;
|
||
}
|
||
|
||
$existing = ImportTemplateMapping::where('import_template_id', $template->id)
|
||
->where('source_column', $source)
|
||
->first();
|
||
|
||
if ($existing) {
|
||
$existing->update([
|
||
'target_field' => $targetField ?? $existing->target_field,
|
||
'entity' => $entity ?? $existing->entity,
|
||
'transform' => $transform ?? $existing->transform,
|
||
'apply_mode' => $apply ?? $existing->apply_mode ?? 'both',
|
||
'options' => empty($opts) ? $existing->options : $opts,
|
||
// keep existing position
|
||
]);
|
||
$updated++;
|
||
} else {
|
||
ImportTemplateMapping::create([
|
||
'import_template_id' => $template->id,
|
||
'entity' => $entity,
|
||
'source_column' => $source,
|
||
'target_field' => $targetField,
|
||
'transform' => $transform,
|
||
'apply_mode' => $apply,
|
||
'options' => empty($opts) ? null : $opts,
|
||
'position' => $basePosition + $idx + 1,
|
||
]);
|
||
$created++;
|
||
}
|
||
}
|
||
});
|
||
|
||
$msg = [];
|
||
if ($created) {
|
||
$msg[] = "$created created";
|
||
}
|
||
if ($updated) {
|
||
$msg[] = "$updated updated";
|
||
}
|
||
$text = 'Mappings processed';
|
||
if (! empty($msg)) {
|
||
$text .= ': '.implode(', ', $msg);
|
||
}
|
||
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', $text);
|
||
}
|
||
|
||
// Update an existing mapping
|
||
public function updateMapping(Request $request, ImportTemplate $template, ImportTemplateMapping $mapping)
|
||
{
|
||
if ($mapping->import_template_id !== $template->id) {
|
||
abort(404);
|
||
}
|
||
$raw = $request->all();
|
||
if (array_key_exists('transform', $raw) && $raw['transform'] === '') {
|
||
$raw['transform'] = null;
|
||
}
|
||
$data = validator($raw, [
|
||
'source_column' => 'required|string',
|
||
'entity' => 'nullable|string|in:person,person_addresses,person_phones,emails,accounts,contracts,client_cases,payments',
|
||
'target_field' => 'nullable|string',
|
||
'transform' => 'nullable|string|in:trim,upper,lower',
|
||
'apply_mode' => 'nullable|string|in:insert,update,both,keyref',
|
||
'options' => 'nullable|array',
|
||
'position' => 'nullable|integer',
|
||
])->validate();
|
||
$mapping->update([
|
||
'source_column' => $data['source_column'],
|
||
'entity' => $data['entity'] ?? null,
|
||
'target_field' => $data['target_field'] ?? null,
|
||
'transform' => $data['transform'] ?? null,
|
||
'apply_mode' => $data['apply_mode'] ?? 'both',
|
||
'options' => $data['options'] ?? null,
|
||
'position' => $data['position'] ?? $mapping->position,
|
||
]);
|
||
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', 'Mapping updated');
|
||
}
|
||
|
||
// Delete a mapping
|
||
public function deleteMapping(ImportTemplate $template, ImportTemplateMapping $mapping)
|
||
{
|
||
if ($mapping->import_template_id !== $template->id) {
|
||
abort(404);
|
||
}
|
||
$mapping->delete();
|
||
|
||
return redirect()->route('importTemplates.edit', ['template' => $template->uuid])
|
||
->with('success', 'Mapping deleted');
|
||
}
|
||
|
||
// Reorder mappings in bulk
|
||
public function reorderMappings(Request $request, ImportTemplate $template)
|
||
{
|
||
$data = $request->validate([
|
||
'order' => 'required|array',
|
||
'order.*' => 'integer',
|
||
]);
|
||
$ids = $data['order'];
|
||
// 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');
|
||
}
|
||
// 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');
|
||
}
|
||
|
||
// Apply a template’s mappings to a specific import (copy into import_mappings)
|
||
public function applyToImport(Request $request, ImportTemplate $template, Import $import)
|
||
{
|
||
// optional: clear previous mappings
|
||
$clear = $request->boolean('clear', true);
|
||
$copied = 0;
|
||
DB::transaction(function () use ($clear, $template, $import, &$copied) {
|
||
if ($clear) {
|
||
\DB::table('import_mappings')->where('import_id', $import->id)->delete();
|
||
}
|
||
|
||
$rows = $template->mappings()->orderBy('position')->get();
|
||
foreach ($rows as $row) {
|
||
$options = $row->options;
|
||
if (is_array($options) || $options instanceof \JsonSerializable || $options instanceof \stdClass) {
|
||
$options = json_encode($options);
|
||
}
|
||
\DB::table('import_mappings')->insert([
|
||
'import_id' => $import->id,
|
||
'entity' => $row->entity,
|
||
'source_column' => $row->source_column,
|
||
'target_field' => $row->target_field,
|
||
'transform' => $row->transform,
|
||
'apply_mode' => $row->apply_mode ?? 'both',
|
||
'options' => $options,
|
||
'position' => $row->position ?? null,
|
||
'created_at' => now(),
|
||
'updated_at' => now(),
|
||
]);
|
||
$copied++;
|
||
}
|
||
|
||
// 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]);
|
||
}
|
||
|
||
// Delete a template and cascade delete its mappings; detach from imports
|
||
public function destroy(ImportTemplate $template)
|
||
{
|
||
DB::transaction(function () use ($template) {
|
||
// Nullify references from imports to this template
|
||
\DB::table('imports')->where('import_template_id', $template->id)->update(['import_template_id' => null]);
|
||
// Delete mappings first (if FK cascade not set)
|
||
\DB::table('import_template_mappings')->where('import_template_id', $template->id)->delete();
|
||
// Delete the template
|
||
$template->delete();
|
||
});
|
||
|
||
return redirect()->route('importTemplates.index')->with('success', 'Template deleted');
|
||
}
|
||
}
|