1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-15 23:52:33 +01:00

Merge branch 'v5-develop' into v5-stable

This commit is contained in:
David Bomba 2021-07-28 17:30:05 +10:00
commit b2aca30453
142 changed files with 218680 additions and 217230 deletions

View File

@ -49,6 +49,10 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
steps:
- name: Add hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 ninja.test" | sudo tee -a /etc/hosts
- name: Start mysql service
run: |
sudo /etc/init.d/mysql start

View File

@ -1 +1 @@
5.2.14
5.2.15

View File

@ -91,6 +91,8 @@ class CreateAccount extends Command
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
'portal_domain' => config('ninja.app_url'),
'portal_mode' => 'domain',
]);
$account->default_company_id = $company->id;

View File

@ -0,0 +1,51 @@
<?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://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Analytics;
use Turbo124\Beacon\ExampleMetric\GenericCounter;
class LivePreview extends GenericCounter
{
/**
* The type of Sample.
*
* Monotonically incrementing counter
*
* - counter
*
* @var string
*/
public $type = 'counter';
/**
* The name of the counter.
* @var string
*/
public $name = 'live_preview.created';
/**
* The datetime of the counter measurement.
*
* date("Y-m-d H:i:s")
*
* @var DateTime
*/
public $datetime;
/**
* The increment amount... should always be
* set to 0.
*
* @var int
*/
public $metric = 0;
}

View File

@ -187,7 +187,7 @@ class Handler extends ExceptionHandler
} elseif ($exception instanceof NotFoundHttpException && $request->expectsJson()) {
return response()->json(['message'=>'Route does not exist'], 404);
} elseif ($exception instanceof MethodNotAllowedHttpException && $request->expectsJson()) {
return response()->json(['message'=>'Method not support for this route'], 404);
return response()->json(['message'=>'Method not supported for this route'], 404);
} elseif ($exception instanceof ValidationException && $request->expectsJson()) {
nlog($exception->validator->getMessageBag());
return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);

View File

