mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
commit
4b0935185f
@ -1 +1 @@
|
||||
5.5.36
|
||||
5.5.37
|
@ -198,7 +198,7 @@ class Handler extends ExceptionHandler
|
||||
// nlog($exception->validator->getMessageBag());
|
||||
return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);
|
||||
} elseif ($exception instanceof RelationNotFoundException && $request->expectsJson()) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
return response()->json(['message' => "Relation `{$exception->relation}` is not a valid include."], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure && $request->expectsJson()) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure) {
|
||||
|
@ -169,7 +169,7 @@ abstract class QueryFilters
|
||||
public function clientFilter()
|
||||
{
|
||||
if (auth()->guard('contact')->user()) {
|
||||
return $this->builder->whereClientId(auth()->guard('contact')->user()->client->id);
|
||||
return $this->builder->where('client_id', auth()->guard('contact')->user()->client->id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,6 +179,15 @@ abstract class QueryFilters
|
||||
|
||||
$created_at = date('Y-m-d H:i:s', $value);
|
||||
|
||||
if(is_string($created_at)){
|
||||
|
||||
$created_at = strtotime(str_replace("/","-",$created_at));
|
||||
|
||||
if(!$created_at)
|
||||
return $this->builder;
|
||||
|
||||
}
|
||||
|
||||
return $this->builder->where('created_at', '>=', $created_at);
|
||||
}
|
||||
|
||||
|
@ -40,4 +40,7 @@ function nlog($output, $context = []): void
|
||||
} else {
|
||||
\Illuminate\Support\Facades\Log::channel('invoiceninja')->info($output, $context);
|
||||
}
|
||||
|
||||
$output = null;
|
||||
$context = null;
|
||||
}
|
@ -105,14 +105,14 @@ class SwissQrGenerator
|
||||
// Add payment reference
|
||||
// This is what you will need to identify incoming payments.
|
||||
|
||||
if(stripos($this->invoice->number, "Live-") === 0)
|
||||
if(stripos($this->invoice->number, "Live") === 0)
|
||||
{
|
||||
// we're currently in preview status. Let's give a dummy reference for now
|
||||
$invoice_number = "123456789";
|
||||
}
|
||||
else
|
||||
{
|
||||
$invoice_number = $this->invoice->number;
|
||||
$invoice_number = iconv("UTF-8", "ASCII", $this->invoice->number);
|
||||
}
|
||||
|
||||
if(strlen($this->company->present()->besr_id()) > 1)
|
||||
@ -141,7 +141,7 @@ class SwissQrGenerator
|
||||
// Optionally, add some human-readable information about what the bill is for.
|
||||
$qrBill->setAdditionalInformation(
|
||||
QrBill\DataGroup\Element\AdditionalInformation::create(
|
||||
$this->invoice->public_notes ? substr($this->invoice->public_notes, 0, 139) : ctrans('texts.invoice_number_placeholder', ['invoice' => $invoice_number])
|
||||
$this->invoice->public_notes ? substr($this->invoice->public_notes, 0, 139) : ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number])
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -33,6 +33,7 @@ use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Repositories\CreditRepository;
|
||||
use App\Services\PdfMaker\PdfMerge;
|
||||
use App\Transformers\CreditTransformer;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\TempFile;
|
||||
@ -534,6 +535,20 @@ class CreditController extends BaseController
|
||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||
}
|
||||
|
||||
if($action == 'bulk_print' && auth()->user()->can('view', $credits->first())){
|
||||
|
||||
$paths = $credits->map(function ($credit){
|
||||
return $credit->service()->getCreditPdf($credit->invitations->first());
|
||||
});
|
||||
|
||||
$merge = (new PdfMerge($paths->toArray()))->run();
|
||||
|
||||
return response()->streamDownload(function () use ($merge) {
|
||||
echo ($merge);
|
||||
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
||||
|
||||
}
|
||||
|
||||
$credits->each(function ($credit, $key) use ($action) {
|
||||
if (auth()->user()->can('edit', $credit)) {
|
||||
$this->performAction($credit, $action, true);
|
||||
|
@ -40,6 +40,7 @@ use App\Models\Invoice;
|
||||
use App\Models\Quote;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Services\PdfMaker\PdfMerge;
|
||||
use App\Transformers\InvoiceTransformer;
|
||||
use App\Transformers\QuoteTransformer;
|
||||
use App\Utils\Ninja;
|
||||
@ -588,6 +589,20 @@ class InvoiceController extends BaseController
|
||||
|
||||
}
|
||||
|
||||
if($action == 'bulk_print' && auth()->user()->can('view', $invoices->first())){
|
||||
|
||||
$paths = $invoices->map(function ($invoice){
|
||||
return $invoice->service()->getInvoicePdf();
|
||||
});
|
||||
|
||||
$merge = (new PdfMerge($paths->toArray()))->run();
|
||||
|
||||
return response()->streamDownload(function () use ($merge) {
|
||||
echo ($merge);
|
||||
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the other actions to the switch
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@ use App\Models\Client;
|
||||
use App\Models\Expense;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Repositories\PurchaseOrderRepository;
|
||||
use App\Services\PdfMaker\PdfMerge;
|
||||
use App\Transformers\ExpenseTransformer;
|
||||
use App\Transformers\PurchaseOrderTransformer;
|
||||
use App\Utils\Ninja;
|
||||
@ -515,6 +516,20 @@ class PurchaseOrderController extends BaseController
|
||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||
}
|
||||
|
||||
if($action == 'bulk_print' && auth()->user()->can('view', $purchase_orders->first())){
|
||||
|
||||
$paths = $purchase_orders->map(function ($purchase_order){
|
||||
return $purchase_order->service()->getPurchaseOrderPdf();
|
||||
});
|
||||
|
||||
$merge = (new PdfMerge($paths->toArray()))->run();
|
||||
|
||||
return response()->streamDownload(function () use ($merge) {
|
||||
echo ($merge);
|
||||
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the other actions to the switch
|
||||
*/
|
||||
|
@ -35,6 +35,7 @@ use App\Models\Invoice;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Services\PdfMaker\PdfMerge;
|
||||
use App\Transformers\InvoiceTransformer;
|
||||
use App\Transformers\ProjectTransformer;
|
||||
use App\Transformers\QuoteTransformer;
|
||||
@ -561,6 +562,20 @@ class QuoteController extends BaseController
|
||||
return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company());
|
||||
}
|
||||
|
||||
if($action == 'bulk_print' && auth()->user()->can('view', $quotes->first())){
|
||||
|
||||
$paths = $quotes->map(function ($quote){
|
||||
return $quote->service()->getQuotePdf();
|
||||
});
|
||||
|
||||
$merge = (new PdfMerge($paths->toArray()))->run();
|
||||
|
||||
return response()->streamDownload(function () use ($merge) {
|
||||
echo ($merge);
|
||||
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if($action == 'convert_to_project')
|
||||
{
|
||||
|
@ -112,6 +112,8 @@ class SelfUpdateController extends BaseController
|
||||
|
||||
$zipFile->close();
|
||||
|
||||
$zipFile = null;
|
||||
|
||||
nlog('Finished extracting files');
|
||||
|
||||
unlink($file);
|
||||
|
@ -55,7 +55,7 @@ class ValidRefundableRequest implements Rule
|
||||
}
|
||||
|
||||
$request_invoices = request()->has('invoices') ? $this->input['invoices'] : [];
|
||||
$request_credits = request()->has('credits') ? $this->input['credits'] : [];
|
||||
// $request_credits = request()->has('credits') ? $this->input['credits'] : [];
|
||||
|
||||
if ($payment->invoices()->exists()) {
|
||||
foreach ($payment->invoices as $paymentable_invoice) {
|
||||
|
@ -44,6 +44,30 @@ class BaseTransformer
|
||||
$this->company = $company;
|
||||
}
|
||||
|
||||
public function parseDate($date)
|
||||
{
|
||||
|
||||
try{
|
||||
|
||||
$parsed_date = Carbon::parse($date);
|
||||
|
||||
return $parsed_date->format('Y-m-d');
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
$parsed_date = date('Y-m-d', strtotime($date));
|
||||
|
||||
if($parsed_date == '1970-01-01')
|
||||
return now()->format('Y-m-d');
|
||||
|
||||
return $parsed_date;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function getString($data, $field)
|
||||
{
|
||||
return isset($data[$field]) && $data[$field] ? trim($data[$field]) : '';
|
||||
|
@ -31,7 +31,7 @@ class ExpenseTransformer extends BaseTransformer
|
||||
|
||||
return [
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => $this->getFloat($data, 'expense.amount'),
|
||||
'amount' => abs($this->getFloat($data, 'expense.amount')),
|
||||
'currency_id' => $this->getCurrencyByCode(
|
||||
$data,
|
||||
'expense.currency_id'
|
||||
|
@ -57,10 +57,10 @@ class InvoiceTransformer extends BaseTransformer
|
||||
'discount' => $this->getFloat($invoice_data, 'invoice.discount'),
|
||||
'po_number' => $this->getString($invoice_data, 'invoice.po_number'),
|
||||
'date' => isset($invoice_data['invoice.date'])
|
||||
? date('Y-m-d', strtotime(str_replace("/","-",$invoice_data['invoice.date'])))
|
||||
? $this->parseDate($invoice_data['invoice.date'])
|
||||
: now()->format('Y-m-d'),
|
||||
'due_date' => isset($invoice_data['invoice.due_date'])
|
||||
? date('Y-m-d', strtotime(str_replace("/","-",$invoice_data['invoice.due_date'])))
|
||||
? $this->parseDate($invoice_data['invoice.due_date'])
|
||||
: null,
|
||||
'terms' => $this->getString($invoice_data, 'invoice.terms'),
|
||||
'public_notes' => $this->getString(
|
||||
@ -140,10 +140,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
$transformed['payments'] = [
|
||||
[
|
||||
'date' => isset($invoice_data['payment.date'])
|
||||
? date(
|
||||
'Y-m-d',
|
||||
strtotime($invoice_data['payment.date'])
|
||||
)
|
||||
? $this->parseDate($invoice_data['payment.date'])
|
||||
: date('y-m-d'),
|
||||
'transaction_reference' => $this->getString(
|
||||
$invoice_data,
|
||||
@ -159,10 +156,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
$transformed['payments'] = [
|
||||
[
|
||||
'date' => isset($invoice_data['payment.date'])
|
||||
? date(
|
||||
'Y-m-d',
|
||||
strtotime($invoice_data['payment.date'])
|
||||
)
|
||||
? $this->parseDate($invoice_data['payment.date'])
|
||||
: date('y-m-d'),
|
||||
'transaction_reference' => $this->getString(
|
||||
$invoice_data,
|
||||
@ -182,10 +176,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
$transformed['payments'] = [
|
||||
[
|
||||
'date' => isset($invoice_data['payment.date'])
|
||||
? date(
|
||||
'Y-m-d',
|
||||
strtotime($invoice_data['payment.date'])
|
||||
)
|
||||
? $this->parseDate($invoice_data['payment.date'])
|
||||
: date('y-m-d'),
|
||||
'transaction_reference' => $this->getString(
|
||||
$invoice_data,
|
||||
|
@ -218,7 +218,15 @@ class CreateEntityPdf implements ShouldQueue
|
||||
throw new FilePermissionsFailure($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->invitation = null;
|
||||
$this->entity = null;
|
||||
$this->company = null;
|
||||
$this->client = null;
|
||||
$this->contact = null;
|
||||
$maker = null;
|
||||
$state = null;
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
|
@ -200,6 +200,8 @@ class CreateRawPdf implements ShouldQueue
|
||||
}
|
||||
|
||||
if ($pdf) {
|
||||
$maker =null;
|
||||
$state = null;
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
|
@ -128,6 +128,17 @@ class EmailEntity implements ShouldQueue
|
||||
$nmo->entity = $this->entity;
|
||||
|
||||
(new NinjaMailerJob($nmo))->handle();
|
||||
|
||||
$nmo = null;
|
||||
$this->invitation = null;
|
||||
$this->company = null;
|
||||
$this->entity_string = null;
|
||||
$this->entity = null;
|
||||
$this->settings = null;
|
||||
$this->reminder_template = null;
|
||||
$this->html_engine = null;
|
||||
$this->template_data = null;
|
||||
$this->email_entity_builder = null;
|
||||
}
|
||||
|
||||
private function resolveEntityString() :string
|
||||
|
@ -23,6 +23,7 @@ use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Vendor;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
@ -81,6 +82,10 @@ class CSVIngest implements ShouldQueue
|
||||
$engine->finalizeImport();
|
||||
|
||||
$this->checkContacts();
|
||||
|
||||
if(Ninja::isHosted())
|
||||
app('queue.worker')->shouldQuit = 1;
|
||||
|
||||
}
|
||||
|
||||
private function checkContacts()
|
||||
|
@ -115,6 +115,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
//send email
|
||||
try {
|
||||
|
||||
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||
nlog("Using mailer => ". $this->mailer);
|
||||
|
||||
@ -128,7 +129,15 @@ class NinjaMailerJob implements ShouldQueue
|
||||
LightLogs::create(new EmailSuccess($this->nmo->company->company_key))
|
||||
->send();
|
||||
|
||||
// nlog('Using ' . ((int) (memory_get_usage(true) / (1024 * 1024))) . 'MB ');
|
||||
|
||||
$this->nmo = null;
|
||||
$this->company = null;
|
||||
|
||||
$mem_usage = memory_get_usage();
|
||||
|
||||
nlog('The script is now using: ' . round($mem_usage / 1024) . 'KBof memory.');
|
||||
|
||||
} catch (\Exception | \RuntimeException | \Google\Service\Exception $e) {
|
||||
|
||||
nlog("error failed with {$e->getMessage()}");
|
||||
@ -166,7 +175,16 @@ class NinjaMailerJob implements ShouldQueue
|
||||
/* Don't send postmark failures to Sentry */
|
||||
if(Ninja::isHosted() && (!$e instanceof ClientException))
|
||||
app('sentry')->captureException($e);
|
||||
|
||||
$message = null;
|
||||
$this->nmo = null;
|
||||
$this->company = null;
|
||||
app('queue.worker')->shouldQuit = 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Switch statement to handle failure notifications */
|
||||
@ -188,6 +206,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
if ($this->nmo->to_user instanceof ClientContact)
|
||||
$this->logMailError($message, $this->nmo->to_user->client);
|
||||
|
||||
}
|
||||
|
||||
private function setMailDriver()
|
||||
@ -381,7 +400,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
private function logMailError($errors, $recipient_object)
|
||||
{
|
||||
|
||||
SystemLogger::dispatch(
|
||||
SystemLogger::dispatchSync(
|
||||
$errors,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_SEND,
|
||||
@ -396,6 +415,9 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
LightLogs::create($job_failure)
|
||||
->send();
|
||||
|
||||
$job_failure = null;
|
||||
|
||||
}
|
||||
|
||||
public function failed($exception = null)
|
||||
|
@ -99,7 +99,7 @@ class ReminderJob implements ShouldQueue
|
||||
(Ninja::isSelfHost() || $invoice->company->account->isPaidHostedClient())) {
|
||||
|
||||
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
|
||||
EmailEntity::dispatchSync($invitation, $invitation->company, $reminder_template);
|
||||
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
||||
});
|
||||
|
||||
|
@ -79,11 +79,22 @@ class SystemLogger implements ShouldQueue
|
||||
|
||||
if (! $this->log) {
|
||||
nlog('SystemLogger:: no log to store');
|
||||
|
||||
$this->category_id = null;
|
||||
$this->event_id = null;
|
||||
$this->type_id = null;
|
||||
$this->client = null;
|
||||
$this->company = null;
|
||||
return;
|
||||
}
|
||||
|
||||
SystemLog::create($sl);
|
||||
|
||||
$this->log = null;
|
||||
$this->category_id = null;
|
||||
$this->event_id = null;
|
||||
$this->type_id = null;
|
||||
$this->client = null;
|
||||
$this->company = null;
|
||||
}
|
||||
|
||||
public function failed($e)
|
||||
|
3
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
3
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
@ -213,6 +213,9 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
||||
info($maker->getCompiledHTML());
|
||||
}
|
||||
|
||||
$maker = null;
|
||||
$state = null;
|
||||
|
||||
return $pdf;
|
||||
|
||||
}
|
||||
|
@ -515,17 +515,10 @@ class MultiDB
|
||||
{
|
||||
/* This will set the database connection for the request */
|
||||
config(['database.default' => $database]);
|
||||
|
||||
// for some reason this breaks everything _hard_
|
||||
// DB::purge($database);
|
||||
// DB::reconnect($database);
|
||||
}
|
||||
|
||||
public static function setDefaultDatabase()
|
||||
{
|
||||
config(['database.default' => config('ninja.db.default')]);
|
||||
|
||||
// DB::purge(config('ninja.db.default'));
|
||||
// DB::reconnect(config('ninja.db.default'));
|
||||
}
|
||||
}
|
||||
|
@ -251,17 +251,17 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
|
||||
private function formatInvoiceField($field)
|
||||
{
|
||||
$invoice = '';
|
||||
$invoicex = '';
|
||||
|
||||
foreach ($this->payment->invoices as $invoice) {
|
||||
|
||||
$invoice_field = $invoice->{$field};
|
||||
|
||||
$invoice .= ctrans('texts.invoice_number_short') . "{$invoice->number} {$invoice_field}";
|
||||
$invoicex .= ctrans('texts.invoice_number_short') . "{$invoice->number} {$invoice_field}";
|
||||
|
||||
}
|
||||
|
||||
return $invoice;
|
||||
return $invoicex;
|
||||
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
|
||||
return $response->redirect();
|
||||
}
|
||||
|
||||
$this->sendFailureMail($response->getMessage() ?: '');
|
||||
// $this->sendFailureMail($response->getMessage() ?: '');
|
||||
|
||||
$message = [
|
||||
'server_response' => $response->getMessage(),
|
||||
|
@ -137,6 +137,9 @@ class Charge
|
||||
return false;
|
||||
}
|
||||
|
||||
if($response?->status != 'succeeded')
|
||||
$this->stripe->processInternallyFailedPayment($this->stripe, new \Exception('Auto billing failed.',400));
|
||||
|
||||
if ($cgt->gateway_type_id == GatewayType::SEPA) {
|
||||
$payment_method_type = PaymentType::SEPA;
|
||||
$status = Payment::STATUS_PENDING;
|
||||
|
@ -41,7 +41,7 @@ class ACH
|
||||
public function authorizeView($data)
|
||||
{
|
||||
$data['gateway'] = $this->wepay_payment_driver;
|
||||
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
$data['country_code'] = $this->wepay_payment_driver?->client?->country ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
|
||||
return render('gateways.wepay.authorize.bank_transfer', $data);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class CreditCard
|
||||
public function authorizeView($data)
|
||||
{
|
||||
$data['gateway'] = $this->wepay_payment_driver;
|
||||
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
$data['country_code'] = $this->wepay_payment_driver?->client?->country ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
|
||||
return render('gateways.wepay.authorize.authorize', $data);
|
||||
}
|
||||
@ -102,7 +102,7 @@ class CreditCard
|
||||
{
|
||||
$data['gateway'] = $this->wepay_payment_driver;
|
||||
$data['description'] = ctrans('texts.invoices').': '.collect($data['invoices'])->pluck('invoice_number');
|
||||
$data['country_code'] = $this->wepay_payment_driver->client ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
$data['country_code'] = $this->wepay_payment_driver?->client?->country ? $this->wepay_payment_driver->client->country->iso_3166_2 : $this->wepay_payment_driver->company_gateway->company()->iso_3166_2;
|
||||
|
||||
return render('gateways.wepay.credit_card.pay', $data);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class ActivityRepository extends BaseRepository
|
||||
$activity->save();
|
||||
|
||||
//rate limiter
|
||||
// $this->createBackup($entity, $activity);
|
||||
$this->createBackup($entity, $activity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,8 +167,13 @@ class ActivityRepository extends BaseRepository
|
||||
|
||||
$maker = new PdfMakerService($state);
|
||||
|
||||
return $maker->design($template)
|
||||
$html = $maker->design($template)
|
||||
->build()
|
||||
->getCompiledHTML(true);
|
||||
|
||||
$maker = null;
|
||||
$state = null;
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
@ -304,8 +304,9 @@ class BaseRepository
|
||||
if (! $model->design_id)
|
||||
$model->design_id = $this->decodePrimaryKey($client->getSetting('invoice_design_id'));
|
||||
|
||||
//links tasks and expenses back to the invoice.
|
||||
$model->service()->linkEntities()->save();
|
||||
//links tasks and expenses back to the invoice, but only if we are not in the middle of a transaction.
|
||||
if (\DB::transactionLevel() == 0)
|
||||
$model->service()->linkEntities()->save();
|
||||
|
||||
if($this->new_model)
|
||||
event('eloquent.created: App\Models\Invoice', $model);
|
||||
|
@ -108,6 +108,9 @@ class Statement
|
||||
\DB::connection(config('database.default'))->rollBack();
|
||||
}
|
||||
|
||||
$maker = null;
|
||||
$state = null;
|
||||
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,9 @@ class GenerateDeliveryNote
|
||||
|
||||
Storage::disk($this->disk)->put($file_path, $pdf);
|
||||
|
||||
$maker = null;
|
||||
$state = null;
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
}
|
||||
|
@ -712,6 +712,8 @@ class Design extends BaseDesign
|
||||
$elements[] = $element;
|
||||
}
|
||||
|
||||
$document = null;
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
|
@ -234,44 +234,11 @@ trait DesignHelpers
|
||||
});
|
||||
";
|
||||
|
||||
// Unminified version, just for the reference.
|
||||
// By default all table headers are hidden with HTML `hidden` property.
|
||||
// This will check for table data values & if they're not empty it will remove hidden from the column itself.
|
||||
|
||||
/*
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll("#product-table > tbody > tr > td, #task-table > tbody > tr > td, #delivery-note-table > tbody > tr > td").forEach(e => {
|
||||
if ("" !== e.innerText) {
|
||||
let t = e.getAttribute("data-ref").slice(0, -3);
|
||||
document.querySelector(`th[data-ref="${t}-th"]`).removeAttribute("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll("#product-table > tbody > tr > td, #task-table > tbody > tr > td, #delivery-note-table > tbody > tr > td").forEach(e => {
|
||||
let t = e.getAttribute("data-ref").slice(0, -3);
|
||||
t = document.querySelector(`th[data-ref="${t}-th"]`);
|
||||
|
||||
if (!t.hasAttribute('hidden')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("" == e.innerText) {
|
||||
e.setAttribute('hidden', 'true');
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
*/
|
||||
|
||||
$javascript = 'document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("#product-table > tbody > tr > td, #task-table > tbody > tr > td, #delivery-note-table > tbody > tr > td").forEach(t=>{if(""!==t.innerText){let e=t.getAttribute("data-ref").slice(0,-3);document.querySelector(`th[data-ref="${e}-th"]`).removeAttribute("hidden")}}),document.querySelectorAll("#product-table > tbody > tr > td, #task-table > tbody > tr > td, #delivery-note-table > tbody > tr > td").forEach(t=>{let e=t.getAttribute("data-ref").slice(0,-3);(e=document.querySelector(`th[data-ref="${e}-th"]`)).hasAttribute("hidden")&&""==t.innerText&&t.setAttribute("hidden","true")})},!1);';
|
||||
|
||||
// Previously we've been decoding the HTML on the backend and XML parsing isn't good options because it requires,
|
||||
// strict & valid HTML to even output/decode. Decoding is now done on the frontend with this piece of Javascript.
|
||||
|
||||
/**
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll(`[data-state="encoded-html"]`).forEach((element) => element.innerHTML = element.innerText)
|
||||
}, false);
|
||||
*/
|
||||
$html_decode = 'document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(`[data-state="encoded-html"]`).forEach(e=>e.innerHTML=e.innerText)},!1);';
|
||||
|
||||
return ['element' => 'div', 'elements' => [
|
||||
@ -391,17 +358,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
return $converter->convert($markdown);
|
||||
}
|
||||
|
||||
// public function processMarkdownOnLineItems(array &$items): void
|
||||
// {
|
||||
// foreach ($items as $key => $item) {
|
||||
// foreach ($item as $variable => $value) {
|
||||
// $item[$variable] = DesignHelpers::parseMarkdownToHtml($value ?? '');
|
||||
// }
|
||||
|
||||
// $items[$key] = $item;
|
||||
// }
|
||||
// }
|
||||
|
||||
public function processNewLines(array &$items): void
|
||||
{
|
||||
foreach ($items as $key => $item) {
|
||||
|
42
app/Services/PdfMaker/PdfMerge.php
Normal file
42
app/Services/PdfMaker/PdfMerge.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?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\Services\PdfMaker;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use \setasign\Fpdi\Fpdi;
|
||||
use setasign\Fpdi\PdfParser\StreamReader;
|
||||
|
||||
class PdfMerge
|
||||
{
|
||||
|
||||
public function __construct(private array $file_paths) {}
|
||||
|
||||
public function run()
|
||||
{
|
||||
|
||||
$pdf = new FPDI();
|
||||
|
||||
foreach ($this->file_paths as $file) {
|
||||
$pageCount = $pdf->setSourceFile(StreamReader::createByString(Storage::get($file)));
|
||||
for ($i = 0; $i < $pageCount; $i++) {
|
||||
$tpl = $pdf->importPage($i + 1, '/MediaBox');
|
||||
$pdf->addPage();
|
||||
$pdf->useTemplate($tpl);
|
||||
}
|
||||
}
|
||||
|
||||
return $pdf->Output('S');
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -143,6 +143,7 @@ class HtmlEngine
|
||||
$data['$credit.datetime'] = &$data['$entity.datetime'];
|
||||
$data['$payment_button'] = ['value' => '<a class="button" href="'.$this->invitation->getPaymentLink().'">'.ctrans('texts.pay_now').'</a>', 'label' => ctrans('texts.pay_now')];
|
||||
$data['$payment_link'] = ['value' => $this->invitation->getPaymentLink(), 'label' => ctrans('texts.pay_now')];
|
||||
$data['$payment_qrcode'] = ['value' => $this->invitation->getPaymentQrCode(), 'label' => ctrans('texts.pay_now')];
|
||||
|
||||
|
||||
if ($this->entity_string == 'invoice' || $this->entity_string == 'recurring_invoice') {
|
||||
@ -894,6 +895,10 @@ html {
|
||||
|
||||
$dom->appendChild($container);
|
||||
|
||||
return $dom->saveHTML();
|
||||
$html = $dom->saveHTML();
|
||||
|
||||
$dom = null;
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +137,8 @@ class Number
|
||||
public static function formatMoney($value, $entity) :string
|
||||
{
|
||||
|
||||
$value = floatval($value);
|
||||
|
||||
$currency = $entity->currency();
|
||||
|
||||
$thousand = $currency->thousand_separator;
|
||||
|
@ -90,6 +90,9 @@ class SystemHealth
|
||||
private static function checkCurrencySanity()
|
||||
{
|
||||
|
||||
if(!self::simpleDbCheck())
|
||||
return true;
|
||||
|
||||
if(strlen(config('ninja.currency_converter_api_key')) == 0){
|
||||
|
||||
$cs = DB::table('clients')
|
||||
|
@ -13,6 +13,11 @@ namespace App\Utils\Traits;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Support\Str;
|
||||
use BaconQrCode\Renderer\ImageRenderer;
|
||||
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
|
||||
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||
use BaconQrCode\Writer;
|
||||
|
||||
|
||||
/**
|
||||
* Class Inviteable.
|
||||
@ -54,6 +59,22 @@ trait Inviteable
|
||||
return $domain.'/client/pay/'.$this->key;
|
||||
}
|
||||
|
||||
public function getPaymentQrCode()
|
||||
{
|
||||
|
||||
$renderer = new ImageRenderer(
|
||||
new RendererStyle(200),
|
||||
new SvgImageBackEnd()
|
||||
);
|
||||
$writer = new Writer($renderer);
|
||||
|
||||
$qr = $writer->writeString($this->getPaymentLink());
|
||||
|
||||
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
|
||||
|
||||
}
|
||||
|
||||
public function getUnsubscribeLink()
|
||||
{
|
||||
if (Ninja::isHosted()) {
|
||||
|
@ -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.36',
|
||||
'app_tag' => '5.5.36',
|
||||
'app_version' => '5.5.37',
|
||||
'app_tag' => '5.5.37',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
4
public/flutter_service_worker.js
vendored
4
public/flutter_service_worker.js
vendored
@ -11,9 +11,9 @@ const RESOURCES = {
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"flutter.js": "f85e6fb278b0fd20c349186fb46ae36d",
|
||||
"/": "cb6f2c73612e3d57c56452ef7c10795a",
|
||||
"/": "b929c2274033670c857cf631017d7f84",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"main.dart.js": "69afcf35930517b4949ed2f4d551307a",
|
||||
"main.dart.js": "b165f2dcfe57c6bae02dc84a3d527590",
|
||||
"assets/AssetManifest.json": "759f9ef9973f7e26c2a51450b55bb9fa",
|
||||
"assets/FontManifest.json": "087fb858dc3cbfbf6baf6a30004922f1",
|
||||
"assets/NOTICES": "1a34e70168d56fad075adfb4bdbb20eb",
|
||||
|
4978
public/main.dart.js
vendored
4978
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
4970
public/main.foss.dart.js
vendored
4970
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
70
public/main.profile.dart.js
vendored
70
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -41,6 +41,10 @@
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#qr-bill td {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user