#4 Prevent duplicate customers on create and update

Merged
dcovington merged 1 commits from Unique_Attribute into main 2 weeks ago
  1. +8
    -2
      .gitignore
  2. +30
    -0
      app/Controllers/CustomerController.php
  3. +18
    -0
      app/Repositories/CustomerRepository.php
  4. +4
    -0
      app/Views/customers/create.php
  5. +4
    -0
      app/Views/customers/edit.php

+ 8
- 2
.gitignore View File

@@ -46,5 +46,11 @@ node_modules/
npm-debug.log*
yarn-error.log*

.claude/
.abacusai/
.claude/*
.abacusai/*
graphify-out/*
.graphify_ast_extract.py
.graphify_ast.json
.graphify_detect.json
.graphify_python
.graphify_uncached.txt

+ 30
- 0
app/Controllers/CustomerController.php View File

@@ -91,6 +91,21 @@ class CustomerController extends Controller
]);
}

$encodedValues = json_encode($form['attribute_values'], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
$duplicate = $this->repo()->findDuplicate((int) $form['customer_type_id'], $encodedValues);

if ($duplicate !== null) {
$model->form = $form;
$model->errors['_duplicate'] = [
'A customer with these exact values already exists: <a href="/customers/' . (int) $duplicate['id'] . '/edit">Customer #' . (int) $duplicate['id'] . ' (' . htmlspecialchars((string) $duplicate['customer_type_name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . ')</a>.',
];

return $this->view('customers.create', [
'model' => $model,
'pageTitle' => $model->title,
]);
}

$customer = new Customer();
$customer->customerTypeId = (int) $form['customer_type_id'];
$customer->attributeValues = $form['attribute_values'];
@@ -159,6 +174,21 @@ class CustomerController extends Controller
]);
}

$encodedValues = json_encode($form['attribute_values'], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
$duplicate = $this->repo()->findDuplicate((int) $form['customer_type_id'], $encodedValues, (int) $id);

if ($duplicate !== null) {
$model->form = $form;
$model->errors['_duplicate'] = [
'These values are identical to an existing customer: <a href="/customers/' . (int) $duplicate['id'] . '/edit">Customer #' . (int) $duplicate['id'] . ' (' . htmlspecialchars((string) $duplicate['customer_type_name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . ')</a>.',
];

return $this->view('customers.edit', [
'model' => $model,
'pageTitle' => $model->title,
]);
}

$customer = new Customer();
$customer->id = (int) $id;
$customer->customerTypeId = (int) $form['customer_type_id'];


+ 18
- 0
app/Repositories/CustomerRepository.php View File

@@ -88,6 +88,24 @@ class CustomerRepository extends Repository
);
}

/** Returns an existing customer with the same type and attribute values, excluding $excludeId (use for update). */
public function findDuplicate(int $typeId, string $attributeValuesJson, int $excludeId = 0): ?array
{
$sql = 'SELECT TOP (1) c.id, ct.name AS customer_type_name
FROM customer c
INNER JOIN customer_type ct ON c.customer_type_id = ct.id
WHERE c.customer_type_id = :type_id
AND c.attribute_values = :attribute_values';
$params = ['type_id' => $typeId, 'attribute_values' => $attributeValuesJson];

if ($excludeId > 0) {
$sql .= ' AND c.id != :exclude_id';
$params['exclude_id'] = $excludeId;
}

return $this->database->first($sql, $params);
}

/** Used after INSERT to recover the generated id for audit logging. */
public function findLatestByType(int $typeId): ?array
{


+ 4
- 0
app/Views/customers/create.php View File

@@ -26,6 +26,10 @@ window.__initialCtVals = <?= json_encode($model->form['attribute_values'], JSON_
<div class="alert alert-error"><?= e($model->errors['_token'][0]) ?></div>
<?php endif; ?>

<?php if (isset($model->errors['_duplicate'])): ?>
<div class="alert alert-error"><?= $model->errors['_duplicate'][0] ?></div>
<?php endif; ?>

<form method="post" action="/customers" class="ct-form" novalidate>
<?= csrf_field() ?>



+ 4
- 0
app/Views/customers/edit.php View File

@@ -27,6 +27,10 @@ window.__initialCtVals = <?= json_encode($model->form['attribute_values'], JSON_
<div class="alert alert-error"><?= e($model->errors['_token'][0]) ?></div>
<?php endif; ?>

<?php if (isset($model->errors['_duplicate'])): ?>
<div class="alert alert-error"><?= $model->errors['_duplicate'][0] ?></div>
<?php endif; ?>

<form method="post" action="/customers/<?= e((string) $customerId) ?>/update" class="ct-form" novalidate>
<?= csrf_field() ?>



Loading…
Cancel
Save

Powered by TurnKey Linux.