@ -28,6 +28,10 @@ class CloneQuoteToInvoiceFactory
unset($quote_array['invoice_id']);
unset($quote_array['id']);
unset($quote_array['invitations']);
unset($quote_array['terms']);
unset($quote_array['public_notes']);
unset($quote_array['footer']);
unset($quote_array['design_id']);
foreach ($quote_array as $key => $value) {
$invoice->{$key} = $value;

View File

@ -92,9 +92,11 @@ class ClientFilters extends QueryFilters
return $this->builder->where(function ($query) use ($filter) {
$query->where('clients.name', 'like', '%'.$filter.'%')
->orWhere('clients.id_number', 'like', '%'.$filter.'%')
->orWhere('client_contacts.first_name', 'like', '%'.$filter.'%')
->orWhere('client_contacts.last_name', 'like', '%'.$filter.'%')
->orWhere('client_contacts.email', 'like', '%'.$filter.'%')
->orWhereHas('contacts', function ($query) use($filter){
$query->where('first_name', 'like', '%'.$filter.'%');
$query->orWhere('last_name', 'like', '%'.$filter.'%');
$query->orWhere('email', 'like', '%'.$filter.'%');
})
->orWhere('clients.custom_value1', 'like', '%'.$filter.'%')
->orWhere('clients.custom_value2', 'like', '%'.$filter.'%')
->orWhere('clients.custom_value3', 'like', '%'.$filter.'%')

View File

@ -38,9 +38,11 @@ class ExpenseFilters extends QueryFilters
return $this->builder->where(function ($query) use ($filter) {
$query->where('expenses.name', 'like', '%'.$filter.'%')
->orWhere('expenses.id_number', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.first_name', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.last_name', 'like', '%'.$filter.'%')
->orWhere('expense_contacts.email', 'like', '%'.$filter.'%')
->orWhereHas('contacts', function ($query) use($filter){
$query->where('expense_contacts.first_name', 'like', '%'.$filter.'%');
$query->orWhere('expense_contacts.last_name', 'like', '%'.$filter.'%');
$query->orWhere('expense_contacts.email', 'like', '%'.$filter.'%');
})
->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%')

View File

@ -13,6 +13,7 @@ namespace App\Filters;
use App\Models\Invoice;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
@ -21,6 +22,7 @@ use Illuminate\Support\Carbon;
*/
class InvoiceFilters extends QueryFilters
{
use MakesHash;
/**
* Filter based on client status.
*
@ -65,6 +67,18 @@ class InvoiceFilters extends QueryFilters
return $this->builder;
}
public function client_id(string $client_id = '') :Builder
{
if (strlen($client_id) == 0) {
return $this->builder;
}
$this->builder->where('client_id', $this->decodePrimaryKey($client_id));
return $this->builder;
}
public function number(string $number) :Builder
{
return $this->builder->where('number', $number);
@ -96,6 +110,7 @@ class InvoiceFilters extends QueryFilters
});
}
/**
* Filters the list based on the status
* archived, active, deleted - legacy from V1.

View File

@ -38,9 +38,11 @@ class VendorFilters extends QueryFilters
return $this->builder->where(function ($query) use ($filter) {
$query->where('vendors.name', 'like', '%'.$filter.'%')
->orWhere('vendors.id_number', 'like', '%'.$filter.'%')
->orWhere('vendor_contacts.first_name', 'like', '%'.$filter.'%')
->orWhere('vendor_contacts.last_name', 'like', '%'.$filter.'%')
->orWhere('vendor_contacts.email', 'like', '%'.$filter.'%')
->orWhereHas('contacts', function ($query) use($filter){
$query->where('vendor_contacts.first_name', 'like', '%'.$filter.'%');
$query->orWhere('vendor_contacts.last_name', 'like', '%'.$filter.'%');
$query->orWhere('vendor_contacts.email', 'like', '%'.$filter.'%');
})
->orWhere('vendors.custom_value1', 'like', '%'.$filter.'%')
->orWhere('vendors.custom_value2', 'like', '%'.$filter.'%')
->orWhere('vendors.custom_value3', 'like', '%'.$filter.'%')

View File

@ -163,6 +163,6 @@ class ActivityController extends BaseController
return response()->streamDownload(function () use ($pdf) {
echo $pdf;
}, $filename);
}, $filename, ['Content-Type' => 'application/pdf']);
}
}

View File

@ -174,7 +174,7 @@ class InvoiceController extends Controller
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);;
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
}
// enable output of HTTP headers

View File

@ -96,7 +96,7 @@ class QuoteController extends Controller
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
}
// enable output of HTTP headers

View File

@ -104,8 +104,13 @@ class ConnectedAccountController extends BaseController
$refresh_token = '';
$token = '';
$email = $google->harvestEmail($user);
if(auth()->user()->email != $email && MultiDB::checkUserEmailExists($email))
return response()->json(['message' => ctrans('texts.email_already_register')], 400);
$connected_account = [
'email' => $google->harvestEmail($user),
'email' => $email,
'oauth_user_id' => $google->harvestSubField($user),
'oauth_provider_id' => 'google',
'email_verified_at' =>now()

View File

@ -544,7 +544,7 @@ class CreditController extends BaseController
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
break;
case 'archive':
$this->credit_repository->archive($credit);
@ -596,8 +596,8 @@ class CreditController extends BaseController
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
// return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
}, basename($file), ['Content-Type' => 'application/pdf']);
}
/**

View File

@ -131,8 +131,8 @@ class EmailController extends BaseController
$entity_obj->service()->markSent()->save();
EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data)
->delay(now()->addSeconds(30));
EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data);
// ->delay(now()->addSeconds(45));
}

View File

@ -672,16 +672,11 @@ class InvoiceController extends BaseController
break;
case 'download':
// $file = $invoice->pdf_file_path();
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
$file = $invoice->service()->getInvoicePdf();
// return response()->download(Storage::get($file), basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
break;
@ -805,11 +800,9 @@ class InvoiceController extends BaseController
$file = $invoice->service()->getInvoicePdf($contact);
// return response()->download(Storage::get($file), basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
}
/**
@ -861,10 +854,9 @@ class InvoiceController extends BaseController
$file = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
// return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
}

View File

@ -11,11 +11,26 @@
namespace App\Http\Controllers;
use App\DataMapper\Analytics\LivePreview;
use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory;
use App\Factory\QuoteFactory;
use App\Factory\RecurringInvoiceFactory;
use App\Http\Requests\Invoice\StoreInvoiceRequest;
use App\Http\Requests\Preview\PreviewInvoiceRequest;
use App\Jobs\Util\PreviewPdf;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Repositories\CreditRepository;
use App\Repositories\InvoiceRepository;
use App\Repositories\QuoteRepository;
use App\Repositories\RecurringInvoiceRepository;
use App\Services\PdfMaker\Design as PdfMakerDesign;
use App\Services\PdfMaker\Design;
use App\Services\PdfMaker\PdfMaker;
use App\Utils\HostedPDF\NinjaPdf;
@ -28,6 +43,7 @@ use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Response;
use Turbo124\Beacon\Facades\LightLogs;
class PreviewController extends BaseController
{
@ -149,6 +165,136 @@ class PreviewController extends BaseController
return $this->blankEntity();
}
public function live(PreviewInvoiceRequest $request)
{
if($request->input('entity') == 'invoice'){
$repo = new InvoiceRepository();
$factory = InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id);
$class = Invoice::class;
}
elseif($request->input('entity') == 'quote'){
$repo = new QuoteRepository();
$factory = QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id);
$class = Quote::class;
}
elseif($request->input('entity') == 'credit'){
$repo = new CreditRepository();
$factory = CreditFactory::create(auth()->user()->company()->id, auth()->user()->id);
$class = Credit::class;
}
elseif($request->input('entity') == 'recurring_invoice'){
$repo = new RecurringInvoiceRepository();
$factory = RecurringInvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id);
$class = RecurringInvoice::class;
}
try {
DB::connection(config('database.default'))->beginTransaction();
if($request->has('entity_id')){
$entity_obj = $class::withTrashed()->whereId($this->decodePrimaryKey($request->input('entity_id')))->company()->first();
$entity_obj = $repo->save($request->all(), $entity_obj);
}
else {
$entity_obj = $repo->save($request->all(), $factory);
}
$entity_obj->load('client');
App::forgetInstance('translator');
$t = app('translator');
App::setLocale($entity_obj->client->contacts()->first()->preferredLocale());
$t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
$html = new HtmlEngine($entity_obj->invitations()->first());
$design = \App\Models\Design::find($entity_obj->design_id);
/* Catch all in case migration doesn't pass back a valid design */
if(!$design)
$design = Design::find(2);
if ($design->is_custom) {
$options = [
'custom_partials' => json_decode(json_encode($design->design), true)
];
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
} else {
$template = new PdfMakerDesign(strtolower($design->name));
}
$variables = $html->generateLabelsAndValues();
$state = [
'template' => $template->elements([
'client' => $entity_obj->client,
'entity' => $entity_obj,
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
'$product' => $design->design->product,
'variables' => $variables,
]),
'variables' => $variables,
'options' => [
'all_pages_header' => $entity_obj->client->getSetting('all_pages_header'),
'all_pages_footer' => $entity_obj->client->getSetting('all_pages_footer'),
],
];
$maker = new PdfMaker($state);
$maker
->design($template)
->build();
DB::connection(config('database.default'))->rollBack();
if (request()->query('html') == 'true') {
return $maker->getCompiledHTML;
}
}
catch(\Exception $e){
DB::connection(config('database.default'))->rollBack();
return;
}
//if phantom js...... inject here..
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
}
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
return (new NinjaPdf())->build($maker->getCompiledHTML(true));
}
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
if(Ninja::isHosted())
{
LightLogs::create(new LivePreview())
->increment()
->batch();
}
$response = Response::make($file_path, 200);
$response->header('Content-Type', 'application/pdf');
return $response;
}
private function blankEntity()
{
App::forgetInstance('translator');

View File

@ -682,7 +682,7 @@ class QuoteController extends BaseController
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
//return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
@ -736,11 +736,10 @@ class QuoteController extends BaseController
$quote = $invitation->quote;
$file = $quote->service()->getQuotePdf($contact);
nlog($file);
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
// return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
}

View File

@ -505,7 +505,7 @@ class RecurringInvoiceController extends BaseController
return response()->streamDownload(function () use($file) {
echo Storage::get($file);
}, basename($file));
}, basename($file), ['Content-Type' => 'application/pdf']);
}

View File

