mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-02 22:57:33 -05:00 
			
		
		
		
	Merge branch 'recurring_expenses' into v5-develop
This commit is contained in:
		
						commit
						c7b9c582a2
					
				@ -12,6 +12,7 @@
 | 
				
			|||||||
namespace App\Console;
 | 
					namespace App\Console;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Jobs\Cron\AutoBillCron;
 | 
					use App\Jobs\Cron\AutoBillCron;
 | 
				
			||||||
 | 
					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\Ninja\AdjustEmailQuota;
 | 
					use App\Jobs\Ninja\AdjustEmailQuota;
 | 
				
			||||||
@ -62,6 +63,8 @@ class Kernel extends ConsoleKernel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
 | 
					        $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 AutoBillCron)->dailyAt('00:30')->withoutOverlapping();        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
 | 
					        $schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,12 @@ class CompanySettings extends BaseSettings
 | 
				
			|||||||
    public $expense_number_pattern = ''; //@implemented
 | 
					    public $expense_number_pattern = ''; //@implemented
 | 
				
			||||||
    public $expense_number_counter = 1; //@implemented
 | 
					    public $expense_number_counter = 1; //@implemented
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $recurring_expense_number_pattern = ''; 
 | 
				
			||||||
 | 
					    public $recurring_expense_number_counter = 1; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $recurring_quote_number_pattern = ''; 
 | 
				
			||||||
 | 
					    public $recurring_quote_number_counter = 1; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public $vendor_number_pattern = ''; //@implemented
 | 
					    public $vendor_number_pattern = ''; //@implemented
 | 
				
			||||||
    public $vendor_number_counter = 1; //@implemented
 | 
					    public $vendor_number_counter = 1; //@implemented
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -349,6 +355,8 @@ class CompanySettings extends BaseSettings
 | 
				
			|||||||
        'task_number_counter'                => 'int',
 | 
					        'task_number_counter'                => 'int',
 | 
				
			||||||
        'expense_number_pattern'             => 'string',
 | 
					        'expense_number_pattern'             => 'string',
 | 
				
			||||||
        'expense_number_counter'             => 'int',
 | 
					        'expense_number_counter'             => 'int',
 | 
				
			||||||
 | 
					        'recurring_expense_number_pattern'   => 'string',
 | 
				
			||||||
 | 
					        'recurring_expense_number_counter'   => 'int',
 | 
				
			||||||
        'vendor_number_pattern'              => 'string',
 | 
					        'vendor_number_pattern'              => 'string',
 | 
				
			||||||
        'vendor_number_counter'              => 'int',
 | 
					        'vendor_number_counter'              => 'int',
 | 
				
			||||||
        'ticket_number_pattern'              => 'string',
 | 
					        'ticket_number_pattern'              => 'string',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasArchived.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasArchived.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseWasArchived.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseWasArchived
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpense
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpense $recurring_expense, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense = $recurring_expense;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasCreated.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasCreated.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseWasCreated.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseWasCreated
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpense
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpense $recurring_expense, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense = $recurring_expense;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasDeleted.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasDeleted.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseWasDeleted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseWasDeleted
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpense
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpense $recurring_expense, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense = $recurring_expense;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								app/Events/RecurringExpense/RecurringExpenseWasRestored.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/Events/RecurringExpense/RecurringExpenseWasRestored.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseWasRestored.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseWasRestored
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpense
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $fromDeleted;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpense $recurring_expense, $fromDeleted, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense = $recurring_expense;
 | 
				
			||||||
 | 
					        $this->fromDeleted = $fromDeleted;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasUpdated.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringExpense/RecurringExpenseWasUpdated.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseWasUpdated.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseWasUpdated
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpense
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpense $recurring_expense, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense = $recurring_expense;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasArchived.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasArchived.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringQuoteWasArchived.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuoteWasArchived
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var Invoice
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Invoice $recurring_quote
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringQuote $recurring_quote, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_quote = $recurring_quote;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasCreated.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasCreated.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringQuoteWasCreated.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuoteWasCreated
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringQuote
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringQuote $recurring_quote
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringQuote $recurring_quote, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_quote = $recurring_quote;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasDeleted.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Events/RecurringQuote/RecurringQuoteWasDeleted.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringQuoteWasDeleted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuoteWasDeleted
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringQuote
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Invoice $invoice
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringQuote $recurring_quote, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_quote = $recurring_quote;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								app/Events/RecurringQuote/RecurringQuoteWasRestored.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/Events/RecurringQuote/RecurringQuoteWasRestored.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringQuoteWasRestored.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuoteWasRestored
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringQuote
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $fromDeleted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param Invoice $invoice
 | 
				
			||||||
 | 
					     * @param $fromDeleted
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringQuote $recurring_quote, $fromDeleted, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_quote = $recurring_quote;
 | 
				
			||||||
 | 
					        $this->fromDeleted = $fromDeleted;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								app/Events/RecurringQuote/RecurringQuoteWasUpdated.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/Events/RecurringQuote/RecurringQuoteWasUpdated.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					<?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\Events\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Broadcasting\InteractsWithSockets;
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Events\Dispatchable;
 | 
				
			||||||
 | 
					use Illuminate\Queue\SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringQuoteWasUpdated.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuoteWasUpdated
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use Dispatchable, InteractsWithSockets, SerializesModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var Invoice
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public $event_vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new event instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param RecurringQuote $recurring_quote
 | 
				
			||||||
 | 
					     * @param Company $company
 | 
				
			||||||
 | 
					     * @param array $event_vars
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringQuote $recurring_quote, Company $company, array $event_vars)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_quote = $recurring_quote;
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					        $this->event_vars = $event_vars;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								app/Factory/QuoteToRecurringQuoteFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/Factory/QuoteToRecurringQuoteFactory.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QuoteToRecurringQuoteFactory
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static function create(Quote $quote) :RecurringQuote
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_quote = new RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_quote->status_id = RecurringQuote::STATUS_DRAFT;
 | 
				
			||||||
 | 
					        $recurring_quote->discount = $quote->discount;
 | 
				
			||||||
 | 
					        $recurring_quote->number = '';
 | 
				
			||||||
 | 
					        $recurring_quote->is_amount_discount = $quote->is_amount_discount;
 | 
				
			||||||
 | 
					        $recurring_quote->po_number = $quote->po_number;
 | 
				
			||||||
 | 
					        $recurring_quote->footer = $quote->footer;
 | 
				
			||||||
 | 
					        $recurring_quote->terms = $quote->terms;
 | 
				
			||||||
 | 
					        $recurring_quote->public_notes = $quote->public_notes;
 | 
				
			||||||
 | 
					        $recurring_quote->private_notes = $quote->private_notes;
 | 
				
			||||||
 | 
					        $recurring_quote->date = date_create()->format($quote->client->date_format());
 | 
				
			||||||
 | 
					        $recurring_quote->due_date = $quote->due_date; //todo calculate based on terms
 | 
				
			||||||
 | 
					        $recurring_quote->is_deleted = $quote->is_deleted;
 | 
				
			||||||
 | 
					        $recurring_quote->line_items = $quote->line_items;
 | 
				
			||||||
 | 
					        $recurring_quote->tax_name1 = $quote->tax_name1;
 | 
				
			||||||
 | 
					        $recurring_quote->tax_rate1 = $quote->tax_rate1;
 | 
				
			||||||
 | 
					        $recurring_quote->tax_name2 = $quote->tax_name2;
 | 
				
			||||||
 | 
					        $recurring_quote->tax_rate2 = $quote->tax_rate2;
 | 
				
			||||||
 | 
					        $recurring_quote->custom_value1 = $quote->custom_value1;
 | 
				
			||||||
 | 
					        $recurring_quote->custom_value2 = $quote->custom_value2;
 | 
				
			||||||
 | 
					        $recurring_quote->custom_value3 = $quote->custom_value3;
 | 
				
			||||||
 | 
					        $recurring_quote->custom_value4 = $quote->custom_value4;
 | 
				
			||||||
 | 
					        $recurring_quote->amount = $quote->amount;
 | 
				
			||||||
 | 
					        // $recurring_quote->balance = $quote->balance;
 | 
				
			||||||
 | 
					        $recurring_quote->user_id = $quote->user_id;
 | 
				
			||||||
 | 
					        $recurring_quote->client_id = $quote->client_id;
 | 
				
			||||||
 | 
					        $recurring_quote->company_id = $quote->company_id;
 | 
				
			||||||
 | 
					        $recurring_quote->frequency_id = RecurringQuote::FREQUENCY_MONTHLY;
 | 
				
			||||||
 | 
					        $recurring_quote->last_sent_date = null;
 | 
				
			||||||
 | 
					        $recurring_quote->next_send_date = null;
 | 
				
			||||||
 | 
					        $recurring_quote->remaining_cycles = 0;
 | 
				
			||||||
 | 
					        $recurring_quote->paid_to_date = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $recurring_quote;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								app/Factory/RecurringExpenseFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								app/Factory/RecurringExpenseFactory.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					<?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\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseFactory
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static function create(int $company_id, int $user_id) :RecurringExpense
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_expense = new RecurringExpense();
 | 
				
			||||||
 | 
					        $recurring_expense->status_id = RecurringInvoice::STATUS_DRAFT;
 | 
				
			||||||
 | 
					        $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;
 | 
				
			||||||
 | 
					        $recurring_expense->tax_name2 = '';
 | 
				
			||||||
 | 
					        $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;
 | 
				
			||||||
 | 
					        $recurring_expense->foreign_amount = 0;
 | 
				
			||||||
 | 
					        $recurring_expense->private_notes = '';
 | 
				
			||||||
 | 
					        $recurring_expense->public_notes = '';
 | 
				
			||||||
 | 
					        $recurring_expense->transaction_reference = '';
 | 
				
			||||||
 | 
					        $recurring_expense->custom_value1 = '';
 | 
				
			||||||
 | 
					        $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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -22,6 +22,7 @@ class RecurringQuoteFactory
 | 
				
			|||||||
        $quote->discount = 0;
 | 
					        $quote->discount = 0;
 | 
				
			||||||
        $quote->is_amount_discount = true;
 | 
					        $quote->is_amount_discount = true;
 | 
				
			||||||
        $quote->po_number = '';
 | 
					        $quote->po_number = '';
 | 
				
			||||||
 | 
					        $quote->number = '';
 | 
				
			||||||
        $quote->footer = '';
 | 
					        $quote->footer = '';
 | 
				
			||||||
        $quote->terms = '';
 | 
					        $quote->terms = '';
 | 
				
			||||||
        $quote->public_notes = '';
 | 
					        $quote->public_notes = '';
 | 
				
			||||||
