Fixes for missing a rollback

This commit is contained in:
David Bomba 2024-10-01 12:51:44 +10:00
parent 2072de908a
commit 8f793ea861
11 changed files with 102 additions and 144 deletions

View File

@ -93,16 +93,13 @@ class EpcQrGenerator
isset($this->company?->custom_fields?->company1) ? $this->company->settings->custom_value1 : '', // IBAN
$this->formatMoney($this->amount), // Amount with EUR prefix
'', // Reference
substr($this->invoice->number, 0, 34) // Unstructured remittance information
substr(($this->invoice->number ?? ''), 0, 34) // Unstructured remittance information
];
return implode("\n", $data);
}
// substr("{$this->invoice->number} {$this->invoice->client->number}", 0,139),
private function validateFields()
{
if (Ninja::isSelfHost() && isset($this->company?->custom_fields?->company2)) {

View File

@ -65,7 +65,7 @@ class PostMarkController extends BaseController
public function webhook(Request $request)
{
if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) {
ProcessPostmarkWebhook::dispatch($request->all())->delay(rand(2, 10));
ProcessPostmarkWebhook::dispatch($request->all())->delay(rand(6, 14));
return response()->json(['message' => 'Success'], 200);
}

View File

@ -1,66 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Jobs\Invitation;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
//todo - ensure we are MultiDB Aware in dispatched jobs
class MarkOpened implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
use NumberFormatter;
public $message_id;
public $entity;
/**
* Create a new job instance.
*
* @param string $message_id
* @param string $entity
*/
public function __construct(string $message_id, string $entity)
{
$this->message_id = $message_id;
$this->entity = $entity;
}
/**
* Execute the job.
*
*/
public function handle()
{
$invitation = $this->entity::with('user', 'contact')
->whereMessageId($this->message_id)
->first();
if (! $invitation) {
return false;
}
$invitation->opened_date = now();
//$invitation->email_error = $error;
$invitation->save();
}
}

View File

@ -69,7 +69,8 @@ class ProcessMailgunWebhook implements ShouldQueue
->where('company_id', $this->invitation->company_id)
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
->where('category_id', SystemLog::CATEGORY_MAIL)
->whereJsonContains('log', ['MessageID' => $this->message_id])
->where('log->MessageID', $message_id)
// ->whereJsonContains('log', ['MessageID' => $this->message_id])
->orderBy('id', 'desc')
->first();

View File

@ -70,7 +70,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
->where('category_id', SystemLog::CATEGORY_MAIL)
// ->where('client_id', $this->invitation->contact->client_id)
->whereJsonContains('log', ['MessageID' => $message_id])
// ->whereJsonContains('log', ['MessageID' => $message_id])
->where('log->MessageID', $message_id)
->orderBy('id', 'desc')
->first();
@ -444,4 +445,10 @@ class ProcessPostmarkWebhook implements ShouldQueue
}
}
public function middleware()
{
return [new \Illuminate\Queue\Middleware\WithoutOverlapping($this->request['Tag'])];
}
}

View File

