mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
commit
d417c4bd5f
@ -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);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ class SwissQrGenerator
|
||||
}
|
||||
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 == 'merge' && 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 == 'merge' && 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 == 'merge' && 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 == 'merge' && 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')
|
||||
{
|
||||
|
@ -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}");
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
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') {
|
||||
|
@ -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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user