diff --git a/app/Factory/InvoiceToRecurringInvoiceFactory.php b/app/Factory/InvoiceToRecurringInvoiceFactory.php index a16cbeaf93a2..5b1927a1a60e 100644 --- a/app/Factory/InvoiceToRecurringInvoiceFactory.php +++ b/app/Factory/InvoiceToRecurringInvoiceFactory.php @@ -49,7 +49,6 @@ class InvoiceToRecurringInvoiceFactory $recurring_invoice->client_id = $invoice->client_id; $recurring_invoice->company_id = $invoice->company_id; $recurring_invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; - $recurring_invoice->start_date = null; $recurring_invoice->last_sent_date = null; $recurring_invoice->next_send_date = null; $recurring_invoice->remaining_cycles = 0; diff --git a/app/Factory/RecurringInvoiceFactory.php b/app/Factory/RecurringInvoiceFactory.php index 4219c73a3803..822e017afea6 100644 --- a/app/Factory/RecurringInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceFactory.php @@ -48,7 +48,6 @@ class RecurringInvoiceFactory $invoice->user_id = $user_id; $invoice->company_id = $company_id; $invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; - $invoice->start_date = null; $invoice->last_sent_date = null; $invoice->next_send_date = null; $invoice->remaining_cycles = 0; diff --git a/app/Factory/RecurringQuoteFactory.php b/app/Factory/RecurringQuoteFactory.php index 4b3d303f3497..8a728fb58304 100644 --- a/app/Factory/RecurringQuoteFactory.php +++ b/app/Factory/RecurringQuoteFactory.php @@ -47,7 +47,6 @@ class RecurringQuoteFactory $quote->user_id = $user_id; $quote->company_id = $company_id; $quote->frequency_id = RecurringQuote::FREQUENCY_MONTHLY; - $quote->start_date = null; $quote->last_sent_date = null; $quote->next_send_date = null; $quote->remaining_cycles = 0; diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php index 99413a9a991f..4988103f7924 100644 --- a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -101,5 +101,6 @@ class StoreRecurringInvoiceRequest extends Request public function messages() { + return []; } } diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 394725f8bbf3..128b704fda9a 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -11,6 +11,8 @@ namespace App\Models; +use App\Helpers\Invoice\InvoiceSum; +use App\Helpers\Invoice\InvoiceSumInclusive; use App\Models\Filterable; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; @@ -74,6 +76,7 @@ class RecurringInvoice extends BaseModel 'po_number', 'date', 'due_date', + 'due_date_days', 'line_items', 'settings', 'footer', @@ -93,7 +96,6 @@ class RecurringInvoice extends BaseModel 'amount', 'partial', 'frequency_id', - 'start_date', ]; protected $casts = [ @@ -176,7 +178,7 @@ class RecurringInvoice extends BaseModel public function getStatusAttribute() { - if ($this->status_id == self::STATUS_ACTIVE && $this->start_date > Carbon::now()) { //marked as active, but yet to fire first cycle + if ($this->status_id == self::STATUS_ACTIVE && $this->next_send_date > Carbon::now()) { //marked as active, but yet to fire first cycle return self::STATUS_PENDING; } elseif ($this->status_id == self::STATUS_ACTIVE && $this->next_send_date > Carbon::now()) { return self::STATUS_COMPLETED; @@ -215,6 +217,38 @@ class RecurringInvoice extends BaseModel } } + public function nextDateByFrequency($date) + { + + switch ($this->frequency_id) { + case self::FREQUENCY_WEEKLY: + return Carbon::parse($date->addWeek()); + case self::FREQUENCY_TWO_WEEKS: + return Carbon::parse($date->addWeeks(2)); + case self::FREQUENCY_FOUR_WEEKS: + return Carbon::parse($date->addWeeks(4)); + case self::FREQUENCY_MONTHLY: + return Carbon::parse($date->addMonthNoOverflow()); + case self::FREQUENCY_TWO_MONTHS: + return Carbon::parse($date->addMonthsNoOverflow(2)); + case self::FREQUENCY_THREE_MONTHS: + return Carbon::parse($date->addMonthsNoOverflow(3)); + case self::FREQUENCY_FOUR_MONTHS: + return Carbon::parse($date->addMonthsNoOverflow(4)); + case self::FREQUENCY_SIX_MONTHS: + return Carbon::parse($date->addMonthsNoOverflow(6)); + case self::FREQUENCY_ANNUALLY: + return Carbon::parse($date->addYear()); + case self::FREQUENCY_TWO_YEARS: + return Carbon::parse($date->addYears(2)); + case self::FREQUENCY_THREE_YEARS: + return Carbon::parse($date->addYears(3)); + default: + return null; + } + + } + public function remainingCycles() : int { if ($this->remaining_cycles == 0) { @@ -299,15 +333,33 @@ class RecurringInvoice extends BaseModel } } + 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() { - //todo send back a list of the next send dates and due dates - + info($this->next_send_date); /* Return early if nothing to send back! */ if( $this->status_id == self::STATUS_COMPLETED || $this->status_id == self::STATUS_DRAFT || $this->status_id == self::STATUS_CANCELLED || - $this->remaining_cycles == 0) { + $this->remaining_cycles == 0 || + !$this->next_send_date) { return []; } @@ -318,26 +370,37 @@ class RecurringInvoice extends BaseModel if($this->remaining_cycles == -1) $iterations = 10; - $next_send_date = $this->next_send_date; - $due_date_days = $this->due_date_days; + $data = []; - if(!$due_date_days) - $due_date_days = 1; + $next_send_date = Carbon::parse($this->next_send_date)->copy(); - $data = []; + for($x=0; $x<$iterations; $x++) + { - for($x=0; $x<$iterations; $x++) - { + $next_due_date = $next_send_date->copy()->addDays($this->due_date_days); - $data[] = [ - 'next_send_date' => $next_send_date->format('Y-m-d'), - 'due_date' => $next_send_date->addDays($due_date_days)->format('Y-m-d') - ]; + $next_send_date = Carbon::parse($next_send_date); + $next_due_date = Carbon::parse($next_due_date); - } + $data[] = [ + 'next_send_date' => $next_send_date->format('Y-m-d'), + 'due_date' => $next_due_date->format('Y-m-d'), + ]; + $next_send_date = $this->nextDateByFrequency($next_send_date); - return $data; + } + + /*If no due date is set - unset the due_date value */ + if(!$this->due_date_days || $this->due_date_days == 0){ + + foreach($data as $key => $value) + $data[$key]['due_date'] = ''; + + } + + return $data; + } diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index 22aab4d03f66..5414e5e8640c 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -77,7 +77,7 @@ class RecurringQuote extends BaseModel 'custom_value4', 'amount', 'frequency_id', - 'start_date', + 'due_date_days', ]; protected $touches = []; diff --git a/app/Transformers/RecurringInvoiceTransformer.php b/app/Transformers/RecurringInvoiceTransformer.php index 71e5586119eb..25e79646ef42 100644 --- a/app/Transformers/RecurringInvoiceTransformer.php +++ b/app/Transformers/RecurringInvoiceTransformer.php @@ -133,8 +133,8 @@ class RecurringInvoiceTransformer extends EntityTransformer 'line_items' => $invoice->line_items ?: (array) [], 'entity_type' => 'recurring_invoice', 'frequency_id' => (string) $invoice->frequency_id, - 'start_date' => $invoice->start_date ?: '', 'remaining_cycles' => (int) $invoice->remaining_cycles, + 'recurring_dates' => (array) $invoice->recurringDates(), ]; } } diff --git a/app/Transformers/RecurringQuoteTransformer.php b/app/Transformers/RecurringQuoteTransformer.php index 65fc7d3ef61d..32e6ffdf58c6 100644 --- a/app/Transformers/RecurringQuoteTransformer.php +++ b/app/Transformers/RecurringQuoteTransformer.php @@ -118,7 +118,6 @@ class RecurringQuoteTransformer extends EntityTransformer 'custom_text_value2' => $quote->custom_text_value2 ?: '', 'settings' => $quote->settings ?: '', 'frequency_id' => (int) $quote->frequency_id, - 'start_date' => $quote->start_date ?: '', 'last_sent_date' => $quote->last_sent_date ?: '', 'next_send_date' => $quote->next_send_date ?: '', 'remaining_cycles' => (int) $quote->remaining_cycles, diff --git a/database/factories/RecurringInvoiceFactory.php b/database/factories/RecurringInvoiceFactory.php index bbd8ef4b65d2..44b9410959dd 100644 --- a/database/factories/RecurringInvoiceFactory.php +++ b/database/factories/RecurringInvoiceFactory.php @@ -25,9 +25,8 @@ $factory->define(App\Models\RecurringInvoice::class, function (Faker $faker) { 'due_date' => $faker->date(), 'line_items' => false, 'frequency_id' => App\Models\RecurringInvoice::FREQUENCY_MONTHLY, - 'start_date' => $faker->date(), - 'last_sent_date' => $faker->date(), - 'next_send_date' => $faker->date(), + 'last_sent_date' => now()->subMonth(), + 'next_send_date' => now()->addMonthNoOverflow(), 'remaining_cycles' => $faker->numberBetween(1, 10), 'amount' => $faker->randomFloat(2, $min = 1, $max = 1000), // 48.8932 diff --git a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php index ffb0bb824179..e7e86ec690fb 100644 --- a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php +++ b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php @@ -71,6 +71,7 @@ class AddIsPublicToDocumentsTable extends Migration $table->integer('remaining_cycles')->nullable()->change(); $table->dropColumn('start_date'); $table->integer('due_date_days')->nullable(); + $table->date('partial_due_date')->nullable(); }); } diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 12a65cc8e094..1ff41c5ccc75 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -317,7 +317,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); @@ -327,7 +327,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now()->addMinutes(2); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); @@ -337,7 +337,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now()->addMinutes(10); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); @@ -347,7 +347,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now()->addMinutes(15); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); @@ -357,7 +357,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now()->addMinutes(20); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); @@ -367,7 +367,7 @@ trait MockAccountData $recurring_invoice->next_send_date = Carbon::now()->addDays(10); $recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE; $recurring_invoice->remaining_cycles = 2; - $recurring_invoice->start_date = Carbon::now(); + $recurring_invoice->next_send_date = Carbon::now(); $recurring_invoice->save(); $recurring_invoice->number = $this->getNextInvoiceNumber($this->invoice->client); diff --git a/tests/Unit/RecurringDatesTest.php b/tests/Unit/RecurringDatesTest.php new file mode 100644 index 000000000000..16ab02d51284 --- /dev/null +++ b/tests/Unit/RecurringDatesTest.php @@ -0,0 +1,87 @@ +makeTestData(); + } + + public function testRecurringDatesDraftInvoice() + { + + $recurring_invoice = RecurringInvoiceFactory::create($this->company->id, $this->user->id); + $recurring_invoice->line_items = $this->buildLineItems(); + $recurring_invoice->client_id = $this->client->id; + $recurring_invoice->save(); + + $recurring_invoice->calc()->getInvoice(); + + $this->assertEquals(0, count($recurring_invoice->recurringDates())); + + } + + public function testRecurringDatesPendingInvoice() + { + + $recurring_invoice = RecurringInvoiceFactory::create($this->company->id, $this->user->id); + $recurring_invoice->line_items = $this->buildLineItems(); + $recurring_invoice->client_id = $this->client->id; + + $recurring_invoice->status_id = RecurringInvoice::STATUS_PENDING; + $recurring_invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; + $recurring_invoice->remaining_cycles = 5; + $recurring_invoice->due_date_days = 5; + $recurring_invoice->next_send_date = now(); + + $recurring_invoice->save(); + + $recurring_invoice->calc()->getInvoice(); + + $this->assertEquals(5, count($recurring_invoice->recurringDates())); + + } + + + public function testRecurringDatesPendingInvoiceWithNoDueDate() + { + + $recurring_invoice = RecurringInvoiceFactory::create($this->company->id, $this->user->id); + $recurring_invoice->line_items = $this->buildLineItems(); + $recurring_invoice->client_id = $this->client->id; + + $recurring_invoice->status_id = RecurringInvoice::STATUS_PENDING; + $recurring_invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; + $recurring_invoice->remaining_cycles = 5; + $recurring_invoice->due_date_days = null; + $recurring_invoice->next_send_date = now(); + + $recurring_invoice->save(); + + $recurring_invoice->calc()->getInvoice(); + + $this->assertEquals(5, count($recurring_invoice->recurringDates())); + + } +}