Merge pull request #8219 from turbo124/v5-stable

v5.5.64
This commit is contained in:
David Bomba 2023-01-28 15:46:02 +11:00 committed by GitHub
commit c7fb814bb3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 120979 additions and 120161 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,7 +126,8 @@ class CheckData extends Command
$this->checkVendorSettings();
$this->checkClientSettings();
$this->checkCompanyTokens();
$this->checkUserState();
if(Ninja::isHosted()){
$this->checkAccountStatuses();
$this->checkNinjaPortalUrls();
@ -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,7 +33,8 @@ class HtmlEngine
{
use MakesDates;
use AppSetup;
use MakesHash;
public $entity;
public $invitation;
@ -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

@ -4,8 +4,8 @@ const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
"flutter.js": "f85e6fb278b0fd20c349186fb46ae36d",
"/": "0626f533f39f1481608bb9467f56daaf",
"main.dart.js": "16a58ed772159e59430f6c95e14416da",
"/": "097f1c4aea4e9afd3db72582b1c2170b",
"main.dart.js": "6cb186c8a46251a56fde6f0120c64876",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",

118024
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

121452
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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.