Merge pull request #8568 from turbo124/v5-develop

v5.6.4
This commit is contained in:
David Bomba 2023-06-22 12:31:21 +10:00 committed by GitHub
commit 91d93dd1d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 320 additions and 50 deletions

View File

@ -1 +1 @@
5.6.3 5.6.4

View File

@ -61,11 +61,11 @@ class DesignFilters extends QueryFilters
*/ */
public function entityFilter(): Builder public function entityFilter(): Builder
{ {
//19-03-2023 change the scope for the design filters /** @var \App\Models\User $user */
return $this->builder->where(function ($query) { $user = auth()->user();
$query->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
// return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
return $this->builder->where(function ($query) use($user){
$query->where('company_id', $user->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
}); });
} }

View File

@ -204,6 +204,14 @@ class InvoiceFilters extends QueryFilters
return $this->builder; return $this->builder;
} }
if ($sort_col[0] == 'client_id') {
$this->builder->with(['client' => function($q) use($sort_col){
$q->orderBy('name', $sort_col[1]);
}]);
}
return $this->builder->orderBy($sort_col[0], $sort_col[1]); return $this->builder->orderBy($sort_col[0], $sort_col[1]);
} }

View File

@ -40,7 +40,10 @@ class PaymentFilters extends QueryFilters
->orWhere('custom_value1', 'like', '%'.$filter.'%') ->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%') ->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%') ->orWhere('custom_value3', 'like', '%'.$filter.'%')
->orWhere('custom_value4', 'like', '%'.$filter.'%'); ->orWhere('custom_value4', 'like', '%'.$filter.'%')
->orWhereHas('client', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%');
});
}); });
} }

View File

@ -34,10 +34,15 @@ class RecurringInvoiceFilters extends QueryFilters
} }
return $this->builder->where(function ($query) use ($filter) { return $this->builder->where(function ($query) use ($filter) {
$query->where('recurring_invoices.custom_value1', 'like', '%'.$filter.'%') $query->where('date', 'like', '%'.$filter.'%')
->orWhere('recurring_invoices.custom_value2', 'like', '%'.$filter.'%') ->orWhere('amount', 'like', '%'.$filter.'%')
->orWhere('recurring_invoices.custom_value3', 'like', '%'.$filter.'%') ->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('recurring_invoices.custom_value4', 'like', '%'.$filter.'%'); ->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%')
->orWhere('custom_value4', 'like', '%'.$filter.'%')
->orWhereHas('client', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%');
});
}); });
} }

View File

@ -39,7 +39,13 @@ class TaskFilters extends QueryFilters
->orWhere('custom_value1', 'like', '%'.$filter.'%') ->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%') ->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%') ->orWhere('custom_value3', 'like', '%'.$filter.'%')
->orWhere('custom_value4', 'like', '%'.$filter.'%'); ->orWhere('custom_value4', 'like', '%'.$filter.'%')
->orWhereHas('project', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%');
})
->orWhereHas('client', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%');
});
}); });
} }

View File

