mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
Update calculations for project duration
This commit is contained in:
parent
dfff937031
commit
83fe0521ca
@ -15,7 +15,6 @@ use App\Jobs\Cron\AutoBillCron;
|
|||||||
use App\Jobs\Cron\RecurringExpensesCron;
|
use App\Jobs\Cron\RecurringExpensesCron;
|
||||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||||
use App\Jobs\Cron\SubscriptionCron;
|
use App\Jobs\Cron\SubscriptionCron;
|
||||||
use App\Jobs\Cron\UpdateCalculatedFields;
|
|
||||||
use App\Jobs\Invoice\InvoiceCheckLateWebhook;
|
use App\Jobs\Invoice\InvoiceCheckLateWebhook;
|
||||||
use App\Jobs\Ninja\AdjustEmailQuota;
|
use App\Jobs\Ninja\AdjustEmailQuota;
|
||||||
use App\Jobs\Ninja\BankTransactionSync;
|
use App\Jobs\Ninja\BankTransactionSync;
|
||||||
@ -68,9 +67,6 @@ class Kernel extends ConsoleKernel
|
|||||||
/* Stale Invoice Cleanup*/
|
/* Stale Invoice Cleanup*/
|
||||||
$schedule->job(new CleanStaleInvoiceOrder())->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer();
|
$schedule->job(new CleanStaleInvoiceOrder())->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer();
|
||||||
|
|
||||||
/* Stale Invoice Cleanup*/
|
|
||||||
$schedule->job(new UpdateCalculatedFields())->hourlyAt(40)->withoutOverlapping()->name('update-calculated-fields-job')->onOneServer();
|
|
||||||
|
|
||||||
/* Checks for large companies and marked them as is_large */
|
/* Checks for large companies and marked them as is_large */
|
||||||
$schedule->job(new CompanySizeCheck())->dailyAt('23:20')->withoutOverlapping()->name('company-size-job')->onOneServer();
|
$schedule->job(new CompanySizeCheck())->dailyAt('23:20')->withoutOverlapping()->name('company-size-job')->onOneServer();
|
||||||
|
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
|
||||||
*
|
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
|
||||||
*
|
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Jobs\Cron;
|
|
||||||
|
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Project;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class UpdateCalculatedFields
|
|
||||||
{
|
|
||||||
use Dispatchable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
nlog("Updating calculated fields");
|
|
||||||
|
|
||||||
Auth::logout();
|
|
||||||
|
|
||||||
if (! config('ninja.db.multi_db_enabled')) {
|
|
||||||
|
|
||||||
Project::query()->with('tasks')->whereHas('tasks', function ($query) {
|
|
||||||
$query->where('updated_at', '>', now()->subHours(2));
|
|
||||||
})
|
|
||||||
->cursor()
|
|
||||||
->each(function ($project) {
|
|
||||||
|
|
||||||
$project->current_hours = $this->calculateDuration($project);
|
|
||||||
$project->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//multiDB environment, need to
|
|
||||||
foreach (MultiDB::$dbs as $db) {
|
|
||||||
MultiDB::setDB($db);
|
|
||||||
|
|
||||||
|
|
||||||
Project::query()->with('tasks')->whereHas('tasks', function ($query) {
|
|
||||||
$query->where('updated_at', '>', now()->subHours(2));
|
|
||||||
})
|
|
||||||
->cursor()
|
|
||||||
->each(function ($project) {
|
|
||||||
$project->current_hours = $this->calculateDuration($project);
|
|
||||||
$project->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
//Clean password resets table
|
|
||||||
\DB::connection($db)->table('password_resets')->where('created_at', '<', now()->subHour())->delete();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function calculateDuration($project): int
|
|
||||||
{
|
|
||||||
$duration = 0;
|
|
||||||
|
|
||||||
$project->tasks->each(function ($task) use (&$duration) {
|
|
||||||
|
|
||||||
if(is_iterable(json_decode($task->time_log))) {
|
|
||||||
|
|
||||||
foreach(json_decode($task->time_log) as $log) {
|
|
||||||
|
|
||||||
if(!is_array($log))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$start_time = $log[0];
|
|
||||||
$end_time = $log[1] == 0 ? time() : $log[1];
|
|
||||||
|
|
||||||
$duration += $end_time - $start_time;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return (int) round(($duration / 60 / 60), 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -96,6 +96,8 @@ class CleanStaleInvoiceOrder implements ShouldQueue
|
|||||||
$invoice->service()->removeUnpaidGatewayFees();
|
$invoice->service()->removeUnpaidGatewayFees();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
\DB::connection($db)->table('password_resets')->where('created_at', '<', now()->subHours(12))->delete();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ class Task extends BaseModel
|
|||||||
// 'project',
|
// 'project',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $touches = [];
|
protected $touches = ['project'];
|
||||||
|
|
||||||
public function getEntityType()
|
public function getEntityType()
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,7 @@ class TaskObserver
|
|||||||
if ($subscriptions) {
|
if ($subscriptions) {
|
||||||
WebhookHandler::dispatch(Webhook::EVENT_ARCHIVE_TASK, $task, $task->company)->delay(0);
|
WebhookHandler::dispatch(Webhook::EVENT_ARCHIVE_TASK, $task, $task->company)->delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -586,10 +586,6 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
|
|
||||||
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
|
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
|
||||||
|
|
||||||
// $invoices->each(function ($invoice) {
|
|
||||||
// $invoice->service()->deletePdf();
|
|
||||||
// });
|
|
||||||
|
|
||||||
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
|
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
|
||||||
if ((bool) $invitation->contact->send_email !== false && $invitation->contact->email) {
|
if ((bool) $invitation->contact->send_email !== false && $invitation->contact->email) {
|
||||||
$nmo->to_user = $invitation->contact;
|
$nmo->to_user = $invitation->contact;
|
||||||
|
@ -72,9 +72,9 @@ class Client extends HttpClient
|
|||||||
$response = $this->httpClient->sendRequest( $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion));
|
$response = $this->httpClient->sendRequest( $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion));
|
||||||
else $response = $this->httpClient->request($method, $uri, compact('body','headers'));
|
else $response = $this->httpClient->request($method, $uri, compact('body','headers'));
|
||||||
} catch (\Http\Client\Exception\NetworkException $networkException) {
|
} catch (\Http\Client\Exception\NetworkException $networkException) {
|
||||||
throw new NetworkException($networkException->getMessage(), $request, $networkException);
|
throw new \Exception($networkException->getMessage());
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
throw new RequestException($exception->getMessage(), $request, $exception);
|
throw new \Exception($exception->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
@ -46,16 +46,16 @@ class TaskRepository extends BaseRepository
|
|||||||
$this->new_task = false;
|
$this->new_task = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($data['assigned_user_id']) && $data['assigned_user_id'] != $task->assigned_user_id){
|
|
||||||
TaskAssigned::dispatch($task, $task->company->db)->delay(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!is_numeric($task->rate) && !isset($data['rate']))
|
if(!is_numeric($task->rate) && !isset($data['rate']))
|
||||||
$data['rate'] = 0;
|
$data['rate'] = 0;
|
||||||
|
|
||||||
$task->fill($data);
|
$task->fill($data);
|
||||||
$task->saveQuietly();
|
$task->saveQuietly();
|
||||||
|
|
||||||
|
if(isset($data['assigned_user_id']) && $data['assigned_user_id'] != $task->assigned_user_id) {
|
||||||
|
TaskAssigned::dispatch($task, $task->company->db)->delay(2);
|
||||||
|
}
|
||||||
|
|
||||||
$this->init($task);
|
$this->init($task);
|
||||||
|
|
||||||
if ($this->new_task && ! $task->status_id) {
|
if ($this->new_task && ! $task->status_id) {
|
||||||
@ -155,6 +155,8 @@ class TaskRepository extends BaseRepository
|
|||||||
$this->saveDocuments($data['documents'], $task);
|
$this->saveDocuments($data['documents'], $task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->calculateProjectDuration($task);
|
||||||
|
|
||||||
return $task;
|
return $task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,6 +263,8 @@ class TaskRepository extends BaseRepository
|
|||||||
$task->saveQuietly();
|
$task->saveQuietly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->calculateProjectDuration($task);
|
||||||
|
|
||||||
return $task;
|
return $task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +306,10 @@ class TaskRepository extends BaseRepository
|
|||||||
$task->saveQuietly();
|
$task->saveQuietly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->calculateProjectDuration($task);
|
||||||
|
|
||||||
return $task;
|
return $task;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function triggeredActions($request, $task)
|
public function triggeredActions($request, $task)
|
||||||
@ -348,4 +355,67 @@ class TaskRepository extends BaseRepository
|
|||||||
|
|
||||||
return $task->number;
|
return $task->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function calculateProjectDuration(Task $task)
|
||||||
|
{
|
||||||
|
|
||||||
|
if($task->project) {
|
||||||
|
|
||||||
|
$duration = 0;
|
||||||
|
|
||||||
|
$task->project->tasks->each(function ($task) use (&$duration) {
|
||||||
|
|
||||||
|
if(is_iterable(json_decode($task->time_log))) {
|
||||||
|
|
||||||
|
foreach(json_decode($task->time_log) as $log) {
|
||||||
|
|
||||||
|
if(!is_array($log)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start_time = $log[0];
|
||||||
|
$end_time = $log[1] == 0 ? time() : $log[1];
|
||||||
|
|
||||||
|
$duration += $end_time - $start_time;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$task->project->current_hours = (int) round(($duration / 60 / 60), 0);
|
||||||
|
$task->push();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $entity
|
||||||
|
*/
|
||||||
|
public function restore($task)
|
||||||
|
{
|
||||||
|
if (!$task->trashed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::restore($task);
|
||||||
|
|
||||||
|
$this->calculateProjectDuration($task);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $entity
|
||||||
|
*/
|
||||||
|
public function delete($task)
|
||||||
|
{
|
||||||
|
if ($task->is_deleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::delete($task);
|
||||||
|
|
||||||
|
$this->calculateProjectDuration($task);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user