diff --git a/app/Http/Controllers/Auth/ContactLoginController.php b/app/Http/Controllers/Auth/ContactLoginController.php index 8168052aab85..2bcf310dfa04 100644 --- a/app/Http/Controllers/Auth/ContactLoginController.php +++ b/app/Http/Controllers/Auth/ContactLoginController.php @@ -80,4 +80,5 @@ class ContactLoginController extends Controller return redirect('/client/login'); } + } diff --git a/app/Http/Controllers/ClientPortal/ContactHashLoginController.php b/app/Http/Controllers/ClientPortal/ContactHashLoginController.php new file mode 100644 index 000000000000..3a64b9f1d36d --- /dev/null +++ b/app/Http/Controllers/ClientPortal/ContactHashLoginController.php @@ -0,0 +1,35 @@ +each(function ($recurring_invoice, $key) use ($action) { if (auth()->user()->can('edit', $recurring_invoice)) { - $this->recurring_invoice_repo->{$action}($recurring_invoice); + $this->performAction($recurring_invoice, $action, true); } }); @@ -572,38 +572,56 @@ class RecurringInvoiceController extends BaseController * ) */ public function action(ActionRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice, $action) + { + return $this->performAction($recurring_invoice, $action); + } + + private function performAction(RecurringInvoice $recurring_invoice, string $action, $bulk = false) { switch ($action) { - case 'clone_to_RecurringInvoice': - // $recurring_invoice = CloneRecurringInvoiceFactory::create($recurring_invoice, auth()->user()->id); - // return $this->itemResponse($recurring_invoice); - break; - case 'clone_to_quote': - // $recurring_invoice = CloneRecurringInvoiceToQuoteFactory::create($recurring_invoice, auth()->user()->id); - // todo build the quote transformer and return response here - break; - case 'history': - // code... - break; - case 'delivery_note': - // code... - break; - case 'mark_paid': - // code... - break; case 'archive': - // code... + $this->recurring_invoice_repo->archive($recurring_invoice); + + if (! $bulk) { + return $this->listResponse($recurring_invoice); + } + break; + case 'restore': + $this->recurring_invoice_repo->restore($recurring_invoice); + + if (! $bulk) { + return $this->listResponse($recurring_invoice); + } break; case 'delete': - // code... + $this->recurring_invoice_repo->delete($recurring_invoice); + + if (! $bulk) { + return $this->listResponse($recurring_invoice); + } break; case 'email': //dispatch email to queue break; + case 'start': + $recurring_invoice = $recurring_invoice->service()->start()->save(); + + if (! $bulk) { + $this->itemResponse($recurring_invoice); + } + break; + case 'stop': + $recurring_invoice = $recurring_invoice->service()->stop()->save(); + + if (! $bulk) { + $this->itemResponse($recurring_invoice); + } + break; default: // code... break; } + } } diff --git a/app/Http/Controllers/SelfUpdateController.php b/app/Http/Controllers/SelfUpdateController.php index 322a8c6a2c65..7745f0942bd7 100644 --- a/app/Http/Controllers/SelfUpdateController.php +++ b/app/Http/Controllers/SelfUpdateController.php @@ -82,6 +82,6 @@ class SelfUpdateController extends BaseController Artisan::call('ninja:post-update'); - return response()->json(['message'=>$res], 200); + return response()->json(['message' => ''], 200); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 5a5f3802fae9..679f5cef0c7a 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -117,5 +117,6 @@ class Kernel extends HttpKernel 'contact.register' => \App\Http\Middleware\ContactRegister::class, 'shop_token_auth' => \App\Http\Middleware\Shop\ShopTokenAuth::class, 'phantom_secret' => \App\Http\Middleware\PhantomSecret::class, + 'contact_key_login' => \App\Http\Middleware\ContactKeyLogin::class, ]; } diff --git a/app/Http/Middleware/ContactKeyLogin.php b/app/Http/Middleware/ContactKeyLogin.php new file mode 100644 index 000000000000..120c03d730db --- /dev/null +++ b/app/Http/Middleware/ContactKeyLogin.php @@ -0,0 +1,54 @@ +segment(3) && config('ninja.db.multi_db_enabled')) { + + if (MultiDB::findAndSetDbByContactKey($request->segment(3))) { + + $client_contact = ClientContact::where('contact_key', $request->segment(3))->first(); + Auth::guard('contact')->login($client_contact, true); + return redirect()->to('client/dashboard'); + + } + + } + else if ($request->has('contact_key')) { + + if($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()){ + Auth::guard('contact')->login($client_contact, true); + return redirect()->to('client/dashboard'); + } + + } + + return $next($request); + } +} diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php index d478ebcd7959..e04a672c46d5 100644 --- a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -95,9 +95,24 @@ class StoreRecurringInvoiceRequest extends Request } $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; - //$input['line_items'] = json_encode($input['line_items']); - $this->replace($input); - } + + if(isset($input['auto_bill'])) + $input['auto_bill_enabled'] = $this->setAutoBillFlag($input['auto_bill']); + + $this->replace($input); +} + +private function setAutoBillFlag($auto_bill) +{ + if($auto_bill == 'always') + return true; + + if($auto_bill == 'off') + return false; + + //todo do we need to handle optin / optout here? + +} public function messages() { diff --git a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php index 48cdae76c6ef..5b1e9111f38a 100644 --- a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php @@ -85,6 +85,22 @@ class UpdateRecurringInvoiceRequest extends Request $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']); + $this->replace($input); } + + private function setAutoBillFlag($auto_bill) + { + if($auto_bill == 'always') + return true; + + if($auto_bill == 'off') + return false; + + //todo do we need to handle optin / optout here? + + } + } diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index bec81ae599cf..850baef2a8ee 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -17,6 +17,7 @@ use App\Helpers\Email\InvoiceEmail; use App\Jobs\Invoice\EmailInvoice; use App\Models\Invoice; use App\Models\RecurringInvoice; +use App\Utils\Ninja; use App\Utils\Traits\GeneratesCounter; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; diff --git a/app/Libraries/MultiDB.php b/app/Libraries/MultiDB.php index 58be6049e7cb..7aebf248f026 100644 --- a/app/Libraries/MultiDB.php +++ b/app/Libraries/MultiDB.php @@ -195,6 +195,20 @@ class MultiDB return false; } + public static function findAndSetDbByContactKey($contact_key) :bool + { + foreach (self::$dbs as $db) { + if ($client_contact = ClientContact::on($db)->where('contact_key', $contact_key)->first()) { + self::setDb($client_contact->company->db); + + return true; + } + } + + return false; + } + + public static function findAndSetDbByDomain($subdomain) :bool { foreach (self::$dbs as $db) { diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 7aadf906fea5..0750e614f262 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -15,6 +15,7 @@ use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSumInclusive; use App\Models\Filterable; use App\Models\RecurringInvoiceInvitation; +use App\Services\Recurring\RecurringService; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; use App\Utils\Traits\Recurring\HasRecurrence; @@ -103,6 +104,7 @@ class RecurringInvoice extends BaseModel 'next_send_date', 'remaining_cycles', 'auto_bill', + 'auto_bill_enabled', ]; protected $casts = [ @@ -190,7 +192,7 @@ class RecurringInvoice extends BaseModel public function getStatusAttribute() { - if ($this->status_id == self::STATUS_ACTIVE && $this->next_send_date > Carbon::now()) + if ($this->status_id == self::STATUS_ACTIVE && Carbon::parse($this->next_send_date)->isFuture()) return self::STATUS_PENDING; else return $this->status_id; @@ -200,27 +202,27 @@ class RecurringInvoice extends BaseModel { switch ($this->frequency_id) { case self::FREQUENCY_WEEKLY: - return Carbon::parse($this->next_send_date->addWeek()); + return Carbon::parse($this->next_send_date)->addWeek(); case self::FREQUENCY_TWO_WEEKS: - return Carbon::parse($this->next_send_date->addWeeks(2)); + return Carbon::parse($this->next_send_date)->addWeeks(2); case self::FREQUENCY_FOUR_WEEKS: - return Carbon::parse($this->next_send_date->addWeeks(4)); + return Carbon::parse($this->next_send_date)->addWeeks(4); case self::FREQUENCY_MONTHLY: - return Carbon::parse($this->next_send_date->addMonthNoOverflow()); + return Carbon::parse($this->next_send_date)->addMonthNoOverflow(); case self::FREQUENCY_TWO_MONTHS: - return Carbon::parse($this->next_send_date->addMonthsNoOverflow(2)); + return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(2); case self::FREQUENCY_THREE_MONTHS: - return Carbon::parse($this->next_send_date->addMonthsNoOverflow(3)); + return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(3); case self::FREQUENCY_FOUR_MONTHS: - return Carbon::parse($this->next_send_date->addMonthsNoOverflow(4)); + return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(4); case self::FREQUENCY_SIX_MONTHS: - return Carbon::parse($this->next_send_date->addMonthsNoOverflow(6)); + return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(6); case self::FREQUENCY_ANNUALLY: - return Carbon::parse($this->next_send_date->addYear()); + return Carbon::parse($this->next_send_date)->addYear(); case self::FREQUENCY_TWO_YEARS: - return Carbon::parse($this->next_send_date->addYears(2)); + return Carbon::parse($this->next_send_date)->addYears(2); case self::FREQUENCY_THREE_YEARS: - return Carbon::parse($this->next_send_date->addYears(3)); + return Carbon::parse($this->next_send_date)->addYears(3); default: return null; } @@ -231,27 +233,27 @@ class RecurringInvoice extends BaseModel switch ($this->frequency_id) { case self::FREQUENCY_WEEKLY: - return Carbon::parse($date->addWeek()); + return Carbon::parse($date)->addWeek(); case self::FREQUENCY_TWO_WEEKS: - return Carbon::parse($date->addWeeks(2)); + return Carbon::parse($date)->addWeeks(2); case self::FREQUENCY_FOUR_WEEKS: - return Carbon::parse($date->addWeeks(4)); + return Carbon::parse($date)->addWeeks(4); case self::FREQUENCY_MONTHLY: - return Carbon::parse($date->addMonthNoOverflow()); + return Carbon::parse($date)->addMonthNoOverflow(); case self::FREQUENCY_TWO_MONTHS: - return Carbon::parse($date->addMonthsNoOverflow(2)); + return Carbon::parse($date)->addMonthsNoOverflow(2); case self::FREQUENCY_THREE_MONTHS: - return Carbon::parse($date->addMonthsNoOverflow(3)); + return Carbon::parse($date)->addMonthsNoOverflow(3); case self::FREQUENCY_FOUR_MONTHS: - return Carbon::parse($date->addMonthsNoOverflow(4)); + return Carbon::parse($date)->addMonthsNoOverflow(4); case self::FREQUENCY_SIX_MONTHS: - return Carbon::parse($date->addMonthsNoOverflow(6)); + return Carbon::parse($date)->addMonthsNoOverflow(6); case self::FREQUENCY_ANNUALLY: - return Carbon::parse($date->addYear()); + return Carbon::parse($date)->addYear(); case self::FREQUENCY_TWO_YEARS: - return Carbon::parse($date->addYears(2)); + return Carbon::parse($date)->addYears(2); case self::FREQUENCY_THREE_YEARS: - return Carbon::parse($date->addYears(3)); + return Carbon::parse($date)->addYears(3); default: return null; } @@ -379,24 +381,24 @@ class RecurringInvoice extends BaseModel if($this->remaining_cycles == -1) $iterations = 10; - $data = []; - $next_send_date = Carbon::parse($this->next_send_date)->copy(); + $data = []; + for($x=0; $x<$iterations; $x++) { - - $next_due_date = $next_send_date->copy()->addDays($this->due_date_days); + // 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_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'), + 'send_date' => $next_send_date->format('Y-m-d'), 'due_date' => $next_due_date->format('Y-m-d'), ]; - $next_send_date = $this->calculateDueDate($next_send_date); + $next_send_date = $this->nextDateByFrequency($next_send_date->format('Y-m-d')); } @@ -434,14 +436,22 @@ class RecurringInvoice extends BaseModel */ 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 $date->copy()->addDays($client_payment_terms); //add the number of days in the payment terms to the date + 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); + } } diff --git a/app/Repositories/InvoiceRepository.php b/app/Repositories/InvoiceRepository.php index 287b9dc308b1..8bcfc705d3f2 100644 --- a/app/Repositories/InvoiceRepository.php +++ b/app/Repositories/InvoiceRepository.php @@ -83,7 +83,9 @@ class InvoiceRepository extends BaseRepository return; } - $invoice->service()->handleCancellation()->save(); + $invoice->service()->markDeleted()->handleCancellation()->save(); + + $invoice = parent::delete($invoice); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index a7e52f7d63ce..11af9ed337f8 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -24,6 +24,7 @@ use App\Services\Invoice\CreateInvitations; use App\Services\Invoice\GetInvoicePdf; use App\Services\Invoice\HandleCancellation; use App\Services\Invoice\HandleReversal; +use App\Services\Invoice\MarkInvoiceDeleted; use App\Services\Invoice\MarkInvoicePaid; use App\Services\Invoice\MarkSent; use App\Services\Invoice\TriggeredActions; @@ -154,6 +155,13 @@ class InvoiceService return $this; } + public function markDeleted() + { + $this->invoice = (new MarkInvoiceDeleted($this->invoice))->run(); + + return $this; + } + public function reverseCancellation() { $this->invoice = (new HandleCancellation($this->invoice))->reverse(); diff --git a/app/Services/Invoice/MarkInvoiceDeleted.php b/app/Services/Invoice/MarkInvoiceDeleted.php new file mode 100644 index 000000000000..2d98ed2ed4fb --- /dev/null +++ b/app/Services/Invoice/MarkInvoiceDeleted.php @@ -0,0 +1,71 @@ +invoice = $invoice; + } + + public function run() + { + $check = false; + $x=0; + + do { + + $number = $this->calcNumber($x); + $check = $this->checkNumberAvailable(Invoice::class, $this->invoice, $number); + $x++; + + } while (!$check); + + $this->invoice->number = $number; + + return $this->invoice; + } + + + private function calcNumber($x) + { + if($x==0) + $number = $this->invoice->number . '_' . ctrans('texts.deleted'); + else + $number = $this->invoice->number . '_' . ctrans('texts.deleted') . '_'. $x; + + return $number; + + } + +} diff --git a/app/Services/Payment/RefundPayment.php b/app/Services/Payment/RefundPayment.php index 961366a0114a..250b4229518b 100644 --- a/app/Services/Payment/RefundPayment.php +++ b/app/Services/Payment/RefundPayment.php @@ -72,8 +72,10 @@ class RefundPayment { if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) { if ($this->payment->company_gateway) { + $response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund); + if ($response['success'] == false) { throw new PaymentRefundFailed(); } diff --git a/app/Services/Recurring/RecurringService.php b/app/Services/Recurring/RecurringService.php index 0dd6efdc4ca4..f05532c7ae1e 100644 --- a/app/Services/Recurring/RecurringService.php +++ b/app/Services/Recurring/RecurringService.php @@ -12,6 +12,7 @@ namespace App\Services\Recurring; use App\Models\RecurringInvoice; +use Illuminate\Support\Carbon; class RecurringService { @@ -23,4 +24,35 @@ class RecurringService } //set schedules - update next_send_dates + + /** + * Stops a recurring invoice + * + * @return $this RecurringService object + */ + public function stop() + { + $this->status_id = RecurringInvoice::STATUS_PAUSED; + + return $this; + } + + public function start() + { + //make sure next_send_date is either now or in the future else return. + if(Carbon::parse($this->recurring_entity->next_send_date)->lt(now())) + return $this; + + $this->recurring_entity->status_id = RecurringInvoice::STATUS_ACTIVE; + + return $this; + + } + + public function save() + { + $this->recurring_entity->save(); + + return $this->recurring_entity; + } } diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index 5a31ea9ab038..4c7814bbaa20 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -66,6 +66,7 @@ class SystemHealth 'php_version' => [ 'minimum_php_version' => (string) self::$php_version, 'current_php_version' => phpversion(), + 'current_php_cli_version' => (string) self::checkPhpCli(), 'is_okay' => version_compare(phpversion(), self::$php_version, '>='), ], 'env_writable' => self::checkEnvWritable(), @@ -116,6 +117,21 @@ class SystemHealth return $result; } + private static function checkPhpCli() + { + + try { + exec('php -v', $foo, $exitCode); + + if ($exitCode === 0) { + return empty($foo[0]) ? 'Found php cli, but no version information' : $foo[0]; + } + } catch (\Exception $e) { + return false; + } + + } + private static function extensions() :array { $loaded_extensions = []; diff --git a/app/Utils/Traits/GeneratesCounter.php b/app/Utils/Traits/GeneratesCounter.php index 8716eb374737..bf801b7fd13a 100644 --- a/app/Utils/Traits/GeneratesCounter.php +++ b/app/Utils/Traits/GeneratesCounter.php @@ -306,6 +306,16 @@ trait GeneratesCounter return $number; } + + /*Check if a number is available for use. */ + public function checkNumberAvailable($class, $entity, $number) :bool + { + if($entity = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->first()) + return false; + + return true; + } + /** * Saves counters at both the company and client level. * diff --git a/app/Utils/Traits/Recurring/HasRecurrence.php b/app/Utils/Traits/Recurring/HasRecurrence.php index 6560e18dd956..e56bdcb00ab2 100644 --- a/app/Utils/Traits/Recurring/HasRecurrence.php +++ b/app/Utils/Traits/Recurring/HasRecurrence.php @@ -53,12 +53,13 @@ trait HasRecurrence */ public function setDayOfMonth($date, $day_of_month) { - - $set_date = $date->copy()->setUnitNoOverflow('day', $day_of_month, 'month'); + $carbon_date = Carbon::parse($date); + + $set_date = $carbon_date->copy()->setUnitNoOverflow('day', $day_of_month, 'month'); //If the set date is less than the original date we need to add a month. //If we are overflowing dates, then we need to diff the dates and ensure it doesn't equal 0 - if($set_date->lte($date) || $set_date->diffInDays($date) == 0) + if($set_date->lte($date) || $set_date->diffInDays($carbon_date) == 0) $set_date->addMonthNoOverflow(); if($day_of_month == '31') diff --git a/composer.lock b/composer.lock index 0caafb6e095d..7a341cde05f3 100644 --- a/composer.lock +++ b/composer.lock @@ -108,16 +108,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.154.6", + "version": "3.155.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "83a1382930359e4d4f4c9187239f059d5b282520" + "reference": "575430a46c329a2a3723cdcb2d30df390f434ba1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/83a1382930359e4d4f4c9187239f059d5b282520", - "reference": "83a1382930359e4d4f4c9187239f059d5b282520", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/575430a46c329a2a3723cdcb2d30df390f434ba1", + "reference": "575430a46c329a2a3723cdcb2d30df390f434ba1", "shasum": "" }, "require": { @@ -189,7 +189,7 @@ "s3", "sdk" ], - "time": "2020-09-18T18:16:42+00:00" + "time": "2020-09-23T18:11:33+00:00" }, { "name": "brick/math", @@ -1084,30 +1084,30 @@ }, { "name": "doctrine/dbal", - "version": "2.10.4", + "version": "2.11.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "47433196b6390d14409a33885ee42b6208160643" + "reference": "0d4e1a8b29dd987704842f0465aded378f441dca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/47433196b6390d14409a33885ee42b6208160643", - "reference": "47433196b6390d14409a33885ee42b6208160643", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/0d4e1a8b29dd987704842f0465aded378f441dca", + "reference": "0d4e1a8b29dd987704842f0465aded378f441dca", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.2" + "php": "^7.3" }, "require-dev": { "doctrine/coding-standard": "^8.1", "jetbrains/phpstorm-stubs": "^2019.1", "nikic/php-parser": "^4.4", "phpstan/phpstan": "^0.12.40", - "phpunit/phpunit": "^8.5.5", + "phpunit/phpunit": "^9.3", "psalm/plugin-phpunit": "^0.10.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", "vimeo/psalm": "^3.14.2" @@ -1121,8 +1121,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev", - "dev-develop": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -1189,7 +1188,7 @@ "type": "tidelift" } ], - "time": "2020-09-12T21:20:41+00:00" + "time": "2020-09-20T23:24:53+00:00" }, { "name": "doctrine/event-manager", @@ -1504,16 +1503,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.20", + "version": "2.1.21", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "f46887bc48db66c7f38f668eb7d6ae54583617ff" + "reference": "563d0cdde5d862235ffe24a158497f4d490191b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f46887bc48db66c7f38f668eb7d6ae54583617ff", - "reference": "f46887bc48db66c7f38f668eb7d6ae54583617ff", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/563d0cdde5d862235ffe24a158497f4d490191b5", + "reference": "563d0cdde5d862235ffe24a158497f4d490191b5", "shasum": "" }, "require": { @@ -1558,7 +1557,7 @@ "validation", "validator" ], - "time": "2020-09-06T13:44:32+00:00" + "time": "2020-09-19T14:37:56+00:00" }, { "name": "fedeisas/laravel-mail-css-inliner", @@ -1834,16 +1833,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.146", + "version": "v0.147", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "029e20e81508cee6dc652529514eeeb1cf56ce54" + "reference": "8624bd004cfccb33b760ae7650d0b750168cd7f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/029e20e81508cee6dc652529514eeeb1cf56ce54", - "reference": "029e20e81508cee6dc652529514eeeb1cf56ce54", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/8624bd004cfccb33b760ae7650d0b750168cd7f7", + "reference": "8624bd004cfccb33b760ae7650d0b750168cd7f7", "shasum": "" }, "require": { @@ -1867,7 +1866,7 @@ "keywords": [ "google" ], - "time": "2020-09-12T00:24:59+00:00" + "time": "2020-09-20T00:24:43+00:00" }, { "name": "google/auth", @@ -2805,16 +2804,16 @@ }, { "name": "laravel/ui", - "version": "v2.4.0", + "version": "v2.4.1", "source": { "type": "git", "url": "https://github.com/laravel/ui.git", - "reference": "f5398544a9cd4804a42d09ce51735e37cd51ea2d" + "reference": "1c69ae3e8b52fe6c9eaf83b43c6dd8ef5c3f9e2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/f5398544a9cd4804a42d09ce51735e37cd51ea2d", - "reference": "f5398544a9cd4804a42d09ce51735e37cd51ea2d", + "url": "https://api.github.com/repos/laravel/ui/zipball/1c69ae3e8b52fe6c9eaf83b43c6dd8ef5c3f9e2c", + "reference": "1c69ae3e8b52fe6c9eaf83b43c6dd8ef5c3f9e2c", "shasum": "" }, "require": { @@ -2856,7 +2855,7 @@ "laravel", "ui" ], - "time": "2020-09-11T15:31:52+00:00" + "time": "2020-09-22T16:51:51+00:00" }, { "name": "league/commonmark", @@ -3265,16 +3264,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "fda190b62b962d96a069fcc414d781db66d65b69" + "reference": "ea2fbfc988bade315acd5967e6d02274086d0f28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/fda190b62b962d96a069fcc414d781db66d65b69", - "reference": "fda190b62b962d96a069fcc414d781db66d65b69", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ea2fbfc988bade315acd5967e6d02274086d0f28", + "reference": "ea2fbfc988bade315acd5967e6d02274086d0f28", "shasum": "" }, "require": { @@ -3312,7 +3311,7 @@ "type": "tidelift" } ], - "time": "2020-08-09T10:34:01+00:00" + "time": "2020-09-21T18:10:53+00:00" }, { "name": "league/oauth1-client", @@ -3839,16 +3838,16 @@ }, { "name": "nesbot/carbon", - "version": "2.40.0", + "version": "2.40.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "6c7646154181013ecd55e80c201b9fd873c6ee5d" + "reference": "d9a76d8b7eb0f97cf3a82529393245212f40ba3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/6c7646154181013ecd55e80c201b9fd873c6ee5d", - "reference": "6c7646154181013ecd55e80c201b9fd873c6ee5d", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d9a76d8b7eb0f97cf3a82529393245212f40ba3b", + "reference": "d9a76d8b7eb0f97cf3a82529393245212f40ba3b", "shasum": "" }, "require": { @@ -3924,20 +3923,20 @@ "type": "tidelift" } ], - "time": "2020-09-11T19:00:58+00:00" + "time": "2020-09-23T08:17:37+00:00" }, { "name": "nikic/php-parser", - "version": "v4.9.1", + "version": "v4.10.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "88e519766fc58bd46b8265561fb79b54e2e00b28" + "reference": "1b479e7592812411c20c34d9ed33db3957bde66e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/88e519766fc58bd46b8265561fb79b54e2e00b28", - "reference": "88e519766fc58bd46b8265561fb79b54e2e00b28", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1b479e7592812411c20c34d9ed33db3957bde66e", + "reference": "1b479e7592812411c20c34d9ed33db3957bde66e", "shasum": "" }, "require": { @@ -3976,7 +3975,7 @@ "parser", "php" ], - "time": "2020-08-30T16:15:20+00:00" + "time": "2020-09-23T18:23:49+00:00" }, { "name": "nwidart/laravel-modules", @@ -4429,16 +4428,16 @@ }, { "name": "php-http/discovery", - "version": "1.10.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "88ff14cad4a0db68b343260fa7ac3f1599703660" + "reference": "4366bf1bc39b663aa87459bd725501d2f1988b6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/88ff14cad4a0db68b343260fa7ac3f1599703660", - "reference": "88ff14cad4a0db68b343260fa7ac3f1599703660", + "url": "https://api.github.com/repos/php-http/discovery/zipball/4366bf1bc39b663aa87459bd725501d2f1988b6c", + "reference": "4366bf1bc39b663aa87459bd725501d2f1988b6c", "shasum": "" }, "require": { @@ -4490,7 +4489,7 @@ "message", "psr7" ], - "time": "2020-09-04T08:41:23+00:00" + "time": "2020-09-22T13:31:04+00:00" }, { "name": "php-http/guzzle6-adapter", @@ -6137,16 +6136,16 @@ }, { "name": "spatie/browsershot", - "version": "3.37.2", + "version": "3.38.0", "source": { "type": "git", "url": "https://github.com/spatie/browsershot.git", - "reference": "32d2984079ed8fe690f4dc5b7b6c205ae0a7b0fd" + "reference": "97ebb1dc0750f9c543162cb1e44d5b4916b17a7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/browsershot/zipball/32d2984079ed8fe690f4dc5b7b6c205ae0a7b0fd", - "reference": "32d2984079ed8fe690f4dc5b7b6c205ae0a7b0fd", + "url": "https://api.github.com/repos/spatie/browsershot/zipball/97ebb1dc0750f9c543162cb1e44d5b4916b17a7c", + "reference": "97ebb1dc0750f9c543162cb1e44d5b4916b17a7c", "shasum": "" }, "require": { @@ -6195,7 +6194,7 @@ "type": "github" } ], - "time": "2020-07-21T22:40:58+00:00" + "time": "2020-09-22T06:26:15+00:00" }, { "name": "spatie/image", @@ -6392,16 +6391,16 @@ }, { "name": "stripe/stripe-php", - "version": "v7.52.0", + "version": "v7.54.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", - "reference": "51e95c514aff45616dff09791ca5b2f10cf5c4e8" + "reference": "3a5cff6ce6f5f2f0fc75164d3677bd5dc3e96fe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/51e95c514aff45616dff09791ca5b2f10cf5c4e8", - "reference": "51e95c514aff45616dff09791ca5b2f10cf5c4e8", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/3a5cff6ce6f5f2f0fc75164d3677bd5dc3e96fe3", + "reference": "3a5cff6ce6f5f2f0fc75164d3677bd5dc3e96fe3", "shasum": "" }, "require": { @@ -6445,7 +6444,7 @@ "payment processing", "stripe" ], - "time": "2020-09-08T19:29:20+00:00" + "time": "2020-09-23T21:48:00+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -9339,33 +9338,33 @@ "packages-dev": [ { "name": "anahkiasen/former", - "version": "4.4.0", + "version": "4.5.0", "source": { "type": "git", "url": "https://github.com/formers/former.git", - "reference": "2fcc1f68ca04af39a01e370ed0e2eef132ed5072" + "reference": "625e1dbcf3a7c9a60b21ce96a7736a17b0f2ebf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/formers/former/zipball/2fcc1f68ca04af39a01e370ed0e2eef132ed5072", - "reference": "2fcc1f68ca04af39a01e370ed0e2eef132ed5072", + "url": "https://api.github.com/repos/formers/former/zipball/625e1dbcf3a7c9a60b21ce96a7736a17b0f2ebf8", + "reference": "625e1dbcf3a7c9a60b21ce96a7736a17b0f2ebf8", "shasum": "" }, "require": { "anahkiasen/html-object": "~1.4", - "illuminate/config": "~5.0|^6.0|^7.0", - "illuminate/container": "~5.0|^6.0|^7.0", - "illuminate/http": "~5.0|^6.0|^7.0", - "illuminate/routing": "~5.0|^6.0|^7.0", - "illuminate/session": "~5.0|^6.0|^7.0", - "illuminate/support": "~5.0|^6.0|^7.0", - "illuminate/translation": "~5.0|^6.0|^7.0", - "php": ">=5.4.0" + "illuminate/config": "~5.0|^6.0|^7.0|^8.0", + "illuminate/container": "~5.0|^6.0|^7.0|^8.0", + "illuminate/http": "~5.0|^6.0|^7.0|^8.0", + "illuminate/routing": "~5.0|^6.0|^7.0|^8.0", + "illuminate/session": "~5.0|^6.0|^7.0|^8.0", + "illuminate/support": "~5.0|^6.0|^7.0|^8.0", + "illuminate/translation": "~5.0|^6.0|^7.0|^8.0", + "php": ">=7.2.0" }, "require-dev": { - "illuminate/database": "~5.0|^6.0|^7.0", - "mockery/mockery": "~0.9.1", - "phpunit/phpunit": "~4" + "illuminate/database": "~5.0|^6.0|^7.0|^8.0", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { @@ -9408,7 +9407,7 @@ "foundation", "laravel" ], - "time": "2020-03-04T08:38:36+00:00" + "time": "2020-09-23T18:18:13+00:00" }, { "name": "anahkiasen/html-object", diff --git a/routes/client.php b/routes/client.php index c30b6217f1ee..05c15b24762e 100644 --- a/routes/client.php +++ b/routes/client.php @@ -19,6 +19,8 @@ Route::get('view/{entity_type}/{invitation_key}', 'ClientPortal\EntityViewContro Route::get('view/{entity_type}/{invitation_key}/password', 'ClientPortal\EntityViewController@password')->name('client.entity_view.password'); Route::post('view/{entity_type}/{invitation_key}/password', 'ClientPortal\EntityViewController@handlePassword'); +Route::get('client/key_login/{contact_key}', 'ClientPortal\ContactHashLoginController@login')->name('client.contact_login')->middleware(['contact_key_login']); + //todo implement domain DB Route::group(['middleware' => ['auth:contact', 'locale'], 'prefix' => 'client', 'as' => 'client.'], function () { Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit diff --git a/tests/Unit/RecurringDatesTest.php b/tests/Unit/RecurringDatesTest.php index 29beb0a72acb..44341112094f 100644 --- a/tests/Unit/RecurringDatesTest.php +++ b/tests/Unit/RecurringDatesTest.php @@ -20,9 +20,11 @@ use App\Models\RecurringInvoice; use Illuminate\Foundation\Testing\DatabaseTransactions; use Tests\MockAccountData; use Tests\TestCase; +use Illuminate\Support\Carbon; /** * @test + * @covers \App\Models\RecurringInvoice */ class RecurringDatesTest extends TestCase { @@ -92,4 +94,13 @@ class RecurringDatesTest extends TestCase $this->assertEquals(5, count($recurring_invoice->recurringDates())); } + + public function testCompareDatesLogic() + { + $date = now()->startOfDay()->format('Y-m-d'); + + $this->assertTrue(Carbon::parse($date)->lte(now()->startOfDay())); + + } + }