Merge pull request #7259 from turbo124/v5-develop

v5.3.65
This commit is contained in:
David Bomba 2022-03-05 20:36:18 +11:00 committed by GitHub
commit 0e5d0ae756
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1005 additions and 625 deletions

View File

@ -1 +1 @@
5.3.64 5.3.65

View File

@ -77,17 +77,27 @@ class BackupUpdate extends Command
{ {
set_time_limit(0); set_time_limit(0);
Backup::whereRaw('html_backup IS NOT NULL')->chunk(5000, function ($backups) { Backup::whereHas('activity')->whereRaw('html_backup IS NOT NULL')->cursor()->each( function ($backup) {
foreach ($backups as $backup) {
if(strlen($backup->html_backup) > 1 && $backup->activity->client()->exists()){
$client = $backup->activity->client; if(strlen($backup->html_backup) > 1 && $backup->activity->invoice->exists()){
$client = $backup->activity->invoice->client;
$backup->storeRemotely($backup->html_backup, $client);
}else if(strlen($backup->html_backup) > 1 && $backup->activity->quote->exists()){
$client = $backup->activity->quote->client;
$backup->storeRemotely($backup->html_backup, $client);
}else if(strlen($backup->html_backup) > 1 && $backup->activity->credit->exists()){
$client = $backup->activity->credit->client;
$backup->storeRemotely($backup->html_backup, $client); $backup->storeRemotely($backup->html_backup, $client);
} }
}
}); });
} }

View File

@ -12,6 +12,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Jobs\Util\VersionCheck; use App\Jobs\Util\VersionCheck;
use App\Utils\Ninja;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
@ -59,7 +60,12 @@ class PostUpdate extends Command
info("finished running composer install "); info("finished running composer install ");
try { try {
if(Ninja::isHosted())
Artisan::call('optimize'); Artisan::call('optimize');
else
Artisan::call('config:clear');
} catch (\Exception $e) { } catch (\Exception $e) {
info("I wasn't able to optimize."); info("I wasn't able to optimize.");
} }

View File

@ -62,21 +62,46 @@ class RecurringInvoiceController extends Controller
public function requestCancellation(RequestCancellationRequest $request, RecurringInvoice $recurring_invoice) public function requestCancellation(RequestCancellationRequest $request, RecurringInvoice $recurring_invoice)
{ {
if (is_null($recurring_invoice->subscription_id) || optional($recurring_invoice->subscription)->allow_cancellation) { nlog("outside cancellation");
if (optional($recurring_invoice->subscription)->allow_cancellation) {
nlog("inside the cancellation");
$nmo = new NinjaMailerObject; $nmo = new NinjaMailerObject;
$nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user()))->build())); $nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user()))->build()));
$nmo->company = $recurring_invoice->company; $nmo->company = $recurring_invoice->company;
$nmo->settings = $recurring_invoice->company->settings; $nmo->settings = $recurring_invoice->company->settings;
$notifiable_users = $this->filterUsersByPermissions($recurring_invoice->company->company_users, $recurring_invoice, ['recurring_cancellation']); // $notifiable_users = $this->filterUsersByPermissions($recurring_invoice->company->company_users, $recurring_invoice, ['recurring_cancellation']);
$recurring_invoice->company->company_users->each(function ($company_user) use ($nmo){
$methods = $this->findCompanyUserNotificationType($company_user, ['recurring_cancellation', 'all_notifications']);
//if mail is a method type -fire mail!!
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$notifiable_users->each(function ($company_user) use($nmo){
$nmo->to_user = $company_user->user; $nmo->to_user = $company_user->user;
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
}
}); });
// $notifiable_users->each(function ($company_user) use($nmo){
// $nmo->to_user = $company_user->user;
// NinjaMailerJob::dispatch($nmo);
// });
//$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user())); //$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user()));
return $this->render('recurring_invoices.cancellation.index', [ return $this->render('recurring_invoices.cancellation.index', [

View File

@ -169,7 +169,8 @@ class SetupController extends Controller
/* Run migrations */ /* Run migrations */
if (!config('ninja.disable_auto_update')) { if (!config('ninja.disable_auto_update')) {
Artisan::call('optimize'); Artisan::call('config:clear');
// Artisan::call('optimize');
} }
Artisan::call('migrate', ['--force' => true]); Artisan::call('migrate', ['--force' => true]);

View File

@ -111,7 +111,7 @@ class ZipInvoices implements ShouldQueue
} }
catch(\PhpZip\Exception\ZipException $e){ catch(\PhpZip\Exception\ZipException $e){
// handle exception nlog("could not make zip => ". $e->getMessage());
} }
finally{ finally{
$zipFile->close(); $zipFile->close();

View File

@ -41,12 +41,17 @@ class NinjaMailer extends Mailable
$from_name = $this->mail_obj->from_name; $from_name = $this->mail_obj->from_name;
} }
return $this->from(config('mail.from.address'), $from_name) $ninja_mailable = $this->from(config('mail.from.address'), $from_name)
->subject($this->mail_obj->subject) ->subject($this->mail_obj->subject)
->view($this->mail_obj->markdown, $this->mail_obj->data) ->view($this->mail_obj->markdown, $this->mail_obj->data)
->withSwiftMessage(function ($message) { ->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag); $message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag);
}); });
if(property_exists($this->mail_obj, 'text_view')){
$ninja_mailable->text($this->mail_obj->text_view, $this->mail_obj->data);
}
return $ninja_mailable;
} }
} }

