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

Merge pull request #4930 from turbo124/v5-stable

Improvements and bug fixes.
This commit is contained in:
David Bomba 2021-02-17 13:58:13 +11:00 committed by GitHub
commit ac0332eacc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
150 changed files with 128975 additions and 126954 deletions

View File

@ -1 +1 @@
5.1.5
5.1.6

View File

@ -73,6 +73,7 @@ class CheckData extends Command
protected $description = 'Check/fix data';
protected $log = '';
protected $isValid = true;
public function handle()
@ -90,13 +91,10 @@ class CheckData extends Command
$this->checkContacts();
$this->checkCompanyData();
//$this->checkLogoFiles();
if (! $this->option('client_id')) {
$this->checkOAuth();
//$this->checkInvitations();
$this->checkFailedJobs();
//$this->checkFailedJobs();
}
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
@ -298,8 +296,6 @@ class CheckData extends Command
$total_invoice_payments = 0;
foreach ($client->invoices->where('is_deleted', false)->where('status_id', '>', 1) as $invoice) {
// $total_amount = $invoice->payments->whereNull('deleted_at')->sum('pivot.amount');
// $total_refund = $invoice->payments->whereNull('deleted_at')->sum('pivot.refunded');
$total_amount = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.amount');
$total_refund = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.refunded');
@ -307,15 +303,15 @@ class CheckData extends Command
$total_invoice_payments += ($total_amount - $total_refund);
}
// 10/02/21
foreach ($client->payments as $payment) {
$credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
}
if ($credit_total_applied < 0) {
$total_invoice_payments += $credit_total_applied;
} //todo this is contentious
}
// nlog("total invoice payments = {$total_invoice_payments} with client paid to date of of {$client->paid_to_date}");
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
$wrong_paid_to_dates++;
@ -393,8 +389,8 @@ class CheckData extends Command
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
if($client->balance != $invoice_balance)
$invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
// if($client->balance != $invoice_balance)
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();

View File

@ -11,6 +11,7 @@
namespace App\Console\Commands;
use App\Libraries\MultiDB;
use App\Models\Design;
use Illuminate\Console\Command;
use stdClass;
@ -47,6 +48,30 @@ class DesignUpdate extends Command
* @return mixed
*/
public function handle()
{
//always return state to first DB
$current_db = config('database.default');
if (! config('ninja.db.multi_db_enabled')) {
$this->handleOnDb();
} else {
//multiDB environment, need to
foreach (MultiDB::$dbs as $db) {
MultiDB::setDB($db);
$this->handleOnDb($db);
}
MultiDB::setDB($current_db);
}
}
private function handleOnDb()
{
foreach (Design::whereIsCustom(false)->get() as $design) {
$invoice_design = new \App\Services\PdfMaker\Design(strtolower($design->name));

View File

@ -13,6 +13,7 @@ namespace App\Console\Commands;
use App\Jobs\Ninja\SendReminders;
use App\Jobs\Util\WebHookHandler;
use App\Libraries\MultiDB;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\Webhook;
@ -58,6 +59,24 @@ class SendRemindersCron extends Command
}
private function webHookOverdueInvoices()
{
if (! config('ninja.db.multi_db_enabled')) {
$this->executeWebhooks();
} else {
//multiDB environment, need to
foreach (MultiDB::$dbs as $db) {
MultiDB::setDB($db);
$this->executeWebhooks();
}
}
}
private function executeWebhooks()
{
$invoices = Invoice::where('is_deleted', 0)
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
@ -68,10 +87,7 @@ class SendRemindersCron extends Command
$invoices->each(function ($invoice) {
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
});
}
private function webHookExpiredQuotes()
{
$quotes = Quote::where('is_deleted', 0)
->where('status_id', Quote::STATUS_SENT)
->whereDate('due_date', '<=', now()->subDays(1)->startOfDay())
@ -81,4 +97,6 @@ class SendRemindersCron extends Command
WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote, $quote->company);
});
}
}

View File

@ -148,6 +148,7 @@ class CompanySettings extends BaseSettings
public $gmail_sending_user_id = '0'; //@implemented
public $reply_to_email = ''; //@TODO
public $reply_to_name = ''; //@TODO
public $bcc_email = ''; //@TODO
public $pdf_email_attachment = false; //@implemented
public $ubl_email_attachment = false; //@implemented
@ -261,6 +262,7 @@ class CompanySettings extends BaseSettings
public $hide_empty_columns_on_pdf = false;
public static $casts = [
'reply_to_name' => 'string',
'hide_empty_columns_on_pdf' => 'bool',
'enable_reminder_endless' => 'bool',
'use_credits_payment' => 'string',

View File

@ -111,6 +111,10 @@ class Handler extends ExceptionHandler
return false;
}
if (strpos($exception->getMessage(), 'expects parameter 1 to be resource') !== false) {
return false;
}
return true;
}

View File

@ -11,6 +11,8 @@
namespace App\Helpers\Mail;
use App\Utils\TempFile;
use Dacastro4\LaravelGmail\Facade\LaravelGmail;
use Dacastro4\LaravelGmail\Services\Message\Mail;
use Illuminate\Mail\Transport\Transport;
use Swift_Mime_SimpleMessage;
@ -27,49 +29,59 @@ class GmailTransport extends Transport
*/
protected $gmail;
/**
* The GMail OAuth Token.
* @var string token
*/
protected $token;
/**
* Create a new Gmail transport instance.
*
* @param Mail $gmail
* @param string $token
*/
public function __construct(Mail $gmail, string $token)
public function __construct(Mail $gmail)
{
$this->gmail = $gmail;
$this->token = $token;
}
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
{
/* For some reason the Injected Mail class carries cached tokens, so we need to reinit the Mail class*/
$this->gmail = null;
$this->gmail = new Mail;
/*We should nest the token in the message and then discard it as needed*/
$token = $message->getHeaders()->get('GmailToken')->getValue();
$message->getHeaders()->remove('GmailToken');
$this->beforeSendPerformed($message);
$this->gmail->using($this->token);
$this->gmail->using($token);
$this->gmail->to($message->getTo());
$this->gmail->from($message->getFrom());
$this->gmail->subject($message->getSubject());
$this->gmail->message($message->getBody());
//$this->gmail->message($message->toString());
$this->gmail->cc($message->getCc());
$this->gmail->bcc($message->getBcc());
nlog(print_r($message->getChildren(), 1));
foreach ($message->getChildren() as $child)
{
foreach ($message->getChildren() as $child) {
$this->gmail->attach($child);
} //todo this should 'just work'
nlog("trying to attach");
if($child->getContentType() != 'text/plain')
{
$this->gmail->attach(TempFile::filePath($child->getBody(), $child->getHeaders()->get('Content-Type')->getParameter('name') ));
}
}
$this->gmail->send();
$this->sendPerformed($message);
return $this->numberOfRecipients($message);
}
}

View File

@ -1,17 +1,25 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Helpers\Mail;
use Illuminate\Mail\MailManager;
use App\CustomMailDriver\CustomTransport;
use Dacastro4\LaravelGmail\Services\Message\Mail;
use Illuminate\Mail\TransportManager;
use Illuminate\Support\Facades\Config;
class GmailTransportManager extends TransportManager
class GmailTransportManager extends MailManager
{
protected function createGmailDriver()
protected function createGmailTransport()
{
$token = $this->app['config']->get('services.gmail.token', []);
$mail = new Mail;
return new GmailTransport($mail, $token);
return new GmailTransport(new Mail);
}
}

View File

@ -12,8 +12,10 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Libraries\MultiDB;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;
use Illuminate\View\View;
@ -65,4 +67,31 @@ class ContactForgotPasswordController extends Controller
{
return Password::broker('contacts');
}
public function sendResetLinkEmail(Request $request)
{
//MultiDB::userFindAndSetDb($request->input('email'));
$user = MultiDB::hasContact(['email' => $request->input('email')]);
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$this->credentials($request)
);
if ($request->ajax()) {
return $response == Password::RESET_LINK_SENT
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
: response()->json(['message' => 'Email not found', 'status' => false], 401);
}
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($request, $response)
: $this->sendResetLinkFailedResponse($request, $response);
}
}

View File

