mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 21:52:35 +01:00
Merge pull request #6508 from turbo124/recurring_expenses
Recurring expenses - Cron
This commit is contained in:
commit
7b0bfeb2af
@ -12,6 +12,7 @@
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\Cron\AutoBillCron;
|
||||
use App\Jobs\Cron\RecurringExpensesCron;
|
||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||
use App\Jobs\Cron\SubscriptionCron;
|
||||
use App\Jobs\Ninja\AdjustEmailQuota;
|
||||
@ -62,6 +63,8 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
|
||||
|
||||
$schedule->job(new RecurringExpensesCron)->dailyAt('23:45')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new AutoBillCron)->dailyAt('00:30')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
|
||||
|
@ -21,6 +21,7 @@ class RecurringExpenseFactory
|
||||
$recurring_expense->user_id = $user_id;
|
||||
$recurring_expense->company_id = $company_id;
|
||||
$recurring_expense->is_deleted = false;
|
||||
$recurring_expense->invoice_documents = false;
|
||||
$recurring_expense->should_be_invoiced = false;
|
||||
$recurring_expense->tax_name1 = '';
|
||||
$recurring_expense->tax_rate1 = 0;
|
||||
@ -28,6 +29,9 @@ class RecurringExpenseFactory
|
||||
$recurring_expense->tax_rate2 = 0;
|
||||
$recurring_expense->tax_name3 = '';
|
||||
$recurring_expense->tax_rate3 = 0;
|
||||
$recurring_expense->tax_amount1 = 0;
|
||||
$recurring_expense->tax_amount2 = 0;
|
||||
$recurring_expense->tax_amount3 = 0;
|
||||
$recurring_expense->date = null;
|
||||
$recurring_expense->payment_date = null;
|
||||
$recurring_expense->amount = 0;
|
||||
@ -39,6 +43,8 @@ class RecurringExpenseFactory
|
||||
$recurring_expense->custom_value2 = '';
|
||||
$recurring_expense->custom_value3 = '';
|
||||
$recurring_expense->custom_value4 = '';
|
||||
$recurring_expense->uses_inclusive_taxes = true;
|
||||
$recurring_expense->calculate_tax_by_amount = true;
|
||||
|
||||
return $recurring_expense;
|
||||
}
|
||||
|
62
app/Factory/RecurringExpenseToExpenseFactory.php
Normal file
62
app/Factory/RecurringExpenseToExpenseFactory.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\RecurringExpense;
|
||||
|
||||
class RecurringExpenseToExpenseFactory
|
||||
{
|
||||
public static function create(RecurringExpense $recurring_expense) :Expense
|
||||
{
|
||||
$expense = new Expense();
|
||||
$expense->user_id = $recurring_expense->user_id;
|
||||
$expense->assigned_user_id = $recurring_expense->assigned_user_id;
|
||||
$expense->vendor_id = $recurring_expense->vendor_id;
|
||||
$expense->invoice_id = $recurring_expense->invoice_id;
|
||||
$expense->currency_id = $recurring_expense->currency_id;
|
||||
$expense->company_id = $recurring_expense->company_id;
|
||||
$expense->bank_id = $recurring_expense->bank_id;
|
||||
$expense->exchange_rate = $recurring_expense->exchange_rate;
|
||||
$expense->is_deleted = false;
|
||||
$expense->should_be_invoiced = $recurring_expense->should_be_invoiced;
|
||||
$expense->tax_name1 = $recurring_expense->tax_name1;
|
||||
$expense->tax_rate1 = $recurring_expense->tax_rate1;
|
||||
$expense->tax_name2 = $recurring_expense->tax_name2;
|
||||
$expense->tax_rate2 = $recurring_expense->tax_rate2;
|
||||
$expense->tax_name3 = $recurring_expense->tax_name3;
|
||||
$expense->tax_rate3 = $recurring_expense->tax_rate3;
|
||||
$expense->date = now()->format('Y-m-d');
|
||||
$expense->payment_date = $recurring_expense->payment_date;
|
||||
$expense->amount = $recurring_expense->amount;
|
||||
$expense->foreign_amount = $recurring_expense->foreign_amount;
|
||||
$expense->private_notes = $recurring_expense->private_notes;
|
||||
$expense->public_notes = $recurring_expense->public_notes;
|
||||
$expense->transaction_reference = $recurring_expense->transaction_reference;
|
||||
$expense->custom_value1 = $recurring_expense->custom_value1;
|
||||
$expense->custom_value2 = $recurring_expense->custom_value2;
|
||||
$expense->custom_value3 = $recurring_expense->custom_value3;
|
||||
$expense->custom_value4 = $recurring_expense->custom_value4;
|
||||
$expense->transaction_id = $recurring_expense->transaction_id;
|
||||
$expense->category_id = $recurring_expense->category_id;
|
||||
$expense->payment_type_id = $recurring_expense->payment_type_id;
|
||||
$expense->project_id = $recurring_expense->project_id;
|
||||
$expense->invoice_documents = $recurring_expense->invoice_documents;
|
||||
$expense->tax_amount1 = $recurring_expense->tax_amount1;
|
||||
$expense->tax_amount2 = $recurring_expense->tax_amount2;
|
||||
$expense->tax_amount3 = $recurring_expense->tax_amount3;
|
||||
$expense->uses_inclusive_taxes = $recurring_expense->uses_inclusive_taxes;
|
||||
$expense->calculate_tax_by_amount = $recurring_expense->calculate_tax_by_amount;
|
||||
|
||||
return $expense;
|
||||
}
|
||||
}
|
95
app/Jobs/Cron/RecurringExpensesCron.php
Normal file
95
app/Jobs/Cron/RecurringExpensesCron.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Cron;
|
||||
|
||||
use App\Factory\RecurringExpenseToExpenseFactory;
|
||||
use App\Jobs\RecurringInvoice\SendRecurring;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\RecurringExpense;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class RecurringExpensesCron
|
||||
{
|
||||
use Dispatchable;
|
||||
use GeneratesCounter;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
/* Get all expenses where the send date is less than NOW + 30 minutes() */
|
||||
nlog("Sending recurring expenses ".Carbon::now()->format('Y-m-d h:i:s'));
|
||||
|
||||
if (! config('ninja.db.multi_db_enabled')) {
|
||||
|
||||
$this->getRecurringExpenses();
|
||||
|
||||
} else {
|
||||
//multiDB environment, need to
|
||||
foreach (MultiDB::$dbs as $db) {
|
||||
MultiDB::setDB($db);
|
||||
|
||||
$this->getRecurringExpenses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getRecurringExpenses()
|
||||
{
|
||||
$recurring_expenses = RecurringExpense::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNotNull('next_send_date')
|
||||
->whereNull('deleted_at')
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
// ->whereHas('client', function ($query) {
|
||||
// $query->where('is_deleted',0)
|
||||
// ->where('deleted_at', NULL);
|
||||
// })
|
||||
->with('company')
|
||||
->cursor();
|
||||
|
||||
nlog(now()->format('Y-m-d') . ' Generating Recurring Expenses. Count = '.$recurring_expenses->count());
|
||||
|
||||
$recurring_expenses->each(function ($recurring_expense, $key) {
|
||||
nlog("Current date = " . now()->format("Y-m-d") . " Recurring date = " .$recurring_expense->next_send_date);
|
||||
|
||||
if (!$recurring_expense->company->is_disabled) {
|
||||
$this->generateExpense($recurring_expense);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function generateExpense(RecurringExpense $recurring_expense)
|
||||
{
|
||||
$expense = RecurringExpenseToExpenseFactory::create($recurring_expense);
|
||||
$expense->save();
|
||||
|
||||
$expense->number = $this->getNextExpenseNumber($expense);
|
||||
$expense->save();
|
||||
}
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ class RecurringExpensesSchema extends Migration
|
||||
$table->date('date')->nullable();
|
||||
$table->date('payment_date')->nullable();
|
||||
$table->boolean('should_be_invoiced')->default(false);
|
||||
$table->boolean('invoice_documents')->default();
|
||||
$table->boolean('invoice_documents')->default(false);
|
||||
$table->string('transaction_id')->nullable();
|
||||
$table->string('custom_value1')->nullable();
|
||||
$table->string('custom_value2')->nullable();
|
||||
@ -46,14 +46,14 @@ class RecurringExpensesSchema extends Migration
|
||||
|
||||
$table->unsignedInteger('category_id')->nullable();
|
||||
$table->boolean('calculate_tax_by_amount')->default(false);
|
||||
$table->decimal('tax_amount1', 20, 6);
|
||||
$table->decimal('tax_amount2', 20, 6);
|
||||
$table->decimal('tax_amount3', 20, 6);
|
||||
$table->decimal('tax_rate1', 20, 6);
|
||||
$table->decimal('tax_rate2', 20, 6);
|
||||
$table->decimal('tax_rate3', 20, 6);
|
||||
$table->decimal('amount', 20, 6);
|
||||
$table->decimal('foreign_amount', 20, 6);
|
||||
$table->decimal('tax_amount1', 20, 6)->nullable();
|
||||
$table->decimal('tax_amount2', 20, 6)->nullable();
|
||||
$table->decimal('tax_amount3', 20, 6)->nullable();
|
||||
$table->decimal('tax_rate1', 20, 6)->nullable();
|
||||
$table->decimal('tax_rate2', 20, 6)->nullable();
|
||||
$table->decimal('tax_rate3', 20, 6)->nullable();
|
||||
$table->decimal('amount', 20, 6)->nullable();
|
||||
$table->decimal('foreign_amount', 20, 6)->nullable();
|
||||
$table->decimal('exchange_rate', 20, 6)->default(1);
|
||||
$table->unsignedInteger('assigned_user_id')->nullable();
|
||||
$table->string('number')->nullable();
|
||||
|
69
tests/Unit/RecurringExpenseCloneTest.php
Normal file
69
tests/Unit/RecurringExpenseCloneTest.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Factory\RecurringExpenseFactory;
|
||||
use App\Factory\RecurringExpenseToExpenseFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\RecurringExpense;
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class RecurringExpenseCloneTest extends TestCase
|
||||
{
|
||||
|
||||
public $faker;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
}
|
||||
|
||||
public function testBadBase64String()
|
||||
{
|
||||
$account = Account::factory()->create();
|
||||
$user = User::factory()->create(['account_id' => $account->id, 'email' => $this->faker->unique()->safeEmail]);
|
||||
$company = Company::factory()->create(['account_id' => $account->id]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
|
||||
$recurring_expense = RecurringExpenseFactory::create($company->id, $user->id);
|
||||
$recurring_expense->date = now();
|
||||
$recurring_expense->amount = 10;
|
||||
$recurring_expense->foreign_amount = 20;
|
||||
$recurring_expense->exchange_rate = 0.5;
|
||||
$recurring_expense->private_notes = "private";
|
||||
$recurring_expense->public_notes = "public";
|
||||
$recurring_expense->custom_value4 = "custom4";
|
||||
$recurring_expense->should_be_invoiced = true;
|
||||
|
||||
$recurring_expense->save();
|
||||
|
||||
$expense = RecurringExpenseToExpenseFactory::create($recurring_expense);
|
||||
$expense->save();
|
||||
|
||||
$this->assertNotNull($expense);
|
||||
$this->assertEquals(20, $expense->foreign_amount);
|
||||
$this->assertEquals(10, $expense->amount);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user