1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00

Merge pull request #4063 from turbo124/v2

Recurring Dates
This commit is contained in:
David Bomba 2020-09-13 20:20:37 +10:00 committed by GitHub
commit 79565ff806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 260 additions and 391 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -81,6 +81,9 @@ class UpdateClientRequest extends Request
'email' => ctrans('validation.email', ['attribute' => 'email']),
'name.required' => ctrans('validation.required', ['attribute' => 'name']),
'required' => ctrans('validation.required', ['attribute' => 'email']),
'contacts.*.password.min' => ctrans('texts.password_strength'),
'contacts.*.password.regex' => ctrans('texts.password_strength'),
'contacts.*.password.string' => ctrans('texts.password_strength'),
];
}
@ -109,11 +112,12 @@ class UpdateClientRequest extends Request
if (strlen($contact['password']) == 0) {
$input['contacts'][$key]['password'] = '';
} else {
$contact['password'] = str_replace('*', '', $contact['password']);
$input['contacts'][$key]['password'] = str_replace('*', '', $contact['password']);
if (strlen($contact['password']) == 0) {
unset($input['contacts'][$key]['password']);
}
}
}
}

View File

@ -101,5 +101,6 @@ class StoreRecurringInvoiceRequest extends Request
public function messages()
{
return [];
}
}

View File