@ -12,6 +12,7 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Libraries\MultiDB;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
@ -103,6 +104,10 @@ class ForgotPasswordController extends Controller
*/
public function sendResetLinkEmail(Request $request)
{
//MultiDB::userFindAndSetDb($request->input('email'));
$user = MultiDB::hasUser(['email' => $request->input('email')]);
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted

View File

@ -289,7 +289,7 @@ class LoginController extends BaseController
$client = new Google_Client();
$client->setClientId(config('ninja.auth.google.client_id'));
$client->setClientSecret(config('ninja.auth.google.client_secret'));
$client->setRedirectUri(config('ninja.app_url'));
$token = $client->authenticate(request()->input('server_auth_code'));
$refresh_token = '';

View File

@ -21,6 +21,7 @@ use App\Http\Requests\Client\EditClientRequest;
use App\Http\Requests\Client\ShowClientRequest;
use App\Http\Requests\Client\StoreClientRequest;
use App\Http\Requests\Client\UpdateClientRequest;
use App\Http\Requests\Client\UploadClientRequest;
use App\Jobs\Client\StoreClient;
use App\Jobs\Client\UpdateClient;
use App\Models\Client;
@ -29,6 +30,7 @@ use App\Transformers\ClientTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use App\Utils\Traits\Uploadable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -42,6 +44,7 @@ class ClientController extends BaseController
use MakesHash;
use Uploadable;
use BulkOptions;
use SavesDocuments;
protected $entity_type = Client::class;
@ -269,6 +272,7 @@ class ClientController extends BaseController
*/
public function update(UpdateClientRequest $request, Client $client)
{
if ($request->entityIsDeleted($client)) {
return $request->disallowUpdate();
}
@ -515,4 +519,66 @@ class ClientController extends BaseController
{
//todo
}
/**
* Update the specified resource in storage.
*
* @param UploadClientRequest $request
* @param Client $client
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/clients/{id}/upload",
* operationId="uploadClient",
* tags={"clients"},
* summary="Uploads a document to a client",
* description="Handles the uploading of a document to a client",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadClientRequest $request, Client $client)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $client);
return $this->itemResponse($client->fresh());
}
}

View File

@ -13,10 +13,15 @@ namespace App\Http\Controllers\ClientPortal;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\ShowRecurringInvoiceRequest;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\RecurringInvoice\ClientContactRequestCancellationObject;
use App\Models\RecurringInvoice;
use App\Notifications\ClientContactRequestCancellation;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\View\View;
@ -28,6 +33,7 @@ class RecurringInvoiceController extends Controller
{
use MakesHash;
use MakesDates;
use UserNotifies;
/**
* Show the list of recurring invoices.
@ -57,7 +63,22 @@ class RecurringInvoiceController extends Controller
{
//todo double check the user is able to request a cancellation
//can add locale specific by chaining ->locale();
$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user()));
$nmo = new NinjaMailerObject;
$nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user()))->build()));
$nmo->company = $recurring_invoice->company;
$nmo->settings = $recurring_invoice->company->settings;
$notifiable_users = $this->filterUsersByPermissions($recurring_invoice->company->company_users, $recurring_invoice, ['recurring_cancellation']);
$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()));
return $this->render('recurring_invoices.cancellation.index', [
'invoice' => $recurring_invoice,

View File

@ -20,6 +20,7 @@ use App\Http\Requests\Company\EditCompanyRequest;
use App\Http\Requests\Company\ShowCompanyRequest;
use App\Http\Requests\Company\StoreCompanyRequest;
use App\Http\Requests\Company\UpdateCompanyRequest;
use App\Http\Requests\Company\UploadCompanyRequest;
use App\Jobs\Company\CreateCompany;
use App\Jobs\Company\CreateCompanyPaymentTerms;
use App\Jobs\Company\CreateCompanyTaskStatuses;
@ -503,4 +504,65 @@ class CompanyController extends BaseController
return response()->json(['message' => ctrans('texts.success')], 200);
}
/**
* Update the specified resource in storage.
*
* @param UploadCompanyRequest $request
* @param Company $client
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/companies/{id}/upload",
* operationId="uploadCompanies",
* tags={"companies"},
* summary="Uploads a document to a company",
* description="Handles the uploading of a document to a company",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Company Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Company"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadCompanyRequest $request, Company $company)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $company);
return $this->itemResponse($company->fresh());
}
}

View File

@ -14,6 +14,7 @@ use App\Http\Requests\Credit\EditCreditRequest;
use App\Http\Requests\Credit\ShowCreditRequest;
use App\Http\Requests\Credit\StoreCreditRequest;
use App\Http\Requests\Credit\UpdateCreditRequest;
use App\Http\Requests\Credit\UploadCreditRequest;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Invoice\EmailCredit;
use App\Models\Client;
@ -24,6 +25,7 @@ use App\Transformers\CreditTransformer;
use App\Utils\Ninja;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
/**
@ -32,6 +34,7 @@ use Illuminate\Http\Response;
class CreditController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = Credit::class;
@ -56,7 +59,7 @@ class CreditController extends BaseController
* @OA\Get(
* path="/api/v1/credits",
* operationId="getCredits",
* tags={"invoices"},
* tags={"credits"},
* summary="Gets a list of credits",
* description="Lists credits, search and filters allow fine grained lists to be generated.
*
@ -576,4 +579,66 @@ class CreditController extends BaseController
return response()->download($file_path);
}
/**
* Update the specified resource in storage.
*
* @param UploadCreditRequest $request
* @param Credit $client
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/credits/{id}/upload",
* operationId="uploadCredits",
* tags={"credits"},
* summary="Uploads a document to a credit",
* description="Handles the uploading of a document to a credit",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Credit Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Credit object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Credit"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadCreditRequest $request, Credit $credit)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $credit);
return $this->itemResponse($credit->fresh());
}
}

View File

@ -21,12 +21,14 @@ use App\Http\Requests\Expense\EditExpenseRequest;
use App\Http\Requests\Expense\ShowExpenseRequest;
use App\Http\Requests\Expense\StoreExpenseRequest;
use App\Http\Requests\Expense\UpdateExpenseRequest;
use App\Http\Requests\Expense\UploadExpenseRequest;
use App\Models\Expense;
use App\Repositories\ExpenseRepository;
use App\Transformers\ExpenseTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use App\Utils\Traits\Uploadable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -40,6 +42,7 @@ class ExpenseController extends BaseController
use MakesHash;
use Uploadable;
use BulkOptions;
use SavesDocuments;
protected $entity_type = Expense::class;
@ -507,4 +510,65 @@ class ExpenseController extends BaseController
{
//todo
}
/**
* Update the specified resource in storage.
*
* @param UploadExpenseRequest $request
* @param Expense $expense
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/expenses/{id}/upload",
* operationId="uploadExpense",
* tags={"expense"},
* summary="Uploads a document to a expense",
* description="Handles the uploading of a document to a expense",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Expense Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Expense object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Expense"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadExpenseRequest $request, Expense $expense)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $expense);
return $this->itemResponse($expense->fresh());
}
}

View File

@ -25,6 +25,7 @@ use App\Http\Requests\Invoice\EditInvoiceRequest;
use App\Http\Requests\Invoice\ShowInvoiceRequest;
use App\Http\Requests\Invoice\StoreInvoiceRequest;
use App\Http\Requests\Invoice\UpdateInvoiceRequest;
use App\Http\Requests\Invoice\UploadInvoiceRequest;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Invoice\StoreInvoice;
use App\Jobs\Invoice\ZipInvoices;
@ -38,6 +39,7 @@ use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\File;
@ -49,6 +51,7 @@ use Illuminate\Support\Facades\Storage;
class InvoiceController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = Invoice::class;
@ -204,6 +207,7 @@ class InvoiceController extends BaseController
*/
public function store(StoreInvoiceRequest $request)
{
$client = Client::find($request->input('client_id'));
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
@ -392,8 +396,6 @@ class InvoiceController extends BaseController
$invoice = $this->invoice_repo->save($request->all(), $invoice);
UnlinkFile::dispatchNow(config('filesystems.default'), $invoice->client->invoice_filepath().$invoice->number.'.pdf');
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars()));
return $this->itemResponse($invoice);
@ -850,4 +852,65 @@ class InvoiceController extends BaseController
return response(['message' => 'Oops, something went wrong. Make sure you have symlink to storage/ in public/ directory.'], 500);
}
}
/**
* Update the specified resource in storage.
*
* @param UploadInvoiceRequest $request
* @param Invoice $invoice
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/invoices/{id}/upload",
* operationId="uploadInvoice",
* tags={"invoices"},
* summary="Uploads a document to a invoice",
* description="Handles the uploading of a document to a invoice",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Invoice Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Invoice object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Invoice"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadInvoiceRequest $request, Invoice $invoice)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $invoice);
return $this->itemResponse($invoice->fresh());
}
}

View File

@ -0,0 +1,23 @@
<?php
/**
* @OA\Schema(
* schema="Document",
* type="object",
* @OA\Property(property="id", type="string", example="AS3df3A", description="The design hashed id"),
* @OA\Property(property="user_id", type="string", example="", description="__________"),
* @OA\Property(property="assigned_user_id", type="string", example="", description="__________"),
* @OA\Property(property="project_id", type="string", example="", description="__________"),
* @OA\Property(property="vendor_id", type="string", example="", description="__________"),
* @OA\Property(property="name", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="url", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="preview", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="type", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="disk", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="hash", type="string", example="Beauty", description="The design name"),
* @OA\Property(property="is_deleted", type="boolean", example=true, description="Flag to determine if the design is deleted"),
* @OA\Property(property="is_default", type="boolean", example=true, description="Flag to determine if the document is a default doc"),
* @OA\Property(property="created_at", type="number", format="integer", example="134341234234", description="Timestamp"),
* @OA\Property(property="updated_at", type="number", format="integer", example="134341234234", description="Timestamp"),
* @OA\Property(property="deleted_at", type="number", format="integer", example="134341234234", description="Timestamp"),
* )
*/

View File

