1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Merge pull request #8580 from turbo124/v5-develop

Fixes for PDF Previews
This commit is contained in:
David Bomba 2023-06-27 21:31:47 +10:00 committed by GitHub
commit 5b9f58e6e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 291 additions and 92 deletions

View File

@ -165,9 +165,6 @@ class Rule extends BaseRule implements RuleInterface
$this->tax_rate1 = 0;
$this->tax_name1 = '';
// $this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
// $this->tax_name1 = "Sales Tax";
return $this;
}

View File

@ -105,7 +105,7 @@ class Handler extends ExceptionHandler
if($exception instanceof ThrottleRequestsException && class_exists(\Modules\Admin\Events\ThrottledExceptionRaised::class)) {
$uri = urldecode(request()->getRequestUri());
event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip()));
// event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip()));
}
Integration::configureScope(function (Scope $scope): void {

View File

@ -0,0 +1,41 @@
<?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\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class QuoteConversion extends Exception
{
/**
* Report the exception.
*
* @return void
*/
public function report()
{
//
}
/**
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
*/
public function render($request)
{
return response()->json(['message' => 'This quote has already been converted. Cannot convert again.'], 400);
}
}

View File

@ -106,6 +106,15 @@ class ExpenseFilters extends QueryFilters
return $this->builder;
}
public function has_invoices(string $value = ''): Builder
{
if ($value == 'true') {
return $this->builder->whereNotNull('invoice_id');
}
return $this->builder;
}
/**
* Returns a list of expenses that can be matched to bank transactions
*/

View File

@ -92,46 +92,47 @@ class ActivityController extends BaseController
->company()
->take($default_activities);
if ($request->has('react')) {
// if ($request->has('react')) {
/** @var \App\Models\User auth()->user() */
$user = auth()->user();
// /** @var \App\Models\User auth()->user() */
// $user = auth()->user();
if (!$user->isAdmin()) {
$activities->where('user_id', auth()->user()->id);
}
// if (!$user->isAdmin()) {
// $activities->where('user_id', auth()->user()->id);
// }
$system = ctrans('texts.system');
// $system = ctrans('texts.system');
$data = $activities->cursor()->map(function ($activity) {
// $data = $activities->cursor()->map(function ($activity) {
$arr =
[
'client' => $activity->client ? $activity->client : '',
'contact' => $activity->client ? $activity->contact : '',
'quote' => $activity->quote ? $activity->quote : '',
'user' => $activity->user ? $activity->user : '',
'expense' => $activity->expense ? $activity->expense : '',
'invoice' => $activity->invoice ? $activity->invoice : '',
'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '',
'payment' => $activity->payment ? $activity->payment : '',
'credit' => $activity->credit ? $activity->credit : '',
'task' => $activity->task ? $activity->task : '',
'vendor' => $activity->vendor ? $activity->vendor : '',
'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '',
'subscription' => $activity->subscription ? $activity->subscription : '',
'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '',
'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
];
// $arr =
// [
// 'client' => $activity->client ? $activity->client : '',
// 'contact' => $activity->client ? $activity->contact : '',
// 'quote' => $activity->quote ? $activity->quote : '',
// 'user' => $activity->user ? $activity->user : '',
// 'expense' => $activity->expense ? $activity->expense : '',
// 'invoice' => $activity->invoice ? $activity->invoice : '',
// 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '',
// 'payment' => $activity->payment ? $activity->payment : '',
// 'credit' => $activity->credit ? $activity->credit : '',
// 'task' => $activity->task ? $activity->task : '',
// 'vendor' => $activity->vendor ? $activity->vendor : '',
// 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '',
// 'subscription' => $activity->subscription ? $activity->subscription : '',
// 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '',
// 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
// ];
$activity_array = $activity->toArray();
// $activity_array = $activity->toArray();
return array_merge($arr, $activity_array);
});
// return array_merge($arr, $activity_array);
// });
return response()->json(['data' => $data->toArray()], 200);
}
elseif($request->has('reactv2')) {
// return response()->json(['data' => $data->toArray()], 200);
// }
// else
if($request->has('reactv2')) {
/** @var \App\Models\User auth()->user() */
$user = auth()->user();

View File

@ -61,7 +61,7 @@ class ChartController extends BaseController
/** @var \App\Models\User auth()->user() */
$user = auth()->user();
$cs = new ChartService($user->company(), $user, $user->isAdmin());
return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200);
}

View File

@ -12,9 +12,12 @@
namespace App\Http\Requests\Chart;
use App\Http\Requests\Request;
use App\Utils\Traits\MakesDates;
class ShowChartRequest extends Request
{
use MakesDates;
/**
* Determine if the user is authorized to make this request.
*
@ -22,14 +25,18 @@ class ShowChartRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->isAdmin();
/**@var \App\Models\User auth()->user */
$user = auth()->user();
return $user->isAdmin();
}
public function rules()
{
return [
'start_date' => 'date',
'end_date' => 'date',
'date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
'start_date' => 'bail|sometimes|date',
'end_date' => 'bail|sometimes|date',
];
}
@ -37,12 +44,18 @@ class ShowChartRequest extends Request
{
$input = $this->all();
if (! array_key_exists('start_date', $input)) {
$input['start_date'] = now()->subDays(20);
if(isset($input['date_range'])) {
$dates = $this->calculateStartAndEndDates($input);
$input['start_date'] = $dates[0];
$input['end_date'] = $dates[1];
}
if (! array_key_exists('end_date', $input)) {
$input['end_date'] = now();
if (! isset($input['start_date'])) {
$input['start_date'] = now()->subDays(20)->format('Y-m-d');
}
if (! isset($input['end_date'])) {
$input['end_date'] = now()->format('Y-m-d');
}
$this->replace($input);

View File

@ -79,7 +79,7 @@ class ProcessBankTransactions implements ShouldQueue
$e->getMessage(),
];
$this->bank_integration->account->company->notification(new GenericNinjaAdminNotification($content))->ninja();
$this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja();
return;
}
} while ($this->stop_loop);

View File

@ -135,6 +135,7 @@ class Import implements ShouldQueue
'recurring_expenses',
'tasks',
'documents',
'activities',
];
/**
@ -181,7 +182,7 @@ class Import implements ShouldQueue
public function middleware()
{
return [(new WithoutOverlapping($this->user->account_id))];
return [(new WithoutOverlapping($this->company->company_key))];
}
/**
@ -303,7 +304,7 @@ class Import implements ShouldQueue
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
$client->paid_to_date = $total_invoice_payments;
$client->save();
$client->saveQuietly();
}
});
}
@ -319,12 +320,12 @@ class Import implements ShouldQueue
$company_ledger->notes = 'Migrated Client Balance';
$company_ledger->balance = $invoice_balances;
$company_ledger->activity_id = Activity::CREATE_CLIENT;
$company_ledger->save();
$company_ledger->saveQuietly();
$client->company_ledger()->save($company_ledger);
$client->balance = $invoice_balances;
$client->save();
$client->saveQuietly();
});
}
@ -1776,6 +1777,78 @@ class Import implements ShouldQueue
$data = null;
}
private function processActivities(array $data): void
{
Activity::where('company_id', $this->company->id)->cursor()->each(function ($a){
$a->forceDelete();
nlog("deleting {$a->id}");
});
Activity::unguard();
foreach ($data as $resource) {
$modified = $resource;
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->processUserId($resource);
try {
if (isset($modified['client_id'])) {
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
}
if (isset($modified['invoice_id'])) {
$modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']);
}
if (isset($modified['quote_id'])) {
$modified['quote_id'] = $this->transformId('quotes', $resource['quote_id']);
}
if (isset($modified['recurring_invoice_id'])) {
$modified['recurring_invoice_id'] = $this->transformId('recurring_invoices', $resource['recurring_invoice_id']);
}
if (isset($modified['payment_id'])) {
$modified['payment_id'] = $this->transformId('payments', $resource['payment_id']);
}
if (isset($modified['credit_id'])) {
$modified['credit_id'] = $this->transformId('credits', $resource['credit_id']);
}
if (isset($modified['expense_id'])) {
$modified['expense_id'] = $this->transformId('expenses', $resource['expense_id']);
}
if (isset($modified['task_id'])) {
$modified['task_id'] = $this->transformId('tasks', $resource['task_id']);
}
if (isset($modified['client_contact_id'])) {
$modified['client_contact_id'] = $this->transformId('client_contacts', $resource['client_contact_id']);
}
$modified['updated_at'] = $modified['created_at'];
$act = Activity::make($modified);
$act->save(['timestamps' => false]);
}
catch (\Exception $e) {
nlog("could not import activity: {$e->getMessage()}");
}
}
Activity::reguard();
}
private function processExpenses(array $data) :void
{
Expense::unguard();

View File

@ -126,7 +126,7 @@ class ReminderJob implements ShouldQueue
}
$reminder_template = $invoice->calculateTemplate('invoice');
nlog("reminder template = {$reminder_template}");
// nlog("reminder template = {$reminder_template}");
$invoice->service()->touchReminder($reminder_template)->save();
$fees = $this->calcLateFee($invoice, $reminder_template);

View File

@ -122,7 +122,9 @@ class WebhookSingle implements ShouldQueue
$client = new Client(['headers' => array_merge($base_headers, $headers)]);
try {
$response = $client->{$subscription->rest_method}($subscription->target_url, [
$verb = $subscription->rest_method ?? 'post';
$response = $client->{$verb}($subscription->target_url, [
RequestOptions::JSON => $data, // or 'json' => [...]
]);

View File

@ -38,25 +38,28 @@ class PaymentCreatedActivity implements ShouldQueue
* @return void
*/
public function handle($event)
{
{
MultiDB::setDb($event->company->db);
$payment = $event->payment;
$invoice_id = null;
if($payment->invoices()->exists())
$invoice_id = $payment->invoices()->first()->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id;
$invoices = $payment->invoices;
$fields = new stdClass;
$fields->payment_id = $payment->id;
$fields->invoice_id = $invoice_id;
$fields->client_id = $payment->client_id;
$fields->user_id = $user_id;
$fields->company_id = $payment->company_id;
$fields->activity_type_id = Activity::CREATE_PAYMENT;
if (count($invoices) == 0) {
$this->activity_repo->save($fields, $payment, $event->event_vars);
}
$this->activity_repo->save($fields, $payment, $event->event_vars);
}
}