@ -69,8 +69,6 @@ class SetupController extends Controller
}
if ($check['system_health'] === false) {
nlog($check);
return response('Oops, something went wrong. Check your logs.'); /* We should never reach this block, but just in case. */
}

View File

@ -26,6 +26,8 @@ class SubdomainController extends BaseController
'docs',
'client_domain',
'custom_domain',
'preview',
'invoiceninja',
];
public function __construct()

View File

@ -42,6 +42,9 @@ class UrlSetDb
$hashed_db = $hashids->decode($segments[0]);
if(!is_array($hashed_db))
return response()->json(['message' => 'Invalid confirmation code'], 403);
MultiDB::setDB(MultiDB::DB_PREFIX.str_pad($hashed_db[0], 2, '0', STR_PAD_LEFT));
}

View File

@ -34,7 +34,7 @@ class StoreCompanyGatewayRequest extends Request
public function rules()
{
$rules = [
'gateway_key' => 'required',
'gateway_key' => 'required|alpha_num',
'fees_and_limits' => new ValidCompanyGatewayFeesAndLimitsRule(),
];
@ -45,9 +45,8 @@ class StoreCompanyGatewayRequest extends Request
{
$input = $this->all();
$gateway = Gateway::where('key', $input['gateway_key'])->first();
if($gateway);
if($gateway = Gateway::where('key', $input['gateway_key'])->first())
{
$default_gateway_fields = json_decode($gateway->fields);

View File

@ -0,0 +1,60 @@
<?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://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\Preview;
use App\Http\Requests\Request;
use App\Http\ValidationRules\Project\ValidProjectForClient;
use App\Models\Invoice;
use App\Utils\Traits\CleanLineItems;
use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule;
class PreviewInvoiceRequest extends Request
{
use MakesHash;
use CleanLineItems;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('create', Invoice::class);
}
public function rules()
{
$rules = [];
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id;
$rules['number'] = ['nullable'];
return $rules;
}
protected function prepareForValidation()
{
$input = $this->all();
$input = $this->decodePrimaryKeys($input);
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
$input['amount'] = 0;
$input['balance'] = 0;
$input['number'] = ctrans('texts.live_preview') . " #". rand(0,1000);
$this->replace($input);
}
}

View File

@ -112,6 +112,10 @@ class NinjaMailerJob implements ShouldQueue
} catch (\Exception $e) {
// if($e instanceof GuzzleHttp\Exception\ClientException){
// }
nlog("error failed with {$e->getMessage()}");
if($this->nmo->entity)
@ -193,8 +197,6 @@ class NinjaMailerJob implements ShouldQueue
return $this->setMailDriver();
}
/*
* Now that our token is refreshed and valid we can boot the
* mail driver at runtime and also set the token which will persist

View File

@ -238,6 +238,10 @@ class Import implements ShouldQueue
/*After a migration first some basic jobs to ensure the system is up to date*/
VersionCheck::dispatch();
$account = $this->company->account;
$account->default_company_id = $this->company->id;
$account->save();
//company size check
if ($this->company->invoices()->count() > 1000 || $this->company->products()->count() > 1000 || $this->company->clients()->count() > 1000) {
$this->company->is_large = true;
@ -531,6 +535,7 @@ class Import implements ShouldQueue
$modified = $resource;
unset($modified['id']);
unset($modified['password']); //cant import passwords.
unset($modified['confirmation_code']); //cant import passwords.
$user = $user_repository->save($modified, $this->fetchUser($resource['email']), true, true);
$user->email_verified_at = now();

View File

@ -174,8 +174,8 @@ class ReminderJob implements ShouldQueue
/**Refresh Invoice values*/
$invoice = $invoice->calc()->getInvoice();
$invoice->client->service()->updateBalance($this->invoice->balance - $temp_invoice_balance)->save();
$invoice->ledger()->updateInvoiceBalance($this->invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$this->invoice->number}");
$invoice->client->service()->updateBalance($invoice->balance - $temp_invoice_balance)->save();
$invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}");
return $invoice;
}

View File

@ -38,7 +38,7 @@ class CreditCreatedNotification implements ShouldQueue
{
MultiDB::setDb($event->company->db);
$first_notification_sent = true;
// $first_notification_sent = true;
$credit = $event->credit;
@ -60,7 +60,7 @@ class CreditCreatedNotification implements ShouldQueue
$methods = $this->findUserNotificationTypes($credit->invitations()->first(), $company_user, 'credit', ['all_notifications', 'credit_created', 'credit_created_all']);
/* If one of the methods is email then we fire the EntitySentMailer */
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
@ -69,7 +69,7 @@ class CreditCreatedNotification implements ShouldQueue
NinjaMailerJob::dispatch($nmo);
/* This prevents more than one notification being sent */
$first_notification_sent = false;
// $first_notification_sent = false;
}
/* Override the methods in the Notification Class */

View File

@ -38,7 +38,7 @@ class CreditEmailedNotification implements ShouldQueue
{
MultiDB::setDb($event->company->db);
$first_notification_sent = true;
// $first_notification_sent = true;
$credit = $event->invitation->credit;
$credit->last_sent_date = now();
@ -56,14 +56,15 @@ class CreditEmailedNotification implements ShouldQueue
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'credit', ['all_notifications', 'credit_sent', 'credit_sent_all']);
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
// if (($key = array_search('mail', $methods))) {
unset($methods[$key]);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
$first_notification_sent = false;
// $first_notification_sent = false;
}
// $notification->method = $methods;

View File

@ -43,9 +43,11 @@ class CreditRestoredActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->credit->user_id;
$fields->credit_id = $event->credit->id;
$fields->client_id = $event->credit->client_id;
$fields->user_id = $event->credit->user_id;
$fields->user_id = $user_id;
$fields->company_id = $event->credit->company_id;
$fields->activity_type_id = Activity::RESTORE_CREDIT;

View File

@ -43,7 +43,9 @@ class CreditViewedActivity implements ShouldQueue
$fields = new stdClass;
$fields->user_id = $event->invitation->user_id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->user_id;
$fields->user_id = $user_id;
$fields->company_id = $event->invitation->company_id;
$fields->activity_type_id = Activity::VIEW_CREDIT;
$fields->client_id = $event->invitation->credit->client_id;

View File

@ -43,9 +43,11 @@ class CreateInvoiceActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::CREATE_INVOICE;

View File

