mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
Improvments to the API
This commit is contained in:
parent
e678d2be62
commit
b387661271
@ -24,8 +24,11 @@ class ClientApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$clients = Client::scope()->with('contacts')->orderBy('created_at', 'desc')->get();
|
$clients = Client::scope()
|
||||||
$clients = Utils::remapPublicIds($clients->toArray());
|
->with('country', 'contacts', 'industry', 'size', 'currency')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
$clients = Utils::remapPublicIds($clients);
|
||||||
|
|
||||||
$response = json_encode($clients, JSON_PRETTY_PRINT);
|
$response = json_encode($clients, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($clients));
|
$headers = Utils::getApiHeaders(count($clients));
|
||||||
@ -44,8 +47,8 @@ class ClientApiController extends Controller
|
|||||||
return Response::make($error, 500, $headers);
|
return Response::make($error, 500, $headers);
|
||||||
} else {
|
} else {
|
||||||
$client = $this->clientRepo->save(isset($data['id']) ? $data['id'] : false, $data, false);
|
$client = $this->clientRepo->save(isset($data['id']) ? $data['id'] : false, $data, false);
|
||||||
$client->load('contacts');
|
$client = Client::scope($client->public_id)->with('country', 'contacts', 'industry', 'size', 'currency')->first();
|
||||||
$client = Utils::remapPublicIds($client->toArray());
|
$client = Utils::remapPublicIds([$client]);
|
||||||
$response = json_encode($client, JSON_PRETTY_PRINT);
|
$response = json_encode($client, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders();
|
$headers = Utils::getApiHeaders();
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class InvoiceApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::scope()->with('invitations')->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get();
|
$invoices = Invoice::scope()->with('client', 'invitations.account')->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get();
|
||||||
|
|
||||||
// Add the first invitation link to the data
|
// Add the first invitation link to the data
|
||||||
foreach ($invoices as $key => $invoice) {
|
foreach ($invoices as $key => $invoice) {
|
||||||
@ -36,7 +36,7 @@ class InvoiceApiController extends Controller
|
|||||||
unset($invoice['invitations']);
|
unset($invoice['invitations']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoices = Utils::remapPublicIds($invoices->toArray());
|
$invoices = Utils::remapPublicIds($invoices);
|
||||||
|
|
||||||
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($invoices));
|
$headers = Utils::getApiHeaders(count($invoices));
|
||||||
@ -99,7 +99,6 @@ class InvoiceApiController extends Controller
|
|||||||
$data = self::prepareData($data);
|
$data = self::prepareData($data);
|
||||||
$data['client_id'] = $client->id;
|
$data['client_id'] = $client->id;
|
||||||
$invoice = $this->invoiceRepo->save(false, $data, false);
|
$invoice = $this->invoiceRepo->save(false, $data, false);
|
||||||
$invoice->load('invoice_items');
|
|
||||||
|
|
||||||
$invitation = Invitation::createNew();
|
$invitation = Invitation::createNew();
|
||||||
$invitation->invoice_id = $invoice->id;
|
$invitation->invoice_id = $invoice->id;
|
||||||
@ -112,13 +111,9 @@ class InvoiceApiController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the return data
|
// prepare the return data
|
||||||
$invoice = $invoice->toArray();
|
$invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->first();
|
||||||
$invoice['link'] = $invitation->getLink();
|
$invoice = Utils::remapPublicIds([$invoice]);
|
||||||
unset($invoice['account']);
|
|
||||||
unset($invoice['client']);
|
|
||||||
$invoice = Utils::remapPublicIds($invoice);
|
|
||||||
$invoice['client_id'] = $client->public_id;
|
|
||||||
|
|
||||||
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,6 +236,11 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$paymentURL = '';
|
||||||
|
if (count($paymentTypes)) {
|
||||||
|
$paymentURL = $paymentTypes[0]['url'];
|
||||||
|
}
|
||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'isConverted' => $invoice->quote_invoice_id ? true : false,
|
'isConverted' => $invoice->quote_invoice_id ? true : false,
|
||||||
'showBreadcrumbs' => false,
|
'showBreadcrumbs' => false,
|
||||||
@ -244,7 +249,8 @@ class InvoiceController extends BaseController
|
|||||||
'invitation' => $invitation,
|
'invitation' => $invitation,
|
||||||
'invoiceLabels' => $account->getInvoiceLabels(),
|
'invoiceLabels' => $account->getInvoiceLabels(),
|
||||||
'contact' => $contact,
|
'contact' => $contact,
|
||||||
'paymentTypes' => $paymentTypes
|
'paymentTypes' => $paymentTypes,
|
||||||
|
'paymentURL' => $paymentURL
|
||||||
);
|
);
|
||||||
|
|
||||||
return View::make('invoices.view', $data);
|
return View::make('invoices.view', $data);
|
||||||
@ -505,9 +511,13 @@ class InvoiceController extends BaseController
|
|||||||
return $this->convertQuote($publicId);
|
return $this->convertQuote($publicId);
|
||||||
} elseif ($action == 'email') {
|
} elseif ($action == 'email') {
|
||||||
if (Auth::user()->confirmed && !Auth::user()->isDemo()) {
|
if (Auth::user()->confirmed && !Auth::user()->isDemo()) {
|
||||||
$message = trans("texts.emailed_{$entityType}");
|
$response = $this->mailer->sendInvoice($invoice);
|
||||||
$this->mailer->sendInvoice($invoice);
|
if ($response === true) {
|
||||||
Session::flash('message', $message);
|
$message = trans("texts.emailed_{$entityType}");
|
||||||
|
Session::flash('message', $message);
|
||||||
|
} else {
|
||||||
|
Session::flash('error', $response);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required');
|
$errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required');
|
||||||
Session::flash('error', $errorMessage);
|
Session::flash('error', $errorMessage);
|
||||||
|
@ -16,9 +16,9 @@ class PaymentApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$payments = Payment::scope()->orderBy('created_at', 'desc')->get();
|
$payments = Payment::scope()->with('client', 'contact', 'invitation', 'user', 'invoice')->orderBy('created_at', 'desc')->get();
|
||||||
$payments = Utils::remapPublicIds($payments->toArray());
|
$payments = Utils::remapPublicIds($payments);
|
||||||
|
|
||||||
$response = json_encode($payments, JSON_PRETTY_PRINT);
|
$response = json_encode($payments, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($payments));
|
$headers = Utils::getApiHeaders(count($payments));
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ class QuoteApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::scope()->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get();
|
$invoices = Invoice::scope()->with('client', 'user')->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get();
|
||||||
$invoices = Utils::remapPublicIds($invoices->toArray());
|
$invoices = Utils::remapPublicIds($invoices);
|
||||||
|
|
||||||
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($invoices));
|
$headers = Utils::getApiHeaders(count($invoices));
|
||||||
|
@ -431,7 +431,6 @@ function otrans($text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Log all SQL queries to laravel.log
|
// Log all SQL queries to laravel.log
|
||||||
Event::listen('illuminate.query', function($query, $bindings, $time, $name)
|
Event::listen('illuminate.query', function($query, $bindings, $time, $name)
|
||||||
{
|
{
|
||||||
@ -456,7 +455,7 @@ Event::listen('illuminate.query', function($query, $bindings, $time, $name)
|
|||||||
|
|
||||||
Log::info($query, $data);
|
Log::info($query, $data);
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (Auth::check() && Auth::user()->id === 1)
|
if (Auth::check() && Auth::user()->id === 1)
|
||||||
|
@ -568,14 +568,15 @@ class Utils
|
|||||||
{
|
{
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
|
|
||||||
$jsonEncodedData = json_encode($data->toJson());
|
$jsonEncodedData = json_encode($data->toPublicArray());
|
||||||
|
|
||||||
$opts = [
|
$opts = [
|
||||||
CURLOPT_URL => $subscription->target_url,
|
CURLOPT_URL => $subscription->target_url,
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||||
CURLOPT_POST => 1,
|
CURLOPT_POST => 1,
|
||||||
CURLOPT_POSTFIELDS => $jsonEncodedData,
|
CURLOPT_POSTFIELDS => $jsonEncodedData,
|
||||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)],
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)],
|
||||||
];
|
];
|
||||||
|
|
||||||
curl_setopt_array($curl, $opts);
|
curl_setopt_array($curl, $opts);
|
||||||
@ -591,27 +592,39 @@ class Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function remapPublicIds(array $data)
|
public static function remapPublicIds($items)
|
||||||
{
|
{
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
foreach ($data as $key => $val) {
|
foreach ($items as $item) {
|
||||||
if ($key === 'public_id') {
|
$return[] = $item->toPublicArray();
|
||||||
$key = 'id';
|
|
||||||
} elseif (strpos($key, '_id')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($val)) {
|
|
||||||
$val = Utils::remapPublicIds($val);
|
|
||||||
}
|
|
||||||
|
|
||||||
$return[$key] = $val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function hideIds($data)
|
||||||
|
{
|
||||||
|
$publicId = null;
|
||||||
|
|
||||||
|
foreach ($data as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$data[$key] = Utils::hideIds($val);
|
||||||
|
} else if ($key == 'id' || strpos($key, '_id')) {
|
||||||
|
if ($key == 'public_id') {
|
||||||
|
$publicId = $val;
|
||||||
|
}
|
||||||
|
unset($data[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($publicId) {
|
||||||
|
$data['id'] = $publicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getApiHeaders($count = 0)
|
public static function getApiHeaders($count = 0)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
@ -74,7 +74,7 @@ class Client extends EntityModel
|
|||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->getDisplayName();
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
@ -82,8 +82,9 @@ class Client extends EntityModel
|
|||||||
if ($this->name) {
|
if ($this->name) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->load('contacts');
|
$this->load('contacts');
|
||||||
|
|
||||||
$contact = $this->contacts()->first();
|
$contact = $this->contacts()->first();
|
||||||
|
|
||||||
return $contact->getDisplayName();
|
return $contact->getDisplayName();
|
||||||
|
@ -38,6 +38,11 @@ class Contact extends EntityModel
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
{
|
{
|
||||||
if ($this->getFullName()) {
|
if ($this->getFullName()) {
|
||||||
|
@ -4,7 +4,12 @@ use Eloquent;
|
|||||||
|
|
||||||
class Country extends Eloquent
|
class Country extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
protected $visible = ['id', 'name'];
|
protected $visible = ['id', 'name'];
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Currency extends Eloquent
|
class Currency extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,4 +77,34 @@ class EntityModel extends Eloquent
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->public_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap ids to public_ids and show name
|
||||||
|
public function toPublicArray()
|
||||||
|
{
|
||||||
|
$data = $this->toArray();
|
||||||
|
|
||||||
|
foreach ($this->attributes as $key => $val) {
|
||||||
|
if (strpos($key, '_id')) {
|
||||||
|
list($field, $id) = explode('_', $key);
|
||||||
|
if ($field == 'account') {
|
||||||
|
// do nothing
|
||||||
|
} else {
|
||||||
|
$entity = @$this->$field;
|
||||||
|
if ($entity) {
|
||||||
|
$data["{$field}_name"] = $entity->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = Utils::hideIds($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Industry extends Eloquent
|
class Industry extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,10 @@ class Invitation extends EntityModel
|
|||||||
|
|
||||||
public function getLink()
|
public function getLink()
|
||||||
{
|
{
|
||||||
$this->load('account');
|
if (!$this->account) {
|
||||||
|
$this->load('account');
|
||||||
|
}
|
||||||
|
|
||||||
$url = SITE_URL;
|
$url = SITE_URL;
|
||||||
|
|
||||||
if ($this->account->subdomain) {
|
if ($this->account->subdomain) {
|
||||||
@ -41,4 +44,9 @@ class Invitation extends EntityModel
|
|||||||
|
|
||||||
return "{$url}/view/{$this->invitation_key}";
|
return "{$url}/view/{$this->invitation_key}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->invitation_key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Size extends Eloquent
|
class Size extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return $this->belongsTo('App\Models\Theme');
|
return $this->belongsTo('App\Models\Theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getPersonType()
|
public function getPersonType()
|
||||||
{
|
{
|
||||||
return PERSON_USER;
|
return PERSON_USER;
|
||||||
|
@ -54,7 +54,11 @@ class ContactMailer extends Mailer
|
|||||||
$data['invoice_id'] = $invoice->id;
|
$data['invoice_id'] = $invoice->id;
|
||||||
|
|
||||||
$fromEmail = $invitation->user->email;
|
$fromEmail = $invitation->user->email;
|
||||||
$this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
$response = $this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
||||||
|
|
||||||
|
if ($response !== true) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
Activity::emailInvoice($invitation);
|
Activity::emailInvoice($invitation);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Ninja\Mailers;
|
<?php namespace App\Ninja\Mailers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Utils;
|
use Utils;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -13,22 +14,29 @@ class Mailer
|
|||||||
'emails.'.$view.'_text',
|
'emails.'.$view.'_text',
|
||||||
];
|
];
|
||||||
|
|
||||||
Mail::send($views, $data, function ($message) use ($toEmail, $fromEmail, $fromName, $subject, $data) {
|
try {
|
||||||
$replyEmail = $fromEmail;
|
Mail::send($views, $data, function ($message) use ($toEmail, $fromEmail, $fromName, $subject, $data) {
|
||||||
$fromEmail = NINJA_FROM_EMAIL;
|
$replyEmail = $fromEmail;
|
||||||
|
$fromEmail = NINJA_FROM_EMAIL;
|
||||||
if(isset($data['invoice_id'])) {
|
|
||||||
$invoice = Invoice::with('account')->where('id', '=', $data['invoice_id'])->get()->first();
|
if(isset($data['invoice_id'])) {
|
||||||
if($invoice->account->pdf_email_attachment && file_exists($invoice->getPDFPath())) {
|
$invoice = Invoice::with('account')->where('id', '=', $data['invoice_id'])->get()->first();
|
||||||
$message->attach(
|
if($invoice->account->pdf_email_attachment && file_exists($invoice->getPDFPath())) {
|
||||||
$invoice->getPDFPath(),
|
$message->attach(
|
||||||
array('as' => $invoice->getFileName(), 'mime' => 'application/pdf')
|
$invoice->getPDFPath(),
|
||||||
);
|
array('as' => $invoice->getFileName(), 'mime' => 'application/pdf')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$message->to($toEmail)->from($fromEmail, $fromName)->replyTo($replyEmail, $fromName)->subject($subject);
|
||||||
|
});
|
||||||
|
|
||||||
//$message->setEncoder(\Swift_Encoding::get8BitEncoding());
|
return true;
|
||||||
$message->to($toEmail)->from($fromEmail, $fromName)->replyTo($replyEmail, $fromName)->subject($subject);
|
} catch (Exception $e) {
|
||||||
});
|
$response = $e->getResponse()->getBody()->getContents();
|
||||||
|
$response = json_decode($response);
|
||||||
|
return nl2br($response->Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if (Session::has('error'))
|
@if (Session::has('error'))
|
||||||
<div class="alert alert-danger">{{ Session::get('error') }}</div>
|
<div class="alert alert-danger">{!! Session::get('error') !!}</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if (!isset($showBreadcrumbs) || $showBreadcrumbs)
|
@if (!isset($showBreadcrumbs) || $showBreadcrumbs)
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
@if (count($paymentTypes) > 1)
|
@if (count($paymentTypes) > 1)
|
||||||
{!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!}
|
{!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!}
|
||||||
@else
|
@else
|
||||||
{!! Button::success(trans('texts.pay_now'))->asLinkTo(URL::to('/payment/' . $invitation->invitation_key))->large() !!}
|
{!! Button::success(trans('texts.pay_now'))->asLinkTo(URL::to($paymentURL))->large() !!}
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
|
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
|
||||||
|
Loading…
Reference in New Issue
Block a user