Merge pull request #8218 from turbo124/v5-develop

Additional docs for mailers
This commit is contained in:
David Bomba 2023-01-28 15:43:59 +11:00 committed by GitHub
commit 8706d5a382
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 539 additions and 42 deletions

View File

@ -15,9 +15,10 @@ https://invoiceninja.github.io/docs/self-host-troubleshooting/ -->
- Environment: <!-- Docker/Shared Hosting/ZIP/Other -->
## Checklist
- Can you replicate the issue on our v5 demo site https://demo.invoiceninja.com pr https://react.invoicing.co/demo?
- Can you replicate the issue on our v5 demo site https://demo.invoiceninja.com or https://react.invoicing.co/demo?
- Have you searched existing issues?
- Have you reported this to Slack/forum before posting?
- Have you inspected the logs in storage/logs/laravel.log for any errors?
## Describe the bug
<!-- A clear and concise description of the bug. -->

View File

@ -1 +1 @@
5.5.63
5.5.64

View File

@ -126,6 +126,7 @@ class CheckData extends Command
$this->checkVendorSettings();
$this->checkClientSettings();
$this->checkCompanyTokens();
$this->checkUserState();
if(Ninja::isHosted()){
$this->checkAccountStatuses();
@ -414,6 +415,16 @@ class CheckData extends Command
}
}
private function checkUserState()
{
User::withTrashed()
->where('deleted_at', '0000-00-00 00:00:00.000000')
->cursor()
->each(function ($user){
$user->restore();
});
}
private function checkEntityInvitations()
{

View File

@ -229,7 +229,7 @@ class CompanySettings extends BaseSettings
public $require_quote_signature = false; //@TODO ben to confirm
//email settings
public $email_sending_method = 'default'; //enum 'default','gmail','office365' //@implemented
public $email_sending_method = 'default'; //enum 'default','gmail','office365' 'client_postmark', 'client_mailgun'//@implemented
public $gmail_sending_user_id = '0'; //@implemented
@ -453,9 +453,15 @@ class CompanySettings extends BaseSettings
public $show_email_footer = true;
public $company_logo_size = '65%';
public $company_logo_size = '';
public $show_paid_stamp = false;
public $show_shipping_address = false;
public static $casts = [
'show_paid_stamp' => 'bool',
'show_shipping_address' => 'bool',
'company_logo_size' => 'string',
'show_email_footer' => 'bool',
'email_alignment' => 'string',

View File

@ -267,7 +267,7 @@ class BaseController extends Controller
$updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0;
if ($user->getCompany()->is_large && $updated_at == 0) {
if ($user->getCompany()->is_large && $updated_at == 0 && $this->complexPermissionsUser()) {
$updated_at = time();
}
@ -613,11 +613,27 @@ class BaseController extends Controller
return $this->response($this->manager->createData($resource)->toArray());
}
/**
* In case a user is not an admin and is
* able to access multiple companies, then we
* need to pass back the mini load only
*
* @return bool
*/
private function complexPermissionsUser(): bool
{
//if the user is attached to more than one company AND they are not an admin across all companies
if(auth()->user()->company_users()->count() > 1 && (auth()->user()->company_users()->where('is_admin',1)->count() != auth()->user()->company_users()->count()))
return true;
return false;
}
protected function timeConstrainedResponse($query)
{
$user = auth()->user();
if ($user->getCompany()->is_large) {
if ($user->getCompany()->is_large || $this->complexPermissionsUser()) {
$this->manager->parseIncludes($this->mini_load);
return $this->miniLoadResponse($query);

View File

@ -218,7 +218,7 @@ class NinjaPlanController extends Controller
if ($account) {
//offer the option to have a free trial
if (!$account->is_trial) {
if (!$account->plan && !$account->is_trial) {
return $this->trial();
}

View File

@ -16,12 +16,14 @@ use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory;
use App\Factory\QuoteFactory;
use App\Factory\RecurringInvoiceFactory;
use App\Http\Requests\Preview\DesignPreviewRequest;
use App\Http\Requests\Preview\PreviewInvoiceRequest;
use App\Jobs\Util\PreviewPdf;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Credit;
use App\Models\GroupSetting;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Quote;
@ -30,9 +32,9 @@ use App\Repositories\CreditRepository;
use App\Repositories\InvoiceRepository;
use App\Repositories\QuoteRepository;
use App\Repositories\RecurringInvoiceRepository;
use App\Services\PdfMaker\Design;
use App\Services\PdfMaker\Design as PdfDesignModel;
use App\Services\PdfMaker\Design as PdfMakerDesign;
use App\Services\PdfMaker\Design;
use App\Services\PdfMaker\PdfMaker;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\HtmlEngine;
@ -173,8 +175,178 @@ class PreviewController extends BaseController
return $this->blankEntity();
}
public function design(DesignPreviewRequest $request)
{
if(Ninja::isHosted() && $request->getHost() != 'preview.invoicing.co')
return response()->json(['message' => 'This server cannot handle this request.'], 400);
$company = auth()->user()->company();
MultiDB::setDb($company->db);
if ($request->input('entity') == 'quote') {
$repo = new QuoteRepository();
$entity_obj = QuoteFactory::create($company->id, auth()->user()->id);
$class = Quote::class;
} elseif ($request->input('entity') == 'credit') {
$repo = new CreditRepository();
$entity_obj = CreditFactory::create($company->id, auth()->user()->id);
$class = Credit::class;
} elseif ($request->input('entity') == 'recurring_invoice') {
$repo = new RecurringInvoiceRepository();
$entity_obj = RecurringInvoiceFactory::create($company->id, auth()->user()->id);
$class = RecurringInvoice::class;
} else { //assume it is either an invoice or a null object
$repo = new InvoiceRepository();
$entity_obj = InvoiceFactory::create($company->id, auth()->user()->id);
$class = Invoice::class;
}
try {
DB::connection(config('database.default'))->beginTransaction();
if ($request->has('entity_id')) {
$entity_obj = $class::on(config('database.default'))
->with('client.company')
->where('id', $this->decodePrimaryKey($request->input('entity_id')))
->where('company_id', $company->id)
->withTrashed()
->first();
}
if($request->has('client_id')) {
$client = Client::withTrashed()->find($this->decodePrimaryKey($request->client_id));
if($request->settings_type == 'client'){
$client->settings = $request->settings;
$client->save();
}
}
if($request->has('group_id')) {
$group = GroupSetting::withTrashed()->find($this->decodePrimaryKey($request->group_id));
if($request->settings_type == 'group'){
$group->settings = $request->settings;
$group->save();
}
}
if($request->settings_type == 'company'){
$company->settings = $request->settings;
$company->save();
}
if($request->has('footer') && !$request->filled('footer') && $request->input('entity') == 'recurring_invoice')
$request->merge(['footer' => $company->settings->invoice_footer]);
if($request->has('terms') && !$request->filled('terms') && $request->input('entity') == 'recurring_invoice')
$request->merge(['terms' => $company->settings->invoice_terms]);
$entity_obj = $repo->save($request->all(), $entity_obj);
if (! $request->has('entity_id')) {
$entity_obj->service()->fillDefaults()->save();
}
App::forgetInstance('translator');
$t = app('translator');
App::setLocale($entity_obj->client->locale());
$t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
$html = new HtmlEngine($entity_obj->invitations()->first());
$design = \App\Models\Design::find($entity_obj->design_id);
/* Catch all in case migration doesn't pass back a valid design */
if (! $design) {
$design = \App\Models\Design::find(2);
}
if ($design->is_custom) {
$options = [
'custom_partials' => json_decode(json_encode($design->design), true),
];
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
} else {
$template = new PdfMakerDesign(strtolower($design->name));
}
$variables = $html->generateLabelsAndValues();
$state = [
'template' => $template->elements([
'client' => $entity_obj->client,
'entity' => $entity_obj,
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
'$product' => $design->design->product,
'variables' => $variables,
]),
'variables' => $variables,
'options' => [
'all_pages_header' => $entity_obj->client->getSetting('all_pages_header'),
'all_pages_footer' => $entity_obj->client->getSetting('all_pages_footer'),
],
'process_markdown' => $entity_obj->client->company->markdown_enabled,
];
$maker = new PdfMaker($state);
$maker
->design($template)
->build();
DB::connection(config('database.default'))->rollBack();
if (request()->query('html') == 'true') {
nlog($maker->getCompiledHTML());
return $maker->getCompiledHTML();
}
}
catch(\Exception $e){
nlog($e->getMessage());
DB::connection(config('database.default'))->rollBack();
return;
}
//if phantom js...... inject here..
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
}
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
$numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
if ($numbered_pdf) {
$pdf = $numbered_pdf;
}
return $pdf;
}
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), $company))->handle();
$response = Response::make($file_path, 200);
$response->header('Content-Type', 'application/pdf');
return $response;
}
public function live(PreviewInvoiceRequest $request)
{
if(Ninja::isHosted() && $request->getHost() != 'preview.invoicing.co')
return response()->json(['message' => 'This server cannot handle this request.'], 400);
$company = auth()->user()->company();
MultiDB::setDb($company->db);

View File

@ -72,9 +72,7 @@ class ProfitAndLossController extends BaseController
// expect a list of visible fields, or use the default
$pnl = new ProfitLoss(auth()->user()->company(), $request->all());
$pnl->build();
$csv = $pnl->getCsv();
$csv = $pnl->run();
$headers = [
'Content-Disposition' => 'attachment',

View File

@ -0,0 +1,71 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\Preview;
use App\Http\Requests\Request;
use App\Http\ValidationRules\Project\ValidProjectForClient;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\PurchaseOrder;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Utils\Traits\CleanLineItems;
use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule;
class DesignPreviewRequest extends Request
{
use MakesHash;
use CleanLineItems;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('create', Invoice::class) ||
auth()->user()->can('create', Quote::class) ||
auth()->user()->can('create', RecurringInvoice::class) ||
auth()->user()->can('create', Credit::class) ||
auth()->user()->can('create', PurchaseOrder::class);
}
public function rules()
{
$rules = [
'entity' => 'bail|sometimes|string',
'entity_id' => 'bail|sometimes|string',
'settings_type' => 'bail|required|in:company,group,client',
'settings' => 'sometimes',
'group_id' => 'sometimes',
'client_id' => 'sometimes',
];
return $rules;
}
public function prepareForValidation()
{
$input = $this->all();
$input = $this->decodePrimaryKeys($input);
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
$input['amount'] = 0;
$input['balance'] = 0;
$input['number'] = ctrans('texts.live_preview').' #'.rand(0, 1000);
$this->replace($input);
}
}

View File

@ -28,8 +28,10 @@ class StoreWebhookRequest extends Request
public function rules()
{
return [
'target_url' => 'required|url',
'event_id' => 'required',
'target_url' => 'bail|required|url',
'event_id' => 'bail|required',
'headers' => 'bail|sometimes|json',
'rest_method' => 'required|in:post,put'
];
}
@ -37,6 +39,9 @@ class StoreWebhookRequest extends Request
{
$input = $this->all();
if(isset($input['headers']) && count($input['headers']) == 0)
$input['headers'] = null;
$this->replace($input);
}
}

View File

@ -27,13 +27,16 @@ class UpdateWebhookRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->isAdmin();
return auth()->user()->can('edit', $this->webhook);
}
public function rules()
{
return [
'target_url' => 'url',
'target_url' => 'bail|required|url',
'event_id' => 'bail|required',
'rest_method' => 'required|in:post,put',
'headers' => 'bail|sometimes|json',
];
}
@ -41,6 +44,9 @@ class UpdateWebhookRequest extends Request
{
$input = $this->all();
if(isset($input['headers']) && count($input['headers']) == 0)
$input['headers'] = null;
$this->replace($input);
}
}