@ -165,7 +165,6 @@ class InvoiceSum
{ {
if (! isset($this->invoice->id) && isset($this->invoice->partial)) { if (! isset($this->invoice->id) && isset($this->invoice->partial)) {
$this->invoice->partial = max(0, min(Number::roundValue($this->invoice->partial, 2), $this->invoice->balance)); $this->invoice->partial = max(0, min(Number::roundValue($this->invoice->partial, 2), $this->invoice->balance));
// $this->invoice->partial = max(0, min($this->formatValue($this->invoice->partial, 2), $this->invoice->balance));
} }
return $this; return $this;

View File

@ -11,12 +11,13 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\CompanyUser\UpdateCompanyUserRequest;
use App\Models\CompanyUser;
use App\Models\User; use App\Models\User;
use App\Models\CompanyUser;
use Illuminate\Http\Response;
use App\Transformers\CompanyUserTransformer; use App\Transformers\CompanyUserTransformer;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Response; use App\Http\Requests\CompanyUser\UpdateCompanyUserRequest;
use App\Http\Requests\CompanyUser\UpdateCompanyUserPreferencesRequest;
class CompanyUserController extends BaseController class CompanyUserController extends BaseController
{ {
@ -131,6 +132,24 @@ class CompanyUserController extends BaseController
return $this->itemResponse($company_user->fresh()); return $this->itemResponse($company_user->fresh());
} }
public function updatePreferences(UpdateCompanyUserPreferencesRequest $request, User $user)
{
$company = auth()->user()->company();
$company_user = CompanyUser::whereUserId($user->id)->whereCompanyId($company->id)->first();
if (! $company_user) {
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
return;
}
$company_user->react_settings = $request->react_settings;
$company_user->save();
return $this->itemResponse($company_user->fresh());
}
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *

View File

@ -821,7 +821,14 @@ class InvoiceController extends BaseController
$contact = $invitation->contact; $contact = $invitation->contact;
$invoice = $invitation->invoice; $invoice = $invitation->invoice;
$file = $invoice->service()->getInvoicePdf($contact); // $file = $invoice->service()->getInvoicePdf($contact);
/************** */
$file_name = $invoice->numberFormatter().'.pdf';
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle();
/************* */
$headers = ['Content-Type' => 'application/pdf']; $headers = ['Content-Type' => 'application/pdf'];
@ -830,8 +837,8 @@ class InvoiceController extends BaseController
} }
return response()->streamDownload(function () use ($file) { return response()->streamDownload(function () use ($file) {
echo Storage::get($file); echo $file;
}, basename($file), $headers); }, $file_name, $headers);
} }
/** /**

View File

@ -58,7 +58,11 @@ class PasswordProtection
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout); Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
return $next($request); return $next($request);
} elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >=1) { }
elseif(strlen(auth()->user()->oauth_provider_id) > 2 && !auth()->user()->company()->oauth_password_required){
return $next($request);
}
elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >=1) {
//user is attempting to reauth with OAuth - check the token value //user is attempting to reauth with OAuth - check the token value
//todo expand this to include all OAuth providers //todo expand this to include all OAuth providers
if (auth()->user()->oauth_provider_id == 'google') { if (auth()->user()->oauth_provider_id == 'google') {

View File

@ -0,0 +1,37 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\CompanyUser;
use App\Http\Requests\Request;
use App\Utils\Traits\MakesHash;
class UpdateCompanyUserPreferencesRequest extends Request
{
use MakesHash;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->id == $this->user->id;
}
public function rules()
{
return [
'react_settings' => 'required'
];
}
}

View File

@ -59,6 +59,8 @@ class StorePurchaseOrderRequest extends Request
$rules['file'] = $this->file_validation; $rules['file'] = $this->file_validation;
} }
$rules['status_id'] = 'nullable|integer|in:1,2,3,4,5';
return $rules; return $rules;
} }

View File

@ -62,6 +62,8 @@ class UpdatePurchaseOrderRequest extends Request
$rules['file'] = $this->file_validation; $rules['file'] = $this->file_validation;
} }
$rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5';
return $rules; return $rules;
} }

View File

@ -95,6 +95,14 @@ class StoreTaskRequest extends Request
} }
} }
if (isset($input['project_id']) && isset($input['client_id'])) {
$search_project_with_client = Project::withTrashed()->where('id', $input['project_id'])->where('client_id', $input['client_id'])->company()->doesntExist();
if ($search_project_with_client) {
unset($input['project_id']);
}
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -104,6 +104,15 @@ class UpdateTaskRequest extends Request
$input['color'] = ''; $input['color'] = '';
} }
if(isset($input['project_id']) && isset($input['client_id'])){
$search_project_with_client = Project::withTrashed()->where('id', $input['project_id'])->where('client_id', $input['client_id'])->company()->doesntExist();
if($search_project_with_client){
unset($input['project_id']);
}
}
$this->replace($input); $this->replace($input);
} }

View File

@ -246,6 +246,15 @@ class BaseTransformer
->exists(); ->exists();
} }
public function hasClientIdNumber($id_number)
{
return Client::where('company_id', $this->company->id)
->where('is_deleted', false)
->where('id_number', trim($id_number))
->exists();
}
/** /**
* @param $name * @param $name
* *

View File

@ -27,7 +27,12 @@ class ClientTransformer extends BaseTransformer
*/ */
public function transform($data) public function transform($data)
{ {
if (isset($data['Company Name']) && $this->hasClient($data['Company Name'])) { $client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
if(isset($data[$client_id_proxy]) && $this->hasClientIdNumber($data[$client_id_proxy])) {
throw new ImportException('Client ID already exists => '. $data[$client_id_proxy]);
}
elseif (isset($data['Company Name']) && $this->hasClient($data['Company Name'])) {
throw new ImportException('Client already exists => '. $data['Company Name']); throw new ImportException('Client already exists => '. $data['Company Name']);
} }
@ -38,8 +43,6 @@ class ClientTransformer extends BaseTransformer
$settings->payment_terms = $data['Payment Terms']; $settings->payment_terms = $data['Payment Terms'];
} }
$client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
$data = [ $data = [
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'name' => $this->getString($data, 'Display Name'), 'name' => $this->getString($data, 'Display Name'),

View File

@ -123,7 +123,6 @@ class InvoiceTransformer extends BaseTransformer
return $client_id_search->first()->id; return $client_id_search->first()->id;
} }
$client_repository = app()->make(\App\Repositories\ClientRepository::class); $client_repository = app()->make(\App\Repositories\ClientRepository::class);
$client_repository->import_mode = true; $client_repository->import_mode = true;

