mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Updates for task time log parsing
This commit is contained in:
parent
c8408bfa36
commit
4cbf10096b
@ -54,7 +54,13 @@ class StoreTaskRequest extends Request
|
|||||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.$user->company()->id.',is_deleted,0';
|
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
$rules['time_log'] = ['bail',function ($attribute, $values, $fail) {
|
||||||
|
|
||||||
|
if(!is_array(json_decode($values, true))) {
|
||||||
|
$fail('The '.$attribute.' must be a valid array.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($values as $k) {
|
foreach ($values as $k) {
|
||||||
if (!is_int($k[0]) || !is_int($k[1])) {
|
if (!is_int($k[0]) || !is_int($k[1])) {
|
||||||
$fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.');
|
$fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.');
|
||||||
@ -110,6 +116,10 @@ class StoreTaskRequest extends Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}'){
|
||||||
|
$input['time_log'] = json_encode([]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,26 +35,38 @@ class UpdateTaskRequest extends Request
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth()->user()->can('edit', $this->task);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->can('edit', $this->task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
$rules = [];
|
$rules = [];
|
||||||
|
|
||||||
if (isset($this->number)) {
|
if (isset($this->number)) {
|
||||||
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id);
|
$rules['number'] = Rule::unique('tasks')->where('company_id', $user->company()->id)->ignore($this->task->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->client_id)) {
|
if (isset($this->client_id)) {
|
||||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->project_id)) {
|
if (isset($this->project_id)) {
|
||||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
|
}
|
||||||
|
|
||||||
|
$rules['time_log'] = ['bail', function ($attribute, $values, $fail) {
|
||||||
|
|
||||||
|
if(!is_array(json_decode($values, true))) {
|
||||||
|
$fail('The '.$attribute.' must be a valid array.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
|
||||||
foreach ($values as $k) {
|
foreach ($values as $k) {
|
||||||
if (!is_int($k[0]) || !is_int($k[1])) {
|
if (!is_int($k[0]) || !is_int($k[1])) {
|
||||||
$fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.');
|
$fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.');
|
||||||
@ -113,6 +125,10 @@ class UpdateTaskRequest extends Request
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}') {
|
||||||
|
$input['time_log'] = json_encode([]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ class Task extends BaseModel
|
|||||||
public function processLogs()
|
public function processLogs()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
collect($this->timelog)->map(function ($log){
|
collect($this->time_log)->map(function ($log){
|
||||||
|
|
||||||
$parent_entity = $this->client ?? $this->company;
|
$parent_entity = $this->client ?? $this->company;
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* Initialized a set of HTMLEngine variables
|
* Initialized a set of HTMLEngine variables
|
||||||
*
|
*
|
||||||
* @param array | Collection $data
|
* @param array | \Illuminate\Support\Collection $data
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
private function processVariables($data): self
|
private function processVariables($data): self
|
||||||
@ -209,7 +209,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* Process data variables
|
* Process data variables
|
||||||
*
|
*
|
||||||
* @param array | Collection $data
|
* @param array | \Illuminate\Support\Collection $data
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function processData($data): self
|
public function processData($data): self
|
||||||
@ -392,7 +392,7 @@ class TemplateService
|
|||||||
* Pre Processes the Data Blocks into
|
* Pre Processes the Data Blocks into
|
||||||
* Twig consumables
|
* Twig consumables
|
||||||
*
|
*
|
||||||
* @param array | Collection $data
|
* @param array | \Illuminate\Support\Collection $data
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function preProcessDataBlocks($data): array
|
private function preProcessDataBlocks($data): array
|
||||||
@ -421,7 +421,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* Process Invoices into consumable form for Twig templates
|
* Process Invoices into consumable form for Twig templates
|
||||||
*
|
*
|
||||||
* @param array | Collection $invoices
|
* @param array | \Illuminate\Support\Collection $invoices
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function processInvoices($invoices): array
|
public function processInvoices($invoices): array
|
||||||
@ -506,7 +506,7 @@ class TemplateService
|
|||||||
* Pads Line Items with raw and formatted content
|
* Pads Line Items with raw and formatted content
|
||||||
*
|
*
|
||||||
* @param array $items
|
* @param array $items
|
||||||
* @param mixed $client
|
* @param Client $client
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function padLineItems(array $items, Client $client): array
|
public function padLineItems(array $items, Client $client): array
|
||||||
@ -698,7 +698,7 @@ class TemplateService
|
|||||||
* Pushes credits through the appropriate transformer
|
* Pushes credits through the appropriate transformer
|
||||||
* and builds any required relationships
|
* and builds any required relationships
|
||||||
*
|
*
|
||||||
* @param array | Collection $credits
|
* @param array | \Illuminate\Support\Collection $credits
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function processCredits($credits): array
|
public function processCredits($credits): array
|
||||||
@ -775,7 +775,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* Pushes payments through the appropriate transformer
|
* Pushes payments through the appropriate transformer
|
||||||
*
|
*
|
||||||
* @param array | Collection $payments
|
* @param array | \Illuminate\Support\Collection $payments
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function processPayments($payments): array
|
public function processPayments($payments): array
|
||||||
@ -832,7 +832,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* @todo refactor
|
* @todo refactor
|
||||||
*
|
*
|
||||||
* @param array | Collection $projects
|
* @param array | \Illuminate\Support\Collection $projects
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function processProjects($projects): array
|
public function processProjects($projects): array
|
||||||
@ -900,7 +900,7 @@ class TemplateService
|
|||||||
/**
|
/**
|
||||||
* Set Company
|
* Set Company
|
||||||
*
|
*
|
||||||
* @param mixed $company
|
* @param Company $company
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setCompany(Company $company): self
|
public function setCompany(Company $company): self
|
||||||
@ -955,7 +955,6 @@ class TemplateService
|
|||||||
})
|
})
|
||||||
->map(function ($stack){
|
->map(function ($stack){
|
||||||
$node = $this->document->getElementById($stack);
|
$node = $this->document->getElementById($stack);
|
||||||
nlog(['stack' => $stack, 'labels' => $node->getAttribute('labels')]);
|
|
||||||
return ['stack' => $stack, 'labels' => $node->getAttribute('labels')];
|
return ['stack' => $stack, 'labels' => $node->getAttribute('labels')];
|
||||||
})
|
})
|
||||||
->each(function ($stack) {
|
->each(function ($stack) {
|
||||||
@ -976,7 +975,7 @@ class TemplateService
|
|||||||
{
|
{
|
||||||
|
|
||||||
match($stack['stack']) {
|
match($stack['stack']) {
|
||||||
'entity-details' => $this->entityDetails($stack['labels'] == 'true'),
|
'entity-details' => $this->entityDetails(),
|
||||||
'client-details' => $this->clientDetails($stack['labels'] == 'true'),
|
'client-details' => $this->clientDetails($stack['labels'] == 'true'),
|
||||||
'vendor-details' => $this->vendorDetails($stack['labels'] == 'true'),
|
'vendor-details' => $this->vendorDetails($stack['labels'] == 'true'),
|
||||||
'company-details' => $this->companyDetails($stack['labels'] == 'true'),
|
'company-details' => $this->companyDetails($stack['labels'] == 'true'),
|
||||||
@ -1010,11 +1009,11 @@ class TemplateService
|
|||||||
});
|
});
|
||||||
})->toArray();
|
})->toArray();
|
||||||
|
|
||||||
nlog($company_details);
|
// nlog($company_details);
|
||||||
|
|
||||||
$company_details = $include_labels ? $this->labelledFieldStack($company_details, 'company_details-') : $company_details;
|
$company_details = $include_labels ? $this->labelledFieldStack($company_details, 'company_details-') : $company_details;
|
||||||
|
|
||||||
nlog($company_details);
|
// nlog($company_details);
|
||||||
|
|
||||||
$this->updateElementProperties('company-details', $company_details);
|
$this->updateElementProperties('company-details', $company_details);
|
||||||
|
|
||||||
|
@ -104,6 +104,90 @@ class TaskApiTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEmptyTimeLogArray()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => '[]',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => '{}',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFaultyTimeLogArray()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'description' => 'Test Task',
|
||||||
|
'time_log' => 'ABBA is the best band in the world',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson("/api/v1/tasks", $data);
|
||||||
|
|
||||||
|
$response->assertStatus(422);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testTaskClientRateSet()
|
public function testTaskClientRateSet()
|
||||||
{
|
{
|
||||||
$settings = ClientSettings::defaults();
|
$settings = ClientSettings::defaults();
|
||||||
@ -262,6 +346,45 @@ class TaskApiTest extends TestCase
|
|||||||
|
|
||||||
$response->assertStatus(200);
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$task->time_log = 'A very strange place';
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray());
|
||||||
|
|
||||||
|
$response->assertStatus(422);
|
||||||
|
|
||||||
|
$task->time_log = null;
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray());
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$task->time_log = '';
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray());
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
|
||||||
|
$task->time_log = '{}';
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray());
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testStoppingTaskWithDescription()
|
public function testStoppingTaskWithDescription()
|
||||||
|
@ -191,8 +191,10 @@ class TemplateTest extends TestCase
|
|||||||
'client_id' => $this->client->id,
|
'client_id' => $this->client->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$data['projects'][] = $p;
|
||||||
|
|
||||||
$ts = new TemplateService();
|
$ts = new TemplateService();
|
||||||
$ts->processData($data['projects'][$p]);
|
$ts->processData($data);
|
||||||
|
|
||||||
$this->assertNotNull($ts);
|
$this->assertNotNull($ts);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user