View File

@ -77,9 +77,6 @@ class UserEmailChanged implements ShouldQueue
NinjaMailerJob::dispatch($nmo, true); NinjaMailerJob::dispatch($nmo, true);
// $nmo->to_user = $this->new_user;
// NinjaMailerJob::dispatch($nmo);
$this->new_user->service()->invite($this->company); $this->new_user->service()->invite($this->company);
} }

View File

@ -39,6 +39,10 @@ class UnlinkFile implements ShouldQueue
*/ */
public function handle() public function handle()
{ {
/* Do not delete files if we are on the sync queue*/
if(config('queue.default') == 'sync')
return;
Storage::disk($this->disk)->delete($this->file_path); Storage::disk($this->disk)->delete($this->file_path);
} }
} }

View File

@ -63,6 +63,7 @@ class VerifyUserObject
$mail_obj->data = $data; $mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic'; $mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key; $mail_obj->tag = $this->company->company_key;
$mail_obj->text_view = 'email.admin.verify_user_text';
return $mail_obj; return $mail_obj;
} }

View File

@ -58,6 +58,7 @@ class ContactPasswordlessLogin extends Mailable
return $this return $this
->subject(ctrans('texts.account_passwordless_login')) ->subject(ctrans('texts.account_passwordless_login'))
->text('email.billing.passwordless-login_text')
->view('email.billing.passwordless-login', [ ->view('email.billing.passwordless-login', [
'logo' => $this->company->present()->logo(), 'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings, 'settings' => $this->company->settings,

View File

@ -43,6 +43,9 @@ class DownloadBackup extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_backup_subject', ['company' => $company->present()->name()])) ->subject(ctrans('texts.download_backup_subject', ['company' => $company->present()->name()]))
->text('email.admin.download_files_text',[
'url' => $this->file_path,
])
->view('email.admin.download_files', [ ->view('email.admin.download_files', [
'url' => $this->file_path, 'url' => $this->file_path,
'logo' => $company->present()->logo, 'logo' => $company->present()->logo,

View File

@ -42,6 +42,9 @@ class DownloadCredits extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_files')) ->subject(ctrans('texts.download_files'))
->text('email.admin.download_credits_text', [
'url' => $this->file_path,
])
->view('email.admin.download_credits', [ ->view('email.admin.download_credits', [
'url' => $this->file_path, 'url' => $this->file_path,
'logo' => $this->company->present()->logo, 'logo' => $this->company->present()->logo,

View File

@ -42,6 +42,9 @@ class DownloadInvoices extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_files')) ->subject(ctrans('texts.download_files'))
->text('email.admin.download_invoices_text', [
'url' => $this->file_path,
])
->view('email.admin.download_invoices', [ ->view('email.admin.download_invoices', [
'url' => $this->file_path, 'url' => $this->file_path,
'logo' => $this->company->present()->logo, 'logo' => $this->company->present()->logo,

View File

@ -42,6 +42,9 @@ class DownloadQuotes extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_files')) ->subject(ctrans('texts.download_files'))
->text('email.admin.download_quotes_text', [
'url' => $this->file_path,
])
->view('email.admin.download_quotes', [ ->view('email.admin.download_quotes', [
'url' => $this->file_path, 'url' => $this->file_path,
'logo' => $this->company->present()->logo, 'logo' => $this->company->present()->logo,

View File

@ -33,6 +33,10 @@ class BaseEmailEngine implements EngineInterface
public $invitation; public $invitation;
public $text_body;
public $text_footer;
public function setFooter($footer) public function setFooter($footer)
{ {
$this->footer = $footer; $this->footer = $footer;
@ -105,6 +109,13 @@ class BaseEmailEngine implements EngineInterface
return $this; return $this;
} }
public function setTextBody($text)
{
$this->text_body = $text;
return $this;
}
public function getSubject() public function getSubject()
{ {
return $this->subject; return $this->subject;
@ -148,11 +159,37 @@ class BaseEmailEngine implements EngineInterface
public function setInvitation($invitation) public function setInvitation($invitation)
{ {
$this->invitation = $invitation; $this->invitation = $invitation;
return $this;
} }
public function getInvitation() public function getInvitation()
{ {
return $this->invitation; return $this->invitation;
} }
public function getTextBody()
{
return $this->text_body;
}
private function replaceEntities($content)
{
$find = [
'<p>',
'</p>',
'<div class="center">',
'<\div>',
];
$replace = [
'',
'\n\n',
'',
'\n\n',
];
return str_replace($find, $replace, $content);
}
} }

View File

@ -93,6 +93,18 @@ class CreditEmailEngine extends BaseEmailEngine
); );
} }
$text_body = trans(
'texts.credit_message',
[
'credit' => $this->credit->number,
'company' => $this->credit->company->present()->name(),
'amount' => Number::formatMoney($this->credit->balance, $this->client),
],
null,
$this->client->locale()
) . "\n\n" . $this->invitation->getLink();
$this->setTemplate($this->client->getSetting('email_style')) $this->setTemplate($this->client->getSetting('email_style'))
->setContact($this->contact) ->setContact($this->contact)
->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine ->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine
@ -101,7 +113,8 @@ class CreditEmailEngine extends BaseEmailEngine
->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_credit').'</a>') ->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_credit').'</a>')
->setViewLink($this->invitation->getLink()) ->setViewLink($this->invitation->getLink())
->setViewText(ctrans('texts.view_credit')) ->setViewText(ctrans('texts.view_credit'))
->setInvitation($this->invitation); ->setInvitation($this->invitation)
->setTextBody($text_body);
if ($this->client->getSetting('pdf_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {

View File

@ -46,4 +46,7 @@ interface EngineInterface
public function getViewText(); public function getViewText();
public function build(); public function build();
public function getTextBody();
} }

View File

@ -79,6 +79,17 @@ class InvoiceEmailEngine extends BaseEmailEngine
} }
$text_body = trans(
'texts.invoice_message',
[
'invoice' => $this->invoice->number,
'company' => $this->invoice->company->present()->name(),
'amount' => Number::formatMoney($this->invoice->balance, $this->client),
],
null,
$this->client->locale()
) . "\n\n" . $this->invitation->getLink();
if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) {
$subject_template = $this->template_data['subject']; $subject_template = $this->template_data['subject'];
nlog("subject = template data"); nlog("subject = template data");
@ -111,7 +122,8 @@ class InvoiceEmailEngine extends BaseEmailEngine
->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_invoice').'</a>') ->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_invoice').'</a>')
->setViewLink($this->invitation->getLink()) ->setViewLink($this->invitation->getLink())
->setViewText(ctrans('texts.view_invoice')) ->setViewText(ctrans('texts.view_invoice'))
->setInvitation($this->invitation); ->setInvitation($this->invitation)
->setTextBody($text_body);
if ($this->client->getSetting('pdf_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {

View File

@ -94,6 +94,18 @@ class QuoteEmailEngine extends BaseEmailEngine
); );
} }
$text_body = trans(
'texts.quote_message',
[
'quote' => $this->quote->number,
'company' => $this->quote->company->present()->name(),
'amount' => Number::formatMoney($this->quote->amount, $this->client),
],
null,
$this->client->locale()
) . "\n\n" . $this->invitation->getLink();
$this->setTemplate($this->client->getSetting('email_style')) $this->setTemplate($this->client->getSetting('email_style'))
->setContact($this->contact) ->setContact($this->contact)
->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine ->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine
@ -102,7 +114,8 @@ class QuoteEmailEngine extends BaseEmailEngine
->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_quote').'</a>') ->setFooter("<a href='{$this->invitation->getLink()}'>".ctrans('texts.view_quote').'</a>')
->setViewLink($this->invitation->getLink()) ->setViewLink($this->invitation->getLink())
->setViewText(ctrans('texts.view_quote')) ->setViewText(ctrans('texts.view_quote'))
->setInvitation($this->invitation); ->setInvitation($this->invitation)
->setTextBody($text_body);
if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {

View File

@ -44,6 +44,7 @@ class ExistingMigration extends Mailable
return $this return $this
->from(config('mail.from.address'), config('mail.from.name')) ->from(config('mail.from.address'), config('mail.from.name'))
->text('email.migration.existing_text')
->view('email.migration.existing'); ->view('email.migration.existing');
} }
} }

View File

@ -54,6 +54,7 @@ class ACHVerificationNotification extends Mailable
return $this return $this
->subject(ctrans('texts.ach_verification_notification_label')) ->subject(ctrans('texts.ach_verification_notification_label'))
->text('email.gateways.ach-verification-notification_text')
->view('email.gateways.ach-verification-notification', [ ->view('email.gateways.ach-verification-notification', [
'logo' => $this->company->present()->logo(), 'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings, 'settings' => $this->company->settings,

View File

@ -59,10 +59,9 @@ class CompanyImportFailure extends Mailable
$this->title = ctrans('texts.company_import_failure_subject', ['company' => $this->company->present()->name()]); $this->title = ctrans('texts.company_import_failure_subject', ['company' => $this->company->present()->name()]);
$this->whitelabel = $this->company->account->isPaid(); $this->whitelabel = $this->company->account->isPaid();
nlog($this->user_message);
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.company_import_failure_subject', ['company' => $this->company->present()->name()])) ->subject(ctrans('texts.company_import_failure_subject', ['company' => $this->company->present()->name()]))
->text('email.import.import_failure_text')
->view('email.import.import_failure', ['user_message' => $this->user_message, 'title' => $this->title]); ->view('email.import.import_failure', ['user_message' => $this->user_message, 'title' => $this->title]);
} }
} }

View File

@ -48,6 +48,7 @@ class MigrationCompleted extends Mailable
$data['logo'] = $this->company->present()->logo(); $data['logo'] = $this->company->present()->logo();
$result = $this->from(config('mail.from.address'), config('mail.from.name')) $result = $this->from(config('mail.from.address'), config('mail.from.name'))
->text('email.import.completed_text', $data)
->view('email.import.completed', $data); ->view('email.import.completed', $data);
return $result; return $result;

View File

@ -40,6 +40,7 @@ class MigrationFailed extends Mailable
return $this return $this
->from(config('mail.from.address'), config('mail.from.name')) ->from(config('mail.from.address'), config('mail.from.name'))
->text('email.migration.failed_text')
->view('email.migration.failed', [ ->view('email.migration.failed', [
'logo' => $this->company->present()->logo(), 'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings, 'settings' => $this->company->settings,

View File

@ -58,6 +58,7 @@ class ClientContactRequestCancellationObject
$mail_obj->data = $data; $mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic'; $mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key; $mail_obj->tag = $this->company->company_key;
$mail_obj->text_view = 'email.admin.generic_text';
return $mail_obj; return $mail_obj;
} }

View File

@ -92,12 +92,10 @@ class TemplateEmail extends Mailable
$this->bcc(explode(",",str_replace(" ", "", $settings->bcc_email)));//remove whitespace if any has been inserted. $this->bcc(explode(",",str_replace(" ", "", $settings->bcc_email)));//remove whitespace if any has been inserted.
$this->subject($this->build_email->getSubject()) $this->subject($this->build_email->getSubject())
->text('email.template.plain', [ ->text('email.template.text', [
'body' => $this->build_email->getBody(), 'text_body' => $this->build_email->getTextBody(),
'footer' => $this->build_email->getFooter(),
'whitelabel' => $this->client->user->account->isPaid() ? true : false, 'whitelabel' => $this->client->user->account->isPaid() ? true : false,
'settings' => $settings, 'settings' => $settings,
'unsubscribe_link' => $this->invitation ? $this->invitation->getUnsubscribeLink() : '',
]) ])
->view($template_name, [ ->view($template_name, [
'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]), 'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]),
@ -111,7 +109,6 @@ class TemplateEmail extends Mailable
'company' => $company, 'company' => $company,
'whitelabel' => $this->client->user->account->isPaid() ? true : false, 'whitelabel' => $this->client->user->account->isPaid() ? true : false,
'logo' => $this->company->present()->logo($settings), 'logo' => $this->company->present()->logo($settings),
'unsubscribe_link' => $this->invitation ? $this->invitation->getUnsubscribeLink() : '',
]) ])
->withSwiftMessage(function ($message) use($company){ ->withSwiftMessage(function ($message) use($company){
$message->getHeaders()->addTextHeader('Tag', $company->company_key); $message->getHeaders()->addTextHeader('Tag', $company->company_key);

View File

@ -50,6 +50,7 @@ class UserAdded extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.created_user')) ->subject(ctrans('texts.created_user'))
->text('email.admin.user_added_text')
->view('email.admin.user_added') ->view('email.admin.user_added')
->with([ ->with([
'settings' => $this->company->settings, 'settings' => $this->company->settings,

View File

@ -50,6 +50,10 @@ class UserLoggedIn extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.new_login_detected')) ->subject(ctrans('texts.new_login_detected'))
->text('email.admin.generic_text',[
'title' => ctrans('texts.new_login_detected'),
'body' => strip_tags(ctrans('texts.new_login_description', ['email' => $this->user->email, 'ip' => $this->ip, 'time' => now()]))
])
->view('email.admin.notification') ->view('email.admin.notification')
->with([ ->with([
'settings' => $this->company->settings, 'settings' => $this->company->settings,

View File

@ -37,6 +37,10 @@ class UserNotificationMailer extends Mailable
{ {
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject($this->mail_obj->subject) ->subject($this->mail_obj->subject)
->text('email.admin.generic_text',[
'title' => $this->mail_obj->data['title'],
'body' => $this->mail_obj->data['message'],
])
->view($this->mail_obj->markdown, $this->mail_obj->data) ->view($this->mail_obj->markdown, $this->mail_obj->data)
->withSwiftMessage(function ($message) { ->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag); $message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag);

View File

@ -177,6 +177,11 @@ class Activity extends StaticModel
return $this->belongsTo(Invoice::class)->withTrashed(); return $this->belongsTo(Invoice::class)->withTrashed();
} }
public function credit()
{
return $this->belongsTo(Credit::class)->withTrashed();
}
/** /**
* @return mixed * @return mixed
*/ */

View File

@ -38,7 +38,7 @@ class PaymentHash extends Model
public function fee_invoice() public function fee_invoice()
{ {
return $this->belongsTo(Invoice::class, 'fee_invoice_id', 'id'); return $this->belongsTo(Invoice::class, 'fee_invoice_id', 'id')->withTrashed();
} }
public function withData(string $property, $value): self public function withData(string $property, $value): self

View File

@ -75,7 +75,6 @@ class ACH
$message = [ $message = [
'server_response' => $e->getMessage(), 'server_response' => $e->getMessage(),
'data' => $this->wepay_payment_driver->payment_hash->data,
]; ];
SystemLogger::dispatch( SystemLogger::dispatch(

View File

@ -148,6 +148,7 @@ class ApplyPayment
if ((int)$this->invoice->balance == 0) { if ((int)$this->invoice->balance == 0) {
$this->invoice->service()->deletePdf(); $this->invoice->service()->deletePdf();
$this->invoice = $this->invoice->fresh();
event(new InvoiceWasPaid($this->invoice, $this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new InvoiceWasPaid($this->invoice, $this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
} }
} }

View File

@ -47,7 +47,7 @@ class AutoBillInvoice extends AbstractService
MultiDB::setDb($this->db); MultiDB::setDb($this->db);
$this->client = $this->invoice->client; $this->client = $this->invoice->client->fresh();
$is_partial = false; $is_partial = false;
@ -181,7 +181,9 @@ class AutoBillInvoice extends AbstractService
->updatePaymentBalance($amount * -1) ->updatePaymentBalance($amount * -1)
->save(); ->save();
$this->invoice->client->service() $client = $this->invoice->client->fresh();
$client->service()
->updateBalance($amount * -1) ->updateBalance($amount * -1)
->updatePaidToDate($amount) ->updatePaidToDate($amount)
->adjustCreditBalance($amount * -1) ->adjustCreditBalance($amount * -1)

View File

@ -41,6 +41,8 @@ class UpdateInvoicePayment
collect($paid_invoices)->each(function ($paid_invoice) use ($invoices) { collect($paid_invoices)->each(function ($paid_invoice) use ($invoices) {
$client = $this->payment->client->fresh();
$invoice = $invoices->first(function ($inv) use ($paid_invoice) { $invoice = $invoices->first(function ($inv) use ($paid_invoice) {
return $paid_invoice->invoice_id == $inv->hashed_id; return $paid_invoice->invoice_id == $inv->hashed_id;
}); });
@ -70,8 +72,7 @@ class UpdateInvoicePayment
->ledger() ->ledger()
->updatePaymentBalance($paid_amount * -1); ->updatePaymentBalance($paid_amount * -1);
$this->payment $client
->client
->service() ->service()
->updateBalance($paid_amount * -1) ->updateBalance($paid_amount * -1)
->updatePaidToDate($paid_amount) ->updatePaidToDate($paid_amount)
@ -95,10 +96,11 @@ class UpdateInvoicePayment
$invoices->each(function ($invoice) { $invoices->each(function ($invoice) {
$invoice = $invoice->fresh();
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
}); });
return $this->payment; return $this->payment->fresh();
} }
} }

View File

@ -16,9 +16,13 @@ use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory; use App\Factory\InvoiceFactory;
use App\Factory\InvoiceToRecurringInvoiceFactory; use App\Factory\InvoiceToRecurringInvoiceFactory;
use App\Factory\RecurringInvoiceFactory; use App\Factory\RecurringInvoiceFactory;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Jobs\Util\SubscriptionWebhookHandler; use App\Jobs\Util\SubscriptionWebhookHandler;
use App\Jobs\Util\SystemLogger; use App\Jobs\Util\SystemLogger;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Mail\RecurringInvoice\ClientContactRequestCancellationObject;
use App\Models\Client; use App\Models\Client;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Models\Credit; use App\Models\Credit;
@ -36,6 +40,7 @@ use App\Services\Subscription\ZeroCostProduct;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Traits\CleanLineItems; use App\Utils\Traits\CleanLineItems;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
use App\Utils\Traits\SubscriptionHooker; use App\Utils\Traits\SubscriptionHooker;
use Carbon\Carbon; use Carbon\Carbon;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
@ -46,6 +51,7 @@ class SubscriptionService
use MakesHash; use MakesHash;
use CleanLineItems; use CleanLineItems;
use SubscriptionHooker; use SubscriptionHooker;
use UserNotifies;
/** @var subscription */ /** @var subscription */
private $subscription; private $subscription;
@ -102,7 +108,7 @@ class SubscriptionService
} }
else else
{ {
$invoice = Invoice::find($payment_hash->fee_invoice_id); $invoice = Invoice::withTrashed()->find($payment_hash->fee_invoice_id);
$context = [ $context = [
'context' => 'single_purchase', 'context' => 'single_purchase',
@ -934,6 +940,29 @@ class SubscriptionService
$this->triggerWebhook($context); $this->triggerWebhook($context);
$nmo = new NinjaMailerObject;
$nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->guard('contact')->user()))->build()));
$nmo->company = $recurring_invoice->company;
$nmo->settings = $recurring_invoice->company->settings;
$recurring_invoice->company->company_users->each(function ($company_user) use ($nmo){
$methods = $this->findCompanyUserNotificationType($company_user, ['recurring_cancellation', 'all_notifications']);
//if mail is a method type -fire mail!!
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$nmo->to_user = $company_user->user;
NinjaMailerJob::dispatch($nmo);
}
});
return $this->handleRedirect('client/subscriptions'); return $this->handleRedirect('client/subscriptions');
} }

View File

@ -26,12 +26,12 @@
], ],
"type": "project", "type": "project",
"require": { "require": {
"php": "^7.4|^8", "php": "^7.4|^8.0",
"ext-dom": "*", "ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-libxml": "*", "ext-libxml": "*",
"afosto/yaac": "^1.4", "afosto/yaac": "^1.4",
"asm/php-ansible": "dev-main", "asm/php-ansible": "^3",
"authorizenet/authorizenet": "^2.0", "authorizenet/authorizenet": "^2.0",
"bacon/bacon-qr-code": "^2.0", "bacon/bacon-qr-code": "^2.0",
"beganovich/snappdf": "^1.7", "beganovich/snappdf": "^1.7",

1168
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.3.64', 'app_version' => '5.3.65',
'app_tag' => '5.3.64', 'app_tag' => '5.3.65',
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''), 'api_secret' => env('API_SECRET', ''),

View File

@ -0,0 +1,10 @@
@component('email.template.admin', ['logo' => $logo, 'settings' => $settings])
<div class="center">
<h1>{{ ctrans('texts.credits_backup_subject') }}</h1>
<p>{{ ctrans('texts.download_timeframe') }}</p>
<a target="_blank" class="button" href="{{ $url }}">
{{ ctrans('texts.download') }}
</a>
</div>
@endcomponent

View File

@ -0,0 +1,5 @@
{!! ctrans('texts.credits_backup_subject') !!}
{!! ctrans('texts.download_timeframe') !!}
{!! $url !!}

View File

@ -0,0 +1,5 @@
{!! ctrans('texts.download_backup_subject') !!}
{!! ctrans('texts.download_timeframe') !!}
{!! $url !!}

View File

@ -0,0 +1,5 @@
{!! ctrans('texts.invoices_backup_subject') !!}
{!! ctrans('texts.download_timeframe') !!}
{!! $url !!}

View File

@ -0,0 +1,10 @@
@component('email.template.admin', ['logo' => $logo, 'settings' => $settings])
<div class="center">
<h1>{{ ctrans('texts.quotes_backup_subject') }}</h1>
<p>{{ ctrans('texts.download_timeframe') }}</p>
<a target="_blank" class="button" href="{{ $url }}">
{{ ctrans('texts.download') }}
</a>
</div>
@endcomponent

View File

@ -0,0 +1,5 @@
{!! ctrans('texts.quotes_backup_subject') !!}
{!! ctrans('texts.download_timeframe') !!}
{!! $url !!}

View File

@ -0,0 +1,9 @@
{!! $title !!}
@isset($body)
{!! $body !!}
@endisset
@isset($content)
{!! $content !!}
@endisset

View File

@ -0,0 +1,3 @@
{!! $title !!}
{!! $body !!}

View File

@ -0,0 +1,5 @@
{!! $title !!}
{!! ctrans('texts.confirmation_message') !!}
{!! $url !!}

View File

@ -0,0 +1,6 @@
{!! ctrans('texts.login_link_requested_label') !!}
{!! ctrans('texts.login_link_requested') !!}
{!! $url !!}

View File

@ -0,0 +1,5 @@
{!! ctrans('texts.ach_verification_notification_label') !!}
{!! ctrans('texts.ach_verification_notification') !!}
{!! $url !!}

View File

@ -0,0 +1,73 @@
Hello, here is the output of your recent import job.
If your logo imported correctly it will available display below. If it didn't import, you'll need to reupload your logo
{!! $company->present()->logo() !!}
@if(isset($company) && $company->clients->count() >=1)
{!! ctrans('texts.clients') !!}: {!! $company->clients->count() !!}
@endif
@if(isset($company) && count($company->products) >=1)
{!! ctrans('texts.products') !!}: {!! count($company->products) !!}
@endif
@if(isset($company) && count($company->invoices) >=1)
{!! ctrans('texts.invoices') !!}: {!! count($company->invoices) !!}
@endif
@if(isset($company) && count($company->payments) >=1)
{!! ctrans('texts.payments') !!}: {!! count($company->payments) !!}
@endif
@if(isset($company) && count($company->recurring_invoices) >=1)
{!! ctrans('texts.recurring_invoices') !!}: {!! count($company->recurring_invoices) !!}
@endif
@if(isset($company) && count($company->quotes) >=1)
{!! ctrans('texts.quotes') !!}: {!! count($company->quotes) !!}
@endif
@if(isset($company) && count($company->credits) >=1)
{!! ctrans('texts.credits') !!}: {!! count($company->credits) !!}
@endif
@if(isset($company) && count($company->projects) >=1)
{!! ctrans('texts.projects') !!}: {!! count($company->projects) !!}
@endif
@if(isset($company) && count($company->tasks) >=1)
{!! ctrans('texts.tasks') !!}: {!! count($company->tasks) !!}
@endif
@if(isset($company) && count($company->vendors) >=1)
{!! ctrans('texts.vendors') !!}: {!! count($company->vendors) !!}
@endif
@if(isset($company) && count($company->expenses) >=1)
{!! ctrans('texts.expenses') !!}: {!! count($company->expenses) !!}
@endif
@if(isset($company) && count($company->company_gateways) >=1)
{!! ctrans('texts.gateways') !!}: {!! count($company->company_gateways) !!}
@endif
@if(isset($company) && count($company->client_gateway_tokens) >=1)
{!! ctrans('texts.tokens') !!}: {!! count($company->client_gateway_tokens) !!}
@endif
@if(isset($company) && count($company->tax_rates) >=1)
{!! ctrans('texts.tax_rates') !!}: {!! count($company->tax_rates) !!}
@endif
@if(isset($company) && count($company->documents) >=1)
{!! ctrans('texts.documents') !!}: {!! count($company->documents) !!}
@endif
{!! url('/') !!}
{!! ctrans('texts.email_signature') !!}
{!! ctrans('texts.email_from') !!}

View File

@ -0,0 +1,7 @@
{!! $title !!}
{!! ctrans('texts.company_import_failure_body') !!}
@if(isset($whitelabel) && !$whitelabel)
{{ ctrans('texts.ninja_email_footer', ['site' => 'https://invoiceninja.com']) }}
@endif

View File

@ -0,0 +1,3 @@
{!! ctrans('texts.migration_already_completed') !!}
{!! ctrans('texts.migration_already_completed_desc', ['company_name' => $company_name]) !!}

View File

@ -0,0 +1,11 @@
{!! ctrans('texts.migration_failed_label') !!}
{!! ctrans('texts.migration_failed') }} {{ $company->present()->name() !!}
@if(\App\Utils\Ninja::isSelfHost() || $is_system)
{!! $exception->getMessage() !!}
{!! $content !!}
@else
Please contact us at contact@invoiceninja.com for more information on this error.
@endif

View File

@ -177,9 +177,6 @@
</p> </p>
@endif @endif
</div> </div>
@if(isset($unsubscribe_link))
<p><a href="{{$unsubscribe_link}}">{{ ctrans('texts.unsubscribe') }}</a></p>
@endif
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -0,0 +1,7 @@
{!! $text_body !!}
@isset($whitelabel)
@if(!$whitelabel)
{{ ctrans('texts.ninja_email_footer', ['site' => 'https://invoiceninja.com']) }}
@endif
@endisset