View File

@ -356,6 +356,11 @@ class PaymentEmailEngine extends BaseEmailEngine
} }
if(strlen($invoice_list) < 4){
$invoice_list = Number::formatMoney($this->payment->amount, $this->client) ?: '&nbsp;';
}
return $invoice_list; return $invoice_list;
} }

View File

@ -76,6 +76,7 @@ class PaymentType extends StaticModel
const BACS = 49; const BACS = 49;
const STRIPE_BANK_TRANSFER = 50; const STRIPE_BANK_TRANSFER = 50;
const CASH_APP = 51; const CASH_APP = 51;
const VENMO = 24;
public array $type_names = [ public array $type_names = [
self::CREDIT => 'payment_type_Credit', self::CREDIT => 'payment_type_Credit',
@ -119,6 +120,7 @@ class PaymentType extends StaticModel
self::Interac_E_Transfer => 'payment_type_Interac E Transfer', self::Interac_E_Transfer => 'payment_type_Interac E Transfer',
self::STRIPE_BANK_TRANSFER => 'bank_transfer', self::STRIPE_BANK_TRANSFER => 'bank_transfer',
self::CASH_APP => 'payment_type_Cash App', self::CASH_APP => 'payment_type_Cash App',
self::VENMO => 'payment_type_Venmo',
]; ];
public static function parseCardType($cardName) public static function parseCardType($cardName)

View File

@ -243,7 +243,7 @@ class CreditService
public function triggeredActions($request) public function triggeredActions($request)
{ {
$this->invoice = (new TriggeredActions($this->credit, $request))->run(); $this->credit = (new TriggeredActions($this->credit, $request))->run();
return $this; return $this;
} }

View File

@ -61,6 +61,10 @@ class TriggeredActions extends AbstractService
$company->save(); $company->save();
} }
if ($this->request->has('mark_paid') && $this->request->input('mark_paid') == 'true') {
$this->credit->service()->markPaid()->save();
}
return $this->credit; return $this->credit;
} }

View File