@ -45,9 +45,12 @@ class InvoiceArchivedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::ARCHIVE_INVOICE;

View File

@ -43,9 +43,11 @@ class InvoiceCancelledActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::CANCELLED_INVOICE;

View File

@ -52,24 +52,23 @@ class InvoiceCreatedNotification implements ShouldQueue
/* The User */
$user = $company_user->user;
/* This is only here to handle the alternate message channels - ie Slack */
// $notification = new EntitySentNotification($event->invitation, 'invoice');
/* Returns an array of notification methods */
$methods = $this->findUserNotificationTypes($invoice->invitations()->first(), $company_user, 'invoice', ['all_notifications', 'invoice_created', 'invoice_created_all']);
/* If one of the methods is email then we fire the EntitySentMailer */
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
// if (($key = array_search('mail', $methods))) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
/* This prevents more than one notification being sent */
$first_notification_sent = false;
}
/* Override the methods in the Notification Class */

View File

@ -43,9 +43,11 @@ class InvoiceDeletedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::DELETE_INVOICE;

View File

@ -43,8 +43,10 @@ class InvoiceEmailActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invitation->invoice->id;
$fields->user_id = $event->invitation->invoice->user_id;
$fields->company_id = $event->invitation->invoice->company_id;
$fields->client_contact_id = $event->invitation->invoice->client_contact_id;
$fields->client_id = $event->invitation->invoice->client_id;

View File

@ -48,9 +48,12 @@ class InvoiceEmailFailedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invitation->invoice->id;
$fields->client_id = $event->invitation->invoice->client_id;
$fields->user_id = $event->invitation->invoice->user_id;
$fields->company_id = $event->invitation->invoice->company_id;
$fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED;
$fields->notes = $event->message;

View File

@ -63,10 +63,9 @@ class InvoiceEmailedNotification implements ShouldQueue
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent', 'invoice_sent_all']);
/* If one of the methods is email then we fire the EntitySentMailer */
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);

View File

@ -58,7 +58,7 @@ class InvoiceFailedEmailNotification
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent', 'invoice_sent_all']);
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
$nmo->to_user = $user;

View File

@ -44,8 +44,10 @@ class InvoicePaidActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::PAID_INVOICE;
$fields->payment_id = $event->payment->id;

View File

@ -42,8 +42,10 @@ class InvoiceReminderEmailActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invitation->invoice->id;
$fields->user_id = $event->invitation->invoice->user_id;
$fields->company_id = $event->invitation->invoice->company_id;
$fields->client_contact_id = $event->invitation->invoice->client_contact_id;
$fields->activity_type_id = $event->reminder;

View File

@ -43,9 +43,11 @@ class InvoiceRestoredActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::RESTORE_INVOICE;

View File

@ -43,9 +43,11 @@ class InvoiceReversedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->invoice_id = $event->invoice->id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::REVERSED_INVOICE;

View File

@ -43,7 +43,10 @@ class InvoiceViewedActivity implements ShouldQueue
$fields = new stdClass;
$fields->user_id = $event->invitation->user_id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id;
$fields->user_id = $user_id;
$fields->company_id = $event->invitation->company_id;
$fields->activity_type_id = Activity::VIEW_INVOICE;
$fields->client_id = $event->invitation->invoice->client_id;

View File

@ -43,8 +43,10 @@ class UpdateInvoiceActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invoice->user_id;
$fields->user_id = $user_id;
$fields->client_id = $event->invoice->client_id;
$fields->user_id = $event->invoice->user_id;
$fields->company_id = $event->invoice->company_id;
$fields->activity_type_id = Activity::UPDATE_INVOICE;
$fields->invoice_id = $event->invoice->id;

View File

@ -43,9 +43,11 @@ class PaymentRestoredActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id;
$fields->user_id = $user_id;
$fields->payment_id = $event->payment->id;
$fields->client_id = $event->payment->client_id;
$fields->user_id = $event->payment->user_id;
$fields->company_id = $event->payment->company_id;
$fields->activity_type_id = Activity::RESTORE_PAYMENT;

View File

@ -43,9 +43,11 @@ class QuoteApprovedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->quote->user_id;
$fields->user_id = $user_id;
$fields->quote_id = $event->quote->id;
$fields->client_id = $event->quote->client_id;
$fields->user_id = $event->quote->user_id;
$fields->client_contact_id = $event->contact->id;
$fields->company_id = $event->quote->company_id;
$fields->activity_type_id = Activity::APPROVE_QUOTE;

View File

@ -43,9 +43,11 @@ class QuoteArchivedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->quote->user_id;
$fields->user_id = $user_id;
$fields->quote_id = $event->quote->id;
$fields->client_id = $event->quote->client_id;
$fields->user_id = $event->quote->user_id;
$fields->company_id = $event->quote->company_id;
$fields->activity_type_id = Activity::ARCHIVE_QUOTE;

View File

@ -60,7 +60,7 @@ class QuoteCreatedNotification implements ShouldQueue
$methods = $this->findUserNotificationTypes($quote->invitations()->first(), $company_user, 'quote', ['all_notifications', 'quote_created', 'quote_created_all']);
/* If one of the methods is email then we fire the EntitySentMailer */
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);

View File

@ -43,9 +43,11 @@ class QuoteDeletedActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->quote->user_id;
$fields->user_id = $user_id;
$fields->quote_id = $event->quote->id;
$fields->client_id = $event->quote->client_id;
$fields->user_id = $event->quote->user_id;
$fields->company_id = $event->quote->company_id;
$fields->activity_type_id = Activity::DELETE_QUOTE;

View File

@ -43,9 +43,13 @@ class QuoteEmailActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->quote->user_id;
$fields->user_id = $user_id;
$fields->quote_id = $event->invitation->quote->id;
$fields->client_id = $event->invitation->quote->client_id;
$fields->user_id = $event->invitation->quote->user_id;
$fields->company_id = $event->invitation->quote->company_id;
$fields->client_contact_id = $event->invitation->quote->client_contact_id;
$fields->client_id = $event->invitation->quote->client_id;

View File

