diff --git a/app/Export/CSV/TaskExport.php b/app/Export/CSV/TaskExport.php new file mode 100644 index 000000000000..2f8686ff222e --- /dev/null +++ b/app/Export/CSV/TaskExport.php @@ -0,0 +1,200 @@ + 'start_date', + 'end_date' => 'end_date', + 'duration' => 'duration', + 'rate' => 'rate', + 'number' => 'number', + 'description' => 'description', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'status' => 'status_id', + 'project' => 'project_id', + 'invoice' => 'invoice_id', + 'client' => 'client_id', + ]; + + private array $decorate_keys = [ + 'status', + 'project', + 'client', + 'invoice', + 'start_date', + 'end_date', + 'duration', + ]; + + public function __construct(Company $company, array $input) + { + $this->company = $company; + $this->input = $input; + $this->entity_transformer = new TaskTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + $this->date_format = DateFormat::find($this->company->settings->date_format_id)->format; + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + $query = Task::query()->where('company_id', $this->company->id)->where('is_deleted', 0); + + $query = $this->addDateRange($query); + + $query->cursor() + ->each(function ($entity){ + + $this->iterateItems($entity); + + }); + + return $this->csv->toString(); + + } + + private function iterateItems(Task $task) + { + $transformed_task = $this->buildRow($task); + + $transformed_items = []; + + $transformed_task = $this->decorateAdvancedFields($task, $transformed_items); + + $entity = []; + + if(is_null(json_decode($task->time_log,1))) + { + foreach(array_values($this->input['report_keys']) as $key) + { + $key = str_replace("item.", "", $key); + + if(array_key_exists($key, $transformed_task)) + $entity[$key] = $transformed_task[$key]; + } + + $this->csv->insertOne($entity); + + + } + else { + + foreach(json_decode($task->time_log,1) as $item) + { + + + foreach(array_values($this->input['report_keys']) as $key) + { + $key = str_replace("item.", "", $key); + + if(array_key_exists($key, $transformed_task)) + $entity[$key] = $transformed_task[$key]; + } + + if(array_key_exists("start_date",$this->input['report_keys'])){ + $entity['start_date'] = Carbon::createFromTimeStamp($item[0])->format($this->date_format); + $entity = array_merge($entity, $transformed_task); + } + + if(array_key_exists("end_date",$this->input['report_keys']) && $item[1] > 0){ + $entity['end_date'] = Carbon::createFromTimeStamp($item[1])->format($this->date_format); + $entity = array_merge($entity, $transformed_task); + } + elseif(array_key_exists('end_date', $this->input['report_keys'])){ + $entity['end_date'] = ctrans('texts.is_running'); + $entity = array_merge($entity, $transformed_task); + } + + + $this->csv->insertOne($entity); + + } + + } + } + + + + private function buildRow(Task $task) :array + { + + $transformed_entity = $this->entity_transformer->transform($task); + + $entity = []; + + foreach(array_values($this->input['report_keys']) as $key){ + + if(array_key_exists($key, $transformed_entity)) + $entity[$key] = $transformed_entity[$key]; + + } + + return $this->decorateAdvancedFields($task, $entity); + + } + + private function decorateAdvancedFields(Task $task, array $entity) :array + { + + if(array_key_exists('status_id', $entity)) + $entity['status_id'] = $task->status()->exists() ? $task->status->name : ''; + + if(array_key_exists('project_id', $entity)) + $entity['project_id'] = $task->project()->exists() ? $task->project->name : ''; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $task->client->present()->name(); + + + + return $entity; + } + +} diff --git a/app/Http/Controllers/Reports/QuoteReportController.php b/app/Http/Controllers/Reports/QuoteReportController.php index 0d57f71fd449..7b07d58a0004 100644 --- a/app/Http/Controllers/Reports/QuoteReportController.php +++ b/app/Http/Controllers/Reports/QuoteReportController.php @@ -30,11 +30,11 @@ class QuoteReportController extends BaseController /** * @OA\Post( - * path="/api/v1/reports/invoices", - * operationId="getInvoiceReport", + * path="/api/v1/reports/quotes", + * operationId="getQuoteReport", * tags={"reports"}, - * summary="Invoice reports", - * description="Export invoice reports", + * summary="Quote reports", + * description="Export quote reports", * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), * @OA\RequestBody( diff --git a/app/Http/Controllers/Reports/TaskReportController.php b/app/Http/Controllers/Reports/TaskReportController.php new file mode 100644 index 000000000000..ee1259105efb --- /dev/null +++ b/app/Http/Controllers/Reports/TaskReportController.php @@ -0,0 +1,84 @@ +user()->company(), $request->all()); + + $csv = $export->run(); + + $headers = array( + 'Content-Disposition' => 'attachment', + 'Content-Type' => 'text/csv', + ); + + return response()->streamDownload(function () use ($csv) { + echo $csv; + }, $this->filename, $headers); + + } + + + +} diff --git a/app/Http/ValidationRules/Account/BlackListRule.php b/app/Http/ValidationRules/Account/BlackListRule.php new file mode 100644 index 000000000000..47f8e9748a6c --- /dev/null +++ b/app/Http/ValidationRules/Account/BlackListRule.php @@ -0,0 +1,55 @@ +blacklist); + } + else + return true; + + + } + + /** + * @return string + */ + public function message() + { + return "This domain is blacklisted, if you think this is in error, please email contact@invoiceninja.com"; + } + + +} diff --git a/routes/api.php b/routes/api.php index bc270bdbf847..bff9838c65cc 100644 --- a/routes/api.php +++ b/routes/api.php @@ -166,6 +166,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale Route::post('reports/recurring_invoices', 'Reports\RecurringInvoiceReportController'); Route::post('reports/payments', 'Reports\PaymentReportController'); Route::post('reports/products', 'Reports\ProductReportController'); + Route::post('reports/tasks', 'Reports\TaskReportController'); Route::get('scheduler', 'SchedulerController@index'); Route::post('support/messages/send', 'Support\Messages\SendingController'); diff --git a/tests/Unit/ValidationRules/BlacklistValidationTest.php b/tests/Unit/ValidationRules/BlacklistValidationTest.php new file mode 100644 index 000000000000..a814082add12 --- /dev/null +++ b/tests/Unit/ValidationRules/BlacklistValidationTest.php @@ -0,0 +1,67 @@ + [new BlackListRule] + ]; + + $data = [ + 'email' => "jimmy@gmail.com", + ]; + + $v = $this->app['validator']->make($data, $rules); + $this->assertTrue($v->passes()); + } + + + public function testInValidEmailRule() + { + + $rules = [ + 'email' => [new BlackListRule] + ]; + + $data = [ + 'email' => "jimmy@candassociates.com", + ]; + + $v = $this->app['validator']->make($data, $rules); + $this->assertFalse($v->passes()); + } + + + + +}