@ -22,12 +22,14 @@ use App\Http\Requests\Payment\RefundPaymentRequest;
use App\Http\Requests\Payment\ShowPaymentRequest;
use App\Http\Requests\Payment\StorePaymentRequest;
use App\Http\Requests\Payment\UpdatePaymentRequest;
use App\Http\Requests\Payment\UploadPaymentRequest;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\PaymentRepository;
use App\Transformers\PaymentTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -37,6 +39,7 @@ use Illuminate\Http\Response;
class PaymentController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = Payment::class;
@ -671,4 +674,65 @@ class PaymentController extends BaseController
return $this->itemResponse($payment);
}
/**
* Update the specified resource in storage.
*
* @param UploadPaymentRequest $request
* @param Payment $payment
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/payments/{id}/upload",
* operationId="uploadPayment",
* tags={"payments"},
* summary="Uploads a document to a payment",
* description="Handles the uploading of a document to a payment",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Payment Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Payment object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Payment"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadPaymentRequest $request, Payment $payment)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $payment);
return $this->itemResponse($payment->fresh());
}
}

View File

@ -19,16 +19,19 @@ use App\Http\Requests\Product\EditProductRequest;
use App\Http\Requests\Product\ShowProductRequest;
use App\Http\Requests\Product\StoreProductRequest;
use App\Http\Requests\Product\UpdateProductRequest;
use App\Http\Requests\Product\UploadProductRequest;
use App\Models\Product;
use App\Repositories\ProductRepository;
use App\Transformers\ProductTransformer;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ProductController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = Product::class;
@ -476,4 +479,65 @@ class ProductController extends BaseController
return $this->listResponse(Product::withTrashed()->whereIn('id', $this->transformKeys($ids)));
}
/**
* Update the specified resource in storage.
*
* @param UploadProductRequest $request
* @param Product $product
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/products/{id}/upload",
* operationId="uploadProduct",
* tags={"products"},
* summary="Uploads a document to a product",
* description="Handles the uploading of a document to a product",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Product Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Product object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Product"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadProductRequest $request, Product $product)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $product);
return $this->itemResponse($product->fresh());
}
}

View File

@ -19,6 +19,7 @@ use App\Http\Requests\Project\EditProjectRequest;
use App\Http\Requests\Project\ShowProjectRequest;
use App\Http\Requests\Project\StoreProjectRequest;
use App\Http\Requests\Project\UpdateProjectRequest;
use App\Http\Requests\Project\UploadProjectRequest;
use App\Models\Project;
use App\Repositories\ProjectRepository;
use App\Transformers\ProjectTransformer;
@ -503,4 +504,65 @@ class ProjectController extends BaseController
return $this->listResponse(Project::withTrashed()->whereIn('id', $this->transformKeys($ids)));
}
/**
* Update the specified resource in storage.
*
* @param UploadProductRequest $request
* @param Product $project
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/projects/{id}/upload",
* operationId="uploadProject",
* tags={"projects"},
* summary="Uploads a document to a project",
* description="Handles the uploading of a document to a project",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Project Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Project object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Project"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadProjectRequest $request, Project $project)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $project);
return $this->itemResponse($project->fresh());
}
}

View File

@ -24,6 +24,7 @@ use App\Http\Requests\Quote\EditQuoteRequest;
use App\Http\Requests\Quote\ShowQuoteRequest;
use App\Http\Requests\Quote\StoreQuoteRequest;
use App\Http\Requests\Quote\UpdateQuoteRequest;
use App\Http\Requests\Quote\UploadQuoteRequest;
use App\Jobs\Invoice\ZipInvoices;
use App\Models\Client;
use App\Models\Invoice;
@ -34,6 +35,7 @@ use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -43,6 +45,7 @@ use Illuminate\Http\Response;
class QuoteController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = Quote::class;
@ -717,4 +720,65 @@ class QuoteController extends BaseController
return response()->download($file_path);
}
/**
* Update the specified resource in storage.
*
* @param UploadQuoteRequest $request
* @param Quote $quote
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/quotes/{id}/upload",
* operationId="uploadQuote",
* tags={"quotes"},
* summary="Uploads a document to a quote",
* description="Handles the uploading of a document to a quote",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Quote Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Quote object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Quote"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadQuoteRequest $request, Quote $quote)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $quote);
return $this->itemResponse($quote->fresh());
}
}

View File

@ -20,10 +20,12 @@ use App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\UploadRecurringInvoiceRequest;
use App\Models\RecurringInvoice;
use App\Repositories\RecurringInvoiceRepository;
use App\Transformers\RecurringInvoiceTransformer;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -33,6 +35,7 @@ use Illuminate\Http\Response;
class RecurringInvoiceController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = RecurringInvoice::class;
@ -680,4 +683,65 @@ class RecurringInvoiceController extends BaseController
break;
}
}
/**
* Update the specified resource in storage.
*
* @param UploadRecurringInvoiceRequest $request
* @param RecurringInvoice $recurring_invoice
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/recurring_invoices/{id}/upload",
* operationId="uploadRecurringInvoice",
* tags={"recurring_invoices"},
* summary="Uploads a document to a recurring_invoice",
* description="Handles the uploading of a document to a recurring_invoice",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The RecurringInvoice Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the RecurringInvoice object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/RecurringInvoice"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $recurring_invoice);
return $this->itemResponse($recurring_invoice->fresh());
}
}

View File

@ -21,12 +21,14 @@ use App\Http\Requests\Task\EditTaskRequest;
use App\Http\Requests\Task\ShowTaskRequest;
use App\Http\Requests\Task\StoreTaskRequest;
use App\Http\Requests\Task\UpdateTaskRequest;
use App\Http\Requests\Task\UploadTaskRequest;
use App\Models\Task;
use App\Repositories\TaskRepository;
use App\Transformers\TaskTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use App\Utils\Traits\Uploadable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -40,6 +42,7 @@ class TaskController extends BaseController
use MakesHash;
use Uploadable;
use BulkOptions;
use SavesDocuments;
protected $entity_type = Task::class;
@ -506,4 +509,65 @@ class TaskController extends BaseController
{
//todo
}
/**
* Update the specified resource in storage.
*
* @param UploadTaskRequest $request
* @param Task $task
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/tasks/{id}/upload",
* operationId="uploadTask",
* tags={"tasks"},
* summary="Uploads a document to a task",
* description="Handles the uploading of a document to a task",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Task Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Task object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Task"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadTaskRequest $request, Task $task)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $task);
return $this->itemResponse($task->fresh());
}
}

View File

@ -21,12 +21,14 @@ use App\Http\Requests\Vendor\EditVendorRequest;
use App\Http\Requests\Vendor\ShowVendorRequest;
use App\Http\Requests\Vendor\StoreVendorRequest;
use App\Http\Requests\Vendor\UpdateVendorRequest;
use App\Http\Requests\Vendor\UploadVendorRequest;
use App\Models\Vendor;
use App\Repositories\VendorRepository;
use App\Transformers\VendorTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use App\Utils\Traits\Uploadable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -39,6 +41,7 @@ class VendorController extends BaseController
use MakesHash;
use Uploadable;
use BulkOptions;
use SavesDocuments;
protected $entity_type = Vendor::class;
@ -511,4 +514,65 @@ class VendorController extends BaseController
{
//todo
}
/**
* Update the specified resource in storage.
*
* @param UploadVendorRequest $request
* @param Vendor $vendor
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/vendors/{id}/upload",
* operationId="uploadVendor",
* tags={"vendors"},
* summary="Uploads a document to a vendor",
* description="Handles the uploading of a document to a vendor",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Vendor Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Vendor object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function upload(UploadVendorRequest $request, Vendor $vendor)
{
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $vendor);
return $this->itemResponse($vendor->fresh());
}
}

View File

@ -28,6 +28,7 @@ class CreditsTable extends Component
{
$query = Credit::query()
->where('client_id', auth('contact')->user()->client->id)
->where('status_id', '<>', Credit::STATUS_DRAFT)
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
->paginate($this->per_page);

View File

@ -0,0 +1,39 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Client;
use App\Http\Requests\Request;
class UploadClientRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->client);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Company;
use App\Http\Requests\Request;
class UploadCompanyRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->company);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Credit;
use App\Http\Requests\Request;
class UploadCreditRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->credit);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Expense;
use App\Http\Requests\Request;
class UploadExpenseRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->expense);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Invoice;
use App\Http\Requests\Request;
class UploadInvoiceRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->invoice);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Payment Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Payment Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Payment;
use App\Http\Requests\Request;
class UploadPaymentRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->payment);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Product Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Product Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Product;
use App\Http\Requests\Request;
class UploadProductRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->product);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Project Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Project Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Project;
use App\Http\Requests\Request;
class UploadProjectRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->project);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Quote;
use App\Http\Requests\Request;
class UploadQuoteRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->quote);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\RecurringInvoice;
use App\Http\Requests\Request;
class UploadRecurringInvoiceRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->recurring_invoice);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Task;
use App\Http\Requests\Request;
class UploadTaskRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->task);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Vendor;
use App\Http\Requests\Request;
class UploadVendorRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->vendor);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
return $rules;
}
}

View File

@ -17,8 +17,12 @@ use App\Jobs\Company\CreateCompany;
use App\Jobs\Company\CreateCompanyPaymentTerms;
use App\Jobs\Company\CreateCompanyTaskStatuses;
use App\Jobs\Company\CreateCompanyToken;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Jobs\User\CreateUser;
use App\Jobs\Util\VersionCheck;
use App\Mail\Admin\AccountCreatedObject;
use App\Models\Account;
use App\Notifications\Ninja\NewAccountCreated;
use App\Utils\Ninja;
@ -88,7 +92,16 @@ class CreateAccount
$spaa9f78->fresh();
$sp035a66->notification(new NewAccountCreated($spaa9f78, $sp035a66))->ninja();
//todo implement SLACK notifications
//$sp035a66->notification(new NewAccountCreated($spaa9f78, $sp035a66))->ninja();
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer((new AccountCreatedObject($spaa9f78, $sp035a66))->build());
$nmo->company = $sp035a66;
$nmo->to_user = $spaa9f78;
$nmo->settings = $sp035a66->settings;
NinjaMailerJob::dispatchNow($nmo);
VersionCheck::dispatchNow();

View File

@ -16,6 +16,8 @@ use App\Events\Invoice\InvoiceWasEmailed;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Jobs\Mail\BaseMailerJob;
use App\Jobs\Mail\EntityFailedSendMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\TemplateEmail;
use App\Models\Activity;
@ -36,7 +38,7 @@ use Illuminate\Support\Str;
/*Multi Mailer implemented*/
class EmailEntity extends BaseMailerJob implements ShouldQueue
class EmailEntity implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
@ -103,21 +105,16 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
/* Set DB */
MultiDB::setDB($this->company->db);
/* Set the correct mail driver */
$this->setMailDriver();
$nmo = new NinjaMailerObject;
$nmo->mailable = new TemplateEmail($this->email_entity_builder,$this->invitation->contact);
$nmo->company = $this->company;
$nmo->settings = $this->settings;
$nmo->to_user = $this->invitation->contact;
$nmo->entity_string = $this->entity_string;
$nmo->invitation = $this->invitation;
$nmo->reminder_template = $this->reminder_template;
try {
Mail::to($this->invitation->contact->email, $this->invitation->contact->present()->name())
->send(
new TemplateEmail(
$this->email_entity_builder,
$this->invitation->contact
)
);
} catch (\Exception $e) {
$this->entityEmailFailed($e->getMessage());
$this->logMailError($e->getMessage(), $this->entity->client);
}
NinjaMailerJob::dispatch($nmo);
/* Mark entity sent */
$this->entity->service()->markSent()->save();
@ -136,7 +133,7 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
}
}
/* Switch statement to handling failure notifications */
/* Switch statement to handle failure notifications */
private function entityEmailFailed($message)
{
switch ($this->entity_string) {

View File

@ -1,109 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\AutoBillingFailureObject;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\PaymentFailureObject;
use App\Models\User;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class AutoBillingFailureMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies;
public $client;
public $error;
public $company;
public $payment_hash;
public $settings;
/**
* Create a new job instance.
*
* @param $client
* @param $message
* @param $company
* @param $amount
*/
public function __construct($client, $error, $company, $payment_hash)
{
$this->client = $client;
$this->error = $error;
$this->company = $company;
$this->payment_hash = $payment_hash;
$this->company = $company;
$this->settings = $client->getMergedSettings();
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
//iterate through company_users
$this->company->company_users->each(function ($company_user) {
//determine if this user has the right permissions
$methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']);
//if mail is a method type -fire mail!!
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$mail_obj = (new AutoBillingFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
try {
Mail::to($company_user->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
//$this->failed($e);
$this->logMailError($e->getMessage(), $this->client);
}
}
});
}
}

View File

@ -18,6 +18,7 @@ use App\Models\SystemLog;
use App\Models\User;
use App\Providers\MailServiceProvider;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
@ -28,11 +29,14 @@ use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Turbo124\Beacon\Facades\LightLogs;
/*Multi Mailer implemented*/
/*
Multi Mailer implemented
@Deprecated 14/02/2021
*/
class BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
public $tries = 5; //number of retries
@ -42,7 +46,11 @@ class BaseMailerJob implements ShouldQueue
public function setMailDriver()
{
/* Singletons need to be rebooted each time just in case our Locale is changing*/
App::forgetInstance('translator');
App::forgetInstance('mail.manager'); //singletons must be destroyed!
/* Inject custom translations if any exist */
Lang::replace(Ninja::transformTranslations($this->settings));
switch ($this->settings->email_sending_method) {
@ -60,7 +68,7 @@ class BaseMailerJob implements ShouldQueue
{
$sending_user = $this->settings->gmail_sending_user_id;
$user = User::find($sending_user);
$user = User::find($this->decodePrimaryKey($sending_user));
$google = (new Google())->init();
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
@ -75,12 +83,15 @@ class BaseMailerJob implements ShouldQueue
* just for this request.
*/
Config::set('mail.driver', 'gmail');
Config::set('services.gmail.token', $user->oauth_user_token->access_token);
Config::set('mail.from.address', $user->email);
Config::set('mail.from.name', $user->present()->name());
// config(['mail.driver' => 'gmail']);
// config(['services.gmail.token' => $user->oauth_user_token->access_token]);
// config(['mail.from.address' => $user->email]);
// config(['mail.from.name' => $user->present()->name()]);
(new MailServiceProvider(app()))->register();
//(new MailServiceProvider(app()))->register();
nlog("after registering mail service provider");
nlog(config('services.gmail.token'));
}
public function logMailError($errors, $recipient_object)
@ -96,7 +107,7 @@ class BaseMailerJob implements ShouldQueue
public function failed($exception = null)
{
nlog('the job failed');
nlog('mailer job failed');
nlog($exception->getMessage());
$job_failure = new EmailFailure();

View File

@ -1,111 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\ClientPaymentFailureObject;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\PaymentFailureObject;
use App\Models\Invoice;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class ClientPaymentFailureMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies, MakesHash;
public $client;
public $error;
public $company;
public $payment_hash;
public $settings;
/**
* Create a new job instance.
*
* @param $client
* @param $message
* @param $company
* @param $amount
*/
public function __construct($client, $error, $company, $payment_hash)
{
$this->company = $company;
$this->error = $error;
$this->client = $client;
$this->payment_hash = $payment_hash;
$this->company = $company;
$this->settings = $client->getMergedSettings();
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$this->invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->get();
$this->invoices->first()->invitations->each(function ($invitation) {
if ($invitation->contact->send_email && $invitation->contact->email) {
$mail_obj = (new ClientPaymentFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
try {
Mail::to($invitation->contact->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
$this->logMailError($e->getMessage(), $this->client);
}
}
});
}
}

View File

@ -1,103 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityFailedSendObject;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\EntitySentObject;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class EntityFailedSendMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $company;
public $user;
public $invitation;
public $entity_type;
public $entity;
public $settings;
public $template;
public $message;
/**
* Create a new job instance.
*
* @param $invitation
* @param $entity_type
* @param $user
* @param $company
*/
public function __construct($invitation, $entity_type, $user, $company, $template, $message)
{
$this->company = $company;
$this->user = $user;
$this->invitation = $invitation;
$this->entity = $invitation->{$entity_type};
$this->entity_type = $entity_type;
$this->settings = $invitation->contact->client->getMergedSettings();
$this->template = $template;
$this->message = $message;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled)
return true;
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$mail_obj = (new EntityFailedSendObject($this->invitation, $this->entity_type, $this->template, $this->message))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
try {
Mail::to($this->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
nlog("failing in EntityFailedSendMailer");
//$this->failed($e);
$this->logMailError($e->getMessage(), $this->entity->client);
}
}
}

View File

@ -1,90 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\EntityPaidObject;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $company;
public $user;
public $payment;
public $entity_type;
public $entity;
public $settings;
/**
* Create a new job instance.
*
* @param $payment
* @param $user
* @param $company
*/
public function __construct($payment, $company, $user)
{
$this->company = $company;
$this->user = $user;
$this->payment = $payment;
$this->settings = $payment->client->getMergedSettings();
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
try {
$mail_obj = (new EntityPaidObject($this->payment))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
Mail::to($this->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
// //$this->failed($e);
$this->logMailError($e->getMessage(), $this->payment->client);
}
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\EntitySentObject;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class EntitySentMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $company;
public $user;
public $invitation;
public $entity_type;
public $entity;
public $settings;
public $template;
/**
* Create a new job instance.
*
* @param $invitation
* @param $entity_type
* @param $user
* @param $company
*/
public function __construct($invitation, $entity_type, $user, $company, $template)
{
$this->company = $company;
$this->user = $user;
$this->invitation = $invitation;
$this->entity = $invitation->{$entity_type};
$this->entity_type = $entity_type;
$this->settings = $invitation->contact->client->getMergedSettings();
$this->template = $template;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled)
return true;
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$mail_obj = (new EntitySentObject($this->invitation, $this->entity_type, $this->template))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
try {
Mail::to($this->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
// //$this->failed($e);
$this->logMailError($e->getMessage(), $this->entity->client);
}
}
}

View File

@ -1,95 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\EntityViewedObject;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
/*Multi Mailer implemented*/
class EntityViewedMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $company;
public $user;
public $invitation;
public $entity_type;
public $entity;
public $settings;
/**
* Create a new job instance.
*
* @param $invitation
* @param $entity_type
* @param $user
* @param $company
*/
public function __construct($invitation, $entity_type, $user, $company)
{
$this->company = $company;
$this->user = $user;
$this->invitation = $invitation;
$this->entity = $invitation->{$entity_type};
$this->entity_type = $entity_type;
$this->settings = $invitation->contact->client->getMergedSettings();
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$mail_obj = (new EntityViewedObject($this->invitation, $this->entity_type))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
try {
Mail::to($this->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
//$this->failed($e);
$this->logMailError($e->getMessage(), $this->entity->client);
}
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use Illuminate\Mail\Mailable;
class NinjaMailer extends Mailable
{
public $mail_obj;
/**
* Create a new message instance.
*
* @param $mail_obj
*/
public function __construct($mail_obj)
{
$this->mail_obj = $mail_obj;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject($this->mail_obj->subject)
->markdown($this->mail_obj->markdown, $this->mail_obj->data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag);
});
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\DataMapper\Analytics\EmailFailure;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Jobs\Mail\NinjaMailerObject;
use App\Jobs\Util\SystemLogger;
use App\Libraries\Google\Google;
use App\Libraries\MultiDB;
use App\Mail\TemplateEmail;
use App\Models\ClientContact;
use App\Models\SystemLog;
use App\Models\User;
use App\Providers\MailServiceProvider;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Mail;
use Turbo124\Beacon\Facades\LightLogs;
use Dacastro4\LaravelGmail\Facade\LaravelGmail;
/*Multi Mailer implemented*/
class NinjaMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
public $tries = 5; //number of retries
public $backoff = 5; //seconds to wait until retry
public $deleteWhenMissingModels = true;
public $nmo;
public function __construct(NinjaMailerObject $nmo)
{
$this->nmo = $nmo;
}
public function handle()
{
/*If we are migrating data we don't want to fire any emails*/
if ($this->nmo->company->is_disabled)
return true;
/*Set the correct database*/
MultiDB::setDb($this->nmo->company->db);
/* Set the email driver */
$this->setMailDriver();
//send email
try {
nlog("trying to send");
Mail::to($this->nmo->to_user->email)
->send($this->nmo->mailable);
} catch (\Exception $e) {
nlog("error failed with {$e->getMessage()}");
if ($this->nmo->to_user instanceof ClientContact)
$this->logMailError($e->getMessage(), $this->nmo->to_user->client);
if($this->nmo->entity_string)
$this->entityEmailFailed($e->getMessage());
}
}
/* Switch statement to handle failure notifications */
private function entityEmailFailed($message)
{
switch ($this->nmo->entity_string) {
case 'invoice':
event(new InvoiceWasEmailedAndFailed($this->nmo->invitation, $this->nmo->company, $message, $this->nmo->reminder_template, Ninja::eventVars()));
break;
default:
# code...
break;
}
}
private function setMailDriver()
{
/* Singletons need to be rebooted each time just in case our Locale is changing*/
App::forgetInstance('translator');
App::forgetInstance('mail.manager'); //singletons must be destroyed!
App::forgetInstance('mailer');
App::forgetInstance('laravelgmail');
/* Inject custom translations if any exist */
Lang::replace(Ninja::transformTranslations($this->nmo->settings));
switch ($this->nmo->settings->email_sending_method) {
case 'default':
config(['mail.driver' => config('mail.default')]);
break;
case 'gmail':
$this->setGmailMailer();
break;
default:
break;
}
(new MailServiceProvider(app()))->register();
}
private function setGmailMailer()
{
if(LaravelGmail::check())
LaravelGmail::logout();
$sending_user = $this->nmo->settings->gmail_sending_user_id;
$user = User::find($this->decodePrimaryKey($sending_user));
nlog("Sending via {$user->present()->name()}");
$google = (new Google())->init();
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
if ($google->getClient()->isAccessTokenExpired()) {
$google->refreshToken($user);
}
/*
* Now that our token is refreshed and valid we can boot the
* mail driver at runtime and also set the token which will persist
* just for this request.
*/
config(['mail.driver' => 'gmail']);
(new MailServiceProvider(app()))->register();
$token = $user->oauth_user_token->access_token;
$this->nmo
->mailable
->from($user->email, $user->present()->name())
->withSwiftMessage(function ($message) use($token) {
$message->getHeaders()->addTextHeader('GmailToken', $token);
});
}
private function logMailError($errors, $recipient_object)
{
SystemLogger::dispatch(
$errors,
SystemLog::CATEGORY_MAIL,
SystemLog::EVENT_MAIL_SEND,
SystemLog::TYPE_FAILURE,
$recipient_object
);
}
public function failed($exception = null)
{
nlog('mailer job failed');
nlog($exception->getMessage());
$job_failure = new EmailFailure();
$job_failure->string_metric5 = get_parent_class($this);
$job_failure->string_metric6 = $exception->getMessage();
LightLogs::create($job_failure)
->batch();
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
/**
* NinjaMailerObject.
*/
class NinjaMailerObject
{
public $mailable;
public $company;
public $from_user; //not yet used
public $to_user;
public $settings;
public $transport; //not yet used
/* Variable for cascading notifications */
public $entity_string = FALSE;
public $invitation = FALSE;
public $template = FALSE;
}

View File

@ -11,9 +11,12 @@
namespace App\Jobs\Mail;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\PaymentFailureObject;
use App\Mail\NinjaMailer;
use App\Models\User;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Bus\Queueable;
@ -70,39 +73,29 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
//iterate through company_users
$this->company->company_users->each(function ($company_user) {
//determine if this user has the right permissions
$methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']);
//if mail is a method type -fire mail!!
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$mail_obj = (new PaymentFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
try {
Mail::to($company_user->user->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
//$this->failed($e);
$this->logMailError($e->getMessage(), $this->client);
}
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer($mail_obj);
$nmo->company = $this->company;
$nmo->to_user = $company_user->user;
$nmo->settings = $this->settings;
NinjaMailerJob::dispatch($nmo);
}
});
}

View File

@ -25,6 +25,7 @@ use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Turbo124\Beacon\Jobs\Database\MySQL\DbStatus;
use Illuminate\Support\Facades\Cache;
class CheckCompanyData implements ShouldQueue
{
@ -36,12 +37,13 @@ class CheckCompanyData implements ShouldQueue
public $company_data = [];
public $is_valid;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Company $company, string $hash)
public function __construct(Company $company, string $hash = '')
{
$this->company = $company;
$this->hash = $hash;
@ -54,6 +56,7 @@ class CheckCompanyData implements ShouldQueue
*/
public function handle()
{
$this->is_valid = true;
$this->checkInvoiceBalances();
$this->checkInvoicePayments();
@ -68,12 +71,19 @@ class CheckCompanyData implements ShouldQueue
else
$cache_instance = Cache::add($this->hash, '');
$cache_instance[$this->company->company_hash] = $this->company_data;
$this->company_data['company_hash'] = $this->company->company_hash;
Cache::put($this->hash, $cache_instance, now()->addMinutes(30));
nlog(Cache::get($this->hash));
nlog($this->company_data);
if(!$this->is_valid)
$this->company_data['status'] = 'errors';
else
$this->company_data['status'] = 'success';
return $this->company_data;
}
@ -88,25 +98,26 @@ class CheckCompanyData implements ShouldQueue
$wrong_balances = 0;
$wrong_paid_to_dates = 0;
foreach ($this->company->clients->where('is_deleted', 0)->cursor() as $client) {
foreach ($this->company->clients->where('is_deleted', 0) as $client) {
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
//$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
if($client->balance != $invoice_balance)
$invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
// if($client->balance != $invoice_balance)
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
$wrong_balances++;
$this->company_data[] = "# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}";
$this->company_data[] = "# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance} ";
$this->isValid = false;
$this->is_valid = false;
}
}
$this->logMessage("{$wrong_balances} clients with incorrect balances");
$this->company_data[] = "{$wrong_balances} clients with incorrect balances";
}
private function checkInvoicePayments()
@ -114,7 +125,7 @@ class CheckCompanyData implements ShouldQueue
$wrong_balances = 0;
$wrong_paid_to_dates = 0;
$this->company->clients->where('is_deleted', 0)->cursor()->each(function ($client) use ($wrong_balances) {
$this->company->clients->where('is_deleted', 0)->each(function ($client) use ($wrong_balances) {
$client->invoices->where('is_deleted', false)->whereIn('status_id', '!=', Invoice::STATUS_DRAFT)->each(function ($invoice) use ($wrong_balances, $client) {
$total_amount = $invoice->payments->whereIn('status_id', [Payment::STATUS_PAID, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.amount');
$total_refund = $invoice->payments->whereIn('status_id', [Payment::STATUS_PAID, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.refunded');
@ -128,7 +139,7 @@ class CheckCompanyData implements ShouldQueue
$this->company_data[] = $client->present()->name.' - '.$client->id." - Total Amount = {$total_amount} != Calculated Total = {$calculated_paid_amount} - Total Refund = {$total_refund} Total credit = {$total_credit}";
$this->isValid = false;
$this->is_valid = false;
}
});
});
@ -141,12 +152,11 @@ class CheckCompanyData implements ShouldQueue
$wrong_paid_to_dates = 0;
$credit_total_applied = 0;
$this->company->clients->where('is_deleted', 0)->cursor()->each(function ($client) use ($wrong_paid_to_dates, $credit_total_applied) {
$this->company->clients->where('is_deleted', 0)->each(function ($client) use ($wrong_paid_to_dates, $credit_total_applied) {
$total_invoice_payments = 0;
foreach ($client->invoices->where('is_deleted', false)->where('status_id', '>', 1) as $invoice) {
// $total_amount = $invoice->payments->whereNull('deleted_at')->sum('pivot.amount');
// $total_refund = $invoice->payments->whereNull('deleted_at')->sum('pivot.refunded');
$total_amount = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.amount');
$total_refund = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.refunded');
@ -154,13 +164,14 @@ class CheckCompanyData implements ShouldQueue
$total_invoice_payments += ($total_amount - $total_refund);
}
foreach ($client->payments as $payment) {
$credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
}
//10/02/21
// foreach ($client->payments as $payment) {
// $credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
// }
if ($credit_total_applied < 0) {
$total_invoice_payments += $credit_total_applied;
} //todo this is contentious
// if ($credit_total_applied < 0) {
// $total_invoice_payments += $credit_total_applied;
// } //todo this is contentious
// nlog("total invoice payments = {$total_invoice_payments} with client paid to date of of {$client->paid_to_date}");
@ -169,7 +180,7 @@ class CheckCompanyData implements ShouldQueue
$this->company_data[] = $client->present()->name.'id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}";
$this->isValid = false;
$this->is_valid = false;
}
});
@ -182,23 +193,24 @@ class CheckCompanyData implements ShouldQueue
$wrong_balances = 0;
$wrong_paid_to_dates = 0;
foreach ($this->company->clients->where('is_deleted', 0)->cursor() as $client) {
foreach ($this->company->clients->where('is_deleted', 0) as $client) {
//$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
$invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
$credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
/*Legacy - V4 will add credits to the balance - we may need to reverse engineer this and remove the credits from the client balance otherwise we need this hack here and in the invoice balance check.*/
if($client->balance != $invoice_balance)
$invoice_balance -= $credit_balance;
//10/02/21
// Legacy - V4 will add credits to the balance - we may need to reverse engineer this and remove the credits from the client balance otherwise we need this hack here and in the invoice balance check.
// if($client->balance != $invoice_balance)
// $invoice_balance -= $credit_balance;
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
if ($ledger && (string) $invoice_balance != (string) $client->balance) {
$wrong_paid_to_dates++;
$this->company_data[] = $client->present()->name.' - '.$client->id." - calculated client balances do not match {$invoice_balance} - ".rtrim($client->balance, '0');
$this->company_data[] = $client->present()->name.' - '.$client->id." - calculated client balances do not match {$invoice_balance} - ".rtrim($client->balance, '0')."";
$this->isValid = false;
$this->is_valid = false;
}
}
@ -209,7 +221,7 @@ class CheckCompanyData implements ShouldQueue
{
// check for contacts with the contact_key value set
$contacts = DB::table('client_contacts')
->where('company_id', $this->company_id)
->where('company_id', $this->company->id)
->whereNull('contact_key')
->orderBy('id')
->get(['id']);
@ -217,24 +229,24 @@ class CheckCompanyData implements ShouldQueue
$this->company_data[] = $contacts->count().' contacts without a contact_key';
if ($contacts->count() > 0) {
$this->isValid = false;
$this->is_valid = false;
}
if ($this->option('fix') == 'true') {
foreach ($contacts as $contact) {
DB::table('client_contacts')
->where('company_id', $this->company->id)
->where('id', '=', $contact->id)
->whereNull('contact_key')
->update([
'contact_key' => str_random(config('ninja.key_length')),
]);
}
}
// if ($this->option('fix') == 'true') {
// foreach ($contacts as $contact) {
// DB::table('client_contacts')
// ->where('company_id', $this->company->id)
// ->where('id', '=', $contact->id)
// ->whereNull('contact_key')
// ->update([
// 'contact_key' => str_random(config('ninja.key_length')),
// ]);
// }
// }
// check for missing contacts
$clients = DB::table('clients')
->where('company_id', $this->company->id)
->where('clients.company_id', $this->company->id)
->leftJoin('client_contacts', function ($join) {
$join->on('client_contacts.client_id', '=', 'clients.id')
->whereNull('client_contacts.deleted_at');
@ -242,34 +254,34 @@ class CheckCompanyData implements ShouldQueue
->groupBy('clients.id', 'clients.user_id', 'clients.company_id')
->havingRaw('count(client_contacts.id) = 0');
if ($this->option('client_id')) {
$clients->where('clients.id', '=', $this->option('client_id'));
}
// if ($this->option('client_id')) {
// $clients->where('clients.id', '=', $this->option('client_id'));
// }
$clients = $clients->get(['clients.id', 'clients.user_id', 'clients.company_id']);
$this->company_data[] = $clients->count().' clients without any contacts';
if ($clients->count() > 0) {
$this->isValid = false;
$this->is_valid = false;
}
if ($this->option('fix') == 'true') {
foreach ($clients as $client) {
$contact = new ClientContact();
$contact->company_id = $client->company_id;
$contact->user_id = $client->user_id;
$contact->client_id = $client->id;
$contact->is_primary = true;
$contact->send_invoice = true;
$contact->contact_key = str_random(config('ninja.key_length'));
$contact->save();
}
}
// if ($this->option('fix') == 'true') {
// foreach ($clients as $client) {
// $contact = new ClientContact();
// $contact->company_id = $client->company_id;
// $contact->user_id = $client->user_id;
// $contact->client_id = $client->id;
// $contact->is_primary = true;
// $contact->send_invoice = true;
// $contact->contact_key = str_random(config('ninja.key_length'));
// $contact->save();
// }
// }
// check for more than one primary contact
$clients = DB::table('clients')
->where('company_id', $this->company->id)
->where('clients.company_id', $this->company->id)
->leftJoin('client_contacts', function ($join) {
$join->on('client_contacts.client_id', '=', 'clients.id')
->where('client_contacts.is_primary', '=', true)
@ -278,15 +290,15 @@ class CheckCompanyData implements ShouldQueue
->groupBy('clients.id')
->havingRaw('count(client_contacts.id) != 1');
if ($this->option('client_id')) {
$clients->where('clients.id', '=', $this->option('client_id'));
}
// if ($this->option('client_id')) {
// $clients->where('clients.id', '=', $this->option('client_id'));
// }
$clients = $clients->get(['clients.id', DB::raw('count(client_contacts.id)')]);
$this->company_data[] = $clients->count().' clients without a single primary contact';
if ($clients->count() > 0) {
$this->isValid = false;
$this->is_valid = false;
}
}
@ -325,11 +337,20 @@ class CheckCompanyData implements ShouldQueue
->get(["{$table}.id"]);
if ($records->count()) {
$this->isValid = false;
$this->is_valid = false;
$this->company_data[] = $records->count()." {$table} records with incorrect {$entityType} company id";
}
}
}
}
public function pluralizeEntityType($type)
{
if ($type === 'company') {
return 'companies';
}
return $type.'s';
}
}

View File

@ -14,6 +14,7 @@ namespace App\Jobs\Util;
use App\DataMapper\Analytics\MigrationFailure;
use App\DataMapper\CompanySettings;
use App\Exceptions\MigrationValidatorFailed;
use App\Exceptions\ProcessingMigrationArchiveFailed;
use App\Exceptions\ResourceDependencyMissing;
use App\Exceptions\ResourceNotAvailableForMigration;
use App\Factory\ClientFactory;
@ -31,7 +32,9 @@ use App\Http\Requests\Company\UpdateCompanyRequest;
use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
use App\Http\ValidationRules\ValidUserForCompany;
use App\Jobs\Company\CreateCompanyToken;
use App\Jobs\Ninja\CheckCompanyData;
use App\Jobs\Ninja\CompanySizeCheck;
use App\Jobs\Util\VersionCheck;
use App\Libraries\MultiDB;
use App\Mail\MigrationCompleted;
use App\Models\Activity;
@ -79,10 +82,10 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\UploadedFile;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Turbo124\Beacon\Facades\LightLogs;
use Illuminate\Support\Facades\Mail;
class Import implements ShouldQueue
{
@ -206,9 +209,13 @@ class Import implements ShouldQueue
$this->setInitialCompanyLedgerBalances();
// $this->fixClientBalances();
$check_data = CheckCompanyData::dispatchNow($this->company, md5(time()));
// if($check_data['status'] == 'errors')
// throw new ProcessingMigrationArchiveFailed(implode("\n", $check_data));
Mail::to($this->user)
->send(new MigrationCompleted($this->company));
->send(new MigrationCompleted($this->company, implode("<br>",$check_data)));
/*After a migration first some basic jobs to ensure the system is up to date*/
VersionCheck::dispatch();
@ -220,15 +227,22 @@ class Import implements ShouldQueue
private function setInitialCompanyLedgerBalances()
{
Client::cursor()->each(function ($client) {
$invoice_balances = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
$company_ledger = CompanyLedgerFactory::create($client->company_id, $client->user_id);
$company_ledger->client_id = $client->id;
$company_ledger->adjustment = $client->balance;
$company_ledger->adjustment = $invoice_balances;
$company_ledger->notes = 'Migrated Client Balance';
$company_ledger->balance = $client->balance;
$company_ledger->balance = $invoice_balances;
$company_ledger->activity_id = Activity::CREATE_CLIENT;
$company_ledger->save();
$client->company_ledger()->save($company_ledger);
$client->balance = $invoice_balances;
$client->save();
});
}
@ -1023,9 +1037,35 @@ class Import implements ShouldQueue
}
if (array_key_exists('invoice_id', $resource) && $resource['invoice_id'] && array_key_exists('invoices', $this->ids)) {
$try_quote = false;
$exception = false;
try{
$invoice_id = $this->transformId('invoices', $resource['invoice_id']);
$entity = Invoice::where('id', $invoice_id)->withTrashed()->first();
}
catch(\Exception $e){
nlog("i couldn't find the invoice document {$resource['invoice_id']}, perhaps it is a quote?");
nlog($e->getMessage());
$try_quote = true;
}
if($try_quote && array_key_exists('quotes', $this->ids) ) {
$quote_id = $this->transformId('quotes', $resource['invoice_id']);
$entity = Quote::where('id', $quote_id)->withTrashed()->first();
$exception = $e;
}
if(!$entity)
throw new Exception("Resource invoice/quote document not available.");
}
if (array_key_exists('expense_id', $resource) && $resource['expense_id'] && array_key_exists('expenses', $this->ids)) {
$expense_id = $this->transformId('expenses', $resource['expense_id']);

View File

@ -108,15 +108,16 @@ class StartMigration implements ShouldQueue
throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.');
}
//$data = json_decode(file_get_contents($file), 1);
//Import::dispatchNow($data['data'], $this->company, $this->user);
Import::dispatchNow($file, $this->company, $this->user);
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
if (app()->environment() !== 'production') {
info($e->getMessage());
}
}
//always make sure we unset the migration as running

View File

@ -142,6 +142,31 @@ class MultiDB
return null;
}
/**
* @param array $data
* @return User|null
*/
public static function hasContact(array $data) : ?ClientContact
{
if (! config('ninja.db.multi_db_enabled')) {
return ClientContact::where($data)->withTrashed()->first();
}
foreach (self::$dbs as $db) {
self::setDB($db);
$user = ClientContacts::where($data)->withTrashed()->first();
if ($user) {
return $user;
}
}
self::setDefaultDatabase();
return null;
}
public static function contactFindAndSetDb($token) :bool
{
foreach (self::$dbs as $db) {

View File

@ -11,8 +11,11 @@
namespace App\Listeners\Credit;
use App\Jobs\Mail\EntitySentMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntitySentObject;
use App\Notifications\Admin\EntitySentNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -41,6 +44,11 @@ class CreditEmailedNotification implements ShouldQueue
$credit->last_sent_date = now();
$credit->save();
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntitySentObject($event->invitation, 'credit', $event->template))->build() );
$nmo->company = $credit->company;
$nmo->settings = $credit->company->settings;
foreach ($event->invitation->company->company_users as $company_user) {
$user = $company_user->user;
@ -51,7 +59,10 @@ class CreditEmailedNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
unset($methods[$key]);
EntitySentMailer::dispatch($event->invitation, 'credit', $user, $event->invitation->company, $event->template);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
$first_notification_sent = false;
}

View File

@ -11,8 +11,11 @@
namespace App\Listeners\Invoice;
use App\Jobs\Mail\EntitySentMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntitySentObject;
use App\Notifications\Admin\EntitySentNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -41,6 +44,12 @@ class InvoiceEmailedNotification implements ShouldQueue
$invoice->last_sent_date = now();
$invoice->save();
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntitySentObject($event->invitation, 'invoice', $event->template))->build() );
$nmo->company = $invoice->company;
$nmo->settings = $invoice->company->settings;
/* We loop through each user and determine whether they need to be notified */
foreach ($event->invitation->company->company_users as $company_user) {
@ -57,7 +66,10 @@ class InvoiceEmailedNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
unset($methods[$key]);
EntitySentMailer::dispatch($event->invitation, 'invoice', $user, $event->invitation->company, $event->template);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View File

@ -11,9 +11,11 @@
namespace App\Listeners\Invoice;
use App\Jobs\Mail\EntityFailedSendMailer;
use App\Jobs\Mail\EntitySentMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityFailedSendObject;
use App\Notifications\Admin\EntitySentNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -44,6 +46,11 @@ class InvoiceFailedEmailNotification implements ShouldQueue
$invoice->last_sent_date = now();
$invoice->save();
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntityFailedSendObject($event->invitation, 'invoice', $event->template, $event->message))->build() );
$nmo->company = $invoice->company;
$nmo->settings = $invoice->company->settings;
foreach ($event->invitation->company->company_users as $company_user) {
$user = $company_user->user;
@ -54,7 +61,10 @@ class InvoiceFailedEmailNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
unset($methods[$key]);
EntityFailedSendMailer::dispatch($event->invitation, 'invoice', $user, $event->invitation->company, $event->template, $event->message);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
$first_notification_sent = false;
}

View File

@ -11,8 +11,11 @@
namespace App\Listeners\Misc;
use App\Jobs\Mail\EntityViewedMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityViewedObject;
use App\Notifications\Admin\EntityViewedNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -46,6 +49,12 @@ class InvitationViewedListener implements ShouldQueue
$notification = new EntityViewedNotification($invitation, $entity_name);
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntityViewedObject($invitation, $entity_name))->build() );
$nmo->company = $invitation->company;
$nmo->settings = $invitation->company->settings;
foreach ($invitation->company->company_users as $company_user) {
$entity_viewed = "{$entity_name}_viewed";
@ -54,7 +63,9 @@ class InvitationViewedListener implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
EntityViewedMailer::dispatch($invitation, $entity_name, $company_user->user, $invitation->company);
$nmo->to_user = $company_user->user;
NinjaMailerJob::dispatch($nmo);
}
$notification->method = $methods;
@ -65,8 +76,8 @@ class InvitationViewedListener implements ShouldQueue
if (isset($invitation->company->slack_webhook_url)) {
$notification->method = ['slack'];
Notification::route('slack', $invitation->company->slack_webhook_url)
->notify($notification);
// Notification::route('slack', $invitation->company->slack_webhook_url)
// ->notify($notification);
}
}
}

View File

@ -11,8 +11,11 @@
namespace App\Listeners\Payment;
use App\Jobs\Mail\EntityPaidMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntityPaidObject;
use App\Notifications\Admin\NewPaymentNotification;
use App\Utils\Ninja;
use App\Utils\Traits\Notifications\UserNotifies;
@ -42,11 +45,15 @@ class PaymentNotification implements ShouldQueue
{
MultiDB::setDb($event->company->db);
if ($event->company->is_disabled)
return true;
$payment = $event->payment;
if ($event->company->is_disabled) {
return true;
}
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntityPaidObject($payment))->build() );
$nmo->company = $event->company;
$nmo->settings = $event->company->settings;
/*User notifications*/
foreach ($payment->company->company_users as $company_user) {
@ -57,7 +64,9 @@ class PaymentNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
EntityPaidMailer::dispatch($payment, $payment->company, $user);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
}
$notification = new NewPaymentNotification($payment, $payment->company);

View File

@ -11,8 +11,11 @@
namespace App\Listeners\Quote;
use App\Jobs\Mail\EntitySentMailer;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\EntitySentObject;
use App\Notifications\Admin\EntitySentNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -41,6 +44,12 @@ class QuoteEmailedNotification implements ShouldQueue
$quote->last_sent_date = now();
$quote->save();
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new EntitySentObject($event->invitation, 'quote', $event->template))->build() );
$nmo->company = $quote->company;
$nmo->settings = $quote->company->settings;
foreach ($event->invitation->company->company_users as $company_user) {
$user = $company_user->user;
@ -51,7 +60,11 @@ class QuoteEmailedNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
unset($methods[$key]);
EntitySentMailer::dispatch($event->invitation, 'quote', $user, $event->invitation->company, $event->template);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
$first_notification_sent = false;
}

View File

@ -11,7 +11,11 @@
namespace App\Listeners;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\Admin\VerifyUserObject;
use App\Notifications\Ninja\VerifyUser;
use App\Utils\Ninja;
use Exception;
@ -45,9 +49,19 @@ class SendVerificationNotification implements ShouldQueue
MultiDB::setDB($event->company->db);
try {
$event->user->notify(new VerifyUser($event->user, $event->company));
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer((new VerifyUserObject($event->user, $event->company))->build());
$nmo->company = $event->company;
$nmo->to_user = $event->user;
$nmo->settings = $event->company->settings;
NinjaMailerJob::dispatch($nmo);
// $event->user->notify(new VerifyUser($event->user, $event->company));
Ninja::registerNinjaUser($event->user);
} catch (Exception $e) {
nlog("I couldn't send the email " . $e->getMessage());
}

View File

@ -0,0 +1,52 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\Admin;
class AccountCreatedObject
{
public $user;
public $company;
/**
*
*/
public function __construct($user, $company)
{
$this->user = $user;
$this->company = $company;
}
public function build()
{
$data = [
'title' => ctrans('texts.new_signup'),
'message' => ctrans('texts.new_signup_text', ['user' => $this->user->present()->name(), 'email' => $this->user->email, 'ip' => $this->user->ip]),
'url' => config('ninja.web_url'),
'button' => ctrans('texts.account_login'),
'signature' => $this->company->settings->email_signature,
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
];
$mail_obj = new \stdClass;
$mail_obj->subject = ctrans('texts.new_signup');
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\Admin;
class ResetPasswordObject
{
public $user;
public $token;
public $company;
/**
*
*/
public function __construct($token, $user, $company)
{
$this->token = $token;
$this->user = $user;
$this->company = $company;
}
public function build()
{
$data = [
'title' => ctrans('texts.your_password_reset_link'),
'message' => ctrans('texts.reset_password'),
'url' => route('password.reset', ['token' => $this->token, 'email' => $this->user->email]),
'button' => ctrans('texts.reset'),
'signature' => $this->company->settings->email_signature,
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
];
$mail_obj = new \stdClass;
$mail_obj->subject = ctrans('texts.your_password_reset_link');
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\Admin;
use App\Utils\Traits\MakesHash;
class VerifyUserObject
{
use MakesHash;
public $user;
public $company;
/**
*
*/
public function __construct($user, $company)
{
$this->user = $user;
$this->company = $company;
}
public function build()
{
$this->user->confirmation_code = $this->createDbHash($this->company->db);
$this->user->save();
$data = [
'title' => ctrans('texts.confirmation_subject'),
'message' => ctrans('texts.confirmation_message'),
'url' => url("/user/confirm/{$this->user->confirmation_code}"),
'button' => ctrans('texts.button_confirmation_message'),
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
'signature' => $this->company->settings->email_signature,
];
$mail_obj = new \stdClass;
$mail_obj->subject = ctrans('texts.confirmation_subject');
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
}

View File

@ -17,9 +17,10 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class BouncedEmail extends Mailable implements ShouldQueue
// class BouncedEmail extends Mailable implements ShouldQueue
class BouncedEmail extends Mailable
{
use Queueable, SerializesModels;
//use Queueable, SerializesModels;
public $invitation;

View File

@ -0,0 +1,54 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\ClientContact;
class ClientContactResetPasswordObject
{
public $client_contact;
public $token;
private $company;
/**
*
*/
public function __construct($token, $client_contact)
{
$this->token = $token;
$this->client_contact = $client_contact;
$this->company = $client_contact->company;
}
public function build()
{
$data = [
'title' => ctrans('texts.your_password_reset_link'),
'message' => ctrans('texts.reset_password'),
'url' => route('client.password.reset', ['token' => $this->token, 'email' => $this->client_contact->email]),
'button' => ctrans('texts.reset'),
'signature' => $this->company->settings->email_signature,
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
];
$mail_obj = new \stdClass;
$mail_obj->subject = ctrans('texts.your_password_reset_link');
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
}

View File

@ -9,7 +9,7 @@ use Illuminate\Queue\SerializesModels;
class DownloadInvoices extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
public $file_path;

View File

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
class ExistingMigration extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
/**
* Create a new message instance.

View File

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
class ImportCompleted extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
/**
* Create a new message instance.

View File

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
class InvoiceWasPaid extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
/**
* Create a new message instance.

View File

@ -9,18 +9,21 @@ use Illuminate\Queue\SerializesModels;
class MigrationCompleted extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
public $company;
public $check_data;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Company $company)
public function __construct(Company $company, $check_data = '')
{
$this->company = $company;
$this->check_data = $check_data;
}
/**
@ -31,8 +34,9 @@ class MigrationCompleted extends Mailable
public function build()
{
$data['settings'] = $this->company->settings;
$data['company'] = $this->company;
$data['company'] = $this->company->fresh();
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
$data['check_data'] = $this->check_data;
$result = $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.import.completed', $data);

View File

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
class MigrationFailed extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
public $exception;
public $content;
@ -22,6 +22,7 @@ class MigrationFailed extends Mailable
public function __construct($exception, $content = null)
{
$this->exception = $exception;
$this->content = $content;
}
/**

View File

@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
class QuoteWasApproved extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
/**
* Create a new message instance.

View File

@ -0,0 +1,55 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\RecurringInvoice;
class ClientContactRequestCancellationObject
{
public $recurring_invoice;
public $client_contact;
private $company;
/**
*
*/
public function __construct($recurring_invoice, $client_contact)
{
$this->recurring_invoice = $recurring_invoice;
$this->client_contact = $client_contact;
$this->company = $recurring_invoice->company;
}
public function build()
{
$data = [
'title' => ctrans('texts.recurring_cancellation_request', ['contact' => $this->client_contact->present()->name()]),
'message' => ctrans('texts.recurring_cancellation_request_body', ['contact' => $this->client_contact->present()->name(), 'client' => $this->client_contact->client->present()->name(), 'invoice' => $this->recurring_invoice->number]),
'url' => config('ninja.web_url'),
'button' => ctrans('texts.account_login'),
'signature' => $this->company->settings->email_signature,
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
];
$mail_obj = new \stdClass;
$mail_obj->subject = ctrans('texts.recurring_cancellation_request', ['contact' => $this->client_contact->present()->name()]);
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
}

View File

@ -11,7 +11,7 @@ use SplFileObject;
class SupportMessageSent extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
public $message;

View File

@ -20,7 +20,6 @@ use Illuminate\Queue\SerializesModels;
class TemplateEmail extends Mailable
{
use Queueable, SerializesModels;
private $build_email;
@ -37,12 +36,6 @@ class TemplateEmail extends Mailable
$this->client = $contact->client;
}
/**
* Build the message.
*
* @return $this
* @throws \Laracasts\Presenter\Exceptions\PresenterException
*/
public function build()
{
$template_name = 'email.template.'.$this->build_email->getTemplate();
@ -79,7 +72,10 @@ class TemplateEmail extends Mailable
'settings' => $settings,
'company' => $company,
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
]);
])
->withSwiftMessage(function ($message) use($company){
$message->getHeaders()->addTextHeader('Tag', $company->company_key);
});
//conditionally attach files
if ($settings->pdf_email_attachment !== false && ! empty($this->build_email->getAttachments())) {

View File

@ -17,7 +17,7 @@ use Illuminate\Queue\SerializesModels;
class TestMailServer extends Mailable
{
use Queueable, SerializesModels;
// use Queueable, SerializesModels;
public $message;

View File

@ -11,6 +11,10 @@
namespace App\Models;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\ClientContact\ClientContactResetPasswordObject;
use App\Models\Presenters\ClientContactPresenter;
use App\Notifications\ClientContactResetPassword;
use App\Utils\Traits\MakesHash;
@ -151,7 +155,15 @@ class ClientContact extends Authenticatable implements HasLocalePreference
public function sendPasswordResetNotification($token)
{
$this->notify(new ClientContactResetPassword($token));
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer((new ClientContactResetPasswordObject($token, $this))->build());
$nmo->to_user = $this;
$nmo->company = $this->company;
$nmo->settings = $this->company->settings;
NinjaMailerJob::dispatch($nmo);
//$this->notify(new ClientContactResetPassword($token));
}
public function preferredLocale()

View File

@ -83,6 +83,8 @@ class Company extends BaseModel
'default_task_is_date_based',
'enable_product_discount',
'expense_inclusive_taxes',
'session_timeout',
'oauth_password_required',
];
protected $hidden = [

View File

@ -67,6 +67,10 @@ class Project extends BaseModel
return $this->morphMany(Document::class, 'documentable');
}
public function user()
{
return $this->belongsTo(User::class)->withTrashed();
}
// /**
// * @return \Illuminate\Database\Eloquent\Relations\HasMany
// */

View File

@ -11,6 +11,10 @@
namespace App\Models;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\Admin\ResetPasswordObject;
use App\Models\Presenters\UserPresenter;
use App\Notifications\ResetPasswordNotification;
use App\Utils\Traits\MakesHash;
@ -371,6 +375,15 @@ class User extends Authenticatable implements MustVerifyEmail
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
$nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer( (new ResetPasswordObject($token, $this, $this->account->default_company))->build());
$nmo->to_user = $this;
$nmo->settings = $this->account->default_company->settings;
$nmo->company = $this->account->default_company;
NinjaMailerJob::dispatch($nmo);
//$this->notify(new ResetPasswordNotification($token));
}
}

View File

@ -99,4 +99,9 @@ class Vendor extends BaseModel
{
return $this->belongsTo(Company::class);
}
public function user()
{
return $this->belongsTo(User::class)->withTrashed();
}
}

View File

@ -21,9 +21,10 @@ use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
//@deprecated
class EntitySentNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
//use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -77,39 +78,6 @@ class EntitySentNotification extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
$subject = ctrans(
"texts.notification_{$this->entity_name}_sent_subject",
[
'client' => $this->contact->present()->name(),
'invoice' => $this->entity->number,
]
);
$data = [
'title' => $subject,
'message' => ctrans(
"texts.notification_{$this->entity_name}_sent",
[
'amount' => $amount,
'client' => $this->contact->present()->name(),
'invoice' => $this->entity->number,
]
),
'url' => $this->invitation->getAdminLink(),
'button' => ctrans("texts.view_{$this->entity_name}"),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->settings,
];
return (new MailMessage)
->subject($subject)
->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**
@ -120,9 +88,7 @@ class EntitySentNotification extends Notification implements ShouldQueue
*/
public function toArray($notifiable)
{
return [
//
];
return [];
}
public function toSlack($notifiable)

View File

@ -23,7 +23,7 @@ use Illuminate\Queue\SerializesModels;
class EntityViewedNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
//use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -76,17 +76,6 @@ class EntityViewedNotification extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$data = $this->buildDataArray();
$subject = $this->buildSubject();
return (new MailMessage)
->subject($subject)
->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**

View File

@ -1,149 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Notifications\Admin;
use App\Utils\Number;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InvoiceSentNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* 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->invitation = $invitation;
$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 MailMessage
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$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.app_url').'/invoices/'.$this->invoice->hashed_id,
'button' => ctrans('texts.view_invoice'),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->settings,
];
return (new MailMessage)
->subject($subject)
->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**
* 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)
->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]), $this->invitation->getAdminLink())
->fields([
ctrans('texts.client') => $this->contact->present()->name(),
ctrans('texts.amount') => $amount,
]);
});
}
}