@ -38,7 +38,7 @@ class QuoteEmailedNotification implements ShouldQueue
{
MultiDB::setDb($event->company->db);
$first_notification_sent = true;
// $first_notification_sent = true;
$quote = $event->invitation->quote;
$quote->last_sent_date = now();
@ -57,7 +57,7 @@ class QuoteEmailedNotification implements ShouldQueue
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'quote', ['all_notifications', 'quote_sent', 'quote_sent_all']);
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
@ -65,7 +65,7 @@ class QuoteEmailedNotification implements ShouldQueue
NinjaMailerJob::dispatch($nmo);
$first_notification_sent = false;
// $first_notification_sent = false;
}
// $notification->method = $methods;

View File

@ -43,7 +43,10 @@ class QuoteRestoredActivity implements ShouldQueue
$fields = new stdClass;
$fields->quote_id = $event->quote->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->quote->user_id;
$fields->user_id = $user_id;
$fields->client_id = $event->quote->client_id;
$fields->user_id = $event->quote->user_id;
$fields->company_id = $event->quote->company_id;

View File

@ -43,9 +43,11 @@ class CreateRecurringInvoiceActivity implements ShouldQueue
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_invoice->user_id;
$fields->user_id = $user_id;
$fields->recurring_invoice_id = $event->recurring_invoice->id;
$fields->client_id = $event->recurring_invoice->client_id;
$fields->user_id = $event->recurring_invoice->user_id;
$fields->company_id = $event->recurring_invoice->company_id;
$fields->activity_type_id = Activity::CREATE_RECURRING_INVOICE;

View File

@ -44,10 +44,11 @@ class RecurringInvoiceArchivedActivity implements ShouldQueue
$event->recurring_invoice->service()->deletePdf();
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_invoice->user_id;
$fields->user_id = $user_id;
$fields->recurring_invoice_id = $event->recurring_invoice->id;
$fields->client_id = $event->recurring_invoice->client_id;
$fields->user_id = $event->recurring_invoice->user_id;
$fields->company_id = $event->recurring_invoice->company_id;
$fields->activity_type_id = Activity::ARCHIVE_RECURRING_INVOICE;

View File

@ -42,10 +42,11 @@ class RecurringInvoiceDeletedActivity implements ShouldQueue
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_invoice->user_id;
$fields->user_id = $user_id;
$fields->recurring_invoice_id = $event->recurring_invoice->id;
$fields->client_id = $event->recurring_invoice->client_id;
$fields->user_id = $event->recurring_invoice->user_id;
$fields->company_id = $event->recurring_invoice->company_id;
$fields->activity_type_id = Activity::DELETE_RECURRING_INVOICE;

View File

@ -42,10 +42,11 @@ class RecurringInvoiceRestoredActivity implements ShouldQueue
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_invoice->user_id;
$fields->user_id = $user_id;
$fields->recurring_invoice_id = $event->recurring_invoice->id;
$fields->client_id = $event->recurring_invoice->client_id;
$fields->user_id = $event->recurring_invoice->user_id;
$fields->company_id = $event->recurring_invoice->company_id;
$fields->activity_type_id = Activity::RESTORE_RECURRING_INVOICE;

View File

@ -42,9 +42,10 @@ class UpdateRecurringInvoiceActivity implements ShouldQueue
MultiDB::setDB($event->company->db);
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->recurring_invoice->user_id;
$fields->user_id = $user_id;
$fields->client_id = $event->recurring_invoice->client_id;
$fields->user_id = $event->recurring_invoice->user_id;
$fields->company_id = $event->recurring_invoice->company_id;
$fields->activity_type_id = Activity::UPDATE_RECURRING_INVOICE;
$fields->recurring_invoice_id = $event->recurring_invoice->id;

View File

@ -43,7 +43,9 @@ class ArchivedUserActivity implements ShouldQueue
$fields = new stdClass;
$fields->user_id = $event->creating_user->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
$fields->user_id = $user_id;
$fields->notes = $event->creating_user->present()->name . " Archived User " . $event->user->present()->name();
$fields->company_id = $event->company->id;

View File

@ -43,7 +43,9 @@ class CreatedUserActivity implements ShouldQueue
$fields = new stdClass;
$fields->user_id = $event->creating_user->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
$fields->user_id = $user_id;
$fields->notes = $event->creating_user->present()->name() . " Created the user " . $event->user->present()->name();
$fields->company_id = $event->company->id;
$fields->activity_type_id = Activity::CREATE_USER;

View File

@ -48,7 +48,10 @@ class DeletedUserActivity implements ShouldQueue
$fields = new stdClass;
$fields->user_id = $event->creating_user->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
$fields->user_id = $user_id;
$fields->notes = $event->creating_user->present()->name() . " Deleted the user " . $event->user->present()->name();
$fields->company_id = $event->company->id;
$fields->activity_type_id = Activity::DELETE_USER;

View File

@ -42,8 +42,9 @@ class RestoredUserActivity implements ShouldQueue
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
$fields->user_id = $event->user->id;
$fields->user_id = $user_id;
$fields->notes = $event->creating_user->present()->name() . " Restored user " . $event->user->present()->name();
$fields->company_id = $event->company->id;

View File

@ -42,7 +42,9 @@ class UpdatedUserActivity implements ShouldQueue
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->user_id = $event->creating_user->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
$fields->user_id = $user_id;
$fields->notes = $event->creating_user->present()->name() . " Updated user " . $event->user->present()->name();
$fields->company_id = $event->company->id;

View File

@ -23,7 +23,7 @@ class EntityCreatedObject
public $entity;
public $contact;
public $client;
public $company;
@ -49,7 +49,7 @@ class EntityCreatedObject
/* Set customized translations _NOW_ */
$t->replace(Ninja::transformTranslations($this->entity->company->settings));
$this->contact = $this->entity->invitations()->first()->contact;
$this->client = $this->entity->client;
$this->company = $this->entity->company;
$this->setTemplate();
@ -100,7 +100,7 @@ class EntityCreatedObject
ctrans(
$this->template_subject,
[
'client' => $this->contact->present()->name(),
'client' => $this->client->present()->name(),
'invoice' => $this->entity->number,
]
);
@ -112,7 +112,7 @@ class EntityCreatedObject
$this->template_body,
[
'amount' => $this->getAmount(),
'client' => $this->contact->present()->name(),
'client' => $this->client->present()->name(),
'invoice' => $this->entity->number,
]
);

View File

