diff --git a/app/Console/Commands/SendRemindersCron.php b/app/Console/Commands/SendRemindersCron.php new file mode 100644 index 000000000000..9eaefac5c0f3 --- /dev/null +++ b/app/Console/Commands/SendRemindersCron.php @@ -0,0 +1,52 @@ + 'bool', @@ -301,6 +304,9 @@ class CompanySettings extends BaseSettings 'late_fee_amount1' => 'float', 'late_fee_amount2' => 'float', 'late_fee_amount3' => 'float', + 'late_fee_percent1' => 'float', + 'late_fee_percent2' => 'float', + 'late_fee_percent3' => 'float', 'endless_reminder_frequency_id' => 'integer', 'client_online_payment_notification' => 'bool', 'client_manual_payment_notification' => 'bool', @@ -312,7 +318,6 @@ class CompanySettings extends BaseSettings 'email_template_statement' => 'string', 'email_subject_statement' => 'string', 'signature_on_pdf' => 'bool', - // 'send_portal_password' => 'bool', 'quote_footer' => 'string', 'page_size' => 'string', 'font_size' => 'int', @@ -431,7 +436,7 @@ class CompanySettings extends BaseSettings 'auto_convert_quote' => 'bool', 'shared_invoice_quote_counter' => 'bool', 'counter_padding' => 'integer', - 'design' => 'string', + //'design' => 'string', 'website' => 'string', 'pdf_variables' => 'object', 'portal_custom_head' => 'string', diff --git a/app/Http/Controllers/CompanyController.php b/app/Http/Controllers/CompanyController.php index f6668b6048f9..2ccf9a6012b7 100644 --- a/app/Http/Controllers/CompanyController.php +++ b/app/Http/Controllers/CompanyController.php @@ -409,7 +409,7 @@ class CompanyController extends BaseController public function update(UpdateCompanyRequest $request, Company $company) { - if($request->hasFile('company_logo') || !array_key_exists('company_logo', $request->input('settings'))) + if($request->hasFile('company_logo') || (is_array($request->input('settings')) && !array_key_exists('company_logo', $request->input('settings')))) $this->removeLogo($company); $company = $this->company_repo->save($request->all(), $company); diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 3a6898e92902..f284e550424c 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -16,7 +16,6 @@ use App\Http\Requests\Credit\ShowCreditRequest; use App\Http\Requests\Credit\StoreCreditRequest; use App\Http\Requests\Credit\UpdateCreditRequest; use App\Http\Requests\Invoice\EditInvoiceRequest; -use App\Jobs\Credit\StoreCredit; use App\Jobs\Entity\EmailEntity; use App\Jobs\Invoice\EmailCredit; use App\Jobs\Invoice\MarkInvoicePaid; @@ -188,7 +187,9 @@ class CreditController extends BaseController $credit = $this->credit_repository->save($request->all(), CreditFactory::create(auth()->user()->company()->id, auth()->user()->id)); - $credit = StoreCredit::dispatchNow($credit, $request->all(), $credit->company); + $credit = $credit->service() + ->fillDefaults() + ->save(); event(new CreditWasCreated($credit, $credit->company, Ninja::eventVars())); diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index dcde8118055d..fb0350e5fe3f 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -213,7 +213,10 @@ class InvoiceController extends BaseController event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars())); - $invoice = $invoice->service()->triggeredActions($request)->save(); + $invoice = $invoice->service() + ->fillDefaults() + ->triggeredActions($request) + ->save(); return $this->itemResponse($invoice); } @@ -790,4 +793,57 @@ class InvoiceController extends BaseController return response()->download($file_path, basename($file_path)); } + + /** + * @OA\Get( + * path="/api/v1/invoices/{id}/delivery_note", + * operationId="deliveryNote", + * tags={"invoices"}, + * summary="Download a specific invoice delivery notes", + * description="Downloads a specific invoice delivery notes", + * @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 Invoice Hahsed Id", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns the invoice delivery note pdf", + * @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"), + * ), + * ) + * @param $invoice + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + */ + public function deliveryNote(ShowInvoiceRequest $request, Invoice $invoice) + { + + $file_path = $invoice->service()->getInvoiceDeliveryNote($invoice->invitations->first()->contact); + + return response()->download($file_path, basename($file_path)); + + } } diff --git a/app/Http/Controllers/OpenAPI/swagger-v3.php b/app/Http/Controllers/OpenAPI/swagger-v3.php index 310fa73d90bf..3fa768a4a02d 100644 --- a/app/Http/Controllers/OpenAPI/swagger-v3.php +++ b/app/Http/Controllers/OpenAPI/swagger-v3.php @@ -12,15 +12,15 @@ * @OA\License( * name="Attribution Assurance License", * url="https://opensource.org/licenses/AAL" - * ) + * ), * ), * @OA\Server( * description="Example InvoiceNinja base url", - * url="https://ninja.test" + * url="https://ninja.test", * ), * @OA\ExternalDocumentation( * description="http://docs.invoiceninja.com", * url="http://docs.invoiceninja.com" - * ) - * ) + * ), + * ), */ diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index a8d93a3e713c..9aba18ada4a6 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -82,8 +82,8 @@ class QuoteController extends BaseController * tags={"quotes"}, * summary="Gets a list of quotes", * description="Lists quotes, search and filters allow fine grained lists to be generated. - - Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters class which defines the methods available", + * + * Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters 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"), @@ -207,6 +207,8 @@ class QuoteController extends BaseController $quote = $this->quote_repo->save($request->all(), QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id)); + $quote = $quote->service()->fillDefaults()->save(); + event(new QuoteWasCreated($quote, $quote->company, Ninja::eventVars())); return $this->itemResponse($quote); diff --git a/app/Jobs/Credit/StoreCredit.php b/app/Jobs/Credit/StoreCredit.php deleted file mode 100644 index 0a114fab9d2d..000000000000 --- a/app/Jobs/Credit/StoreCredit.php +++ /dev/null @@ -1,55 +0,0 @@ -credit = $credit; - - $this->data = $data; - } - - /** - * Execute the job. - * - * @param CreditRepository $credit_repository - * @return Credit|null - */ - public function handle(CreditRepository $credit_repository): ?Credit - { - // MultiDB::setDB($this->company->db); - - // $payment = false; - - // if ($payment) { - // PaymentNotification::dispatch($payment, $payment->company); - // } - - return $this->credit; - } -} diff --git a/app/Jobs/Entity/EmailEntity.php b/app/Jobs/Entity/EmailEntity.php index 2edf49716043..f2c27e6857ce 100644 --- a/app/Jobs/Entity/EmailEntity.php +++ b/app/Jobs/Entity/EmailEntity.php @@ -79,7 +79,7 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue $this->entity = $invitation->{$this->entity_string}; - $this->reminder_template = $reminder_template ?: $this->findReminderTemplate(); + $this->reminder_template = $reminder_template ?: $this->entity->calculateTemplate($this->entity_string); $this->html_engine = new HtmlEngine($invitation); diff --git a/app/Jobs/Ninja/SendReminders.php b/app/Jobs/Ninja/SendReminders.php new file mode 100644 index 000000000000..a10e45075cb4 --- /dev/null +++ b/app/Jobs/Ninja/SendReminders.php @@ -0,0 +1,112 @@ +format('Y-m-d h:i:s')); + + if (! config('ninja.db.multi_db_enabled')) { + + $this->sendReminderEmails(); + + + } else { + //multiDB environment, need to + foreach (MultiDB::$dbs as $db) + { + + MultiDB::setDB($db); + + $this->sendReminderEmails(); + } + + } + + } + + + private function chargeLateFee() + { + + } + + private function sendReminderEmails() + { + $invoices = Invoice::where('is_deleted', 0) + ->where('balance', '>', 0) + ->whereDate('next_send_date', '<=', now()->startOfDay()) + ->cursor(); + + //we only need invoices that are payable + $invoices->filter(function ($invoice){ + + return $invoice->isPayable(); + + })->each(function ($invoice){ + + $reminder_template = $invoice->calculateTemplate('invoice'); + + if($reminder_template == 'reminder1'){ + + } + elseif($reminder_template == 'reminder2'){ + + } + elseif($reminder_template == 'reminder3'){ + + } + elseif($reminder_template == 'endless_reminder'){ + + } + + //@todo + + }); + //iterate through all the reminder emails due today + // + //determine which reminder + // + //determine late fees + // + //send + } + +} \ No newline at end of file diff --git a/app/Models/Credit.php b/app/Models/Credit.php index cd11e9ea578c..9ad51f51605b 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -23,6 +23,7 @@ use App\Utils\Ninja; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesInvoiceValues; +use App\Utils\Traits\MakesReminders; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Carbon; @@ -37,7 +38,8 @@ class Credit extends BaseModel use SoftDeletes; use PresentableTrait; use MakesInvoiceValues; - + use MakesReminders; + protected $presenter = CreditPresenter::class; protected $fillable = [ diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 54ec44405f52..36a884e1d90d 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -301,10 +301,6 @@ class BaseRepository if ($class->name == Quote::class) { $model = $model->calc()->getQuote(); - - if (! $model->design_id) { - $model->design_id = $this->decodePrimaryKey($client->getSetting('quote_design_id')); - } } $model->save(); diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index 4db7a15ae816..4928b4d45178 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -16,9 +16,12 @@ use App\Services\Credit\ApplyPayment; use App\Services\Credit\CreateInvitations; use App\Services\Credit\MarkSent; use App\Services\Credit\SendEmail; +use App\Utils\Traits\MakesHash; class CreditService { + use MakesHash; + protected $credit; public function __construct($credit) @@ -98,6 +101,24 @@ class CreditService return $this; } + + public function fillDefaults() + { + $settings = $this->credit->client->getMergedSettings(); + + if(! $this->credit->design_id) + $this->credit->design_id = $this->decodePrimaryKey($settings->credit_design_id); + + if(!isset($this->credit->footer)) + $this->credit->footer = $settings->credit_footer; + + if(!isset($this->credit->terms)) + $this->credit->terms = $settings->credit_terms; + + + return $this; + } + /** * Saves the credit. * @return Credit object diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index 878d766075e7..102f1bee251b 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -60,8 +60,8 @@ class AutoBillInvoice extends AbstractService if($this->client->getSetting('use_credits_payment') != 'off') $this->applyCreditPayment(); - info("partial = {$this->invoice->partial}"); - info("balance = {$this->invoice->balance}"); + // info("partial = {$this->invoice->partial}"); + // info("balance = {$this->invoice->balance}"); /* Determine $amount */ if ($this->invoice->partial > 0) diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 0a17c929ea44..5171752aea9e 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -143,6 +143,11 @@ class InvoiceService return (new GetInvoicePdf($this->invoice, $contact))->run(); } + public function getInvoiceDeliveryNote($contact = null) + { + //stubbed + } + public function sendEmail($contact = null) { $send_email = new SendEmail($this->invoice, null, $contact); @@ -357,6 +362,24 @@ class InvoiceService return $this; } + + public function fillDefaults() + { + $settings = $this->invoice->client->getMergedSettings(); + + if(! $this->invoice->design_id) + $this->invoice->design_id = $this->decodePrimaryKey($settings->invoice_design_id); + + if(!isset($this->invoice->footer)) + $this->invoice->footer = $settings->invoice_footer; + + if(!isset($this->invoice->terms)) + $this->invoice->terms = $settings->invoice_terms; + + + return $this; + } + /** * Saves the invoice. * @return Invoice object diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index 0e6ea9a54a0a..1fe1d0deed01 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -66,6 +66,8 @@ class MarkPaid extends AbstractService 'amount' => $payment->amount, ]); + $this->invoice->next_send_date = null; + $this->invoice->service() ->updateBalance($payment->amount * -1) ->setStatus(Invoice::STATUS_PAID) diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index f74dd3cfe590..6d18c5dd9d26 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -19,9 +19,12 @@ use App\Repositories\QuoteRepository; use App\Services\Quote\CreateInvitations; use App\Services\Quote\GetQuotePdf; use App\Utils\Ninja; +use App\Utils\Traits\MakesHash; class QuoteService { + use MakesHash; + protected $quote; public $invoice; @@ -158,6 +161,23 @@ class QuoteService return true; } + public function fillDefaults() + { + $settings = $this->quote->client->getMergedSettings(); + + if(! $this->quote->design_id) + $this->quote->design_id = $this->decodePrimaryKey($settings->quote_design_id); + + if(!isset($this->quote->footer)) + $this->quote->footer = $settings->quote_footer; + + if(!isset($this->quote->terms)) + $this->quote->terms = $settings->quote_terms; + + + return $this; + } + /** * Saves the quote. * @return Quote|null diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 4c33bf564fd6..9eae2077ff07 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -311,7 +311,11 @@ class HtmlEngine $data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; - $data['$contact.signature'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')]; + + if($this->settings->signature_on_pdf) + $data['$contact.signature'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')]; + else + $data['$contact.signature'] = ['value' => '', 'label' => '']; $data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')]; $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; diff --git a/app/Utils/Traits/MakesReminders.php b/app/Utils/Traits/MakesReminders.php index 7efe062e157b..9754573b401a 100644 --- a/app/Utils/Traits/MakesReminders.php +++ b/app/Utils/Traits/MakesReminders.php @@ -186,6 +186,9 @@ trait MakesReminders //if invoice is currently a draft, or being marked as sent, this will be the initial email $client = $this->client; + if($entity_string != 'invoice') + return $entity_string; + //if the invoice if ($client->getSetting('enable_reminder1') !== false && $this->inReminderWindow( $client->getSetting('schedule_reminder1'), diff --git a/config/l5-swagger.php b/config/l5-swagger.php new file mode 100644 index 000000000000..b97581cdb9dd --- /dev/null +++ b/config/l5-swagger.php @@ -0,0 +1,198 @@ + 'default', + 'documentations' => [ + 'default' => [ + 'api' => [ + 'title' => 'L5 Swagger UI', + ], + + 'routes' => [ + /* + * Route for accessing api documentation interface + */ + 'api' => 'api/documentation', + ], + 'paths' => [ + /* + * File name of the generated json documentation file + */ + 'docs_json' => 'api-docs.json', + + /* + * File name of the generated YAML documentation file + */ + 'docs_yaml' => 'api-docs.yaml', + + /* + * Absolute paths to directory containing the swagger annotations are stored. + */ + 'annotations' => [ + base_path('app'), + ], + + ], + ], + ], + 'defaults' => [ + 'routes' => [ + /* + * Route for accessing parsed swagger annotations. + */ + 'docs' => 'docs', + + /* + * Route for Oauth2 authentication callback. + */ + 'oauth2_callback' => 'api/oauth2-callback', + + /* + * Middleware allows to prevent unexpected access to API documentation + */ + 'middleware' => [ + 'api' => [], + 'asset' => [], + 'docs' => [], + 'oauth2_callback' => [], + ], + + /* + * Route Group options + */ + 'group_options' => [], + ], + + 'paths' => [ + /* + * Absolute path to location where parsed annotations will be stored + */ + 'docs' => storage_path('api-docs'), + + /* + * Absolute path to directory where to export views + */ + 'views' => base_path('resources/views/vendor/l5-swagger'), + + /* + * Edit to set the api's base path + */ + 'base' => env('L5_SWAGGER_BASE_PATH', null), + + /* + * Edit to set path where swagger ui assets should be stored + */ + 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), + + /* + * Absolute path to directories that should be exclude from scanning + */ + 'excludes' => [], + ], + + /* + * API security definitions. Will be generated into documentation file. + */ + 'securityDefinitions' => [ + 'securitySchemes' => [ + /* + * Examples of Security schemes + */ + /* + 'api_key_security_example' => [ // Unique name of security + 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for security scheme', + 'name' => 'api_key', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + 'oauth2_security_example' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for oauth2 security scheme.', + 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". + 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) + //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) + 'scopes' => [ + 'read:projects' => 'read your projects', + 'write:projects' => 'modify projects in your account', + ] + ], + */ + + /* Open API 3.0 support + 'passport' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Laravel passport oauth2 security.', + 'in' => 'header', + 'scheme' => 'https', + 'flows' => [ + "password" => [ + "authorizationUrl" => config('app.url') . '/oauth/authorize', + "tokenUrl" => config('app.url') . '/oauth/token', + "refreshUrl" => config('app.url') . '/token/refresh', + "scopes" => [] + ], + ], + ], + */ + ], + 'security' => [ + /* + * Examples of Securities + */ + [ + /* + 'oauth2_security_example' => [ + 'read', + 'write' + ], + + 'passport' => [] + */ + ], + ], + ], + + /* + * Set this to `true` in development mode so that docs would be regenerated on each request + * Set this to `false` to disable swagger generation on production + */ + 'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false), + + /* + * Set this to `true` to generate a copy of documentation in yaml format + */ + 'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false), + + /* + * Edit to trust the proxy's ip address - needed for AWS Load Balancer + * string[] + */ + 'proxy' => false, + + /* + * Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle. + * See more at: https://github.com/swagger-api/swagger-ui#configs-plugin + */ + 'additional_config_url' => null, + + /* + * Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), + * 'method' (sort by HTTP method). + * Default is the order returned by the server unchanged. + */ + 'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null), + + /* + * Pass the validatorUrl parameter to SwaggerUi init on the JS side. + * A null value here disables validation. + */ + 'validator_url' => null, + + /* + * Uncomment to add constants which can be used in annotations + */ + // 'constants' => [ + // 'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'), + // ], + ], +]; diff --git a/resources/views/vendor/l5-swagger/.gitkeep b/resources/views/vendor/l5-swagger/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/resources/views/vendor/l5-swagger/index.blade.php b/resources/views/vendor/l5-swagger/index.blade.php new file mode 100644 index 000000000000..c35050391d72 --- /dev/null +++ b/resources/views/vendor/l5-swagger/index.blade.php @@ -0,0 +1,106 @@ + + + + + + {{config('l5-swagger.documentations.'.$documentation.'.api.title')}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/routes/api.php b/routes/api.php index f30d1641e138..7c3fe0989a83 100644 --- a/routes/api.php +++ b/routes/api.php @@ -35,6 +35,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::resource('invoices', 'InvoiceController'); // name = (invoices. index / create / show / update / destroy / edit + Route::get('invoices/{invoice}/delivery_note', 'InvoiceController@deliveryNote')->name('invoices.delivery_note'); + Route::get('invoices/{invoice}/{action}', 'InvoiceController@action')->name('invoices.action'); Route::get('invoice/{invitation_key}/download', 'InvoiceController@downloadPdf')->name('invoices.downloadPdf'); diff --git a/tests/Unit/GroupTest.php b/tests/Unit/GroupTest.php index c15edf39c126..e417e478fe1e 100644 --- a/tests/Unit/GroupTest.php +++ b/tests/Unit/GroupTest.php @@ -29,7 +29,7 @@ class GroupTest extends TestCase public function testGroupsPropertiesExistsResponses() { - $this->assertTrue(property_exists($this->settings, 'design')); + $this->assertTrue(property_exists($this->settings, 'timezone_id')); } public function testPropertyValueAccessors()