Fixes for invoicing projects from react where custom values are not passed across to the invoice

This commit is contained in:
David Bomba 2025-08-26 20:33:52 +10:00
parent 799425478d
commit 2ed4beb6e2
4 changed files with 88 additions and 53 deletions

View File

@ -114,6 +114,31 @@ class StoreTaskRequest extends Request
$this->files->set('file', [$this->file('file')]);
}
if(isset($input['time_log']) &&is_string($input['time_log'])) {
$input['time_log'] = json_decode($input['time_log'], true);
}
if(isset($input['time_log']) && is_array($input['time_log'])) {
$time_logs = $input['time_log'];
foreach($time_logs as &$time_log) {
if (is_string($time_log)) {
continue; //catch if it isn't even a proper time log
}
$time_log[0] = intval($time_log[0]);
$time_log[1] = intval($time_log[1]);
$time_log[2] = strval($time_log[2] ?? '');
$time_log[3] = boolval($time_log[3] ?? true);
}
$input['time_log'] = json_encode($time_logs);
}
/* Ensure the project is related */
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();

View File

@ -131,6 +131,32 @@ class UpdateTaskRequest extends Request
$input['color'] = '';
}
if(isset($input['time_log']) &&is_string($input['time_log'])) {
$input['time_log'] = json_decode($input['time_log'], true);
}
if(isset($input['time_log']) && is_array($input['time_log'])) {
$time_logs = $input['time_log'];
foreach($time_logs as &$time_log) {
if (is_string($time_log)) {
continue; //catch if it isn't even a proper time log
}
$time_log[0] = intval($time_log[0] ?? 0);
$time_log[1] = intval($time_log[1] ?? 0);
$time_log[2] = strval($time_log[2] ?? '');
$time_log[3] = boolval($time_log[3] ?? true);
}
$input['time_log'] = json_encode($time_logs);
}
if (isset($input['project_id']) && isset($input['client_id'])) {
$search_project_with_client = Project::withTrashed()->where('id', $input['project_id'])->where('client_id', $input['client_id'])->company()->doesntExist();

View File

@ -58,7 +58,10 @@ class ProjectRepository extends BaseRepository
$item->task_id = $task->hashed_id;
$item->tax_id = (string) Product::PRODUCT_TYPE_SERVICE;
$item->type_id = '2';
$item->custom_value1 = $task->custom_value1;
$item->custom_value2 = $task->custom_value2;
$item->custom_value3 = $task->custom_value3;
$item->custom_value4 = $task->custom_value4;
$lines[] = $item;
}
@ -86,6 +89,10 @@ class ProjectRepository extends BaseRepository
$item->tax_id = (string) Product::PRODUCT_TYPE_PHYSICAL;
$item->expense_id = $expense->hashed_id;
$item->type_id = '1';
$item->custom_value1 = $expense->custom_value1;
$item->custom_value2 = $expense->custom_value2;
$item->custom_value3 = $expense->custom_value3;
$item->custom_value4 = $expense->custom_value4;
$lines[] = $item;
});

View File

@ -144,16 +144,15 @@ class TaskApiTest extends TestCase
$data = [
'client_id' => $this->client->hashed_id,
'description' => 'Test Task',
'time_log' => '[[1731391977,1731399177,null,2342432],[1731399178,1731499177,null, 1231231]]',
'time_log' => '[[1731391977,1731399177,null,2342432],[1731399178,1731499177, null, 1231231]]',
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson("/api/v1/tasks", $data);
$response->assertStatus(422);
$response->assertStatus(200);
}
@ -486,6 +485,7 @@ class TaskApiTest extends TestCase
$response->assertStatus(200);
nlog($response->json());
}
public function testUserFilters()
@ -612,8 +612,9 @@ class TaskApiTest extends TestCase
'X-API-TOKEN' => $this->token,
])->postJson("/api/v1/tasks", $data);
$response->assertStatus(422);
$response->assertStatus(200);
$this->assertEquals('[]', $response->json()['data']['time_log']);
}
public function testTaskClientRateSet()
@ -657,11 +658,14 @@ class TaskApiTest extends TestCase
'X-API-TOKEN' => $this->token,
])->postJson("/api/v1/tasks", $data);
$response->assertStatus(422);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals('[]', $response->json()['data']['time_log']);
}
public function testTaskProjectRateSet()
@ -753,9 +757,8 @@ class TaskApiTest extends TestCase
$this->assertIsArray($logs);
}
public function testStartStopSanity()
{
@ -781,7 +784,8 @@ class TaskApiTest extends TestCase
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray());
$response->assertStatus(422);
// nlog($response->json());
$response->assertStatus(200);
$task->time_log = null;
@ -1096,33 +1100,6 @@ class TaskApiTest extends TestCase
}
// public function testTaskLocking()
// {
// $data = [
// 'timelog' => [[1,2],[3,4]],
// ];
// $response = $this->withHeaders([
// 'X-API-SECRET' => config('ninja.api_secret'),
// 'X-API-TOKEN' => $this->token,
// ])->post('/api/v1/tasks', $data);
// $arr = $response->json();
// $response->assertStatus(200);
// $response = $this->withHeaders([
// 'X-API-SECRET' => config('ninja.api_secret'),
// 'X-API-TOKEN' => $this->token,
// ])->putJson('/api/v1/tasks/' . $arr['data']['id'], $data);
// $arr = $response->json();
// $response->assertStatus(200);
// }
public function testTimeLogValidation()
@ -1136,8 +1113,10 @@ class TaskApiTest extends TestCase
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/tasks', $data);
$response->assertStatus(422);
$response->assertStatus(200);
$this->assertEquals('[]', $response->json()['data']['time_log']);
}
public function testTimeLogValidation1()
@ -1185,6 +1164,7 @@ class TaskApiTest extends TestCase
$response->assertStatus(422);
}
public function testTimeLogValidation4()
@ -1255,22 +1235,21 @@ class TaskApiTest extends TestCase
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/tasks/'.$arr['data']['id'], $data);
])->putJson('/api/v1/tasks/'.$arr['data']['id'], $data);
$response->assertStatus(200);
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tasks', $data);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/tasks', $data);
$arr = $response->json();
} catch (ValidationException $e) {
$response->assertStatus(302);
}
$arr = $response->json();
$this->assertNotEmpty($arr['data']['number']);
$response->assertStatus(422);
// $this->assertNotEmpty($arr['data']['number']);
}
public function testTaskPostNoDefinedTaskNumber()
@ -1295,15 +1274,13 @@ class TaskApiTest extends TestCase
'client_id' => $this->faker->firstName(),
];
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tasks', $data);
])->postJson('/api/v1/tasks', $data);
$arr = $response->json();
} catch (ValidationException $e) {
$response->assertStatus(302);
}
$response->assertStatus(422);
}
public function testTaskPostWithActionStart()