@ -121,7 +121,7 @@ class EntitySentObject
ctrans(
$this->template_subject,
[
'client' => $this->contact->present()->name(),
'client' => $this->contact->client->present()->name(),
'invoice' => $this->entity->number,
]
);
@ -133,7 +133,7 @@ class EntitySentObject
$this->template_body,
[
'amount' => $this->getAmount(),
'client' => $this->contact->present()->name(),
'client' => $this->contact->client->present()->name(),
'invoice' => $this->entity->number,
]
);

View File

@ -107,7 +107,6 @@ class TemplateEmail extends Mailable
$message->invitation = $this->invitation;
});
//hosted | plan check here
foreach ($this->build_email->getAttachments() as $file) {
if(is_string($file))

View File

@ -19,13 +19,13 @@ class TestMailServer extends Mailable
{
// use Queueable, SerializesModels;
public $message;
public $support_messages;
public $from_email;
public function __construct($message, $from_email)
public function __construct($support_messages, $from_email)
{
$this->message = $message;
$this->support_messages = $support_messages;
$this->from_email = $from_email;
}
@ -39,7 +39,7 @@ class TestMailServer extends Mailable
return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.email'))
->markdown('email.support.message', [
'message' => $this->message,
'support_message' => $this->support_messages,
'system_info' => '',
'laravel_log' => [],
]);

View File

@ -229,7 +229,7 @@ class Client extends BaseModel implements HasLocalePreference
public function system_logs()
{
return $this->hasMany(SystemLog::class);
return $this->hasMany(SystemLog::class)->orderBy('id', 'desc');
}
public function timezone()

View File

@ -87,10 +87,10 @@ class Gateway extends StaticModel
case 20:
case 56:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable']],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']],
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable']]]; //Stripe
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; //Stripe
break;
case 39:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Checkout

View File

@ -452,7 +452,7 @@ class Invoice extends BaseModel
return false;
break;
case 'when_sent':
return $this->status_id == self::STATUS_DRAFT;
return $this->status_id == self::STATUS_SENT;
break;
case 'when_paid':
return $this->status_id == self::STATUS_PAID || $this->status_id == self::STATUS_PARTIAL;
@ -477,19 +477,19 @@ class Invoice extends BaseModel
{
switch ($reminder_template) {
case 'invoice':
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(), $template));
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break;
case 'reminder1':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(), Activity::INVOICE_REMINDER1_SENT));
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER1_SENT));
break;
case 'reminder2':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(), Activity::INVOICE_REMINDER2_SENT));
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER2_SENT));
break;
case 'reminder3':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(), Activity::INVOICE_REMINDER3_SENT));
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER3_SENT));
break;
case 'reminder_endless':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(), Activity::INVOICE_REMINDER_ENDLESS_SENT));
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER_ENDLESS_SENT));
break;
default:
# code...

View File

