fix: handle contact details on create

Separate nested contact details from the base payload, propagate sync failures to the API response, and add a regression test covering contact creation with details.
This commit is contained in:
mahdahar 2026-04-13 13:16:06 +07:00
parent ee7b677ae4
commit 1c1808fdb9
3 changed files with 98 additions and 41 deletions

View File

@ -72,8 +72,17 @@ class ContactController extends BaseController {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); } if (!$this->validateData($input, $this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); }
try { try {
$id = $this->model->saveContact($input,true); $result = $this->model->saveContact($input);
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201);
if (($result['status'] ?? 'error') !== 'success') {
return $this->respond([
'status' => 'failed',
'message' => $result['message'] ?? 'Failed to create contact',
'data' => []
], 400);
}
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $result ], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }

View File

@ -79,6 +79,9 @@ class ContactModel extends BaseModel {
$db->transStart(); $db->transStart();
try { try {
$details = $data['Details'] ?? [];
unset($data['Details']);
if (!empty($data['ContactID'])) { if (!empty($data['ContactID'])) {
$contactId = $data['ContactID']; $contactId = $data['ContactID'];
$this->update($contactId, $data); $this->update($contactId, $data);
@ -90,9 +93,9 @@ class ContactModel extends BaseModel {
throw new \RuntimeException('Failed to save contact'); throw new \RuntimeException('Failed to save contact');
} }
if (!empty($data['Details'])) { if (!empty($details)) {
$modelDetail = new \App\Models\Contact\ContactDetailModel(); $modelDetail = new \App\Models\Contact\ContactDetailModel();
$result = $modelDetail->syncDetails($contactId, $data['Details']); $result = $modelDetail->syncDetails($contactId, $details);
if ($result['status'] !== 'success') { if ($result['status'] !== 'success') {
throw new \RuntimeException('SyncDetails failed: ' . $result['message']); throw new \RuntimeException('SyncDetails failed: ' . $result['message']);
@ -104,6 +107,7 @@ class ContactModel extends BaseModel {
return [ return [
'status' => 'success', 'status' => 'success',
'ContactID' => $contactId, 'ContactID' => $contactId,
'DetailsCount' => count($details),
]; ];
} catch (\Throwable $e) { } catch (\Throwable $e) {
$db->transRollback(); $db->transRollback();

View File

@ -111,6 +111,50 @@ class ContactControllerTest extends CIUnitTestCase
$this->assertIsInt($data['data']['ContactID']); $this->assertIsInt($data['data']['ContactID']);
} }
public function testCreateContactWithDetails()
{
$contactData = [
'NameFirst' => 'TestContact' . time(),
'NameLast' => 'LastName',
'Initial' => 'TC',
'Details' => [
[
'SiteID' => '1',
'ContactCode' => 'CODE1',
'ContactEmail' => 'code1@example.com',
'OccupationID' => '1',
'JobTitle' => 'Doctor',
'Department' => 'General',
],
[
'SiteID' => '2',
'ContactCode' => 'CODE2',
'ContactEmail' => 'code2@example.com',
'OccupationID' => '2',
'JobTitle' => 'Specialist',
'Department' => 'Laboratory',
],
],
];
$result = $this->withHeaders(['Cookie' => 'token=' . $this->token])
->withBody(json_encode($contactData))
->call('post', 'api/contact');
$result->assertStatus(201);
$data = json_decode($result->getJSON(), true);
$contactId = $data['data']['ContactID'] ?? null;
$this->assertIsInt($contactId);
$show = $this->callProtected('get', 'api/contact/' . $contactId);
$show->assertStatus(200);
$showData = json_decode($show->getJSON(), true)['data'];
$this->assertCount(2, $showData['Details']);
$this->assertEqualsCanonicalizing(['1', '2'], array_column($showData['Details'], 'SiteID'));
}
public function testPartialUpdateContactWithSingleField() public function testPartialUpdateContactWithSingleField()
{ {
$contactId = $this->createContact(['NameFirst' => 'Original']); $contactId = $this->createContact(['NameFirst' => 'Original']);
@ -121,7 +165,7 @@ class ContactControllerTest extends CIUnitTestCase
'NameFirst' => 'Patched' 'NameFirst' => 'Patched'
]); ]);
$patch->assertStatus(201); $patch->assertStatus(200);
$response = json_decode($patch->getJSON(), true); $response = json_decode($patch->getJSON(), true);
$this->assertEquals('success', $response['status']); $this->assertEquals('success', $response['status']);