View File

@ -515,9 +515,8 @@ class Activity extends StaticModel
{
$system = ctrans('texts.system');
return match($variable) {
':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']],
':contact' => $translation = $this->resolveContact(),
match($variable) {
':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']],
':user' => $translation = [substr($variable, 1) => [ 'label' => $this?->user?->present()->name() ?? $system, 'hashed_id' => $this->user->hashed_id ?? '']],
':quote' => $translation = [substr($variable, 1) => [ 'label' => $this?->quote?->number ?? '', 'hashed_id' => $this->quote->hashed_id ?? '']],
':credit' => $translation = [substr($variable, 1) => [ 'label' => $this?->credit?->number ?? '', 'hashed_id' => $this->credit->hashed_id ?? '']],
@ -531,6 +530,7 @@ class Activity extends StaticModel
':payment_amount' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->amount, $this?->payment?->client) ?? '', 'hashed_id' => '']],
':adjustment' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client) ?? '', 'hashed_id' => '']],
':ip' => $translation = [ 'ip' => $this->ip ?? ''],
':contact' => $translation = $this->resolveContact(),
default => $translation = [],
};

View File

@ -225,6 +225,11 @@ class Expense extends BaseModel
return $this->belongsTo(Company::class);
}
public function invoice()
{
return $this->belongsTo(Invoice::class);
}
public function vendor()
{
return $this->belongsTo(Vendor::class);

View File

@ -185,7 +185,7 @@ class PaymentRepository extends BaseRepository
$paymentable->payment_id = $payment->id;
$paymentable->paymentable_id = $credit->id;
$paymentable->paymentable_type = Credit::class;
$paymentable->amount = $paid_invoice['amount'];
$paymentable->amount = $paid_credit['amount'];
$paymentable->save();
$credit = $credit->service()->markSent()->save();

View File

@ -76,6 +76,8 @@ class ChartService
$currencies = $this->getCurrencyCodes();
$data = [];
$data['start_date'] = $start_date;
$data['end_date'] = $end_date;
foreach ($currencies as $key => $value) {
$data[$key]['invoices'] = $this->getInvoiceChartQuery($start_date, $end_date, $key);
@ -97,6 +99,9 @@ class ChartService
$data['currencies'] = $this->getCurrencyCodes();
$data['start_date'] = $start_date;
$data['end_date'] = $end_date;
$revenue = $this->getRevenue($start_date, $end_date);
$outstanding = $this->getOutstanding($start_date, $end_date);
$expenses = $this->getExpenses($start_date, $end_date);

View File

@ -653,7 +653,7 @@ class PdfBuilder
$data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value4) >= 1 ? $helpers->formatCustomFieldValue($this->service->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->service->config->currency_entity) : '';
if ($item->quantity > 0 || $item->cost > 0) {
$data[$key][$table_type.'.quantity'] = $this->service->config->formatMoney($item->quantity);
$data[$key][$table_type.'.quantity'] = $item->quantity;
$data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoney($item->cost);

View File

@ -232,6 +232,9 @@ class PdfMock
'$secondary_font_url' => 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
'$contact.signature' => '',
'$company_logo_size' => $this->settings->company_logo_size ?: '65%',
'$product.tax_rate1' => ctrans('texts.tax'),
'$product.tax_rate2' => ctrans('texts.tax'),
'$product.tax_rate3' => ctrans('texts.tax'),
'$product.tax_name1' => '',
'$product.tax_name2' => '',
'$product.tax_name3' => '',
@ -688,8 +691,11 @@ class PdfMock
'$net_subtotal_label' => ctrans('texts.net_subtotal'),
'$credit.total_label' => ctrans('texts.total'),
'$quote.amount_label' => ctrans('texts.amount'),
'$description_label' => ctrans('texts.description'),
'$product.tax_rate1_label' => ctrans('texts.tax'),
'$product.tax_rate2_label' => ctrans('texts.tax'),
'$product.tax_rate3_label' => ctrans('texts.tax'),
'$product.tax_label' => ctrans('texts.tax'),
'$description_label' => ctrans('texts.description'),
'$your_entity_label' => ctrans("texts.your_{$this->entity_string}"),
'$view_button_label' => ctrans('texts.view'),
'$status_logo_label' => ctrans('texts.logo'),
@ -782,9 +788,9 @@ class PdfMock
'$amount_label' => ctrans('texts.amount'),
'$notes_label' => ctrans('texts.notes'),
'$terms_label' => ctrans('texts.terms'),
'tax_rate1_label' => ctrans('texts.tax_rate1'),
'tax_rate2_label' => ctrans('texts.tax_rate2'),
'tax_rate3_label' => ctrans('texts.tax_rate3'),
'$tax_rate1_label' => ctrans('texts.tax_rate1'),
'$tax_rate2_label' => ctrans('texts.tax_rate2'),
'$tax_rate3_label' => ctrans('texts.tax_rate3'),
'$phone_label' => ctrans('texts.phone'),
'$email_label' => ctrans('texts.email'),
'$taxes_label' => ctrans('texts.taxes'),

View File

@ -11,14 +11,14 @@
namespace App\Services\Quote;
use App\Events\Quote\QuoteWasApproved;
use App\Jobs\Entity\CreateEntityPdf;
use App\Jobs\Util\UnlinkFile;
use App\Models\Invoice;
use App\Models\Quote;
use App\Repositories\QuoteRepository;
use App\Utils\Ninja;
use App\Models\Quote;
use App\Jobs\Util\UnlinkFile;
use App\Utils\Traits\MakesHash;
use App\Exceptions\QuoteConversion;
use App\Jobs\Entity\CreateEntityPdf;
use App\Repositories\QuoteRepository;
use App\Events\Quote\QuoteWasApproved;
class QuoteService
{
@ -43,7 +43,7 @@ class QuoteService
public function convert() :self
{
if ($this->quote->invoice_id) {
return $this;
throw new QuoteConversion();
}
$convert_quote = (new ConvertQuote($this->quote->client))->run($this->quote);

View File

@ -58,7 +58,8 @@ class EmailReport
public function run()
{
$start_end_dates = $this->calculateStartAndEndDates();
$start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters);
$data = [];
$data = [

View File

@ -69,7 +69,7 @@ class ZipTax implements TaxProviderInterface
private function parseResponse($response)
{
if(isset($response['rCode']) && $response['rCode'] == 100)
if(isset($response['rCode']) && $response['rCode'] == 100 && isset($response['results']['0']))
return $response['results']['0'];
if(isset($response['rCode']) && class_exists(\Modules\Admin\Events\TaxProviderException::class))

View File

@ -11,12 +11,15 @@
namespace App\Transformers;
use App\Models\Document;
use App\Models\Expense;
use App\Models\Vendor;
use App\Models\Expense;
use App\Models\Invoice;
use App\Models\Document;
use App\Models\ExpenseCategory;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\SoftDeletes;
use League\Fractal\Resource\Item;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Transformers\ExpenseCategoryTransformer;
/**
* class ExpenseTransformer.
@ -36,6 +39,8 @@ class ExpenseTransformer extends EntityTransformer
protected $availableIncludes = [
'client',
'vendor',
'category',
'invoice',
];
public function includeDocuments(Expense $expense)
@ -56,6 +61,28 @@ class ExpenseTransformer extends EntityTransformer
return $this->includeItem($expense->client, $transformer, Client::class);
}
public function includeInvoice(Expense $expense): ?Item
{
$transformer = new InvoiceTransformer($this->serializer);
if (!$expense->invoice) {
return null;
}
return $this->includeItem($expense->invoice, $transformer, Invoice::class);
}
public function includeCategory(Expense $expense): ?Item
{
$transformer = new ExpenseCategoryTransformer($this->serializer);
if (!$expense->category) {
return null;
}
return $this->includeItem($expense->category, $transformer, ExpenseCategory::class);
}
public function includeVendor(Expense $expense): ?Item
{
$transformer = new VendorTransformer($this->serializer);

View File

@ -119,9 +119,9 @@ trait MakesDates
*
* @return array [$start_date, $end_date];
*/
public function calculateStartAndEndDates(): array
public function calculateStartAndEndDates(array $data): array
{
return match ($this->scheduler->parameters['date_range']) {
return match ($data['date_range']) {
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
@ -131,9 +131,9 @@ trait MakesDates
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}
}
}

View File

@ -3863,7 +3863,7 @@ $LANG = array(
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
'reset_password_text' => 'Enter your email to reset your password.',
'password_reset' => 'Password reset',
'account_login_text' => 'Welcome back! Glad to see you.',
'account_login_text' => 'Welcome! Glad to see you.',
'request_cancellation' => 'Request cancellation',
'delete_payment_method' => 'Delete Payment Method',
'about_to_delete_payment_method' => 'You are about to delete the payment method.',

View File

@ -11,16 +11,17 @@
namespace Tests\Feature;
use App\Models\ClientContact;
use App\Models\Project;
use App\Models\Quote;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Session;
use Tests\MockAccountData;
use Tests\TestCase;
use App\Models\Quote;
use App\Models\Project;
use Tests\MockAccountData;
use App\Models\ClientContact;
use App\Utils\Traits\MakesHash;
use App\Exceptions\QuoteConversion;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Session;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
@ -32,6 +33,8 @@ class QuoteTest extends TestCase
use DatabaseTransactions;
use MockAccountData;
public $faker;
protected function setUp() :void
{
parent::setUp();
@ -49,6 +52,19 @@ class QuoteTest extends TestCase
);
}
public function testQuoteConversion()
{
$invoice = $this->quote->service()->convertToInvoice();
$this->assertInstanceOf('\App\Models\Invoice', $invoice);
$this->expectException(QuoteConversion::class);
$invoice = $this->quote->service()->convertToInvoice();
}
public function testQuoteDownloadPDF()
{
$i = $this->quote->invitations->first();