mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
Merge remote-tracking branch 'upstream/v5-develop' into laravel11
This commit is contained in:
commit
39a0ffc52d
2
.github/workflows/react_release.yml
vendored
2
.github/workflows/react_release.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: 8.2
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gd, curl, zip, openssl, mbstring, xml
|
||||
|
||||
- name: Checkout code
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: 8.2
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gd, curl, zip, openssl, mbstring, xml
|
||||
|
||||
- name: Checkout code
|
||||
|
@ -1 +1 @@
|
||||
5.8.57
|
||||
5.9.2
|
@ -105,17 +105,34 @@ class PayPalBalanceAffecting
|
||||
public $discount;
|
||||
public $creditTransactionalFee;
|
||||
public $originalInvoiceId;
|
||||
|
||||
|
||||
public function __construct(private array $import_row){}
|
||||
|
||||
public function run(): self
|
||||
{
|
||||
$this->cleanUp();
|
||||
|
||||
foreach($this->import_row as $key => $value) {
|
||||
|
||||
$prop = $this->key_map[$key] ?? false;
|
||||
|
||||
if($prop)
|
||||
if($prop){
|
||||
|
||||
echo "Setting {$prop} to {$value}".PHP_EOL;
|
||||
$this->{$prop} = $value;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function cleanUp(): self
|
||||
{
|
||||
|
||||
foreach($this->key_map as $value){
|
||||
echo "Setting {$value} to null".PHP_EOL;
|
||||
$this->{$value} = null;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -149,6 +166,7 @@ class PayPalBalanceAffecting
|
||||
'line_items' => [$item],
|
||||
'name' => $this->name ?? '',
|
||||
'email' => $this->fromEmailAddress ?? '',
|
||||
'transaction_reference' => $this->transactionId ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,9 @@ class ExpenseFilters extends QueryFilters
|
||||
})
|
||||
->orWhereHas('vendor', function ($q) use ($filter) {
|
||||
$q->where('name', 'like', '%'.$filter.'%');
|
||||
})
|
||||
->orWhereHas('client', function ($q) use ($filter) {
|
||||
$q->where('name', 'like', '%'.$filter.'%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ class TaskFilters extends QueryFilters
|
||||
*
|
||||
* @param string $filter
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ class NordigenController extends BaseController
|
||||
/** @var array $context */
|
||||
$context = $request->getTokenContent();
|
||||
$company = $request->getCompany();
|
||||
$lang = $company->locale();
|
||||
$lang = substr($company->locale(), 0, 2);
|
||||
$context["lang"] = $lang;
|
||||
|
||||
if (!$context) {
|
||||
@ -143,7 +143,7 @@ class NordigenController extends BaseController
|
||||
$data = $request->all();
|
||||
$company = $request->getCompany();
|
||||
$account = $company->account;
|
||||
$lang = $company->locale();
|
||||
$lang = substr($company->locale(), 0, 2);
|
||||
|
||||
/** @var array $context */
|
||||
$context = $request->getTokenContent();
|
||||
|
@ -11,33 +11,35 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\HtmlEngine;
|
||||
use Illuminate\Support\Str;
|
||||
use Twig\Error\SyntaxError;
|
||||
use App\Jobs\Util\PreviewPdf;
|
||||
use App\Models\ClientContact;
|
||||
use App\Services\Pdf\PdfMock;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Services\Pdf\PdfService;
|
||||
use App\Utils\PhantomJS\Phantom;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Services\PdfMaker\Design;
|
||||
use App\Utils\HostedPDF\NinjaPdf;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\PdfMaker\PdfMaker;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesInvoiceHtml;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
use App\Utils\Traits\Pdf\PageNumbering;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use App\DataMapper\Analytics\LivePreview;
|
||||
use App\Services\Template\TemplateService;
|
||||
use App\Http\Requests\Preview\ShowPreviewRequest;
|
||||
use App\Http\Requests\Preview\DesignPreviewRequest;
|
||||
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
||||
use App\Http\Requests\Preview\ShowPreviewRequest;
|
||||
use App\Jobs\Util\PreviewPdf;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Services\Pdf\PdfMock;
|
||||
use App\Services\Pdf\PdfService;
|
||||
use App\Services\PdfMaker\Design;
|
||||
use App\Services\PdfMaker\PdfMaker;
|
||||
use App\Services\Template\TemplateService;
|
||||
use App\Utils\HostedPDF\NinjaPdf;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\PhantomJS\Phantom;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\MakesInvoiceHtml;
|
||||
use App\Utils\Traits\Pdf\PageNumbering;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
use Twig\Error\SyntaxError;
|
||||
use App\Utils\VendorHtmlEngine;
|
||||
|
||||
class PreviewController extends BaseController
|
||||
{
|
||||
@ -136,6 +138,7 @@ class PreviewController extends BaseController
|
||||
*/
|
||||
public function show(ShowPreviewRequest $request)
|
||||
{
|
||||
|
||||
if($request->input('design.is_template')) {
|
||||
return $this->template();
|
||||
}
|
||||
@ -143,8 +146,8 @@ class PreviewController extends BaseController
|
||||
if (request()->has('entity') &&
|
||||
request()->has('entity_id') &&
|
||||
! empty(request()->input('entity')) &&
|
||||
! empty(request()->input('entity_id')) &&
|
||||
request()->has('body')) {
|
||||
! empty(request()->input('entity_id')))
|
||||
{
|
||||
|
||||
$design_object = json_decode(json_encode(request()->input('design')));
|
||||
|
||||
@ -152,7 +155,8 @@ class PreviewController extends BaseController
|
||||
return response()->json(['message' => ctrans('texts.invalid_design_object')], 400);
|
||||
}
|
||||
|
||||
$entity = ucfirst(request()->input('entity'));
|
||||
// $entity = ucfirst(request()->input('entity'));
|
||||
$entity = Str::camel(request()->input('entity'));
|
||||
|
||||
$class = "App\Models\\$entity";
|
||||
|
||||
@ -166,17 +170,20 @@ class PreviewController extends BaseController
|
||||
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
App::setLocale($entity_obj->client->primary_contact()->preferredLocale());
|
||||
App::setLocale($entity_obj->client->preferredLocale());
|
||||
$t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
|
||||
|
||||
$html = new HtmlEngine($entity_obj->invitations()->first());
|
||||
if($entity_obj->client){
|
||||
$html = new HtmlEngine($entity_obj->invitations()->first());
|
||||
}
|
||||
else {
|
||||
$html = new VendorHtmlEngine($entity_obj->invitations()->first());
|
||||
}
|
||||
|
||||
$design_namespace = 'App\Services\PdfMaker\Designs\\'.request()->design['name'];
|
||||
|
||||
$design_class = new $design_namespace();
|
||||
$design = new Design(Design::CUSTOM, ['custom_partials' => request()->design['design']]);
|
||||
|
||||
$state = [
|
||||
'template' => $design_class->elements([
|
||||
'template' => $design->elements([
|
||||
'client' => $entity_obj->client,
|
||||
'entity' => $entity_obj,
|
||||
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
|
||||
@ -191,7 +198,6 @@ class PreviewController extends BaseController
|
||||
]
|
||||
];
|
||||
|
||||
$design = new Design(request()->design['name']);
|
||||
$maker = new PdfMaker($state);
|
||||
|
||||
$maker
|
||||
|
@ -70,12 +70,10 @@ class StartupCheck
|
||||
private function buildTemplates($name = 'templates')
|
||||
{
|
||||
$data = [
|
||||
|
||||
'invoice' => [
|
||||
'subject' => EmailTemplateDefaults::emailInvoiceSubject(),
|
||||
'body' => EmailTemplateDefaults::emailInvoiceTemplate(),
|
||||
],
|
||||
|
||||
'quote' => [
|
||||
'subject' => EmailTemplateDefaults::emailQuoteSubject(),
|
||||
'body' => EmailTemplateDefaults::emailQuoteTemplate(),
|
||||
|
@ -38,7 +38,7 @@ class StoreVendorRequest extends Request
|
||||
$user = auth()->user();
|
||||
|
||||
$rules = [];
|
||||
|
||||
$rules['name'] = 'bail|required|string';
|
||||
$rules['contacts'] = 'bail|array';
|
||||
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';
|
||||
$rules['contacts.*.password'] = [
|
||||
|
@ -81,7 +81,7 @@ class SubscriptionCron
|
||||
|
||||
$company = Company::find($company_id);
|
||||
|
||||
$timezone_now = now()->setTimezone($company->timezone()->name);
|
||||
$timezone_now = now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway');
|
||||
|
||||
//Capture companies within the window of 00:00 and 00:30
|
||||
if($timezone_now->gt($timezone_now->copy()->startOfDay()) && $timezone_now->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||
|
@ -112,6 +112,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||
->mailable
|
||||
->withSymfonyMessage(function ($message) {
|
||||
$message->getHeaders()->addTextHeader('x-invitation', $this->nmo->invitation->key);
|
||||
// $message->getHeaders()->addTextHeader('List-Unsubscribe', $this->nmo->mailable->viewData->email_preferences);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property int|null $last_login
|
||||
* @property int|null $industry_id
|
||||
* @property int|null $size_id
|
||||
* @property object|null $e_invoice
|
||||
* @property string|null $address1
|
||||
* @property string|null $address2
|
||||
* @property string|null $city
|
||||
@ -185,6 +186,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
'deleted_at' => 'timestamp',
|
||||
'last_login' => 'timestamp',
|
||||
'tax_data' => 'object',
|
||||
'e_invoice' => 'object',
|
||||
];
|
||||
|
||||
protected $touches = [];
|
||||
@ -376,15 +378,16 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function language()
|
||||
{
|
||||
$languages = Cache::get('languages');
|
||||
$languages = app('languages');
|
||||
// $languages = Cache::get('languages');
|
||||
|
||||
if (! $languages) {
|
||||
$this->buildCache(true);
|
||||
}
|
||||
// if (! $languages) {
|
||||
// $this->buildCache(true);
|
||||
// }
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $languages->first(function ($item) {
|
||||
return $item->id == $this->getSetting('language_id');
|
||||
})->first();
|
||||
});
|
||||
}
|
||||
|
||||
public function industry(): BelongsTo
|
||||
@ -408,28 +411,30 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function date_format()
|
||||
{
|
||||
$date_formats = Cache::get('date_formats');
|
||||
$date_formats = app('date_formats');
|
||||
// $date_formats = Cache::get('date_formats');
|
||||
|
||||
if (! $date_formats) {
|
||||
$this->buildCache(true);
|
||||
}
|
||||
// if (! $date_formats) {
|
||||
// $this->buildCache(true);
|
||||
// }
|
||||
|
||||
return $date_formats->filter(function ($item) {
|
||||
return $date_formats->first(function ($item) {
|
||||
return $item->id == $this->getSetting('date_format_id');
|
||||
})->first()->format;
|
||||
})->format;
|
||||
}
|
||||
|
||||
public function currency()
|
||||
{
|
||||
$currencies = Cache::get('currencies');
|
||||
$currencies = app('currencies');
|
||||
// $currencies = Cache::get('currencies');
|
||||
|
||||
if (! $currencies) {
|
||||
$this->buildCache(true);
|
||||
}
|
||||
// if (! $currencies) {
|
||||
// $this->buildCache(true);
|
||||
// }
|
||||
|
||||
return $currencies->filter(function ($item) {
|
||||
return $currencies->first(function ($item) {
|
||||
return $item->id == $this->getSetting('currency_id');
|
||||
})->first();
|
||||
});
|
||||
}
|
||||
|
||||
public function service(): ClientService
|
||||
@ -737,15 +742,17 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function preferredLocale()
|
||||
{
|
||||
$languages = Cache::get('languages');
|
||||
$this->language()->locale ?? 'en';
|
||||
// $languages = app('languages');
|
||||
// $languages = Cache::get('languages');
|
||||
|
||||
if (! $languages) {
|
||||
$this->buildCache(true);
|
||||
}
|
||||
// if (! $languages) {
|
||||
// $this->buildCache(true);
|
||||
// }
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->getSetting('language_id');
|
||||
})->first()->locale;
|
||||
// return $languages->first(function ($item) {
|
||||
// return $item->id == $this->getSetting('language_id');
|
||||
// })->locale;
|
||||
}
|
||||
|
||||
public function backup_path(): string
|
||||
|
@ -20,6 +20,10 @@ use App\Utils\Traits\MakesHash;
|
||||
use App\PaymentDrivers\Common\MethodInterface;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use App\Services\Email\EmailObject;
|
||||
use App\Services\Email\Email;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class BTCPay implements MethodInterface
|
||||
{
|
||||
@ -128,18 +132,55 @@ class BTCPay implements MethodInterface
|
||||
public function refund(Payment $payment, $amount)
|
||||
{
|
||||
try {
|
||||
$invoice = $payment->invoices()->first();
|
||||
$isPartialRefund = ($amount < $payment->amount);
|
||||
if ($amount == $payment->amount) {
|
||||
$refundVariant = "Fiat";
|
||||
$refundPaymentMethod = "BTC";
|
||||
$refundDescription = "Full refund";
|
||||
$refundCustomCurrency = null;
|
||||
$refundCustomAmount = null;
|
||||
} else {
|
||||
$refundVariant = "Custom";
|
||||
$refundPaymentMethod = "";
|
||||
$refundDescription = "Partial refund";
|
||||
$refundCustomCurrency = $payment->currency;
|
||||
$refundCustomAmount = $amount;
|
||||
}
|
||||
|
||||
$client = new \BTCPayServer\Client\Invoice($this->driver_class->btcpay_url, $this->driver_class->api_key);
|
||||
$refund = $client->refundInvoice($this->driver_class->store_id, $payment->transaction_reference);
|
||||
$refund = $client->refundInvoice(
|
||||
$this->driver_class->store_id,
|
||||
$payment->transaction_reference,
|
||||
$refundVariant,
|
||||
$refundPaymentMethod,
|
||||
null,
|
||||
$refundDescription,
|
||||
0,
|
||||
$refundCustomAmount,
|
||||
$refundCustomCurrency
|
||||
);
|
||||
App::setLocale($payment->company->getLocale());
|
||||
|
||||
/* $data = [];
|
||||
$data['InvoiceNumber'] = $invoice->number;
|
||||
$data['isPartialRefund'] = $isPartialRefund;
|
||||
$data['BTCPayLink'] = $refund->getViewLink();*/
|
||||
$mo = new EmailObject();
|
||||
$mo->subject = ctrans('texts.btcpay_refund_subject');
|
||||
$mo->body = ctrans('texts.btcpay_refund_body') . '<br>' . $refund->getViewLink();
|
||||
$mo->text_body = ctrans('texts.btcpay_refund_body') . '\n' . $refund->getViewLink();
|
||||
$mo->company_key = $payment->company->company_key;
|
||||
$mo->html_template = 'email.template.generic';
|
||||
$mo->to = [new Address($payment->client->present()->email(), $payment->client->present()->name())];
|
||||
$mo->email_template_body = 'btcpay_refund_subject';
|
||||
$mo->email_template_subject = 'btcpay_refund_body';
|
||||
|
||||
return $refund->getViewLink();
|
||||
Email::dispatch($mo, $payment->company);
|
||||
|
||||
$data = [
|
||||
'transaction_reference' => $refund->getId(),
|
||||
'transaction_response' => json_encode($refund),
|
||||
'success' => true,
|
||||
'description' => "Please follow this link to claim your refund: " . $refund->getViewLink(),
|
||||
'code' => 202,
|
||||
];
|
||||
|
||||
return $data;
|
||||
} catch (\Throwable $e) {
|
||||
throw new PaymentFailed('Error during BTCPay refund : ' . $e->getMessage());
|
||||
}
|
||||
|
@ -79,10 +79,14 @@ class BTCPayPaymentDriver extends BaseDriver
|
||||
return $this->payment_method->paymentView($data); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
return $this->payment_method->paymentResponse($request);
|
||||
}
|
||||
|
||||
public function processWebhookRequest()
|
||||
{
|
||||
$webhook_payload = file_get_contents('php://input');
|
||||
//file_put_contents("/home/claude/invoiceninja/storage/my.log", $webhook_payload);
|
||||
|
||||
$btcpayRep = json_decode($webhook_payload);
|
||||
if ($btcpayRep == null) {
|
||||
|
131
app/Providers/StaticServiceProvider.php
Normal file
131
app/Providers/StaticServiceProvider.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Bank;
|
||||
use App\Models\Size;
|
||||
use App\Models\Country;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Industry;
|
||||
use App\Models\Language;
|
||||
use App\Models\Timezone;
|
||||
use App\Models\DateFormat;
|
||||
use App\Models\PaymentTerm;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
|
||||
class StaticServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
|
||||
|
||||
app()->singleton('currencies', function ($app) {
|
||||
return Currency::query()->orderBy('name')->get();
|
||||
});
|
||||
|
||||
app()->singleton('languages', function ($app) {
|
||||
return Language::query()->orderBy('name')->get();
|
||||
});
|
||||
|
||||
app()->singleton('countries', function ($app) {
|
||||
return Country::query()->orderBy('name')->get();
|
||||
});
|
||||
|
||||
app()->singleton('payment_types', function ($app) {
|
||||
return PaymentTerm::query()->orderBy('num_days')->get();
|
||||
});
|
||||
|
||||
app()->singleton('industries', function ($app) {
|
||||
return Industry::query()->orderBy('name')->get();
|
||||
});
|
||||
|
||||
app()->singleton('banks', function ($app) {
|
||||
return Bank::query()->orderBy('name')->get();
|
||||
});
|
||||
|
||||
app()->singleton('date_formats', function ($app) {
|
||||
return DateFormat::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
app()->singleton('timezones', function ($app) {
|
||||
return Timezone::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
app()->singleton('gateways', function ($app) {
|
||||
return Gateway::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
app()->singleton('industries', function ($app) {
|
||||
return Industry::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
app()->singleton('sizes', function ($app) {
|
||||
return Size::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
/** @deprecated */
|
||||
app()->singleton('banks', function ($app) {
|
||||
return Bank::query()->orderBy('id')->get();
|
||||
});
|
||||
|
||||
app()->singleton('templates', function ($app) {
|
||||
return [
|
||||
'invoice' => [
|
||||
'subject' => EmailTemplateDefaults::emailInvoiceSubject(),
|
||||
'body' => EmailTemplateDefaults::emailInvoiceTemplate(),
|
||||
],
|
||||
'quote' => [
|
||||
'subject' => EmailTemplateDefaults::emailQuoteSubject(),
|
||||
'body' => EmailTemplateDefaults::emailQuoteTemplate(),
|
||||
],
|
||||
'payment' => [
|
||||
'subject' => EmailTemplateDefaults::emailPaymentSubject(),
|
||||
'body' => EmailTemplateDefaults::emailPaymentTemplate(),
|
||||
],
|
||||
'reminder1' => [
|
||||
'subject' => EmailTemplateDefaults::emailReminder1Subject(),
|
||||
'body' => EmailTemplateDefaults::emailReminder1Template(),
|
||||
],
|
||||
'reminder2' => [
|
||||
'subject' => EmailTemplateDefaults::emailReminder2Subject(),
|
||||
'body' => EmailTemplateDefaults::emailReminder2Template(),
|
||||
],
|
||||
'reminder3' => [
|
||||
'subject' => EmailTemplateDefaults::emailReminder3Subject(),
|
||||
'body' => EmailTemplateDefaults::emailReminder3Template(),
|
||||
],
|
||||
'reminder_endless' => [
|
||||
'subject' => EmailTemplateDefaults::emailReminderEndlessSubject(),
|
||||
'body' => EmailTemplateDefaults::emailReminderEndlessTemplate(),
|
||||
],
|
||||
'statement' => [
|
||||
'subject' => EmailTemplateDefaults::emailStatementSubject(),
|
||||
'body' => EmailTemplateDefaults::emailStatementTemplate(),
|
||||
],
|
||||
];
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -11,19 +11,20 @@
|
||||
|
||||
namespace App\Services\Email;
|
||||
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
use App\Jobs\Entity\CreateRawPdf;
|
||||
use App\Jobs\Invoice\CreateUbl;
|
||||
use App\Models\Task;
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Account;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Task;
|
||||
use App\Utils\Ninja;
|
||||
use App\Jobs\Invoice\CreateUbl;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use App\Jobs\Entity\CreateRawPdf;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use App\DataMapper\EmailTemplateDefaults;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
||||
class EmailDefaults
|
||||
@ -388,6 +389,7 @@ class EmailDefaults
|
||||
{
|
||||
if ($this->email->email_object->invitation_key) {
|
||||
$this->email->email_object->headers = array_merge($this->email->email_object->headers, ['x-invitation' => $this->email->email_object->invitation_key]);
|
||||
// $this->email->email_object->headers = array_merge($this->email->email_object->headers, ['x-invitation' => $this->email->email_object->invitation_key,'List-Unsubscribe' => URL::signedRoute('client.email_preferences', ['entity' => $this->email->email_object->invitation->getEntityString(), 'invitation_key' => $this->email->email_object->invitation->key])]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -570,7 +570,7 @@ class InvoiceService
|
||||
$this->invoice->exchange_rate = $this->invoice->client->setExchangeRate();
|
||||
}
|
||||
|
||||
if ($is_recurring && $this->invoice->client->getSetting('auto_bill_standard_invoices')) {
|
||||
if (!$is_recurring && $this->invoice->client->getSetting('auto_bill_standard_invoices')) {
|
||||
$this->invoice->auto_bill_enabled = true;
|
||||
}
|
||||
|
||||
|
@ -341,7 +341,7 @@ class PdfMock
|
||||
'$client.currency' => 'USD',
|
||||
'$company.country' => $this->company->country()?->name ?? 'USA',
|
||||
'$company.address' => $this->company->present()->address(),
|
||||
'$tech_hero_image' => 'http://ninja.test:8000/images/pdf-designs/tech-hero-image.jpg',
|
||||
'$tech_hero_image' => 'https://invoicing.co/images/pdf-designs/tech-hero-image.jpg',
|
||||
'$task.tax_name1' => '',
|
||||
'$task.tax_name2' => '',
|
||||
'$task.tax_name3' => '',
|
||||
|
@ -164,6 +164,7 @@ class ClientTransformer extends EntityTransformer
|
||||
'routing_id' => (string) $client->routing_id,
|
||||
'tax_info' => $client->tax_data ?: new \stdClass(),
|
||||
'classification' => $client->classification ?: '',
|
||||
'e_invoice' => $client->e_invoice ?: new \stdClass(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ class CompanyShopProfileTransformer extends EntityTransformer
|
||||
'email' => $company->settings->email,
|
||||
'country_id' => $company->settings->country_id,
|
||||
'vat_number' => $company->settings->vat_number,
|
||||
'product' => $company->settings->translations->product ?? ctrans('texts.product'),
|
||||
'products' => $company->settings->translations->products ?? ctrans('texts.products'),
|
||||
'client_registration_fields' => $company->client_registration_fields,
|
||||
];
|
||||
|
||||
$new_settings = new stdClass();
|
||||
|
@ -660,10 +660,12 @@ class HtmlEngine
|
||||
if ($this->settings->signature_on_pdf) {
|
||||
$data['$contact.signature'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')];
|
||||
$data['$contact.signature_date'] = ['value' => $this->translateDate($this->invitation->signature_date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.date')];
|
||||
$data['$contact.signature_ip'] = ['value' => $this->invitation->signature_ip ?? '', 'label' => ctrans('texts.address')];
|
||||
|
||||
} else {
|
||||
$data['$contact.signature'] = ['value' => '', 'label' => ''];
|
||||
$data['$contact.signature_date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
||||
$data['$contact.signature_ip'] = ['value' => '', 'label' => ctrans('texts.address')];
|
||||
}
|
||||
|
||||
$data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')];
|
||||
|
@ -45,7 +45,6 @@
|
||||
"braintree/braintree_php": "^6.0",
|
||||
"btcpayserver/btcpayserver-greenfield-php": "^2.6",
|
||||
"checkout/checkout-sdk-php": "^3.0",
|
||||
"invoiceninja/ubl_invoice": "^2",
|
||||
"doctrine/dbal": "^4.0",
|
||||
"eway/eway-rapid-php": "^1.3",
|
||||
"fakerphp/faker": "^1.14",
|
||||
@ -56,10 +55,14 @@
|
||||
"halaxa/json-machine": "^0.7.0",
|
||||
"hashids/hashids": "^4.0",
|
||||
"hedii/laravel-gelf-logger": "^9",
|
||||
"horstoeko/orderx": "dev-master",
|
||||
"horstoeko/zugferd": "^1",
|
||||
"hyvor/php-json-exporter": "^0.0.3",
|
||||
"imdhemy/laravel-purchases": "^1.7",
|
||||
"intervention/image": "^2.5",
|
||||
"invoiceninja/inspector": "^3.0",
|
||||
"invoiceninja/einvoice": "dev-main",
|
||||
"invoiceninja/ubl_invoice": "^2",
|
||||
"josemmo/facturae-php": "^1.7",
|
||||
"laracasts/presenter": "^0.2.1",
|
||||
"laravel/framework": "^11.0",
|
||||
@ -89,7 +92,7 @@
|
||||
"setasign/fpdi": "^2.3",
|
||||
"socialiteproviders/apple": "dev-master",
|
||||
"socialiteproviders/microsoft": "^4.1",
|
||||
"spatie/laravel-data": "^3.5",
|
||||
"spatie/laravel-data": "^3.6",
|
||||
"sprain/swiss-qr-bill": "^4.3",
|
||||
"square/square": "30.0.0.*",
|
||||
"stripe/stripe-php": "^12",
|
||||
@ -102,10 +105,7 @@
|
||||
"twig/twig": "^3",
|
||||
"twilio/sdk": "^6.40",
|
||||
"webpatser/laravel-countries": "dev-master#75992ad",
|
||||
"wildbit/postmark-php": "^4.0",
|
||||
"hyvor/php-json-exporter": "^0.0.3",
|
||||
"invoiceninja/einvoice": "dev-main",
|
||||
"horstoeko/orderx": "dev-master"
|
||||
"wildbit/postmark-php": "^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.6",
|
||||
|
8
composer.lock
generated
8
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "7a41ed3da96a8351f9ef162244dad6da",
|
||||
"content-hash": "942c6a9765c10a4c48ad4904e2561cb7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adrienrn/php-mimetyper",
|
||||
@ -20357,10 +20357,10 @@
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"asm/php-ansible": 20,
|
||||
"socialiteproviders/apple": 20,
|
||||
"webpatser/laravel-countries": 20,
|
||||
"horstoeko/orderx": 20,
|
||||
"invoiceninja/einvoice": 20,
|
||||
"horstoeko/orderx": 20
|
||||
"socialiteproviders/apple": 20,
|
||||
"webpatser/laravel-countries": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
|
@ -201,6 +201,7 @@ return [
|
||||
App\Providers\MultiDBProvider::class,
|
||||
App\Providers\ClientPortalServiceProvider::class,
|
||||
App\Providers\NinjaTranslationServiceProvider::class,
|
||||
App\Providers\StaticServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
@ -215,8 +216,8 @@ return [
|
||||
*/
|
||||
|
||||
'aliases' => Facade::defaultAliases()->merge([
|
||||
'Collector' => Turbo124\Collector\CollectorFacade::class,
|
||||
'Countries' => 'Webpatser\Countries\CountriesFacade',
|
||||
'Collector' => Turbo124\Beacon\CollectorFacade::class,
|
||||
// 'Countries' => 'Webpatser\Countries\CountriesFacade',
|
||||
'CustomMessage' => App\Utils\ClientPortal\CustomMessage\CustomMessageFacade::class,
|
||||
'Redis' => Illuminate\Support\Facades\Redis::class,
|
||||
])->toArray(),
|
||||
|
@ -17,8 +17,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => env('APP_VERSION', '5.8.58'),
|
||||
'app_tag' => env('APP_TAG', '5.8.58'),
|
||||
'app_version' => env('APP_VERSION', '5.9.2'),
|
||||
'app_tag' => env('APP_TAG', '5.9.2'),
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', false),
|
||||
|
@ -36,7 +36,6 @@ return new class extends Migration
|
||||
$table->mediumText('e_invoice')->nullable();
|
||||
});
|
||||
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->integer('email_quota')->default(20)->nullable();
|
||||
});
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
|
||||
Schema::table('clients', function (Blueprint $table) {
|
||||
$table->mediumText('e_invoice')->nullable();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
}
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if($g = \App\Models\Gateway::find(62))
|
||||
{
|
||||
$g->fields = '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}';
|
||||
$g->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
@ -87,7 +87,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['id' => 59, 'name' => 'Forte', 'provider' => 'Forte', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs', 'fields' => '{"testMode":false,"apiLoginId":"","apiAccessId":"","secureKey":"","authOrganizationId":"","organizationId":"","locationId":""}'],
|
||||
['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'],
|
||||
['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'],
|
||||
['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey:"", "storeId":"", "webhookSecret":""}'],
|
||||
['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'],
|
||||
];
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
|
@ -252,7 +252,7 @@ class RandomDataSeeder extends Seeder
|
||||
|
||||
$invoice->service()->createInvitations()->markSent()->save();
|
||||
|
||||
$invoice->ledger()->update_invoiceBalance($invoice->balance);
|
||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance);
|
||||
|
||||
if (rand(0, 1)) {
|
||||
$payment = Payment::create([
|
||||
|
@ -199,7 +199,7 @@ $lang = array(
|
||||
'removed_logo' => 'Successfully removed logo',
|
||||
'sent_message' => 'Successfully sent message',
|
||||
'invoice_error' => 'Please make sure to select a client and correct any errors',
|
||||
'limit_clients' => 'You\'ve hit the :count client limit on Free accounts. Congrats on your success!.',
|
||||
'limit_clients' => 'You\'ve hit the :count client limit on Free accounts. Congrats on your success!',
|
||||
'payment_error' => 'There was an error processing your payment. Please try again later.',
|
||||
'registration_required' => 'Registration Required',
|
||||
'confirmation_required' => 'Please confirm your email address, :link to resend the confirmation email.',
|
||||
@ -5147,7 +5147,7 @@ $lang = array(
|
||||
'payment_refund_receipt' => 'Payment Refund Receipt # :number',
|
||||
'payment_receipt' => 'Payment Receipt # :number',
|
||||
'load_template_description' => 'The template will be applied to following:',
|
||||
'run_template' => 'Run template',
|
||||
'run_template' => 'Run Template',
|
||||
'statement_design' => 'Statement Design',
|
||||
'delivery_note_design' => 'Delivery Note Design',
|
||||
'payment_receipt_design' => 'Payment Receipt Design',
|
||||
@ -5306,18 +5306,20 @@ $lang = array(
|
||||
'activity_140' => 'Statement sent to :client',
|
||||
'invoice_net_amount' => 'Invoice Net Amount',
|
||||
'round_to_minutes' => 'Round To Minutes',
|
||||
'1_second' => '1 Second',
|
||||
'1_minute' => '1 Minute',
|
||||
'5_minutes' => '5 Minutes',
|
||||
'15_minutes' => '15 Minutes',
|
||||
'30_minutes' => '30 Minutes',
|
||||
'1_hour' => '1 Hour',
|
||||
'1_day' => '1 Day',
|
||||
'round_tasks' => 'Round Tasks',
|
||||
'round_tasks_help' => 'Round time intervals when saving tasks',
|
||||
'round_tasks' => 'Task Rounding Direction',
|
||||
'round_tasks_help' => 'Round task times up or down.',
|
||||
'direction' => 'Direction',
|
||||
'round_up' => 'Round Up',
|
||||
'round_down' => 'Round Down',
|
||||
'task_round_to_nearest' => 'Round To Nearest',
|
||||
'task_round_to_nearest_help' => 'The interval to round the task to.',
|
||||
'bulk_updated' => 'Successfully updated data',
|
||||
'bulk_update' => 'Bulk Update',
|
||||
'calculate' => 'Calculate',
|
||||
@ -5328,9 +5330,10 @@ $lang = array(
|
||||
'disconnected' => 'Disconnected',
|
||||
'reconnect' => 'Reconnect',
|
||||
'e_invoice_settings' => 'E-Invoice Settings',
|
||||
'btcpay_refund_subject' => 'Refund of your invoice via BTCPay',
|
||||
'btcpay_refund_body' => 'A refund intended for you has been issued. To claim it via BTCPay, please click on this link:',
|
||||
'currency_mauritanian_ouguiya' => 'Mauritanian Ouguiya',
|
||||
'currency_bhutan_ngultrum' => 'Bhutan Ngultrum',
|
||||
|
||||
);
|
||||
|
||||
return $lang;
|
||||
return $lang;
|
@ -5322,6 +5322,12 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'money' => 'Argent',
|
||||
'web_app' => 'App web',
|
||||
'desktop_app' => 'App de bureau',
|
||||
'disconnected' => 'Déconnecté',
|
||||
'reconnect' => 'Reconnecté',
|
||||
'e_invoice_settings' => 'Paramètres E-Facture',
|
||||
'currency_mauritanian_ouguiya' => 'Ouguiya mauritanien',
|
||||
'currency_bhutan_ngultrum' => 'Ngultrum Bhoutan',
|
||||
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
1982
package-lock.json
generated
1982
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -9,18 +9,20 @@
|
||||
"@babel/compat-data": "7.15.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"cypress": "^12.5.1",
|
||||
"laravel-mix-purgecss": "^6.0.0",
|
||||
"laravel-vite-plugin": "^0.8.0",
|
||||
"postcss": "^8.4.35",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-static-copy": "^0.17.0",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/forms": "^0.3.4",
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"@tailwindcss/typography": "^0.4.1",
|
||||
"autoprefixer": "^10.3.7",
|
||||
"axios": "^0.25",
|
||||
"card-js": "^1.0.13",
|
||||
"card-validator": "^8.1.1",
|
||||
@ -31,11 +33,9 @@
|
||||
"laravel-mix": "^6.0.34",
|
||||
"linkify-urls": "^4.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"postcss": "^8.3.11",
|
||||
"resolve-url-loader": "^4.0.0",
|
||||
"sass": "^1.43.4",
|
||||
"sass-loader": "^12.3.0",
|
||||
"tailwindcss": "^2.2.17"
|
||||
"sass-loader": "^12.3.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
109
public/build/assets/app-8722f22d.js
vendored
Normal file
109
public/build/assets/app-8722f22d.js
vendored
Normal file
File diff suppressed because one or more lines are too long
109
public/build/assets/app-a52d5f77.js
vendored
109
public/build/assets/app-a52d5f77.js
vendored
File diff suppressed because one or more lines are too long
1
public/build/assets/app-c6dc74fe.css
vendored
1
public/build/assets/app-c6dc74fe.css
vendored
File diff suppressed because one or more lines are too long
1
public/build/assets/app-c7c5fad4.css
vendored
Normal file
1
public/build/assets/app-c7c5fad4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
||||
]
|
||||
},
|
||||
"resources/js/app.js": {
|
||||
"file": "assets/app-a52d5f77.js",
|
||||
"file": "assets/app-8722f22d.js",
|
||||
"imports": [
|
||||
"_index-08e160a7.js",
|
||||
"__commonjsHelpers-725317a4.js"
|
||||
@ -240,7 +240,7 @@
|
||||
"src": "resources/js/setup/setup.js"
|
||||
},
|
||||
"resources/sass/app.scss": {
|
||||
"file": "assets/app-c6dc74fe.css",
|
||||
"file": "assets/app-c7c5fad4.css",
|
||||
"isEntry": true,
|
||||
"src": "resources/sass/app.scss"
|
||||
}
|
||||
|
2
resources/sass/components/alerts.scss
vendored
2
resources/sass/components/alerts.scss
vendored
@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
@apply border-green-500;
|
||||
@apply border-emerald-500;
|
||||
}
|
||||
|
||||
.alert-failure {
|
||||
|
4
resources/sass/components/badge.scss
vendored
4
resources/sass/components/badge.scss
vendored
@ -15,7 +15,7 @@
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
@apply bg-green-100 text-green-500;
|
||||
@apply bg-emerald-100 text-emerald-500;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
@apply bg-blue-500 text-yellow-600;
|
||||
@apply bg-blue-500 text-amber-600;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
|
2
resources/sass/components/validation.scss
vendored
2
resources/sass/components/validation.scss
vendored
@ -7,5 +7,5 @@
|
||||
}
|
||||
|
||||
.validation-pass {
|
||||
@apply border-green-500 text-gray-700 text-sm;
|
||||
@apply border-emerald-500 text-gray-700 text-sm;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@
|
||||
|
||||
<div class="flex justify-between items-center mt-8">
|
||||
|
||||
<a href="{{route('client.login')}}" class="button button-info bg-green-600 text-white">{{ ctrans('texts.login_label') }}</a>
|
||||
<a href="{{route('client.login')}}" class="button button-info bg-emerald-600 text-white">{{ ctrans('texts.login_label') }}</a>
|
||||
|
||||
<span class="inline-flex items-center" x-data="{ terms_of_service: false, privacy_policy: false }">
|
||||
@if(!empty($register_company->settings->client_portal_terms) || !empty($register_company->settings->client_portal_privacy_policy))
|
||||
|
@ -25,7 +25,7 @@
|
||||
@foreach($multiple_contacts as $contact)
|
||||
<a data-turbolinks="false"
|
||||
href="{{ route('client.switch_company', $contact->hashed_id) }}"
|
||||
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ $contact->client->present()->name()}}
|
||||
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ $contact->client->present()->name()}} - ({{$contact->company->present()->name()}})
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
|
@ -250,7 +250,7 @@
|
||||
|
||||
@if($steps['passwordless_login_sent'])
|
||||
<span
|
||||
class="block mt-2 text-sm text-green-600">{!! ctrans('texts.sent') !!}</span>
|
||||
class="block mt-2 text-sm text-emerald-600">{!! ctrans('texts.sent') !!}</span>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
|
@ -15,22 +15,22 @@
|
||||
<table class="min-w-full shadow rounded border border-gray-200 mt-4 credits-table bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary task_description">
|
||||
<span role="button" wire:click="sortBy('description')" class="cursor-pointer">
|
||||
{{ ctrans('texts.description') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary task_project">
|
||||
<span role="button" wire:click="sortBy('description')" class="cursor-pointer">
|
||||
{{ ctrans('texts.project') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider task_status">
|
||||
<span role="button" wire:click="sortBy('status_id')" class="cursor-pointer">
|
||||
{{ ctrans('texts.status') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider task_duration">
|
||||
<span role="button" class="cursor-pointer">
|
||||
{{ ctrans('texts.duration') }}
|
||||
</span>
|
||||
@ -40,13 +40,13 @@
|
||||
<tbody>
|
||||
@foreach($tasks as $task)
|
||||
<tr class="bg-white group hover:bg-gray-100">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500 task_descripton">
|
||||
{{ \Illuminate\Support\Str::limit($task->description, 80) }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500 task_project">
|
||||
{{ $task->project?->name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500 task_status">
|
||||
<div class="flex">
|
||||
{!! $task->stringStatus() !!}
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500 task_duration">
|
||||
{{ \Carbon\CarbonInterval::seconds($task->calcDuration())->cascade()->forHumans() }}
|
||||
</td>
|
||||
</tr>
|
||||
@ -68,17 +68,17 @@
|
||||
<table class="min-w-full ml-5">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500">
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500 task_date">
|
||||
<span>
|
||||
{{ ctrans('texts.date') }}
|
||||
</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500">
|
||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500 task_duration">
|
||||
<span>
|
||||
{{ ctrans('texts.duration') }}
|
||||
</span>
|
||||
</th>
|
||||
<th colspan="4" class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500">
|
||||
<th colspan="4" class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-gray-500 task_description">
|
||||
<span>
|
||||
{{ ctrans('texts.description') }}
|
||||
</span>
|
||||
@ -89,13 +89,13 @@
|
||||
@foreach($task->processLogsExpandedNotation() as $log)
|
||||
@if(strlen($log['description']) > 1)
|
||||
<tr class="bg-white group border-b border-gray-100">
|
||||
<td class="px-6 py-4 text-sm leading-5 text-gray-500 w-1/6">
|
||||
<td class="px-6 py-4 text-sm leading-5 text-gray-500 w-1/6 task_date">
|
||||
{{ $log['start_date']}}
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm leading-5 text-gray-500 w-1/6">
|
||||
<td class="px-6 py-4 text-sm leading-5 text-gray-500 w-1/6 task_duration">
|
||||
{{ $log['duration']}}
|
||||
</td>
|
||||
<td colspan="4" class="px-6 py-4 text-sm leading-5 text-gray-500 w-4/6">
|
||||
<td colspan="4" class="px-6 py-4 text-sm leading-5 text-gray-500 w-4/6 task_description">
|
||||
{!! nl2br(e($log['description'])) !!}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -5,10 +5,10 @@
|
||||
<div class="flex flex-col xl:flex-row gap-4">
|
||||
<div class="w-full rounded-md border border-[#E5E7EB] bg-white p-5 text-sm text-[#6C727F]">
|
||||
<h3 class="mb-4 text-xl font-semibold text-[#212529]">{{ $contact->first_name }} {{ $contact->last_name }}</h3>
|
||||
<p class="mb-1.5">{{ $contact->phone }}</p>
|
||||
<p class="mb-4">{{ $client->address1 }}</p>
|
||||
<p class="mb-1.5">{{ $client->city }}, {{ $client->state }}</p>
|
||||
<p class="mb-1.5">{{ $client->postal_code }}</p>
|
||||
<p>{{ $contact->phone }}</p>
|
||||
<p>{{ $client->address1 }}</p>
|
||||
<p>{{ $client->city }}, {{ $client->state }}</p>
|
||||
<p>{{ $client->postal_code }}</p>
|
||||
<p>{{ App\Models\Country::find($client->country_id)?->name }}</p>
|
||||
</div>
|
||||
|
||||
@ -81,16 +81,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-light-grey-text flex grow basis-full flex-col justify-center pt-5 text-sm md:basis-1/2 md:border-r md:border-[#E5E7EB] md:pt-0 xl:basis-auto xl:px-5">
|
||||
<p class="mb-2">{{ $client->company->settings->address1 }}</p>
|
||||
<p class="mb-2">{{ $client->company->settings->address2 }}</p>
|
||||
<p class="mb-2">{{ $client->company->settings->postal_code }}</p>
|
||||
<div class="text-light-grey-text flex grow basis-full flex-col justify-center pt-5 text-sm md:basis-1/2 md:border-r md:border-[#E5E7EB] md:pt-0 xl:basis-auto xl:px-5 space-y-2">
|
||||
<p>{{ $client->company->settings->address1 }}</p>
|
||||
<p>{{ $client->company->settings->city }} {{ $client->company->settings->state }}</p>
|
||||
<p>{{ $client->company->settings->postal_code }}</p>
|
||||
<p>{{ App\Models\Country::find($client->company->settings->country_id)?->name }}</p>
|
||||
</div>
|
||||
<div class="text-light-grey-text flex grow basis-full flex-col justify-center text-sm md:basis-1/2 md:pl-4 xl:basis-auto xl:px-5">
|
||||
<p class="mb-2">{{ $client->company->settings->email }}</p>
|
||||
<p class="mb-2">{{ $client->company->settings->phone }}</p>
|
||||
<p>{{ $client->company->settings->website }}</p>
|
||||
|
||||
<div class="text-light-grey-text flex grow basis-full flex-col justify-center text-sm md:basis-1/2 md:pl-4 xl:basis-auto xl:px-5 space-y-2 mt-3 xl:mt-0">
|
||||
<p><span class="font-semibold">{{ ctrans('texts.vat') }}</span>: {{ $client->company->settings->vat_number }}</p>
|
||||
<p>
|
||||
<a class="underline" href="mailto:{{ $client->company->settings->email }}" target="_blank">{{ $client->company->settings->email }}</a>
|
||||
</p>
|
||||
<p>{{ $client->company->settings->phone }}</p>
|
||||
<p>
|
||||
<a class="underline" href="{{ $client->company->settings->website }}" target="_blank">
|
||||
{{ $client->company->settings->website }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
@if(Request::isSecure())
|
||||
<span class="block mx-4 mb-4 text-xs inline-flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-green-600"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-emerald-600"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
|
||||
<span class="ml-1">Secure 256-bit encryption</span>
|
||||
</span>
|
||||
@endif
|
||||
|
@ -56,7 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white shadow rounded-sm mb-4 mt-4 border-l-2 border-green-500" translate>
|
||||
<div class="bg-white shadow rounded-sm mb-4 mt-4 border-l-2 border-emerald-500" translate>
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<div>
|
||||
|
@ -1,27 +1,24 @@
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
|
||||
module.exports = {
|
||||
purge: [
|
||||
content: [
|
||||
'./resources/views/portal/ninja2020/**/*.blade.php',
|
||||
'./resources/views/email/template/**/*.blade.php',
|
||||
'./resources/views/email/components/**/*.blade.php',
|
||||
'./resources/views/themes/ninja2020/**/*.blade.php',
|
||||
'./resources/views/auth/**/*.blade.php',
|
||||
'./resources/views/setup/**/*.blade.php',
|
||||
'./resources/views/billing-portal/**/*.blade.php',
|
||||
'./resources/views/billing-portal/**/*.blade.php'
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ["Open Sans", ...defaultTheme.fontFamily.sans]
|
||||
}
|
||||
}
|
||||
sans: ['Open Sans', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {},
|
||||
plugins: [
|
||||
require('@tailwindcss/line-clamp'),
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
]
|
||||
|
||||
],
|
||||
};
|
||||
|
@ -28,6 +28,8 @@ class BankIntegrationApiTest extends TestCase
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
protected $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
@ -60,6 +60,7 @@ class DesignApiTest extends TestCase
|
||||
|
||||
$q = Design::query()
|
||||
->where('is_template', true)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereRaw('FIND_IN_SET( ? ,entities)', [$searchable]);
|
||||
|
||||
$this->assertEquals(1, $q->count());
|
||||
|
@ -42,7 +42,7 @@ class FatturaPATest extends TestCase
|
||||
$this->makeTestData();
|
||||
|
||||
|
||||
$this->markTestSkipped('prevent running in CI');
|
||||
// $this->markTestSkipped('prevent running in CI');
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
@ -56,9 +56,9 @@ class FatturaPATest extends TestCase
|
||||
$settings->address1 = 'Via Silvio Spaventa 108';
|
||||
$settings->city = 'Calcinelli';
|
||||
|
||||
$settings->state = 'PA';
|
||||
$settings->state = 'PA';
|
||||
|
||||
// $settings->state = 'Perugia';
|
||||
// $settings->state = 'Perugia';
|
||||
$settings->postal_code = '61030';
|
||||
$settings->country_id = '380';
|
||||
$settings->currency_id = '3';
|
||||
@ -129,6 +129,9 @@ $settings->state = 'PA';
|
||||
$encoder = new Encode($fe);
|
||||
$xml = $encoder->toXml();
|
||||
|
||||
|
||||
nlog($xml);
|
||||
|
||||
$this->assertNotNull($xml);
|
||||
|
||||
|
||||
|
@ -11,17 +11,18 @@
|
||||
|
||||
namespace Tests\Feature\Notify;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\CompanyUser;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\Product;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\Notifications\UserNotifies;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use App\Models\User;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use Tests\MockAccountData;
|
||||
use App\Models\CompanyUser;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Utils\Traits\Notifications\UserNotifies;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -32,6 +33,8 @@ class NotificationTest extends TestCase
|
||||
use UserNotifies;
|
||||
use MockAccountData;
|
||||
|
||||
protected $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
@ -27,6 +27,7 @@ class ShopInvoiceTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use MockAccountData;
|
||||
protected $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
|
@ -48,4 +48,60 @@ class ShopProfileTest extends TestCase
|
||||
$this->assertArrayHasKey('custom_value1', $arr['data']['settings']);
|
||||
$this->assertEquals($this->company->company_key, $arr['data']['company_key']);
|
||||
}
|
||||
|
||||
public function testProfileSettingsUpdate()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
|
||||
$settings = $this->company->settings;
|
||||
|
||||
$trans = new \stdClass;
|
||||
$trans->product = "Service";
|
||||
$trans->products = "Services";
|
||||
|
||||
$settings->translations = $trans;
|
||||
$this->company->settings = $settings;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key,
|
||||
])->getJson('/api/v1/shop/profile');
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals("Service", $arr['data']['settings']['product']);
|
||||
$this->assertEquals("Services", $arr['data']['settings']['products']);
|
||||
|
||||
}
|
||||
|
||||
public function testProfileSettingsUpdate2()
|
||||
{
|
||||
|
||||
$this->company->enable_shop_api = true;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-COMPANY-KEY' => $this->company->company_key,
|
||||
])->getJson('/api/v1/shop/profile');
|
||||
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals("Product", $arr['data']['settings']['product']);
|
||||
$this->assertEquals("Products", $arr['data']['settings']['products']);
|
||||
$this->assertIsArray($arr['data']['settings']['client_registration_fields']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -11,12 +11,13 @@
|
||||
|
||||
namespace Tests\Unit\ValidationRules;
|
||||
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use Tests\TestCase;
|
||||
use App\Models\Invoice;
|
||||
use Tests\MockAccountData;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
* @test
|
||||
|
Loading…
Reference in New Issue
Block a user