@ -20,6 +20,8 @@ class GetInvoicePdf extends AbstractService
{ {
public $entity; public $entity;
public $contact;
public function __construct($entity, ClientContact $contact = null) public function __construct($entity, ClientContact $contact = null)
{ {
$this->entity = $entity; $this->entity = $entity;

View File

@ -297,9 +297,12 @@ class ProfitLoss
$amount_payment_paid += $pivot->amount - $pivot->refunded; $amount_payment_paid += $pivot->amount - $pivot->refunded;
$amount_payment_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1); $amount_payment_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
if ($invoice->amount > 0) {
$tax_amount += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
$tax_amount_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
}
$tax_amount += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
$tax_amount_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
} }
if ($pivot->paymentable_type == 'credits') { if ($pivot->paymentable_type == 'credits') {
@ -592,52 +595,50 @@ class ProfitLoss
case 'all': case 'all':
$this->start_date = now()->subYears(50); $this->start_date = now()->subYears(50);
$this->end_date = now(); $this->end_date = now();
// return $query; break;
// no break
case 'last7': case 'last7':
$this->start_date = now()->subDays(7); $this->start_date = now()->subDays(7);
$this->end_date = now(); $this->end_date = now();
// return $query->whereBetween($this->date_key, [now()->subDays(7), now()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'last30': case 'last30':
$this->start_date = now()->subDays(30); $this->start_date = now()->subDays(30);
$this->end_date = now(); $this->end_date = now();
// return $query->whereBetween($this->date_key, [now()->subDays(30), now()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'this_month': case 'this_month':
$this->start_date = now()->startOfMonth(); $this->start_date = now()->startOfMonth();
$this->end_date = now(); $this->end_date = now();
//return $query->whereBetween($this->date_key, [now()->startOfMonth(), now()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'last_month': case 'last_month':
$this->start_date = now()->startOfMonth()->subMonth(); $this->start_date = now()->startOfMonth()->subMonth();
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth(); $this->end_date = now()->startOfMonth()->subMonth()->endOfMonth();
//return $query->whereBetween($this->date_key, [now()->startOfMonth()->subMonth(), now()->startOfMonth()->subMonth()->endOfMonth()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'this_quarter': case 'this_quarter':
$this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter(); $this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter();
$this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter(); $this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter();
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-3 months'))->firstOfQuarter(), (new \Carbon\Carbon('-3 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'last_quarter': case 'last_quarter':
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter(); $this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter();
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter(); $this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter();
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-6 months'))->firstOfQuarter(), (new \Carbon\Carbon('-6 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'this_year': case 'this_year':
$this->start_date = now()->startOfYear(); $this->start_date = now()->startOfYear();
$this->end_date = now(); $this->end_date = now();
//return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC'); break;
// no break
case 'custom': case 'custom':
$this->start_date = $custom_start_date; $this->start_date = $custom_start_date;
$this->end_date = $custom_end_date; $this->end_date = $custom_end_date;
//return $query->whereBetween($this->date_key, [$custom_start_date, $custom_end_date])->orderBy($this->date_key, 'ASC'); break;
// no break
default: default:
$this->start_date = now()->startOfYear(); $this->start_date = now()->startOfYear();
$this->end_date = now(); $this->end_date = now();
// return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
} }
return $this; return $this;

View File

@ -132,7 +132,7 @@ class TaxProvider
'city' => $this->client->shipping_city, 'city' => $this->client->shipping_city,
'state' => $this->client->shipping_state, 'state' => $this->client->shipping_state,
'postal_code' => $this->client->shipping_postal_code, 'postal_code' => $this->client->shipping_postal_code,
'country' => $this->client->shipping_country->name, 'country' => $this->client?->shipping_country?->name,
]; ];
$taxable_address = $this->taxShippingAddress() ? $shipping_details : $billing_details; $taxable_address = $this->taxShippingAddress() ? $shipping_details : $billing_details;

View File

