mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-16 08:02:40 +01:00
commit
694a704d89
@ -1 +1 @@
|
||||
5.2.6
|
||||
5.2.7
|
@ -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)
|
||||
{
|
||||
$db2->subdomain = $company->subdomain;
|
||||
$db2->save();
|
||||
}
|
||||
// if($db2)
|
||||
// {
|
||||
// $db2->subdomain = $company->subdomain;
|
||||
// $db2->save();
|
||||
// }
|
||||
|
||||
});
|
||||
// });
|
||||
|
||||
|
||||
$db1 = null;
|
||||
$db2 = null;
|
||||
// $db1 = 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)
|
||||
{
|
||||
$db1->subdomain = $company->subdomain;
|
||||
$db1->save();
|
||||
}
|
||||
});
|
||||
// if($db1)
|
||||
// {
|
||||
// $db1->subdomain = $company->subdomain;
|
||||
// $db1->save();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class CompanySettings extends BaseSettings
|
||||
public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented
|
||||
|
||||
public $enable_client_portal_tasks = false; //@ben to implement
|
||||
public $show_all_tasks_client_portal = 'all'; // all, uninvoiced, invoiced
|
||||
public $show_all_tasks_client_portal = 'invoiced'; // all, uninvoiced, invoiced
|
||||
public $enable_client_portal_password = false; //@implemented
|
||||
public $enable_client_portal = true; //@implemented
|
||||
public $enable_client_portal_dashboard = false; // @TODO There currently is no dashboard so this is pending
|
||||
@ -398,7 +398,6 @@ class CompanySettings extends BaseSettings
|
||||
'email_template_reminder2' => 'string',
|
||||
'email_template_reminder3' => 'string',
|
||||
'email_template_reminder_endless' => 'string',
|
||||
'enable_client_portal_password' => 'bool',
|
||||
'inclusive_taxes' => 'bool',
|
||||
'invoice_number_pattern' => 'string',
|
||||
'invoice_number_counter' => 'integer',
|
||||
|
@ -77,7 +77,7 @@ class Handler extends ExceptionHandler
|
||||
return;
|
||||
}
|
||||
|
||||
if(Ninja::isHosted()){
|
||||
if(Ninja::isHosted() && !($exception instanceof ValidationException)){
|
||||
|
||||
app('sentry')->configureScope(function (Scope $scope): void {
|
||||
|
||||
|
@ -46,8 +46,6 @@ class GmailTransport extends Transport
|
||||
$this->gmail = null;
|
||||
$this->gmail = new Mail;
|
||||
|
||||
nlog($message->getBcc());
|
||||
|
||||
/*We should nest the token in the message and then discard it as needed*/
|
||||
$token = $message->getHeaders()->get('GmailToken')->getValue();
|
||||
|
||||
@ -62,13 +60,13 @@ class GmailTransport extends Transport
|
||||
$this->gmail->message($message->getBody());
|
||||
|
||||
$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)
|
||||
{
|
||||
|
||||
nlog("trying to attach");
|
||||
|
||||
if($child->getContentType() != 'text/plain')
|
||||
{
|
||||
|
||||
|
@ -201,6 +201,14 @@ class LoginController extends BaseController
|
||||
->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);
|
||||
|
||||
$this->setLoginCache($user);
|
||||
|
@ -21,8 +21,6 @@ class PaymentWebhookController extends Controller
|
||||
public function __invoke(PaymentWebhookRequest $request, string $company_key, string $company_gateway_id)
|
||||
{
|
||||
|
||||
// MultiDB::findAndSetDbByCompanyKey($company_key);
|
||||
|
||||
$payment = $request->getPayment();
|
||||
|
||||
if(!$payment)
|
||||
@ -33,7 +31,6 @@ class PaymentWebhookController extends Controller
|
||||
if(!$client)
|
||||
return response()->json(['message' => 'Client record not found.'], 400);
|
||||
|
||||
|
||||
return $request->getCompanyGateway()
|
||||
->driver($client)
|
||||
->processWebhookRequest($request, $payment);
|
||||
|
@ -155,7 +155,7 @@ class PreviewController extends BaseController
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
||||
|
||||
DB::beginTransaction();
|
||||
DB::connection(config('database.default'))->beginTransaction();
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => auth()->user()->id,
|
||||
@ -230,7 +230,7 @@ class PreviewController extends BaseController
|
||||
|
||||
$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->header('Content-Type', 'application/pdf');
|
||||
|
@ -11,11 +11,17 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
use App\Models\User;
|
||||
use App\Transformers\UserTransformer;
|
||||
use Crypt;
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
|
||||
class TwoFactorController extends BaseController
|
||||
{
|
||||
protected $entity_type = User::class;
|
||||
|
||||
protected $entity_transformer = UserTransformer::class;
|
||||
|
||||
public function setupTwoFactor()
|
||||
{
|
||||
$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')) {
|
||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNotNull('next_send_date')
|
||||
->whereNull('deleted_at')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->with('company')
|
||||
@ -66,6 +67,7 @@ class RecurringInvoicesCron
|
||||
|
||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNotNull('next_send_date')
|
||||
->whereNull('deleted_at')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->with('company')
|
||||
@ -74,7 +76,7 @@ class RecurringInvoicesCron
|
||||
nlog(now()->format('Y-m-d') . ' Sending Recurring Invoices. Count = '.$recurring_invoices->count().' On Database # '.$db);
|
||||
|
||||
$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) {
|
||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||
|
@ -136,6 +136,11 @@ class CreateEntityPdf implements ShouldQueue
|
||||
$entity_design_id = 2;
|
||||
|
||||
$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);
|
||||
|
||||
if ($design->is_custom) {
|
||||
|
@ -101,7 +101,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
//send email
|
||||
try {
|
||||
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||
|
||||
nlog("Using mailer => ". $this->mailer);
|
||||
|
||||
Mail::mailer($this->mailer)
|
||||
->to($this->nmo->to_user->email)
|
||||
->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*/
|
||||
App::forgetInstance('translator');
|
||||
// App::forgetInstance('mail.manager'); //singletons must be destroyed!
|
||||
// App::forgetInstance('mailer');
|
||||
// App::forgetInstance('laravelgmail');
|
||||
$t = app('translator');
|
||||
/* Inject custom translations if any exist */
|
||||
$t->replace(Ninja::transformTranslations($this->nmo->settings));
|
||||
|
||||
switch ($this->nmo->settings->email_sending_method) {
|
||||
@ -165,7 +162,6 @@ class NinjaMailerJob implements ShouldQueue
|
||||
break;
|
||||
}
|
||||
|
||||
(new MailServiceProvider(app()))->register();
|
||||
}
|
||||
|
||||
private function setGmailMailer()
|
||||
@ -182,7 +178,14 @@ class NinjaMailerJob implements ShouldQueue
|
||||
$google = (new Google())->init();
|
||||
|
||||
try{
|
||||
|
||||
if ($google->getClient()->isAccessTokenExpired()) {
|
||||
$google->refreshToken($user);
|
||||
$user = $user->fresh();
|
||||
}
|
||||
|
||||
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
||||
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||
@ -190,9 +193,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
return $this->setMailDriver();
|
||||
}
|
||||
|
||||
if ($google->getClient()->isAccessTokenExpired()) {
|
||||
$google->refreshToken($user);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Now that our token is refreshed and valid we can boot the
|
||||
|
@ -55,10 +55,15 @@ class CompanySizeCheck implements ShouldQueue
|
||||
private function check()
|
||||
{
|
||||
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->save();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -337,6 +337,10 @@ class Import implements ShouldQueue
|
||||
|
||||
if(!MultiDB::checkDomainAvailable($data['subdomain']))
|
||||
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||
|
||||
if(strlen($data['subdomain']) == 0)
|
||||
$data['subdomain'] = MultiDB::randomSubdomainGenerator();
|
||||
|
||||
}
|
||||
|
||||
$rules = (new UpdateCompanyRequest())->rules();
|
||||
|
@ -56,6 +56,7 @@ class ReminderJob implements ShouldQueue
|
||||
nlog("Sending invoice reminders " . now()->format('Y-m-d h:i:s'));
|
||||
|
||||
Invoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNull('deleted_at')
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
|
@ -25,14 +25,21 @@ class ACHVerificationNotification extends Mailable
|
||||
*/
|
||||
public $company;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $url;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Company $company)
|
||||
public function __construct(Company $company, string $url)
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +36,7 @@ class MigrationCompleted extends Mailable
|
||||
$data['settings'] = $this->company->settings;
|
||||
$data['company'] = $this->company->fresh();
|
||||
$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();
|
||||
|
||||
$result = $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||
|
@ -49,8 +49,11 @@ class TemplateEmail extends Mailable
|
||||
|
||||
public function build()
|
||||
{
|
||||
// $template_name = 'email.template.'.$this->build_email->getTemplate();
|
||||
$template_name = 'email.template.client';
|
||||
$template_name = 'email.template.'.$this->build_email->getTemplate();
|
||||
|
||||
if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') {
|
||||
$template_name = 'email.template.client';
|
||||
}
|
||||
|
||||
if($this->build_email->getTemplate() == '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(
|
||||
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;
|
||||
|
@ -224,6 +224,13 @@ class RecurringInvoice extends BaseModel
|
||||
|
||||
$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) {
|
||||
case self::FREQUENCY_DAILY:
|
||||
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
|
||||
];
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
|
||||
|
||||
return new Item([
|
||||
'name' => $lineItem->product_key,
|
||||
'description' => substr($lineItem->notes, 0, 100),
|
||||
'description' => substr(strip_tags($lineItem->notes), 0, 100),
|
||||
'price' => $lineItem->cost,
|
||||
'quantity' => $lineItem->quantity,
|
||||
]);
|
||||
|
@ -13,6 +13,7 @@
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\PaymentMethod\VerifyPaymentMethodRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
@ -67,7 +68,7 @@ class ACH
|
||||
$client_gateway_token = $this->storePaymentMethod($source, $request->input('method'), $customer);
|
||||
|
||||
$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->settings = auth('contact')->user()->client->company->settings;
|
||||
$mailer->to_user = auth('contact')->user();
|
||||
@ -79,6 +80,12 @@ class ACH
|
||||
|
||||
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 = [
|
||||
'token' => $token,
|
||||
'gateway' => $this->stripe,
|
||||
@ -87,8 +94,14 @@ class ACH
|
||||
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();
|
||||
|
||||
$bank_account = Customer::retrieveSource($request->customer, $request->source, $this->stripe->stripe_connect_auth);
|
||||
@ -96,12 +109,14 @@ class ACH
|
||||
try {
|
||||
$bank_account->verify(['amounts' => request()->transactions]);
|
||||
|
||||
$token->meta->verified_at = now();
|
||||
$meta = $token->meta;
|
||||
$meta->state = 'authorized';
|
||||
$token->meta = $meta;
|
||||
$token->save();
|
||||
|
||||
return redirect()
|
||||
->route('client.invoices.index')
|
||||
->with('success', __('texts.payment_method_verified'));
|
||||
->route('client.payment_methods.show', $token->hashed_id)
|
||||
->with('message', __('texts.payment_method_verified'));
|
||||
} catch (CardException $e) {
|
||||
return back()->with('error', $e->getMessage());
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ class ACH
|
||||
{
|
||||
$meta = $token->meta;
|
||||
$meta->state = $response->state;
|
||||
$token->meta;
|
||||
$token->meta = $meta;
|
||||
$token->save();
|
||||
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
@ -189,7 +189,7 @@ class ACH
|
||||
|
||||
public function paymentResponse($request)
|
||||
{
|
||||
nlog($request->all());
|
||||
// nlog($request->all());
|
||||
|
||||
$token = ClientGatewayToken::find($this->decodePrimaryKey($request->input('source')));
|
||||
$token_meta = $token->meta;
|
||||
@ -197,14 +197,20 @@ class ACH
|
||||
if($token_meta->state != "authorized")
|
||||
return redirect()->route('client.payment_methods.verification', ['payment_method' => $token->hashed_id, 'method' => GatewayType::BANK_TRANSFER]);
|
||||
|
||||
$app_fee = (config('ninja.wepay.fee_ach_multiplier') * $this->wepay_payment_driver->payment_hash->data->amount_with_fee) + config('ninja.wepay.fee_fixed');
|
||||
|
||||
$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),
|
||||
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
||||
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
||||
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
||||
'short_description' => 'A vacation home rental',
|
||||
'short_description' => 'Goods and Services',
|
||||
'type' => 'goods',
|
||||
'fee' => [
|
||||
'fee_payer' => config('ninja.wepay.fee_payer'),
|
||||
'app_fee' => $app_fee,
|
||||
],
|
||||
'payment_method' => array(
|
||||
'type' => 'payment_bank',
|
||||
'payment_bank' => array(
|
||||
|
@ -139,16 +139,21 @@ use WePayCommon;
|
||||
}
|
||||
|
||||
// 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
|
||||
$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),
|
||||
'account_id' => $this->wepay_payment_driver->company_gateway->getConfigField('accountId'),
|
||||
'amount' => $this->wepay_payment_driver->payment_hash->data->amount_with_fee,
|
||||
'currency' => $this->wepay_payment_driver->client->getCurrencyCode(),
|
||||
'short_description' => 'A vacation home rental',
|
||||
'short_description' => 'Goods and services',
|
||||
'type' => 'goods',
|
||||
'fee' => [
|
||||
'fee_payer' => config('ninja.wepay.fee_payer'),
|
||||
'app_fee' => $app_fee,
|
||||
],
|
||||
'payment_method' => array(
|
||||
'type' => 'credit_card',
|
||||
'credit_card' => array(
|
||||
|
@ -24,8 +24,13 @@ trait WePayCommon
|
||||
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 = [
|
||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'payment_type' => $payment_type,
|
||||
'amount' => $response->amount,
|
||||
'transaction_reference' => $response->checkout_id,
|
||||
'gateway_type_id' => $gateway_type,
|
||||
|
@ -266,18 +266,17 @@ class WePayPaymentDriver extends BaseDriver
|
||||
|
||||
$response = $this->wepay->request('checkout/refund', array(
|
||||
'checkout_id' => $payment->transaction_reference,
|
||||
'refund_reason' => 'Refund',
|
||||
'refund_reason' => 'Refund by merchant',
|
||||
'amount' => $amount
|
||||
));
|
||||
|
||||
|
||||
return [
|
||||
'transaction_reference' => $response->checkout_id,
|
||||
'transaction_response' => json_encode($response),
|
||||
'success' => $response->state == 'refunded' ? true : false,
|
||||
'description' => 'refund',
|
||||
'code' => 0,
|
||||
];
|
||||
return [
|
||||
'transaction_reference' => $response->checkout_id,
|
||||
'transaction_response' => json_encode($response),
|
||||
'success' => $response->state == 'refunded' ? true : false,
|
||||
'description' => 'refund',
|
||||
'code' => 0,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,14 @@
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\GroupSetting;
|
||||
|
||||
class GroupSettingRepository extends BaseRepository
|
||||
{
|
||||
public function save($data, GroupSetting $group_setting) :?GroupSetting
|
||||
{
|
||||
|
||||
$group_setting->fill($data);
|
||||
$group_setting->save();
|
||||
|
||||
@ -27,6 +29,15 @@ class GroupSettingRepository extends BaseRepository
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +208,9 @@ class PaymentMigrationRepository extends BaseRepository
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$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;
|
||||
|
@ -199,7 +199,9 @@ class PaymentRepository extends BaseRepository {
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$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;
|
||||
|
@ -13,6 +13,7 @@
|
||||
namespace App\Repositories;
|
||||
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Models\Client;
|
||||
@ -44,8 +45,8 @@ class SubscriptionRepository extends BaseRepository
|
||||
private function calculatePrice($subscription) :array
|
||||
{
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
// DB::beginTransaction();
|
||||
DB::connection(config('database.default'))->beginTransaction();
|
||||
$data = [];
|
||||
|
||||
$client = Client::factory()->create([
|
||||
@ -53,6 +54,7 @@ class SubscriptionRepository extends BaseRepository
|
||||
'company_id' => $subscription->company_id,
|
||||
'group_settings_id' => $subscription->group_id,
|
||||
'country_id' => $subscription->company->settings->country_id,
|
||||
'settings' => ClientSettings::defaults(),
|
||||
]);
|
||||
|
||||
$contact = ClientContact::factory()->create([
|
||||
@ -88,8 +90,9 @@ class SubscriptionRepository extends BaseRepository
|
||||
|
||||
$data['promo_price'] = $invoice->calc()->getTotal();
|
||||
|
||||
DB::rollBack();
|
||||
|
||||
// DB::rollBack();
|
||||
DB::connection(config('database.default'))->rollBack();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
@ -377,23 +377,28 @@ class InvoiceService
|
||||
{
|
||||
switch ($reminder_template) {
|
||||
case 'reminder1':
|
||||
$this->invoice->reminder1_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder1_sent = now();
|
||||
$this->invoice->reminder_last_sent = now();
|
||||
$this->invoice->last_sent_date = now();
|
||||
break;
|
||||
case 'reminder2':
|
||||
$this->invoice->reminder2_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder2_sent = now();
|
||||
$this->invoice->reminder_last_sent = now();
|
||||
$this->invoice->last_sent_date = now();
|
||||
break;
|
||||
case 'reminder3':
|
||||
$this->invoice->reminder3_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder3_sent = now();
|
||||
$this->invoice->reminder_last_sent = now();
|
||||
$this->invoice->last_sent_date = now();
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
$this->invoice->reminder1_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder1_sent = now();
|
||||
$this->invoice->reminder_last_sent = now();
|
||||
$this->invoice->last_sent_date = now();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,9 @@ class MarkPaid extends AbstractService
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$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();
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Services\AbstractService;
|
||||
use Carbon\Carbon;
|
||||
|
||||
@ -126,6 +127,14 @@ class UpdateReminder extends AbstractService
|
||||
$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()))
|
||||
$this->invoice->next_send_date = $date_collection->sort()->first();
|
||||
else
|
||||
@ -133,4 +142,41 @@ class UpdateReminder extends AbstractService
|
||||
|
||||
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)]];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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' => 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' => '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')) {
|
||||
$_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' => [
|
||||
['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 . '_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)]],
|
||||
]];
|
||||
} elseif (Str::startsWith($variable, '$custom')) {
|
||||
$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['$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['$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['$invoice.due_date'] = &$data['$due_date'];
|
||||
$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['$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['$invoice.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['$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['$viewLink'] = &$data['$view_link'];
|
||||
$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')];
|
||||
|
||||
@ -139,6 +144,7 @@ class HtmlEngine
|
||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.quote_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['$viewLink'] = &$data['$view_link'];
|
||||
$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')];
|
||||
}
|
||||
@ -149,6 +155,7 @@ class HtmlEngine
|
||||
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.credit_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['$viewLink'] = &$data['$view_link'];
|
||||
$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['$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['$invoice.balance_due'] = $data['$balance_due'];
|
||||
$data['$quote.balance_due'] = &$data['$balance_due'];
|
||||
$data['$invoice.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'] = &$data['$partial_due'];
|
||||
|
||||
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')];
|
||||
$data['$amount'] = &$data['$total'];
|
||||
$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['$entity.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['$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['$client_name'] = ['value' => $this->entity->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')];
|
||||
$data['$client.name'] = &$data['$client_name'];
|
||||
$data['$client'] = &$data['$client_name'];
|
||||
|
||||
$data['$client.address1'] = &$data['$address1'];
|
||||
$data['$client.address2'] = &$data['$address2'];
|
||||
$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['$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.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.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')];
|
||||
|
||||
|
||||
@ -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.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['$account'] = &$data['$company.name'];
|
||||
|
||||
$data['$company.address1'] = ['value' => $this->settings->address1 ?: ' ', 'label' => ctrans('texts.address1')];
|
||||
$data['$company.address2'] = ['value' => $this->settings->address2 ?: ' ', 'label' => ctrans('texts.address2')];
|
||||
$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['$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' => ''];
|
||||
|
||||
@ -393,6 +412,8 @@ class HtmlEngine
|
||||
$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['$autoBill'] = ['value' => ctrans('texts.auto_bill_notification_placeholder'), 'label' => ''];
|
||||
$data['$auto_bill'] = &$data['$autoBill'];
|
||||
|
||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||
|
@ -212,7 +212,7 @@ class TemplateEngine
|
||||
} else {
|
||||
$wrapper = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($email_style == 'plain') {
|
||||
$wrapper = view($this->getTemplatePath($email_style), $data)->render();
|
||||
$injection = '';
|
||||
@ -226,7 +226,7 @@ class TemplateEngine
|
||||
|
||||
$data = [
|
||||
'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,
|
||||
'raw_body' => $this->raw_body,
|
||||
'raw_subject' => $this->raw_subject
|
||||
@ -239,7 +239,7 @@ class TemplateEngine
|
||||
|
||||
private function mockEntity()
|
||||
{
|
||||
DB::beginTransaction();
|
||||
DB::connection(config('database.default'))->beginTransaction();
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => auth()->user()->id,
|
||||
@ -277,52 +277,6 @@ class TemplateEngine
|
||||
|
||||
private function tearDown()
|
||||
{
|
||||
DB::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'));
|
||||
DB::connection(config('database.default'))->rollBack();
|
||||
}
|
||||
}
|
||||
|
@ -568,13 +568,21 @@ trait GeneratesCounter
|
||||
$search[] = '{$client_counter}';
|
||||
$replace[] = $counter;
|
||||
|
||||
$search[] = '{$clientCounter}';
|
||||
$replace[] = $counter;
|
||||
|
||||
$search[] = '{$group_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;
|
||||
$search[] = '{$user_id}';
|
||||
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
|
||||
$search[] = '{$userId}';
|
||||
$replace[] = str_pad(($user_id), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$matches = false;
|
||||
@ -624,9 +632,15 @@ trait GeneratesCounter
|
||||
$search[] = '{$client_custom1}';
|
||||
$replace[] = $client->custom_value1;
|
||||
|
||||
$search[] = '{$clientCustom1}';
|
||||
$replace[] = $client->custom_value1;
|
||||
|
||||
$search[] = '{$client_custom2}';
|
||||
$replace[] = $client->custom_value2;
|
||||
|
||||
$search[] = '{$clientCustom2}';
|
||||
$replace[] = $client->custom_value2;
|
||||
|
||||
$search[] = '{$client_custom3}';
|
||||
$replace[] = $client->custom_value3;
|
||||
|
||||
@ -638,6 +652,9 @@ trait GeneratesCounter
|
||||
|
||||
$search[] = '{$client_id_number}';
|
||||
$replace[] = $client->id_number;
|
||||
|
||||
$search[] = '{$clientIdNumber}';
|
||||
$replace[] = $client->id_number;
|
||||
}
|
||||
|
||||
return str_replace($search, $replace, $pattern);
|
||||
|
@ -474,7 +474,7 @@ trait MakesInvoiceValues
|
||||
}
|
||||
|
||||
if ($matches->keys()->first() == ':MONTH') {
|
||||
$output = \Carbon\Carbon::create()->month($output)->localeMonth;
|
||||
$output = \Carbon\Carbon::create()->month($output)->translatedFormat('F');
|
||||
}
|
||||
|
||||
$value = preg_replace(
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.2.6',
|
||||
'app_tag' => '5.2.6-release',
|
||||
'app_version' => '5.2.7',
|
||||
'app_tag' => '5.2.7-release',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
@ -152,6 +152,10 @@ return [
|
||||
'environment' => env('WEPAY_ENVIRONMENT', 'stage'),
|
||||
'client_id' => env('WEPAY_CLIENT_ID', ''),
|
||||
'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_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/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"main.dart.js": "1225d7da63eaf3817e25a8b6726635cc",
|
||||
"main.dart.js": "383f48eff49849cbbe38e2fe4ae81ad4",
|
||||
"/": "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",
|
||||
"/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/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
||||
"/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:',
|
||||
'recurring_invoice_due_date' => 'Due Date',
|
||||
'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;
|
||||
|
@ -236,7 +236,7 @@ $LANG = array(
|
||||
'archived_vendors' => 'Successfully archived :count vendors',
|
||||
'deleted_vendor' => 'Successfully deleted vendor',
|
||||
'deleted_vendors' => 'Successfully deleted :count vendors',
|
||||
'confirmation_subject' => 'Invoice Ninja Account Confirmation',
|
||||
'confirmation_subject' => 'Account Confirmation',
|
||||
'confirmation_header' => 'Account Confirmation',
|
||||
'confirmation_message' => 'Please access the link below to confirm your 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.',
|
||||
'token_expired' => 'Validation token was expired. Please try again.',
|
||||
'invoice_link' => 'Invoice Link',
|
||||
'button_confirmation_message' => 'Click to confirm your email address.',
|
||||
'button_confirmation_message' => 'Click to confirm your email.',
|
||||
'confirm' => 'Confirm',
|
||||
'email_preferences' => 'Email Preferences',
|
||||
'created_invoices' => 'Successfully created :count invoice(s)',
|
||||
|
@ -25,7 +25,7 @@
|
||||
@endisset
|
||||
|
||||
@isset($signature)
|
||||
{!! $signature !!}
|
||||
{!! nl2br($signature) !!}
|
||||
@endisset
|
||||
</div>
|
||||
@endcomponent
|
||||
|
@ -2,5 +2,7 @@
|
||||
<div class="center">
|
||||
<h1>{{ ctrans('texts.ach_verification_notification_label') }}</h1>
|
||||
<p>{{ ctrans('texts.ach_verification_notification') }}</p>
|
||||
|
||||
<a class="button" href="{{ $url }}">{{ ctrans('texts.complete_verification') }}</a>
|
||||
</div>
|
||||
@endcomponent
|
||||
|
@ -67,7 +67,7 @@
|
||||
<p><b>{{ ctrans('texts.documents') }}:</b> {{ count($company->documents) }} </p>
|
||||
@endif
|
||||
|
||||
@if($check_data)
|
||||
@if(isset($check_data))
|
||||
<p><b>Data Quality:</b></p>
|
||||
<p> {!! $check_data !!} </p>
|
||||
@endif
|
||||
|
@ -90,6 +90,10 @@
|
||||
#content .center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#content .left {
|
||||
text-align: left !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -116,15 +120,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
|
||||
{{ $slot ?? '' }}
|
||||
{!! $body ?? '' !!}
|
||||
|
||||
@isset($signature)
|
||||
{{ nl2br($signature) }}
|
||||
@endisset
|
||||
|
||||
<div>
|
||||
<a href="#"
|
||||
@ -135,24 +135,27 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@if(isset($company) && $company instanceof \App\Models\Company)
|
||||
<tr>
|
||||
<td>
|
||||
<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;">
|
||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-bottom: 30px;">
|
||||
{{ ctrans('texts.client_email_company_contact_label') }}
|
||||
</p>
|
||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 500; margin-bottom:0;">
|
||||
{{ $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>
|
||||
@isset($signature)
|
||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 400; margin-bottom: 30px;">
|
||||
{!! nl2br($signature) !!}
|
||||
</p>
|
||||
@endisset
|
||||
|
||||
@if(isset($company) && $company instanceof \App\Models\Company)
|
||||
<p style="font-size: 15px; color: #2e2e2e; font-family: 'roboto', Arial, Helvetica, sans-serif; font-weight: 500; margin-bottom:0;">
|
||||
{{ $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>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
@ -37,7 +37,7 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#company-details > span:first-child {
|
||||
#company-details > p:first-child {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<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="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 }}"
|
||||
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>
|
||||
<dl>
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
{{ ctrans('texts.payment_type') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ ucfirst($payment_method->gateway_type->name) }}
|
||||
</dd>
|
||||
</div>
|
||||
<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">
|
||||
{{ ctrans('texts.payment_type') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ ucfirst($payment_method->gateway_type->name) }}
|
||||
</dd>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
{{ ctrans('texts.type') }}
|
||||
</dt>
|
||||
<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)->scheme }}
|
||||
</dd>
|
||||
</div>
|
||||
<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">
|
||||
{{ ctrans('texts.type') }}
|
||||
</dt>
|
||||
<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)->scheme }}
|
||||
</dd>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
{{ ctrans('texts.card_number') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
**** {{ ucfirst($payment_method->meta->last4) }}
|
||||
</dd>
|
||||
</div>
|
||||
<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">
|
||||
{{ ctrans('texts.card_number') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
**** {{ ucfirst($payment_method->meta->last4) }}
|
||||
</dd>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
{{ ctrans('texts.date_created') }}
|
||||
</dt>
|
||||
<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()) }}
|
||||
</dd>
|
||||
</div>
|
||||
<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">
|
||||
{{ ctrans('texts.date_created') }}
|
||||
</dt>
|
||||
<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()) }}
|
||||
</dd>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
{{ ctrans('texts.default') }}
|
||||
</dt>
|
||||
<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') }}
|
||||
<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">
|
||||
{{ ctrans('texts.default') }}
|
||||
</dt>
|
||||
<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') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
@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">
|
||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||
@ -83,7 +83,10 @@
|
||||
</dl>
|
||||
</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="sm:flex sm:items-start sm:justify-between">
|
||||
<div>
|
||||
@ -109,3 +112,11 @@
|
||||
</div>
|
||||
</div>
|
||||
@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>
|
||||
|
||||
@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)
|
||||
<div class="bg-white shadow sm:rounded-lg mt-4">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
|
Loading…
Reference in New Issue
Block a user