View File

@ -508,7 +508,7 @@ class CompanyImport implements ShouldQueue
if(Ninja::isHosted())
{
$this->company->portal_mode = 'sub_domain';
$this->company->portal_mode = 'subdomain';
$this->company->portal_domain = '';
}

View File

@ -11,9 +11,22 @@
namespace App\Policies;
use App\Models\User;
/**
* Class WebhookPolicy.
*/
class WebhookPolicy extends EntityPolicy
{
/**
* Checks if the user has create permissions.
*
* @param User $user
* @return bool
*/
public function create(User $user) : bool
{
return $user->isAdmin();
}
}

View File

@ -94,6 +94,11 @@ class ProfitLoss
$this->setBillingReportType();
}
public function run()
{
return $this->build()->getCsv();
}
public function build()
{
MultiDB::setDb($this->company->db);

View File

@ -24,6 +24,7 @@ use App\Utils\Ninja;
use App\Utils\Number;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Exception;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
@ -32,6 +33,7 @@ class HtmlEngine
{
use MakesDates;
use AppSetup;
use MakesHash;
public $entity;
@ -98,6 +100,56 @@ class HtmlEngine
}
}
private function resolveCompanyLogoSize()
{
$design_map = [
"VolejRejNm" => "65%", // "Plain",
"Wpmbk5ezJn" => "65%", //"Clean",
"Opnel5aKBz" => "65%", //"Bold",
"wMvbmOeYAl" => "55%", //Modern",
"4openRe7Az" => "65%", //"Business",
"WJxbojagwO" => "65%", //"Creative",
"k8mep2bMyJ" => "55%", //"Elegant",
"l4zbq2dprO" => "65%", //"Hipster",
"yMYerEdOBQ" => "65%", //"Playful",
"gl9avmeG1v" => "65%", //"Tech",
"7LDdwRb1YK" => "65%", //"Calm",
"APdRoy0eGy" => "65%", //"Calm-DB2",
"y1aK83rbQG" => "65%", //"Calm-DB1",
];
$design_int_map = [
"1" => "65%", // "Plain",
"2" => "65%", //"Clean",
"3" => "65%", //"Bold",
"4" => "55%", //Modern",
"5" => "65%", //"Business",
"6" => "65%", //"Creative",
"7" => "55%", //"Elegant",
"8" => "65%", //"Hipster",
"9" => "65%", //"Playful",
"10" => "65%", //"Tech",
"11" => "65%", //"Calm",
"6972" => "65%", //"C-DB2"
"11221" => "65%", //"C-DB1"
];
if(isset($this->settings->company_logo_size) && strlen($this->settings->company_logo_size) > 1)
return $this->settings->company_logo_size;
if($this->entity->design_id && array_key_exists($this->entity->design_id, $design_int_map))
return $design_int_map[$this->entity->design_id];
$default_design_id = $this->entity_string."_design_id";
$design_id = $this->settings->{$default_design_id};
if(array_key_exists($design_id, $design_map))
return $design_map[$design_id];
return '65%';
}
public function buildEntityDataArray() :array
{
if (! $this->client->currency()) {
@ -111,8 +163,9 @@ class HtmlEngine
$t->replace(Ninja::transformTranslations($this->settings));
$data = [];
//$data['<html>'] = ['value' => '<html dir="rtl">', 'label' => ''];
$data['$global_margin'] = ['value' => '6.35mm', 'label' => ''];
$data['$company_logo_size'] = ['value' => $this->resolveCompanyLogoSize(), 'label' => ''];
$data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
$data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => ''];
$data['$from'] = ['value' => '', 'label' => ctrans('texts.from')];

View File

@ -584,6 +584,12 @@ trait GeneratesCounter
$settings->invoice_number_counter = 1;
$settings->quote_number_counter = 1;
$settings->credit_number_counter = 1;
$settings->ticket_number_counter = 1;
$settings->payment_number_counter = 1;
$settings->project_number_counter = 1;
$settings->task_number_counter = 1;
$settings->expense_number_counter = 1;
$settings->recurring_expense_number_counter = 1;
$settings->purchase_order_number_counter = 1;
$client->company->settings = $settings;
@ -600,48 +606,67 @@ trait GeneratesCounter
return false;
}
switch ($company->reset_counter_frequency_id) {
$settings = $company->settings;
$reset_counter_frequency = (int) $settings->reset_counter_frequency_id;
if ($reset_counter_frequency == 0) {
if($settings->reset_counter_date){
$settings->reset_counter_date = "";
$company->settings = $settings;
$company->save();
}
return;
}
switch ($reset_counter_frequency) {
case RecurringInvoice::FREQUENCY_DAILY:
$reset_date->addDay();
$new_reset_date = $reset_date->addDay();
break;
case RecurringInvoice::FREQUENCY_WEEKLY:
$reset_date->addWeek();
$new_reset_date = $reset_date->addWeek();
break;
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
$reset_date->addWeeks(2);
$new_reset_date = $reset_date->addWeeks(2);
break;
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
$reset_date->addWeeks(4);
$new_reset_date = $reset_date->addWeeks(4);
break;
case RecurringInvoice::FREQUENCY_MONTHLY:
$reset_date->addMonth();
$new_reset_date = $reset_date->addMonth();
break;
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
$reset_date->addMonths(2);
$new_reset_date = $reset_date->addMonths(2);
break;
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
$reset_date->addMonths(3);
$new_reset_date = $reset_date->addMonths(3);
break;
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
$reset_date->addMonths(4);
$new_reset_date = $reset_date->addMonths(4);
break;
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
$reset_date->addMonths(6);
$new_reset_date = $reset_date->addMonths(6);
break;
case RecurringInvoice::FREQUENCY_ANNUALLY:
$reset_date->addYear();
$new_reset_date = $reset_date->addYear();
break;
case RecurringInvoice::FREQUENCY_TWO_YEARS:
$reset_date->addYears(2);
$new_reset_date = $reset_date->addYears(2);
break;
default:
$new_reset_date = $reset_date->addYear();
break;
}
$settings = $company->settings;
$settings->reset_counter_date = $reset_date->format('Y-m-d');
$settings->reset_counter_date = $new_reset_date->format('Y-m-d');
$settings->invoice_number_counter = 1;
$settings->quote_number_counter = 1;
$settings->credit_number_counter = 1;
$settings->vendor_number_counter = 1;
$settings->ticket_number_counter = 1;
$settings->payment_number_counter = 1;
$settings->project_number_counter = 1;

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.63',
'app_tag' => '5.5.63',
'app_version' => '5.5.64',
'app_tag' => '5.5.64',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
\Illuminate\Support\Facades\Artisan::call('ninja:design-update');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -4951,6 +4951,7 @@ $LANG = array(
'notify_vendor_when_paid_help' => 'Send an email to the vendor when the expense is marked as paid',
'update_payment' => 'Update Payment',
'markup' => 'Markup',
'unlock_pro' => 'Unlock Pro',
);

View File

@ -59,6 +59,7 @@
.company-logo {
height: 100%;
max-width: 100%;
/* max-width: $company_logo_size;*/
object-fit: contain;
object-position: left center;
}

View File

@ -41,6 +41,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.header-container > span {

View File

@ -47,6 +47,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.client-and-entity-wrapper {

View File

@ -23,7 +23,7 @@
@page {
margin-left: $global_margin;
margin-right: $global_margin;
margin-top: 0;
margin-top: 5;
margin-bottom: 0;
size: $page_size $page_layout;
}
@ -53,6 +53,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
#company-details {
@ -164,7 +165,7 @@
padding-top: .5rem;
padding-right: 1rem;
gap: 80px;
page-break-inside:auto;
page-break-inside:avoid;
overflow: visible !important;
}

View File

@ -42,6 +42,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
#entity-details p { margin-top: 5px; }

View File

@ -32,6 +32,7 @@
.company-logo {
max-width: 55%;
/* max-width: $company_logo_size;*/
margin-left: auto;
margin-right: auto;
display: block;

View File

@ -81,6 +81,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.entity-label {

View File

@ -85,6 +85,7 @@
.company-logo {
max-width: 55%;
/* max-width: $company_logo_size;*/
}
#client-details {

View File

@ -42,6 +42,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.header-wrapper #company-address {

View File

@ -63,6 +63,7 @@
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.contacts-wrapper {

View File

@ -63,10 +63,12 @@
.company-logo-wrapper {
padding-bottom: 60px;
height: 5rem;
}
.company-logo-wrapper {
height: 5rem;
.company-logo {
max-width: 65%;
/* max-width: $company_logo_size;*/
}
.header-invoice-number {

View File

@ -103,7 +103,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_secret_check']], function
Route::post('api/v1/oauth_login', [LoginController::class, 'oauthApiLogin']);
});
Route::group(['middleware' => ['throttle:10,1','api_secret_check','email_db']], function () {
Route::group(['middleware' => ['throttle:50,1','api_secret_check','email_db']], function () {
Route::post('api/v1/login', [LoginController::class, 'apiLogin'])->name('login.submit')->middleware('throttle:20,1');
Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail']);
});
@ -228,6 +228,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale
Route::post('preview', [PreviewController::class, 'show'])->name('preview.show');
Route::post('live_preview', [PreviewController::class, 'live'])->name('preview.live');
Route::post('live_design', [PreviewController::class, 'design'])->name('preview.design');
Route::post('preview/purchase_order', [PreviewPurchaseOrderController::class, 'show'])->name('preview_purchase_order.show');
Route::post('live_preview/purchase_order', [PreviewPurchaseOrderController::class, 'live'])->name('preview_purchase_order.live');

View File

@ -46,6 +46,7 @@ class DesignApiTest extends TestCase
public function testDesignPost()
{
$design = [
'body' => 'body',
'includes' => 'includes',

View File

@ -0,0 +1,62 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
* @covers App\Http\Controllers\PreviewController
*/
class LiveDesignTest extends TestCase
{
use DatabaseTransactions;
use MockAccountData;
protected function setUp() :void
{
parent::setUp();
$this->makeTestData();
$this->withoutMiddleware(
ThrottleRequests::class
);
if (config('ninja.testvars.travis') !== false) {
$this->markTestSkipped('Skip test for Travis');
}
}
public function testDesignRoute200()
{
$data = [
'entity' => 'invoice',
'entity_id' => $this->invoice->hashed_id,
'settings_type' => 'company',
'settings' => (array)$this->company->settings,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/live_design/', $data);
$response->assertStatus(200);
}
}

View File

@ -308,13 +308,15 @@ class RecurringInvoiceTest extends TestCase
public function testRecurringDatePassesToInvoice()
{
$noteText = "Hello this is for :MONTH_AFTER";
$recurringDate = \Carbon\Carbon::now()->subDays(10);
$recurringDate = \Carbon\Carbon::now()->timezone($this->client->timezone()->name)->subDays(10);
$item = InvoiceItemFactory::create();
$item->cost = 10;
$item->notes = $noteText;
$recurring_invoice = InvoiceToRecurringInvoiceFactory::create($this->invoice);
$recurring_invoice->user_id = $this->user->id;
$recurring_invoice->next_send_date = $recurringDate;
$recurring_invoice->status_id = RecurringInvoice::STATUS_ACTIVE;

View File

@ -70,6 +70,7 @@ class WebhookAPITest extends TestCase
$data = [
'target_url' => 'http://hook.com',
'event_id' => 1,
'rest_method' => 'post',
'format' => 'JSON',
];
@ -85,7 +86,10 @@ class WebhookAPITest extends TestCase
$this->assertEquals(1, $arr['data']['event_id']);
$data = [
'target_url' => 'http://hook.com',
'event_id' => 2,
'rest_method' => 'post',
'format' => 'JSON',
];
$response = $this->withHeaders([

2
tests/cypress/screenshots/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
tests/cypress/videos/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

Binary file not shown.