@ -102,7 +102,11 @@ class TemplateEngine
} elseif (stripos($this->template, 'purchase') !== false && $purchase_order = PurchaseOrder::whereHas('invitations')->withTrashed()->company()->first()) { } elseif (stripos($this->template, 'purchase') !== false && $purchase_order = PurchaseOrder::whereHas('invitations')->withTrashed()->company()->first()) {
$this->entity = 'purchase_order'; $this->entity = 'purchase_order';
$this->entity_obj = $purchase_order; $this->entity_obj = $purchase_order;
} elseif ($invoice = Invoice::whereHas('invitations')->withTrashed()->company()->first()) { }elseif (stripos($this->template, 'payment') !== false && $payment = Payment::withTrashed()->company()->first()) {
$this->entity = 'payment';
$this->entity_obj = $payment;
}
elseif ($invoice = Invoice::whereHas('invitations')->withTrashed()->company()->first()) {
$this->entity_obj = $invoice; $this->entity_obj = $invoice;
} else { } else {
$this->mockEntity(); $this->mockEntity();

View File

@ -116,6 +116,8 @@ trait MakesTemplateData
$data['$quote_total'] = ['value' => '$20.00', 'label' => ctrans('texts.quote_total')]; $data['$quote_total'] = ['value' => '$20.00', 'label' => ctrans('texts.quote_total')];
$data['$credit_amount'] = ['value' => '$15.00', 'label' => ctrans('texts.credit_amount')]; $data['$credit_amount'] = ['value' => '$15.00', 'label' => ctrans('texts.credit_amount')];
$data['$credit_balance'] = ['value' => '$12.00', 'label' => ctrans('texts.credit_balance')]; $data['$credit_balance'] = ['value' => '$12.00', 'label' => ctrans('texts.credit_balance')];
$data['$invoice_references'] = ['value' => 'Invoice #2222', 'label' => ctrans('texts.invoices')];
$data['$invoice_references_subject'] = ['value' => 'Invoice #2222', 'label' => ctrans('texts.invoices')];
$data['$credit_number'] = &$data['$number']; $data['$credit_number'] = &$data['$number'];
$data['$credit_no'] = &$data['$number']; $data['$credit_no'] = &$data['$number'];

View File

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

View File

@ -1446,7 +1446,7 @@ Ensure the default browser behavior of the `hidden` attribute.
<h2 class="text-[24px] font-bold leading-[1.5em] mb-[26px] relative md:text-[30px] md:mb-[46px]"> <h2 class="text-[24px] font-bold leading-[1.5em] mb-[26px] relative md:text-[30px] md:mb-[46px]">
Your Pro Plan trial is <br/>loaded and ready to go! Your Pro Plan trial is <br/>loaded and ready to go!
</h2> </h2>
<a href="https://invoicing.co" <a href="https://app.invoicing.co/#/"
type="button" type="button"
class="mx-[auto] max-w-[212px] bg-primary-blue hover:opacity-80 button button-primary bg-primary rounded-sm text-sm transition duration-300 ease-in md:mx-[0]" class="mx-[auto] max-w-[212px] bg-primary-blue hover:opacity-80 button button-primary bg-primary rounded-sm text-sm transition duration-300 ease-in md:mx-[0]"
> >

View File

@ -179,6 +179,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
Route::post('company_gateways/bulk', [CompanyGatewayController::class, 'bulk'])->name('company_gateways.bulk'); Route::post('company_gateways/bulk', [CompanyGatewayController::class, 'bulk'])->name('company_gateways.bulk');
Route::put('company_users/{user}', [CompanyUserController::class, 'update']); Route::put('company_users/{user}', [CompanyUserController::class, 'update']);
Route::put('company_users/{user}/preferences', [CompanyUserController::class, 'updatePreferences']);
Route::resource('credits', CreditController::class); // name = (credits. index / create / show / update / destroy / edit Route::resource('credits', CreditController::class); // name = (credits. index / create / show / update / destroy / edit
Route::put('credits/{credit}/upload', [CreditController::class, 'upload'])->name('credits.upload'); Route::put('credits/{credit}/upload', [CreditController::class, 'upload'])->name('credits.upload');

View File

@ -35,6 +35,71 @@ class UpdateCompanyUserTest extends TestCase
$this->makeTestData(); $this->makeTestData();
} }
public function testUpdatingCompanyUserReactSettings()
{
$company_user = CompanyUser::whereUserId($this->user->id)->whereCompanyId($this->company->id)->first();
$this->user->company_user = $company_user;
$settings = [
'react_settings' => [
'show_pdf_preview' => true,
'react_notification_link' => false
],
];
$response = null;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/company_users/'.$this->encodePrimaryKey($this->user->id).'/preferences', $settings);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
$this->assertNotNull($message);
}
$response->assertStatus(200);
$arr = $response->json();
$this->assertTrue($arr['data']['react_settings']['show_pdf_preview']);
$this->assertFalse($arr['data']['react_settings']['react_notification_link']);
$settings = [
'react_settings' => [
'show_pdf_preview' => false,
'react_notification_link' => true
],
];
$response = null;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/company_users/'.$this->encodePrimaryKey($this->user->id).'/preferences', $settings);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
$this->assertNotNull($message);
}
$response->assertStatus(200);
$arr = $response->json();
$this->assertFalse($arr['data']['react_settings']['show_pdf_preview']);
$this->assertTrue($arr['data']['react_settings']['react_notification_link']);
}
public function testUpdatingCompanyUserAsAdmin() public function testUpdatingCompanyUserAsAdmin()
{ {
// User::unguard(); // User::unguard();
@ -67,4 +132,6 @@ class UpdateCompanyUserTest extends TestCase
$this->assertEquals('ninja', $arr['data']['settings']['invoice']); $this->assertEquals('ninja', $arr['data']['settings']['invoice']);
} }
} }

