mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Task imports
This commit is contained in:
parent
f7ae037584
commit
83844a0c27
66
app/Import/Definitions/TaskMap.php
Normal file
66
app/Import/Definitions/TaskMap.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Definitions;
|
||||||
|
|
||||||
|
class TaskMap
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function importable()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'task.number',
|
||||||
|
1 => 'task.user_id',
|
||||||
|
2 => 'task.rate',
|
||||||
|
3 => 'project.name',
|
||||||
|
4 => 'client.name',
|
||||||
|
5 => 'client.email',
|
||||||
|
6 => 'task.description',
|
||||||
|
7 => 'task.is_billable',
|
||||||
|
8 => 'task.start_date',
|
||||||
|
9 => 'task.end_date',
|
||||||
|
10 => 'task.start_time',
|
||||||
|
11 => 'task.end_time',
|
||||||
|
12 => 'task.duration',
|
||||||
|
13 => 'task.status',
|
||||||
|
14 => 'task.custom_value1',
|
||||||
|
15 => 'task.custom_value1',
|
||||||
|
16 => 'task.custom_value1',
|
||||||
|
17 => 'task.custom_value1',
|
||||||
|
18 => 'task.notes',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function import_keys()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'texts.task_number',
|
||||||
|
1 => 'texts.user',
|
||||||
|
2 => 'texts.task_rate',
|
||||||
|
3 => 'texts.project',
|
||||||
|
4 => 'texts.client',
|
||||||
|
5 => 'texts.client_email',
|
||||||
|
6 => 'texts.description',
|
||||||
|
7 => 'texts.billable',
|
||||||
|
8 => 'texts.start_date',
|
||||||
|
9 => 'texts.end_date',
|
||||||
|
10 => 'texts.start_time',
|
||||||
|
11 => 'texts.end_time',
|
||||||
|
12 => 'texts.duration',
|
||||||
|
13 => 'texts.status',
|
||||||
|
14 => 'texts.task1',
|
||||||
|
15 => 'texts.task2',
|
||||||
|
16 => 'texts.task3',
|
||||||
|
17 => 'texts.task4',
|
||||||
|
18 => 'texts.notes',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ use App\Factory\InvoiceFactory;
|
|||||||
use App\Factory\PaymentFactory;
|
use App\Factory\PaymentFactory;
|
||||||
use App\Factory\QuoteFactory;
|
use App\Factory\QuoteFactory;
|
||||||
use App\Factory\RecurringInvoiceFactory;
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
|
use App\Factory\TaskFactory;
|
||||||
use App\Http\Requests\Quote\StoreQuoteRequest;
|
use App\Http\Requests\Quote\StoreQuoteRequest;
|
||||||
use App\Import\ImportException;
|
use App\Import\ImportException;
|
||||||
use App\Jobs\Mail\NinjaMailerJob;
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
@ -30,6 +31,7 @@ use App\Repositories\InvoiceRepository;
|
|||||||
use App\Repositories\PaymentRepository;
|
use App\Repositories\PaymentRepository;
|
||||||
use App\Repositories\QuoteRepository;
|
use App\Repositories\QuoteRepository;
|
||||||
use App\Repositories\RecurringInvoiceRepository;
|
use App\Repositories\RecurringInvoiceRepository;
|
||||||
|
use App\Repositories\TaskRepository;
|
||||||
use App\Utils\Traits\CleanLineItems;
|
use App\Utils\Traits\CleanLineItems;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
@ -158,6 +160,32 @@ class BaseImport
|
|||||||
}, $csvData);
|
}, $csvData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function groupTasks($csvData, $key)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (! $key) {
|
||||||
|
return $csvData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group by tasks.
|
||||||
|
$grouped = [];
|
||||||
|
|
||||||
|
foreach ($csvData as $item) {
|
||||||
|
if (empty($item[$key])) {
|
||||||
|
$this->error_array['task'][] = [
|
||||||
|
'task' => $item,
|
||||||
|
'error' => 'No task number',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$grouped[$item[$key]][] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function groupInvoices($csvData, $key)
|
private function groupInvoices($csvData, $key)
|
||||||
{
|
{
|
||||||
if (! $key) {
|
if (! $key) {
|
||||||
@ -413,6 +441,66 @@ class BaseImport
|
|||||||
return $count;
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ingestTasks($tasks, $task_number_key)
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
$task_transformer = $this->transformer;
|
||||||
|
|
||||||
|
$task_repository = new TaskRepository();
|
||||||
|
// $task_repository->import_mode = true;
|
||||||
|
|
||||||
|
$tasks = $this->groupTasks($tasks, $task_number_key);
|
||||||
|
|
||||||
|
foreach ($tasks as $raw_task) {
|
||||||
|
$task_data = [];
|
||||||
|
try {
|
||||||
|
$task_data = $task_transformer->transform($raw_task);
|
||||||
|
$task_data['user_id'] = $this->company->owner()->id;
|
||||||
|
|
||||||
|
$validator = $this->request_name::runFormRequest($task_data);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
$this->error_array['task'][] = [
|
||||||
|
'invoice' => $task_data,
|
||||||
|
'error' => $validator->errors()->all(),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$task = TaskFactory::create(
|
||||||
|
$this->company->id,
|
||||||
|
$this->company->owner()->id
|
||||||
|
);
|
||||||
|
|
||||||
|
$task_repository->save($task_data, $task);
|
||||||
|
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
if (\DB::connection(config('database.default'))->transactionLevel() > 0) {
|
||||||
|
\DB::connection(config('database.default'))->rollBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ex instanceof ImportException) {
|
||||||
|
$message = $ex->getMessage();
|
||||||
|
} else {
|
||||||
|
report($ex);
|
||||||
|
$message = 'Unknown error ';
|
||||||
|
nlog($ex->getMessage());
|
||||||
|
nlog($task_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->error_array['task'][] = [
|
||||||
|
'task' => $task_data,
|
||||||
|
'error' => $message,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function ingestInvoices($invoices, $invoice_number_key)
|
public function ingestInvoices($invoices, $invoice_number_key)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ use App\Factory\PaymentFactory;
|
|||||||
use App\Factory\ProductFactory;
|
use App\Factory\ProductFactory;
|
||||||
use App\Factory\QuoteFactory;
|
use App\Factory\QuoteFactory;
|
||||||
use App\Factory\RecurringInvoiceFactory;
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
|
use App\Factory\TaskFactory;
|
||||||
use App\Factory\VendorFactory;
|
use App\Factory\VendorFactory;
|
||||||
use App\Http\Requests\BankTransaction\StoreBankTransactionRequest;
|
use App\Http\Requests\BankTransaction\StoreBankTransactionRequest;
|
||||||
use App\Http\Requests\Client\StoreClientRequest;
|
use App\Http\Requests\Client\StoreClientRequest;
|
||||||
@ -28,6 +29,7 @@ use App\Http\Requests\Payment\StorePaymentRequest;
|
|||||||
use App\Http\Requests\Product\StoreProductRequest;
|
use App\Http\Requests\Product\StoreProductRequest;
|
||||||
use App\Http\Requests\Quote\StoreQuoteRequest;
|
use App\Http\Requests\Quote\StoreQuoteRequest;
|
||||||
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
|
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
|
||||||
|
use App\Http\Requests\Task\StoreTaskRequest;
|
||||||
use App\Http\Requests\Vendor\StoreVendorRequest;
|
use App\Http\Requests\Vendor\StoreVendorRequest;
|
||||||
use App\Import\Transformer\Bank\BankTransformer;
|
use App\Import\Transformer\Bank\BankTransformer;
|
||||||
use App\Import\Transformer\Csv\ClientTransformer;
|
use App\Import\Transformer\Csv\ClientTransformer;
|
||||||
@ -37,6 +39,7 @@ use App\Import\Transformer\Csv\PaymentTransformer;
|
|||||||
use App\Import\Transformer\Csv\ProductTransformer;
|
use App\Import\Transformer\Csv\ProductTransformer;
|
||||||
use App\Import\Transformer\Csv\QuoteTransformer;
|
use App\Import\Transformer\Csv\QuoteTransformer;
|
||||||
use App\Import\Transformer\Csv\RecurringInvoiceTransformer;
|
use App\Import\Transformer\Csv\RecurringInvoiceTransformer;
|
||||||
|
use App\Import\Transformer\Csv\TaskTransformer;
|
||||||
use App\Import\Transformer\Csv\VendorTransformer;
|
use App\Import\Transformer\Csv\VendorTransformer;
|
||||||
use App\Repositories\BankTransactionRepository;
|
use App\Repositories\BankTransactionRepository;
|
||||||
use App\Repositories\ClientRepository;
|
use App\Repositories\ClientRepository;
|
||||||
@ -46,6 +49,7 @@ use App\Repositories\PaymentRepository;
|
|||||||
use App\Repositories\ProductRepository;
|
use App\Repositories\ProductRepository;
|
||||||
use App\Repositories\QuoteRepository;
|
use App\Repositories\QuoteRepository;
|
||||||
use App\Repositories\RecurringInvoiceRepository;
|
use App\Repositories\RecurringInvoiceRepository;
|
||||||
|
use App\Repositories\TaskRepository;
|
||||||
use App\Repositories\VendorRepository;
|
use App\Repositories\VendorRepository;
|
||||||
use App\Services\Bank\BankMatchingService;
|
use App\Services\Bank\BankMatchingService;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
@ -69,6 +73,7 @@ class Csv extends BaseImport implements ImportInterface
|
|||||||
'quote',
|
'quote',
|
||||||
'bank_transaction',
|
'bank_transaction',
|
||||||
'recurring_invoice',
|
'recurring_invoice',
|
||||||
|
'tasks',
|
||||||
])
|
])
|
||||||
) {
|
) {
|
||||||
$this->{$entity}();
|
$this->{$entity}();
|
||||||
@ -348,6 +353,31 @@ class Csv extends BaseImport implements ImportInterface
|
|||||||
|
|
||||||
public function task()
|
public function task()
|
||||||
{
|
{
|
||||||
|
$entity_type = 'task';
|
||||||
|
|
||||||
|
$data = $this->getCsvData($entity_type);
|
||||||
|
|
||||||
|
if (is_array($data)) {
|
||||||
|
$data = $this->preTransformCsv($data, $entity_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
$this->entity_count['invoices'] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->request_name = StoreTaskRequest::class;
|
||||||
|
$this->repository_name = TaskRepository::class;
|
||||||
|
$this->factory_name = TaskFactory::class;
|
||||||
|
|
||||||
|
$this->repository = app()->make($this->repository_name);
|
||||||
|
// $this->repository->import_mode = true;
|
||||||
|
|
||||||
|
$this->transformer = new TaskTransformer($this->company);
|
||||||
|
|
||||||
|
$task_count = $this->ingestTasks($data, 'task.number');
|
||||||
|
|
||||||
|
$this->entity_count['tasks'] = $task_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform(array $data)
|
public function transform(array $data)
|
||||||
|
126
app/Import/Transformer/Csv/TaskTransformer.php
Normal file
126
app/Import/Transformer/Csv/TaskTransformer.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformer\Csv;
|
||||||
|
|
||||||
|
use App\Import\Transformer\BaseTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TaskTransformer.
|
||||||
|
*/
|
||||||
|
class TaskTransformer extends BaseTransformer
|
||||||
|
{
|
||||||
|
private int $stubbed_timestamp = 0;
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform($task_items_data)
|
||||||
|
{
|
||||||
|
$this->stubbed_timestamp = time();
|
||||||
|
|
||||||
|
$task_data = reset($task_items_data);
|
||||||
|
|
||||||
|
$clientId = $this->getClient(
|
||||||
|
$this->getString($task_data, 'client.name'),
|
||||||
|
$this->getString($task_data, 'client.email')
|
||||||
|
);
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'number' => $this->getString($task_data, 'task.number'),
|
||||||
|
'user_id' => $this->getString($task_data, 'task.user_id'),
|
||||||
|
'client_id' => $clientId,
|
||||||
|
'project_id' => $this->getProjectId($task_data['project.name'], $clientId),
|
||||||
|
'description' => $this->getString($task_data, 'task.description'),
|
||||||
|
'status' => $this->getTaskStatusId($task_data),
|
||||||
|
'custom_value1' => $this->getString($task_data, 'task.custom_value1'),
|
||||||
|
'custom_value2' => $this->getString($task_data, 'task.custom_value2'),
|
||||||
|
'custom_value3' => $this->getString($task_data, 'task.custom_value3'),
|
||||||
|
'custom_value4' => $this->getString($task_data, 'task.custom_value4'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$time_log = collect($task_items_data)
|
||||||
|
->map(function ($item) {
|
||||||
|
|
||||||
|
return $this->parseLog($item);
|
||||||
|
|
||||||
|
})->toJson();
|
||||||
|
|
||||||
|
nlog($time_log);
|
||||||
|
|
||||||
|
$transformed['time_log'] = $time_log;
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseLog($item): array
|
||||||
|
{
|
||||||
|
$start_date = false;
|
||||||
|
$end_date = false;
|
||||||
|
|
||||||
|
$notes = $item['task.notes'] ?? '';
|
||||||
|
$is_billable = $item['task.is_billable'] ?? false;
|
||||||
|
|
||||||
|
if(isset($item['start_date']) &&
|
||||||
|
isset($item['end_date'])) {
|
||||||
|
$start_date = $this->resolveStartDate($item);
|
||||||
|
$end_date = $this->resolveEndDate($item);
|
||||||
|
} elseif(isset($item['duration'])) {
|
||||||
|
$duration = strtotime($item['duration']) - strtotime('TODAY');
|
||||||
|
$start_date = $this->stubbed_timestamp;
|
||||||
|
$end_date = $this->stubbed_timestamp + $duration;
|
||||||
|
$this->stubbed_timestamp++;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$start_date, $end_date, $notes, $is_billable];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveStartDate($item)
|
||||||
|
{
|
||||||
|
|
||||||
|
$stub_start_date = $item['start_date'] . ' ' . isset($item['start_time']) ?? '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stub_start_date = \Carbon\Carbon::parse($stub_start_date);
|
||||||
|
$this->stubbed_timestamp = $stub_start_date->timestamp;
|
||||||
|
return $stub_start_date->timestamp;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->stubbed_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveEndDate($item)
|
||||||
|
{
|
||||||
|
|
||||||
|
$stub_start_date = $item['end_date'] . ' ' . isset($item['end_time']) ?? '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stub_start_date = \Carbon\Carbon::parse($stub_start_date);
|
||||||
|
|
||||||
|
if($stub_start_date->timestamp == $this->stubbed_timestamp) {
|
||||||
|
$this->stubbed_timestamp++;
|
||||||
|
return $this->stubbed_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->stubbed_timestamp = $stub_start_date->timestamp++;
|
||||||
|
return $stub_start_date->timestamp;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->stubbed_timestamp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user