@ -48,6 +49,7 @@ class RecurringQuoteFactory
 | 
				
			|||||||
        $quote->last_sent_date = null;
 | 
					        $quote->last_sent_date = null;
 | 
				
			||||||
        $quote->next_send_date = null;
 | 
					        $quote->next_send_date = null;
 | 
				
			||||||
        $quote->remaining_cycles = 0;
 | 
					        $quote->remaining_cycles = 0;
 | 
				
			||||||
 | 
					        $quote->paid_to_date = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $quote;
 | 
					        return $quote;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								app/Factory/RecurringQuoteToQuoteFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/Factory/RecurringQuoteToQuoteFactory.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					<?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\Client;
 | 
				
			||||||
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteToQuoteFactory
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static function create(RecurringQuote $recurring_quote, Client $client) :Quote
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $quote = new Quote();
 | 
				
			||||||
 | 
					        $quote->status_id = Quote::STATUS_DRAFT;
 | 
				
			||||||
 | 
					        $quote->discount = $recurring_quote->discount;
 | 
				
			||||||
 | 
					        $quote->is_amount_discount = $recurring_quote->is_amount_discount;
 | 
				
			||||||
 | 
					        $quote->po_number = $recurring_quote->po_number;
 | 
				
			||||||
 | 
					        $quote->footer = $recurring_quote->footer;
 | 
				
			||||||
 | 
					        $quote->terms = $recurring_quote->terms;
 | 
				
			||||||
 | 
					        $quote->public_notes = $recurring_quote->public_notes;
 | 
				
			||||||
 | 
					        $quote->private_notes = $recurring_quote->private_notes;
 | 
				
			||||||
 | 
					        //$quote->date = now()->format($client->date_format());
 | 
				
			||||||
 | 
					        //$quote->due_date = $recurring_quote->calculateDueDate(now());
 | 
				
			||||||
 | 
					        $quote->is_deleted = $recurring_quote->is_deleted;
 | 
				
			||||||
 | 
					        $quote->line_items = $recurring_quote->line_items;
 | 
				
			||||||
 | 
					        $quote->tax_name1 = $recurring_quote->tax_name1;
 | 
				
			||||||
 | 
					        $quote->tax_rate1 = $recurring_quote->tax_rate1;
 | 
				
			||||||
 | 
					        $quote->tax_name2 = $recurring_quote->tax_name2;
 | 
				
			||||||
 | 
					        $quote->tax_rate2 = $recurring_quote->tax_rate2;
 | 
				
			||||||
 | 
					        $quote->tax_name3 = $recurring_quote->tax_name3;
 | 
				
			||||||
 | 
					        $quote->tax_rate3 = $recurring_quote->tax_rate3;
 | 
				
			||||||
 | 
					        $quote->total_taxes = $recurring_quote->total_taxes;
 | 
				
			||||||
 | 
					        $quote->subscription_id = $recurring_quote->subscription_id;
 | 
				
			||||||
 | 
					        $quote->custom_value1 = $recurring_quote->custom_value1;
 | 
				
			||||||
 | 
					        $quote->custom_value2 = $recurring_quote->custom_value2;
 | 
				
			||||||
 | 
					        $quote->custom_value3 = $recurring_quote->custom_value3;
 | 
				
			||||||
 | 
					        $quote->custom_value4 = $recurring_quote->custom_value4;
 | 
				
			||||||
 | 
					        $quote->amount = $recurring_quote->amount;
 | 
				
			||||||
 | 
					        // $quote->balance = $recurring_quote->balance;
 | 
				
			||||||
 | 
					        $quote->user_id = $recurring_quote->user_id;
 | 
				
			||||||
 | 
					        $quote->assigned_user_id = $recurring_quote->assigned_user_id;
 | 
				
			||||||
 | 
					        $quote->company_id = $recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $quote->recurring_id = $recurring_quote->id;
 | 
				
			||||||
 | 
					        $quote->client_id = $client->id;
 | 
				
			||||||
 | 
					        $quote->auto_bill_enabled = $recurring_quote->auto_bill_enabled;
 | 
				
			||||||
 | 
					        $quote->paid_to_date = 0;
 | 
				
			||||||
 | 
					        $quote->design_id = $recurring_quote->design_id;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return $quote;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -38,11 +38,6 @@ class ExpenseFilters extends QueryFilters
 | 
				
			|||||||
        return  $this->builder->where(function ($query) use ($filter) {
 | 
					        return  $this->builder->where(function ($query) use ($filter) {
 | 
				
			||||||
            $query->where('expenses.name', 'like', '%'.$filter.'%')
 | 
					            $query->where('expenses.name', 'like', '%'.$filter.'%')
 | 
				
			||||||
                          ->orWhere('expenses.id_number', 'like', '%'.$filter.'%')
 | 
					                          ->orWhere('expenses.id_number', 'like', '%'.$filter.'%')
 | 
				
			||||||
                          ->orWhereHas('contacts', function ($query) use($filter){
 | 
					 | 
				
			||||||
                              $query->where('expense_contacts.first_name', 'like', '%'.$filter.'%');
 | 
					 | 
				
			||||||
                              $query->orWhere('expense_contacts.last_name', 'like', '%'.$filter.'%');
 | 
					 | 
				
			||||||
                              $query->orWhere('expense_contacts.email', 'like', '%'.$filter.'%');
 | 
					 | 
				
			||||||
                          })
 | 
					 | 
				
			||||||
                          ->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
 | 
					                          ->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
 | 
				
			||||||
                          ->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
 | 
					                          ->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
 | 
				
			||||||
                          ->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%')
 | 
					                          ->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										148
									
								
								app/Filters/RecurringExpenseFilters.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								app/Filters/RecurringExpenseFilters.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					<?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\Filters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Models\User;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Builder;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\DB;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Gate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * RecurringExpenseFilters.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseFilters extends QueryFilters
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Filter based on search text.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string query filter
 | 
				
			||||||
 | 
					     * @return Builder
 | 
				
			||||||
 | 
					     * @deprecated
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function filter(string $filter = '') : Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (strlen($filter) == 0) {
 | 
				
			||||||
 | 
					            return $this->builder;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return  $this->builder->where(function ($query) use ($filter) {
 | 
				
			||||||
 | 
					            $query->where('recurring_expenses.name', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
					                          ->orWhere('recurring_expenses.id_number', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
					                          ->orWhere('recurring_expenses.custom_value1', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
					                          ->orWhere('recurring_expenses.custom_value2', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
					                          ->orWhere('recurring_expenses.custom_value3', 'like', '%'.$filter.'%')
 | 
				
			||||||
 | 
					                          ->orWhere('recurring_expenses.custom_value4', 'like', '%'.$filter.'%');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Filters the list based on the status
 | 
				
			||||||
 | 
					     * archived, active, deleted.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string filter
 | 
				
			||||||
 | 
					     * @return Builder
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function status(string $filter = '') : Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (strlen($filter) == 0) {
 | 
				
			||||||
 | 
					            return $this->builder;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $table = 'expenses';
 | 
				
			||||||
 | 
					        $filters = explode(',', $filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->builder->where(function ($query) use ($filters, $table) {
 | 
				
			||||||
 | 
					            $query->whereNull($table.'.id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (in_array(parent::STATUS_ACTIVE, $filters)) {
 | 
				
			||||||
 | 
					                $query->orWhereNull($table.'.deleted_at');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (in_array(parent::STATUS_ARCHIVED, $filters)) {
 | 
				
			||||||
 | 
					                $query->orWhere(function ($query) use ($table) {
 | 
				
			||||||
 | 
					                    $query->whereNotNull($table.'.deleted_at');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (! in_array($table, ['users'])) {
 | 
				
			||||||
 | 
					                        $query->where($table.'.is_deleted', '=', 0);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (in_array(parent::STATUS_DELETED, $filters)) {
 | 
				
			||||||
 | 
					                $query->orWhere($table.'.is_deleted', '=', 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sorts the list based on $sort.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param string sort formatted as column|asc
 | 
				
			||||||
 | 
					     * @return Builder
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function sort(string $sort) : Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $sort_col = explode('|', $sort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->builder->orderBy($sort_col[0], $sort_col[1]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the base query.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param int company_id
 | 
				
			||||||
 | 
					     * @param User $user
 | 
				
			||||||
 | 
					     * @return Builder
 | 
				
			||||||
 | 
					     * @deprecated
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function baseQuery(int $company_id, User $user) : Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query = DB::table('recurring_expenses')
 | 
				
			||||||
 | 
					            ->join('companies', 'companies.id', '=', 'recurring_expenses.company_id')
 | 
				
			||||||
 | 
					            ->where('recurring_expenses.company_id', '=', $company_id)
 | 
				
			||||||
 | 
					            ->select(
 | 
				
			||||||
 | 
					                DB::raw('COALESCE(recurring_expenses.country_id, companies.country_id) country_id'),
 | 
				
			||||||
 | 
					                'recurring_expenses.id',
 | 
				
			||||||
 | 
					                'recurring_expenses.private_notes',
 | 
				
			||||||
 | 
					                'recurring_expenses.custom_value1',
 | 
				
			||||||
 | 
					                'recurring_expenses.custom_value2',
 | 
				
			||||||
 | 
					                'recurring_expenses.custom_value3',
 | 
				
			||||||
 | 
					                'recurring_expenses.custom_value4',
 | 
				
			||||||
 | 
					                'recurring_expenses.created_at',
 | 
				
			||||||
 | 
					                'recurring_expenses.created_at as expense_created_at',
 | 
				
			||||||
 | 
					                'recurring_expenses.deleted_at',
 | 
				
			||||||
 | 
					                'recurring_expenses.is_deleted',
 | 
				
			||||||
 | 
					                'recurring_expenses.user_id',
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * If the user does not have permissions to view all invoices
 | 
				
			||||||
 | 
					         * limit the user to only the invoices they have created
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (Gate::denies('view-list', RecurringExpense::class)) {
 | 
				
			||||||
 | 
					            $query->where('recurring_expenses.user_id', '=', $user->id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $query;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Filters the query by the users company ID.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Illuminate\Database\Query\Builder
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function entityFilter()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->builder->company();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -84,6 +84,7 @@ class BaseController extends Controller
 | 
				
			|||||||
          'company.payments.documents',
 | 
					          'company.payments.documents',
 | 
				
			||||||
          'company.payment_terms.company',
 | 
					          'company.payment_terms.company',
 | 
				
			||||||
          'company.projects.documents',
 | 
					          'company.projects.documents',
 | 
				
			||||||
 | 
					          'company.recurring_expenses',
 | 
				
			||||||
          'company.recurring_invoices',
 | 
					          'company.recurring_invoices',
 | 
				
			||||||
          'company.recurring_invoices.invitations.contact',
 | 
					          'company.recurring_invoices.invitations.contact',
 | 
				
			||||||
          'company.recurring_invoices.invitations.company',
 | 
					          'company.recurring_invoices.invitations.company',
 | 
				
			||||||
@ -307,6 +308,13 @@ class BaseController extends Controller
 | 
				
			|||||||
                if(!$user->hasPermission('view_recurring_invoice'))
 | 
					                if(!$user->hasPermission('view_recurring_invoice'))
 | 
				
			||||||
                  $query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
 | 
					                  $query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'company.recurring_expenses'=> function ($query) use ($updated_at, $user) {
 | 
				
			||||||
 | 
					                $query->where('updated_at', '>=', $updated_at)->with('documents');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(!$user->hasPermission('view_recurring_expense'))
 | 
				
			||||||
 | 
					                  $query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            'company.tasks'=> function ($query) use ($updated_at, $user) {
 | 
					            'company.tasks'=> function ($query) use ($updated_at, $user) {
 | 
				
			||||||
                $query->where('updated_at', '>=', $updated_at)->with('documents');
 | 
					                $query->where('updated_at', '>=', $updated_at)->with('documents');
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										616
									
								
								app/Http/Controllers/RecurringExpenseController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										616
									
								
								app/Http/Controllers/RecurringExpenseController.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,616 @@
 | 
				
			|||||||
 | 
					<?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\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasCreated;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasUpdated;
 | 
				
			||||||
 | 
					use App\Factory\RecurringExpenseFactory;
 | 
				
			||||||
 | 
					use App\Filters\RecurringExpenseFilters;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\CreateRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\DestroyRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\EditRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\ShowRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\StoreRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\UpdateRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Http\Requests\RecurringExpense\UploadRecurringExpenseRequest;
 | 
				
			||||||
 | 
					use App\Models\Account;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Repositories\RecurringExpenseRepository;
 | 
				
			||||||
 | 
					use App\Transformers\RecurringExpenseTransformer;
 | 
				
			||||||
 | 
					use App\Utils\Ninja;
 | 
				
			||||||
 | 
					use App\Utils\Traits\BulkOptions;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use App\Utils\Traits\SavesDocuments;
 | 
				
			||||||
 | 
					use App\Utils\Traits\Uploadable;
 | 
				
			||||||
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					use Illuminate\Http\Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpenseController.
 | 
				
			||||||
 | 
					 * @covers App\Http\Controllers\RecurringExpenseController
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseController extends BaseController
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					    use Uploadable;
 | 
				
			||||||
 | 
					    use BulkOptions;
 | 
				
			||||||
 | 
					    use SavesDocuments;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    protected $entity_type = RecurringExpense::class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $entity_transformer = RecurringExpenseTransformer::class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var RecurringExpenseepository
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected $recurring_expense_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * RecurringExpenseController constructor.
 | 
				
			||||||
 | 
					     * @param RecurringExpenseRepository $recurring_expense_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(RecurringExpenseRepository $recurring_expense_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->recurring_expense_repo = $recurring_expense_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @OA\Get(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses",
 | 
				
			||||||
 | 
					     *      operationId="getRecurringExpenses",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Gets a list of recurring_expenses",
 | 
				
			||||||
 | 
					     *      description="Lists recurring_expenses, search and filters allow fine grained lists to be generated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Query parameters can be added to performed more fine grained filtering of the recurring_expenses, these are handled by the RecurringExpenseFilters class which defines the methods available",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/index"),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="A list of recurring_expenses",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     * @param RecurringExpenseFilters $filters
 | 
				
			||||||
 | 
					     * @return Response|mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function index(RecurringExpenseFilters $filters)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_expenses = RecurringExpense::filter($filters);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->listResponse($recurring_expenses);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Display the specified resource.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ShowRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Get(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/{id}",
 | 
				
			||||||
 | 
					     *      operationId="showRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Shows a client",
 | 
				
			||||||
 | 
					     *      description="Displays a client by id",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(
 | 
				
			||||||
 | 
					     *          name="id",
 | 
				
			||||||
 | 
					     *          in="path",
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense Hashed ID",
 | 
				
			||||||
 | 
					     *          example="D2J234DFA",
 | 
				
			||||||
 | 
					     *          required=true,
 | 
				
			||||||
 | 
					     *          @OA\Schema(
 | 
				
			||||||
 | 
					     *              type="string",
 | 
				
			||||||
 | 
					     *              format="string",
 | 
				
			||||||
 | 
					     *          ),
 | 
				
			||||||
 | 
					     *      ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns the recurring_expense object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function show(ShowRecurringExpenseRequest $request, RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the form for editing the specified resource.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param EditRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Get(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/{id}/edit",
 | 
				
			||||||
 | 
					     *      operationId="editRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Shows a client for editting",
 | 
				
			||||||
 | 
					     *      description="Displays a client by id",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(
 | 
				
			||||||
 | 
					     *          name="id",
 | 
				
			||||||
 | 
					     *          in="path",
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense Hashed ID",
 | 
				
			||||||
 | 
					     *          example="D2J234DFA",
 | 
				
			||||||
 | 
					     *          required=true,
 | 
				
			||||||
 | 
					     *          @OA\Schema(
 | 
				
			||||||
 | 
					     *              type="string",
 | 
				
			||||||
 | 
					     *              format="string",
 | 
				
			||||||
 | 
					     *          ),
 | 
				
			||||||
 | 
					     *      ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns the client object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function edit(EditRecurringExpenseRequest $request, RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update the specified resource in storage.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param UpdateRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Put(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/{id}",
 | 
				
			||||||
 | 
					     *      operationId="updateRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Updates a client",
 | 
				
			||||||
 | 
					     *      description="Handles the updating of a client by id",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(
 | 
				
			||||||
 | 
					     *          name="id",
 | 
				
			||||||
 | 
					     *          in="path",
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense Hashed ID",
 | 
				
			||||||
 | 
					     *          example="D2J234DFA",
 | 
				
			||||||
 | 
					     *          required=true,
 | 
				
			||||||
 | 
					     *          @OA\Schema(
 | 
				
			||||||
 | 
					     *              type="string",
 | 
				
			||||||
 | 
					     *              format="string",
 | 
				
			||||||
 | 
					     *          ),
 | 
				
			||||||
 | 
					     *      ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns the client object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function update(UpdateRecurringExpenseRequest $request, RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($request->entityIsDeleted($recurring_expense)) {
 | 
				
			||||||
 | 
					            return $request->disallowUpdate();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_expense = $this->recurring_expense_repo->save($request->all(), $recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->uploadLogo($request->file('company_logo'), $recurring_expense->company, $recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        event(new RecurringExpenseWasUpdated($recurring_expense, $recurring_expense->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense->fresh());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the form for creating a new resource.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param CreateRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Get(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/create",
 | 
				
			||||||
 | 
					     *      operationId="getRecurringExpensesCreate",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Gets a new blank client object",
 | 
				
			||||||
 | 
					     *      description="Returns a blank object with default values",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="A blank client object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function create(CreateRecurringExpenseRequest $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_expense = RecurringExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Store a newly created resource in storage.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param StoreRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Post(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses",
 | 
				
			||||||
 | 
					     *      operationId="storeRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Adds a client",
 | 
				
			||||||
 | 
					     *      description="Adds an client to a company",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns the saved client object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function store(StoreRecurringExpenseRequest $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_expense = $this->recurring_expense_repo->save($request->all(), RecurringExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        event(new RecurringExpenseWasCreated($recurring_expense, $recurring_expense->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Remove the specified resource from storage.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param DestroyRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws \Exception
 | 
				
			||||||
 | 
					     * @OA\Delete(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/{id}",
 | 
				
			||||||
 | 
					     *      operationId="deleteRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Deletes a client",
 | 
				
			||||||
 | 
					     *      description="Handles the deletion of a client by id",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(
 | 
				
			||||||
 | 
					     *          name="id",
 | 
				
			||||||
 | 
					     *          in="path",
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense Hashed ID",
 | 
				
			||||||
 | 
					     *          example="D2J234DFA",
 | 
				
			||||||
 | 
					     *          required=true,
 | 
				
			||||||
 | 
					     *          @OA\Schema(
 | 
				
			||||||
 | 
					     *              type="string",
 | 
				
			||||||
 | 
					     *              format="string",
 | 
				
			||||||
 | 
					     *          ),
 | 
				
			||||||
 | 
					     *      ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns a HTTP status",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function destroy(DestroyRecurringExpenseRequest $request, RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->recurring_expense_repo->delete($recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense->fresh());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Perform bulk actions on the list view.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Post(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/bulk",
 | 
				
			||||||
 | 
					     *      operationId="bulkRecurringExpenses",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expenses"},
 | 
				
			||||||
 | 
					     *      summary="Performs bulk actions on an array of recurring_expenses",
 | 
				
			||||||
 | 
					     *      description="",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/index"),
 | 
				
			||||||
 | 
					     *      @OA\RequestBody(
 | 
				
			||||||
 | 
					     *         description="User credentials",
 | 
				
			||||||
 | 
					     *         required=true,
 | 
				
			||||||
 | 
					     *         @OA\MediaType(
 | 
				
			||||||
 | 
					     *             mediaType="application/json",
 | 
				
			||||||
 | 
					     *             @OA\Schema(
 | 
				
			||||||
 | 
					     *                 type="array",
 | 
				
			||||||
 | 
					     *                 @OA\Items(
 | 
				
			||||||
 | 
					     *                     type="integer",
 | 
				
			||||||
 | 
					     *                     description="Array of hashed IDs to be bulk 'actioned",
 | 
				
			||||||
 | 
					     *                     example="[0,1,2,3]",
 | 
				
			||||||
 | 
					     *                 ),
 | 
				
			||||||
 | 
					     *             )
 | 
				
			||||||
 | 
					     *         )
 | 
				
			||||||
 | 
					     *     ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense User response",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function bulk()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $action = request()->input('action');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $ids = request()->input('ids');
 | 
				
			||||||
 | 
					        $recurring_expenses = RecurringExpense::withTrashed()->find($this->transformKeys($ids));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_expenses->each(function ($recurring_expense, $key) use ($action) {
 | 
				
			||||||
 | 
					            if (auth()->user()->can('edit', $recurring_expense)) {
 | 
				
			||||||
 | 
					                $this->performAction($recurring_expense, $action, true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->listResponse(RecurringExpense::withTrashed()->whereIn('id', $this->transformKeys($ids)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function performAction(RecurringExpense $recurring_expense, string $action, $bulk = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch ($action) {
 | 
				
			||||||
 | 
					            case 'archive':
 | 
				
			||||||
 | 
					                $this->recurring_expense_repo->archive($recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (! $bulk) {
 | 
				
			||||||
 | 
					                    return $this->listResponse($recurring_expense);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'restore':
 | 
				
			||||||
 | 
					                $this->recurring_expense_repo->restore($recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (! $bulk) {
 | 
				
			||||||
 | 
					                    return $this->listResponse($recurring_expense);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'delete':
 | 
				
			||||||
 | 
					                $this->recurring_expense_repo->delete($recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (! $bulk) {
 | 
				
			||||||
 | 
					                    return $this->listResponse($recurring_expense);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'email':
 | 
				
			||||||
 | 
					                //dispatch email to queue
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'start':
 | 
				
			||||||
 | 
					                $recurring_expense = $recurring_expense->service()->start()->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (! $bulk) {
 | 
				
			||||||
 | 
					                    $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'stop':
 | 
				
			||||||
 | 
					                $recurring_expense = $recurring_expense->service()->stop()->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (! $bulk) {
 | 
				
			||||||
 | 
					                    $this->itemResponse($recurring_expense);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                // code...
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update the specified resource in storage.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param UploadRecurringExpenseRequest $request
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     * @return Response
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @OA\Put(
 | 
				
			||||||
 | 
					     *      path="/api/v1/recurring_expenses/{id}/upload",
 | 
				
			||||||
 | 
					     *      operationId="uploadRecurringExpense",
 | 
				
			||||||
 | 
					     *      tags={"recurring_expense"},
 | 
				
			||||||
 | 
					     *      summary="Uploads a document to a recurring_expense",
 | 
				
			||||||
 | 
					     *      description="Handles the uploading of a document to a recurring_expense",
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(ref="#/components/parameters/include"),
 | 
				
			||||||
 | 
					     *      @OA\Parameter(
 | 
				
			||||||
 | 
					     *          name="id",
 | 
				
			||||||
 | 
					     *          in="path",
 | 
				
			||||||
 | 
					     *          description="The RecurringExpense Hashed ID",
 | 
				
			||||||
 | 
					     *          example="D2J234DFA",
 | 
				
			||||||
 | 
					     *          required=true,
 | 
				
			||||||
 | 
					     *          @OA\Schema(
 | 
				
			||||||
 | 
					     *              type="string",
 | 
				
			||||||
 | 
					     *              format="string",
 | 
				
			||||||
 | 
					     *          ),
 | 
				
			||||||
 | 
					     *      ),
 | 
				
			||||||
 | 
					     *      @OA\Response(
 | 
				
			||||||
 | 
					     *          response=200,
 | 
				
			||||||
 | 
					     *          description="Returns the RecurringExpense object",
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
				
			||||||
 | 
					     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/RecurringExpense"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *          response=422,
 | 
				
			||||||
 | 
					     *          description="Validation error",
 | 
				
			||||||
 | 
					     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *       @OA\Response(
 | 
				
			||||||
 | 
					     *           response="default",
 | 
				
			||||||
 | 
					     *           description="Unexpected Error",
 | 
				
			||||||
 | 
					     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
				
			||||||
 | 
					     *       ),
 | 
				
			||||||
 | 
					     *     )
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function upload(UploadRecurringExpenseRequest $request, RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!$this->checkFeature(Account::FEATURE_DOCUMENTS))
 | 
				
			||||||
 | 
					            return $this->featureFailure();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if ($request->has('documents')) 
 | 
				
			||||||
 | 
					            $this->saveDocuments($request->file('documents'), $recurring_expense);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->itemResponse($recurring_expense->fresh());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -31,7 +31,6 @@ use App\Utils\Ninja;
 | 
				
			|||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
use App\Utils\Traits\SavesDocuments;
 | 
					use App\Utils\Traits\SavesDocuments;
 | 
				
			||||||
use Carbon\Carbon;
 | 
					use Carbon\Carbon;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					 | 
				
			||||||
use Illuminate\Http\Response;
 | 
					use Illuminate\Http\Response;
 | 
				
			||||||
use Illuminate\Support\Facades\Storage;
 | 
					use Illuminate\Support\Facades\Storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -577,7 +577,7 @@ class RecurringQuoteController extends BaseController
 | 
				
			|||||||
    public function action(ActionRecurringQuoteRequest $request, RecurringQuote $recurring_quote, $action)
 | 
					    public function action(ActionRecurringQuoteRequest $request, RecurringQuote $recurring_quote, $action)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        switch ($action) {
 | 
					        switch ($action) {
 | 
				
			||||||
            case 'clone_to_RecurringQuote':
 | 
					            case 'clone_to_recurring_quote':
 | 
				
			||||||
          //      $recurring_invoice = CloneRecurringQuoteFactory::create($recurring_invoice, auth()->user()->id);
 | 
					          //      $recurring_invoice = CloneRecurringQuoteFactory::create($recurring_invoice, auth()->user()->id);
 | 
				
			||||||
          //      return $this->itemResponse($recurring_invoice);
 | 
					          //      return $this->itemResponse($recurring_invoice);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Utils\Traits\BulkOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BulkRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use BulkOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (! $this->has('action')) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (! in_array($this->action, $this->getBulkOptions(), true)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return auth()->user()->can(auth()->user()->isAdmin(), RecurringExpense::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the validation rules that apply to the request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function rules()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $rules = $this->getGlobalRules();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* We don't require IDs on bulk storing. */
 | 
				
			||||||
 | 
					        if ($this->action !== self::$STORE_METHOD) {
 | 
				
			||||||
 | 
					            $rules['ids'] = ['required'];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $rules;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CreateRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('create', RecurringExpense::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DestroyRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('edit', $this->recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EditRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('edit', $this->recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ShowRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('view', $this->recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					use App\Http\ValidationRules\RecurringExpense\UniqueRecurringExpenseNumberRule;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Validation\Rule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StoreRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('create', RecurringExpense::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rules()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $rules = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->number) 
 | 
				
			||||||
 | 
					            $rules['number'] = Rule::unique('recurring_expenses')->where('company_id', auth()->user()->company()->id);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if(!empty($this->client_id))
 | 
				
			||||||
 | 
					            $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['frequency_id'] = 'required|integer|digits_between:1,12';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->globalRules($rules);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected function prepareForValidation()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $input = $this->all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $input = $this->decodePrimaryKeys($input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('category_id', $input) && is_string($input['category_id'])) {
 | 
				
			||||||
 | 
					            $input['category_id'] = $this->decodePrimaryKey($input['category_id']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) {
 | 
				
			||||||
 | 
					            $input['currency_id'] = (string)auth()->user()->company()->settings->currency_id;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(array_key_exists('color', $input) && is_null($input['color']))
 | 
				
			||||||
 | 
					            $input['color'] = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->replace($input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function messages()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'unique' => ctrans('validation.unique', ['attribute' => 'email']),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					use App\Utils\Traits\ChecksEntityStatus;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Validation\Rule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UpdateRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					    use ChecksEntityStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('edit', $this->recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rules()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* Ensure we have a client name, and that all emails are unique*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['country_id'] = 'integer|nullable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['contacts.*.email'] = 'nullable|distinct';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isset($this->number)) {
 | 
				
			||||||
 | 
					            $rules['number'] = Rule::unique('recurring_expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->recurring_expense->id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->globalRules($rules);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function messages()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'unique' => ctrans('validation.unique', ['attribute' => 'email']),
 | 
				
			||||||
 | 
					            'email' => ctrans('validation.email', ['attribute' => 'email']),
 | 
				
			||||||
 | 
					            'name.required' => ctrans('validation.required', ['attribute' => 'name']),
 | 
				
			||||||
 | 
					            'required' => ctrans('validation.required', ['attribute' => 'email']),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected function prepareForValidation()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $input = $this->all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $input = $this->decodePrimaryKeys($input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('category_id', $input) && is_string($input['category_id'])) {
 | 
				
			||||||
 | 
					            $input['category_id'] = $this->decodePrimaryKey($input['category_id']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('documents', $input)) {
 | 
				
			||||||
 | 
					            unset($input['documents']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) {
 | 
				
			||||||
 | 
					            $input['currency_id'] = (string)auth()->user()->company()->settings->currency_id;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->replace($input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					<?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\Http\Requests\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UploadRecurringExpenseRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('edit', $this->recurring_expense);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rules()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	$rules = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if($this->input('documents'))
 | 
				
			||||||
 | 
					            $rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	return $rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,9 +12,12 @@
 | 
				
			|||||||
namespace App\Http\Requests\RecurringQuote;
 | 
					namespace App\Http\Requests\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Http\Requests\Request;
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					use App\Http\ValidationRules\Recurring\UniqueRecurringQuoteNumberRule;
 | 
				
			||||||
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
use App\Utils\Traits\CleanLineItems;
 | 
					use App\Utils\Traits\CleanLineItems;
 | 
				
			||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Http\UploadedFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StoreRecurringQuoteRequest extends Request
 | 
					class StoreRecurringQuoteRequest extends Request
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -33,26 +36,61 @@ class StoreRecurringQuoteRequest extends Request
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function rules()
 | 
					    public function rules()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return [
 | 
					        $rules = [];
 | 
				
			||||||
            'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx',
 | 
					
 | 
				
			||||||
            'client_id' => 'required|exists:clients,id,company_id,'.auth()->user()->company()->id,
 | 
					        if ($this->input('documents') && is_array($this->input('documents'))) {
 | 
				
			||||||
        ];
 | 
					            $documents = count($this->input('documents'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (range(0, $documents) as $index) {
 | 
				
			||||||
 | 
					                $rules['documents.'.$index] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } elseif ($this->input('documents')) {
 | 
				
			||||||
 | 
					            $rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['client_id'] = 'required|exists:clients,id,company_id,'.auth()->user()->company()->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['invitations.*.client_contact_id'] = 'distinct';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['frequency_id'] = 'required|integer|digits_between:1,12';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules['number'] = new UniqueRecurringQuoteNumberRule($this->all());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $rules;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected function prepareForValidation()
 | 
					    protected function prepareForValidation()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $input = $this->all();
 | 
					        $input = $this->all();
 | 
				
			||||||
 | 
					        $input = $this->decodePrimaryKeys($input);
 | 
				
			||||||
        if ($input['client_id']) {
 | 
					 | 
				
			||||||
            $input['client_id'] = $this->decodePrimaryKey($input['client_id']);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
 | 
					 | 
				
			||||||
            $input['assigned_user_id'] = $this->decodePrimaryKey($input['assigned_user_id']);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
					        $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
				
			||||||
        //$input['line_items'] = json_encode($input['line_items']);
 | 
					        
 | 
				
			||||||
 | 
					        if (isset($input['auto_bill'])) {
 | 
				
			||||||
 | 
					            $input['auto_bill_enabled'] = $this->setAutoBillFlag($input['auto_bill']);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if ($client = Client::find($input['client_id'])) {
 | 
				
			||||||
 | 
					                $input['auto_bill'] = $client->getSetting('auto_bill');
 | 
				
			||||||
 | 
					                $input['auto_bill_enabled'] = $this->setAutoBillFlag($input['auto_bill']);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
        $this->replace($input);
 | 
					        $this->replace($input);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function setAutoBillFlag($auto_bill)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($auto_bill == 'always' || $auto_bill == 'optout') {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function messages()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,12 +14,15 @@ namespace App\Http\Requests\RecurringQuote;
 | 
				
			|||||||
use App\Http\Requests\Request;
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
use App\Utils\Traits\ChecksEntityStatus;
 | 
					use App\Utils\Traits\ChecksEntityStatus;
 | 
				
			||||||
use App\Utils\Traits\CleanLineItems;
 | 
					use App\Utils\Traits\CleanLineItems;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Http\UploadedFile;
 | 
				
			||||||
use Illuminate\Validation\Rule;
 | 
					use Illuminate\Validation\Rule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UpdateRecurringQuoteRequest extends Request
 | 
					class UpdateRecurringQuoteRequest extends Request
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use ChecksEntityStatus;
 | 
					    use ChecksEntityStatus;
 | 
				
			||||||
    use CleanLineItems;
 | 
					    use CleanLineItems;
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Determine if the user is authorized to make this request.
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
@ -33,24 +36,64 @@ class UpdateRecurringQuoteRequest extends Request
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function rules()
 | 
					    public function rules()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return [
 | 
					        $rules = [];
 | 
				
			||||||
            'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx',
 | 
					
 | 
				
			||||||
        ];
 | 
					        if ($this->input('documents') && is_array($this->input('documents'))) {
 | 
				
			||||||
 | 
					            $documents = count($this->input('documents'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (range(0, $documents) as $index) {
 | 
				
			||||||
 | 
					                $rules['documents.'.$index] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } elseif ($this->input('documents')) {
 | 
				
			||||||
 | 
					            $rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if($this->number)
 | 
				
			||||||
 | 
					            $rules['number'] = Rule::unique('recurring_quotes')->where('company_id', auth()->user()->company()->id)->ignore($this->recurring_quote->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $rules;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected function prepareForValidation()
 | 
					    protected function prepareForValidation()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $input = $this->all();
 | 
					        $input = $this->all();
 | 
				
			||||||
 | 
					        $input = $this->decodePrimaryKeys($input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
 | 
					        if (isset($input['line_items'])) {
 | 
				
			||||||
            $input['assigned_user_id'] = $this->decodePrimaryKey($input['assigned_user_id']);
 | 
					            $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
					        if (isset($input['auto_bill'])) {
 | 
				
			||||||
 | 
					            $input['auto_bill_enabled'] = $this->setAutoBillFlag($input['auto_bill']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if($this->number)
 | 
					        if (array_key_exists('documents', $input)) {
 | 
				
			||||||
            $rules['number'] = Rule::unique('recurring_quotes')->where('company_id', auth()->user()->company()->id)->ignore($this->recurring_quote->id);
 | 
					            unset($input['documents']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        $this->replace($input);
 | 
					        $this->replace($input);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * if($auto_bill == '')
 | 
				
			||||||
 | 
					     * off / optin / optout will reset the status of this field to off to allow
 | 
				
			||||||
 | 
					     * the client to choose whether to auto_bill or not.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param enum $auto_bill off/always/optin/optout
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function setAutoBillFlag($auto_bill) :bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($auto_bill == 'always') {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // if($auto_bill == '')
 | 
				
			||||||
 | 
					        // off / optin / optout will reset the status of this field to off to allow
 | 
				
			||||||
 | 
					        // the client to choose whether to auto_bill or not.
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Quote Ninja (https://paymentninja.com).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @link https://github.com/paymentninja/paymentninja source repository
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @license https://www.elastic.co/licensing/elastic-license
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Http\Requests\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Http\Requests\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UploadRecurringQuoteRequest extends Request
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Determine if the user is authorized to make this request.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function authorize() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return auth()->user()->can('edit', $this->recurring_quote);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function rules()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	$rules = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if($this->input('documents'))
 | 
				
			||||||
 | 
					            $rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	return $rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Quote Ninja (https://invoiceninja.com).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @copyright Copyright (c) 2021. Quote Ninja LLC (https://invoiceninja.com)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @license https://www.elastic.co/licensing/elastic-license
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Http\ValidationRules\Recurring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Validation\Rule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class UniqueRecurringQuoteNumberRule.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class UniqueRecurringQuoteNumberRule implements Rule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public $input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct($input)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->input = $input;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param string $attribute
 | 
				
			||||||
 | 
					     * @param mixed $value
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function passes($attribute, $value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->checkIfQuoteNumberUnique(); //if it exists, return false!
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function message()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ctrans('texts.recurring_quote_number_taken', ['number' => $this->input['number']]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function checkIfQuoteNumberUnique() : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (empty($this->input['number'])) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $invoice = RecurringQuote::where('client_id', $this->input['client_id'])
 | 
				
			||||||
 | 
					                        ->where('number', $this->input['number'])
 | 
				
			||||||
 | 
					                        ->withTrashed()
 | 
				
			||||||
 | 
					                        ->exists();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($invoice) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -59,6 +59,7 @@ use App\Models\PaymentTerm;
 | 
				
			|||||||
use App\Models\Product;
 | 
					use App\Models\Product;
 | 
				
			||||||
use App\Models\Project;
 | 
					use App\Models\Project;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
use App\Models\Task;
 | 
					use App\Models\Task;
 | 
				
			||||||
use App\Models\TaskStatus;
 | 
					use App\Models\TaskStatus;
 | 
				
			||||||
@ -132,13 +133,14 @@ class Import implements ShouldQueue
 | 
				
			|||||||
        'projects',
 | 
					        'projects',
 | 
				
			||||||
        'products',
 | 
					        'products',
 | 
				
			||||||
        'credits',
 | 
					        'credits',
 | 
				
			||||||
        'invoices',
 | 
					 | 
				
			||||||
        'recurring_invoices',
 | 
					        'recurring_invoices',
 | 
				
			||||||
 | 
					        'invoices',
 | 
				
			||||||
        'quotes',
 | 
					        'quotes',
 | 
				
			||||||
        'payments',
 | 
					        'payments',
 | 
				
			||||||
        'expense_categories',
 | 
					        'expense_categories',
 | 
				
			||||||
        'task_statuses',
 | 
					        'task_statuses',
 | 
				
			||||||
        'expenses',
 | 
					        'expenses',
 | 
				
			||||||
 | 
					        'recurring_expenses',
 | 
				
			||||||
        'tasks',
 | 
					        'tasks',
 | 
				
			||||||
        'documents',
 | 
					        'documents',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
@ -812,6 +814,68 @@ class Import implements ShouldQueue
 | 
				
			|||||||
        $product_repository = null;
 | 
					        $product_repository = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function processRecurringExpenses(array $data) :void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RecurringExpense::unguard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $rules = [
 | 
				
			||||||
 | 
					            '*.amount' => ['numeric'],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $validator = Validator::make($data, $rules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($validator->fails()) {
 | 
				
			||||||
 | 
					            throw new MigrationValidatorFailed(json_encode($validator->errors()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($data as $resource) {
 | 
				
			||||||
 | 
					            $modified = $resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            unset($modified['id']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $modified['company_id'] = $this->company->id;
 | 
				
			||||||
 | 
					            $modified['user_id'] = $this->processUserId($resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (isset($resource['client_id'])) {
 | 
				
			||||||
 | 
					                $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (isset($resource['category_id'])) {
 | 
				
			||||||
 | 
					                $modified['category_id'] = $this->transformId('expense_categories', $resource['category_id']);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (isset($resource['vendor_id'])) {
 | 
				
			||||||
 | 
					                $modified['vendor_id'] = $this->transformId('vendors', $resource['vendor_id']);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $expense = RecurringExpense::create($modified);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(array_key_exists('created_at', $modified))
 | 
				
			||||||
 | 
					                $expense->created_at = Carbon::parse($modified['created_at']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(array_key_exists('updated_at', $modified))
 | 
				
			||||||
 | 
					                $expense->updated_at = Carbon::parse($modified['updated_at']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $expense->save(['timestamps' => false]);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $key = "recurring_expenses_{$resource['id']}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->ids['recurring_expenses'][$key] = [
 | 
				
			||||||
 | 
					                'old' => $resource['id'],
 | 
				
			||||||
 | 
					                'new' => $expense->id,
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        RecurringExpense::reguard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*Improve memory handling by setting everything to null when we have finished*/
 | 
				
			||||||
 | 
					        $data = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function processRecurringInvoices(array $data) :void
 | 
					    private function processRecurringInvoices(array $data) :void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        RecurringInvoice::unguard();
 | 
					        RecurringInvoice::unguard();
 | 
				
			||||||
@ -908,6 +972,10 @@ class Import implements ShouldQueue
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
 | 
					            $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(array_key_exists('recurring_id', $resource) && !is_null($resource['recurring_id']))
 | 
				
			||||||
 | 
					                $modified['recurring_id'] = $this->transformId('recurring_invoices', (string)$resource['recurring_id']);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            $modified['user_id'] = $this->processUserId($resource);
 | 
					            $modified['user_id'] = $this->processUserId($resource);
 | 
				
			||||||
            $modified['company_id'] = $this->company->id;
 | 
					            $modified['company_id'] = $this->company->id;
 | 
				
			||||||
            $modified['line_items'] = $this->cleanItems($modified['line_items']);
 | 
					            $modified['line_items'] = $this->cleanItems($modified['line_items']);
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CreatedRecurringExpenseActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_expense = $event->recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_expense->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->recurring_expense_id = $recurring_expense->id;
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $recurring_expense->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::CREATE_RECURRING_EXPENSE;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $recurring_expense, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseArchivedActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_expense = $event->recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_expense->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->recurring_expense_id = $recurring_expense->id;
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $recurring_expense->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::ARCHIVE_RECURRING_EXPENSE;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $recurring_expense, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseDeletedActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_expense->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->recurring_expense_id = $event->recurring_expense->id;
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_expense->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::DELETE_RECURRING_EXPENSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_expense, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseRestoredActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_expense->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->recurring_expense_id = $event->recurring_expense->id;
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_expense->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::RESTORE_RECURRING_EXPENSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_expense, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringExpense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseUpdatedActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_expense = $event->recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_expense->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->recurring_expense_id = $recurring_expense->id;
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $recurring_expense->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::UPDATE_RECURRING_EXPENSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $recurring_expense, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CreateRecurringQuoteActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_quote->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->recurring_quote_id = $event->recurring_quote->id;
 | 
				
			||||||
 | 
					        $fields->client_id = $event->recurring_quote->client_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::CREATE_RECURRING_QUOTE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_quote, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteArchivedActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $event->recurring_quote->service()->deletePdf();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_quote->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->recurring_quote_id = $event->recurring_quote->id;
 | 
				
			||||||
 | 
					        $fields->client_id = $event->recurring_quote->client_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::ARCHIVE_RECURRING_QUOTE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_quote, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteDeletedActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_quote->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->recurring_quote_id = $event->recurring_quote->id;
 | 
				
			||||||
 | 
					        $fields->client_id = $event->recurring_quote->client_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::DELETE_RECURRING_QUOTE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_quote, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteRestoredActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDb($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_quote->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->recurring_quote_id = $event->recurring_quote->id;
 | 
				
			||||||
 | 
					        $fields->client_id = $event->recurring_quote->client_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::RESTORE_RECURRING_QUOTE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_quote, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					<?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\Listeners\RecurringQuote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Libraries\MultiDB;
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Repositories\ActivityRepository;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Queue\ShouldQueue;
 | 
				
			||||||
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UpdateRecurringQuoteActivity implements ShouldQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $activity_repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create the event listener.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ActivityRepository $activity_repo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(ActivityRepository $activity_repo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->activity_repo = $activity_repo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle the event.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  object  $event
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function handle($event)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MultiDB::setDB($event->company->db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields = new stdClass;
 | 
				
			||||||
 | 
					        $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_quote->user_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $fields->user_id = $user_id;
 | 
				
			||||||
 | 
					        $fields->client_id = $event->recurring_quote->client_id;
 | 
				
			||||||
 | 
					        $fields->company_id = $event->recurring_quote->company_id;
 | 
				
			||||||
 | 
					        $fields->activity_type_id = Activity::UPDATE_RECURRING_QUOTE;
 | 
				
			||||||
 | 
					        $fields->recurring_quote_id = $event->recurring_quote->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->activity_repo->save($fields, $event->recurring_quote, $event->event_vars);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -96,6 +96,18 @@ class Activity extends StaticModel
 | 
				
			|||||||
    const DELETE_RECURRING_INVOICE = 103; 
 | 
					    const DELETE_RECURRING_INVOICE = 103; 
 | 
				
			||||||
    const RESTORE_RECURRING_INVOICE = 104; 
 | 
					    const RESTORE_RECURRING_INVOICE = 104; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const CREATE_RECURRING_QUOTE = 110;
 | 
				
			||||||
 | 
					    const UPDATE_RECURRING_QUOTE = 111; 
 | 
				
			||||||
 | 
					    const ARCHIVE_RECURRING_QUOTE = 112; 
 | 
				
			||||||
 | 
					    const DELETE_RECURRING_QUOTE = 113; 
 | 
				
			||||||
 | 
					    const RESTORE_RECURRING_QUOTE = 114; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const CREATE_RECURRING_EXPENSE = 120;
 | 
				
			||||||
 | 
					    const UPDATE_RECURRING_EXPENSE = 121; 
 | 
				
			||||||
 | 
					    const ARCHIVE_RECURRING_EXPENSE = 122; 
 | 
				
			||||||
 | 
					    const DELETE_RECURRING_EXPENSE = 123; 
 | 
				
			||||||
 | 
					    const RESTORE_RECURRING_EXPENSE = 124; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $casts = [
 | 
					    protected $casts = [
 | 
				
			||||||
        'is_system' => 'boolean',
 | 
					        'is_system' => 'boolean',
 | 
				
			||||||
        'updated_at' => 'timestamp',
 | 
					        'updated_at' => 'timestamp',
 | 
				
			||||||
 | 
				
			|||||||
@ -260,6 +260,14 @@ class Company extends BaseModel
 | 
				
			|||||||
        return $this->hasMany(RecurringInvoice::class)->withTrashed();
 | 
					        return $this->hasMany(RecurringInvoice::class)->withTrashed();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return HasMany
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function recurring_expenses()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->hasMany(RecurringExpense::class)->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @return HasMany
 | 
					     * @return HasMany
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								app/Models/Presenters/RecurringQuotePresenter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/Models/Presenters/RecurringQuotePresenter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					<?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\Models\Presenters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Utils\Number;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesDates;
 | 
				
			||||||
 | 
					use Laracasts\Presenter\PresentableTrait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class QuotePresenter.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For convenience and to allow users to easiliy
 | 
				
			||||||
 | 
					 * customise their invoices, we provide all possible
 | 
				
			||||||
 | 
					 * invoice variables to be available from this presenter.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Shortcuts to other presenters are here to facilitate
 | 
				
			||||||
 | 
					 * a clean UI / UX
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuotePresenter extends InvoicePresenter
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										117
									
								
								app/Models/RecurringExpense.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								app/Models/RecurringExpense.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					<?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\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Services\Recurring\RecurringService;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\SoftDeletes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpense extends BaseModel
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use SoftDeletes;
 | 
				
			||||||
 | 
					    use Filterable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $fillable = [
 | 
				
			||||||
 | 
					        'client_id',
 | 
				
			||||||
 | 
					        'assigned_user_id',
 | 
				
			||||||
 | 
					        'vendor_id',
 | 
				
			||||||
 | 
					        'invoice_id',
 | 
				
			||||||
 | 
					        'currency_id',
 | 
				
			||||||
 | 
					        'date',
 | 
				
			||||||
 | 
					        'invoice_currency_id',
 | 
				
			||||||
 | 
					        'amount',
 | 
				
			||||||
 | 
					        'foreign_amount',
 | 
				
			||||||
 | 
					        'exchange_rate',
 | 
				
			||||||
 | 
					        'private_notes',
 | 
				
			||||||
 | 
					        'public_notes',
 | 
				
			||||||
 | 
					        'bank_id',
 | 
				
			||||||
 | 
					        'transaction_id',
 | 
				
			||||||
 | 
					        'category_id',
 | 
				
			||||||
 | 
					        'tax_rate1',
 | 
				
			||||||
 | 
					        'tax_name1',
 | 
				
			||||||
 | 
					        'tax_rate2',
 | 
				
			||||||
 | 
					        'tax_name2',
 | 
				
			||||||
 | 
					        'tax_rate3',
 | 
				
			||||||
 | 
					        'tax_name3',
 | 
				
			||||||
 | 
					        'payment_date',
 | 
				
			||||||
 | 
					        'payment_type_id',
 | 
				
			||||||
 | 
					        'project_id',
 | 
				
			||||||
 | 
					        'transaction_reference',
 | 
				
			||||||
 | 
					        'invoice_documents',
 | 
				
			||||||
 | 
					        'should_be_invoiced',
 | 
				
			||||||
 | 
					        'custom_value1',
 | 
				
			||||||
 | 
					        'custom_value2',
 | 
				
			||||||
 | 
					        'custom_value3',
 | 
				
			||||||
 | 
					        'custom_value4',
 | 
				
			||||||
 | 
					        'number',
 | 
				
			||||||
 | 
					        'tax_amount1',
 | 
				
			||||||
 | 
					        'tax_amount2',
 | 
				
			||||||
 | 
					        'tax_amount3',
 | 
				
			||||||
 | 
					        'uses_inclusive_taxes',
 | 
				
			||||||
 | 
					        'calculate_tax_by_amount',
 | 
				
			||||||
 | 
					        'frequency_id',
 | 
				
			||||||
 | 
					        'last_sent_date',
 | 
				
			||||||
 | 
					        'next_send_date',
 | 
				
			||||||
 | 
					        'remaining_cycles',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $casts = [
 | 
				
			||||||
 | 
					        'is_deleted' => 'boolean',
 | 
				
			||||||
 | 
					        'updated_at' => 'timestamp',
 | 
				
			||||||
 | 
					        'created_at' => 'timestamp',
 | 
				
			||||||
 | 
					        'deleted_at' => 'timestamp',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $touches = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getEntityType()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return self::class;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function documents()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->morphMany(Document::class, 'documentable');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function user()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(User::class)->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function assigned_user()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(User::class, 'assigned_user_id', 'id');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function company()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(Company::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function vendor()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(Vendor::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function client()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(Client::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Service entry points.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function service() :RecurringService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new RecurringService($this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -11,56 +11,73 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\Models;
 | 
					namespace App\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Helpers\Invoice\InvoiceSum;
 | 
				
			||||||
 | 
					use App\Helpers\Invoice\InvoiceSumInclusive;
 | 
				
			||||||
 | 
					use App\Models\Presenters\RecurringQuotePresenter;
 | 
				
			||||||
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuoteInvitation;
 | 
				
			||||||
 | 
					use App\Services\Recurring\RecurringService;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesDates;
 | 
				
			||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use App\Utils\Traits\Recurring\HasRecurrence;
 | 
				
			||||||
use Illuminate\Database\Eloquent\SoftDeletes;
 | 
					use Illuminate\Database\Eloquent\SoftDeletes;
 | 
				
			||||||
use Illuminate\Support\Carbon;
 | 
					use Illuminate\Support\Carbon;
 | 
				
			||||||
 | 
					use Laracasts\Presenter\PresentableTrait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Class for Recurring Invoices.
 | 
					 * Class for Recurring Quotes.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class RecurringQuote extends BaseModel
 | 
					class RecurringQuote extends BaseModel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use MakesHash;
 | 
					    use MakesHash;
 | 
				
			||||||
    use SoftDeletes;
 | 
					    use SoftDeletes;
 | 
				
			||||||
    use Filterable;
 | 
					    use Filterable;
 | 
				
			||||||
 | 
					    use MakesDates;
 | 
				
			||||||
 | 
					    use HasRecurrence;
 | 
				
			||||||
 | 
					    use PresentableTrait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $presenter = RecurringQuotePresenter::class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Invoice Statuses.
 | 
					     * Quote Statuses.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    const STATUS_DRAFT = 2;
 | 
					    const STATUS_DRAFT = 1;
 | 
				
			||||||
    const STATUS_ACTIVE = 3;
 | 
					    const STATUS_ACTIVE = 2;
 | 
				
			||||||
 | 
					    const STATUS_PAUSED = 3;
 | 
				
			||||||
 | 
					    const STATUS_COMPLETED = 4;
 | 
				
			||||||
    const STATUS_PENDING = -1;
 | 
					    const STATUS_PENDING = -1;
 | 
				
			||||||
    const STATUS_COMPLETED = -2;
 | 
					 | 
				
			||||||
    const STATUS_CANCELLED = -3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Recurring intervals.
 | 
					     * Quote Frequencies.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    const FREQUENCY_WEEKLY = 1;
 | 
					    const FREQUENCY_DAILY = 1;
 | 
				
			||||||
    const FREQUENCY_TWO_WEEKS = 2;
 | 
					    const FREQUENCY_WEEKLY = 2;
 | 
				
			||||||
    const FREQUENCY_FOUR_WEEKS = 3;
 | 
					    const FREQUENCY_TWO_WEEKS = 3;
 | 
				
			||||||
    const FREQUENCY_MONTHLY = 4;
 | 
					    const FREQUENCY_FOUR_WEEKS = 4;
 | 
				
			||||||
    const FREQUENCY_TWO_MONTHS = 5;
 | 
					    const FREQUENCY_MONTHLY = 5;
 | 
				
			||||||
    const FREQUENCY_THREE_MONTHS = 6;
 | 
					    const FREQUENCY_TWO_MONTHS = 6;
 | 
				
			||||||
    const FREQUENCY_FOUR_MONTHS = 7;
 | 
					    const FREQUENCY_THREE_MONTHS = 7;
 | 
				
			||||||
    const FREQUENCY_SIX_MONTHS = 8;
 | 
					    const FREQUENCY_FOUR_MONTHS = 8;
 | 
				
			||||||
    const FREQUENCY_ANNUALLY = 9;
 | 
					    const FREQUENCY_SIX_MONTHS = 9;
 | 
				
			||||||
    const FREQUENCY_TWO_YEARS = 10;
 | 
					    const FREQUENCY_ANNUALLY = 10;
 | 
				
			||||||
 | 
					    const FREQUENCY_TWO_YEARS = 11;
 | 
				
			||||||
 | 
					    const FREQUENCY_THREE_YEARS = 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const RECURS_INDEFINITELY = -1;
 | 
					    const RECURS_INDEFINITELY = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $fillable = [
 | 
					    protected $fillable = [
 | 
				
			||||||
        'client_id',
 | 
					        'client_id',
 | 
				
			||||||
        'quote_number',
 | 
					        'project_id',
 | 
				
			||||||
 | 
					        'number',
 | 
				
			||||||
        'discount',
 | 
					        'discount',
 | 
				
			||||||
        'is_amount_discount',
 | 
					        'is_amount_discount',
 | 
				
			||||||
        'po_number',
 | 
					        'po_number',
 | 
				
			||||||
        'quote_date',
 | 
					        'date',
 | 
				
			||||||
        'valid_until',
 | 
					        'due_date',
 | 
				
			||||||
 | 
					        'due_date_days',
 | 
				
			||||||
        'line_items',
 | 
					        'line_items',
 | 
				
			||||||
        'settings',
 | 
					 | 
				
			||||||
        'footer',
 | 
					        'footer',
 | 
				
			||||||
        'public_note',
 | 
					        'public_notes',
 | 
				
			||||||
        'private_notes',
 | 
					        'private_notes',
 | 
				
			||||||
        'terms',
 | 
					        'terms',
 | 
				
			||||||
        'tax_name1',
 | 
					        'tax_name1',
 | 
				
			||||||
@ -74,26 +91,42 @@ class RecurringQuote extends BaseModel
 | 
				
			|||||||
        'custom_value3',
 | 
					        'custom_value3',
 | 
				
			||||||
        'custom_value4',
 | 
					        'custom_value4',
 | 
				
			||||||
        'amount',
 | 
					        'amount',
 | 
				
			||||||
 | 
					        'partial',
 | 
				
			||||||
        'frequency_id',
 | 
					        'frequency_id',
 | 
				
			||||||
        'due_date_days',
 | 
					        'next_send_date',
 | 
				
			||||||
 | 
					        'remaining_cycles',
 | 
				
			||||||
 | 
					        'auto_bill',
 | 
				
			||||||
 | 
					        'auto_bill_enabled',
 | 
				
			||||||
 | 
					        'design_id',
 | 
				
			||||||
 | 
					        'custom_surcharge1',
 | 
				
			||||||
 | 
					        'custom_surcharge2',
 | 
				
			||||||
 | 
					        'custom_surcharge3',
 | 
				
			||||||
 | 
					        'custom_surcharge4',
 | 
				
			||||||
 | 
					        'custom_surcharge_tax1',
 | 
				
			||||||
 | 
					        'custom_surcharge_tax2',
 | 
				
			||||||
 | 
					        'custom_surcharge_tax3',
 | 
				
			||||||
 | 
					        'custom_surcharge_tax4',
 | 
				
			||||||
 | 
					        'design_id',
 | 
				
			||||||
 | 
					        'assigned_user_id',
 | 
				
			||||||
 | 
					        'exchange_rate',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $touches = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected $casts = [
 | 
					    protected $casts = [
 | 
				
			||||||
 | 
					        'settings' => 'object',
 | 
				
			||||||
        'line_items' => 'object',
 | 
					        'line_items' => 'object',
 | 
				
			||||||
        'backup' => 'object',
 | 
					        'backup' => 'object',
 | 
				
			||||||
        'settings' => 'object',
 | 
					 | 
				
			||||||
        'updated_at' => 'timestamp',
 | 
					        'updated_at' => 'timestamp',
 | 
				
			||||||
        'created_at' => 'timestamp',
 | 
					        'created_at' => 'timestamp',
 | 
				
			||||||
        'deleted_at' => 'timestamp',
 | 
					        'deleted_at' => 'timestamp',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $with = [
 | 
					    protected $appends = [
 | 
				
			||||||
   //     'client',
 | 
					        'hashed_id',
 | 
				
			||||||
   //     'company',
 | 
					        'status',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $touches = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getEntityType()
 | 
					    public function getEntityType()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return self::class;
 | 
					        return self::class;
 | 
				
			||||||
@ -126,6 +159,16 @@ class RecurringQuote extends BaseModel
 | 
				
			|||||||
        return $value;
 | 
					        return $value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function activities()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->hasMany(Activity::class)->orderBy('id', 'DESC')->take(50);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function history()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->hasManyThrough(Backup::class, Activity::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function company()
 | 
					    public function company()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->belongsTo(Company::class);
 | 
					        return $this->belongsTo(Company::class);
 | 
				
			||||||
@ -136,6 +179,11 @@ class RecurringQuote extends BaseModel
 | 
				
			|||||||
        return $this->belongsTo(Client::class)->withTrashed();
 | 
					        return $this->belongsTo(Client::class)->withTrashed();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function project()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(Project::class)->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function user()
 | 
					    public function user()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->belongsTo(User::class)->withTrashed();
 | 
					        return $this->belongsTo(User::class)->withTrashed();
 | 
				
			||||||
@ -146,8 +194,299 @@ class RecurringQuote extends BaseModel
 | 
				
			|||||||
        return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed();
 | 
					        return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function quotes()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->hasMany(Quote::class, 'recurring_id', 'id')->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function invitations()
 | 
					    public function invitations()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->morphMany(RecurringQuoteInvitation::class);
 | 
					        return $this->hasMany(RecurringQuoteInvitation::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function documents()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->morphMany(Document::class, 'documentable');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getStatusAttribute()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->status_id == self::STATUS_ACTIVE && Carbon::parse($this->next_send_date)->isFuture()) {
 | 
				
			||||||
 | 
					            return self::STATUS_PENDING;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return $this->status_id;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function nextSendDate() :?Carbon
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!$this->next_send_date) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        $offset = $this->client->timezone_offset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* 
 | 
				
			||||||
 | 
					        As we are firing at UTC+0 if our offset is negative it is technically firing the day before so we always need
 | 
				
			||||||
 | 
					        to add ON a day - a day = 86400 seconds
 | 
				
			||||||
 | 
					        */
 | 
				
			||||||
 | 
					        if($offset < 0)
 | 
				
			||||||
 | 
					            $offset += 86400;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch ($this->frequency_id) {
 | 
				
			||||||
 | 
					            case self::FREQUENCY_DAILY:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addDay()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_WEEKLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addWeek()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_WEEKS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addWeeks(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_WEEKS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addWeeks(4)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_MONTHLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_THREE_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(4)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_SIX_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(6)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_ANNUALLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addYear()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_YEARS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addYears(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_THREE_YEARS:
 | 
				
			||||||
 | 
					                return Carbon::parse($this->next_send_date)->startOfDay()->addYears(3)->addSeconds($offset);
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function nextDateByFrequency($date)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $offset = $this->client->timezone_offset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch ($this->frequency_id) {
 | 
				
			||||||
 | 
					            case self::FREQUENCY_DAILY:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addDay()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_WEEKLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addWeek()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_WEEKS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addWeeks(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_WEEKS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addWeeks(4)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_MONTHLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_THREE_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(4)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_SIX_MONTHS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->addMonthsNoOverflow(6)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_ANNUALLY:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addYear()->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_YEARS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addYears(2)->addSeconds($offset);
 | 
				
			||||||
 | 
					            case self::FREQUENCY_THREE_YEARS:
 | 
				
			||||||
 | 
					                return Carbon::parse($date)->startOfDay()->addYears(3)->addSeconds($offset);
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function remainingCycles() : int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->remaining_cycles == 0) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        } elseif ($this->remaining_cycles == -1) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return $this->remaining_cycles - 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCompleted() :  void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->status_id = self::STATUS_COMPLETED;
 | 
				
			||||||
 | 
					        $this->next_send_date = null;
 | 
				
			||||||
 | 
					        $this->remaining_cycles = 0;
 | 
				
			||||||
 | 
					        $this->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static function badgeForStatus(int $status)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch ($status) {
 | 
				
			||||||
 | 
					            case self::STATUS_DRAFT:
 | 
				
			||||||
 | 
					                return '<h4><span class="badge badge-light">'.ctrans('texts.draft').'</span></h4>';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::STATUS_PENDING:
 | 
				
			||||||
 | 
					                return '<h4><span class="badge badge-primary">'.ctrans('texts.pending').'</span></h4>';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::STATUS_ACTIVE:
 | 
				
			||||||
 | 
					                return '<h4><span class="badge badge-primary">'.ctrans('texts.active').'</span></h4>';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::STATUS_COMPLETED:
 | 
				
			||||||
 | 
					                return '<h4><span class="badge badge-success">'.ctrans('texts.status_completed').'</span></h4>';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::STATUS_PAUSED:
 | 
				
			||||||
 | 
					                return '<h4><span class="badge badge-danger">'.ctrans('texts.paused').'</span></h4>';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                // code...
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static function frequencyForKey(int $frequency_id) :string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch ($frequency_id) {
 | 
				
			||||||
 | 
					            case self::FREQUENCY_DAILY:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_daily');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_WEEKLY:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_weekly');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_WEEKS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_two_weeks');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_WEEKS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_four_weeks');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_MONTHLY:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_monthly');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_MONTHS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_two_months');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_THREE_MONTHS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_three_months');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_FOUR_MONTHS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_four_months');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_SIX_MONTHS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_six_months');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_ANNUALLY:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_annually');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case self::FREQUENCY_TWO_YEARS:
 | 
				
			||||||
 | 
					                return ctrans('texts.freq_two_years');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                // code...
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function calc()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $invoice_calc = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->uses_inclusive_taxes) {
 | 
				
			||||||
 | 
					            $invoice_calc = new InvoiceSumInclusive($this);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $invoice_calc = new InvoiceSum($this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $invoice_calc->build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Important to note when playing with carbon dates - in order
 | 
				
			||||||
 | 
					     * not to modify the original instance, always use a `->copy()`
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function recurringDates()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Return early if nothing to send back! */
 | 
				
			||||||
 | 
					        if ($this->status_id == self::STATUS_COMPLETED ||
 | 
				
			||||||
 | 
					            $this->remaining_cycles == 0 ||
 | 
				
			||||||
 | 
					            !$this->next_send_date) {
 | 
				
			||||||
 | 
					            return [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Endless - lets send 10 back*/
 | 
				
			||||||
 | 
					        $iterations = $this->remaining_cycles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->remaining_cycles == -1) {
 | 
				
			||||||
 | 
					            $iterations = 10;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $data = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!Carbon::parse($this->next_send_date)) {
 | 
				
			||||||
 | 
					            return $data;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $next_send_date = Carbon::parse($this->next_send_date)->copy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for ($x=0; $x<$iterations; $x++) {
 | 
				
			||||||
 | 
					            // we don't add the days... we calc the day of the month!!
 | 
				
			||||||
 | 
					            $next_due_date = $this->calculateDueDate($next_send_date->copy()->format('Y-m-d'));
 | 
				
			||||||
 | 
					            $next_due_date_string = $next_due_date ? $next_due_date->format('Y-m-d') : '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $next_send_date = Carbon::parse($next_send_date);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $data[] = [
 | 
				
			||||||
 | 
					                'send_date' => $next_send_date->format('Y-m-d'),
 | 
				
			||||||
 | 
					                'due_date' => $next_due_date_string
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Fixes the timeshift in case the offset is negative which cause a infinite loop due to UTC +0*/
 | 
				
			||||||
 | 
					            if($this->client->timezone_offset() < 0){
 | 
				
			||||||
 | 
					                $next_send_date = $this->nextDateByFrequency($next_send_date->addDay()->format('Y-m-d'));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                $next_send_date = $this->nextDateByFrequency($next_send_date->format('Y-m-d'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function calculateDueDate($date)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch ($this->due_date_days) {
 | 
				
			||||||
 | 
					            case 'terms':
 | 
				
			||||||
 | 
					                return $this->calculateDateFromTerms($date);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return $this->setDayOfMonth($date, $this->due_date_days);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Calculates a date based on the client payment terms.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  Carbon $date A given date
 | 
				
			||||||
 | 
					     * @return NULL|Carbon  The date
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function calculateDateFromTerms($date)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $new_date = Carbon::parse($date);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $client_payment_terms = $this->client->getSetting('payment_terms');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($client_payment_terms == '') {//no due date! return null;
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $new_date->addDays($client_payment_terms); //add the number of days in the payment terms to the date
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Service entry points.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function service() :RecurringService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new RecurringService($this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										88
									
								
								app/Models/RecurringQuoteInvitation.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								app/Models/RecurringQuoteInvitation.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Invoice Ninja (https://quoteninja.com).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @link https://github.com/quoteninja/quoteninja source repository
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://quoteninja.com)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @license https://www.elastic.co/licensing/elastic-license
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Utils\Traits\Inviteable;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesDates;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Relations\BelongsTo;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\SoftDeletes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteInvitation extends BaseModel
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesDates;
 | 
				
			||||||
 | 
					    use SoftDeletes;
 | 
				
			||||||
 | 
					    use Inviteable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $fillable = ['client_contact_id'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $touches = ['recurring_quote'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $with = [
 | 
				
			||||||
 | 
					        'company',
 | 
				
			||||||
 | 
					        'contact',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getEntityType()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return self::class;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function entityType()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return RecurringQuote::class;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function recurring_quote()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(RecurringQuote::class)->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function contact()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(ClientContact::class, 'client_contact_id', 'id')->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function user()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(User::class)->withTrashed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return BelongsTo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function company()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->belongsTo(Company::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function markViewed()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->viewed_date = now();
 | 
				
			||||||
 | 
					        $this->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function markOpened()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->opened_date = now();
 | 
				
			||||||
 | 
					        $this->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								app/Policies/RecurringExpensePolicy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/Policies/RecurringExpensePolicy.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					<?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\Policies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class RecurringExpensePolicy.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpensePolicy extends EntityPolicy
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *  Checks if the user has create permissions.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  User $user
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function create(User $user) : bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $user->isAdmin() || $user->hasPermission('create_recurring_expense') || $user->hasPermission('create_all');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,7 +12,6 @@
 | 
				
			|||||||
namespace App\Providers;
 | 
					namespace App\Providers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Models\Activity;
 | 
					use App\Models\Activity;
 | 
				
			||||||
use App\Models\Subscription;
 | 
					 | 
				
			||||||
use App\Models\Client;
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Company;
 | 
					use App\Models\Company;
 | 
				
			||||||
use App\Models\CompanyGateway;
 | 
					use App\Models\CompanyGateway;
 | 
				
			||||||
@ -29,8 +28,10 @@ use App\Models\PaymentTerm;
 | 
				
			|||||||
use App\Models\Product;
 | 
					use App\Models\Product;
 | 
				
			||||||
use App\Models\Project;
 | 
					use App\Models\Project;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Models\Subscription;
 | 
				
			||||||
use App\Models\Task;
 | 
					use App\Models\Task;
 | 
				
			||||||
use App\Models\TaskStatus;
 | 
					use App\Models\TaskStatus;
 | 
				
			||||||
use App\Models\TaxRate;
 | 
					use App\Models\TaxRate;
 | 
				
			||||||
@ -38,7 +39,6 @@ use App\Models\User;
 | 
				
			|||||||
use App\Models\Vendor;
 | 
					use App\Models\Vendor;
 | 
				
			||||||
use App\Models\Webhook;
 | 
					use App\Models\Webhook;
 | 
				
			||||||
use App\Policies\ActivityPolicy;
 | 
					use App\Policies\ActivityPolicy;
 | 
				
			||||||
use App\Policies\SubscriptionPolicy;
 | 
					 | 
				
			||||||
use App\Policies\ClientPolicy;
 | 
					use App\Policies\ClientPolicy;
 | 
				
			||||||
use App\Policies\CompanyGatewayPolicy;
 | 
					use App\Policies\CompanyGatewayPolicy;
 | 
				
			||||||
use App\Policies\CompanyPolicy;
 | 
					use App\Policies\CompanyPolicy;
 | 
				
			||||||
@ -55,8 +55,10 @@ use App\Policies\PaymentTermPolicy;
 | 
				
			|||||||
use App\Policies\ProductPolicy;
 | 
					use App\Policies\ProductPolicy;
 | 
				
			||||||
use App\Policies\ProjectPolicy;
 | 
					use App\Policies\ProjectPolicy;
 | 
				
			||||||
use App\Policies\QuotePolicy;
 | 
					use App\Policies\QuotePolicy;
 | 
				
			||||||
 | 
					use App\Policies\RecurringExpensePolicy;
 | 
				
			||||||
use App\Policies\RecurringInvoicePolicy;
 | 
					use App\Policies\RecurringInvoicePolicy;
 | 
				
			||||||
use App\Policies\RecurringQuotePolicy;
 | 
					use App\Policies\RecurringQuotePolicy;
 | 
				
			||||||
 | 
					use App\Policies\SubscriptionPolicy;
 | 
				
			||||||
use App\Policies\TaskPolicy;
 | 
					use App\Policies\TaskPolicy;
 | 
				
			||||||
use App\Policies\TaskStatusPolicy;
 | 
					use App\Policies\TaskStatusPolicy;
 | 
				
			||||||
use App\Policies\TaxRatePolicy;
 | 
					use App\Policies\TaxRatePolicy;
 | 
				
			||||||
@ -92,6 +94,7 @@ class AuthServiceProvider extends ServiceProvider
 | 
				
			|||||||
        Product::class => ProductPolicy::class,
 | 
					        Product::class => ProductPolicy::class,
 | 
				
			||||||
        Project::class => ProjectPolicy::class,
 | 
					        Project::class => ProjectPolicy::class,
 | 
				
			||||||
        Quote::class => QuotePolicy::class,
 | 
					        Quote::class => QuotePolicy::class,
 | 
				
			||||||
 | 
					        RecurringExpense::class => RecurringExpensePolicy::class,
 | 
				
			||||||
        RecurringInvoice::class => RecurringInvoicePolicy::class,
 | 
					        RecurringInvoice::class => RecurringInvoicePolicy::class,
 | 
				
			||||||
        RecurringQuote::class => RecurringQuotePolicy::class,
 | 
					        RecurringQuote::class => RecurringQuotePolicy::class,
 | 
				
			||||||
        Webhook::class => WebhookPolicy::class,
 | 
					        Webhook::class => WebhookPolicy::class,
 | 
				
			||||||
 | 
				
			|||||||
@ -68,11 +68,21 @@ use App\Events\Quote\QuoteWasEmailed;
 | 
				
			|||||||
use App\Events\Quote\QuoteWasRestored;
 | 
					use App\Events\Quote\QuoteWasRestored;
 | 
				
			||||||
use App\Events\Quote\QuoteWasUpdated;
 | 
					use App\Events\Quote\QuoteWasUpdated;
 | 
				
			||||||
use App\Events\Quote\QuoteWasViewed;
 | 
					use App\Events\Quote\QuoteWasViewed;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasArchived;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasCreated;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasDeleted;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasRestored;
 | 
				
			||||||
 | 
					use App\Events\RecurringExpense\RecurringExpenseWasUpdated;
 | 
				
			||||||
use App\Events\RecurringInvoice\RecurringInvoiceWasArchived;
 | 
					use App\Events\RecurringInvoice\RecurringInvoiceWasArchived;
 | 
				
			||||||
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
 | 
					use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
 | 
				
			||||||
use App\Events\RecurringInvoice\RecurringInvoiceWasDeleted;
 | 
					use App\Events\RecurringInvoice\RecurringInvoiceWasDeleted;
 | 
				
			||||||
use App\Events\RecurringInvoice\RecurringInvoiceWasRestored;
 | 
					use App\Events\RecurringInvoice\RecurringInvoiceWasRestored;
 | 
				
			||||||
use App\Events\RecurringInvoice\RecurringInvoiceWasUpdated;
 | 
					use App\Events\RecurringInvoice\RecurringInvoiceWasUpdated;
 | 
				
			||||||
 | 
					use App\Events\RecurringQuote\RecurringQuoteWasArchived;
 | 
				
			||||||
 | 
					use App\Events\RecurringQuote\RecurringQuoteWasCreated;
 | 
				
			||||||
 | 
					use App\Events\RecurringQuote\RecurringQuoteWasDeleted;
 | 
				
			||||||
 | 
					use App\Events\RecurringQuote\RecurringQuoteWasRestored;
 | 
				
			||||||
 | 
					use App\Events\RecurringQuote\RecurringQuoteWasUpdated;
 | 
				
			||||||
use App\Events\Subscription\SubscriptionWasArchived;
 | 
					use App\Events\Subscription\SubscriptionWasArchived;
 | 
				
			||||||
use App\Events\Subscription\SubscriptionWasCreated;
 | 
					use App\Events\Subscription\SubscriptionWasCreated;
 | 
				
			||||||
use App\Events\Subscription\SubscriptionWasDeleted;
 | 
					use App\Events\Subscription\SubscriptionWasDeleted;
 | 
				
			||||||
@ -170,11 +180,21 @@ use App\Listeners\Quote\QuoteEmailedNotification;
 | 
				
			|||||||
use App\Listeners\Quote\QuoteRestoredActivity;
 | 
					use App\Listeners\Quote\QuoteRestoredActivity;
 | 
				
			||||||
use App\Listeners\Quote\QuoteViewedActivity;
 | 
					use App\Listeners\Quote\QuoteViewedActivity;
 | 
				
			||||||
use App\Listeners\Quote\ReachWorkflowSettings;
 | 
					use App\Listeners\Quote\ReachWorkflowSettings;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringExpense\CreatedRecurringExpenseActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringExpense\RecurringExpenseArchivedActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringExpense\RecurringExpenseDeletedActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringExpense\RecurringExpenseRestoredActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringExpense\RecurringExpenseUpdatedActivity;
 | 
				
			||||||
use App\Listeners\RecurringInvoice\CreateRecurringInvoiceActivity;
 | 
					use App\Listeners\RecurringInvoice\CreateRecurringInvoiceActivity;
 | 
				
			||||||
use App\Listeners\RecurringInvoice\RecurringInvoiceArchivedActivity;
 | 
					use App\Listeners\RecurringInvoice\RecurringInvoiceArchivedActivity;
 | 
				
			||||||
use App\Listeners\RecurringInvoice\RecurringInvoiceDeletedActivity;
 | 
					use App\Listeners\RecurringInvoice\RecurringInvoiceDeletedActivity;
 | 
				
			||||||
use App\Listeners\RecurringInvoice\RecurringInvoiceRestoredActivity;
 | 
					use App\Listeners\RecurringInvoice\RecurringInvoiceRestoredActivity;
 | 
				
			||||||
use App\Listeners\RecurringInvoice\UpdateRecurringInvoiceActivity;
 | 
					use App\Listeners\RecurringInvoice\UpdateRecurringInvoiceActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringQuote\CreateRecurringQuoteActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringQuote\RecurringQuoteArchivedActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringQuote\RecurringQuoteDeletedActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringQuote\RecurringQuoteRestoredActivity;
 | 
				
			||||||
 | 
					use App\Listeners\RecurringQuote\UpdateRecurringQuoteActivity;
 | 
				
			||||||
use App\Listeners\SendVerificationNotification;
 | 
					use App\Listeners\SendVerificationNotification;
 | 
				
			||||||
use App\Listeners\User\ArchivedUserActivity;
 | 
					use App\Listeners\User\ArchivedUserActivity;
 | 
				
			||||||
use App\Listeners\User\CreatedUserActivity;
 | 
					use App\Listeners\User\CreatedUserActivity;
 | 
				
			||||||
@ -412,6 +432,36 @@ class EventServiceProvider extends ServiceProvider
 | 
				
			|||||||
        QuoteWasRestored::class => [
 | 
					        QuoteWasRestored::class => [
 | 
				
			||||||
            QuoteRestoredActivity::class,
 | 
					            QuoteRestoredActivity::class,
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringExpenseWasCreated::class => [
 | 
				
			||||||
 | 
					            CreatedRecurringExpenseActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringExpenseWasUpdated::class => [
 | 
				
			||||||
 | 
					            RecurringExpenseUpdatedActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringExpenseWasArchived::class => [
 | 
				
			||||||
 | 
					            RecurringExpenseArchivedActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringExpenseWasDeleted::class => [
 | 
				
			||||||
 | 
					            RecurringExpenseDeletedActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringExpenseWasRestored::class => [
 | 
				
			||||||
 | 
					            RecurringExpenseRestoredActivity::class
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringQuoteWasUpdated::class => [
 | 
				
			||||||
 | 
					            UpdateRecurringQuoteActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringQuoteWasCreated::class => [
 | 
				
			||||||
 | 
					            CreateRecurringQuoteActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringQuoteWasDeleted::class => [
 | 
				
			||||||
 | 
					            RecurringQuoteDeletedActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringQuoteWasArchived::class => [
 | 
				
			||||||
 | 
					            RecurringQuoteArchivedActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        RecurringQuoteWasRestored::class => [
 | 
				
			||||||
 | 
					            RecurringQuoteRestoredActivity::class,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
        RecurringInvoiceWasUpdated::class => [
 | 
					        RecurringInvoiceWasUpdated::class => [
 | 
				
			||||||
            UpdateRecurringInvoiceActivity::class,
 | 
					            UpdateRecurringInvoiceActivity::class,
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								app/Repositories/RecurringExpenseRepository.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/Repositories/RecurringExpenseRepository.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					<?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\Repositories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Factory\RecurringExpenseFactory;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Utils\Traits\GeneratesCounter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * RecurringExpenseRepository.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseRepository extends BaseRepository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use GeneratesCounter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Saves the recurring_expense and its contacts.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param      array  $data    The data
 | 
				
			||||||
 | 
					     * @param      \App\Models\RecurringExpense              $recurring_expense  The recurring_expense
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return     \App\Models\RecurringExpense|Null  recurring_expense Object
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function save(array $data, RecurringExpense $recurring_expense) : ?RecurringExpense
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_expense->fill($data);
 | 
				
			||||||
 | 
					        $recurring_expense->number = empty($recurring_expense->number) ? $this->getNextRecurringExpenseNumber($recurring_expense) : $recurring_expense->number;
 | 
				
			||||||
 | 
					        $recurring_expense->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (array_key_exists('documents', $data)) {
 | 
				
			||||||
 | 
					            $this->saveDocuments($data['documents'], $recurring_expense);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $recurring_expense;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Store recurring_expenses in bulk.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param array $recurring_expense
 | 
				
			||||||
 | 
					     * @return \App\Models\RecurringExpense|null
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function create($recurring_expense): ?RecurringExpense
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->save(
 | 
				
			||||||
 | 
					            $recurring_expense,
 | 
				
			||||||
 | 
					            RecurringExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -13,7 +13,6 @@ namespace App\Transformers;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use App\Models\Account;
 | 
					use App\Models\Account;
 | 
				
			||||||
use App\Models\Activity;
 | 
					use App\Models\Activity;
 | 
				
			||||||
use App\Models\Subscription;
 | 
					 | 
				
			||||||
use App\Models\Client;
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Company;
 | 
					use App\Models\Company;
 | 
				
			||||||
use App\Models\CompanyGateway;
 | 
					use App\Models\CompanyGateway;
 | 
				
			||||||
@ -31,13 +30,16 @@ use App\Models\PaymentTerm;
 | 
				
			|||||||
use App\Models\Product;
 | 
					use App\Models\Product;
 | 
				
			||||||
use App\Models\Project;
 | 
					use App\Models\Project;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\Models\Subscription;
 | 
				
			||||||
use App\Models\SystemLog;
 | 
					use App\Models\SystemLog;
 | 
				
			||||||
use App\Models\Task;
 | 
					use App\Models\Task;
 | 
				
			||||||
use App\Models\TaskStatus;
 | 
					use App\Models\TaskStatus;
 | 
				
			||||||
use App\Models\TaxRate;
 | 
					use App\Models\TaxRate;
 | 
				
			||||||
use App\Models\User;
 | 
					use App\Models\User;
 | 
				
			||||||
use App\Models\Webhook;
 | 
					use App\Models\Webhook;
 | 
				
			||||||
 | 
					use App\Transformers\RecurringExpenseTransformer;
 | 
				
			||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
use stdClass;
 | 
					use stdClass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -92,6 +94,7 @@ class CompanyTransformer extends EntityTransformer
 | 
				
			|||||||
        'expense_categories',
 | 
					        'expense_categories',
 | 
				
			||||||
        'task_statuses',
 | 
					        'task_statuses',
 | 
				
			||||||
        'subscriptions',
 | 
					        'subscriptions',
 | 
				
			||||||
 | 
					        'recurring_expenses',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -296,6 +299,13 @@ class CompanyTransformer extends EntityTransformer
 | 
				
			|||||||
        return $this->includeCollection($company->recurring_invoices, $transformer, RecurringInvoice::class);
 | 
					        return $this->includeCollection($company->recurring_invoices, $transformer, RecurringInvoice::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function includeRecurringExpenses(Company $company)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $transformer = new RecurringExpenseTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->includeCollection($company->recurring_expenses, $transformer, RecurringExpense::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function includeQuotes(Company $company)
 | 
					    public function includeQuotes(Company $company)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $transformer = new QuoteTransformer($this->serializer);
 | 
					        $transformer = new QuoteTransformer($this->serializer);
 | 
				
			||||||
 | 
				
			|||||||
@ -94,6 +94,7 @@ class ExpenseTransformer extends EntityTransformer
 | 
				
			|||||||
            'tax_amount3' => (float) $expense->tax_amount3,
 | 
					            'tax_amount3' => (float) $expense->tax_amount3,
 | 
				
			||||||
            'uses_inclusive_taxes' => (bool) $expense->uses_inclusive_taxes,
 | 
					            'uses_inclusive_taxes' => (bool) $expense->uses_inclusive_taxes,
 | 
				
			||||||
            'calculate_tax_by_amount' => (bool) $expense->calculate_tax_by_amount,
 | 
					            'calculate_tax_by_amount' => (bool) $expense->calculate_tax_by_amount,
 | 
				
			||||||
 | 
					            'entity_type' => 'expense',
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										106
									
								
								app/Transformers/RecurringExpenseTransformer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								app/Transformers/RecurringExpenseTransformer.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					<?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\Transformers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Document;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\SoftDeletes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * class RecurringExpenseTransformer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseTransformer extends EntityTransformer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					    use SoftDeletes;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    protected $defaultIncludes = [
 | 
				
			||||||
 | 
					        'documents',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected $availableIncludes = [
 | 
				
			||||||
 | 
					        'documents',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function includeDocuments(RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $transformer = new DocumentTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->includeCollection($recurring_expense->documents, $transformer, Document::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param RecurringExpense $recurring_expense
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function transform(RecurringExpense $recurring_expense)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'id' => $this->encodePrimaryKey($recurring_expense->id),
 | 
				
			||||||
 | 
					            'user_id' => $this->encodePrimaryKey($recurring_expense->user_id),
 | 
				
			||||||
 | 
					            'assigned_user_id' => $this->encodePrimaryKey($recurring_expense->assigned_user_id),
 | 
				
			||||||
 | 
					            'status_id' => (string) ($recurring_expense->status_id ?: 1),
 | 
				
			||||||
 | 
					            'vendor_id' => $this->encodePrimaryKey($recurring_expense->vendor_id),
 | 
				
			||||||
 | 
					            'invoice_id' => $this->encodePrimaryKey($recurring_expense->invoice_id),
 | 
				
			||||||
 | 
					            'client_id' => $this->encodePrimaryKey($recurring_expense->client_id),
 | 
				
			||||||
 | 
					            'bank_id' => (string) $recurring_expense->bank_id ?: '',
 | 
				
			||||||
 | 
					            'invoice_currency_id' => (string) $recurring_expense->invoice_currency_id ?: '',
 | 
				
			||||||
 | 
					            'recurring_expense_currency_id' => '', //todo remove redundant in 5.0.25
 | 
				
			||||||
 | 
					            'currency_id' => (string) $recurring_expense->currency_id ?: '',
 | 
				
			||||||
 | 
					            'category_id' => $this->encodePrimaryKey($recurring_expense->category_id),
 | 
				
			||||||
 | 
					            'payment_type_id' => (string) $recurring_expense->payment_type_id ?: '',
 | 
				
			||||||
 | 
					            'recurring_recurring_expense_id' => (string) $recurring_expense->recurring_recurring_expense_id ?: '',
 | 
				
			||||||
 | 
					            'is_deleted' => (bool) $recurring_expense->is_deleted,
 | 
				
			||||||
 | 
					            'should_be_invoiced' => (bool) $recurring_expense->should_be_invoiced,
 | 
				
			||||||
 | 
					            'invoice_documents' => (bool) $recurring_expense->invoice_documents,
 | 
				
			||||||
 | 
					            'amount' => (float) $recurring_expense->amount ?: 0,
 | 
				
			||||||
 | 
					            'foreign_amount' => (float) $recurring_expense->foreign_amount ?: 0,
 | 
				
			||||||
 | 
					            'exchange_rate' => (float) $recurring_expense->exchange_rate ?: 0,
 | 
				
			||||||
 | 
					            'tax_name1' => $recurring_expense->tax_name1 ? $recurring_expense->tax_name1 : '',
 | 
				
			||||||
 | 
					            'tax_rate1' => (float) $recurring_expense->tax_rate1,
 | 
				
			||||||
 | 
					            'tax_name2' => $recurring_expense->tax_name2 ? $recurring_expense->tax_name2 : '',
 | 
				
			||||||
 | 
					            'tax_rate2' => (float) $recurring_expense->tax_rate2,
 | 
				
			||||||
 | 
					            'tax_name3' => $recurring_expense->tax_name3 ? $recurring_expense->tax_name3 : '',
 | 
				
			||||||
 | 
					            'tax_rate3' => (float) $recurring_expense->tax_rate3,
 | 
				
			||||||
 | 
					            'private_notes' => (string) $recurring_expense->private_notes ?: '',
 | 
				
			||||||
 | 
					            'public_notes' => (string) $recurring_expense->public_notes ?: '',
 | 
				
			||||||
 | 
					            'transaction_reference' => (string) $recurring_expense->transaction_reference ?: '',
 | 
				
			||||||
 | 
					            'transaction_id' => (string) $recurring_expense->transaction_id ?: '',
 | 
				
			||||||
 | 
					            'date' => $recurring_expense->date ?: '',
 | 
				
			||||||
 | 
					            'number' => (string)$recurring_expense->number ?: '',
 | 
				
			||||||
 | 
					            'payment_date' => $recurring_expense->payment_date ?: '',
 | 
				
			||||||
 | 
					            'custom_value1' => $recurring_expense->custom_value1 ?: '',
 | 
				
			||||||
 | 
					            'custom_value2' => $recurring_expense->custom_value2 ?: '',
 | 
				
			||||||
 | 
					            'custom_value3' => $recurring_expense->custom_value3 ?: '',
 | 
				
			||||||
 | 
					            'custom_value4' => $recurring_expense->custom_value4 ?: '',
 | 
				
			||||||
 | 
					            'updated_at' => (int) $recurring_expense->updated_at,
 | 
				
			||||||
 | 
					            'archived_at' => (int) $recurring_expense->deleted_at,
 | 
				
			||||||
 | 
					            'created_at' => (int) $recurring_expense->created_at,
 | 
				
			||||||
 | 
					            'project_id' => $this->encodePrimaryKey($recurring_expense->project_id),
 | 
				
			||||||
 | 
					            'tax_amount1' => (float) $recurring_expense->tax_amount1,
 | 
				
			||||||
 | 
					            'tax_amount2' => (float) $recurring_expense->tax_amount2,
 | 
				
			||||||
 | 
					            'tax_amount3' => (float) $recurring_expense->tax_amount3,
 | 
				
			||||||
 | 
					            'uses_inclusive_taxes' => (bool) $recurring_expense->uses_inclusive_taxes,
 | 
				
			||||||
 | 
					            'calculate_tax_by_amount' => (bool) $recurring_expense->calculate_tax_by_amount,
 | 
				
			||||||
 | 
					            'entity_type' => 'recurringExpense',
 | 
				
			||||||
 | 
					            'frequency_id' => (string) $recurring_expense->frequency_id,
 | 
				
			||||||
 | 
					            'remaining_cycles' => (int) $recurring_expense->remaining_cycles,
 | 
				
			||||||
 | 
					            'last_sent_date' => $recurring_expense->last_sent_date ?: '',
 | 
				
			||||||
 | 
					            'next_send_date' => $recurring_expense->next_send_date ?: '',
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -34,36 +34,6 @@ class RecurringInvoiceTransformer extends EntityTransformer
 | 
				
			|||||||
        'activities',
 | 
					        'activities',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
        public function includeInvoiceItems(Invoice $invoice)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new InvoiceItemTransformer($this->serializer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEM);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public function includeInvitations(Invoice $invoice)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new InvitationTransformer($this->account, $this->serializer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeCollection($invoice->invitations, $transformer, ENTITY_INVITATION);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public function includePayments(Invoice $invoice)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new PaymentTransformer($this->account, $this->serializer, $invoice);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeCollection($invoice->payments, $transformer, ENTITY_PAYMENT);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public function includeClient(Invoice $invoice)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new ClientTransformer($this->account, $this->serializer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeItem($invoice->client, $transformer, ENTITY_CLIENT);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
   
 | 
					 | 
				
			||||||
    public function includeHistory(RecurringInvoice $invoice)
 | 
					    public function includeHistory(RecurringInvoice $invoice)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $transformer = new InvoiceHistoryTransformer($this->serializer);
 | 
					        $transformer = new InvoiceHistoryTransformer($this->serializer);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								app/Transformers/RecurringQuoteInvitationTransformer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app/Transformers/RecurringQuoteInvitationTransformer.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					<?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\Transformers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringQuoteInvitation;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringQuoteInvitationTransformer extends EntityTransformer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function transform(RecurringQuoteInvitation $invitation)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'id' => $this->encodePrimaryKey($invitation->id),
 | 
				
			||||||
 | 
					            'client_contact_id' => $this->encodePrimaryKey($invitation->client_contact_id),
 | 
				
			||||||
 | 
					            'key' => $invitation->key,
 | 
				
			||||||
 | 
					            'link' => $invitation->getLink() ?: '',
 | 
				
			||||||
 | 
					            'sent_date' => $invitation->sent_date ?: '',
 | 
				
			||||||
 | 
					            'viewed_date' => $invitation->viewed_date ?: '',
 | 
				
			||||||
 | 
					            'opened_date' => $invitation->opened_date ?: '',
 | 
				
			||||||
 | 
					            'updated_at'        => (int) $invitation->updated_at,
 | 
				
			||||||
 | 
					            'archived_at'       => (int) $invitation->deleted_at,
 | 
				
			||||||
 | 
					            'created_at'       => (int) $invitation->created_at,
 | 
				
			||||||
 | 
					            'email_status'      => $invitation->email_status ?: '',
 | 
				
			||||||
 | 
					            'email_error'       => (string)$invitation->email_error,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -11,7 +11,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\Transformers;
 | 
					namespace App\Transformers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Activity;
 | 
				
			||||||
 | 
					use App\Models\Backup;
 | 
				
			||||||
 | 
					use App\Models\Document;
 | 
				
			||||||
 | 
					use App\Models\Quote;
 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuoteInvitation;
 | 
				
			||||||
 | 
					use App\Transformers\ActivityTransformer;
 | 
				
			||||||
 | 
					use App\Transformers\QuoteHistoryTransformer;
 | 
				
			||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RecurringQuoteTransformer extends EntityTransformer
 | 
					class RecurringQuoteTransformer extends EntityTransformer
 | 
				
			||||||
@ -19,107 +26,110 @@ class RecurringQuoteTransformer extends EntityTransformer
 | 
				
			|||||||
    use MakesHash;
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $defaultIncludes = [
 | 
					    protected $defaultIncludes = [
 | 
				
			||||||
    //    'invoice_items',
 | 
					        'invitations',
 | 
				
			||||||
 | 
					        'documents',
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $availableIncludes = [
 | 
					    protected $availableIncludes = [
 | 
				
			||||||
    //    'invitations',
 | 
					        'invitations',
 | 
				
			||||||
    //    'payments',
 | 
					        'documents',
 | 
				
			||||||
 | 
					        'activities',
 | 
				
			||||||
 | 
					        // 'history',
 | 
				
			||||||
    //    'client',
 | 
					    //    'client',
 | 
				
			||||||
    //    'documents',
 | 
					 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
    /*
 | 
					    public function includeHistory(RecurringQuote $quote)
 | 
				
			||||||
        public function includeInvoiceItems(Invoice $quote)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            $transformer = new InvoiceItemTransformer($this->serializer);
 | 
					        $transformer = new QuoteHistoryTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this->includeCollection($quote->invoice_items, $transformer, ENTITY_INVOICE_ITEM);
 | 
					        return $this->includeCollection($quote->history, $transformer, Backup::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
       
 | 
					       
 | 
				
			||||||
        public function includeInvitations(Invoice $quote)
 | 
					    public function includeActivities(RecurringQuote $quote)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            $transformer = new InvitationTransformer($this->account, $this->serializer);
 | 
					        $transformer = new ActivityTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this->includeCollection($quote->invitations, $transformer, ENTITY_INVITATION);
 | 
					        return $this->includeCollection($quote->activities, $transformer, Activity::class);
 | 
				
			||||||
    }   
 | 
					    }   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public function includePayments(Invoice $quote)
 | 
					    public function includeInvitations(RecurringQuote $quote)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            $transformer = new PaymentTransformer($this->account, $this->serializer, $quote);
 | 
					        $transformer = new RecurringQuoteInvitationTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this->includeCollection($quote->payments, $transformer, ENTITY_PAYMENT);
 | 
					        return $this->includeCollection($quote->invitations, $transformer, RecurringQuoteInvitation::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public function includeClient(Invoice $quote)
 | 
					    public function includeDocuments(RecurringQuote $quote)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
            $transformer = new ClientTransformer($this->account, $this->serializer);
 | 
					        $transformer = new DocumentTransformer($this->serializer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this->includeItem($quote->client, $transformer, ENTITY_CLIENT);
 | 
					        return $this->includeCollection($quote->documents, $transformer, Document::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        public function includeExpenses(Invoice $quote)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new ExpenseTransformer($this->account, $this->serializer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeCollection($quote->expenses, $transformer, ENTITY_EXPENSE);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public function includeDocuments(Invoice $quote)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $transformer = new DocumentTransformer($this->account, $this->serializer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            $quote->documents->each(function ($document) use ($quote) {
 | 
					 | 
				
			||||||
                $document->setRelation('invoice', $quote);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $this->includeCollection($quote->documents, $transformer, ENTITY_DOCUMENT);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    public function transform(RecurringQuote $quote)
 | 
					    public function transform(RecurringQuote $quote)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
            'id' => $this->encodePrimaryKey($quote->id),
 | 
					            'id' => $this->encodePrimaryKey($quote->id),
 | 
				
			||||||
            'user_id' => $this->encodePrimaryKey($quote->user_id),
 | 
					            'user_id' => $this->encodePrimaryKey($quote->user_id),
 | 
				
			||||||
 | 
					            'project_id' => $this->encodePrimaryKey($quote->project_id),
 | 
				
			||||||
            'assigned_user_id' => $this->encodePrimaryKey($quote->assigned_user_id),
 | 
					            'assigned_user_id' => $this->encodePrimaryKey($quote->assigned_user_id),
 | 
				
			||||||
            'amount' => (float) $quote->amount ?: '',
 | 
					            'amount' => (float) $quote->amount,
 | 
				
			||||||
            'balance' => (float) $quote->balance ?: '',
 | 
					            'balance' => (float) $quote->balance,
 | 
				
			||||||
            'client_id' => (string) $quote->client_id,
 | 
					            'client_id' => (string) $this->encodePrimaryKey($quote->client_id),
 | 
				
			||||||
 | 
					            'vendor_id' => (string) $this->encodePrimaryKey($quote->vendor_id),
 | 
				
			||||||
            'status_id' => (string) ($quote->status_id ?: 1),
 | 
					            'status_id' => (string) ($quote->status_id ?: 1),
 | 
				
			||||||
 | 
					            'design_id' => (string) $this->encodePrimaryKey($quote->design_id),
 | 
				
			||||||
            'created_at' => (int) $quote->created_at,
 | 
					            'created_at' => (int) $quote->created_at,
 | 
				
			||||||
            'updated_at' => (int) $quote->updated_at,
 | 
					            'updated_at' => (int) $quote->updated_at,
 | 
				
			||||||
            'archived_at' => (int) $quote->deleted_at,
 | 
					            'archived_at' => (int) $quote->deleted_at,
 | 
				
			||||||
            'discount' => (float) $quote->discount ?: '',
 | 
					            'is_deleted' => (bool) $quote->is_deleted,
 | 
				
			||||||
 | 
					            'number' => $quote->number ?: '',
 | 
				
			||||||
 | 
					            'discount' => (float) $quote->discount,
 | 
				
			||||||
            'po_number' => $quote->po_number ?: '',
 | 
					            'po_number' => $quote->po_number ?: '',
 | 
				
			||||||
            'quote_date' => $quote->quote_date ?: '',
 | 
					            'date' => $quote->date ?: '',
 | 
				
			||||||
            'valid_until' => $quote->valid_until ?: '',
 | 
					            'last_sent_date' => $quote->last_sent_date ?: '',
 | 
				
			||||||
 | 
					            'next_send_date' => $quote->next_send_date ?: '',
 | 
				
			||||||
 | 
					            'due_date' => $quote->due_date ?: '',
 | 
				
			||||||
            'terms' => $quote->terms ?: '',
 | 
					            'terms' => $quote->terms ?: '',
 | 
				
			||||||
            'public_notes' => $quote->public_notes ?: '',
 | 
					            'public_notes' => $quote->public_notes ?: '',
 | 
				
			||||||
            'private_notes' => $quote->private_notes ?: '',
 | 
					            'private_notes' => $quote->private_notes ?: '',
 | 
				
			||||||
            'is_deleted' => (bool) $quote->is_deleted,
 | 
					            'uses_inclusive_taxes' => (bool) $quote->uses_inclusive_taxes,
 | 
				
			||||||
            'tax_name1' => $quote->tax_name1 ? $quote->tax_name1 : '',
 | 
					            'tax_name1' => $quote->tax_name1 ? $quote->tax_name1 : '',
 | 
				
			||||||
            'tax_rate1' => (float) $quote->tax_rate1 ?: '',
 | 
					            'tax_rate1' => (float) $quote->tax_rate1,
 | 
				
			||||||
            'tax_name2' => $quote->tax_name2 ? $quote->tax_name2 : '',
 | 
					            'tax_name2' => $quote->tax_name2 ? $quote->tax_name2 : '',
 | 
				
			||||||
            'tax_rate2' => (float) $quote->tax_rate2 ?: '',
 | 
					            'tax_rate2' => (float) $quote->tax_rate2,
 | 
				
			||||||
            'tax_name3' => $quote->tax_name3 ? $quote->tax_name3 : '',
 | 
					            'tax_name3' => $quote->tax_name3 ? $quote->tax_name3 : '',
 | 
				
			||||||
            'tax_rate3' => (float) $quote->tax_rate3 ?: '',
 | 
					            'tax_rate3' => (float) $quote->tax_rate3,
 | 
				
			||||||
 | 
					            'total_taxes' => (float) $quote->total_taxes,
 | 
				
			||||||
            'is_amount_discount' => (bool) ($quote->is_amount_discount ?: false),
 | 
					            'is_amount_discount' => (bool) ($quote->is_amount_discount ?: false),
 | 
				
			||||||
            'quote_footer' => $quote->quote_footer ?: '',
 | 
					            'footer' => $quote->footer ?: '',
 | 
				
			||||||
            'partial' => (float) ($quote->partial ?: 0.0),
 | 
					            'partial' => (float) ($quote->partial ?: 0.0),
 | 
				
			||||||
            'partial_due_date' => $quote->partial_due_date ?: '',
 | 
					            'partial_due_date' => $quote->partial_due_date ?: '',
 | 
				
			||||||
            'custom_value1' => (float) $quote->custom_value1 ?: '',
 | 
					            'custom_value1' => (string) $quote->custom_value1 ?: '',
 | 
				
			||||||
            'custom_value2' => (float) $quote->custom_value2 ?: '',
 | 
					            'custom_value2' => (string) $quote->custom_value2 ?: '',
 | 
				
			||||||
            'custom_taxes1' => (bool) $quote->custom_taxes1 ?: '',
 | 
					            'custom_value3' => (string) $quote->custom_value3 ?: '',
 | 
				
			||||||
            'custom_taxes2' => (bool) $quote->custom_taxes2 ?: '',
 | 
					            'custom_value4' => (string) $quote->custom_value4 ?: '',
 | 
				
			||||||
            'has_tasks' => (bool) $quote->has_tasks,
 | 
					            'has_tasks' => (bool) $quote->has_tasks,
 | 
				
			||||||
            'has_expenses' => (bool) $quote->has_expenses,
 | 
					            'has_expenses' => (bool) $quote->has_expenses,
 | 
				
			||||||
            'custom_text_value1' => $quote->custom_text_value1 ?: '',
 | 
					            'custom_surcharge1' => (float) $quote->custom_surcharge1,
 | 
				
			||||||
            'custom_text_value2' => $quote->custom_text_value2 ?: '',
 | 
					            'custom_surcharge2' => (float) $quote->custom_surcharge2,
 | 
				
			||||||
            'settings' => $quote->settings ?: '',
 | 
					            'custom_surcharge3' => (float) $quote->custom_surcharge3,
 | 
				
			||||||
            'frequency_id' => (int) $quote->frequency_id,
 | 
					            'custom_surcharge4' => (float) $quote->custom_surcharge4,
 | 
				
			||||||
            'last_sent_date' => $quote->last_sent_date ?: '',
 | 
					            'exchange_rate' => (float) $quote->exchange_rate,
 | 
				
			||||||
            'next_send_date' => $quote->next_send_date ?: '',
 | 
					            'custom_surcharge_tax1' => (bool) $quote->custom_surcharge_tax1,
 | 
				
			||||||
 | 
					            'custom_surcharge_tax2' => (bool) $quote->custom_surcharge_tax2,
 | 
				
			||||||
 | 
					            'custom_surcharge_tax3' => (bool) $quote->custom_surcharge_tax3,
 | 
				
			||||||
 | 
					            'custom_surcharge_tax4' => (bool) $quote->custom_surcharge_tax4,
 | 
				
			||||||
 | 
					            'line_items' => $quote->line_items ?: (array) [],
 | 
				
			||||||
 | 
					            'entity_type' => 'recurringQuote',
 | 
				
			||||||
 | 
					            'frequency_id' => (string) $quote->frequency_id,
 | 
				
			||||||
            'remaining_cycles' => (int) $quote->remaining_cycles,
 | 
					            'remaining_cycles' => (int) $quote->remaining_cycles,
 | 
				
			||||||
 | 
					            'recurring_dates' => (array) $quote->recurringDates(),
 | 
				
			||||||
 | 
					            'auto_bill' => (string) $quote->auto_bill,
 | 
				
			||||||
 | 
					            'auto_bill_enabled' => (bool) $quote->auto_bill_enabled,
 | 
				
			||||||
 | 
					            'due_date_days' => (string) $quote->due_date_days ?: '',
 | 
				
			||||||
 | 
					            'paid_to_date' => (float) $quote->paid_to_date,
 | 
				
			||||||
 | 
					            'subscription_id' => (string)$this->encodePrimaryKey($quote->subscription_id),
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,9 @@ use App\Models\Invoice;
 | 
				
			|||||||
use App\Models\Payment;
 | 
					use App\Models\Payment;
 | 
				
			||||||
use App\Models\Project;
 | 
					use App\Models\Project;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
use App\Models\Task;
 | 
					use App\Models\Task;
 | 
				
			||||||
use App\Models\Timezone;
 | 
					use App\Models\Timezone;
 | 
				
			||||||
use App\Models\Vendor;
 | 
					use App\Models\Vendor;
 | 
				
			||||||
@ -135,6 +137,12 @@ trait GeneratesCounter
 | 
				
			|||||||
            case RecurringInvoice::class:
 | 
					            case RecurringInvoice::class:
 | 
				
			||||||
                return 'recurring_invoice_number_counter';
 | 
					                return 'recurring_invoice_number_counter';
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            case RecurringQuote::class:
 | 
				
			||||||
 | 
					                return 'recurring_quote_number_counter';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case RecurringExpense::class:
 | 
				
			||||||
 | 
					                return 'recurring_expense_number_counter';
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            case Payment::class:
 | 
					            case Payment::class:
 | 
				
			||||||
                return 'payment_number_counter';
 | 
					                return 'payment_number_counter';
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -196,6 +204,11 @@ trait GeneratesCounter
 | 
				
			|||||||
        return $this->getNextEntityNumber(RecurringInvoice::class, $client);
 | 
					        return $this->getNextEntityNumber(RecurringInvoice::class, $client);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getNextRecurringQuoteNumber(Client $client)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->getNextEntityNumber(RecurringQuote::class, $client);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the next Payment number.
 | 
					     * Gets the next Payment number.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -312,6 +325,27 @@ trait GeneratesCounter
 | 
				
			|||||||
        return $expense_number;
 | 
					        return $expense_number;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the next expense number.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param   RecurringExpense       $expense    The expense
 | 
				
			||||||
 | 
					     * @return  string                 The next expense number.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getNextRecurringExpenseNumber(RecurringExpense $expense) :string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->resetCompanyCounters($expense->company);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $counter = $expense->company->settings->recurring_expense_number_counter;
 | 
				
			||||||
 | 
					        $setting_entity = $expense->company->settings->recurring_expense_number_counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $expense_number = $this->checkEntityNumber(RecurringExpense::class, $expense, $counter, $expense->company->settings->counter_padding, $expense->company->settings->recurring_expense_number_pattern);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->incrementCounter($expense->company, 'recurring_expense_number_counter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $expense_number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Determines if it has shared counter.
 | 
					     * Determines if it has shared counter.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								database/factories/RecurringExpenseFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								database/factories/RecurringExpenseFactory.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					<?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 Database\Factories;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Factories\Factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpenseFactory extends Factory
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The name of the factory's corresponding model.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @var string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected $model = RecurringExpense::class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Define the model's default state.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function definition()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'amount' => $this->faker->numberBetween(1, 10),
 | 
				
			||||||
 | 
					            'custom_value1' => $this->faker->text(10),
 | 
				
			||||||
 | 
					            'custom_value2' => $this->faker->text(10),
 | 
				
			||||||
 | 
					            'custom_value3' => $this->faker->text(10),
 | 
				
			||||||
 | 
					            'custom_value4' => $this->faker->text(10),
 | 
				
			||||||
 | 
					            'exchange_rate' => $this->faker->randomFloat(2, 0, 1),
 | 
				
			||||||
 | 
					            'date' => $this->faker->date(),
 | 
				
			||||||
 | 
					            'is_deleted' => false,
 | 
				
			||||||
 | 
					            'public_notes' => $this->faker->text(50),
 | 
				
			||||||
 | 
					            'private_notes' => $this->faker->text(50),
 | 
				
			||||||
 | 
					            'transaction_reference' => $this->faker->text(5),
 | 
				
			||||||
 | 
					            'invoice_id' => null,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -50,7 +50,6 @@ class RecurringQuoteFactory extends Factory
 | 
				
			|||||||
                'due_date' => $this->faker->date(),
 | 
					                'due_date' => $this->faker->date(),
 | 
				
			||||||
                'line_items' => false,
 | 
					                'line_items' => false,
 | 
				
			||||||
                'frequency_id' => RecurringQuote::FREQUENCY_MONTHLY,
 | 
					                'frequency_id' => RecurringQuote::FREQUENCY_MONTHLY,
 | 
				
			||||||
                'start_date' => $this->faker->date(),
 | 
					 | 
				
			||||||
                'last_sent_date' => $this->faker->date(),
 | 
					                'last_sent_date' => $this->faker->date(),
 | 
				
			||||||
                'next_send_date' => $this->faker->date(),
 | 
					                'next_send_date' => $this->faker->date(),
 | 
				
			||||||
                'remaining_cycles' => $this->faker->numberBetween(1, 10),
 | 
					                'remaining_cycles' => $this->faker->numberBetween(1, 10),
 | 
				
			||||||
 | 
				
			|||||||
@ -25,8 +25,5 @@ class AddSubscriptionIdToActivitiesTable extends Migration
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function down()
 | 
					    public function down()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Schema::table('activities', function (Blueprint $table) {
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,160 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Migrations\Migration;
 | 
				
			||||||
 | 
					use Illuminate\Database\Schema\Blueprint;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RecurringExpensesSchema extends Migration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Run the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function up()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::create('recurring_expenses', function ($table) {
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            $table->increments('id');
 | 
				
			||||||
 | 
					            $table->timestamps(6);
 | 
				
			||||||
 | 
					            $table->softDeletes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->unsignedInteger('company_id')->index();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('vendor_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('user_id');
 | 
				
			||||||
 | 
					            $table->unsignedInteger('status_id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->unsignedInteger('invoice_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('client_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('bank_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('project_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('payment_type_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('recurring_expense_id')->nullable();
 | 
				
			||||||
 | 
					            $table->boolean('is_deleted')->default(false);
 | 
				
			||||||
 | 
					            $table->boolean('uses_inclusive_taxes')->default(true);
 | 
				
			||||||
 | 
					            $table->string('tax_name1')->nullable();
 | 
				
			||||||
 | 
					            $table->string('tax_name2')->nullable();
 | 
				
			||||||
 | 
					            $table->string('tax_name3')->nullable();
 | 
				
			||||||
 | 
					            $table->date('date')->nullable();
 | 
				
			||||||
 | 
					            $table->date('payment_date')->nullable();
 | 
				
			||||||
 | 
					            $table->boolean('should_be_invoiced')->default(false);
 | 
				
			||||||
 | 
					            $table->boolean('invoice_documents')->default(false);
 | 
				
			||||||
 | 
					            $table->string('transaction_id')->nullable();
 | 
				
			||||||
 | 
					            $table->string('custom_value1')->nullable();
 | 
				
			||||||
 | 
					            $table->string('custom_value2')->nullable();
 | 
				
			||||||
 | 
					            $table->string('custom_value3')->nullable();
 | 
				
			||||||
 | 
					            $table->string('custom_value4')->nullable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->unsignedInteger('category_id')->nullable();
 | 
				
			||||||
 | 
					            $table->boolean('calculate_tax_by_amount')->default(false);
 | 
				
			||||||
 | 
					            $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();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('invoice_currency_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('currency_id')->nullable();
 | 
				
			||||||
 | 
					            $table->text('private_notes')->nullable();
 | 
				
			||||||
 | 
					            $table->text('public_notes')->nullable();
 | 
				
			||||||
 | 
					            $table->text('transaction_reference')->nullable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->unsignedInteger('frequency_id');
 | 
				
			||||||
 | 
					            $table->datetime('last_sent_date')->nullable();
 | 
				
			||||||
 | 
					            $table->datetime('next_send_date')->nullable();
 | 
				
			||||||
 | 
					            $table->integer('remaining_cycles')->nullable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $table->unique(['company_id', 'number']);
 | 
				
			||||||
 | 
					            $table->index(['company_id', 'deleted_at']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Relations
 | 
				
			||||||
 | 
					            $table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('activities', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->unsignedInteger('recurring_expense_id')->nullable();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('recurring_quote_id')->nullable();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('recurring_quotes', function ($table){
 | 
				
			||||||
 | 
					            $table->string('auto_bill')->default('off');
 | 
				
			||||||
 | 
					            $table->boolean('auto_bill_enabled')->default(0);
 | 
				
			||||||
 | 
					            $table->decimal('paid_to_date', 20, 6)->default(0);
 | 
				
			||||||
 | 
					            $table->decimal('custom_surcharge1', 20,6)->nullable();
 | 
				
			||||||
 | 
					            $table->decimal('custom_surcharge2', 20,6)->nullable();
 | 
				
			||||||
 | 
					            $table->decimal('custom_surcharge3', 20,6)->nullable();
 | 
				
			||||||
 | 
					            $table->decimal('custom_surcharge4', 20,6)->nullable();
 | 
				
			||||||
 | 
					            $table->boolean('custom_surcharge_tax1')->default(false);
 | 
				
			||||||
 | 
					            $table->boolean('custom_surcharge_tax2')->default(false);
 | 
				
			||||||
 | 
					            $table->boolean('custom_surcharge_tax3')->default(false);
 | 
				
			||||||
 | 
					            $table->boolean('custom_surcharge_tax4')->default(false);
 | 
				
			||||||
 | 
					            $table->string('due_date_days')->nullable();
 | 
				
			||||||
 | 
					            $table->decimal('exchange_rate', 13, 6)->default(1);
 | 
				
			||||||
 | 
					            $table->decimal('partial', 16, 4)->nullable();
 | 
				
			||||||
 | 
					            $table->date('partial_due_date')->nullable();                        
 | 
				
			||||||
 | 
					            $table->unsignedInteger('remaining_cycles')->nullable()->change();
 | 
				
			||||||
 | 
					            $table->unsignedInteger('subscription_id')->nullable();
 | 
				
			||||||
 | 
					            $table->dropColumn('start_date');
 | 
				
			||||||
 | 
					            $table->boolean('uses_inclusive_taxes')->default(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::create('recurring_quote_invitations', function ($t) {
 | 
				
			||||||
 | 
					            $t->increments('id');
 | 
				
			||||||
 | 
					            $t->unsignedInteger('company_id');
 | 
				
			||||||
 | 
					            $t->unsignedInteger('user_id');
 | 
				
			||||||
 | 
					            $t->unsignedInteger('client_contact_id');
 | 
				
			||||||
 | 
					            $t->unsignedInteger('recurring_quote_id')->index();
 | 
				
			||||||
 | 
					            $t->string('key')->index();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $t->foreign('recurring_quote_id')->references('id')->on('recurring_invoices')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					            $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					            $t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					            $t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $t->string('transaction_reference')->nullable();
 | 
				
			||||||
 | 
					            $t->string('message_id')->nullable();
 | 
				
			||||||
 | 
					            $t->mediumText('email_error')->nullable();
 | 
				
			||||||
 | 
					            $t->text('signature_base64')->nullable();
 | 
				
			||||||
 | 
					            $t->datetime('signature_date')->nullable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $t->datetime('sent_date')->nullable();
 | 
				
			||||||
 | 
					            $t->datetime('viewed_date')->nullable();
 | 
				
			||||||
 | 
					            $t->datetime('opened_date')->nullable();
 | 
				
			||||||
 | 
					            $t->enum('email_status', ['delivered', 'bounced', 'spam'])->nullable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $t->timestamps(6);
 | 
				
			||||||
 | 
					            $t->softDeletes('deleted_at', 6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $t->index(['deleted_at', 'recurring_quote_id', 'company_id'], 'rec_co_del_q');
 | 
				
			||||||
 | 
					            $t->unique(['client_contact_id', 'recurring_quote_id'], 'cli_rec_q');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reverse the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function down()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4297,6 +4297,7 @@ $LANG = array(
 | 
				
			|||||||
    'lang_Latvian' => 'Latvian',
 | 
					    'lang_Latvian' => 'Latvian',
 | 
				
			||||||
    'expiry_date' => 'Expiry date',
 | 
					    'expiry_date' => 'Expiry date',
 | 
				
			||||||
    'cardholder_name' => 'Card holder name',
 | 
					    'cardholder_name' => 'Card holder name',
 | 
				
			||||||
 | 
					    'recurring_quote_number_taken' => 'Recurring Quote number :number already taken',
 | 
				
			||||||
    'account_type' => 'Account type',
 | 
					    'account_type' => 'Account type',
 | 
				
			||||||
    'locality' => 'Locality',
 | 
					    'locality' => 'Locality',
 | 
				
			||||||
    'checking' => 'Checking',
 | 
					    'checking' => 'Checking',
 | 
				
			||||||
 | 
				
			|||||||
@ -132,12 +132,17 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
 | 
				
			|||||||
    Route::post('quotes/bulk', 'QuoteController@bulk')->name('quotes.bulk');
 | 
					    Route::post('quotes/bulk', 'QuoteController@bulk')->name('quotes.bulk');
 | 
				
			||||||
    Route::put('quotes/{quote}/upload', 'QuoteController@upload');
 | 
					    Route::put('quotes/{quote}/upload', 'QuoteController@upload');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Route::resource('recurring_expenses', 'RecurringExpenseController');
 | 
				
			||||||
 | 
					    Route::post('recurring_expenses/bulk', 'RecurringExpenseController@bulk')->name('recurring_expenses.bulk');
 | 
				
			||||||
 | 
					    Route::put('recurring_expenses/{recurring_expense}/upload', 'RecurringExpenseController@upload');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Route::resource('recurring_invoices', 'RecurringInvoiceController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
 | 
					    Route::resource('recurring_invoices', 'RecurringInvoiceController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
 | 
				
			||||||
    Route::post('recurring_invoices/bulk', 'RecurringInvoiceController@bulk')->name('recurring_invoices.bulk');
 | 
					    Route::post('recurring_invoices/bulk', 'RecurringInvoiceController@bulk')->name('recurring_invoices.bulk');
 | 
				
			||||||
    Route::put('recurring_invoices/{recurring_invoice}/upload', 'RecurringInvoiceController@upload');
 | 
					    Route::put('recurring_invoices/{recurring_invoice}/upload', 'RecurringInvoiceController@upload');
 | 
				
			||||||
    Route::resource('recurring_quotes', 'RecurringQuoteController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
 | 
					    Route::resource('recurring_quotes', 'RecurringQuoteController'); // name = (recurring_invoices. index / create / show / update / destroy / edit
 | 
				
			||||||
 | 
					 | 
				
			||||||
    Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
 | 
					    Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
 | 
				
			||||||
 | 
					    Route::put('recurring_quotes/{recurring_quote}/upload', 'RecurringQuoteController@upload');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Route::post('refresh', 'Auth\LoginController@refresh');
 | 
					    Route::post('refresh', 'Auth\LoginController@refresh');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										215
									
								
								tests/Feature/RecurringExpenseApiTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								tests/Feature/RecurringExpenseApiTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,215 @@
 | 
				
			|||||||
 | 
					<?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\Feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Session;
 | 
				
			||||||
 | 
					use Illuminate\Validation\ValidationException;
 | 
				
			||||||
 | 
					use Tests\MockAccountData;
 | 
				
			||||||
 | 
					use Tests\TestCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @test
 | 
				
			||||||
 | 
					 * @covers App\Http\Controllers\RecurringExpenseController
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringExpenseApiTest extends TestCase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					    use DatabaseTransactions;
 | 
				
			||||||
 | 
					    use MockAccountData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUp() :void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->makeTestData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Session::start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->faker = \Faker\Factory::create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Model::reguard();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseGet()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_expenses/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   public function testRecurringExpenseGetSingleExpense()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_expenses/'.$this->recurring_expense->hashed_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpensePost()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'amount' => 10,
 | 
				
			||||||
 | 
					            'client_id' => $this->client->hashed_id,
 | 
				
			||||||
 | 
					            'number' => '123321',
 | 
				
			||||||
 | 
					            'frequency_id' => 5,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					            'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					            'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					        ])->put('/api/v1/recurring_expenses/'.$arr['data']['id'], $data)->assertStatus(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					        ])->post('/api/v1/recurring_expenses', $data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch(ValidationException $e){
 | 
				
			||||||
 | 
					            $response->assertStatus(302);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpensePut()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'amount' => 20,
 | 
				
			||||||
 | 
					            'public_notes' => 'Coolio',
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->put('/api/v1/recurring_expenses/'.$this->encodePrimaryKey($this->recurring_expense->id), $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseNotArchived()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_expenses/'.$this->encodePrimaryKey($this->recurring_expense->id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals(0, $arr['data']['archived_at']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseArchived()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=archive', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertNotNull($arr['data'][0]['archived_at']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseRestored()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=restore', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals(0, $arr['data'][0]['archived_at']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseDeleted()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=delete', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertTrue($arr['data'][0]['is_deleted']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpenseStart()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=start', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					nlog($arr);
 | 
				
			||||||
 | 
					        $this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data'][0]['status_id']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringExpensePaused()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $data = [
 | 
				
			||||||
 | 
					            'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=start', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_expenses/bulk?action=stop', $data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					nlog($arr);
 | 
				
			||||||
 | 
					        $this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data'][0]['status_id']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										195
									
								
								tests/Feature/RecurringQuotesTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								tests/Feature/RecurringQuotesTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,195 @@
 | 
				
			|||||||
 | 
					<?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\Feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Factory\QuoteToRecurringQuoteFactory;
 | 
				
			||||||
 | 
					use App\Factory\RecurringQuoteToQuoteFactory;
 | 
				
			||||||
 | 
					use App\Models\Client;
 | 
				
			||||||
 | 
					use App\Models\ClientContact;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
				
			||||||
 | 
					use Illuminate\Routing\Middleware\ThrottleRequests;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Session;
 | 
				
			||||||
 | 
					use Tests\MockAccountData;
 | 
				
			||||||
 | 
					use Tests\TestCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @test
 | 
				
			||||||
 | 
					 * @covers App\Http\Controllers\RecurringQuoteController
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class RecurringQuotesTest extends TestCase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					    use DatabaseTransactions;
 | 
				
			||||||
 | 
					    use MockAccountData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUp() :void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::setUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Session::start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->faker = \Faker\Factory::create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Model::reguard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->withoutMiddleware(
 | 
				
			||||||
 | 
					            ThrottleRequests::class
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->makeTestData();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringQuoteList()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Client::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) {
 | 
				
			||||||
 | 
					        //     ClientContact::factory()->create([
 | 
				
			||||||
 | 
					        //         'user_id' => $this->user->id,
 | 
				
			||||||
 | 
					        //         'client_id' => $c->id,
 | 
				
			||||||
 | 
					        //         'company_id' => $this->company->id,
 | 
				
			||||||
 | 
					        //         'is_primary' => 1,
 | 
				
			||||||
 | 
					        //     ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //     ClientContact::factory()->create([
 | 
				
			||||||
 | 
					        //         'user_id' => $this->user->id,
 | 
				
			||||||
 | 
					        //         'client_id' => $c->id,
 | 
				
			||||||
 | 
					        //         'company_id' => $this->company->id,
 | 
				
			||||||
 | 
					        //     ]);
 | 
				
			||||||
 | 
					        // });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // $client = Client::all()->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // RecurringQuote::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_quotes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRecurringQuoteRESTEndPoints()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_quotes/'.$this->recurring_quote->hashed_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->get('/api/v1/recurring_quotes/'.$this->recurring_quote->hashed_id.'/edit');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $RecurringQuote_update = [
 | 
				
			||||||
 | 
					            'status_id' => RecurringQuote::STATUS_DRAFT,
 | 
				
			||||||
 | 
					            'number' => 'customnumber'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->put('/api/v1/recurring_quotes/'.$this->recurring_quote->hashed_id, $RecurringQuote_update);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					        $arr = $response->json();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals('customnumber', $arr['data']['number']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->put('/api/v1/recurring_quotes/'.$this->recurring_quote->hashed_id, $RecurringQuote_update)
 | 
				
			||||||
 | 
					            ->assertStatus(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $RecurringQuote_update = [
 | 
				
			||||||
 | 
					            'status_id' => RecurringQuote::STATUS_DRAFT,
 | 
				
			||||||
 | 
					            'client_id' => $this->recurring_quote->hashed_id,
 | 
				
			||||||
 | 
					            'number' => 'customnumber'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->post('/api/v1/recurring_quotes/', $RecurringQuote_update)
 | 
				
			||||||
 | 
					            ->assertStatus(302);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->withHeaders([
 | 
				
			||||||
 | 
					                'X-API-SECRET' => config('ninja.api_secret'),
 | 
				
			||||||
 | 
					                'X-API-TOKEN' => $this->token,
 | 
				
			||||||
 | 
					            ])->delete('/api/v1/recurring_quotes/'.$this->encodePrimaryKey($this->recurring_quote->id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response->assertStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testSubscriptionIdPassesToQuote()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_invoice = QuoteToRecurringQuoteFactory::create($this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->user_id = $this->user->id;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->status_id = RecurringQuote::STATUS_ACTIVE;
 | 
				
			||||||
 | 
					        $recurring_invoice->remaining_cycles = 2;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_invoice->number = $this->getNextRecurringQuoteNumber($this->quote->client, $this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->subscription_id = 10;
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $invoice = RecurringQuoteToQuoteFactory::create($recurring_invoice, $this->client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals(10, $invoice->subscription_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testSubscriptionIdPassesToQuoteIfNull()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_invoice = QuoteToRecurringQuoteFactory::create($this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->user_id = $this->user->id;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->status_id = RecurringQuote::STATUS_ACTIVE;
 | 
				
			||||||
 | 
					        $recurring_invoice->remaining_cycles = 2;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_invoice->number = $this->getNextRecurringQuoteNumber($this->quote->client, $this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $invoice = RecurringQuoteToQuoteFactory::create($recurring_invoice, $this->client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals(null, $invoice->subscription_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testSubscriptionIdPassesToQuoteIfNothingSet()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $recurring_invoice = QuoteToRecurringQuoteFactory::create($this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->user_id = $this->user->id;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->status_id = RecurringQuote::STATUS_ACTIVE;
 | 
				
			||||||
 | 
					        $recurring_invoice->remaining_cycles = 2;
 | 
				
			||||||
 | 
					        $recurring_invoice->next_send_date = \Carbon\Carbon::now()->addDays(10);
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $recurring_invoice->number = $this->getNextRecurringQuoteNumber($this->quote->client, $this->quote);
 | 
				
			||||||
 | 
					        $recurring_invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $invoice = RecurringQuoteToQuoteFactory::create($recurring_invoice, $this->client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertEquals(null, $invoice->subscription_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -36,7 +36,9 @@ use App\Models\Product;
 | 
				
			|||||||
use App\Models\Project;
 | 
					use App\Models\Project;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
use App\Models\QuoteInvitation;
 | 
					use App\Models\QuoteInvitation;
 | 
				
			||||||
 | 
					use App\Models\RecurringExpense;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
use App\Models\Task;
 | 
					use App\Models\Task;
 | 
				
			||||||
use App\Models\TaskStatus;
 | 
					use App\Models\TaskStatus;
 | 
				
			||||||
use App\Models\User;
 | 
					use App\Models\User;
 | 
				
			||||||
@ -83,6 +85,16 @@ trait MockAccountData
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public $token;
 | 
					    public $token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_expense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public $recurring_quote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @var
 | 
					     * @var
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@ -286,6 +298,20 @@ trait MockAccountData
 | 
				
			|||||||
            'company_id' => $this->company->id,
 | 
					            'company_id' => $this->company->id,
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->recurring_expense = RecurringExpense::factory()->create([
 | 
				
			||||||
 | 
					            'user_id' => $user_id,
 | 
				
			||||||
 | 
					            'company_id' => $this->company->id,
 | 
				
			||||||
 | 
					            'frequency_id' => 5,
 | 
				
			||||||
 | 
					            'remaining_cycles' => 5,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->recurring_quote = RecurringQuote::factory()->create([
 | 
				
			||||||
 | 
					            'user_id' => $user_id,
 | 
				
			||||||
 | 
					            'company_id' => $this->company->id,
 | 
				
			||||||
 | 
					            'client_id' => $this->client->id,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->task = Task::factory()->create([
 | 
					        $this->task = Task::factory()->create([
 | 
				
			||||||
            'user_id' => $user_id,
 | 
					            'user_id' => $user_id,
 | 
				
			||||||
            'company_id' => $this->company->id,
 | 
					            'company_id' => $this->company->id,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user