View File

@ -1,142 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Notifications\Admin;
use App\Utils\Number;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InvoiceViewedNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* 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 MailMessage
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
$subject = ctrans(
'texts.notification_invoice_viewed_subject',
[
'client' => $this->contact->present()->name(),
'invoice' => $this->invoice->number,
]
);
$data = [
'title' => $subject,
'message' => ctrans(
'texts.notification_invoice_viewed',
[
'amount' => $amount,
'client' => $this->contact->present()->name(),
'invoice' => $this->invoice->number,
]
),
'url' => config('ninja.app_url').'/invoices/'.$this->invoice->hashed_id,
'button' => ctrans('texts.view_invoice'),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->settings,
];
return (new MailMessage)
->subject($subject)
->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**
* 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_viewed',
[
'amount' => $amount,
'client' => $this->contact->present()->name(),
'invoice' => $this->invoice->number,
]
));
}
}

View File

@ -1,148 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Notifications\Admin;
use App\Utils\Number;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class NewPartialPaymentNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
*
* @return void
*/
protected $payment;
protected $company;
protected $settings;
protected $is_system;
public function __construct($payment, $company, $is_system = false, $settings = null)
{
$this->payment = $payment;
$this->company = $company;
$this->settings = $payment->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 MailMessage
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
$invoice_texts = ctrans('texts.invoice_number_short');
foreach ($this->payment->invoices as $invoice) {
$invoice_texts .= $invoice->number.',';
}
$invoice_texts = substr($invoice_texts, 0, -1);
$data = [
'title' => ctrans(
'texts.notification_partial_payment_paid_subject',
['client' => $this->payment->client->present()->name()]
),
'message' => ctrans(
'texts.notification_partial_payment_paid',
['amount' => $amount,
'client' => $this->payment->client->present()->name(),
'invoice' => $invoice_texts,
]
),
'url' => config('ninja.app_url').'/payments/'.$this->payment->hashed_id,
'button' => ctrans('texts.view_payment'),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->settings,
];
return (new MailMessage)
->subject(
ctrans(
'texts.notification_partial_payment_paid_subject',
['client' => $this->payment->client->present()->name()]
)
)->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**
* 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->payment->amount, $this->payment->client);
$invoice_texts = ctrans('texts.invoice_number_short');
foreach ($this->payment->invoices as $invoice) {
$invoice_texts .= $invoice->number.',';
}
$invoice_texts = substr($invoice_texts, 0, -1);
return (new SlackMessage)
->success()
//->to("#devv2")
->from('System')
->image($logo)
->content(ctrans(
'texts.notification_payment_paid',
['amount' => $amount,
'client' => $this->payment->client->present()->name(),
'invoice' => $invoice_texts, ]
));
}
}

