Additional tests for report generation

This commit is contained in:
David Bomba 2023-07-18 18:21:12 +10:00
parent 9fc9a0fd78
commit a2b0a13c1f
5 changed files with 229 additions and 68 deletions

View File

@ -20,6 +20,7 @@ use App\Models\Payment;
use League\Fractal\Manager; use League\Fractal\Manager;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Transformers\TaskTransformer;
use App\Transformers\PaymentTransformer; use App\Transformers\PaymentTransformer;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use League\Fractal\Serializer\ArraySerializer; use League\Fractal\Serializer\ArraySerializer;
@ -348,8 +349,6 @@ class BaseExport
'custom_value4' => 'task.custom_value4', 'custom_value4' => 'task.custom_value4',
'status' => 'task.status_id', 'status' => 'task.status_id',
'project' => 'task.project_id', 'project' => 'task.project_id',
'invoice' => 'task.invoice_id',
'client' => 'task.client_id',
]; ];
protected function filterByClients($query) protected function filterByClients($query)
@ -385,6 +384,7 @@ class BaseExport
'quote' => $value = $this->resolveQuoteKey($parts[1], $entity, $transformer), 'quote' => $value = $this->resolveQuoteKey($parts[1], $entity, $transformer),
'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer), 'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer),
'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer), 'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer),
'task' => $value = $this->resolveTaskKey($parts[1], $entity, $transformer),
default => $value = '' default => $value = ''
}; };
@ -450,6 +450,22 @@ class BaseExport
} }
private function resolveTaskKey($column, $entity, $transformer)
{
nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column];
}
return '';
}
private function resolveVendorKey($column, $entity, $transformer) private function resolveVendorKey($column, $entity, $transformer)
{ {
@ -587,7 +603,23 @@ class BaseExport
} }
$transformed_invoice = $transformer->transform($entity); if($transformer instanceof TaskTransformer) {
$transformed_invoice = $transformer->includeInvoice($entity);
if(!$transformed_invoice)
return '';
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_invoice = $manager->createData($transformed_invoice)->toArray();
}
if(array_key_exists($column, $transformed_invoice)) {
return $transformed_invoice[$column];
} elseif (array_key_exists(str_replace("invoice.", "", $column), $transformed_invoice)) {
return $transformed_invoice[$column];
}
if($column == 'status') if($column == 'status')
return $entity->stringStatus($entity->status_id); return $entity->stringStatus($entity->status_id);
@ -886,6 +918,8 @@ class BaseExport
} }
} }
// nlog($header);
return $header; return $header;
} }
} }

View File

@ -46,9 +46,7 @@ class TaskExport extends BaseExport
'custom_value4' => 'custom_value4', 'custom_value4' => 'custom_value4',
'status' => 'status_id', 'status' => 'status_id',
'project' => 'project_id', 'project' => 'project_id',
'invoice' => 'invoice_id', ];
'client' => 'client_id',
];
private array $decorate_keys = [ private array $decorate_keys = [
'status', 'status',
@ -109,38 +107,39 @@ class TaskExport extends BaseExport
$entity = []; $entity = [];
$transformed_entity = $this->entity_transformer->transform($task); $transformed_entity = $this->entity_transformer->transform($task);
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer);
}
}
$entity['start_date'] = '';
$entity['end_date'] = '';
$entity['duration'] = '';
if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) { if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) {
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else {
$entity[$keyval] = '';
}
}
$entity['start_date'] = '';
$entity['end_date'] = '';
$entity['duration'] = '';
$entity = $this->decorateAdvancedFields($task, $entity);
ksort($entity);
$this->csv->insertOne($entity); $this->csv->insertOne($entity);
} elseif (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) > 0) { } else {
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else {
$entity[$keyval] = '';
}
}
$this->iterateLogs($task, $entity); $this->iterateLogs($task, $entity);
} }
} }
private function iterateLogs(Task $task, array $entity) private function iterateLogs(Task $task, array $entity)
@ -163,39 +162,26 @@ class TaskExport extends BaseExport
} }
foreach ($logs as $key => $item) { foreach ($logs as $key => $item) {
if (in_array('start_date', $this->input['report_keys'])) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
$entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); $entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default);
} }
if (in_array('end_date', $this->input['report_keys']) && $item[1] > 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) {
$entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); $entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default);
} }
if (in_array('end_date', $this->input['report_keys']) && $item[1] == 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
$entity['end_date'] = ctrans('texts.is_running'); $entity['end_date'] = ctrans('texts.is_running');
} }
if (in_array('duration', $this->input['report_keys'])) { if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
$entity['duration'] = $task->calcDuration(); $entity['duration'] = $task->calcDuration();
} }
if (! array_key_exists('duration', $entity)) {
$entity['duration'] = '';
}
if (! array_key_exists('start_date', $entity)) {
$entity['start_date'] = '';
}
if (! array_key_exists('end_date', $entity)) {
$entity['end_date'] = '';
}
$entity = $this->decorateAdvancedFields($task, $entity); $entity = $this->decorateAdvancedFields($task, $entity);
ksort($entity);
$this->csv->insertOne($entity); $this->csv->insertOne($entity);
unset($entity['start_date']); unset($entity['start_date']);
unset($entity['end_date']); unset($entity['end_date']);
unset($entity['duration']); unset($entity['duration']);
@ -212,14 +198,6 @@ class TaskExport extends BaseExport
$entity['project'] = $task->project()->exists() ? $task->project->name : ''; $entity['project'] = $task->project()->exists() ? $task->project->name : '';
} }
if (in_array('client_id', $this->input['report_keys'])) {
$entity['client'] = $task->client ? $task->client->present()->name() : '';
}
if (in_array('invoice_id', $this->input['report_keys'])) {
$entity['invoice'] = $task->invoice ? $task->invoice->number : '';
}
return $entity; return $entity;
} }
} }