@ -97,6 +97,9 @@ class ReminderJob implements ShouldQueue
->whereHas('company', function ($query) {
$query->where('is_disabled', 0);
})
->whereHas('company.account', function ($q){
$q->whereNotNull('plan')->where('plan_expire', '>', now()->subDays(2));
})
->with('invitations')
->cursor()
->each(function ($invoice) {

View File

@ -16,6 +16,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
class UpdateContactLastLogin implements ShouldQueue
{
public $delay = 8;
/**
* Create the event listener.
*
@ -38,8 +39,6 @@ class UpdateContactLastLogin implements ShouldQueue
$client_contact = $event->client_contact;
$client_contact->last_login = now();
$client_contact->client->last_login = now();
$client_contact->push();
$client_contact->save();
}
}

View File

@ -215,6 +215,11 @@ class SystemLog extends Model
return $query;
}
public function company()
{
return $this->hasMany(\App\Models\Company::class);
}
public function getCategoryName()
{
switch ($this->category_id) {

View File

@ -253,7 +253,7 @@ class ClientService
$pdf = $statement->run();
if ($send_email) {
if ($send_email && $pdf) {
// If selected, ignore clients that don't have any invoices to put on the statement.
if (!empty($options['only_clients_with_invoices']) && $statement->getInvoices()->count() == 0) {
return false;
@ -311,6 +311,8 @@ class ClientService
$invoice = $this->client->invoices()->whereHas('invitations')->first();
$invoice = \App\Models\Invoice::where('client_id', $this->client->id)->whereHas('invitations')->first();
$email_object->attachments = [['file' => base64_encode($pdf), 'name' => ctrans('texts.statement') . ".pdf"]];
$email_object->client_id = $this->client->id;
$email_object->entity_class = Invoice::class;

View File

@ -55,79 +55,94 @@ class Statement
public function run(): ?string
{
$this
->setupOptions()
->setupEntity();
try {
$this
->setupOptions()
->setupEntity();
$html = new HtmlEngine($this->getInvitation());
$html = new HtmlEngine($this->getInvitation());
$variables = [];
$variables = $html->generateLabelsAndValues();
$variables = [];
$variables = $html->generateLabelsAndValues();
$option_template = &$this->options['template'];
$option_template = &$this->options['template'];
$custom_statement_template = \App\Models\Design::where('id', $this->decodePrimaryKey($this->client->getSetting('statement_design_id')))->where('is_template', true)->first();
$custom_statement_template = \App\Models\Design::where('id', $this->decodePrimaryKey($this->client->getSetting('statement_design_id')))->where('is_template', true)->first();
if($custom_statement_template || $option_template && $option_template != '') {
if($custom_statement_template || $option_template && $option_template != '') {
$variables['values']['$start_date'] = $this->translateDate($this->options['start_date'], $this->client->date_format(), $this->client->locale());
$variables['values']['$end_date'] = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale());
$variables['labels']['$start_date_label'] = ctrans('texts.start_date');
$variables['labels']['$end_date_label'] = ctrans('texts.end_date');
$variables['values']['$start_date'] = $this->translateDate($this->options['start_date'], $this->client->date_format(), $this->client->locale());
$variables['values']['$end_date'] = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale());
$variables['labels']['$start_date_label'] = ctrans('texts.start_date');
$variables['labels']['$end_date_label'] = ctrans('texts.end_date');
return $this->templateStatement($variables);
}
return $this->templateStatement($variables);
}
if ($this->getDesign()->is_custom) {
$this->options['custom_partials'] = \json_decode(\json_encode($this->getDesign()->design), true);
if ($this->getDesign()->is_custom) {
$this->options['custom_partials'] = \json_decode(\json_encode($this->getDesign()->design), true);
$template = new PdfMakerDesign(\App\Services\PdfMaker\Design::CUSTOM, $this->options);
} else {
$template = new PdfMakerDesign(strtolower($this->getDesign()->name), $this->options);
}
$template = new PdfMakerDesign(\App\Services\PdfMaker\Design::CUSTOM, $this->options);
} else {
$template = new PdfMakerDesign(strtolower($this->getDesign()->name), $this->options);
}
$variables = $html->generateLabelsAndValues();
$variables['values']['$show_paid_stamp'] = 'none'; //do not show paid stamp on statement
$variables = $html->generateLabelsAndValues();
$variables['values']['$show_paid_stamp'] = 'none'; //do not show paid stamp on statement
$state = [
'template' => $template->elements([
'client' => $this->client,
'entity' => $this->entity,
'pdf_variables' => (array) $this->entity->company->settings->pdf_variables,
'$product' => $this->getDesign()->design->product,
$state = [
'template' => $template->elements([
'client' => $this->client,
'entity' => $this->entity,
'pdf_variables' => (array) $this->entity->company->settings->pdf_variables,
'$product' => $this->getDesign()->design->product,
'variables' => $variables,
'invoices' => $this->getInvoices()->cursor(),
'payments' => $this->getPayments()->cursor(),
'credits' => $this->getCredits()->cursor(),
'aging' => $this->getAging(),
], \App\Services\PdfMaker\Design::STATEMENT),
'variables' => $variables,
'invoices' => $this->getInvoices()->cursor(),
'payments' => $this->getPayments()->cursor(),
'credits' => $this->getCredits()->cursor(),
'aging' => $this->getAging(),
], \App\Services\PdfMaker\Design::STATEMENT),
'variables' => $variables,
'options' => [
],
'process_markdown' => $this->entity->client->company->markdown_enabled,
];
'options' => [
],
'process_markdown' => $this->entity->client->company->markdown_enabled,
];
$maker = new PdfMaker($state);
$maker = new PdfMaker($state);
$maker
->design($template)
->build();
$maker
->design($template)
->build();
$pdf = null;
$html = $maker->getCompiledHTML(true);
$pdf = null;
$html = $maker->getCompiledHTML(true);
if ($this->rollback) {
\DB::connection(config('database.default'))->rollBack();
$this->rollback = false;
}
$pdf = $this->convertToPdf($html);
$this->setVariables($variables);
$maker = null;
$state = null;
return $pdf;
}
catch(\Throwable $th){
nlog("STATEMENT:: Throwable::" . $th->getMessage());
if ($this->rollback) {
\DB::connection(config('database.default'))->rollBack();
}
if ($this->rollback) {
\DB::connection(config('database.default'))->rollBack();
}
$pdf = $this->convertToPdf($html);
return null;
$this->setVariables($variables);
$maker = null;
$state = null;
return $pdf;
}
public function setVariables($variables): self
@ -178,19 +193,14 @@ class Statement
{
$pdf = false;
try {
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
$pdf = (new Phantom())->convertHtmlToPdf($html);
} elseif (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
$pdf = (new NinjaPdf())->build($html);
} else {
$pdf = $this->makePdf(null, null, $html);
}
} catch (\Exception $e) {
nlog(print_r($e->getMessage(), true));
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
$pdf = (new Phantom())->convertHtmlToPdf($html);
} elseif (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
$pdf = (new NinjaPdf())->build($html);
} else {
$pdf = $this->makePdf(null, null, $html);
}
return $pdf;
}
/**
@ -208,7 +218,7 @@ class Statement
DB::connection(config('database.default'))->beginTransaction();
$this->rollback = true;
$invoice = InvoiceFactory::create($this->client->company->id, $this->client->user->id);
$invoice->client_id = $this->client->id;
$invoice->line_items = $this->buildLineItems();

View File

@ -70,7 +70,7 @@ class EmailStatementService
'show_aging_table' => $this->scheduler->parameters['show_aging_table'] ?? true,
'show_credits_table' => $this->scheduler->parameters['show_credits_table'] ?? true,
'only_clients_with_invoices' => $this->scheduler->parameters['only_clients_with_invoices'] ?? false,
'status' => $this->scheduler->parameters['status']
'status' => $this->scheduler->parameters['status'] ?? 'all',
];
}