@ -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,11 +217,47 @@ 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) {
return 0;
} else {
}
else if($this->remaining_cycles == -1) {
return -1;
}
else {
return $this->remaining_cycles - 1;
}
}
@ -295,8 +333,75 @@ 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->next_send_date) {
return [];
}
/* Endless - lets send 10 back*/
$iterations = $this->remaining_cycles;
if($this->remaining_cycles == -1)
$iterations = 10;
$data = [];
$next_send_date = Carbon::parse($this->next_send_date)->copy();
for($x=0; $x<$iterations; $x++)
{
$next_due_date = $next_send_date->copy()->addDays($this->due_date_days);
$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);
}
/*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;
}
}

View File

@ -77,7 +77,7 @@ class RecurringQuote extends BaseModel
'custom_value4',
'amount',
'frequency_id',
'start_date',
'due_date_days',
];
protected $touches = [];

View File

@ -58,12 +58,10 @@ class ClientContactRepository extends BaseRepository
$update_contact->fill($contact);
if (array_key_exists('password', $contact)) {
if (strlen($contact['password']) == 0) {
$update_contact->password = '';
} else {
$update_contact->password = Hash::make($contact['password']);
}
if (array_key_exists('password', $contact) && strlen($contact['password']) > 1) {
$update_contact->password = Hash::make($contact['password']);
}
$update_contact->save();

View File

@ -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(),
];
}
}

View File

@ -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,

View File

@ -56,17 +56,14 @@
"stripe/stripe-php": "^7.50",
"turbo124/beacon": "^1",
"webpatser/laravel-countries": "dev-master#75992ad",
"laravel/ui": "^2.0",
"fruitcake/laravel-cors": "^2.0"
"laravel/ui": "^2.0"
},
"require-dev": {
"laravelcollective/html": "^6",
"wildbit/postmark-php": "^2.6",
"anahkiasen/former": "^4.2",
"barryvdh/laravel-debugbar": "^3.4",
"darkaonline/l5-swagger": "^7.0",
"filp/whoops": "^2.7",
"laravel/dusk": "^6.5",
"mockery/mockery": "^1.3.1",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5",

396
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1e9eef01abf64118b10e9fc2dff9c5e9",
"content-hash": "897c03f97efca6c6540700216fa6d789",
"packages": [
{
"name": "asgrim/ofxparser",
@ -63,58 +63,6 @@
"abandoned": true,
"time": "2018-10-29T10:10:13+00:00"
},
{
"name": "asm89/stack-cors",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/asm89/stack-cors.git",
"reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/asm89/stack-cors/zipball/23f469e81c65e2fb7fc7bce371fbdc363fe32adf",
"reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf",
"shasum": ""
},
"require": {
"php": "^7.0",
"symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0",
"symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0"
},
"require-dev": {
"phpunit/phpunit": "^6|^7|^8|^9",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Asm89\\Stack\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alexander",
"email": "iam.asm89@gmail.com"
}
],
"description": "Cross-origin resource sharing library and stack middleware",
"homepage": "https://github.com/asm89/stack-cors",
"keywords": [
"cors",
"stack"
],
"time": "2020-05-31T07:17:05+00:00"
},
{
"name": "authorizenet/authorizenet",
"version": "2.0.0",
@ -160,16 +108,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.153.0",
"version": "3.154.1",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "3045bc6c8f7d2521b3e0d4a7b407194af8725c8f"
"reference": "5651d8a92164d98869b70a15e4c06ce4c14c7c28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3045bc6c8f7d2521b3e0d4a7b407194af8725c8f",
"reference": "3045bc6c8f7d2521b3e0d4a7b407194af8725c8f",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5651d8a92164d98869b70a15e4c06ce4c14c7c28",
"reference": "5651d8a92164d98869b70a15e4c06ce4c14c7c28",
"shasum": ""
},
"require": {
@ -241,7 +189,7 @@
"s3",
"sdk"
],
"time": "2020-09-09T18:12:35+00:00"
"time": "2020-09-11T18:12:41+00:00"
},
{
"name": "brick/math",
@ -1771,79 +1719,6 @@
],
"time": "2020-03-25T18:49:23+00:00"
},
{
"name": "fruitcake/laravel-cors",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/laravel-cors.git",
"reference": "4b19bfc3bd422948af37a42a62fad7f49025894a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/4b19bfc3bd422948af37a42a62fad7f49025894a",
"reference": "4b19bfc3bd422948af37a42a62fad7f49025894a",
"shasum": ""
},
"require": {
"asm89/stack-cors": "^2.0.1",
"illuminate/contracts": "^6|^7|^8",
"illuminate/support": "^6|^7|^8",
"php": ">=7.2",
"symfony/http-foundation": "^4|^5",
"symfony/http-kernel": "^4.3.4|^5"
},
"require-dev": {
"laravel/framework": "^6|^7|^8",
"orchestra/testbench-dusk": "^4|^5|^6",
"phpunit/phpunit": "^6|^7|^8",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
},
"laravel": {
"providers": [
"Fruitcake\\Cors\\CorsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Fruitcake\\Cors\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fruitcake",
"homepage": "https://fruitcake.nl"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application",
"keywords": [
"api",
"cors",
"crossdomain",
"laravel"
],
"funding": [
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2020-09-07T11:48:52+00:00"
},
{
"name": "fzaninotto/faker",
"version": "v1.9.1",
@ -2929,27 +2804,27 @@
},
{
"name": "laravel/ui",
"version": "v2.3.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/ui.git",
"reference": "2ccaa3b821ea8ac7e05393b946d0578bdb46099b"
"reference": "f5398544a9cd4804a42d09ce51735e37cd51ea2d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/ui/zipball/2ccaa3b821ea8ac7e05393b946d0578bdb46099b",
"reference": "2ccaa3b821ea8ac7e05393b946d0578bdb46099b",
"url": "https://api.github.com/repos/laravel/ui/zipball/f5398544a9cd4804a42d09ce51735e37cd51ea2d",
"reference": "f5398544a9cd4804a42d09ce51735e37cd51ea2d",
"shasum": ""
},
"require": {
"illuminate/console": "^7.0|^8.0",
"illuminate/filesystem": "^7.0|^8.0",
"illuminate/support": "^7.0|^8.0",
"illuminate/console": "^7.0",
"illuminate/filesystem": "^7.0",
"illuminate/support": "^7.0",
"php": "^7.2.5"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^8.0|^9.0"
"phpunit/phpunit": "^8.0"
},
"type": "library",
"extra": {
@ -2980,7 +2855,7 @@
"laravel",
"ui"
],
"time": "2020-09-09T12:07:59+00:00"
"time": "2020-09-11T15:31:52+00:00"
},
{
"name": "league/commonmark",
@ -3963,16 +3838,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.39.1",
"version": "2.39.2",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "7af467873250583cc967a59ee9df29fabab193c1"
"reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7af467873250583cc967a59ee9df29fabab193c1",
"reference": "7af467873250583cc967a59ee9df29fabab193c1",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/326efde1bc09077a26cb77f6e2e32e13f06c27f2",
"reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2",
"shasum": ""
},
"require": {
@ -4048,7 +3923,7 @@
"type": "tidelift"
}
],
"time": "2020-09-04T13:11:37+00:00"
"time": "2020-09-10T12:16:42+00:00"
},
{
"name": "nikic/php-parser",
@ -5085,16 +4960,16 @@
},
{
"name": "predis/predis",
"version": "v1.1.4",
"version": "v1.1.6",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "8be2418f0116572f1937083daf5cceb1bddc9f0d"
"reference": "9930e933c67446962997b05201c69c2319bf26de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/8be2418f0116572f1937083daf5cceb1bddc9f0d",
"reference": "8be2418f0116572f1937083daf5cceb1bddc9f0d",
"url": "https://api.github.com/repos/predis/predis/zipball/9930e933c67446962997b05201c69c2319bf26de",
"reference": "9930e933c67446962997b05201c69c2319bf26de",
"shasum": ""
},
"require": {
@ -5156,7 +5031,7 @@
"type": "github"
}
],
"time": "2020-08-29T22:15:08+00:00"
"time": "2020-09-11T19:18:05+00:00"
},
{
"name": "psr/cache",
@ -5659,16 +5534,16 @@
},
{
"name": "ramsey/collection",
"version": "1.1.0",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "044184884e3c803e4cbb6451386cb71562939b18"
"reference": "24d93aefb2cd786b7edd9f45b554aea20b28b9b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/044184884e3c803e4cbb6451386cb71562939b18",
"reference": "044184884e3c803e4cbb6451386cb71562939b18",
"url": "https://api.github.com/repos/ramsey/collection/zipball/24d93aefb2cd786b7edd9f45b554aea20b28b9b1",
"reference": "24d93aefb2cd786b7edd9f45b554aea20b28b9b1",
"shasum": ""
},
"require": {
@ -5724,7 +5599,7 @@
"type": "github"
}
],
"time": "2020-08-11T00:57:21+00:00"
"time": "2020-09-10T20:58:17+00:00"
},
{
"name": "ramsey/uuid",
@ -9975,142 +9850,6 @@
],
"time": "2020-07-09T08:09:16+00:00"
},
{
"name": "laravel/dusk",
"version": "v6.6.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/dusk.git",
"reference": "be00c525f9bde15bcfec1afc4857ab26afa6b369"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/be00c525f9bde15bcfec1afc4857ab26afa6b369",
"reference": "be00c525f9bde15bcfec1afc4857ab26afa6b369",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-zip": "*",
"illuminate/console": "^6.0|^7.0|^8.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"nesbot/carbon": "^2.0",
"php": "^7.2",
"php-webdriver/webdriver": "^1.8.1",
"symfony/console": "^4.3|^5.0",
"symfony/finder": "^4.3|^5.0",
"symfony/process": "^4.3|^5.0",
"vlucas/phpdotenv": "^3.0|^4.0|^5.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.5.15|^8.4|^9.0"
},
"suggest": {
"ext-pcntl": "Used to gracefully terminate Dusk when tests are running."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Dusk\\DuskServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Dusk\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Dusk provides simple end-to-end testing and browser automation.",
"keywords": [
"laravel",
"testing",
"webdriver"
],
"time": "2020-09-08T16:09:25+00:00"
},
{
"name": "laravelcollective/html",
"version": "v6.2.0",
"source": {
"type": "git",
"url": "https://github.com/LaravelCollective/html.git",
"reference": "3bb99be7502feb2129b375cd026ccb0fa4b66628"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/LaravelCollective/html/zipball/3bb99be7502feb2129b375cd026ccb0fa4b66628",
"reference": "3bb99be7502feb2129b375cd026ccb0fa4b66628",
"shasum": ""
},
"require": {
"illuminate/http": "^6.0|^7.0|^8.0",
"illuminate/routing": "^6.0|^7.0|^8.0",
"illuminate/session": "^6.0|^7.0|^8.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"illuminate/view": "^6.0|^7.0|^8.0",
"php": ">=7.2.5"
},
"require-dev": {
"illuminate/database": "^6.0|^7.0|^8.0",
"mockery/mockery": "~1.0",
"phpunit/phpunit": "~7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
},
"laravel": {
"providers": [
"Collective\\Html\\HtmlServiceProvider"
],
"aliases": {
"Form": "Collective\\Html\\FormFacade",
"Html": "Collective\\Html\\HtmlFacade"
}
}
},
"autoload": {
"psr-4": {
"Collective\\Html\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Adam Engebretson",
"email": "adam@laravelcollective.com"
},
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "HTML and Form Builders for the Laravel Framework",
"homepage": "https://laravelcollective.com",
"time": "2020-09-07T19:59:40+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.16.3",
@ -10480,71 +10219,6 @@
"description": "Library for handling version information and constraints",
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^5.6 || ~7.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.0",
"jakub-onderka/php-parallel-lint": "^1.0",
"php-coveralls/php-coveralls": "^2.0",
"php-mock/php-mock-phpunit": "^1.1",
"phpunit/phpunit": "^5.7",
"sebastian/environment": "^1.3.4 || ^2.0 || ^3.0",
"sminnee/phpunit-mock-objects": "^3.4",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
},
"files": [
"lib/Exception/TimeoutException.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"time": "2020-03-04T14:40:12+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
@ -11792,16 +11466,16 @@
},
{
"name": "swagger-api/swagger-ui",
"version": "v3.32.5",
"version": "v3.33.0",
"source": {
"type": "git",
"url": "https://github.com/swagger-api/swagger-ui.git",
"reference": "57f39bd5724956d96af43a86439e2808b981fb18"
"reference": "829d87530030bb5bfa24a5093d098c672adfbb9b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/57f39bd5724956d96af43a86439e2808b981fb18",
"reference": "57f39bd5724956d96af43a86439e2808b981fb18",
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/829d87530030bb5bfa24a5093d098c672adfbb9b",
"reference": "829d87530030bb5bfa24a5093d098c672adfbb9b",
"shasum": ""
},
"type": "library",
@ -11845,7 +11519,7 @@
"swagger",
"ui"
],
"time": "2020-08-27T20:11:06+00:00"
"time": "2020-09-10T23:20:14+00:00"
},
{
"name": "symfony/debug",

View File

@ -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

View File

@ -66,6 +66,13 @@ class AddIsPublicToDocumentsTable extends Migration
Schema::table('companies', function ($table) {
$table->enum('default_auto_bill', ['off', 'always', 'optin', 'optout'])->default('off');
});
Schema::table('recurring_invoices', function (Blueprint $table) {
$table->integer('remaining_cycles')->nullable()->change();
$table->dropColumn('start_date');
$table->integer('due_date_days')->nullable();
$table->date('partial_due_date')->nullable();
});
}
/**

View File

@ -3269,4 +3269,5 @@ return [
'payment_due' => 'Payment due',
'account_balance' => 'Account balance',
'password_strength' => 'Password strength too weak',
];

View File

@ -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);

View File

@ -0,0 +1,87 @@
<?php
namespace Tests\Unit;
use App\Factory\CloneQuoteToInvoiceFactory;
use App\Factory\InvoiceFactory;
use App\Factory\InvoiceItemFactory;
use App\Factory\RecurringInvoiceFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
*/
class RecurringDatesTest extends TestCase
{
use MockAccountData;
use DatabaseTransactions;
public function setUp() :void
{
parent::setUp();
$this->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()));
}
}