mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Fixes for pdf_variables validation (#3419)
* Client and System Notifications * Fix for group settings currency not applying correctly. * Split head out of design in order to reuse headers and footers * export the designs * Fixes for pdf_variables
This commit is contained in:
parent
d14b21f471
commit
6d5d1da472
@ -13,6 +13,7 @@ namespace App\Designs;
|
||||
|
||||
abstract class AbstractDesign
|
||||
{
|
||||
abstract public function include();
|
||||
|
||||
abstract public function header();
|
||||
|
||||
|
@ -17,8 +17,8 @@ class Bold extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -41,7 +41,12 @@ class Bold extends AbstractDesign
|
||||
margin-top: 5mm;
|
||||
}
|
||||
</style>
|
||||
';
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
<div class="flex static bg-gray-800 p-12">
|
||||
<div class="w-1/2">
|
||||
<div class="absolute bg-white pt-10 px-10 pb-4 inline-block align-middle">
|
||||
|
@ -17,8 +17,8 @@ class Business extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -48,6 +48,13 @@ class Business extends AbstractDesign
|
||||
}
|
||||
</style>
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="my-16 mx-10">
|
||||
<div class="flex justify-between">
|
||||
<div class="w-1/2">
|
||||
|
@ -17,8 +17,9 @@ class Clean extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -41,6 +42,14 @@ class Clean extends AbstractDesign
|
||||
margin-top: 5mm;
|
||||
}
|
||||
</style>
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
|
||||
<div class="px-12 my-10">
|
||||
<div class="flex items-center">
|
||||
|
@ -20,8 +20,9 @@ class Creative extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -45,6 +46,14 @@ class Creative extends AbstractDesign
|
||||
}
|
||||
</style>
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="py-16 mx-16">
|
||||
<div class="flex justify-between">
|
||||
<div class="w-2/3 flex">
|
||||
|
@ -13,6 +13,7 @@ namespace App\Designs;
|
||||
|
||||
class Custom extends AbstractDesign
|
||||
{
|
||||
private $include;
|
||||
|
||||
private $header;
|
||||
|
||||
@ -26,6 +27,7 @@ class Custom extends AbstractDesign
|
||||
|
||||
public function __construct($design)
|
||||
{
|
||||
$this->include = $design->include;
|
||||
|
||||
$this->header = $design->header;
|
||||
|
||||
@ -39,6 +41,11 @@ class Custom extends AbstractDesign
|
||||
|
||||
}
|
||||
|
||||
public function include()
|
||||
{
|
||||
return $this->include;
|
||||
}
|
||||
|
||||
public function header()
|
||||
{
|
||||
|
||||
|
@ -69,6 +69,7 @@ class Designer {
|
||||
{
|
||||
|
||||
$this->exportVariables($entity)
|
||||
->setDesign($this->getSection('include'))
|
||||
->setDesign($this->getSection('header'))
|
||||
->setDesign($this->getSection('body'))
|
||||
->setDesign($this->getTable($entity))
|
||||
|
@ -17,8 +17,9 @@ class Elegant extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -42,6 +43,14 @@ class Elegant extends AbstractDesign
|
||||
}
|
||||
</style>
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="py-16 px-8">
|
||||
<div class="flex flex justify-between border-b-4 border-black">
|
||||
<div style="margin-bottom: 15px">
|
||||
|
@ -17,8 +17,9 @@ class Hipster extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -42,6 +43,15 @@ class Hipster extends AbstractDesign
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="px-12 py-16">
|
||||
<div class="flex">
|
||||
<div class="w-1/2 border-l pl-4 border-black mr-4">
|
||||
|
@ -17,8 +17,9 @@ class Modern extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -34,6 +35,14 @@ class Modern extends AbstractDesign
|
||||
</head>
|
||||
<body>
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="bg-orange-600 flex justify-between py-12 px-12">
|
||||
<div class="w-1/2">
|
||||
<h1 class="text-white font-bold text-5xl">$company.name</h1>
|
||||
|
@ -17,8 +17,9 @@ class Photo extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -34,6 +35,16 @@ class Photo extends AbstractDesign
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<style>
|
||||
@page
|
||||
{
|
||||
|
@ -17,8 +17,9 @@ class Plain extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -43,6 +44,15 @@ class Plain extends AbstractDesign
|
||||
</style>
|
||||
|
||||
<body>
|
||||
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
|
||||
<div class="px-12 py-8">
|
||||
<div class="flex justify-between">
|
||||
$company_logo
|
||||
|
@ -17,8 +17,9 @@ class Playful extends AbstractDesign
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function header() {
|
||||
|
||||
public function include()
|
||||
{
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -41,7 +42,13 @@ class Playful extends AbstractDesign
|
||||
margin-top: 5mm;
|
||||
}
|
||||
</style>
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
public function header() {
|
||||
|
||||
return '
|
||||
<div class="my-12 mx-16">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="w-1/2">
|
||||
|
40
app/Events/Misc/InvitationWasViewed.php
Normal file
40
app/Events/Misc/InvitationWasViewed.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Events\Misc;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class InvitationWasViewed.
|
||||
*/
|
||||
class InvitationWasViewed
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Invoice
|
||||
*/
|
||||
public $invitation;
|
||||
|
||||
public $entity;
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Invoice $invoice
|
||||
*/
|
||||
public function __construct($entity, $invitation)
|
||||
{
|
||||
$this->entity = $entity;
|
||||
$this->invitation = $invitation;
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ namespace App\Helpers\Email;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Utils\Number;
|
||||
|
||||
class InvoiceEmail extends EmailBuilder
|
||||
{
|
||||
@ -30,7 +31,12 @@ class InvoiceEmail extends EmailBuilder
|
||||
/* Use default translations if a custom message has not been set*/
|
||||
if (iconv_strlen($body_template) == 0) {
|
||||
$body_template = trans('texts.invoice_message',
|
||||
['invoice' => $invoice->number, 'company' => $invoice->company->present()->name()], null,
|
||||
[
|
||||
'invoice' => $invoice->number,
|
||||
'company' => $invoice->company->present()->name(),
|
||||
'amount' => Number::formatMoney($invoice->balance, $invoice->client),
|
||||
],
|
||||
null,
|
||||
$invoice->client->locale());
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,14 @@ class InvitationController extends Controller
|
||||
auth()->guard('contact')->login($invitation->contact, false);
|
||||
}
|
||||
|
||||
if(!request()->has('is_admin')){
|
||||
|
||||
$invitation->markViewed();
|
||||
|
||||
event(new InvitationWasViewed($entity, $invitation));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]);
|
||||
} else {
|
||||
abort(404);
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Factory\CloneInvoiceFactory;
|
||||
use App\Factory\CloneInvoiceToQuoteFactory;
|
||||
@ -675,6 +676,9 @@ class InvoiceController extends BaseController {
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
||||
$this->reminder_template = $invoice->calculateTemplate();
|
||||
|
||||
$invoice->invitations->each(function ($invitation) use($invoice){
|
||||
|
||||
$email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template);
|
||||
@ -683,6 +687,11 @@ class InvoiceController extends BaseController {
|
||||
|
||||
});
|
||||
|
||||
if($invoice->invitations->count() > 0){
|
||||
\Log::error("more than one invitation to send");
|
||||
event(new InvoiceWasEmailed($invoice->invitations->first()));
|
||||
}
|
||||
|
||||
if (!$bulk) {
|
||||
return response()->json(['message' => 'email sent'], 200);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ class StoreClientRequest extends Request
|
||||
{
|
||||
$group_settings = GroupSetting::find($input['group_settings_id']);
|
||||
|
||||
if($group_settings && property_exists($group_settings, 'currency_id') && is_int($group_settings->currency_id))
|
||||
if($group_settings && property_exists($group_settings->settings, 'currency_id') && is_int($group_settings->settings->currency_id))
|
||||
$input['settings']->currency_id = $group_settings->currency_id;
|
||||
else
|
||||
$input['settings']->currency_id = auth()->user()->company()->settings->currency_id;
|
||||
|
@ -74,7 +74,7 @@ class StoreUserRequest extends Request
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
||||
//@todo make sure the user links back to the account ID for this company!!!!!!
|
||||
public function fetchUser() :User
|
||||
{
|
||||
$user = MultiDB::hasUser(['email' => $this->input('email')]);
|
||||
|
@ -46,9 +46,9 @@ class InvoiceEmailActivity implements ShouldQueue
|
||||
$fields->invoice_id = $event->invitation->invoice->id;
|
||||
$fields->user_id = $event->invitation->invoice->user_id;
|
||||
$fields->company_id = $event->invitation->invoice->company_id;
|
||||
$fields->contact_id = $event->invitation->invoice->client_contact_id;
|
||||
$fields->client_contact_id = $event->invitation->invoice->client_contact_id;
|
||||
$fields->activity_type_id = Activity::EMAIL_INVOICE;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice);
|
||||
$this->activity_repo->save($fields, $event->invitation->invoice);
|
||||
}
|
||||
}
|
||||
|
56
app/Listeners/Invoice/InvoiceEmailedNotification.php
Normal file
56
app/Listeners/Invoice/InvoiceEmailedNotification.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Listeners\Invoice;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Notifications\Admin\InvoiceSentNotification;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class InvoiceEmailedNotification implements ShouldQueue
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param object $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
$invitation = $event->invitation;
|
||||
|
||||
foreach($invitation->company->company_users as $company_user)
|
||||
{
|
||||
|
||||
$company_user->user->notify(new InvoiceSentNotification($invitation, $invitation->company));
|
||||
|
||||
}
|
||||
|
||||
if(isset($invitation->company->slack_webhook_url)){
|
||||
|
||||
Notification::route('slack', $invitation->company->slack_webhook_url)
|
||||
->notify(new InvoiceSentNotification($invitation, $invitation->company, true));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
55
app/Listeners/Misc/InvitationViewedListener.php
Normal file
55
app/Listeners/Misc/InvitationViewedListener.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Listeners\Misc;
|
||||
|
||||
use App\Notifications\Admin\EntityViewedNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class InvitationViewedListener implements ShouldQueue
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(){}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param object $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
$entity_name = $event->entity;
|
||||
$invitation = $event->invitation;
|
||||
|
||||
$notification = new EntityViewedNotification($invitation, $entity_name);
|
||||
|
||||
foreach($invitation->company->company_users as $company_user)
|
||||
{
|
||||
$company_user->user->notify($notification);
|
||||
}
|
||||
|
||||
if(isset($invitation->company->slack_webhook_url)){
|
||||
|
||||
$notification->is_system = true;
|
||||
|
||||
Notification::route('slack', $payment->company->slack_webhook_url)
|
||||
->notify($notification);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace App\Listeners\Payment;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Notifications\Payment\NewPaymentNotification;
|
||||
use App\Notifications\Admin\NewPaymentNotification;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
@ -41,7 +41,8 @@ class PaymentNotification implements ShouldQueue
|
||||
{
|
||||
$payment = $event->payment;
|
||||
|
||||
//$invoices = $payment->invoices;
|
||||
//todo need to iterate through teh company user and determine if the user
|
||||
//will receive this notification.
|
||||
|
||||
foreach($payment->company->company_users as $company_user)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ class Currency extends StaticModel
|
||||
public $timestamps = false;
|
||||
|
||||
protected $casts = [
|
||||
'exchange_rate' => 'float',
|
||||
'swap_currency_symbol' => 'boolean',
|
||||
'updated_at' => 'timestamp',
|
||||
'created_at' => 'timestamp',
|
||||
|
@ -71,4 +71,9 @@ class QuoteInvitation extends BaseModel
|
||||
|
||||
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name));
|
||||
}
|
||||
|
||||
public function markViewed() {
|
||||
$this->viewed_date = Carbon::now();
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
131
app/Notifications/Admin/EntityViewedNotification.php
Normal file
131
app/Notifications/Admin/EntityViewedNotification.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Admin;
|
||||
|
||||
use App\Utils\Number;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class EntityViewedNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable, Dispatchable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
* @
|
||||
*/
|
||||
|
||||
protected $invitation;
|
||||
|
||||
protected $entity_name;
|
||||
|
||||
protected $entity;
|
||||
|
||||
protected $company;
|
||||
|
||||
protected $settings;
|
||||
|
||||
public $is_system;
|
||||
|
||||
protected $contact;
|
||||
|
||||
public function __construct($invitation, $entity_name, $is_system = false, $settings = null)
|
||||
{
|
||||
$this->entity = $invitation->{$entity_name};
|
||||
$this->contact = $invitation->contact;
|
||||
$this->company = $invitation->company;
|
||||
$this->settings = $this->entity->client->getMergedSettings();
|
||||
$this->is_system = $is_system;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
|
||||
return $this->is_system ? ['slack'] : ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
$data = $this->buildDataArray();
|
||||
$subject = $this->buildSubject();
|
||||
|
||||
return (new MailMessage)
|
||||
->subject($subject)
|
||||
->markdown('email.admin.generic', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
$logo = $this->company->present()->logo();
|
||||
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->image($logo)
|
||||
->content(ctrans("texts.notification_{$this->entity_name}_viewed",
|
||||
[
|
||||
'amount' => $amount,
|
||||
'client' => $this->contact->present()->name(),
|
||||
$this->entity_name => $this->entity->number
|
||||
]));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function buildDataArray()
|
||||
{
|
||||
|
||||
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||
$subject = ctrans("texts.notification_{$this->entity_name}_viewed_subject",
|
||||
[
|
||||
'client' => $this->contact->present()->name(),
|
||||
$this->entity_name => $this->entity->number,
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'title' => $subject,
|
||||
'message' => ctrans("texts.notification_{$this->entity_name}_viewed",
|
||||
[
|
||||
'amount' => $amount,
|
||||
'client' => $this->contact->present()->name(),
|
||||
$this->entity_name => $this->entity->number,
|
||||
]),
|
||||
'url' => config('ninja.site_url') . "/{$this->entity_name}s/" . $this->entity->hashed_id,
|
||||
'button' => ctrans("texts.view_{$this->entity_name}"),
|
||||
'signature' => $this->settings->email_signature,
|
||||
'logo' => $this->company->present()->logo(),
|
||||
];
|
||||
|
||||
}
|
||||
}
|
142
app/Notifications/Admin/InvoiceSentNotification.php
Normal file
142
app/Notifications/Admin/InvoiceSentNotification.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Admin;
|
||||
|
||||
use App\Utils\Number;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class InvoiceSentNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected $invitation;
|
||||
|
||||
protected $invoice;
|
||||
|
||||
protected $company;
|
||||
|
||||
protected $settings;
|
||||
|
||||
public $is_system;
|
||||
|
||||
protected $contact;
|
||||
|
||||
public function __construct($invitation, $company, $is_system = false, $settings = null)
|
||||
{
|
||||
$this->invoice = $invitation->invoice;
|
||||
$this->contact = $invitation->contact;
|
||||
$this->company = $company;
|
||||
$this->settings = $this->invoice->client->getMergedSettings();
|
||||
$this->is_system = $is_system;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
|
||||
return $this->is_system ? ['slack'] : ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
|
||||
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
||||
$subject = ctrans('texts.notification_invoice_sent_subject',
|
||||
[
|
||||
'client' => $this->contact->present()->name(),
|
||||
'invoice' => $this->invoice->number,
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'title' => $subject,
|
||||
'message' => ctrans('texts.notification_invoice_sent',
|
||||
[
|
||||
'amount' => $amount,
|
||||
'client' => $this->contact->present()->name(),
|
||||
'invoice' => $this->invoice->number,
|
||||
]),
|
||||
'url' => config('ninja.site_url') . '/invoices/' . $this->invoice->hashed_id,
|
||||
'button' => ctrans('texts.view_invoice'),
|
||||
'signature' => $this->settings->email_signature,
|
||||
'logo' => $this->company->present()->logo(),
|
||||
];
|
||||
|
||||
|
||||
return (new MailMessage)
|
||||
->subject($subject)
|
||||
->markdown('email.admin.generic', $data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
$logo = $this->company->present()->logo();
|
||||
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
||||
|
||||
// return (new SlackMessage)
|
||||
// ->success()
|
||||
// ->from(ctrans('texts.notification_bot'))
|
||||
// ->image($logo)
|
||||
// ->content(ctrans('texts.notification_invoice_sent',
|
||||
// [
|
||||
// 'amount' => $amount,
|
||||
// 'client' => $this->contact->present()->name(),
|
||||
// 'invoice' => $this->invoice->number
|
||||
// ]));
|
||||
|
||||
|
||||
return (new SlackMessage)
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->success()
|
||||
->image('https://app.invoiceninja.com/favicon-v2.png')
|
||||
->content(trans('texts.notification_invoice_sent_subject',
|
||||
[
|
||||
'amount' => $amount,
|
||||
'client' => $this->contact->present()->name(),
|
||||
'invoice' => $this->invoice->number
|
||||
]))
|
||||
->attachment(function ($attachment) use($amount){
|
||||
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number]), 'http://linky')
|
||||
->fields([
|
||||
ctrans('texts.client') => $this->contact->present()->name(),
|
||||
ctrans('texts.amount') => $amount,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Payment;
|
||||
namespace App\Notifications\Admin;
|
||||
|
||||
use App\Utils\Number;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@ -116,8 +116,9 @@ class InvoiceViewedNotification extends Notification implements ShouldQueue
|
||||
[
|
||||
'amount' => $amount,
|
||||
'client' => $this->contact->present()->name(),
|
||||
'invoice' => $this->invoice->number,
|
||||
]);
|
||||
'invoice' => $this->invoice->number
|
||||
]));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Payment;
|
||||
namespace App\Notifications\Admin;
|
||||
|
||||
use App\Mail\Signup\NewSignup;
|
||||
use App\Utils\Number;
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Payment;
|
||||
namespace App\Notifications\Admin;
|
||||
|
||||
use App\Mail\Signup\NewSignup;
|
||||
use App\Utils\Number;
|
@ -19,6 +19,7 @@ use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasMarkedSent;
|
||||
use App\Events\Invoice\InvoiceWasPaid;
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Events\Misc\InvitationWasViewed;
|
||||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Events\Payment\PaymentWasDeleted;
|
||||
use App\Events\Payment\PaymentWasRefunded;
|
||||
@ -37,8 +38,10 @@ use App\Listeners\Invoice\CreateInvoiceInvitation;
|
||||
use App\Listeners\Invoice\CreateInvoicePdf;
|
||||
use App\Listeners\Invoice\InvoiceEmailActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailFailedActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailedNotification;
|
||||
use App\Listeners\Invoice\UpdateInvoiceActivity;
|
||||
use App\Listeners\Invoice\UpdateInvoiceInvitations;
|
||||
use App\Listeners\Misc\InvitationViewedListener;
|
||||
use App\Listeners\Payment\PaymentNotification;
|
||||
use App\Listeners\SendVerificationNotification;
|
||||
use App\Listeners\SetDBListener;
|
||||
@ -121,11 +124,16 @@ class EventServiceProvider extends ServiceProvider
|
||||
],
|
||||
InvoiceWasEmailed::class => [
|
||||
InvoiceEmailActivity::class,
|
||||
InvoiceEmailedNotification::class,
|
||||
],
|
||||
InvoiceWasEmailedAndFailed::class => [
|
||||
InvoiceEmailFailedActivity::class,
|
||||
],
|
||||
|
||||
InvitationWasViewed::class => [
|
||||
InvitationViewedListener::class
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ trait Inviteable
|
||||
*
|
||||
* @return string The status.
|
||||
*/
|
||||
public function getStatus() : string
|
||||
public function getStatus() :string
|
||||
{
|
||||
$status = '';
|
||||
|
||||
@ -44,7 +44,7 @@ trait Inviteable
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function getLink() : string
|
||||
public function getLink() :string
|
||||
{
|
||||
$entity_type = strtolower(class_basename($this->entityType()));
|
||||
|
||||
@ -67,4 +67,10 @@ trait Inviteable
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function getAdminLink() :string
|
||||
{
|
||||
|
||||
return $this->getLink(). '?is_admin=true';
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,11 @@ trait SettingsSaver
|
||||
private function checkSettingType($settings) : \stdClass
|
||||
{
|
||||
$settings = (object)$settings;
|
||||
|
||||
/* Because of the object casting we cannot check pdf_variables */
|
||||
if(property_exists($settings, 'pdf_variables'))
|
||||
unset($settings->pdf_variables);
|
||||
|
||||
$casts = CompanySettings::$casts;
|
||||
|
||||
foreach ($casts as $key => $value) {
|
||||
|
@ -36,5 +36,22 @@ class DesignSeeder extends Seeder
|
||||
Design::create($design);
|
||||
}
|
||||
|
||||
foreach(Design::all() as $design){
|
||||
|
||||
$class = 'App\Designs\\'.$design->name;
|
||||
$invoice_design = new $class();
|
||||
|
||||
$design_object = new \stdClass;
|
||||
$design_object->include = $invoice_design->include();
|
||||
$design_object->header = $invoice_design->header();
|
||||
$design_object->body = $invoice_design->body();
|
||||
$design_object->table_styles = $invoice_design->table_styles();
|
||||
$design_object->table = $invoice_design->table();
|
||||
$design_object->footer = $invoice_design->footer();
|
||||
|
||||
$design->design = $design_object;
|
||||
$design->save();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -251,9 +251,13 @@ $LANG = array(
|
||||
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
|
||||
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
|
||||
'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client',
|
||||
'notification_credit_viewed_subject' => 'Credit :credit was viewed by :client',
|
||||
'notification_quote_viewed_subject' => 'Quote :quote was viewed by :client',
|
||||
'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
|
||||
'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
|
||||
'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
|
||||
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
|
||||
'notification_quote_viewed' => 'The following client :client viewed Quote :quote for :amount.',
|
||||
'reset_password' => 'You can reset your account password by clicking the following button:',
|
||||
'secure_payment' => 'Secure Payment',
|
||||
'card_number' => 'Card Number',
|
||||
@ -3124,8 +3128,9 @@ $LANG = array(
|
||||
'notification_payment_paid' => 'A payment of :amount was made by client :client towards :invoice',
|
||||
'notification_partial_payment_paid' => 'A partial payment of :amount was made by client :client towards :invoice',
|
||||
'notification_bot' => 'Notification Bot',
|
||||
|
||||
'invoice_number_placeholder' => 'Invoice # :invoice',
|
||||
'email_link_not_working' => 'If button above isn\'t working for you, please click on the link',
|
||||
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
Loading…
x
Reference in New Issue
Block a user