@ -27,9 +27,9 @@ class CompanyPresenter extends EntityPresenter
return $this->settings->name ?: ctrans('texts.untitled_account');
//return $this->entity->name ?: ctrans('texts.untitled_account');
}
public function logo($settings = null)
{
if (! $settings) {
@ -45,6 +45,24 @@ class CompanyPresenter extends EntityPresenter
}
/**
* Test for using base64 encoding
*/
public function logo_base64($settings = null)
{
if (! $settings) {
$settings = $this->entity->settings;
}
if(strlen($settings->company_logo) >= 1 && (strpos($settings->company_logo, 'http') !== false))
return "data:image/png;base64, ". base64_encode(file_get_contents($settings->company_logo));
else if(strlen($settings->company_logo) >= 1)
return "data:image/png;base64, ". base64_encode(file_get_contents(url('') . $settings->company_logo));
else
return "data:image/png;base64, ". base64_encode(file_get_contents(asset('images/new_logo.png')));
}
public function address($settings = null)
{
$str = '';

View File

@ -128,6 +128,49 @@ class CheckoutComPaymentDriver extends BaseDriver
return 'gateways.checkout.credit_card.pay';
}
public function getClientRequiredFields(): array
{
$fields = [];
if ($this->company_gateway->require_client_name) {
$fields[] = ['name' => 'client_name', 'label' => ctrans('texts.client_name'), 'type' => 'text', 'validation' => 'required'];
}
if ($this->company_gateway->require_contact_name) {
$fields[] = ['name' => 'contact_first_name', 'label' => ctrans('texts.first_name'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'contact_last_name', 'label' => ctrans('texts.last_name'), 'type' => 'text', 'validation' => 'required'];
}
if ($this->company_gateway->require_contact_email) {
$fields[] = ['name' => 'contact_email', 'label' => ctrans('texts.email'), 'type' => 'text', 'validation' => 'required,email:rfc'];
}
if ($this->company_gateway->require_client_phone) {
$fields[] = ['name' => 'client_phone', 'label' => ctrans('texts.client_phone'), 'type' => 'tel', 'validation' => 'required'];
}
if ($this->company_gateway->require_billing_address) {
$fields[] = ['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_city', 'label' => ctrans('texts.city'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_state', 'label' => ctrans('texts.state'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'text', 'validation' => 'required'];
}
if($this->company_gateway->require_postal_code) {
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
}
if ($this->company_gateway->require_shipping_address) {
$fields[] = ['name' => 'client_shipping_address_line_1', 'label' => ctrans('texts.shipping_address1'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_city', 'label' => ctrans('texts.shipping_city'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_state', 'label' => ctrans('texts.shipping_state'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_postal_code', 'label' => ctrans('texts.shipping_postal_code'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_country_id', 'label' => ctrans('texts.shipping_country'), 'type' => 'text', 'validation' => 'required'];
}
return $fields;
}
public function authorizeView($data)
{
return $this->payment_method->authorizeView($data);

View File

@ -105,7 +105,7 @@ class ACH
$this->stripe->init();
$bank_account = Customer::retrieveSource($request->customer, $request->source, $this->stripe->stripe_connect_auth);
$bank_account = Customer::retrieveSource($request->customer, ['source' => $request->source], $this->stripe->stripe_connect_auth);
try {
$bank_account->verify(['amounts' => request()->transactions]);

View File

@ -142,6 +142,9 @@ class ACH
}
catch(\Exception $e){
nlog("we pay exception");
nlog($e->getMessage());
return redirect()->route('client.payment_methods.verification', ['payment_method' => $token->hashed_id, 'method' => GatewayType::BANK_TRANSFER])
->with('error', $e->getMessage());
@ -194,7 +197,7 @@ class ACH
$token = ClientGatewayToken::find($this->decodePrimaryKey($request->input('source')));
$token_meta = $token->meta;
if($token_meta->state != "authorized")
if(!property_exists($token_meta, 'state') || $token_meta->state != "authorized")
return redirect()->route('client.payment_methods.verification', ['payment_method' => $token->hashed_id, 'method' => GatewayType::BANK_TRANSFER]);
$app_fee = (config('ninja.wepay.fee_ach_multiplier') * $this->wepay_payment_driver->payment_hash->data->amount_with_fee) + config('ninja.wepay.fee_fixed');

View File

@ -51,11 +51,11 @@ class ActivityRepository extends BaseRepository
}
if ($token_id = $this->getTokenId($event_vars)) {
$fields->token_id = $token_id;
$activity->token_id = $token_id;
}
$fields->ip = $event_vars['ip'];
$fields->is_system = $event_vars['is_system'];
$activity->ip = $event_vars['ip'];
$activity->is_system = $event_vars['is_system'];
$activity->save();

View File

@ -300,7 +300,7 @@ class BaseRepository
$model->partial = min($model->amount, $model->balance);
/* Update product details if necessary */
if ($model->company->update_products)
if ($model->company->update_products && $model->id)
UpdateOrCreateProduct::dispatch($model->line_items, $model, $model->company);
/* Perform model specific tasks */

View File

@ -40,6 +40,7 @@ class ConvertQuote
$invoice->fresh();
$invoice->service()
->fillDefaults()
// ->markSent()
// ->createInvitations()
->save();

View File

@ -167,7 +167,7 @@ class HtmlEngine
$data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.discount')];
$data['$discount'] = &$data['$invoice.discount'];
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
$data['$net_subtotal'] = ['value' => Number::formatMoney(($this->entity_calc->getSubTotal() - $this->entity->total_taxes), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
$data['$net_subtotal'] = ['value' => Number::formatMoney(($this->entity_calc->getSubTotal() - $this->entity->total_taxes), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.net_subtotal')];
$data['$invoice.subtotal'] = &$data['$subtotal'];
if ($this->entity->partial > 0) {
@ -331,7 +331,7 @@ class HtmlEngine
$data['$spc_qr_code'] = ['value' => $this->company->present()->getSpcQrCode($this->client->currency()->code, $this->entity->number, $this->entity->balance, $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'company1', $this->settings->custom_value1, $this->client)), 'label' => ''];
$logo = $this->company->present()->logo($this->settings);
$logo = $this->company->present()->logo_base64($this->settings);
$data['$company.logo'] = ['value' => $logo ?: '&nbsp;', 'label' => ctrans('texts.logo')];
$data['$company_logo'] = &$data['$company.logo'];

View File

@ -36,6 +36,7 @@ trait CompanySettingsSaver
*/
public function saveSettings($settings, $entity)
{
/* No Settings, No Save!*/
if (! $settings) {
return;
@ -58,6 +59,8 @@ trait CompanySettingsSaver
}
}
if(property_exists($settings, 'translations'))
{
//this pass will handle any null values that are in the translations
foreach ($settings->translations as $key => $value) {
if (is_null($settings->translations[$key])) {
@ -66,6 +69,7 @@ trait CompanySettingsSaver
}
$company_settings->translations = $settings->translations;
}
$entity->settings = $company_settings;

View File

@ -24,6 +24,7 @@ use App\Models\Task;
use App\Models\Timezone;
use App\Models\Vendor;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
/**
* Class GeneratesCounter.
@ -343,17 +344,24 @@ trait GeneratesCounter
{
$check = false;
$check_counter = 1;
do {
$number = $this->padCounter($counter, $padding);
$number = $this->applyNumberPattern($entity, $number, $pattern);
$number = $this->prefixCounter($number, $prefix);
$check = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->first();
$check = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->exists();
$counter++;
$check_counter++;
if($check_counter > 100)
return $number . "_" . Str::random(5);
} while ($check);
return $number;
@ -364,7 +372,7 @@ trait GeneratesCounter
public function checkNumberAvailable($class, $entity, $number) :bool
{
if ($entity = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->first())
if ($entity = $class::whereCompanyId($entity->company_id)->whereNumber($number)->withTrashed()->exists())
return false;
return true;

View File

@ -273,13 +273,13 @@ trait MakesInvoiceValues
foreach ($items as $key => $item) {
if ($table_type == '$product' && $item->type_id != 1) {
if ($item->type_id != 4 && $item->type_id != 6) {
if ($item->type_id != 4 && $item->type_id != 6 && $item->type_id != 5) {
continue;
}
}
if ($table_type == '$task' && $item->type_id != 2) {
if ($item->type_id != 4) {
if ($item->type_id != 4 && $item->type_id != 5) {
continue;
}
}

View File

@ -33,10 +33,6 @@ trait Uploadable
if ($file) {
$path = UploadAvatar::dispatchNow($file, $company->company_key);
//$path = str_replace(config("ninja.app_url"), "", $path);
info("the path {$path}");
if ($path) {
$settings = $entity->settings;
$settings->company_logo = $path;

View File

@ -46,7 +46,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
// 'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
// 'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
],
'sqlite' => [
@ -93,7 +93,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
// 'options' => array(
// PDO::ATTR_EMULATE_PREPARES => true
// ),
@ -111,7 +111,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
// 'options' => array(
// PDO::ATTR_EMULATE_PREPARES => true
// ),
@ -129,7 +129,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
// 'options' => array(
// PDO::ATTR_EMULATE_PREPARES => true
// ),
@ -147,7 +147,7 @@ return [
'prefix' => '',
'prefix_indexes' => true,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
'engine' => 'InnoDB ROW_FORMAT=DYNAMIC',
// 'options' => array(
// PDO::ATTR_EMULATE_PREPARES => true
// ),

View File

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

View File

@ -0,0 +1,33 @@
<?php
use App\Models\Language;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ChangeEnglishLanguagesTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if($language = Language::find(1))
{
$language->name = 'English - United States';
$language->save();
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -24,7 +24,7 @@ class LanguageSeeder extends Seeder
// https://www.loc.gov/standards/iso639-2/php/code_list.php
$languages = [
['id' => 1, 'name' => 'English', 'locale' => 'en'],
['id' => 1, 'name' => 'English - United States', 'locale' => 'en'],
['id' => 2, 'name' => 'Italian', 'locale' => 'it'],
['id' => 3, 'name' => 'German', 'locale' => 'de'],
['id' => 4, 'name' => 'French', 'locale' => 'fr'],

View File

@ -1 +1 @@
{"assets/images/google-icon.png":["assets/images/google-icon.png"],"assets/images/icon.png":["assets/images/icon.png"],"assets/images/payment_types/ach.png":["assets/images/payment_types/ach.png"],"assets/images/payment_types/amex.png":["assets/images/payment_types/amex.png"],"assets/images/payment_types/carteblanche.png":["assets/images/payment_types/carteblanche.png"],"assets/images/payment_types/dinerscard.png":["assets/images/payment_types/dinerscard.png"],"assets/images/payment_types/discover.png":["assets/images/payment_types/discover.png"],"assets/images/payment_types/jcb.png":["assets/images/payment_types/jcb.png"],"assets/images/payment_types/laser.png":["assets/images/payment_types/laser.png"],"assets/images/payment_types/maestro.png":["assets/images/payment_types/maestro.png"],"assets/images/payment_types/mastercard.png":["assets/images/payment_types/mastercard.png"],"assets/images/payment_types/other.png":["assets/images/payment_types/other.png"],"assets/images/payment_types/paypal.png":["assets/images/payment_types/paypal.png"],"assets/images/payment_types/solo.png":["assets/images/payment_types/solo.png"],"assets/images/payment_types/switch.png":["assets/images/payment_types/switch.png"],"assets/images/payment_types/unionpay.png":["assets/images/payment_types/unionpay.png"],"assets/images/payment_types/visa.png":["assets/images/payment_types/visa.png"],"packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf":["packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf"]}
{"assets/images/google-icon.png":["assets/images/google-icon.png"],"assets/images/icon.png":["assets/images/icon.png"],"assets/images/logo.png":["assets/images/logo.png"],"assets/images/payment_types/ach.png":["assets/images/payment_types/ach.png"],"assets/images/payment_types/amex.png":["assets/images/payment_types/amex.png"],"assets/images/payment_types/carteblanche.png":["assets/images/payment_types/carteblanche.png"],"assets/images/payment_types/dinerscard.png":["assets/images/payment_types/dinerscard.png"],"assets/images/payment_types/discover.png":["assets/images/payment_types/discover.png"],"assets/images/payment_types/jcb.png":["assets/images/payment_types/jcb.png"],"assets/images/payment_types/laser.png":["assets/images/payment_types/laser.png"],"assets/images/payment_types/maestro.png":["assets/images/payment_types/maestro.png"],"assets/images/payment_types/mastercard.png":["assets/images/payment_types/mastercard.png"],"assets/images/payment_types/other.png":["assets/images/payment_types/other.png"],"assets/images/payment_types/paypal.png":["assets/images/payment_types/paypal.png"],"assets/images/payment_types/solo.png":["assets/images/payment_types/solo.png"],"assets/images/payment_types/switch.png":["assets/images/payment_types/switch.png"],"assets/images/payment_types/unionpay.png":["assets/images/payment_types/unionpay.png"],"assets/images/payment_types/visa.png":["assets/images/payment_types/visa.png"],"packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf":["packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf"]}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -4,7 +4,7 @@ const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"main.dart.js": "0e2c2fce69f7c2311615c518afa55e3e",
"main.dart.js": "c3ca362d549201394b5c4301af639ddb",
"/": "23224b5e03519aaa87594403d54412cf",
"manifest.json": "ce1b79950eb917ea619a0a30da27c6a3",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
@ -13,6 +13,7 @@ const RESOURCES = {
"assets/fonts/MaterialIcons-Regular.otf": "1288c9e28052e028aba623321f7826ac",
"assets/assets/images/google-icon.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
"assets/assets/images/logo.png": "e5f46d5a78e226e7a9553d4ca6f69219",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
@ -28,7 +29,7 @@ const RESOURCES = {
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"assets/AssetManifest.json": "7e49562f32e24a9e2557fe4178a84b79",
"assets/AssetManifest.json": "753bba1dee0531d5fad970b5ce1d296d",
"version.json": "3f9e03374a3e78d2cab3afd8723d0993",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",

217613
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

216977
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,7 @@ $LANG = array(
'quantity' => 'Menge',
'line_total' => 'Summe',
'subtotal' => 'Zwischensumme',
'net_subtotal' => 'Netto',
'paid_to_date' => 'Bereits gezahlt',
'balance_due' => 'Offener Betrag',
'invoice_design_id' => 'Design',

View File

@ -41,6 +41,7 @@ $LANG = array(
'quantity' => 'Quantity',
'line_total' => 'Line Total',
'subtotal' => 'Subtotal',
'net_subtotal' => 'Net',
'paid_to_date' => 'Paid to Date',
'balance_due' => 'Balance Due',
'invoice_design_id' => 'Design',
@ -1749,6 +1750,7 @@ $LANG = array(
'lang_Danish' => 'Danish',
'lang_Dutch' => 'Dutch',
'lang_English' => 'English',
'lang_English - United States' => 'English',
'lang_French' => 'French',
'lang_French - Canada' => 'French - Canada',
'lang_German' => 'German',
@ -4284,6 +4286,7 @@ $LANG = array(
'user_created_user' => ':user created :created_user at :time',
'company_deleted' => 'Company deleted',
'company_deleted_body' => 'Company [ :company ] was deleted by :user',
'back_to' => 'Back to :url',
);
return $LANG;

View File

@ -41,6 +41,7 @@ $LANG = array(
'quantity' => 'Quantity',
'line_total' => 'Line Total',
'subtotal' => 'Subtotal',
'net_subtotal' => 'Net',
'paid_to_date' => 'Paid to Date',
'balance_due' => 'Balance Due',
'invoice_design_id' => 'Design',

View File

@ -1,4 +1,4 @@
@component('email.template.admin', ['logo' => 'https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-white-horizontal-1.png', 'settings' => $settings, 'company' => $company ?? ''])
@component('email.template.admin', ['logo' => $logo, 'settings' => $settings, 'company' => $company ?? ''])
<div class="center">
<h1>{{ ctrans('texts.import_complete') }}</h1>
<p>Hello, here is the output of your recent import job.</p>

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