View File

@ -49,6 +49,68 @@ class InvoiceTest extends TestCase
$this->invoice_calc = new InvoiceSum($this->invoice); $this->invoice_calc = new InvoiceSum($this->invoice);
} }
public function testTaskRoundingPrecisionThree()
{
$invoice = InvoiceFactory::create($this->company->id, $this->user->id);
$invoice->client_id = $this->client->id;
$invoice->uses_inclusive_taxes = false;
$line_items = [];
$line_item = new InvoiceItem;
$line_item->quantity = 25;
$line_item->cost = 0.333;
$line_item->tax_rate1 = 0;
$line_item->tax_name1 = '';
$line_item->product_key = 'Test';
$line_item->notes = 'Test';
$line_items[] = $line_item;
$line_item = new InvoiceItem;
$line_item->quantity = 25;
$line_item->cost = 0.333;
$line_item->tax_rate1 = 0;
$line_item->tax_name1 = '';
$line_item->product_key = 'Test';
$line_item->notes = 'Test';
$line_items[] = $line_item;
$line_item = new InvoiceItem;
$line_item->quantity = 25;
$line_item->cost = 1.333;
$line_item->tax_rate1 = 0;
$line_item->tax_name1 = '';
$line_item->product_key = 'Test';
$line_item->notes = 'Test';
$line_items[] = $line_item;
$line_item = new InvoiceItem;
$line_item->quantity = 25;
$line_item->cost = 0.267;
$line_item->tax_rate1 = 0;
$line_item->tax_name1 = '';
$line_item->product_key = 'Test';
$line_item->notes = 'Test';
$line_items[] = $line_item;
$line_item = new InvoiceItem;
$line_item->quantity = 25;
$line_item->cost = 0.05;
$line_item->tax_rate1 = 0;
$line_item->tax_name1 = '';
$line_item->product_key = 'Test';
$line_item->notes = 'Test';
$line_items[] = $line_item;
$invoice->line_items = $line_items;
$invoice->save();
$invoice = $invoice->calc()->getInvoice();
$this->assertEquals(57.90, $invoice->amount);
}
public function testRoundingWithLargeUnitCostPrecision() public function testRoundingWithLargeUnitCostPrecision()
{ {
$invoice = InvoiceFactory::create($this->company->id, $this->user->id); $invoice = InvoiceFactory::create($this->company->id, $this->user->id);