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

Merge pull request #7911 from turbo124/v5-develop

Swiss QR Code fixes
This commit is contained in:
David Bomba 2022-10-31 12:05:44 +11:00 committed by GitHub
commit d417c4bd5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 147 additions and 10 deletions

View File

@ -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);
}

View File

@ -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])
)
);

View File

@ -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);

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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')
{

View File

@ -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}");
});

View File

@ -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;
}

View File

@ -95,7 +95,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
return $response->redirect();
}
$this->sendFailureMail($response->getMessage() ?: '');
// $this->sendFailureMail($response->getMessage() ?: '');
$message = [
'server_response' => $response->getMessage(),

View File

@ -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;

View File

@ -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);

View 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');
}
}

View File

@ -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') {

View File

@ -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()) {