View File

@ -37,6 +37,7 @@ class TaskTransformer extends EntityTransformer
'status', 'status',
'project', 'project',
'user', 'user',
'invoice',
]; ];
public function includeDocuments(Task $task) public function includeDocuments(Task $task)
@ -46,6 +47,17 @@ class TaskTransformer extends EntityTransformer
return $this->includeCollection($task->documents, $transformer, Document::class); return $this->includeCollection($task->documents, $transformer, Document::class);
} }
public function includeInvoice(Task $task): ?Item
{
$transformer = new InvoiceTransformer($this->serializer);
if (!$task->user) {
return null;
}
return $this->includeItem($task->invoice, $transformer, Invoice::class);
}
public function includeUser(Task $task): ?Item public function includeUser(Task $task): ?Item
{ {
$transformer = new UserTransformer($this->serializer); $transformer = new UserTransformer($this->serializer);

View File

@ -5,7 +5,7 @@ parameters:
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false
parallel: parallel:
jobSize: 5 jobSize: 5
maximumNumberOfProcesses: 16 maximumNumberOfProcesses: 1
processTimeout: 600.0 processTimeout: 600.0
ignoreErrors: ignoreErrors:
- '#Call to an undefined method .*badMethod\(\)#' - '#Call to an undefined method .*badMethod\(\)#'

View File

@ -164,9 +164,92 @@ class ReportCsvGenerationTest extends TestCase
} }
public function testTaskCustomColumnsCsvGeneration()
{
$invoice = \App\Models\Invoice::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'client_id' => $this->client->id,
'date' => '2023-01-01',
'amount' => 1000,
'balance' => 1000,
'number' => '123456',
'status_id' => 2,
'discount' => 10,
'po_number' => '12345',
'public_notes' => 'Public5',
'private_notes' => 'Private5',
'terms' => 'Terms5',
]);
$log = '[[1689547165,1689550765,"sumtin",true]]';
\App\Models\Task::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'client_id' => $this->client->id,
'invoice_id' => $invoice->id,
'description' => 'test1',
'time_log' => $log,
'custom_value1' => 'Custom 11',
'custom_value2' => 'Custom 22',
'custom_value3' => 'Custom 33',
'custom_value4' => 'Custom 44',
]);
$data = [
'date_range' => 'all',
'report_keys' => [
'client.name',
'invoice.number',
'invoice.amount',
'task.start_date',
'task.end_date',
'task.duration',
'task.description',
'task.custom_value1',
'task.custom_value2',
'task.custom_value3',
'task.custom_value4',
],
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/tasks', $data);
$csv = $response->streamedContent();
$this->assertEquals(3600, $this->getFirstValueByColumn($csv, 'Task Duration'));
$this->assertEquals('test1', $this->getFirstValueByColumn($csv, 'Task Description'));
$this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'Task Start Date'));
$this->assertEquals('16/Jul/2023', $this->getFirstValueByColumn($csv, 'Task End Date'));
$this->assertEquals('Custom 11', $this->getFirstValueByColumn($csv, 'Task Custom Value 1'));
$this->assertEquals('Custom 22', $this->getFirstValueByColumn($csv, 'Task Custom Value 2'));
$this->assertEquals('Custom 33', $this->getFirstValueByColumn($csv, 'Task Custom Value 3'));
$this->assertEquals('Custom 44', $this->getFirstValueByColumn($csv, 'Task Custom Value 4'));
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
$this->assertEquals('123456', $this->getFirstValueByColumn($csv, 'Invoice Invoice Number'));
$this->assertEquals(1000, $this->getFirstValueByColumn($csv, 'Invoice Amount'));
}
public function testTasksCsvGeneration() public function testTasksCsvGeneration()
{ {
\App\Models\Task::query()->cursor()->each(function ($t) {
$t->forceDelete();
});
$log = '[[1689547165,1689550765,"sumtin",true]]'; $log = '[[1689547165,1689550765,"sumtin",true]]';
\App\Models\Task::factory()->create([ \App\Models\Task::factory()->create([
@ -247,13 +330,70 @@ class ReportCsvGenerationTest extends TestCase
public function testPaymentCsvGeneration() public function testPaymentCsvGeneration()
{
$invoice = \App\Models\Invoice::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'client_id' => $this->client->id,
'date' => '2023-01-01',
'amount' => 100,
'balance' => 100,
'number' => '12345',
'status_id' => 2,
'discount' => 10,
'po_number' => '1234',
'public_notes' => 'Public',
'private_notes' => 'Private',
'terms' => 'Terms',
]);
$invoice->client->balance = 100;
$invoice->client->paid_to_date = 0;
$invoice->push();
$invoice->service()->markPaid()->save();
$data = [
'date_range' => 'all',
'report_keys' => [
"payment.date",
"payment.amount",
"invoice.number",
"invoice.amount",
"client.name",
"client.balance",
"client.paid_to_date"
],
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/payments', $data);
$csv = $response->streamedContent();
$this->assertEquals(100, $this->getFirstValueByColumn($csv, 'Payment Amount'));
$this->assertEquals(now()->addSeconds($this->company->timezone()->utc_offset)->format('Y-m-d'), $this->getFirstValueByColumn($csv, 'Payment Date'));
$this->assertEquals('12345', $this->getFirstValueByColumn($csv, 'Invoice Invoice Number'));
$this->assertEquals(100, $this->getFirstValueByColumn($csv, 'Invoice Amount'));
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
$this->assertEquals(0, $this->getFirstValueByColumn($csv, 'Client Balance'));
$this->assertEquals(100, $this->getFirstValueByColumn($csv, 'Client Paid to Date'));
}
public function testPaymentCustomFieldsCsvGeneration()
{ {
\App\Models\Payment::factory()->create([ \App\Models\Payment::factory()->create([
'amount' => 500, 'amount' => 500,
'date' => '2020-01-01', 'date' => '2020-01-01',
'company_id' => $this->company->id,
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'company_id' => $this->company->id,
'client_id' => $this->client->id, 'client_id' => $this->client->id,
'transaction_reference' => '1234', 'transaction_reference' => '1234',
]); ]);
@ -279,6 +419,7 @@ class ReportCsvGenerationTest extends TestCase
} }
public function testClientCsvGeneration() public function testClientCsvGeneration()
{ {
@ -443,8 +584,6 @@ class ReportCsvGenerationTest extends TestCase
$csv = $response->streamedContent(); $csv = $response->streamedContent();
nlog($csv);
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name')); $this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Recurring Invoice Invoice Number')); $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Recurring Invoice Invoice Number'));
$this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'Recurring Invoice How Often')); $this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'Recurring Invoice How Often'));
@ -694,8 +833,6 @@ class ReportCsvGenerationTest extends TestCase
$csv = $response->streamedContent(); $csv = $response->streamedContent();
nlog($csv);
$this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Vendor Name')); $this->assertEquals('Vendor 1', $this->getFirstValueByColumn($csv, 'Vendor Name'));
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Purchase Order Number')); $this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Purchase Order Number'));
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Quantity')); $this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Quantity'));