View File

@ -23,7 +23,7 @@ use Illuminate\Queue\SerializesModels;
class NewPaymentNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -68,47 +68,6 @@ class NewPaymentNotification extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
$invoice_texts = ctrans('texts.invoice_number_short');
foreach ($this->payment->invoices as $invoice) {
$invoice_texts .= $invoice->number.',';
}
$invoice_texts = substr($invoice_texts, 0, -1);
$data = [
'title' => ctrans(
'texts.notification_payment_paid_subject',
['client' => $this->payment->client->present()->name()]
),
'message' => ctrans(
'texts.notification_payment_paid',
['amount' => $amount,
'client' => $this->payment->client->present()->name(),
'invoice' => $invoice_texts,
]
),
'url' => config('ninja.app_url').'/payments/'.$this->payment->hashed_id,
'button' => ctrans('texts.view_payment'),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->settings,
];
return (new MailMessage)
->subject(
ctrans(
'texts.notification_payment_paid_subject',
['client' => $this->payment->client->present()->name()]
)
)->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**

View File

@ -18,9 +18,9 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class BaseNotification extends Notification implements ShouldQueue
class BaseNotification extends Notification
{
use Queueable;
// use Queueable;
use MakesInvoiceHtml;
/**

View File

@ -22,9 +22,10 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
class ClientContactRequestCancellation extends Notification implements ShouldQueue
//@deprecated for mail
class ClientContactRequestCancellation extends Notification
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -56,7 +57,7 @@ class ClientContactRequestCancellation extends Notification implements ShouldQue
*/
public function via($notifiable)
{
return ['mail', 'slack'];
return ['slack'];
}
/**
@ -67,19 +68,6 @@ class ClientContactRequestCancellation extends Notification implements ShouldQue
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->client_contact);
}
$client_contact_name = $this->client_contact->present()->name();
$client_name = $this->client_contact->client->present()->name();
$recurring_invoice_number = $this->recurring_invoice->number;
return (new MailMessage)
->subject('Request for recurring invoice cancellation from '.$client_contact_name)
->markdown('email.support.cancellation', [
'message' => "Contact [{$client_contact_name}] from Client [{$client_name}] requested to cancel Recurring Invoice [#{$recurring_invoice_number}]",
]);
}
/**

View File

@ -19,9 +19,10 @@ use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
//@deprecated
class ClientContactResetPassword extends Notification
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The password reset token.
*
@ -55,7 +56,7 @@ class ClientContactResetPassword extends Notification
*/
public function via($notifiable)
{
return ['mail'];
return [];
}
/**
@ -66,16 +67,6 @@ class ClientContactResetPassword extends Notification
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
return (new MailMessage)
->subject('Reset Password Notification')
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', url(config('app.url').route('client.password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->line('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.users.expire')])
->line('If you did not request a password reset, no further action is required.');
}
/**

View File

@ -1,73 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class GmailTestNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

View File

@ -20,9 +20,10 @@ use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class NewAccountCreated extends Notification implements ShouldQueue
//@deprecated
class NewAccountCreated extends Notification
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
//use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -50,7 +51,7 @@ class NewAccountCreated extends Notification implements ShouldQueue
*/
public function via($notifiable)
{
return ['slack', 'mail'];
return ['slack'];
}
/**
@ -61,26 +62,6 @@ class NewAccountCreated extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
$user_name = $this->user->first_name.' '.$this->user->last_name;
$email = $this->user->email;
$ip = $this->user->ip;
$data = [
'title' => ctrans('texts.new_signup'),
'message' => ctrans('texts.new_signup_text', ['user' => $user_name, 'email' => $email, 'ip' => $ip]),
'url' => config('ninja.web_url'),
'button' => ctrans('texts.account_login'),
'signature' => $this->company->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings,
];
return (new MailMessage)
->subject(ctrans('texts.new_signup'))
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
})
->markdown('email.admin.generic', $data);
}
/**

View File

@ -20,9 +20,11 @@ use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class NewAccountCreated extends Notification implements ShouldQueue
//@deprecated
class NewAccountCreated extends Notification
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -50,7 +52,7 @@ class NewAccountCreated extends Notification implements ShouldQueue
*/
public function via($notifiable)
{
return ['slack', 'mail'];
return ['slack'];
}
/**
@ -61,26 +63,6 @@ class NewAccountCreated extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
$user_name = $this->user->first_name.' '.$this->user->last_name;
$email = $this->user->email;
$ip = $this->user->ip;
$data = [
'title' => ctrans('texts.new_signup'),
'message' => ctrans('texts.new_signup_text', ['user' => $user_name, 'email' => $email, 'ip' => $ip]),
'url' => config('ninja.web_url'),
'button' => ctrans('texts.account_login'),
'signature' => $this->company->settings->email_signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings,
];
return (new MailMessage)
->subject(ctrans('texts.new_signup'))
->markdown('email.admin.generic', $data)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->company->company_key);
});
}
/**

View File

@ -19,9 +19,10 @@ use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class VerifyUser extends Notification implements ShouldQueue
//@deprecated
class VerifyUser extends Notification
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
@ -46,7 +47,7 @@ class VerifyUser extends Notification implements ShouldQueue
*/
public function via($notifiable)
{
return ['mail'];
return [''];
}
/**
@ -57,19 +58,6 @@ class VerifyUser extends Notification implements ShouldQueue
*/
public function toMail($notifiable)
{
$data = [
'title' => ctrans('texts.confirmation_subject'),
'message' => ctrans('texts.confirmation_message'),
'url' => url("/user/confirm/{$this->user->confirmation_code}"),
'button' => ctrans('texts.button_confirmation_message'),
'signature' => '',
'logo' => 'https://www.invoiceninja.com/wp-content/uploads/2019/01/InvoiceNinja-Logo-Round-300x300.png',
'settings' => $this->company->settings,
];
return (new MailMessage)
->subject(ctrans('texts.confirmation_subject'))
->markdown('email.admin.generic', $data);
}
/**

View File

@ -6,9 +6,10 @@ use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
//@deprecated
class ResetPasswordNotification extends Notification
{
use Queueable;
// use Queueable;
public $token;
@ -30,7 +31,7 @@ class ResetPasswordNotification extends Notification
*/
public function via($notifiable)
{
return ['mail'];
return [];
}
/**
@ -41,8 +42,6 @@ class ResetPasswordNotification extends Notification
*/
public function toMail($notifiable)
{
return (new MailMessage)
->view('email.auth.password-reset', ['link' => route('password.reset', $this->token)]);
}
/**

View File

@ -1,124 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Notifications;
use App\Models\Invoice;
use App\Utils\Number;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\SerializesModels;
class SendGenericNotification extends BaseNotification implements ShouldQueue
{
use Queueable;
use Dispatchable;
use SerializesModels;
/**
* Create a new notification instance.
*
* @return void
*/
protected $invitation;
protected $entity;
protected $contact;
protected $entity_string;
protected $settings;
public $is_system;
protected $body;
protected $subject;
public function __construct($invitation, $entity_string, $subject, $body)
{
$this->entity = $invitation->{$entity_string};
$this->contact = $invitation->contact;
$this->settings = $this->entity->client->getMergedSettings();
$this->subject = $subject;
$this->body = $body;
$this->invitation = $invitation;
$this->entity_string = $entity_string;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return MailMessage
*/
public function toMail($notifiable)
{
$mail_message = (new MailMessage)
->withSwiftMessage(function ($message) {
$message->getHeaders()->addTextHeader('Tag', $this->invitation->company->company_key);
})->markdown($this->getTemplateView(), $this->buildMailMessageData());
//})->markdown('email.template.plain', $this->buildMailMessageData());
$mail_message = $this->buildMailMessageSettings($mail_message);
return $mail_message;
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
public function toSlack($notifiable)
{
return '';
// $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_viewed',
// [
// 'amount' => $amount,
// 'client' => $this->contact->present()->name(),
// 'invoice' => $this->invoice->number
// ]
// ));
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* Credit Ninja (https://creditninja.com).
*
* @link https://github.com/creditninja/creditninja source repository
*
* @copyright Copyright (c) 2021. Credit Ninja LLC (https://creditninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Observers;
use App\Jobs\Util\UnlinkFile;
use App\Jobs\Util\WebhookHandler;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Webhook;
class CreditObserver
{
/**
* Handle the client "created" event.
*
* @param Credit $credit
* @return void
*/
public function created(Credit $credit)
{
}
/**
* Handle the client "updated" event.
*
* @param Credit $credit
* @return void
*/
public function updated(Credit $credit)
{
UnlinkFile::dispatchNow(config('filesystems.default'), $credit->client->credit_filepath() . $credit->number.'.pdf');
}
/**
* Handle the client "deleted" event.
*
* @param Credit $credit
* @return void
*/
public function deleted(Credit $credit)
{
}
/**
* Handle the client "restored" event.
*
* @param Credit $credit
* @return void
*/
public function restored(Credit $credit)
{
//
}
/**
* Handle the client "force deleted" event.
*
* @param Credit $credit
* @return void
*/
public function forceDeleted(Credit $credit)
{
//
}
}

View File

@ -11,6 +11,7 @@
namespace App\Observers;
use App\Jobs\Util\UnlinkFile;
use App\Jobs\Util\WebhookHandler;
use App\Models\Client;
use App\Models\Invoice;
@ -50,6 +51,9 @@ class InvoiceObserver
if ($subscriptions) {
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_INVOICE, $invoice, $invoice->company);
}
// UnlinkFile::dispatchNow(config('filesystems.default'), $invoice->client->invoice_filepath() . $invoice->number.'.pdf');
}
/**

Some files were not shown because too many files have changed in this diff Show More