mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-09-28 12:17:09 +02:00
Merge branch 'v5-develop' into v5-stable
This commit is contained in:
commit
3dbeece1cf
@ -60,36 +60,36 @@ class SubdomainFill extends Command
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$db1 = Company::on('db-ninja-01')->get();
|
// $db1 = Company::on('db-ninja-01')->get();
|
||||||
|
|
||||||
$db1->each(function ($company){
|
// $db1->each(function ($company){
|
||||||
|
|
||||||
$db2 = Company::on('db-ninja-02a')->find($company->id);
|
// $db2 = Company::on('db-ninja-02a')->find($company->id);
|
||||||
|
|
||||||
if($db2)
|
// if($db2)
|
||||||
{
|
// {
|
||||||
$db2->subdomain = $company->subdomain;
|
// $db2->subdomain = $company->subdomain;
|
||||||
$db2->save();
|
// $db2->save();
|
||||||
}
|
// }
|
||||||
|
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
$db1 = null;
|
// $db1 = null;
|
||||||
$db2 = null;
|
// $db2 = null;
|
||||||
|
|
||||||
$db2 = Company::on('db-ninja-02')->get();
|
// $db2 = Company::on('db-ninja-02')->get();
|
||||||
|
|
||||||
$db2->each(function ($company){
|
// $db2->each(function ($company){
|
||||||
|
|
||||||
$db1 = Company::on('db-ninja-01a')->find($company->id);
|
// $db1 = Company::on('db-ninja-01a')->find($company->id);
|
||||||
|
|
||||||
if($db1)
|
// if($db1)
|
||||||
{
|
// {
|
||||||
$db1->subdomain = $company->subdomain;
|
// $db1->subdomain = $company->subdomain;
|
||||||
$db1->save();
|
// $db1->save();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,6 @@ class CompanySettings extends BaseSettings
|
|||||||
'email_template_reminder2' => 'string',
|
'email_template_reminder2' => 'string',
|
||||||
'email_template_reminder3' => 'string',
|
'email_template_reminder3' => 'string',
|
||||||
'email_template_reminder_endless' => 'string',
|
'email_template_reminder_endless' => 'string',
|
||||||
'enable_client_portal_password' => 'bool',
|
|
||||||
'inclusive_taxes' => 'bool',
|
'inclusive_taxes' => 'bool',
|
||||||
'invoice_number_pattern' => 'string',
|
'invoice_number_pattern' => 'string',
|
||||||
'invoice_number_counter' => 'integer',
|
'invoice_number_counter' => 'integer',
|
||||||
|
@ -77,7 +77,7 @@ class Handler extends ExceptionHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Ninja::isHosted()){
|
if(Ninja::isHosted() && !($exception instanceof ValidationException)){
|
||||||
|
|
||||||
app('sentry')->configureScope(function (Scope $scope): void {
|
app('sentry')->configureScope(function (Scope $scope): void {
|
||||||
|
|
||||||
|
@ -46,8 +46,6 @@ class GmailTransport extends Transport
|
|||||||
$this->gmail = null;
|
$this->gmail = null;
|
||||||
$this->gmail = new Mail;
|
$this->gmail = new Mail;
|
||||||
|
|
||||||
nlog($message->getBcc());
|
|
||||||
|
|
||||||
/*We should nest the token in the message and then discard it as needed*/
|
/*We should nest the token in the message and then discard it as needed*/
|
||||||
$token = $message->getHeaders()->get('GmailToken')->getValue();
|
$token = $message->getHeaders()->get('GmailToken')->getValue();
|
||||||
|
|
||||||
@ -62,13 +60,13 @@ class GmailTransport extends Transport
|
|||||||
$this->gmail->message($message->getBody());
|
$this->gmail->message($message->getBody());
|
||||||
|
|
||||||
$this->gmail->cc($message->getCc());
|
$this->gmail->cc($message->getCc());
|
||||||
$this->gmail->bcc($message->getBcc());
|
|
||||||
|
if(is_array($message->getBcc()))
|
||||||
|
$this->gmail->bcc(array_keys($message->getBcc()));
|
||||||
|
|
||||||
foreach ($message->getChildren() as $child)
|
foreach ($message->getChildren() as $child)
|
||||||
{
|
{
|
||||||
|
|
||||||
nlog("trying to attach");
|
|
||||||
|
|
||||||
if($child->getContentType() != 'text/plain')
|
if($child->getContentType() != 'text/plain')
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -201,6 +201,14 @@ class LoginController extends BaseController
|
|||||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If for some reason we lose state on the default company ie. a company is deleted - always make sure we can default to a company*/
|
||||||
|
if(!$user->account->default_company){
|
||||||
|
$account = $user->account;
|
||||||
|
$account->default_company_id = $user->companies->first()->id;
|
||||||
|
$account->save();
|
||||||
|
$user = $user->fresh();
|
||||||
|
}
|
||||||
|
|
||||||
$user->setCompany($user->account->default_company);
|
$user->setCompany($user->account->default_company);
|
||||||
|
|
||||||
$this->setLoginCache($user);
|
$this->setLoginCache($user);
|
||||||
|
@ -21,8 +21,6 @@ class PaymentWebhookController extends Controller
|
|||||||
public function __invoke(PaymentWebhookRequest $request, string $company_key, string $company_gateway_id)
|
public function __invoke(PaymentWebhookRequest $request, string $company_key, string $company_gateway_id)
|
||||||
{
|
{
|
||||||
|
|
||||||
// MultiDB::findAndSetDbByCompanyKey($company_key);
|
|
||||||
|
|
||||||
$payment = $request->getPayment();
|
$payment = $request->getPayment();
|
||||||
|
|
||||||
if(!$payment)
|
if(!$payment)
|
||||||
@ -33,7 +31,6 @@ class PaymentWebhookController extends Controller
|
|||||||
if(!$client)
|
if(!$client)
|
||||||
return response()->json(['message' => 'Client record not found.'], 400);
|
return response()->json(['message' => 'Client record not found.'], 400);
|
||||||
|
|
||||||
|
|
||||||
return $request->getCompanyGateway()
|
return $request->getCompanyGateway()
|
||||||
->driver($client)
|
->driver($client)
|
||||||
->processWebhookRequest($request, $payment);
|
->processWebhookRequest($request, $payment);
|
||||||
|
@ -155,7 +155,7 @@ class PreviewController extends BaseController
|
|||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
$t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
$t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
|
|
||||||
$client = Client::factory()->create([
|
$client = Client::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
@ -230,7 +230,7 @@ class PreviewController extends BaseController
|
|||||||
|
|
||||||
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||||
|
|
||||||
DB::rollBack();
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
$response = Response::make($file_path, 200);
|
$response = Response::make($file_path, 200);
|
||||||
$response->header('Content-Type', 'application/pdf');
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
@ -11,11 +11,17 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use PragmaRX\Google2FA\Google2FA;
|
use App\Models\User;
|
||||||
|
use App\Transformers\UserTransformer;
|
||||||
use Crypt;
|
use Crypt;
|
||||||
|
use PragmaRX\Google2FA\Google2FA;
|
||||||
|
|
||||||
class TwoFactorController extends BaseController
|
class TwoFactorController extends BaseController
|
||||||
{
|
{
|
||||||
|
protected $entity_type = User::class;
|
||||||
|
|
||||||
|
protected $entity_transformer = UserTransformer::class;
|
||||||
|
|
||||||
public function setupTwoFactor()
|
public function setupTwoFactor()
|
||||||
{
|
{
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
56
app/Http/Livewire/PaymentMethods/UpdateDefaultMethod.php
Normal file
56
app/Http/Livewire/PaymentMethods/UpdateDefaultMethod.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?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\Livewire\PaymentMethods;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class UpdateDefaultMethod extends Component
|
||||||
|
{
|
||||||
|
/** @var \App\Models\Company */
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
/** @var \App\Models\ClientGatewayToken */
|
||||||
|
public $token;
|
||||||
|
|
||||||
|
/** @var \App\Models\Client */
|
||||||
|
public $client;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->company = $this->client->company;
|
||||||
|
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
$this->is_disabled = $this->token->is_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeDefault(): void
|
||||||
|
{
|
||||||
|
if ($this->token->is_default) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->client->gateway_tokens()->update(['is_default' => 0]);
|
||||||
|
|
||||||
|
$this->token->is_default = 1;
|
||||||
|
$this->token->save();
|
||||||
|
|
||||||
|
$this->emit('UpdateDefaultMethod::method-updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return render('components.livewire.update-default-payment-method');
|
||||||
|
}
|
||||||
|
}
|
34
app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php
Normal file
34
app/Http/Livewire/RecurringInvoices/UpdateAutoBilling.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?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\Livewire\RecurringInvoices;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class UpdateAutoBilling extends Component
|
||||||
|
{
|
||||||
|
/** @var \App\Models\RecurringInvoice */
|
||||||
|
public $invoice;
|
||||||
|
|
||||||
|
public function updateAutoBilling(): void
|
||||||
|
{
|
||||||
|
if ($this->invoice->auto_bill === 'optin' || $this->invoice->auto_bill === 'optout') {
|
||||||
|
$this->invoice->auto_bill_enabled = !$this->invoice->auto_bill_enabled;
|
||||||
|
$this->invoice->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return render('components.livewire.recurring-invoices-switch-autobilling');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\ClientPortal\PaymentMethod;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class VerifyPaymentMethodRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'transactions.*' => 'integer'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,7 @@ class RecurringInvoicesCron
|
|||||||
if (! config('ninja.db.multi_db_enabled')) {
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||||
->whereNotNull('next_send_date')
|
->whereNotNull('next_send_date')
|
||||||
|
->whereNull('deleted_at')
|
||||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||||
->where('remaining_cycles', '!=', '0')
|
->where('remaining_cycles', '!=', '0')
|
||||||
->with('company')
|
->with('company')
|
||||||
@ -66,6 +67,7 @@ class RecurringInvoicesCron
|
|||||||
|
|
||||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||||
->whereNotNull('next_send_date')
|
->whereNotNull('next_send_date')
|
||||||
|
->whereNull('deleted_at')
|
||||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||||
->where('remaining_cycles', '!=', '0')
|
->where('remaining_cycles', '!=', '0')
|
||||||
->with('company')
|
->with('company')
|
||||||
@ -74,7 +76,7 @@ class RecurringInvoicesCron
|
|||||||
nlog(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
|
nlog(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
|
||||||
|
|
||||||
$recurring_invoices->each(function ($recurring_invoice, $key) {
|
$recurring_invoices->each(function ($recurring_invoice, $key) {
|
||||||
nlog("Current date = " . now()->format("Y-m-d") . " Recurring date = " .$recurring_invoice->next_send_date);
|
nlog("Current date = " . now()->format("Y-m-d") . " Recurring date = " .$recurring_invoice->next_send_date ." Recurring #id = ". $recurring_invoice->id);
|
||||||
|
|
||||||
if (!$recurring_invoice->company->is_disabled) {
|
if (!$recurring_invoice->company->is_disabled) {
|
||||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||||
|
@ -136,6 +136,11 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
$entity_design_id = 2;
|
$entity_design_id = 2;
|
||||||
|
|
||||||
$design = Design::find($entity_design_id);
|
$design = Design::find($entity_design_id);
|
||||||
|
|
||||||
|
/* Catch all in case migration doesn't pass back a valid design */
|
||||||
|
if(!$design)
|
||||||
|
$design = Design::find(2);
|
||||||
|
|
||||||
$html = new HtmlEngine($this->invitation);
|
$html = new HtmlEngine($this->invitation);
|
||||||
|
|
||||||
if ($design->is_custom) {
|
if ($design->is_custom) {
|
||||||
|
@ -101,7 +101,8 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
//send email
|
//send email
|
||||||
try {
|
try {
|
||||||
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||||
|
nlog("Using mailer => ". $this->mailer);
|
||||||
|
|
||||||
Mail::mailer($this->mailer)
|
Mail::mailer($this->mailer)
|
||||||
->to($this->nmo->to_user->email)
|
->to($this->nmo->to_user->email)
|
||||||
->send($this->nmo->mailable);
|
->send($this->nmo->mailable);
|
||||||
@ -146,11 +147,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
/* Singletons need to be rebooted each time just in case our Locale is changing*/
|
/* Singletons need to be rebooted each time just in case our Locale is changing*/
|
||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
// App::forgetInstance('mail.manager'); //singletons must be destroyed!
|
|
||||||
// App::forgetInstance('mailer');
|
|
||||||
// App::forgetInstance('laravelgmail');
|
|
||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
/* Inject custom translations if any exist */
|
|
||||||
$t->replace(Ninja::transformTranslations($this->nmo->settings));
|
$t->replace(Ninja::transformTranslations($this->nmo->settings));
|
||||||
|
|
||||||
switch ($this->nmo->settings->email_sending_method) {
|
switch ($this->nmo->settings->email_sending_method) {
|
||||||
@ -165,7 +162,6 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(new MailServiceProvider(app()))->register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setGmailMailer()
|
private function setGmailMailer()
|
||||||
@ -182,7 +178,14 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
$google = (new Google())->init();
|
$google = (new Google())->init();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
|
if ($google->getClient()->isAccessTokenExpired()) {
|
||||||
|
$google->refreshToken($user);
|
||||||
|
$user = $user->fresh();
|
||||||
|
}
|
||||||
|
|
||||||
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(\Exception $e) {
|
catch(\Exception $e) {
|
||||||
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||||
@ -190,9 +193,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
return $this->setMailDriver();
|
return $this->setMailDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($google->getClient()->isAccessTokenExpired()) {
|
|
||||||
$google->refreshToken($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that our token is refreshed and valid we can boot the
|
* Now that our token is refreshed and valid we can boot the
|
||||||
|
@ -55,10 +55,15 @@ class CompanySizeCheck implements ShouldQueue
|
|||||||
private function check()
|
private function check()
|
||||||
{
|
{
|
||||||
Company::cursor()->each(function ($company) {
|
Company::cursor()->each(function ($company) {
|
||||||
if ($company->invoices->count() > 1000 || $company->products->count() > 1000 || $company->clients->count() > 1000) {
|
|
||||||
|
if ($company->invoices()->count() > 1000 || $company->products()->count() > 1000 || $company->clients()->count() > 1000) {
|
||||||
|
|
||||||
|
nlog("Marking company {$company->id} as large");
|
||||||
|
|
||||||
$company->is_large = true;
|
$company->is_large = true;
|
||||||
$company->save();
|
$company->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,6 +337,10 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
if(!MultiDB::checkDomainAvailable($data['subdomain']))
|
if(!MultiDB::checkDomainAvailable($data['subdomain']))
|
||||||
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||||
|
|
||||||
|
if(strlen($data['subdomain']) == 0)
|
||||||
|
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules = (new UpdateCompanyRequest())->rules();
|
$rules = (new UpdateCompanyRequest())->rules();
|
||||||
|
@ -56,6 +56,7 @@ class ReminderJob implements ShouldQueue
|
|||||||
nlog("Sending invoice reminders " . now()->format('Y-m-d h:i:s'));
|
nlog("Sending invoice reminders " . now()->format('Y-m-d h:i:s'));
|
||||||
|
|
||||||
Invoice::where('next_send_date', '<=', now()->toDateTimeString())
|
Invoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||||
|
->whereNull('deleted_at')
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
|
@ -25,14 +25,21 @@ class ACHVerificationNotification extends Mailable
|
|||||||
*/
|
*/
|
||||||
public $company;
|
public $company;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Company $company)
|
public function __construct(Company $company, string $url)
|
||||||
{
|
{
|
||||||
$this->company = $company;
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->url = $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,7 @@ class MigrationCompleted extends Mailable
|
|||||||
$data['settings'] = $this->company->settings;
|
$data['settings'] = $this->company->settings;
|
||||||
$data['company'] = $this->company->fresh();
|
$data['company'] = $this->company->fresh();
|
||||||
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
|
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
|
||||||
$data['check_data'] = $this->check_data;
|
$data['check_data'] = $this->check_data ?: '';
|
||||||
$data['logo'] = $this->company->present()->logo();
|
$data['logo'] = $this->company->present()->logo();
|
||||||
|
|
||||||
$result = $this->from(config('mail.from.address'), config('mail.from.name'))
|
$result = $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||||
|
@ -49,8 +49,11 @@ class TemplateEmail extends Mailable
|
|||||||
|
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
// $template_name = 'email.template.'.$this->build_email->getTemplate();
|
$template_name = 'email.template.'.$this->build_email->getTemplate();
|
||||||
$template_name = 'email.template.client';
|
|
||||||
|
if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') {
|
||||||
|
$template_name = 'email.template.client';
|
||||||
|
}
|
||||||
|
|
||||||
if($this->build_email->getTemplate() == 'custom') {
|
if($this->build_email->getTemplate() == 'custom') {
|
||||||
$this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom')));
|
$this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom')));
|
||||||
@ -62,10 +65,6 @@ class TemplateEmail extends Mailable
|
|||||||
$this->build_email->setBody(
|
$this->build_email->setBody(
|
||||||
DesignHelpers::parseMarkdownToHtml($this->build_email->getBody())
|
DesignHelpers::parseMarkdownToHtml($this->build_email->getBody())
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->build_email->setBody(
|
|
||||||
TemplateEngine::wrapElementsIntoTables('<div id="content-wrapper"></div>', $this->build_email->getBody(), $settings)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$company = $this->client->company;
|
$company = $this->client->company;
|
||||||
|
@ -224,6 +224,13 @@ class RecurringInvoice extends BaseModel
|
|||||||
|
|
||||||
$offset = $this->client->timezone_offset();
|
$offset = $this->client->timezone_offset();
|
||||||
|
|
||||||
|
/*
|
||||||
|
As we are firing at UTC+0 if our offset is negative it is technically firing the day before so we always need
|
||||||
|
to add ON a day - a day = 86400 seconds
|
||||||
|
*/
|
||||||
|
if($offset < 0)
|
||||||
|
$offset += 86400;
|
||||||
|
|
||||||
switch ($this->frequency_id) {
|
switch ($this->frequency_id) {
|
||||||
case self::FREQUENCY_DAILY:
|
case self::FREQUENCY_DAILY:
|
||||||
return Carbon::parse($this->next_send_date)->startOfDay()->addDay()->addSeconds($offset);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addDay()->addSeconds($offset);
|
||||||
@ -428,17 +435,14 @@ class RecurringInvoice extends BaseModel
|
|||||||
'due_date' => $next_due_date_string
|
'due_date' => $next_due_date_string
|
||||||
];
|
];
|
||||||
|
|
||||||
$next_send_date = $this->nextDateByFrequency($next_send_date->format('Y-m-d'));
|
/* Fixes the timeshift in case the offset is negative which cause a infinite loop due to UTC +0*/
|
||||||
|
if($this->client->timezone_offset() < 0){
|
||||||
|
$next_send_date = $this->nextDateByFrequency($next_send_date->addDay()->format('Y-m-d'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$next_send_date = $this->nextDateByFrequency($next_send_date->format('Y-m-d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*If no due date is set - unset the due_date value */
|
|
||||||
// if(!$this->due_date_days || $this->due_date_days == 0){
|
|
||||||
|
|
||||||
// foreach($data as $key => $value)
|
|
||||||
// $data[$key]['due_date'] = '';
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
return new Item([
|
return new Item([
|
||||||
'name' => $lineItem->product_key,
|
'name' => $lineItem->product_key,
|
||||||
'description' => substr($lineItem->notes, 0, 100),
|
'description' => substr(strip_tags($lineItem->notes), 0, 100),
|
||||||
'price' => $lineItem->cost,
|
'price' => $lineItem->cost,
|
||||||
'quantity' => $lineItem->quantity,
|
'quantity' => $lineItem->quantity,
|
||||||
]);
|
]);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
namespace App\PaymentDrivers\Stripe;
|
namespace App\PaymentDrivers\Stripe;
|
||||||
|
|
||||||
use App\Exceptions\PaymentFailed;
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Http\Requests\ClientPortal\PaymentMethod\VerifyPaymentMethodRequest;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Jobs\Mail\NinjaMailerJob;
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
use App\Jobs\Mail\NinjaMailerObject;
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
@ -67,7 +68,7 @@ class ACH
|
|||||||
$client_gateway_token = $this->storePaymentMethod($source, $request->input('method'), $customer);
|
$client_gateway_token = $this->storePaymentMethod($source, $request->input('method'), $customer);
|
||||||
|
|
||||||
$mailer = new NinjaMailerObject();
|
$mailer = new NinjaMailerObject();
|
||||||
$mailer->mailable = new ACHVerificationNotification(auth('contact')->user()->client->company);
|
$mailer->mailable = new ACHVerificationNotification(auth('contact')->user()->client->company, route('client.payment_methods.verification', ['payment_method' => $client_gateway_token->hashed_id, 'method' => GatewayType::BANK_TRANSFER]));
|
||||||
$mailer->company = auth('contact')->user()->client->company;
|
$mailer->company = auth('contact')->user()->client->company;
|
||||||
$mailer->settings = auth('contact')->user()->client->company->settings;
|
$mailer->settings = auth('contact')->user()->client->company->settings;
|
||||||
$mailer->to_user = auth('contact')->user();
|
$mailer->to_user = auth('contact')->user();
|
||||||
@ -79,6 +80,12 @@ class ACH
|
|||||||
|
|
||||||
public function verificationView(ClientGatewayToken $token)
|
public function verificationView(ClientGatewayToken $token)
|
||||||
{
|
{
|
||||||
|
if (isset($token->meta->state) && $token->meta->state === 'authorized') {
|
||||||
|
return redirect()
|
||||||
|
->route('client.payment_methods.show', $token->hashed_id)
|
||||||
|
->with('message', __('texts.payment_method_verified'));
|
||||||
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'token' => $token,
|
'token' => $token,
|
||||||
'gateway' => $this->stripe,
|
'gateway' => $this->stripe,
|
||||||
@ -87,8 +94,14 @@ class ACH
|
|||||||
return render('gateways.stripe.ach.verify', $data);
|
return render('gateways.stripe.ach.verify', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processVerification(Request $request, ClientGatewayToken $token)
|
public function processVerification($request, ClientGatewayToken $token)
|
||||||
{
|
{
|
||||||
|
if (isset($token->meta->state) && $token->meta->state === 'authorized') {
|
||||||
|
return redirect()
|
||||||
|
->route('client.payment_methods.show', $token->hashed_id)
|
||||||
|
->with('message', __('texts.payment_method_verified'));
|
||||||
|
}
|
||||||
|
|
||||||
$this->stripe->init();
|
$this->stripe->init();
|
||||||
|
|
||||||
$bank_account = Customer::retrieveSource($request->customer, $request->source, $this->stripe->stripe_connect_auth);
|
$bank_account = Customer::retrieveSource($request->customer, $request->source, $this->stripe->stripe_connect_auth);
|
||||||
@ -96,12 +109,14 @@ class ACH
|
|||||||
try {
|
try {
|
||||||
$bank_account->verify(['amounts' => request()->transactions]);
|
$bank_account->verify(['amounts' => request()->transactions]);
|
||||||
|
|
||||||
$token->meta->verified_at = now();
|
$meta = $token->meta;
|
||||||
|
$meta->state = 'authorized';
|
||||||
|
$token->meta = $meta;
|
||||||
$token->save();
|
$token->save();
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('client.invoices.index')
|
->route('client.payment_methods.show', $token->hashed_id)
|
||||||
->with('success', __('texts.payment_method_verified'));
|
->with('message', __('texts.payment_method_verified'));
|
||||||
} catch (CardException $e) {
|
} catch (CardException $e) {
|
||||||
return back()->with('error', $e->getMessage());
|
return back()->with('error', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ class ACH
|
|||||||
{
|
{
|
||||||
$meta = $token->meta;
|
$meta = $token->meta;
|
||||||
$meta->state = $response->state;
|
$meta->state = $response->state;
|
||||||
$token->meta;
|
$token->meta = $meta;
|
||||||
$token->save();
|
$token->save();
|
||||||
|
|
||||||
return redirect()->route('client.payment_methods.index');
|
return redirect()->route('client.payment_methods.index');
|
||||||
@ -189,7 +189,7 @@ class ACH
|
|||||||
|
|
||||||
public function paymentResponse($request)
|
public function paymentResponse($request)
|
||||||
{
|
{
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
$token = ClientGatewayToken::find($this->decodePrimaryKey($request->input('source')));
|
$token = ClientGatewayToken::find($this->decodePrimaryKey($request->input('source')));
|
||||||
$token_meta = $token->meta;
|
$token_meta = $token->meta;
|
||||||
@ -197,14 +197,20 @@ class ACH
|
|||||||
if($token_meta->state != "authorized")
|
if($token_meta->state != "authorized")
|
||||||
return redirect()->route('client.payment_methods.verification', ['payment_method' => $token->hashed_id, 'method' => GatewayType::BANK_TRANSFER]);
|
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');
|
||||||
|
|
||||||
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
||||||
// 'callback_uri' => route('payment_webhook', ['company_key' => $this->wepay_payment_driver->company_gateway->company->company_key, 'company_gateway_id' => $this->wepay_payment_driver->company_gateway->hashed_id]),
|
// 'callback_uri' => route('payment_webhook', ['company_key' => $this->wepay_payment_driver->company_gateway->company->company_key, 'company_gateway_id' => $this->wepay_payment_driver->company_gateway->hashed_id]),
|
||||||
'unique_id' => Str::random(40),
|
'unique_id' => Str::random(40),
|
||||||
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
||||||
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
||||||
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
||||||
'short_description' => 'A vacation home rental',
|
'short_description' => 'Goods and Services',
|
||||||
'type' => 'goods',
|
'type' => 'goods',
|
||||||
|
'fee' => [
|
||||||
|
'fee_payer' => config('ninja.wepay.fee_payer'),
|
||||||
|
'app_fee' => $app_fee,
|
||||||
|
],
|
||||||
'payment_method' => array(
|
'payment_method' => array(
|
||||||
'type' => 'payment_bank',
|
'type' => 'payment_bank',
|
||||||
'payment_bank' => array(
|
'payment_bank' => array(
|
||||||
|
@ -139,16 +139,21 @@ use WePayCommon;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// USD, CAD, and GBP.
|
// USD, CAD, and GBP.
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
|
$app_fee = (config('ninja.wepay.fee_cc_multiplier') * $this->wepay_payment_driver->payment_hash->data->amount_with_fee) + config('ninja.wepay.fee_fixed');
|
||||||
// charge the credit card
|
// charge the credit card
|
||||||
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
$response = $this->wepay_payment_driver->wepay->request('checkout/create', array(
|
||||||
// 'callback_uri' => route('payment_webhook', ['company_key' => $this->wepay_payment_driver->company_gateway->company->company_key, 'company_gateway_id' => $this->wepay_payment_driver->company_gateway->hashed_id]),
|
|
||||||
'unique_id' => Str::random(40),
|
'unique_id' => Str::random(40),
|
||||||
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
||||||
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
||||||
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
||||||
'short_description' => 'A vacation home rental',
|
'short_description' => 'Goods and services',
|
||||||
'type' => 'goods',
|
'type' => 'goods',
|
||||||
|
'fee' => [
|
||||||
|
'fee_payer' => config('ninja.wepay.fee_payer'),
|
||||||
|
'app_fee' => $app_fee,
|
||||||
|
],
|
||||||
'payment_method' => array(
|
'payment_method' => array(
|
||||||
'type' => 'credit_card',
|
'type' => 'credit_card',
|
||||||
'credit_card' => array(
|
'credit_card' => array(
|
||||||
|
@ -24,8 +24,13 @@ trait WePayCommon
|
|||||||
private function processSuccessfulPayment($response, $payment_status, $gateway_type)
|
private function processSuccessfulPayment($response, $payment_status, $gateway_type)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if($gateway_type == GatewayType::BANK_TRANSFER)
|
||||||
|
$payment_type = PaymentType::ACH;
|
||||||
|
else
|
||||||
|
$payment_type = PaymentType::CREDIT_CARD_OTHER;
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
|
'payment_type' => $payment_type,
|
||||||
'amount' => $response->amount,
|
'amount' => $response->amount,
|
||||||
'transaction_reference' => $response->checkout_id,
|
'transaction_reference' => $response->checkout_id,
|
||||||
'gateway_type_id' => $gateway_type,
|
'gateway_type_id' => $gateway_type,
|
||||||
|
@ -266,18 +266,17 @@ class WePayPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$response = $this->wepay->request('checkout/refund', array(
|
$response = $this->wepay->request('checkout/refund', array(
|
||||||
'checkout_id' => $payment->transaction_reference,
|
'checkout_id' => $payment->transaction_reference,
|
||||||
'refund_reason' => 'Refund',
|
'refund_reason' => 'Refund by merchant',
|
||||||
'amount' => $amount
|
'amount' => $amount
|
||||||
));
|
));
|
||||||
|
|
||||||
|
return [
|
||||||
return [
|
'transaction_reference' => $response->checkout_id,
|
||||||
'transaction_reference' => $response->checkout_id,
|
'transaction_response' => json_encode($response),
|
||||||
'transaction_response' => json_encode($response),
|
'success' => $response->state == 'refunded' ? true : false,
|
||||||
'success' => $response->state == 'refunded' ? true : false,
|
'description' => 'refund',
|
||||||
'description' => 'refund',
|
'code' => 0,
|
||||||
'code' => 0,
|
];
|
||||||
];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
|
|
||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\GroupSetting;
|
use App\Models\GroupSetting;
|
||||||
|
|
||||||
class GroupSettingRepository extends BaseRepository
|
class GroupSettingRepository extends BaseRepository
|
||||||
{
|
{
|
||||||
public function save($data, GroupSetting $group_setting) :?GroupSetting
|
public function save($data, GroupSetting $group_setting) :?GroupSetting
|
||||||
{
|
{
|
||||||
|
|
||||||
$group_setting->fill($data);
|
$group_setting->fill($data);
|
||||||
$group_setting->save();
|
$group_setting->save();
|
||||||
|
|
||||||
@ -27,6 +29,15 @@ class GroupSettingRepository extends BaseRepository
|
|||||||
$group_setting->save();
|
$group_setting->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlog($data['settings']);
|
||||||
|
|
||||||
|
if(count((array)$data['settings']) == 0){
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->entity = Client::class;
|
||||||
|
$group_setting->settings = $settings;
|
||||||
|
$group_setting->save();
|
||||||
|
}
|
||||||
|
|
||||||
return $group_setting;
|
return $group_setting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,9 @@ class PaymentMigrationRepository extends BaseRepository
|
|||||||
$exchange_rate = new CurrencyApi();
|
$exchange_rate = new CurrencyApi();
|
||||||
|
|
||||||
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
||||||
$payment->exchange_currency_id = $client_currency;
|
// $payment->exchange_currency_id = $client_currency;
|
||||||
|
$payment->exchange_currency_id = $company_currency;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
|
@ -199,7 +199,9 @@ class PaymentRepository extends BaseRepository {
|
|||||||
$exchange_rate = new CurrencyApi();
|
$exchange_rate = new CurrencyApi();
|
||||||
|
|
||||||
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
||||||
$payment->exchange_currency_id = $client_currency;
|
// $payment->exchange_currency_id = $client_currency;
|
||||||
|
$payment->exchange_currency_id = $company_currency;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
use App\DataMapper\InvoiceItem;
|
use App\DataMapper\InvoiceItem;
|
||||||
use App\Factory\InvoiceFactory;
|
use App\Factory\InvoiceFactory;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -44,8 +45,8 @@ class SubscriptionRepository extends BaseRepository
|
|||||||
private function calculatePrice($subscription) :array
|
private function calculatePrice($subscription) :array
|
||||||
{
|
{
|
||||||
|
|
||||||
DB::beginTransaction();
|
// DB::beginTransaction();
|
||||||
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
$client = Client::factory()->create([
|
$client = Client::factory()->create([
|
||||||
@ -53,6 +54,7 @@ class SubscriptionRepository extends BaseRepository
|
|||||||
'company_id' => $subscription->company_id,
|
'company_id' => $subscription->company_id,
|
||||||
'group_settings_id' => $subscription->group_id,
|
'group_settings_id' => $subscription->group_id,
|
||||||
'country_id' => $subscription->company->settings->country_id,
|
'country_id' => $subscription->company->settings->country_id,
|
||||||
|
'settings' => ClientSettings::defaults(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$contact = ClientContact::factory()->create([
|
$contact = ClientContact::factory()->create([
|
||||||
@ -88,8 +90,9 @@ class SubscriptionRepository extends BaseRepository
|
|||||||
|
|
||||||
$data['promo_price'] = $invoice->calc()->getTotal();
|
$data['promo_price'] = $invoice->calc()->getTotal();
|
||||||
|
|
||||||
DB::rollBack();
|
// DB::rollBack();
|
||||||
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,23 +377,28 @@ class InvoiceService
|
|||||||
{
|
{
|
||||||
switch ($reminder_template) {
|
switch ($reminder_template) {
|
||||||
case 'reminder1':
|
case 'reminder1':
|
||||||
$this->invoice->reminder1_sent = now()->format('Y-m-d');
|
$this->invoice->reminder1_sent = now();
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now();
|
||||||
|
$this->invoice->last_sent_date = now();
|
||||||
break;
|
break;
|
||||||
case 'reminder2':
|
case 'reminder2':
|
||||||
$this->invoice->reminder2_sent = now()->format('Y-m-d');
|
$this->invoice->reminder2_sent = now();
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now();
|
||||||
|
$this->invoice->last_sent_date = now();
|
||||||
break;
|
break;
|
||||||
case 'reminder3':
|
case 'reminder3':
|
||||||
$this->invoice->reminder3_sent = now()->format('Y-m-d');
|
$this->invoice->reminder3_sent = now();
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now();
|
||||||
|
$this->invoice->last_sent_date = now();
|
||||||
break;
|
break;
|
||||||
case 'endless_reminder':
|
case 'endless_reminder':
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now();
|
||||||
|
$this->invoice->last_sent_date = now();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$this->invoice->reminder1_sent = now()->format('Y-m-d');
|
$this->invoice->reminder1_sent = now();
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now();
|
||||||
|
$this->invoice->last_sent_date = now();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,9 @@ class MarkPaid extends AbstractService
|
|||||||
$exchange_rate = new CurrencyApi();
|
$exchange_rate = new CurrencyApi();
|
||||||
|
|
||||||
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
||||||
$payment->exchange_currency_id = $client_currency;
|
//$payment->exchange_currency_id = $client_currency; // 23/06/2021
|
||||||
|
$payment->exchange_currency_id = $company_currency;
|
||||||
|
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Services\Invoice;
|
namespace App\Services\Invoice;
|
||||||
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
use App\Services\AbstractService;
|
use App\Services\AbstractService;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
@ -126,6 +127,14 @@ class UpdateReminder extends AbstractService
|
|||||||
$date_collection->push($reminder_date);
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->invoice->last_sent_date &&
|
||||||
|
(int)$this->settings->endless_reminder_frequency_id > 0) {
|
||||||
|
$reminder_date = $this->addTimeInterval($this->invoice->last_sent_date, (int)$this->settings->num_days_reminder3)->addSeconds($offset);
|
||||||
|
|
||||||
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
|
$date_collection->push($reminder_date);
|
||||||
|
}
|
||||||
|
|
||||||
if($date_collection->count() >=1 && $date_collection->sort()->first()->gte(now()))
|
if($date_collection->count() >=1 && $date_collection->sort()->first()->gte(now()))
|
||||||
$this->invoice->next_send_date = $date_collection->sort()->first();
|
$this->invoice->next_send_date = $date_collection->sort()->first();
|
||||||
else
|
else
|
||||||
@ -133,4 +142,41 @@ class UpdateReminder extends AbstractService
|
|||||||
|
|
||||||
return $this->invoice;
|
return $this->invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function addTimeInterval($date, $endless_reminder_frequency_id) :?Carbon
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!$date)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch ($endless_reminder_frequency_id) {
|
||||||
|
case RecurringInvoice::FREQUENCY_DAILY:
|
||||||
|
return Carbon::parse($date)->addDay()->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||||
|
return Carbon::parse($date)->addWeek()->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||||
|
return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||||
|
return Carbon::parse($date)->addWeeks(4)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||||
|
return Carbon::parse($date)->addMonthNoOverflow()->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||||
|
return Carbon::parse($date)->addMonthsNoOverflow(2)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||||
|
return Carbon::parse($date)->addMonthsNoOverflow(3)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||||
|
return Carbon::parse($date)->addMonthsNoOverflow(4)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||||
|
return Carbon::parse($date)->addMonthsNoOverflow(6)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||||
|
return Carbon::parse($date)->addYear()->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||||
|
return Carbon::parse($date)->addYears(2)->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||||
|
return Carbon::parse($date)->addYears(3)->startOfDay();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -137,10 +137,6 @@ class Design extends BaseDesign
|
|||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (['company1', 'company2', 'company3', 'company4'] as $field) {
|
|
||||||
$elements[] = ['element' => 'p', 'content' => $this->getCustomFieldValue($field), 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . $field]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +439,7 @@ class Design extends BaseDesign
|
|||||||
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']],
|
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']],
|
||||||
['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
||||||
]],
|
]],
|
||||||
['element' => 'img', 'properties' => ['hidden' => $this->client->getSetting('signature_on_pdf'), 'style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature']],
|
['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']],
|
||||||
['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [
|
['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [
|
||||||
['element' => 'img', 'properties' => ['src' => '$invoiceninja.whitelabel', 'style' => 'height: 2.5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false', 'id' => 'invoiceninja-whitelabel-logo']],
|
['element' => 'img', 'properties' => ['src' => '$invoiceninja.whitelabel', 'style' => 'height: 2.5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false', 'id' => 'invoiceninja-whitelabel-logo']],
|
||||||
]],
|
]],
|
||||||
@ -501,11 +497,11 @@ class Design extends BaseDesign
|
|||||||
} elseif (Str::startsWith($variable, '$custom_surcharge')) {
|
} elseif (Str::startsWith($variable, '$custom_surcharge')) {
|
||||||
$_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1
|
$_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1
|
||||||
|
|
||||||
$visible = $this->entity->{$_variable} == '0';
|
$visible = $this->entity->{$_variable} > 0 || $this->entity->{$_variable} > '0';
|
||||||
|
|
||||||
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [
|
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [
|
||||||
['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => $visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']],
|
['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']],
|
||||||
['element' => 'span', 'content' => $variable, 'properties' => ['hidden' => $visible, 'data-ref' => 'totals_table-' . substr($variable, 1)]],
|
['element' => 'span', 'content' => $variable, 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1)]],
|
||||||
]];
|
]];
|
||||||
} elseif (Str::startsWith($variable, '$custom')) {
|
} elseif (Str::startsWith($variable, '$custom')) {
|
||||||
$field = explode('_', $variable);
|
$field = explode('_', $variable);
|
||||||
|
@ -109,11 +109,15 @@ class HtmlEngine
|
|||||||
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.date')];
|
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.date')];
|
||||||
|
|
||||||
$data['$invoice.date'] = &$data['$date'];
|
$data['$invoice.date'] = &$data['$date'];
|
||||||
|
$data['$invoiceDate'] = &$data['$date'];
|
||||||
$data['$due_date'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
|
$data['$due_date'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
|
||||||
|
$data['$dueDate'] = &$data['$due_date'];
|
||||||
|
|
||||||
$data['$payment_due'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.payment_due')];
|
$data['$payment_due'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.payment_due')];
|
||||||
$data['$invoice.due_date'] = &$data['$due_date'];
|
$data['$invoice.due_date'] = &$data['$due_date'];
|
||||||
$data['$invoice.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
$data['$invoice.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||||
$data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: ' ', 'label' => ctrans('texts.po_number')];
|
$data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: ' ', 'label' => ctrans('texts.po_number')];
|
||||||
|
$data['$poNumber'] = &$data['$invoice.po_number'];
|
||||||
$data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->entity->client->date_format(), $this->entity->client->locale()), 'label' => ctrans('texts.date')];
|
$data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->entity->client->date_format(), $this->entity->client->locale()), 'label' => ctrans('texts.date')];
|
||||||
$data['$invoice.datetime'] = &$data['$entity.datetime'];
|
$data['$invoice.datetime'] = &$data['$entity.datetime'];
|
||||||
$data['$quote.datetime'] = &$data['$entity.datetime'];
|
$data['$quote.datetime'] = &$data['$entity.datetime'];
|
||||||
@ -125,6 +129,7 @@ class HtmlEngine
|
|||||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.invoice_terms')];
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.invoice_terms')];
|
||||||
$data['$terms'] = &$data['$entity.terms'];
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
|
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
|
||||||
|
$data['$viewLink'] = &$data['$view_link'];
|
||||||
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_invoice')];
|
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_invoice')];
|
||||||
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.invoice_date')];
|
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.invoice_date')];
|
||||||
|
|
||||||
@ -139,6 +144,7 @@ class HtmlEngine
|
|||||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.quote_terms')];
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.quote_terms')];
|
||||||
$data['$terms'] = &$data['$entity.terms'];
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.view_quote')];
|
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.view_quote')];
|
||||||
|
$data['$viewLink'] = &$data['$view_link'];
|
||||||
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
|
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
|
||||||
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.quote_date')];
|
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.quote_date')];
|
||||||
}
|
}
|
||||||
@ -149,6 +155,7 @@ class HtmlEngine
|
|||||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.credit_terms')];
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.credit_terms')];
|
||||||
$data['$terms'] = &$data['$entity.terms'];
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_credit').'</a>', 'label' => ctrans('texts.view_credit')];
|
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_credit').'</a>', 'label' => ctrans('texts.view_credit')];
|
||||||
|
$data['$viewLink'] = &$data['$view_link'];
|
||||||
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
|
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
|
||||||
// $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
|
// $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
|
||||||
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.credit_date')];
|
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: ' ', 'label' => ctrans('texts.credit_date')];
|
||||||
@ -171,11 +178,13 @@ class HtmlEngine
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['$quote.balance_due'] = $data['$balance_due'];
|
$data['$quote.balance_due'] = &$data['$balance_due'];
|
||||||
$data['$invoice.balance_due'] = $data['$balance_due'];
|
$data['$invoice.balance_due'] = &$data['$balance_due'];
|
||||||
// $data['$balance_due'] = $data['$balance_due'];
|
// $data['$balance_due'] = $data['$balance_due'];
|
||||||
$data['$outstanding'] = $data['$balance_due'];
|
$data['$outstanding'] = &$data['$balance_due'];
|
||||||
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||||
|
$data['$partial'] = &$data['$partial_due'];
|
||||||
|
|
||||||
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')];
|
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')];
|
||||||
$data['$amount'] = &$data['$total'];
|
$data['$amount'] = &$data['$total'];
|
||||||
$data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')];
|
$data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')];
|
||||||
@ -205,6 +214,7 @@ class HtmlEngine
|
|||||||
$data['$invoice.public_notes'] = ['value' => $this->entity->public_notes ?: '', 'label' => ctrans('texts.public_notes')];
|
$data['$invoice.public_notes'] = ['value' => $this->entity->public_notes ?: '', 'label' => ctrans('texts.public_notes')];
|
||||||
$data['$entity.public_notes'] = &$data['$invoice.public_notes'];
|
$data['$entity.public_notes'] = &$data['$invoice.public_notes'];
|
||||||
$data['$public_notes'] = &$data['$invoice.public_notes'];
|
$data['$public_notes'] = &$data['$invoice.public_notes'];
|
||||||
|
$data['$notes'] = &$data['$public_notes'];
|
||||||
|
|
||||||
$data['$entity_issued_to'] = ['value' => '', 'label' => ctrans("texts.{$this->entity_string}_issued_to")];
|
$data['$entity_issued_to'] = ['value' => '', 'label' => ctrans("texts.{$this->entity_string}_issued_to")];
|
||||||
$data['$your_entity'] = ['value' => '', 'label' => ctrans("texts.your_{$this->entity_string}")];
|
$data['$your_entity'] = ['value' => '', 'label' => ctrans("texts.your_{$this->entity_string}")];
|
||||||
@ -249,6 +259,8 @@ class HtmlEngine
|
|||||||
$data['$email'] = ['value' => isset($this->contact) ? $this->contact->email : 'no contact email on record', 'label' => ctrans('texts.email')];
|
$data['$email'] = ['value' => isset($this->contact) ? $this->contact->email : 'no contact email on record', 'label' => ctrans('texts.email')];
|
||||||
$data['$client_name'] = ['value' => $this->entity->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')];
|
$data['$client_name'] = ['value' => $this->entity->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')];
|
||||||
$data['$client.name'] = &$data['$client_name'];
|
$data['$client.name'] = &$data['$client_name'];
|
||||||
|
$data['$client'] = &$data['$client_name'];
|
||||||
|
|
||||||
$data['$client.address1'] = &$data['$address1'];
|
$data['$client.address1'] = &$data['$address1'];
|
||||||
$data['$client.address2'] = &$data['$address2'];
|
$data['$client.address2'] = &$data['$address2'];
|
||||||
$data['$client_address'] = ['value' => $this->client->present()->address() ?: ' ', 'label' => ctrans('texts.address')];
|
$data['$client_address'] = ['value' => $this->client->present()->address() ?: ' ', 'label' => ctrans('texts.address')];
|
||||||
@ -272,11 +284,15 @@ class HtmlEngine
|
|||||||
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];
|
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];
|
||||||
|
|
||||||
$data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')];
|
$data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')];
|
||||||
|
$data['$contact'] = &$data['$contact.full_name'];
|
||||||
|
|
||||||
$data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')];
|
$data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')];
|
||||||
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
||||||
|
|
||||||
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : $this->client->present()->name(), 'label' => ctrans('texts.contact_name')];
|
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : $this->client->present()->name(), 'label' => ctrans('texts.contact_name')];
|
||||||
$data['$contact.first_name'] = ['value' => isset($this->contact) ? $this->contact->first_name : '', 'label' => ctrans('texts.first_name')];
|
$data['$contact.first_name'] = ['value' => isset($this->contact) ? $this->contact->first_name : '', 'label' => ctrans('texts.first_name')];
|
||||||
|
$data['$firstName'] = &$data['$contact.first_name'];
|
||||||
|
|
||||||
$data['$contact.last_name'] = ['value' => isset($this->contact) ? $this->contact->last_name : '', 'label' => ctrans('texts.last_name')];
|
$data['$contact.last_name'] = ['value' => isset($this->contact) ? $this->contact->last_name : '', 'label' => ctrans('texts.last_name')];
|
||||||
|
|
||||||
|
|
||||||
@ -288,6 +304,8 @@ class HtmlEngine
|
|||||||
$data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')];
|
$data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')];
|
||||||
$data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')];
|
$data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')];
|
||||||
$data['$company.name'] = ['value' => $this->settings->name ?: ctrans('texts.untitled_account'), 'label' => ctrans('texts.company_name')];
|
$data['$company.name'] = ['value' => $this->settings->name ?: ctrans('texts.untitled_account'), 'label' => ctrans('texts.company_name')];
|
||||||
|
$data['$account'] = &$data['$company.name'];
|
||||||
|
|
||||||
$data['$company.address1'] = ['value' => $this->settings->address1 ?: ' ', 'label' => ctrans('texts.address1')];
|
$data['$company.address1'] = ['value' => $this->settings->address1 ?: ' ', 'label' => ctrans('texts.address1')];
|
||||||
$data['$company.address2'] = ['value' => $this->settings->address2 ?: ' ', 'label' => ctrans('texts.address2')];
|
$data['$company.address2'] = ['value' => $this->settings->address2 ?: ' ', 'label' => ctrans('texts.address2')];
|
||||||
$data['$company.city'] = ['value' => $this->settings->city ?: ' ', 'label' => ctrans('texts.city')];
|
$data['$company.city'] = ['value' => $this->settings->city ?: ' ', 'label' => ctrans('texts.city')];
|
||||||
@ -302,6 +320,7 @@ class HtmlEngine
|
|||||||
$data['$company.address'] = ['value' => $this->company->present()->address($this->settings) ?: ' ', 'label' => ctrans('texts.address')];
|
$data['$company.address'] = ['value' => $this->company->present()->address($this->settings) ?: ' ', 'label' => ctrans('texts.address')];
|
||||||
|
|
||||||
$data['$signature'] = ['value' => $this->settings->email_signature ?: ' ', 'label' => ''];
|
$data['$signature'] = ['value' => $this->settings->email_signature ?: ' ', 'label' => ''];
|
||||||
|
$data['$emailSignature'] = &$data['$signature'];
|
||||||
|
|
||||||
$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' => ''];
|
$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' => ''];
|
||||||
|
|
||||||
@ -393,6 +412,8 @@ class HtmlEngine
|
|||||||
$data['$page_layout'] = ['value' => property_exists($this->settings, 'page_layout') ? $this->settings->page_layout : 'Portrait', 'label' => ''];
|
$data['$page_layout'] = ['value' => property_exists($this->settings, 'page_layout') ? $this->settings->page_layout : 'Portrait', 'label' => ''];
|
||||||
|
|
||||||
$data['$tech_hero_image'] = ['value' => asset('images/pdf-designs/tech-hero-image.jpg'), 'label' => ''];
|
$data['$tech_hero_image'] = ['value' => asset('images/pdf-designs/tech-hero-image.jpg'), 'label' => ''];
|
||||||
|
$data['$autoBill'] = ['value' => ctrans('texts.auto_bill_notification_placeholder'), 'label' => ''];
|
||||||
|
$data['$auto_bill'] = &$data['$autoBill'];
|
||||||
|
|
||||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||||
|
@ -212,7 +212,7 @@ class TemplateEngine
|
|||||||
} else {
|
} else {
|
||||||
$wrapper = '';
|
$wrapper = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($email_style == 'plain') {
|
elseif ($email_style == 'plain') {
|
||||||
$wrapper = view($this->getTemplatePath($email_style), $data)->render();
|
$wrapper = view($this->getTemplatePath($email_style), $data)->render();
|
||||||
$injection = '';
|
$injection = '';
|
||||||
@ -226,7 +226,7 @@ class TemplateEngine
|
|||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'subject' => $this->subject,
|
'subject' => $this->subject,
|
||||||
'body' => $email_style == 'custom' ? $this->body : self::wrapElementsIntoTables(strtr('<div id="content-wrapper"></div>', ['$body' => '']), $this->body, $this->entity_obj->client->getMergedSettings()),
|
'body' => $this->body,
|
||||||
'wrapper' => $wrapper,
|
'wrapper' => $wrapper,
|
||||||
'raw_body' => $this->raw_body,
|
'raw_body' => $this->raw_body,
|
||||||
'raw_subject' => $this->raw_subject
|
'raw_subject' => $this->raw_subject
|
||||||
@ -239,7 +239,7 @@ class TemplateEngine
|
|||||||
|
|
||||||
private function mockEntity()
|
private function mockEntity()
|
||||||
{
|
{
|
||||||
DB::beginTransaction();
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
|
|
||||||
$client = Client::factory()->create([
|
$client = Client::factory()->create([
|
||||||
'user_id' => auth()->user()->id,
|
'user_id' => auth()->user()->id,
|
||||||
@ -277,52 +277,6 @@ class TemplateEngine
|
|||||||
|
|
||||||
private function tearDown()
|
private function tearDown()
|
||||||
{
|
{
|
||||||
DB::rollBack();
|
DB::connection(config('database.default'))->rollBack();
|
||||||
}
|
|
||||||
|
|
||||||
public static function wrapElementsIntoTables(string $wrapper, string $body, $settings): ?string
|
|
||||||
{
|
|
||||||
$documents['wrapper'] = new \DOMDocument();
|
|
||||||
@$documents['wrapper']->loadHTML($wrapper);
|
|
||||||
|
|
||||||
$documents['master'] = new \DOMDocument();
|
|
||||||
|
|
||||||
$documents['master']->loadHTML(
|
|
||||||
view('email.template.master', ['header' => '', 'slot' => '', 'settings' => $settings])->render()
|
|
||||||
);
|
|
||||||
|
|
||||||
$styles = $documents['master']->getElementsByTagName('style')->item(0)->nodeValue;
|
|
||||||
|
|
||||||
$documents['wrapper']->saveHTML();
|
|
||||||
|
|
||||||
$documents['body'] = new \DOMDocument();
|
|
||||||
$documents['body']->loadHTML(empty($body) ? '<div></div>' : mb_convert_encoding((new CssToInlineStyles())->convert($body, $styles), 'HTML-ENTITIES', 'UTF-8'));
|
|
||||||
|
|
||||||
$table_html ='
|
|
||||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td style="overflow-wrap:break-word;word-break:break-word;padding:5px;font-family:arial,helvetica,sans-serif;" align="left">
|
|
||||||
<div style="color: #000000; line-height: 140%; text-align: left; word-wrap: break-word;" id="table-content" class="content-contrast-color"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>';
|
|
||||||
|
|
||||||
foreach ($documents['body']->getElementsByTagName('body')->item(0)->childNodes as $element) {
|
|
||||||
$table = new \DOMDocument();
|
|
||||||
|
|
||||||
$table->loadHTML($table_html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
|
|
||||||
|
|
||||||
$element = $table->importNode($element, true);
|
|
||||||
|
|
||||||
$table->getElementById('table-content')->appendChild($element);
|
|
||||||
|
|
||||||
$node = $documents['wrapper']->importNode($table->documentElement, true);
|
|
||||||
|
|
||||||
$documents['wrapper']->getElementById('content-wrapper')->appendChild($node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $documents['wrapper']->getElementById('content-wrapper')->ownerDocument->saveHTML($documents['wrapper']->getElementById('content-wrapper'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,13 +568,21 @@ trait GeneratesCounter
|
|||||||
$search[] = '{$client_counter}';
|
$search[] = '{$client_counter}';
|
||||||
$replace[] = $counter;
|
$replace[] = $counter;
|
||||||
|
|
||||||
|
$search[] = '{$clientCounter}';
|
||||||
|
$replace[] = $counter;
|
||||||
|
|
||||||
$search[] = '{$group_counter}';
|
$search[] = '{$group_counter}';
|
||||||
$replace[] = $counter;
|
$replace[] = $counter;
|
||||||
|
|
||||||
if (strstr($pattern, '{$user_id}')) {
|
$search[] = '{$year}';
|
||||||
|
$replace[] = date('Y');
|
||||||
|
|
||||||
|
if (strstr($pattern, '{$user_id}') || strstr($pattern, '{$userId}')) {
|
||||||
$user_id = $entity->user_id ? $entity->user_id : 0;
|
$user_id = $entity->user_id ? $entity->user_id : 0;
|
||||||
$search[] = '{$user_id}';
|
$search[] = '{$user_id}';
|
||||||
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
|
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
|
||||||
|
$search[] = '{$userId}';
|
||||||
|
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
$matches = false;
|
$matches = false;
|
||||||
@ -624,9 +632,15 @@ trait GeneratesCounter
|
|||||||
$search[] = '{$client_custom1}';
|
$search[] = '{$client_custom1}';
|
||||||
$replace[] = $client->custom_value1;
|
$replace[] = $client->custom_value1;
|
||||||
|
|
||||||
|
$search[] = '{$clientCustom1}';
|
||||||
|
$replace[] = $client->custom_value1;
|
||||||
|
|
||||||
$search[] = '{$client_custom2}';
|
$search[] = '{$client_custom2}';
|
||||||
$replace[] = $client->custom_value2;
|
$replace[] = $client->custom_value2;
|
||||||
|
|
||||||
|
$search[] = '{$clientCustom2}';
|
||||||
|
$replace[] = $client->custom_value2;
|
||||||
|
|
||||||
$search[] = '{$client_custom3}';
|
$search[] = '{$client_custom3}';
|
||||||
$replace[] = $client->custom_value3;
|
$replace[] = $client->custom_value3;
|
||||||
|
|
||||||
@ -638,6 +652,9 @@ trait GeneratesCounter
|
|||||||
|
|
||||||
$search[] = '{$client_id_number}';
|
$search[] = '{$client_id_number}';
|
||||||
$replace[] = $client->id_number;
|
$replace[] = $client->id_number;
|
||||||
|
|
||||||
|
$search[] = '{$clientIdNumber}';
|
||||||
|
$replace[] = $client->id_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str_replace($search, $replace, $pattern);
|
return str_replace($search, $replace, $pattern);
|
||||||
|
@ -474,7 +474,7 @@ trait MakesInvoiceValues
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($matches->keys()->first() == ':MONTH') {
|
if ($matches->keys()->first() == ':MONTH') {
|
||||||
$output = \Carbon\Carbon::create()->month($output)->localeMonth;
|
$output = \Carbon\Carbon::create()->month($output)->translatedFormat('F');
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = preg_replace(
|
$value = preg_replace(
|
||||||
|
@ -152,6 +152,10 @@ return [
|
|||||||
'environment' => env('WEPAY_ENVIRONMENT', 'stage'),
|
'environment' => env('WEPAY_ENVIRONMENT', 'stage'),
|
||||||
'client_id' => env('WEPAY_CLIENT_ID', ''),
|
'client_id' => env('WEPAY_CLIENT_ID', ''),
|
||||||
'client_secret' => env('WEPAY_CLIENT_SECRET',''),
|
'client_secret' => env('WEPAY_CLIENT_SECRET',''),
|
||||||
|
'fee_payer' => env('WEPAY_FEE_PAYER'),
|
||||||
|
'fee_cc_multiplier' => env('WEPAY_APP_FEE_CC_MULTIPLIER'),
|
||||||
|
'fee_ach_multiplier' => env('WEPAY_APP_FEE_ACH_MULTIPLIER'),
|
||||||
|
'fee_fixed' => env('WEPAY_APP_FEE_FIXED'),
|
||||||
],
|
],
|
||||||
'ninja_stripe_publishable_key' => env('NINJA_PUBLISHABLE_KEY', null),
|
'ninja_stripe_publishable_key' => env('NINJA_PUBLISHABLE_KEY', null),
|
||||||
'ninja_stripe_client_id' => env('NINJA_STRIPE_CLIENT_ID', null),
|
'ninja_stripe_client_id' => env('NINJA_STRIPE_CLIENT_ID', null),
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class PaymentsTableCurrencyNullable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('payments', function (Blueprint $table){
|
||||||
|
|
||||||
|
$table->unsignedInteger('exchange_currency_id')->nullable()->change();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
2
public/flutter_service_worker.js
vendored
2
public/flutter_service_worker.js
vendored
@ -31,7 +31,7 @@ const RESOURCES = {
|
|||||||
"assets/NOTICES": "687b68d41e137cfbdee105c0b9be3e9d",
|
"assets/NOTICES": "687b68d41e137cfbdee105c0b9be3e9d",
|
||||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||||
"main.dart.js": "1225d7da63eaf3817e25a8b6726635cc",
|
"main.dart.js": "383f48eff49849cbbe38e2fe4ae81ad4",
|
||||||
"/": "23224b5e03519aaa87594403d54412cf"
|
"/": "23224b5e03519aaa87594403d54412cf"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
112046
public/main.dart.js
vendored
112046
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
106878
public/main.foss.dart.js
vendored
106878
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
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5",
|
"/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5",
|
||||||
"/css/app.css": "/css/app.css?id=b3b5fbe4dbfcef5b5f8e",
|
"/css/app.css": "/css/app.css?id=d9b987796d537e68bee7",
|
||||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
|
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
|
||||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
||||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
|
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
|
||||||
|
@ -4268,6 +4268,10 @@ $LANG = array(
|
|||||||
'company_import_failure_body' => 'There was an error importing the company data, the error message was:',
|
'company_import_failure_body' => 'There was an error importing the company data, the error message was:',
|
||||||
'recurring_invoice_due_date' => 'Due Date',
|
'recurring_invoice_due_date' => 'Due Date',
|
||||||
'amount_cents' => 'Amount in pennies,pence or cents',
|
'amount_cents' => 'Amount in pennies,pence or cents',
|
||||||
|
'default_payment_method_label' => 'Default Payment Method',
|
||||||
|
'default_payment_method' => 'Make this your preferred way of paying.',
|
||||||
|
'already_default_payment_method' => 'This is your preferred way of paying.',
|
||||||
|
'auto_bill_disabled' => 'Auto Bill Disabled',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -236,7 +236,7 @@ $LANG = array(
|
|||||||
'archived_vendors' => 'Successfully archived :count vendors',
|
'archived_vendors' => 'Successfully archived :count vendors',
|
||||||
'deleted_vendor' => 'Successfully deleted vendor',
|
'deleted_vendor' => 'Successfully deleted vendor',
|
||||||
'deleted_vendors' => 'Successfully deleted :count vendors',
|
'deleted_vendors' => 'Successfully deleted :count vendors',
|
||||||
'confirmation_subject' => 'Invoice Ninja Account Confirmation',
|
'confirmation_subject' => 'Account Confirmation',
|
||||||
'confirmation_header' => 'Account Confirmation',
|
'confirmation_header' => 'Account Confirmation',
|
||||||
'confirmation_message' => 'Please access the link below to confirm your account.',
|
'confirmation_message' => 'Please access the link below to confirm your account.',
|
||||||
'invoice_subject' => 'New invoice :number from :account',
|
'invoice_subject' => 'New invoice :number from :account',
|
||||||
@ -887,7 +887,7 @@ $LANG = array(
|
|||||||
'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.',
|
'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.',
|
||||||
'token_expired' => 'Validation token was expired. Please try again.',
|
'token_expired' => 'Validation token was expired. Please try again.',
|
||||||
'invoice_link' => 'Invoice Link',
|
'invoice_link' => 'Invoice Link',
|
||||||
'button_confirmation_message' => 'Click to confirm your email address.',
|
'button_confirmation_message' => 'Click to confirm your email.',
|
||||||
'confirm' => 'Confirm',
|
'confirm' => 'Confirm',
|
||||||
'email_preferences' => 'Email Preferences',
|
'email_preferences' => 'Email Preferences',
|
||||||
'created_invoices' => 'Successfully created :count invoice(s)',
|
'created_invoices' => 'Successfully created :count invoice(s)',
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
@endisset
|
@endisset
|
||||||
|
|
||||||
@isset($signature)
|
@isset($signature)
|
||||||
{!! $signature !!}
|
{!! nl2br($signature) !!}
|
||||||
@endisset
|
@endisset
|
||||||
</div>
|
</div>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
@ -2,5 +2,7 @@
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>{{ ctrans('texts.ach_verification_notification_label') }}</h1>
|
<h1>{{ ctrans('texts.ach_verification_notification_label') }}</h1>
|
||||||
<p>{{ ctrans('texts.ach_verification_notification') }}</p>
|
<p>{{ ctrans('texts.ach_verification_notification') }}</p>
|
||||||
|
|
||||||
|
<a class="button" href="{{ $url }}">{{ ctrans('texts.complete_verification') }}</a>
|
||||||
</div>
|
</div>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
<p><b>{{ ctrans('texts.documents') }}:</b> {{ count($company->documents) }} </p>
|
<p><b>{{ ctrans('texts.documents') }}:</b> {{ count($company->documents) }} </p>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($check_data)
|
@if(isset($check_data))
|
||||||
<p><b>Data Quality:</b></p>
|
<p><b>Data Quality:</b></p>
|
||||||
<p> {!! $check_data !!} </p>
|
<p> {!! $check_data !!} </p>
|
||||||
@endif
|
@endif
|
||||||
|
@ -90,6 +90,10 @@
|
|||||||
#content .center {
|
#content .center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#content .left {
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -116,15 +120,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div style="border: 1px solid #c2c2c2; border-top: none; border-bottom: none; padding: 20px;" id="content">
|
<div style="border: 1px solid #c2c2c2; border-top: none; border-bottom: none; padding: 20px; text-align: center" id="content">
|
||||||
<div style="padding-top: 10px;"></div>
|
<div style="padding-top: 10px;"></div>
|
||||||
|
|
||||||
{{ $slot ?? '' }}
|
{{ $slot ?? '' }}
|
||||||
{!! $body ?? '' !!}
|
{!! $body ?? '' !!}
|
||||||
|
|
||||||
@isset($signature)
|
|
||||||
{{ nl2br($signature) }}
|
|
||||||
@endisset
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="#"
|
<a href="#"
|
||||||
@ -135,24 +135,27 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@if(isset($company) && $company instanceof \App\Models\Company)
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div class="dark-bg dark-text-white"
|
<div class="dark-bg dark-text-white"
|
||||||
style="text-align: center; padding-top: 10px; padding-bottom: 25px; background-color: #f9f9f9; border: 1px solid #c2c2c2; border-top: none; border-bottom-color: #f9f9f9;">
|
style="text-align: center; padding-top: 10px; padding-bottom: 25px; background-color: #f9f9f9; border: 1px solid #c2c2c2; border-top: none; border-bottom-color: #f9f9f9;">
|
||||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-bottom: 30px;">
|
@isset($signature)
|
||||||
{{ ctrans('texts.client_email_company_contact_label') }}
|
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-bottom: 30px;">
|
||||||
</p>
|
{!! nl2br($signature) !!}
|
||||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 500; margin-bottom:0;">
|
</p>
|
||||||
{{ $company->present()->name() }}</p>
|
@endisset
|
||||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-top: 5px;">
|
|
||||||
<span>{{ $company->settings->phone }}</span>
|
@if(isset($company) && $company instanceof \App\Models\Company)
|
||||||
<span style="font-weight: 500"> {{ $company->settings->website }}</span>
|
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 500; margin-bottom:0;">
|
||||||
</p>
|
{{ $company->present()->name() }}</p>
|
||||||
|
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-top: 5px;">
|
||||||
|
<span>{{ $company->settings->phone }}</span>
|
||||||
|
<span style="font-weight: 500"> {{ $company->settings->website }}</span>
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endif
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#company-details > span:first-child {
|
#company-details > p:first-child {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div class="grid grid-cols-12">
|
<div class="grid grid-cols-12">
|
||||||
<div class="col-span-12 lg:col-span-6 bg-gray-50 flex flex-col items-center">
|
<div class="col-span-12 lg:col-span-6 bg-gray-50 flex flex-col items-center">
|
||||||
<div class="w-full p-10 lg:w-1/2 lg:mt-24 lg:p-0">
|
<div class="w-full p-10 lg:mt-24 md:max-w-3xl">
|
||||||
<img class="h-8" src="{{ $subscription->company->present()->logo }}"
|
<img class="h-8" src="{{ $subscription->company->present()->logo }}"
|
||||||
alt="{{ $subscription->company->present()->name }}">
|
alt="{{ $subscription->company->present()->name }}">
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
<label class="flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" class="form-checkbox mr-2"
|
||||||
|
wire:change="updateAutoBilling" {{ $invoice->auto_bill_enabled ? 'checked' : '' }}>
|
||||||
|
|
||||||
|
<span class="text-sm leading-5 font-medium text-gray-900">
|
||||||
|
{{ $invoice->auto_bill_enabled ? ctrans('texts.auto_bill_enabled') : ctrans('texts.auto_bill_disabled') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
@ -0,0 +1,25 @@
|
|||||||
|
<div class="mt-4 mb-4 bg-white shadow sm:rounded-lg">
|
||||||
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium leading-6 text-gray-900">
|
||||||
|
{{ ctrans('texts.default_payment_method_label') }}
|
||||||
|
</h3>
|
||||||
|
<div class="max-w-xl mt-2 text-sm leading-5 text-gray-500 flex items-center">
|
||||||
|
<span class="text-primary mr-1 hidden" data-ref="success-label">{{ ctrans('texts.success') }}!</span>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ $token->is_default ? ctrans('texts.already_default_payment_method') : ctrans('texts.default_payment_method') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||||
|
<form wire:submit.prevent="makeDefault">
|
||||||
|
<button class="button button-primary bg-primary" {{ $token->is_default ? 'disabled' : '' }}>
|
||||||
|
{{ ctrans('texts.save_as_default') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -15,61 +15,61 @@
|
|||||||
<div>
|
<div>
|
||||||
<dl>
|
<dl>
|
||||||
@if(!empty($payment_method->gateway_type->name) && !is_null($payment_method->gateway_type->name))
|
@if(!empty($payment_method->gateway_type->name) && !is_null($payment_method->gateway_type->name))
|
||||||
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.payment_type') }}
|
{{ ctrans('texts.payment_type') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
{{ ucfirst($payment_method->gateway_type->name) }}
|
{{ ucfirst($payment_method->gateway_type->name) }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(!empty($payment_method->meta) && !is_null($payment_method->meta))
|
@if(!empty($payment_method->meta) && !is_null($payment_method->meta))
|
||||||
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.type') }}
|
{{ ctrans('texts.type') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
{{ optional($payment_method->meta)->brand }}
|
{{ optional($payment_method->meta)->brand }}
|
||||||
{{ optional($payment_method->meta)->scheme }}
|
{{ optional($payment_method->meta)->scheme }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(!empty($payment_method->meta->last4) && !is_null($payment_method->meta->last4))
|
@if(!empty($payment_method->meta->last4) && !is_null($payment_method->meta->last4))
|
||||||
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.card_number') }}
|
{{ ctrans('texts.card_number') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
**** {{ ucfirst($payment_method->meta->last4) }}
|
**** {{ ucfirst($payment_method->meta->last4) }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(!empty($payment_method->created_at) && !is_null($payment_method->created_at))
|
@if(!empty($payment_method->created_at) && !is_null($payment_method->created_at))
|
||||||
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.date_created') }}
|
{{ ctrans('texts.date_created') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
{{ $payment_method->formatDateTimestamp($payment_method->created_at, auth()->user()->client->date_format()) }}
|
{{ $payment_method->formatDateTimestamp($payment_method->created_at, auth()->user()->client->date_format()) }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(!empty($payment_method->is_default) && !is_null($payment_method->is_default))
|
@if(!empty($payment_method->is_default) && !is_null($payment_method->is_default))
|
||||||
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.default') }}
|
{{ ctrans('texts.default') }}
|
||||||
</dt>
|
</dt>
|
||||||
<div class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<div class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
{{ $payment_method->is_default ? ctrans('texts.yes') : ctrans('texts.no') }}
|
{{ $payment_method->is_default ? ctrans('texts.yes') : ctrans('texts.no') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@isset($payment_method->meta->exp_month)
|
@isset($payment_method->meta->exp_month)
|
||||||
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
@ -83,7 +83,10 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 mb-4 bg-white shadow sm:rounded-lg" translate>
|
|
||||||
|
@livewire('payment-methods.update-default-method', ['token' => $payment_method, 'client' => $client])
|
||||||
|
|
||||||
|
<div class="mt-4 mb-4 bg-white shadow sm:rounded-lg">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<div class="sm:flex sm:items-start sm:justify-between">
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
<div>
|
<div>
|
||||||
@ -109,3 +112,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@section('footer')
|
||||||
|
<script>
|
||||||
|
Livewire.on('UpdateDefaultMethod::method-updated', event => {
|
||||||
|
document.querySelector('span[data-ref=success-label]').classList.remove('hidden');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
|
@ -59,6 +59,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if($invoice->auto_bill === 'optin' || $invoice->auto_bill === 'optout')
|
||||||
|
<div class="bg-white shadow overflow-hidden lg:rounded-lg mt-4">
|
||||||
|
<div class="flex flex-col md:flex-row items-start justify-between px-4 py-5 sm:p-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">Auto Bill</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">Change your update bill preferences.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex mt-4 space-x-2">
|
||||||
|
@livewire('recurring-invoices.update-auto-billing', ['invoice' => $invoice])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if(is_null($invoice->subscription_id) || optional($invoice->subscription)->allow_cancellation)
|
@if(is_null($invoice->subscription_id) || optional($invoice->subscription)->allow_cancellation)
|
||||||
<div class="bg-white shadow sm:rounded-lg mt-4">
|
<div class="bg-white shadow sm:rounded-lg mt-4">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
Loading…
Reference in New Issue
Block a user