addMonthNoOverflow()->thisDayOrLast($subscription->day); echo "You will be billed on {$day} in month {$month}\n"; } */ const FREQUENCY_DAILY = 1; const FREQUENCY_WEEKLY = 2; const FREQUENCY_TWO_WEEKS = 3; const FREQUENCY_FOUR_WEEKS = 4; const FREQUENCY_MONTHLY = 5; const FREQUENCY_TWO_MONTHS = 6; const FREQUENCY_THREE_MONTHS = 7; const FREQUENCY_FOUR_MONTHS = 8; const FREQUENCY_SIX_MONTHS = 9; const FREQUENCY_ANNUALLY = 10; const FREQUENCY_TWO_YEARS = 11; const FREQUENCY_THREE_YEARS = 12; const RECURS_INDEFINITELY = -1; protected $fillable = [ 'client_id', 'number', 'discount', 'is_amount_discount', 'po_number', 'date', 'due_date', 'line_items', 'settings', 'footer', 'public_notes', 'private_notes', 'terms', 'tax_name1', 'tax_name2', 'tax_name3', 'tax_rate1', 'tax_rate2', 'tax_rate3', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4', 'amount', 'partial', 'frequency_id', 'start_date', ]; protected $casts = [ 'settings' => 'object', 'line_items' => 'object', 'backup' => 'object', 'updated_at' => 'timestamp', 'created_at' => 'timestamp', 'deleted_at' => 'timestamp', ]; protected $appends = [ 'hashed_id', 'status' ]; protected $touches = []; public function getEntityType() { return RecurringInvoice::class; } public function getDateAttribute($value) { if (!empty($value)) { return (new Carbon($value))->format('Y-m-d'); } return $value; } public function getDueDateAttribute($value) { if (!empty($value)) { return (new Carbon($value))->format('Y-m-d'); } return $value; } public function getPartialDueDateAttribute($value) { if (!empty($value)) { return (new Carbon($value))->format('Y-m-d'); } return $value; } public function company() { return $this->belongsTo(Company::class); } public function client() { return $this->belongsTo(Client::class)->withTrashed(); } public function user() { return $this->belongsTo(User::class)->withTrashed(); } public function assigned_user() { return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function invoices() { return $this->hasMany(Invoice::class, "id", "recurring_id")->withTrashed(); } public function invitations() { $this->morphMany(RecurringInvoiceInvitation::class); } public function getStatusAttribute() { if ($this->status_id == RecurringInvoice::STATUS_ACTIVE && $this->start_date > Carbon::now()) { //marked as active, but yet to fire first cycle return RecurringInvoice::STATUS_PENDING; } elseif ($this->status_id == RecurringInvoice::STATUS_ACTIVE && $this->next_send_date > Carbon::now()) { return RecurringInvoice::STATUS_COMPLETED; } else { return $this->status_id; } } public function nextSendDate() :?Carbon { switch ($this->frequency_id) { case RecurringInvoice::FREQUENCY_WEEKLY: return Carbon::parse($this->next_send_date->addWeek()); case RecurringInvoice::FREQUENCY_TWO_WEEKS: return Carbon::parse($this->next_send_date->addWeeks(2)); case RecurringInvoice::FREQUENCY_FOUR_WEEKS: return Carbon::parse($this->next_send_date->addWeeks(4)); case RecurringInvoice::FREQUENCY_MONTHLY: return Carbon::parse($this->next_send_date->addMonthNoOverflow()); case RecurringInvoice::FREQUENCY_TWO_MONTHS: return Carbon::parse($this->next_send_date->addMonthsNoOverflow(2)); case RecurringInvoice::FREQUENCY_THREE_MONTHS: return Carbon::parse($this->next_send_date->addMonthsNoOverflow(3)); case RecurringInvoice::FREQUENCY_FOUR_MONTHS: return Carbon::parse($this->next_send_date->addMonthsNoOverflow(4)); case RecurringInvoice::FREQUENCY_SIX_MONTHS: return Carbon::parse($this->next_send_date->addMonthsNoOverflow(6)); case RecurringInvoice::FREQUENCY_ANNUALLY: return Carbon::parse($this->next_send_date->addYear()); case RecurringInvoice::FREQUENCY_TWO_YEARS: return Carbon::parse($this->next_send_date->addYears(2)); case RecurringInvoice::FREQUENCY_THREE_YEARS: return Carbon::parse($this->next_send_date->addYears(3)); default: return null; } } public function remainingCycles() : int { if ($this->remaining_cycles == 0) { return 0; } 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 RecurringInvoice::STATUS_DRAFT: return '

'.ctrans('texts.draft').'

'; break; case RecurringInvoice::STATUS_PENDING: return '

'.ctrans('texts.sent').'

'; break; case RecurringInvoice::STATUS_ACTIVE: return '

'.ctrans('texts.partial').'

'; break; case RecurringInvoice::STATUS_COMPLETED: return '

'.ctrans('texts.status_completed').'

'; break; case RecurringInvoice::STATUS_CANCELLED: return '

'.ctrans('texts.overdue').'

'; break; default: # code... break; } } public static function frequencyForKey(int $frequency_id) :string { switch ($frequency_id) { case RecurringInvoice::FREQUENCY_WEEKLY: return ctrans('texts.freq_weekly'); break; case RecurringInvoice::FREQUENCY_TWO_WEEKS: return ctrans('texts.freq_two_weeks'); break; case RecurringInvoice::FREQUENCY_FOUR_WEEKS: return ctrans('texts.freq_four_weeks'); break; case RecurringInvoice::FREQUENCY_MONTHLY: return ctrans('texts.freq_monthly'); break; case RecurringInvoice::FREQUENCY_TWO_MONTHS: return ctrans('texts.freq_two_months'); break; case RecurringInvoice::FREQUENCY_THREE_MONTHS: return ctrans('texts.freq_three_months'); break; case RecurringInvoice::FREQUENCY_FOUR_MONTHS: return ctrans('texts.freq_four_months'); break; case RecurringInvoice::FREQUENCY_SIX_MONTHS: return ctrans('texts.freq_six_months'); break; case RecurringInvoice::FREQUENCY_ANNUALLY: return ctrans('texts.freq_annually'); break; case RecurringInvoice::FREQUENCY_TWO_YEARS: return ctrans('texts.freq_two_years'); break; default: # code... break; } } public function recurringDates() { //todo send back a list of the next send dates and due dates } }