commit
4ff745de82
|
|
@ -1 +1 @@
|
||||||
5.11.23
|
5.11.24
|
||||||
|
|
@ -172,6 +172,7 @@ class SwissQrGenerator
|
||||||
->setPrintable(false)
|
->setPrintable(false)
|
||||||
->getPaymentPart();
|
->getPaymentPart();
|
||||||
|
|
||||||
|
// return $html;
|
||||||
return htmlspecialchars($html);
|
return htmlspecialchars($html);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,14 +106,14 @@ class InvoiceController extends Controller
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(200000);
|
usleep(300000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation = false;
|
$invitation = false;
|
||||||
|
|
||||||
match($data['entity_type'] ?? 'invoice') {
|
match($data['entity_type'] ?? 'invoice') {
|
||||||
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']), //@todo - sometimes this is false!!
|
||||||
'quote' => $invitation = QuoteInvitation::withTrashed()->find($data['invitation_id']),
|
'quote' => $invitation = QuoteInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
'credit' => $invitation = CreditInvitation::withTrashed()->find($data['invitation_id']),
|
'credit' => $invitation = CreditInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,10 @@ class UpdateCompanyRequest extends Request
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
foreach ($this->protected_input as $protected_var) {
|
foreach ($this->protected_input as $protected_var) {
|
||||||
$settings[$protected_var] = str_replace("script", "", $settings[$protected_var]);
|
|
||||||
|
if(isset($settings[$protected_var])) {
|
||||||
|
$settings[$protected_var] = str_replace("script", "", $settings[$protected_var]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ namespace App\Http\Requests\RecurringInvoice;
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
||||||
use App\Http\ValidationRules\Recurring\UniqueRecurringInvoiceNumberRule;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Utils\Traits\CleanLineItems;
|
use App\Utils\Traits\CleanLineItems;
|
||||||
|
|
@ -68,7 +67,7 @@ class StoreRecurringInvoiceRequest extends Request
|
||||||
|
|
||||||
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
||||||
|
|
||||||
$rules['number'] = new UniqueRecurringInvoiceNumberRule($this->all());
|
$rules['number'] = ['bail', 'nullable', \Illuminate\Validation\Rule::unique('recurring_invoices')->where('company_id', $user->company()->id)];
|
||||||
|
|
||||||
$rules['tax_rate1'] = 'bail|sometimes|numeric';
|
$rules['tax_rate1'] = 'bail|sometimes|numeric';
|
||||||
$rules['tax_rate2'] = 'bail|sometimes|numeric';
|
$rules['tax_rate2'] = 'bail|sometimes|numeric';
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
namespace App\Http\Requests\RecurringQuote;
|
namespace App\Http\Requests\RecurringQuote;
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Http\ValidationRules\Recurring\UniqueRecurringQuoteNumberRule;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\RecurringQuote;
|
use App\Models\RecurringQuote;
|
||||||
use App\Utils\Traits\CleanLineItems;
|
use App\Utils\Traits\CleanLineItems;
|
||||||
|
|
@ -63,7 +62,7 @@ class StoreRecurringQuoteRequest extends Request
|
||||||
|
|
||||||
$rules['frequency_id'] = 'required|integer|digits_between:1,12';
|
$rules['frequency_id'] = 'required|integer|digits_between:1,12';
|
||||||
|
|
||||||
$rules['number'] = new UniqueRecurringQuoteNumberRule($this->all());
|
$rules['number'] = ['bail', 'nullable', \Illuminate\Validation\Rule::unique('recurring_quotes')->where('company_id', $user->company()->id)];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
<?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\Http\ValidationRules\Recurring;
|
|
||||||
|
|
||||||
use App\Models\RecurringInvoice;
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class UniqueRecurringInvoiceNumberRule.
|
|
||||||
*/
|
|
||||||
class UniqueRecurringInvoiceNumberRule implements Rule
|
|
||||||
{
|
|
||||||
public $input;
|
|
||||||
|
|
||||||
public function __construct($input)
|
|
||||||
{
|
|
||||||
$this->input = $input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $attribute
|
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value)
|
|
||||||
{
|
|
||||||
return $this->checkIfInvoiceNumberUnique(); //if it exists, return false!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function message()
|
|
||||||
{
|
|
||||||
return ctrans('texts.recurring_invoice_number_taken', ['number' => $this->input['number']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function checkIfInvoiceNumberUnique(): bool
|
|
||||||
{
|
|
||||||
if (empty($this->input['number'])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice = RecurringInvoice::query()->where('client_id', $this->input['client_id'])
|
|
||||||
->where('number', $this->input['number'])
|
|
||||||
->withTrashed()
|
|
||||||
->exists();
|
|
||||||
|
|
||||||
if ($invoice) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Quote Ninja (https://invoiceninja.com).
|
|
||||||
*
|
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2022. Quote Ninja LLC (https://invoiceninja.com)
|
|
||||||
*
|
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\ValidationRules\Recurring;
|
|
||||||
|
|
||||||
use App\Models\RecurringQuote;
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class UniqueRecurringQuoteNumberRule.
|
|
||||||
*/
|
|
||||||
class UniqueRecurringQuoteNumberRule implements Rule
|
|
||||||
{
|
|
||||||
public $input;
|
|
||||||
|
|
||||||
public function __construct($input)
|
|
||||||
{
|
|
||||||
$this->input = $input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $attribute
|
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value)
|
|
||||||
{
|
|
||||||
return $this->checkIfQuoteNumberUnique(); //if it exists, return false!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function message()
|
|
||||||
{
|
|
||||||
return ctrans('texts.recurring_quote_number_taken', ['number' => $this->input['number']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function checkIfQuoteNumberUnique(): bool
|
|
||||||
{
|
|
||||||
if (empty($this->input['number'])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice = RecurringQuote::query()->where('client_id', $this->input['client_id'])
|
|
||||||
->where('number', $this->input['number'])
|
|
||||||
->withTrashed()
|
|
||||||
->exists();
|
|
||||||
|
|
||||||
if ($invoice) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -515,7 +515,7 @@ class NinjaMailerJob implements ShouldQueue
|
||||||
private function checkValidSendingUser($user)
|
private function checkValidSendingUser($user)
|
||||||
{
|
{
|
||||||
/* Always ensure the user is set on the correct account */
|
/* Always ensure the user is set on the correct account */
|
||||||
if ($user->account_id != $this->company->account_id) {
|
if (!$user ||($user->account_id != $this->company->account_id)) {
|
||||||
$this->nmo->settings->email_sending_method = 'default';
|
$this->nmo->settings->email_sending_method = 'default';
|
||||||
return $this->setMailDriver();
|
return $this->setMailDriver();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,9 @@ class InvoicePay extends Component
|
||||||
|
|
||||||
$company_gateway = CompanyGateway::query()->find($company_gateway_id);
|
$company_gateway = CompanyGateway::query()->find($company_gateway_id);
|
||||||
|
|
||||||
|
if(!$company_gateway)
|
||||||
|
return $this->required_fields = false;
|
||||||
|
|
||||||
$this->checkRequiredFields($company_gateway);
|
$this->checkRequiredFields($company_gateway);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,10 @@ class AuthorizeTransaction
|
||||||
$transactionRequestType->setOrder($order);
|
$transactionRequestType->setOrder($order);
|
||||||
$transactionRequestType->addToTransactionSettings($duplicateWindowSetting);
|
$transactionRequestType->addToTransactionSettings($duplicateWindowSetting);
|
||||||
|
|
||||||
|
$solution = new \net\authorize\api\contract\v1\SolutionType();
|
||||||
|
$solution->setId($this->authorize->company_gateway->getConfigField('testMode') ? 'AAA100303' : 'AAA172036');
|
||||||
|
$transactionRequestType->setSolution($solution);
|
||||||
|
|
||||||
$transactionRequestType->setPayment($paymentOne);
|
$transactionRequestType->setPayment($paymentOne);
|
||||||
$transactionRequestType->setCurrencyCode($this->authorize->client->currency()->code);
|
$transactionRequestType->setCurrencyCode($this->authorize->client->currency()->code);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,10 @@ class ChargePaymentProfile
|
||||||
$transactionRequestType->setProfile($profileToCharge);
|
$transactionRequestType->setProfile($profileToCharge);
|
||||||
$transactionRequestType->setCurrencyCode($this->authorize->client->currency()->code);
|
$transactionRequestType->setCurrencyCode($this->authorize->client->currency()->code);
|
||||||
|
|
||||||
|
$solution = new \net\authorize\api\contract\v1\SolutionType();
|
||||||
|
$solution->setId($this->authorize->company_gateway->getConfigField('testMode') ? 'AAA100303' : 'AAA172036');
|
||||||
|
$transactionRequestType->setSolution($solution);
|
||||||
|
|
||||||
$request = new CreateTransactionRequest();
|
$request = new CreateTransactionRequest();
|
||||||
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
||||||
$request->setRefId($refId);
|
$request->setRefId($refId);
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,10 @@ class RefundTransaction
|
||||||
$transactionRequest->setPayment($paymentOne);
|
$transactionRequest->setPayment($paymentOne);
|
||||||
$transactionRequest->setRefTransId($payment->transaction_reference);
|
$transactionRequest->setRefTransId($payment->transaction_reference);
|
||||||
|
|
||||||
|
$solution = new \net\authorize\api\contract\v1\SolutionType();
|
||||||
|
$solution->setId($this->authorize->company_gateway->getConfigField('testMode') ? 'AAA100303' : 'AAA172036');
|
||||||
|
$transactionRequest->setSolution($solution);
|
||||||
|
|
||||||
$request = new CreateTransactionRequest();
|
$request = new CreateTransactionRequest();
|
||||||
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
||||||
$request->setRefId($refId);
|
$request->setRefId($refId);
|
||||||
|
|
|
||||||
|
|
@ -691,7 +691,7 @@ class Email implements ShouldQueue
|
||||||
private function checkValidSendingUser($user)
|
private function checkValidSendingUser($user)
|
||||||
{
|
{
|
||||||
/* Always ensure the user is set on the correct account */
|
/* Always ensure the user is set on the correct account */
|
||||||
if ($user->account_id != $this->company->account_id) {
|
if (!$user || ($user->account_id != $this->company->account_id)) {
|
||||||
$this->email_object->settings->email_sending_method = 'default';
|
$this->email_object->settings->email_sending_method = 'default';
|
||||||
|
|
||||||
return $this->setMailDriver();
|
return $this->setMailDriver();
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ class PdfBuilder
|
||||||
$outstanding = $this->service->options['invoices']->sum('balance');
|
$outstanding = $this->service->options['invoices']->sum('balance');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => '$outstanding_label: ' . $this->service->config->formatMoney($outstanding)],
|
['element' => 'div', 'content' => '$outstanding_label: ' . $this->service->config->formatMoney($outstanding)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,7 +402,7 @@ class PdfBuilder
|
||||||
$outstanding = $this->service->options['credits']->sum('balance');
|
$outstanding = $this->service->options['credits']->sum('balance');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => '$credit.balance_label: ' . $this->service->config->formatMoney($outstanding)],
|
['element' => 'div', 'content' => '$credit.balance_label: ' . $this->service->config->formatMoney($outstanding)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,7 +474,7 @@ class PdfBuilder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'thead', 'elements' => $this->buildTableHeader('statement_payment')],
|
['element' => 'thead', 'elements' => $this->buildTableHeader('statement_payment')],
|
||||||
['element' => 'tbody', 'elements' => $tbody],
|
['element' => 'tbody', 'elements' => $tbody],
|
||||||
|
|
@ -500,9 +500,9 @@ class PdfBuilder
|
||||||
$payment = $this->service->options['payments']->first();
|
$payment = $this->service->options['payments']->first();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), $this->service->config->formatMoney($this->payment_amount_total))],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), $this->service->config->formatMoney($this->payment_amount_total))],
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_method'), $payment->translatedType())],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_method'), $payment->translatedType())],
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_date'), $this->translateDate($payment->date, $this->service->config->date_format, $this->service->config->locale) ?: ' ')],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_date'), $this->translateDate($payment->date, $this->service->config->date_format, $this->service->config->locale) ?: ' ')],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -520,9 +520,9 @@ class PdfBuilder
|
||||||
$payment = $this->service->options['unapplied']->first();
|
$payment = $this->service->options['unapplied']->first();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_balance'), $this->service->config->formatMoney($this->unapplied_total))],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_balance'), $this->service->config->formatMoney($this->unapplied_total))],
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_method'), $payment->translatedType())],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_method'), $payment->translatedType())],
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_date'), $this->translateDate($payment->date, $this->service->config->date_format, $this->service->config->locale) ?: ' ')],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_date'), $this->translateDate($payment->date, $this->service->config->date_format, $this->service->config->locale) ?: ' ')],
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -866,7 +866,6 @@ class PdfBuilder
|
||||||
$element['elements'][$last_visible]['properties']['class'] .= ' right-radius';
|
$element['elements'][$last_visible]['properties']['class'] .= ' right-radius';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Then, filter the elements array
|
// Then, filter the elements array
|
||||||
$element['elements'] = array_map(function ($el) {
|
$element['elements'] = array_map(function ($el) {
|
||||||
|
|
@ -1405,7 +1404,7 @@ class PdfBuilder
|
||||||
['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
|
['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
|
||||||
]],
|
]],
|
||||||
['element' => 'div', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
|
['element' => 'div', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
|
||||||
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "text-align: left; margin-top: 1rem; {$show_terms_label}"]],
|
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight:bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]],
|
||||||
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
||||||
]],
|
]],
|
||||||
['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']],
|
['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']],
|
||||||
|
|
@ -1761,20 +1760,20 @@ class PdfBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
$elements = [
|
$elements = [
|
||||||
['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
['element' => 'div', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
||||||
['element' => 'p', 'content' => $this->service->config->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
|
['element' => 'div', 'content' => $this->service->config->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
|
||||||
['element' => 'p', 'content' => $this->service->config->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']],
|
['element' => 'div', 'content' => $this->service->config->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']],
|
||||||
['element' => 'p', 'content' => $this->service->config->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']],
|
['element' => 'div', 'content' => $this->service->config->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']],
|
||||||
['element' => 'p', 'show_empty' => false, 'elements' => [
|
['element' => 'div', 'show_empty' => false, 'elements' => [
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']],
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']],
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']],
|
||||||
]],
|
]],
|
||||||
['element' => 'p', 'content' => optional($this->service->config->client->shipping_country)->name, 'show_empty' => false],
|
['element' => 'div', 'content' => optional($this->service->config->client->shipping_country)->name, 'show_empty' => false],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!is_null($this->service->config->contact)) {
|
if (!is_null($this->service->config->contact)) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $this->service->config->contact->email, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-contact.email']];
|
$elements[] = ['element' => 'div', 'content' => $this->service->config->contact->email, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-contact.email']];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1796,7 +1795,7 @@ class PdfBuilder
|
||||||
$variables = $this->service->config->pdf_variables['client_details'];
|
$variables = $this->service->config->pdf_variables['client_details'];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'client_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'client_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1811,16 +1810,16 @@ class PdfBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
$elements = [
|
$elements = [
|
||||||
['element' => 'p', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
['element' => 'div', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
||||||
// ['element' => 'p', 'content' => $this->service->config->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.name']],
|
// ['element' => 'div', 'content' => $this->service->config->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.name']],
|
||||||
['element' => 'p', 'content' => $this->service->config->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.shipping_address1']],
|
['element' => 'div', 'content' => $this->service->config->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.shipping_address1']],
|
||||||
['element' => 'p', 'content' => $this->service->config->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.shipping_address2']],
|
['element' => 'div', 'content' => $this->service->config->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'shipping_address-client.shipping_address2']],
|
||||||
['element' => 'p', 'show_empty' => false, 'elements' => [
|
['element' => 'div', 'show_empty' => false, 'elements' => [
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_city} ", 'properties' => ['ref' => 'shipping_address-client.shipping_city']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_city} ", 'properties' => ['ref' => 'shipping_address-client.shipping_city']],
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_state} ", 'properties' => ['ref' => 'shipping_address-client.shipping_state']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_state} ", 'properties' => ['ref' => 'shipping_address-client.shipping_state']],
|
||||||
['element' => 'span', 'content' => "{$this->service->config->client->shipping_postal_code} ", 'properties' => ['ref' => 'shipping_address-client.shipping_postal_code']],
|
['element' => 'span', 'content' => "{$this->service->config->client->shipping_postal_code} ", 'properties' => ['ref' => 'shipping_address-client.shipping_postal_code']],
|
||||||
]],
|
]],
|
||||||
['element' => 'p', 'content' => optional($this->service->config->client->shipping_country)->name, 'show_empty' => false],
|
['element' => 'div', 'content' => optional($this->service->config->client->shipping_country)->name, 'show_empty' => false],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1899,7 +1898,7 @@ class PdfBuilder
|
||||||
$elements = [];
|
$elements = [];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1919,7 +1918,7 @@ class PdfBuilder
|
||||||
$elements = [];
|
$elements = [];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_address-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_address-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1939,7 +1938,7 @@ class PdfBuilder
|
||||||
$variables = $this->service->config->pdf_variables['vendor_details'];
|
$variables = $this->service->config->pdf_variables['vendor_details'];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'vendor_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'vendor_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -1997,23 +1996,49 @@ class PdfBuilder
|
||||||
public function createElementContent($element, $children): self
|
public function createElementContent($element, $children): self
|
||||||
{
|
{
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
|
|
||||||
$contains_html = false;
|
$contains_html = false;
|
||||||
|
$contains_markdown = false;
|
||||||
|
$child['content'] = $child['content'] ?? '';
|
||||||
|
|
||||||
if ($child['element'] !== 'script') {
|
$lines = explode("\n", $child['content']);
|
||||||
if ($this->service->company->markdown_enabled && array_key_exists('content', $child)) {
|
$contains_markdown = false;
|
||||||
$child['content'] = str_replace('<br>', "\r", ($child['content'] ?? ''));
|
|
||||||
$child['content'] = $this->commonmark->convert($child['content'] ?? ''); //@phpstan-ignore-line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($child['content'])) {
|
foreach ($lines as $line) {
|
||||||
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
$trimmed = ltrim($line);
|
||||||
|
if (empty($trimmed)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contains_html = preg_match('#(?<=<)\w+(?=[^<]*?>)#', $child['content'], $m) != 0;
|
$first_char = substr($trimmed, 0, 1);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$first_char === '#' || // Headers
|
||||||
|
$first_char === '>' || // Blockquotes
|
||||||
|
$first_char === '-' || // Lists
|
||||||
|
$first_char === '*' || // Lists/Bold
|
||||||
|
$first_char === '_' || // Italic
|
||||||
|
$first_char === '`' || // Code
|
||||||
|
$first_char === '[' || // Links
|
||||||
|
str_contains($trimmed, '**') // Bold (special case)
|
||||||
|
) {
|
||||||
|
$contains_markdown = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->service->company->markdown_enabled && $contains_markdown && $child['element'] !== 'script') {
|
||||||
|
$child['content'] = str_ireplace('<br>', "\r", $child['content']);
|
||||||
|
$child['content'] = $this->commonmark->convert($child['content']); //@phpstan-ignore-line
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contains_html = str_contains($child['content'], '<') && str_contains($child['content'], '>');
|
||||||
|
|
||||||
|
|
||||||
if ($contains_html) {
|
if ($contains_html) {
|
||||||
|
|
||||||
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
||||||
|
|
@ -2030,7 +2055,7 @@ class PdfBuilder
|
||||||
// .. in case string doesn't contain any HTML, we'll just return
|
// .. in case string doesn't contain any HTML, we'll just return
|
||||||
// raw $content
|
// raw $content
|
||||||
|
|
||||||
$_child = $this->document->createElement($child['element'], isset($child['content']) ? htmlspecialchars($child['content']) : '');
|
$_child = $this->document->createElement($child['element'], htmlspecialchars($child['content']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$element->appendChild($_child);
|
$element->appendChild($_child);
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@ class Design extends BaseDesign
|
||||||
$elements = [];
|
$elements = [];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -254,7 +254,7 @@ class Design extends BaseDesign
|
||||||
$elements = [];
|
$elements = [];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_address-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_address-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -271,7 +271,7 @@ class Design extends BaseDesign
|
||||||
$variables = $this->context['pdf_variables']['vendor_details'];
|
$variables = $this->context['pdf_variables']['vendor_details'];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'vendor_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'vendor_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -301,12 +301,12 @@ class Design extends BaseDesign
|
||||||
})->map(function ($variable) {
|
})->map(function ($variable) {
|
||||||
|
|
||||||
$variable = str_replace('$client.', '$client.shipping_', $variable);
|
$variable = str_replace('$client.', '$client.shipping_', $variable);
|
||||||
return ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => "client_details-shipping-" . substr($variable, 1)]];
|
return ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => "client_details-shipping-" . substr($variable, 1)]];
|
||||||
|
|
||||||
})->toArray();
|
})->toArray();
|
||||||
|
|
||||||
$header = [];
|
$header = [];
|
||||||
$header[] = ['element' => 'p', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']];
|
$header[] = ['element' => 'div', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']];
|
||||||
|
|
||||||
return array_merge($header, $elements);
|
return array_merge($header, $elements);
|
||||||
|
|
||||||
|
|
@ -322,20 +322,20 @@ class Design extends BaseDesign
|
||||||
|
|
||||||
if ($this->type == self::DELIVERY_NOTE) {
|
if ($this->type == self::DELIVERY_NOTE) {
|
||||||
$elements = [
|
$elements = [
|
||||||
['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
['element' => 'div', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
|
||||||
['element' => 'p', 'content' => $this->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
|
['element' => 'div', 'content' => $this->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
|
||||||
['element' => 'p', 'content' => $this->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']],
|
['element' => 'div', 'content' => $this->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']],
|
||||||
['element' => 'p', 'content' => $this->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']],
|
['element' => 'div', 'content' => $this->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']],
|
||||||
['element' => 'p', 'show_empty' => false, 'elements' => [
|
['element' => 'div', 'show_empty' => false, 'elements' => [
|
||||||
['element' => 'span', 'content' => "{$this->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']],
|
['element' => 'span', 'content' => "{$this->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']],
|
||||||
['element' => 'span', 'content' => "{$this->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']],
|
['element' => 'span', 'content' => "{$this->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']],
|
||||||
['element' => 'span', 'content' => "{$this->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']],
|
['element' => 'span', 'content' => "{$this->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']],
|
||||||
]],
|
]],
|
||||||
['element' => 'p', 'content' => optional($this->client->shipping_country)->name, 'show_empty' => false],
|
['element' => 'div', 'content' => optional($this->client->shipping_country)->name, 'show_empty' => false],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!is_null($this->context['contact'])) {
|
if (!is_null($this->context['contact'])) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $this->context['contact']->email, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-contact.email']];
|
$elements[] = ['element' => 'div', 'content' => $this->context['contact']->email, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-contact.email']];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -344,7 +344,7 @@ class Design extends BaseDesign
|
||||||
$variables = $this->context['pdf_variables']['client_details'];
|
$variables = $this->context['pdf_variables']['client_details'];
|
||||||
|
|
||||||
foreach ($variables as $variable) {
|
foreach ($variables as $variable) {
|
||||||
$elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'client_details-' . substr($variable, 1)]];
|
$elements[] = ['element' => 'div', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'client_details-' . substr($variable, 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $elements;
|
return $elements;
|
||||||
|
|
@ -553,7 +553,7 @@ class Design extends BaseDesign
|
||||||
$outstanding = $this->invoices->sum('balance');
|
$outstanding = $this->invoices->sum('balance');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->client)],
|
['element' => 'div', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->client)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,7 +682,7 @@ class Design extends BaseDesign
|
||||||
$outstanding = $this->credits->sum('balance');
|
$outstanding = $this->credits->sum('balance');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => '$credit.balance_label: ' . Number::formatMoney($outstanding, $this->client)],
|
['element' => 'div', 'content' => '$credit.balance_label: ' . Number::formatMoney($outstanding, $this->client)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -699,8 +699,8 @@ class Design extends BaseDesign
|
||||||
$payment = $this->payments->first();
|
$payment = $this->payments->first();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $this->client))],
|
// ['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $this->client))],
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payment_amount_total, $this->client))],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payment_amount_total, $this->client))],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -716,7 +716,7 @@ class Design extends BaseDesign
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.payment_balance_on_file'), Number::formatMoney($this->unapplied_total, $this->client))],
|
['element' => 'div', 'content' => \sprintf('%s: %s', ctrans('texts.payment_balance_on_file'), Number::formatMoney($this->unapplied_total, $this->client))],
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1127,10 +1127,10 @@ class Design extends BaseDesign
|
||||||
|
|
||||||
$elements = [
|
$elements = [
|
||||||
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
|
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
|
||||||
['element' => 'p', 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;'], 'elements' => [
|
['element' => 'div', 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;'], 'elements' => [
|
||||||
['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
|
['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
|
||||||
]],
|
]],
|
||||||
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
|
['element' => 'div', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
|
||||||
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight: bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]],
|
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight: bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]],
|
||||||
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
||||||
]],
|
]],
|
||||||
|
|
|
||||||
|
|
@ -91,22 +91,46 @@ trait PdfMakerUtilities
|
||||||
{
|
{
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
$contains_html = false;
|
$contains_html = false;
|
||||||
|
$contains_markdown = false;
|
||||||
|
$child['content'] = $child['content'] ?? '';
|
||||||
|
|
||||||
if ($child['element'] !== 'script') {
|
$lines = explode("\n", $child['content']);
|
||||||
if (array_key_exists('process_markdown', $this->data) && array_key_exists('content', $child) && $this->data['process_markdown']) {
|
$contains_markdown = false;
|
||||||
$child['content'] = str_replace('<br>', "\r", ($child['content'] ?? ''));
|
|
||||||
$child['content'] = $this->commonmark->convert($child['content'] ?? ''); //@phpstan-ignore-line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($child['content'])) {
|
foreach ($lines as $line) {
|
||||||
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
$trimmed = ltrim($line);
|
||||||
|
if (empty($trimmed)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contains_html = preg_match('#(?<=<)\w+(?=[^<]*?>)#', $child['content'], $m) != 0;
|
$first_char = substr($trimmed, 0, 1);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$first_char === '#' || // Headers
|
||||||
|
$first_char === '>' || // Blockquotes
|
||||||
|
$first_char === '-' || // Lists
|
||||||
|
$first_char === '*' || // Lists/Bold
|
||||||
|
$first_char === '_' || // Italic
|
||||||
|
$first_char === '`' || // Code
|
||||||
|
$first_char === '[' || // Links
|
||||||
|
str_contains($trimmed, '**') // Bold (special case)
|
||||||
|
) {
|
||||||
|
$contains_markdown = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($this->data['process_markdown']) && $this->data['process_markdown'] && $contains_markdown &&$child['element'] !== 'script') {
|
||||||
|
$child['content'] = str_replace('<br>', "\r", $child['content']);
|
||||||
|
$child['content'] = $this->commonmark->convert($child['content']); //@phpstan-ignore-line
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contains_html = str_contains($child['content'], '<') && str_contains($child['content'], '>');
|
||||||
|
|
||||||
if ($contains_html) {
|
if ($contains_html) {
|
||||||
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
||||||
// encode it for us, preventing any errors on the processing stage.
|
// encode it for us, preventing any errors on the processing stage.
|
||||||
|
|
@ -118,9 +142,7 @@ trait PdfMakerUtilities
|
||||||
$_child->nodeValue = htmlspecialchars($child['content']);
|
$_child->nodeValue = htmlspecialchars($child['content']);
|
||||||
} else {
|
} else {
|
||||||
// .. in case string doesn't contain any HTML, we'll just return
|
// .. in case string doesn't contain any HTML, we'll just return
|
||||||
// raw $content.
|
$_child = $this->document->createElement($child['element'], htmlspecialchars($child['content']));
|
||||||
|
|
||||||
$_child = $this->document->createElement($child['element'], isset($child['content']) ? htmlspecialchars($child['content']) : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$element->appendChild($_child);
|
$element->appendChild($_child);
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class TemplateService
|
||||||
|
|
||||||
private ?Vendor $vendor = null;
|
private ?Vendor $vendor = null;
|
||||||
|
|
||||||
private Invoice | Quote | Credit | PurchaseOrder | RecurringInvoice | Task | Project $entity;
|
private Invoice | Quote | Credit | PurchaseOrder | RecurringInvoice | Task | Project | Payment $entity;
|
||||||
|
|
||||||
private Payment $payment;
|
private Payment $payment;
|
||||||
|
|
||||||
|
|
@ -1575,23 +1575,14 @@ class TemplateService
|
||||||
|
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
$contains_html = false;
|
$contains_html = false;
|
||||||
|
$child['content'] = $child['content'] ?? '';
|
||||||
|
|
||||||
//06-11-2023 for some reason this parses content as HTML
|
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
||||||
// if ($child['element'] !== 'script') {
|
continue;
|
||||||
// if ($this->company->markdown_enabled && array_key_exists('content', $child)) {
|
|
||||||
// $child['content'] = str_replace('<br>', "\r", $child['content']);
|
|
||||||
// $child['content'] = $this->commonmark->convert($child['content'] ?? '');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (isset($child['content'])) {
|
|
||||||
if (isset($child['is_empty']) && $child['is_empty'] === true) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$contains_html = preg_match('#(?<=<)\w+(?=[^<]*?>)#', $child['content'], $m) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$contains_html = str_contains($child['content'], '<') && str_contains($child['content'], '>');
|
||||||
|
|
||||||
if ($contains_html) {
|
if ($contains_html) {
|
||||||
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
// If the element contains the HTML, we gonna display it as is. Backend is going to
|
||||||
// encode it for us, preventing any errors on the processing stage.
|
// encode it for us, preventing any errors on the processing stage.
|
||||||
|
|
@ -1605,7 +1596,7 @@ class TemplateService
|
||||||
} else {
|
} else {
|
||||||
// .. in case string doesn't contain any HTML, we'll just return
|
// .. in case string doesn't contain any HTML, we'll just return
|
||||||
// raw $content.
|
// raw $content.
|
||||||
$_child = $this->document->createElement($child['element'], isset($child['content']) ? $child['content'] : '');
|
$_child = $this->document->createElement($child['element'], $child['content']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$element->appendChild($_child);
|
$element->appendChild($_child);
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,14 @@ trait ClientGroupSettingsSaver
|
||||||
unset($settings[$field]);
|
unset($settings[$field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$company_settings_stub = new CompanySettings();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for clients and group settings, if a field is not set or is set to a blank value,
|
* for clients and group settings, if a field is not set or is set to a blank value,
|
||||||
* we unset it from the settings object
|
* we unset it from the settings object
|
||||||
*/
|
*/
|
||||||
foreach ($settings as $key => $value) {
|
foreach ($settings as $key => $value) {
|
||||||
if (! isset($settings->{$key}) || empty($settings->{$key}) || (! is_object($settings->{$key}) && strlen($settings->{$key}) == 0)) {
|
if (! isset($settings->{$key}) || empty($settings->{$key}) || !property_exists($company_settings_stub, $key) || (! is_object($settings->{$key}) && strlen($settings->{$key}) == 0)) {
|
||||||
unset($settings->{$key});
|
unset($settings->{$key});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ trait PdfMaker
|
||||||
}
|
}
|
||||||
|
|
||||||
$html = str_ireplace(['file:/', 'iframe', '<embed', '<embed', '<object', '<object', '127.0.0.1', 'localhost', '<?xml encoding="UTF-8">'], '', $html);
|
$html = str_ireplace(['file:/', 'iframe', '<embed', '<embed', '<object', '<object', '127.0.0.1', 'localhost', '<?xml encoding="UTF-8">'], '', $html);
|
||||||
|
|
||||||
|
// nlog($html);
|
||||||
$generated = $pdf
|
$generated = $pdf
|
||||||
->setHtml($html)
|
->setHtml($html)
|
||||||
->generate();
|
->generate();
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ return [
|
||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => env('APP_VERSION', '5.11.23'),
|
'app_version' => env('APP_VERSION', '5.11.24'),
|
||||||
'app_tag' => env('APP_TAG', '5.11.23'),
|
'app_tag' => env('APP_TAG', '5.11.24'),
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', false),
|
'api_secret' => env('API_SECRET', false),
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ $lang = array(
|
||||||
'invoice' => 'Rechnung',
|
'invoice' => 'Rechnung',
|
||||||
'client' => 'Kunde',
|
'client' => 'Kunde',
|
||||||
'invoice_number' => 'Rechnungsnummer',
|
'invoice_number' => 'Rechnungsnummer',
|
||||||
'invoice_number_short' => 'Re-Nr.',
|
'invoice_number_short' => 'Rechnung ',
|
||||||
'po_number' => 'Bestellnummer',
|
'po_number' => 'Bestellnummer',
|
||||||
'po_number_short' => 'Best.-Nr.',
|
'po_number_short' => 'Best.-Nr.',
|
||||||
'frequency_id' => 'Wie oft',
|
'frequency_id' => 'Wie oft',
|
||||||
|
|
@ -1536,8 +1536,8 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||||
'country_Kazakhstan' => 'Kasachstan',
|
'country_Kazakhstan' => 'Kasachstan',
|
||||||
'country_Jordan' => 'Jordanien',
|
'country_Jordan' => 'Jordanien',
|
||||||
'country_Kenya' => 'Kenia',
|
'country_Kenya' => 'Kenia',
|
||||||
'country_Korea, Democratic People\'s Republic of' => 'Korea, Democratic People\'s Republic of',
|
'country_Korea, Democratic People\'s Republic of' => 'Nordkorea',
|
||||||
'country_Korea, Republic of' => 'Korea, Republic of',
|
'country_Korea, Republic of' => 'Südkorea',
|
||||||
'country_Kuwait' => 'Kuwait',
|
'country_Kuwait' => 'Kuwait',
|
||||||
'country_Kyrgyzstan' => 'Kirgisistan',
|
'country_Kyrgyzstan' => 'Kirgisistan',
|
||||||
'country_Lao People\'s Democratic Republic' => 'Lao People\'s Democratic Republic',
|
'country_Lao People\'s Democratic Republic' => 'Lao People\'s Democratic Republic',
|
||||||
|
|
@ -1562,7 +1562,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||||
'country_Mexico' => 'Mexiko',
|
'country_Mexico' => 'Mexiko',
|
||||||
'country_Monaco' => 'Monaco',
|
'country_Monaco' => 'Monaco',
|
||||||
'country_Mongolia' => 'Mongolei',
|
'country_Mongolia' => 'Mongolei',
|
||||||
'country_Moldova, Republic of' => 'Moldova, Republic of',
|
'country_Moldova, Republic of' => 'Moldau',
|
||||||
'country_Montenegro' => 'Montenegro',
|
'country_Montenegro' => 'Montenegro',
|
||||||
'country_Montserrat' => 'Montserrat',
|
'country_Montserrat' => 'Montserrat',
|
||||||
'country_Morocco' => 'Marokko',
|
'country_Morocco' => 'Marokko',
|
||||||
|
|
@ -1625,7 +1625,7 @@ Sobald Sie die Beträge erhalten haben, kommen Sie bitte wieder zurück zu diese
|
||||||
'country_Singapore' => 'Singapur',
|
'country_Singapore' => 'Singapur',
|
||||||
'country_Slovakia' => 'Slowakei',
|
'country_Slovakia' => 'Slowakei',
|
||||||
'country_Viet Nam' => 'Vietnam',
|
'country_Viet Nam' => 'Vietnam',
|
||||||
'country_Slovenia' => 'Slovenien',
|
'country_Slovenia' => 'Slowenien',
|
||||||
'country_Somalia' => 'Somalia',
|
'country_Somalia' => 'Somalia',
|
||||||
'country_South Africa' => 'Südafrika',
|
'country_South Africa' => 'Südafrika',
|
||||||
'country_Zimbabwe' => 'Simbabwe',
|
'country_Zimbabwe' => 'Simbabwe',
|
||||||
|
|
@ -4035,7 +4035,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||||
'connect_google' => 'Google-Konto verbinden',
|
'connect_google' => 'Google-Konto verbinden',
|
||||||
'disconnect_google' => 'Google-Konto entfernen',
|
'disconnect_google' => 'Google-Konto entfernen',
|
||||||
'disable_two_factor' => 'Zwei-Faktor-Authentifizierung deaktivieren',
|
'disable_two_factor' => 'Zwei-Faktor-Authentifizierung deaktivieren',
|
||||||
'invoice_task_datelog' => 'In Aufgabe erfasste Daten in Rechnungen ausweisen',
|
'invoice_task_datelog' => 'In Aufgabe erfasstes Datum in Rechnungen ausweisen',
|
||||||
'invoice_task_datelog_help' => 'Zeigt Datumsdetails in den Rechnungspositionen an',
|
'invoice_task_datelog_help' => 'Zeigt Datumsdetails in den Rechnungspositionen an',
|
||||||
'promo_code' => 'Gutscheincode',
|
'promo_code' => 'Gutscheincode',
|
||||||
'recurring_invoice_issued_to' => 'Wiederkehrende Rechnung ausgestellt an',
|
'recurring_invoice_issued_to' => 'Wiederkehrende Rechnung ausgestellt an',
|
||||||
|
|
@ -4932,7 +4932,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||||
'oauth_mail' => 'OAuth / E-Mail',
|
'oauth_mail' => 'OAuth / E-Mail',
|
||||||
'preferences' => 'Einstellungen',
|
'preferences' => 'Einstellungen',
|
||||||
'analytics' => 'Analytik',
|
'analytics' => 'Analytik',
|
||||||
'reduced_rate' => 'Reduzierte Rate',
|
'reduced_rate' => 'Reduzierter Preis',
|
||||||
'tax_all' => 'Alles besteuern',
|
'tax_all' => 'Alles besteuern',
|
||||||
'tax_selected' => 'Steuer ausgewählt',
|
'tax_selected' => 'Steuer ausgewählt',
|
||||||
'version' => 'Ausführung',
|
'version' => 'Ausführung',
|
||||||
|
|
@ -4987,7 +4987,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
|
||||||
'enable_auto_bill' => 'Automatische Bezahlung aktivieren',
|
'enable_auto_bill' => 'Automatische Bezahlung aktivieren',
|
||||||
'email_count_invoices' => ':count Rechnungen versenden',
|
'email_count_invoices' => ':count Rechnungen versenden',
|
||||||
'invoice_task_item_description' => 'Rechnungspositionsbeschreibung',
|
'invoice_task_item_description' => 'Rechnungspositionsbeschreibung',
|
||||||
'invoice_task_item_description_help' => 'Element-Beschreibung zu den Rechnungs-Positionen hinzufügen',
|
'invoice_task_item_description_help' => 'Element-Beschreibung zu den Rechnungspositionen hinzufügen',
|
||||||
'next_send_time' => 'Nächster Versandzeitpunkt',
|
'next_send_time' => 'Nächster Versandzeitpunkt',
|
||||||
'uploaded_certificate' => 'Das Zertifikat wurde erfolgreich hochgeladen',
|
'uploaded_certificate' => 'Das Zertifikat wurde erfolgreich hochgeladen',
|
||||||
'certificate_set' => 'Zertifikat hochgeladen',
|
'certificate_set' => 'Zertifikat hochgeladen',
|
||||||
|
|
@ -5141,6 +5141,8 @@ Leistungsempfängers',
|
||||||
'nordigen_handler_error_contents_institution_invalid' => 'Die angegebene Institutions-ID ist ungültig oder nicht mehr gültig.',
|
'nordigen_handler_error_contents_institution_invalid' => 'Die angegebene Institutions-ID ist ungültig oder nicht mehr gültig.',
|
||||||
'nordigen_handler_error_heading_ref_invalid' => 'Ungültige Referenz',
|
'nordigen_handler_error_heading_ref_invalid' => 'Ungültige Referenz',
|
||||||
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless hat keine gültige Referenz angegeben. Bitte führen Sie Flow erneut aus und wenden Sie sich an den Support, wenn das Problem weiterhin besteht.',
|
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless hat keine gültige Referenz angegeben. Bitte führen Sie Flow erneut aus und wenden Sie sich an den Support, wenn das Problem weiterhin besteht.',
|
||||||
|
'nordigen_handler_error_heading_eua_failure' => 'EUA Fehler',
|
||||||
|
'nordigen_handler_error_contents_eua_failure' => 'Beim Erstellen der Endbenutzervereinbarung (EUA) ist ein Fehler aufgetreten:',
|
||||||
'nordigen_handler_error_heading_not_found' => 'Ungültige Anforderung',
|
'nordigen_handler_error_heading_not_found' => 'Ungültige Anforderung',
|
||||||
'nordigen_handler_error_contents_not_found' => 'GoCardless hat keine gültige Referenz angegeben. Bitte führen Sie Flow erneut aus und wenden Sie sich an den Support, wenn das Problem weiterhin besteht.',
|
'nordigen_handler_error_contents_not_found' => 'GoCardless hat keine gültige Referenz angegeben. Bitte führen Sie Flow erneut aus und wenden Sie sich an den Support, wenn das Problem weiterhin besteht.',
|
||||||
'nordigen_handler_error_heading_requisition_invalid_status' => 'Nicht bereit',
|
'nordigen_handler_error_heading_requisition_invalid_status' => 'Nicht bereit',
|
||||||
|
|
@ -5370,7 +5372,7 @@ Leistungsempfängers',
|
||||||
'peppol_plan_warning' => 'Für die Nutzung der elektronischen Rechnungsstellung über das PEPPOL-Netzwerk ist ein Enterprise-Tarif erforderlich.',
|
'peppol_plan_warning' => 'Für die Nutzung der elektronischen Rechnungsstellung über das PEPPOL-Netzwerk ist ein Enterprise-Tarif erforderlich.',
|
||||||
'peppol_credits_info' => 'Zum Senden und Empfangen von E-Rechnungen sind E-Credits erforderlich. Diese werden pro Dokument berechnet.',
|
'peppol_credits_info' => 'Zum Senden und Empfangen von E-Rechnungen sind E-Credits erforderlich. Diese werden pro Dokument berechnet.',
|
||||||
'buy_credits' => 'E Credits kaufen',
|
'buy_credits' => 'E Credits kaufen',
|
||||||
'peppol_successfully_configured' => 'PEPPOL erfolgreich konfiguriert.',
|
'peppol_successfully_configured' => 'PEPPOL erfolgreich konfiguriert.',
|
||||||
'peppol_not_paid_message' => 'Für PEPPOL ist ein Enterprise-Tarif erforderlich. Bitte aktualisieren Sie Ihren Plan.',
|
'peppol_not_paid_message' => 'Für PEPPOL ist ein Enterprise-Tarif erforderlich. Bitte aktualisieren Sie Ihren Plan.',
|
||||||
'peppol_country_not_supported' => 'Das PEPPOL-Netzwerk ist für dieses Land noch nicht verfügbar.',
|
'peppol_country_not_supported' => 'Das PEPPOL-Netzwerk ist für dieses Land noch nicht verfügbar.',
|
||||||
'peppol_disconnect' => 'Trennen Sie die Verbindung zum PEPPOL-Netzwerk',
|
'peppol_disconnect' => 'Trennen Sie die Verbindung zum PEPPOL-Netzwerk',
|
||||||
|
|
@ -5382,24 +5384,24 @@ Leistungsempfängers',
|
||||||
'hidden_taxes_warning' => 'Einige Steuern sind aufgrund der aktuellen Steuereinstellungen ausgeblendet. :link',
|
'hidden_taxes_warning' => 'Einige Steuern sind aufgrund der aktuellen Steuereinstellungen ausgeblendet. :link',
|
||||||
'tax3' => 'Dritte Steuer',
|
'tax3' => 'Dritte Steuer',
|
||||||
'negative_payment_warning' => 'Möchten Sie wirklich eine negative Zahlung erstellen? Diese kann nicht als Gutschrift oder Zahlung verwendet werden.',
|
'negative_payment_warning' => 'Möchten Sie wirklich eine negative Zahlung erstellen? Diese kann nicht als Gutschrift oder Zahlung verwendet werden.',
|
||||||
'currency_Bermudian_Dollar' => 'Bermuda-Dollar',
|
'currency_bermudian_dollar' => 'Bermuda-Dollar',
|
||||||
'currency_Central_African_CFA_Franc' => 'Zentralafrikanischer CFA-Franc',
|
'currency_central_african_cfa_franc' => 'Zentralafrikanischer CFA-Franc',
|
||||||
'currency_Congolese_Franc' => 'Kongolesischer Franc',
|
'currency_congolese_franc' => 'Kongolesisches Franc',
|
||||||
'currency_Djiboutian_Franc' => 'Dschibuti-Franc',
|
'currency_djiboutian_franc' => 'Dschibuti-Franc',
|
||||||
'currency_Eritrean_Nakfa' => 'Eritreischer Nakfa',
|
'currency_eritrean_nakfa' => 'Eritreische Nakia',
|
||||||
'currency_Falkland_Islands_Pound' => 'Falklandinseln Pfund',
|
'currency_falkland_islands_pound' => 'Falklandinseln Pfund',
|
||||||
'currency_Guinean_Franc' => 'Guinea-Franc',
|
'currency_guinean_franc' => 'Guinea-Franc',
|
||||||
'currency_Iraqi_Dinar' => 'Irakischer Dinar',
|
'currency_iraqi_dinar' => 'Irakischer Dinar',
|
||||||
'currency_Lesotho_Loti' => 'Lesothischer Loti',
|
'currency_lesotho_loti' => 'Lesotho Loti',
|
||||||
'currency_Mongolian_Tugrik' => 'Mongolischer Tugrik',
|
'currency_mongolian_tugrik' => 'Mongolian Tugrik',
|
||||||
'currency_Seychellois_Rupee' => 'Seychellen-Rupie',
|
'currency_seychellois_rupee' => 'Seychellois Rupee',
|
||||||
'currency_Solomon_Islands_Dollar' => 'Salomonen-Dollar',
|
'currency_solomon_islands_dollar' => 'Solomon Islands Dollar',
|
||||||
'currency_Somali_Shilling' => 'Somalischer Schilling',
|
'currency_somali_shilling' => 'Somali Shilling',
|
||||||
'currency_South_Sudanese_Pound' => 'Südsudanesisches Pfund',
|
'currency_south_sudanese_pound' => 'South Sudanese Pound',
|
||||||
'currency_Sudanese_Pound' => 'Sudanesisches Pfund',
|
'currency_sudanese_pound' => 'Sudanese Pound',
|
||||||
'currency_Tajikistani_Somoni' => 'Tadschikischer Somoni',
|
'currency_tajikistani_somoni' => 'Tajikistani Somoni',
|
||||||
'currency_Turkmenistani_Manat' => 'Turkmenistan-Manat',
|
'currency_turkmenistani_manat' => 'Turkmenistani Manat',
|
||||||
'currency_Uzbekistani_Som' => 'Usbekischer Som',
|
'currency_uzbekistani_som' => 'Uzbekistani Som',
|
||||||
'payment_status_changed' => 'Bitte beachten Sie, dass der Status Ihrer Zahlung aktualisiert wurde. Wir empfehlen, die Seite zu aktualisieren, um die aktuellste Version anzuzeigen.',
|
'payment_status_changed' => 'Bitte beachten Sie, dass der Status Ihrer Zahlung aktualisiert wurde. Wir empfehlen, die Seite zu aktualisieren, um die aktuellste Version anzuzeigen.',
|
||||||
'credit_status_changed' => 'Bitte beachten Sie, dass der Status Ihres Guthabens aktualisiert wurde. Wir empfehlen, die Seite zu aktualisieren, um die aktuellste Version anzuzeigen.',
|
'credit_status_changed' => 'Bitte beachten Sie, dass der Status Ihres Guthabens aktualisiert wurde. Wir empfehlen, die Seite zu aktualisieren, um die aktuellste Version anzuzeigen.',
|
||||||
'credit_updated' => 'Kredit- aktualisiert',
|
'credit_updated' => 'Kredit- aktualisiert',
|
||||||
|
|
@ -5481,15 +5483,14 @@ Leistungsempfängers',
|
||||||
'download_ready' => 'Ihr Download ist jetzt bereit! [:message]',
|
'download_ready' => 'Ihr Download ist jetzt bereit! [:message]',
|
||||||
'notification_quote_reminder1_sent_subject' => 'Erste Erinnerung für Angebot :invoice wurde an :client gesendet',
|
'notification_quote_reminder1_sent_subject' => 'Erste Erinnerung für Angebot :invoice wurde an :client gesendet',
|
||||||
'custom_reminder_sent' => 'Benutzerdefinierte Erinnerung wurde an :client gesendet',
|
'custom_reminder_sent' => 'Benutzerdefinierte Erinnerung wurde an :client gesendet',
|
||||||
'use_system_fonts' => 'Use System Fonts',
|
'use_system_fonts' => 'Verwende Systemschriftarten',
|
||||||
'use_system_fonts_help' => 'Override the standard fonts with those from the web browser',
|
'use_system_fonts_help' => 'Überschreibe die Standardschriftarten mit denen aus dem Webbrowser',
|
||||||
'active_tasks' => 'Active Tasks',
|
'active_tasks' => 'Aktive Aufgaben',
|
||||||
'enable_public_notifications_1' => 'Hallo! Sie können jetzt Echtzeitbenachrichtigungen von Invoice Ninja erhalten!',
|
|
||||||
'enable_public_notifications_2' => 'Dies bedeutet, dass Sie mit den offiziellen Invoice Ninja-Servern verbunden werden. Wir möchten Sie daher nach Ihrer Präferenz fragen.',
|
|
||||||
'enable_public_notifications_3' => 'Bitte beachten Sie, dass Sie dieses Modal nur einmal sehen. Wenn Sie Ihre Einstellungen ändern möchten, können Sie dies im Einstellungsmenü tun.',
|
|
||||||
'enable_notifications' => 'Aktiviere Benachrichtigungen',
|
'enable_notifications' => 'Aktiviere Benachrichtigungen',
|
||||||
'enable_public_notifications' => 'Aktiviere öffentliche Benachrichtigungen',
|
'enable_public_notifications' => 'Aktiviere öffentliche Benachrichtigungen',
|
||||||
'navigate' => 'Navigate',
|
'enable_public_notifications_help' => 'Aktivieren Sie Echtzeitbenachrichtigungen von Invoice Ninja.',
|
||||||
|
'navigate' => 'Navigiere',
|
||||||
|
'calculate_taxes_warning' => 'Mit dieser Aktion werden Einzelpostensteuern aktiviert und Gesamtsteuern deaktiviert. Eventuell offene Rechnungen können mit den neuen Einstellungen neu berechnet werden!',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $lang;
|
return $lang;
|
||||||
|
|
|
||||||
|
|
@ -5134,6 +5134,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||||
'nordigen_handler_error_contents_institution_invalid' => 'L\'identifiant d\'institution fourni n\'est pas ou n\'est plus valide.',
|
'nordigen_handler_error_contents_institution_invalid' => 'L\'identifiant d\'institution fourni n\'est pas ou n\'est plus valide.',
|
||||||
'nordigen_handler_error_heading_ref_invalid' => 'Référence non valide',
|
'nordigen_handler_error_heading_ref_invalid' => 'Référence non valide',
|
||||||
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless n\'a pas fourni une référence valide. Veuillez relancer le processus et contacter le support si le problème persiste.',
|
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless n\'a pas fourni une référence valide. Veuillez relancer le processus et contacter le support si le problème persiste.',
|
||||||
|
'nordigen_handler_error_heading_eua_failure' => 'Échec du CLUF',
|
||||||
|
'nordigen_handler_error_contents_eua_failure' => 'Erreur lors de la création du CLUF :',
|
||||||
'nordigen_handler_error_heading_not_found' => 'Réquisition non valide',
|
'nordigen_handler_error_heading_not_found' => 'Réquisition non valide',
|
||||||
'nordigen_handler_error_contents_not_found' => 'GoCardless n\'a pas fourni une référence valide. Veuillez relancer le processus et contacter le support si le problème persiste.',
|
'nordigen_handler_error_contents_not_found' => 'GoCardless n\'a pas fourni une référence valide. Veuillez relancer le processus et contacter le support si le problème persiste.',
|
||||||
'nordigen_handler_error_heading_requisition_invalid_status' => 'Pas prêt',
|
'nordigen_handler_error_heading_requisition_invalid_status' => 'Pas prêt',
|
||||||
|
|
@ -5364,7 +5366,7 @@ Développe automatiquement la section des notes dans le tableau de produits pour
|
||||||
'peppol_plan_warning' => 'Un plan Entreprise est requis pour utiliser la facturation électronique sur le réseau PEPPOL.',
|
'peppol_plan_warning' => 'Un plan Entreprise est requis pour utiliser la facturation électronique sur le réseau PEPPOL.',
|
||||||
'peppol_credits_info' => 'Des crédits électroniques (Ecredits) sont nécessaires pour envoyer et recevoir des factures électroniques. Ils sont facturés par document.',
|
'peppol_credits_info' => 'Des crédits électroniques (Ecredits) sont nécessaires pour envoyer et recevoir des factures électroniques. Ils sont facturés par document.',
|
||||||
'buy_credits' => 'Acheter des Ecredits',
|
'buy_credits' => 'Acheter des Ecredits',
|
||||||
'peppol_successfully_configured' => 'PEPPOL a été configuré correctement',
|
'peppol_successfully_configured' => 'PEPPOL a été configuré correctement',
|
||||||
'peppol_not_paid_message' => 'Un plan Entreprise est requis pour PEPPOL. Veuillez mettre à niveau votre plan.',
|
'peppol_not_paid_message' => 'Un plan Entreprise est requis pour PEPPOL. Veuillez mettre à niveau votre plan.',
|
||||||
'peppol_country_not_supported' => 'Le réseau PEPPOL n\'est pas encore disponible pour ce pays.',
|
'peppol_country_not_supported' => 'Le réseau PEPPOL n\'est pas encore disponible pour ce pays.',
|
||||||
'peppol_disconnect' => 'Se déconnecter du réseau PEPPOL',
|
'peppol_disconnect' => 'Se déconnecter du réseau PEPPOL',
|
||||||
|
|
@ -5376,24 +5378,24 @@ Développe automatiquement la section des notes dans le tableau de produits pour
|
||||||
'hidden_taxes_warning' => 'Certaines taxes sont masquées en raison des paramètres de taxes actuels.',
|
'hidden_taxes_warning' => 'Certaines taxes sont masquées en raison des paramètres de taxes actuels.',
|
||||||
'tax3' => 'Troisième taxe',
|
'tax3' => 'Troisième taxe',
|
||||||
'negative_payment_warning' => 'Êtes-vous sûr de vouloir créer un paiement négatif? Cela ne peut pas être utilisé comme crédit ou paiement.',
|
'negative_payment_warning' => 'Êtes-vous sûr de vouloir créer un paiement négatif? Cela ne peut pas être utilisé comme crédit ou paiement.',
|
||||||
'currency_Bermudian_Dollar' => 'Dollar bermudien',
|
'currency_bermudian_dollar' => 'Dollar bermudien',
|
||||||
'currency_Central_African_CFA_Franc' => 'Franc CFA de l\'Afrique centrale',
|
'currency_central_african_cfa_franc' => 'Franc CFA centrafricain',
|
||||||
'currency_Congolese_Franc' => 'Franc congolais',
|
'currency_congolese_franc' => 'Franc congolais',
|
||||||
'currency_Djiboutian_Franc' => 'Franc Djiboutien',
|
'currency_djiboutian_franc' => 'Franc Djibouti',
|
||||||
'currency_Eritrean_Nakfa' => 'Nakfa érythréen',
|
'currency_eritrean_nakfa' => 'Nakfa érythréen',
|
||||||
'currency_Falkland_Islands_Pound' => 'Livre des Îles Malouines',
|
'currency_falkland_islands_pound' => 'Livre des Îles Malouines',
|
||||||
'currency_Guinean_Franc' => 'Franc guinéen',
|
'currency_guinean_franc' => 'Franc guinéen',
|
||||||
'currency_Iraqi_Dinar' => 'Dinar irakien',
|
'currency_iraqi_dinar' => 'Dinar irakien',
|
||||||
'currency_Lesotho_Loti' => 'Loti lésothien',
|
'currency_lesotho_loti' => 'Loti Lesotho',
|
||||||
'currency_Mongolian_Tugrik' => 'Tugrik mongolien',
|
'currency_mongolian_tugrik' => 'Tugrik mongol',
|
||||||
'currency_Seychellois_Rupee' => 'Roupie seychelloise',
|
'currency_seychellois_rupee' => 'Roupie seychelloise',
|
||||||
'currency_Solomon_Islands_Dollar' => 'Dollar des Salomon',
|
'currency_solomon_islands_dollar' => 'Dollar des Salomon',
|
||||||
'currency_Somali_Shilling' => 'Shilling somalien',
|
'currency_somali_shilling' => 'Shilling somalien',
|
||||||
'currency_South_Sudanese_Pound' => 'Livre sud-soudanaise',
|
'currency_south_sudanese_pound' => 'Livre sud-soudanaise',
|
||||||
'currency_Sudanese_Pound' => 'Livre soudanaise',
|
'currency_sudanese_pound' => 'Livre soudanaise',
|
||||||
'currency_Tajikistani_Somoni' => 'Somoni Tadjik',
|
'currency_tajikistani_somoni' => 'Somoni Tadjik',
|
||||||
'currency_Turkmenistani_Manat' => 'Manat turkmène',
|
'currency_turkmenistani_manat' => 'Manat turkmène',
|
||||||
'currency_Uzbekistani_Som' => 'Sum Ouzbek',
|
'currency_uzbekistani_som' => 'Sum Ouzbek',
|
||||||
'payment_status_changed' => 'Veuillez noter que le statut de votre paiement a été mis à jour. Nous vous recommandons de rafraîchir la page pour voir la version la plus récente.',
|
'payment_status_changed' => 'Veuillez noter que le statut de votre paiement a été mis à jour. Nous vous recommandons de rafraîchir la page pour voir la version la plus récente.',
|
||||||
'credit_status_changed' => 'Veuillez noter que le statut de votre crédit a été mis à jour. Nous vous recommandons de rafraîchir la page pour voir la version la plus récente.',
|
'credit_status_changed' => 'Veuillez noter que le statut de votre crédit a été mis à jour. Nous vous recommandons de rafraîchir la page pour voir la version la plus récente.',
|
||||||
'credit_updated' => 'Crédit mis à jour',
|
'credit_updated' => 'Crédit mis à jour',
|
||||||
|
|
@ -5478,12 +5480,11 @@ Développe automatiquement la section des notes dans le tableau de produits pour
|
||||||
'use_system_fonts' => 'Utiliser les polices de caractères du système',
|
'use_system_fonts' => 'Utiliser les polices de caractères du système',
|
||||||
'use_system_fonts_help' => 'Remplacer les polices standard par celles du navigateur web',
|
'use_system_fonts_help' => 'Remplacer les polices standard par celles du navigateur web',
|
||||||
'active_tasks' => 'Tâches actives',
|
'active_tasks' => 'Tâches actives',
|
||||||
'enable_public_notifications_1' => 'Bonjour ! Vous pouvez maintenant recevoir des notifications en temps réel d\'Invoice Ninja !',
|
|
||||||
'enable_public_notifications_2' => 'Cela signifie que vous serez connecté aux serveurs officiels d\'Invoice Ninja, nous aimerions donc connaître votre préférence.',
|
|
||||||
'enable_public_notifications_3' => 'Veuillez noter que vous ne verrez cette fenêtre modale qu\'une seule fois. Si vous souhaitez modifier vos paramètres, vous pouvez le faire dans le menu des paramètres.',
|
|
||||||
'enable_notifications' => 'Activer les notifications',
|
'enable_notifications' => 'Activer les notifications',
|
||||||
'enable_public_notifications' => 'Activer les notifications publiques',
|
'enable_public_notifications' => 'Activer les notifications publiques',
|
||||||
|
'enable_public_notifications_help' => 'Activer les notifications en temps réel de Invoice Ninja.',
|
||||||
'navigate' => 'Naviguer',
|
'navigate' => 'Naviguer',
|
||||||
|
'calculate_taxes_warning' => 'Cette action activera les taxes par ligne et désactivera les taxes totales. Toutes les factures ouvertes peuvent être recalculées avec les nouveaux paramètres !',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $lang;
|
return $lang;
|
||||||
|
|
|
||||||
|
|
@ -738,7 +738,7 @@ $lang = array(
|
||||||
'activity_7' => ':contact đã xem hóa đơn :invoice gửi đến :client',
|
'activity_7' => ':contact đã xem hóa đơn :invoice gửi đến :client',
|
||||||
'activity_8' => ':user hóa đơn lưu trữ :invoice',
|
'activity_8' => ':user hóa đơn lưu trữ :invoice',
|
||||||
'activity_9' => ':user đã xóa hóa đơn :invoice',
|
'activity_9' => ':user đã xóa hóa đơn :invoice',
|
||||||
'activity_10' => ':user đã nhập thanh toán :payment bởi :payment _số tiền trên hóa đơn :invoice cho :client',
|
'activity_10' => ':user đã nhập thanh toán :payment bởi :payment số tiền trên hóa đơn :invoice cho :client',
|
||||||
'activity_11' => ':user cập nhật thanh toán :payment',
|
'activity_11' => ':user cập nhật thanh toán :payment',
|
||||||
'activity_12' => ':user thanh toán đã lưu trữ :payment',
|
'activity_12' => ':user thanh toán đã lưu trữ :payment',
|
||||||
'activity_13' => ':user đã xóa thanh toán :payment',
|
'activity_13' => ':user đã xóa thanh toán :payment',
|
||||||
|
|
@ -2132,7 +2132,7 @@ $lang = array(
|
||||||
'purge_data_message' => 'Cảnh báo: Thao tác này sẽ xóa vĩnh viễn dữ liệu của bạn, không thể hoàn tác.',
|
'purge_data_message' => 'Cảnh báo: Thao tác này sẽ xóa vĩnh viễn dữ liệu của bạn, không thể hoàn tác.',
|
||||||
'contact_phone' => 'Điện thoại liên hệ',
|
'contact_phone' => 'Điện thoại liên hệ',
|
||||||
'contact_email' => 'Email liên hệ',
|
'contact_email' => 'Email liên hệ',
|
||||||
'reply_to_email' => 'Trả lời Email',
|
'reply_to_email' => 'Địa chỉ mail',
|
||||||
'reply_to_email_help' => 'Chỉ định địa chỉ trả lời cho email của khách hàng.',
|
'reply_to_email_help' => 'Chỉ định địa chỉ trả lời cho email của khách hàng.',
|
||||||
'bcc_email_help' => 'Bao gồm riêng địa chỉ này vào email của khách hàng.',
|
'bcc_email_help' => 'Bao gồm riêng địa chỉ này vào email của khách hàng.',
|
||||||
'import_complete' => 'Quá trình nhập của bạn đã hoàn tất thành công.',
|
'import_complete' => 'Quá trình nhập của bạn đã hoàn tất thành công.',
|
||||||
|
|
@ -2188,7 +2188,7 @@ $lang = array(
|
||||||
'host' => 'Chủ nhà',
|
'host' => 'Chủ nhà',
|
||||||
'database' => 'Cơ sở dữ liệu',
|
'database' => 'Cơ sở dữ liệu',
|
||||||
'test_connection' => 'Kiểm tra kết nối',
|
'test_connection' => 'Kiểm tra kết nối',
|
||||||
'from_name' => 'Từ Tên',
|
'from_name' => 'Người gửi',
|
||||||
'from_address' => 'Từ Địa chỉ',
|
'from_address' => 'Từ Địa chỉ',
|
||||||
'port' => 'Cảng',
|
'port' => 'Cảng',
|
||||||
'encryption' => 'Mã hóa',
|
'encryption' => 'Mã hóa',
|
||||||
|
|
@ -2903,7 +2903,7 @@ $lang = array(
|
||||||
'local_part_available' => 'Name available',
|
'local_part_available' => 'Name available',
|
||||||
'local_part_invalid' => 'Tên không hợp lệ (chỉ chữ số, không có khoảng trắng',
|
'local_part_invalid' => 'Tên không hợp lệ (chỉ chữ số, không có khoảng trắng',
|
||||||
'local_part_help' => 'Tùy chỉnh phần địa phương của email hỗ trợ đến của bạn, ví dụ: YOUR_NAME@support.invoiceninja.com',
|
'local_part_help' => 'Tùy chỉnh phần địa phương của email hỗ trợ đến của bạn, ví dụ: YOUR_NAME@support.invoiceninja.com',
|
||||||
'from_name_help' => 'Từ tên là người gửi có thể nhận dạng được hiển thị thay cho địa chỉ email, tức là Trung tâm hỗ trợ',
|
'from_name_help' => 'Người gửi là người gửi có thể nhận dạng được hiển thị thay cho địa chỉ email, tức là Trung tâm hỗ trợ',
|
||||||
'local_part_placeholder' => 'YOUR_NAME',
|
'local_part_placeholder' => 'YOUR_NAME',
|
||||||
'from_name_placeholder' => 'Trung tâm hỗ trợ',
|
'from_name_placeholder' => 'Trung tâm hỗ trợ',
|
||||||
'attachments' => 'Đính kèm',
|
'attachments' => 'Đính kèm',
|
||||||
|
|
@ -3981,7 +3981,7 @@ $lang = array(
|
||||||
'converted_paid_to_date' => 'Đã chuyển đổi thanh toán',
|
'converted_paid_to_date' => 'Đã chuyển đổi thanh toán',
|
||||||
'converted_credit_balance' => 'Số dư tín dụng đã chuyển đổi',
|
'converted_credit_balance' => 'Số dư tín dụng đã chuyển đổi',
|
||||||
'converted_total' => 'Tổng số đã chuyển đổi',
|
'converted_total' => 'Tổng số đã chuyển đổi',
|
||||||
'reply_to_name' => 'Trả lời tên',
|
'reply_to_name' => 'Soạn thư',
|
||||||
'payment_status_-2' => 'Một phần chưa áp dụng',
|
'payment_status_-2' => 'Một phần chưa áp dụng',
|
||||||
'color_theme' => 'Chủ đề màu sắc',
|
'color_theme' => 'Chủ đề màu sắc',
|
||||||
'start_migration' => 'Bắt đầu di chuyển',
|
'start_migration' => 'Bắt đầu di chuyển',
|
||||||
|
|
@ -4527,7 +4527,7 @@ $lang = array(
|
||||||
'connect_email' => 'Kết nối Email',
|
'connect_email' => 'Kết nối Email',
|
||||||
'disconnect_email' => 'Ngắt kết nối Email',
|
'disconnect_email' => 'Ngắt kết nối Email',
|
||||||
'use_web_app_to_connect_microsoft' => 'Vui lòng sử dụng ứng dụng web để kết nối với Microsoft',
|
'use_web_app_to_connect_microsoft' => 'Vui lòng sử dụng ứng dụng web để kết nối với Microsoft',
|
||||||
'email_provider' => 'Nhà cung cấp email',
|
'email_provider' => 'Email',
|
||||||
'connect_microsoft' => 'Kết nối Microsoft',
|
'connect_microsoft' => 'Kết nối Microsoft',
|
||||||
'disconnect_microsoft' => 'Ngắt kết nối Microsoft',
|
'disconnect_microsoft' => 'Ngắt kết nối Microsoft',
|
||||||
'connected_microsoft' => 'Đã kết nối thành công Microsoft',
|
'connected_microsoft' => 'Đã kết nối thành công Microsoft',
|
||||||
|
|
@ -5137,6 +5137,8 @@ $lang = array(
|
||||||
'nordigen_handler_error_contents_institution_invalid' => 'Mã số tổ chức được cung cấp không hợp lệ hoặc không còn hợp lệ.',
|
'nordigen_handler_error_contents_institution_invalid' => 'Mã số tổ chức được cung cấp không hợp lệ hoặc không còn hợp lệ.',
|
||||||
'nordigen_handler_error_heading_ref_invalid' => 'Tham chiếu không hợp lệ',
|
'nordigen_handler_error_heading_ref_invalid' => 'Tham chiếu không hợp lệ',
|
||||||
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless không cung cấp tham chiếu hợp lệ. Vui lòng chạy lại luồng và liên hệ với bộ phận hỗ trợ nếu sự cố này vẫn tiếp diễn.',
|
'nordigen_handler_error_contents_ref_invalid' => 'GoCardless không cung cấp tham chiếu hợp lệ. Vui lòng chạy lại luồng và liên hệ với bộ phận hỗ trợ nếu sự cố này vẫn tiếp diễn.',
|
||||||
|
'nordigen_handler_error_heading_eua_failure' => 'Lỗi EUA',
|
||||||
|
'nordigen_handler_error_contents_eua_failure' => 'Đã xảy ra lỗi trong quá trình tạo Thỏa thuận kết thúc Người dùng :',
|
||||||
'nordigen_handler_error_heading_not_found' => 'Yêu cầu không hợp lệ',
|
'nordigen_handler_error_heading_not_found' => 'Yêu cầu không hợp lệ',
|
||||||
'nordigen_handler_error_contents_not_found' => 'GoCardless không cung cấp tham chiếu hợp lệ. Vui lòng chạy lại luồng và liên hệ với bộ phận hỗ trợ nếu sự cố này vẫn tiếp diễn.',
|
'nordigen_handler_error_contents_not_found' => 'GoCardless không cung cấp tham chiếu hợp lệ. Vui lòng chạy lại luồng và liên hệ với bộ phận hỗ trợ nếu sự cố này vẫn tiếp diễn.',
|
||||||
'nordigen_handler_error_heading_requisition_invalid_status' => 'Chưa sẵn sàng',
|
'nordigen_handler_error_heading_requisition_invalid_status' => 'Chưa sẵn sàng',
|
||||||
|
|
@ -5366,7 +5368,7 @@ $lang = array(
|
||||||
'peppol_plan_warning' => 'Cần có gói doanh nghiệp đến sử dụng hóa đơn điện tử qua mạng PEPPOL.',
|
'peppol_plan_warning' => 'Cần có gói doanh nghiệp đến sử dụng hóa đơn điện tử qua mạng PEPPOL.',
|
||||||
'peppol_credits_info' => 'Cần có Ecredit đến gửi và nhận hóa đơn điện tử. Chúng được tính phí theo từng chứng từ.',
|
'peppol_credits_info' => 'Cần có Ecredit đến gửi và nhận hóa đơn điện tử. Chúng được tính phí theo từng chứng từ.',
|
||||||
'buy_credits' => 'Mua tín dụng E',
|
'buy_credits' => 'Mua tín dụng E',
|
||||||
'peppol_successfully_configured' => 'PEPPOL đã được cấu hình thành công.',
|
'peppol_successfully_configured' => 'PEPPOL đã được cấu hình thành công.',
|
||||||
'peppol_not_paid_message' => 'Cần có gói Enterprise cho PEPPOL. Vui lòng nâng cấp gói của bạn.',
|
'peppol_not_paid_message' => 'Cần có gói Enterprise cho PEPPOL. Vui lòng nâng cấp gói của bạn.',
|
||||||
'peppol_country_not_supported' => 'Mạng PEPPOL hiện chưa khả dụng ở quốc gia này.',
|
'peppol_country_not_supported' => 'Mạng PEPPOL hiện chưa khả dụng ở quốc gia này.',
|
||||||
'peppol_disconnect' => 'Ngắt kết nối khỏi mạng PEPPOL',
|
'peppol_disconnect' => 'Ngắt kết nối khỏi mạng PEPPOL',
|
||||||
|
|
@ -5378,24 +5380,24 @@ $lang = array(
|
||||||
'hidden_taxes_warning' => 'Một số loại thuế bị ẩn Quá hạn đến Cài đặt thuế hiện hành . :link',
|
'hidden_taxes_warning' => 'Một số loại thuế bị ẩn Quá hạn đến Cài đặt thuế hiện hành . :link',
|
||||||
'tax3' => 'Thuế thứ ba',
|
'tax3' => 'Thuế thứ ba',
|
||||||
'negative_payment_warning' => 'Bạn có chắc chắn đến Tạo một Sự chi trả giá âm ? Điều này không thể được sử dụng như một khoản tín dụng hoặc Sự chi trả .',
|
'negative_payment_warning' => 'Bạn có chắc chắn đến Tạo một Sự chi trả giá âm ? Điều này không thể được sử dụng như một khoản tín dụng hoặc Sự chi trả .',
|
||||||
'currency_Bermudian_Dollar' => 'Đô la Bermuda',
|
'currency_bermudian_dollar' => 'Đô la Bermuda',
|
||||||
'currency_Central_African_CFA_Franc' => 'Franc CFA Trung Phi',
|
'currency_central_african_cfa_franc' => 'Franc CFA Trung Phi',
|
||||||
'currency_Congolese_Franc' => 'Franc Congo',
|
'currency_congolese_franc' => 'Franc Congo',
|
||||||
'currency_Djiboutian_Franc' => 'Franc Djibouti',
|
'currency_djiboutian_franc' => 'Franc Djibouti',
|
||||||
'currency_Eritrean_Nakfa' => 'Nakfa Eritrea',
|
'currency_eritrean_nakfa' => 'Nakfa Eritrea',
|
||||||
'currency_Falkland_Islands_Pound' => 'Bảng Anh Quần đảo Falkland',
|
'currency_falkland_islands_pound' => 'Bảng Anh Quần đảo Falkland',
|
||||||
'currency_Guinean_Franc' => 'Franc Guinea',
|
'currency_guinean_franc' => 'Franc Guinea',
|
||||||
'currency_Iraqi_Dinar' => 'Dinar Iraq',
|
'currency_iraqi_dinar' => 'Dinar Iraq',
|
||||||
'currency_Lesotho_Loti' => 'Loti Lesotho',
|
'currency_lesotho_loti' => 'Loti Lesotho',
|
||||||
'currency_Mongolian_Tugrik' => 'Tugrik Mông Cổ',
|
'currency_mongolian_tugrik' => 'Tugrik Mông Cổ',
|
||||||
'currency_Seychellois_Rupee' => 'Rupee Seychelles',
|
'currency_seychellois_rupee' => 'Rupee Seychelles',
|
||||||
'currency_Solomon_Islands_Dollar' => 'Đô la Quần đảo Solomon',
|
'currency_solomon_islands_dollar' => 'Đô la Quần đảo Solomon',
|
||||||
'currency_Somali_Shilling' => 'Shilling Somali',
|
'currency_somali_shilling' => 'Shilling Somali',
|
||||||
'currency_South_Sudanese_Pound' => 'Bảng Nam Sudan',
|
'currency_south_sudanese_pound' => 'Bảng Nam Sudan',
|
||||||
'currency_Sudanese_Pound' => 'Bảng Sudan',
|
'currency_sudanese_pound' => 'Bảng Sudan',
|
||||||
'currency_Tajikistani_Somoni' => 'Somoni Tajikistan',
|
'currency_tajikistani_somoni' => 'Somoni Tajikistan',
|
||||||
'currency_Turkmenistani_Manat' => 'Đồng Manat Turkmenistan',
|
'currency_turkmenistani_manat' => 'Đồng Manat Turkmenistan',
|
||||||
'currency_Uzbekistani_Som' => 'Som Uzbekistan',
|
'currency_uzbekistani_som' => 'Som Uzbekistan',
|
||||||
'payment_status_changed' => 'Xin Ghi chú rằng trạng thái Sự chi trả của bạn đã được đã cập nhật . Chúng tôi khuyên bạn nên làm mới trang đến Xem phiên bản mới nhất.',
|
'payment_status_changed' => 'Xin Ghi chú rằng trạng thái Sự chi trả của bạn đã được đã cập nhật . Chúng tôi khuyên bạn nên làm mới trang đến Xem phiên bản mới nhất.',
|
||||||
'credit_status_changed' => 'Vui lòng Ghi chú rằng trạng thái tín dụng của bạn đã được đã cập nhật . Chúng tôi khuyên bạn nên làm mới trang đến Xem phiên bản mới nhất.',
|
'credit_status_changed' => 'Vui lòng Ghi chú rằng trạng thái tín dụng của bạn đã được đã cập nhật . Chúng tôi khuyên bạn nên làm mới trang đến Xem phiên bản mới nhất.',
|
||||||
'credit_updated' => 'đã cập nhật tín dụng',
|
'credit_updated' => 'đã cập nhật tín dụng',
|
||||||
|
|
@ -5480,12 +5482,11 @@ $lang = array(
|
||||||
'use_system_fonts' => 'Sử dụng Phông chữ Hệ thống',
|
'use_system_fonts' => 'Sử dụng Phông chữ Hệ thống',
|
||||||
'use_system_fonts_help' => 'Ghi đè phông chữ chuẩn bằng phông chữ từ trình duyệt web',
|
'use_system_fonts_help' => 'Ghi đè phông chữ chuẩn bằng phông chữ từ trình duyệt web',
|
||||||
'active_tasks' => 'Nhiệm vụ đang hoạt động',
|
'active_tasks' => 'Nhiệm vụ đang hoạt động',
|
||||||
'enable_public_notifications_1' => 'Xin chào! Bây giờ bạn có thể nhận thông báo theo thời gian thực từ Hóa đơn Ninja!',
|
|
||||||
'enable_public_notifications_2' => 'Điều này có nghĩa là bạn sẽ được kết nối đến máy chủ Hóa đơn Ninja chính thức, vì vậy chúng tôi muốn hỏi ý kiến đến về sở thích của bạn.',
|
|
||||||
'enable_public_notifications_3' => 'Vui lòng Ghi chú , bạn sẽ chỉ nhìn thấy phương thức này một lần. Nếu bạn muốn đến đổi Cài đặt của mình, bạn có thể làm như vậy trong menu Cài đặt .',
|
|
||||||
'enable_notifications' => 'Bật thông báo',
|
'enable_notifications' => 'Bật thông báo',
|
||||||
'enable_public_notifications' => 'Bật thông báo công khai',
|
'enable_public_notifications' => 'Bật thông báo công khai',
|
||||||
|
'enable_public_notifications_help' => 'Bật thông báo thời gian thực từ Invoice Ninja.',
|
||||||
'navigate' => 'Điều hướng',
|
'navigate' => 'Điều hướng',
|
||||||
|
'calculate_taxes_warning' => 'Hành động này sẽ kích hoạt thuế mục hàng và vô hiệu hóa thuế Tổng cộng . Mọi Hóa đơn đang mở có thể được tính toán lại bằng Cài đặt mới !',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $lang;
|
return $lang;
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,10 @@
|
||||||
|
|
||||||
#header, #header-spacer {
|
#header, #header-spacer {
|
||||||
height: 160px;
|
height: 160px;
|
||||||
padding: 2rem;
|
padding-top: 2rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
.company-logo {
|
.company-logo {
|
||||||
|
|
@ -129,7 +132,7 @@
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
margin-top: 0rem;
|
margin-top: 0.5rem;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,8 +184,8 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-template-columns: 2fr 1fr;
|
||||||
padding-top: .5rem;
|
padding-top: .5rem;
|
||||||
padding-left: 3rem;
|
padding-left: 1rem;
|
||||||
padding-right: 3rem;
|
padding-right: 1rem;
|
||||||
gap: 80px;
|
gap: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +251,7 @@
|
||||||
|
|
||||||
#footer, #footer-spacer {
|
#footer, #footer-spacer {
|
||||||
height: 160px;
|
height: 160px;
|
||||||
padding: 1rem 3rem;
|
padding: 1rem 1rem;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,8 +260,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref="footer_content"]{
|
[data-ref="footer_content"]{
|
||||||
padding-right: 2rem;
|
padding-right: 1rem;
|
||||||
margin-right: 2rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
|
@ -309,7 +312,10 @@
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.unit_cost-th'],
|
[data-ref='product_table-product.unit_cost-th']{
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.quantity-th'],
|
[data-ref='product_table-product.quantity-th'],
|
||||||
[data-ref='product_table-product.product1-th'],
|
[data-ref='product_table-product.product1-th'],
|
||||||
[data-ref='product_table-product.product2-th'],
|
[data-ref='product_table-product.product2-th'],
|
||||||
|
|
@ -323,9 +329,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.line_total-th'],
|
[data-ref='product_table-product.line_total-th'],
|
||||||
[data-ref='product_table-product.line_total-td'] {
|
[data-ref='product_table-product.line_total-td'],
|
||||||
width: 8%;
|
[data-ref='task_table-task.line_total-th'],
|
||||||
text-align: right;
|
[data-ref='task_table-task.line_total-td'] {
|
||||||
|
width: 10%;
|
||||||
|
text-align: right !important;
|
||||||
|
padding-right: 1rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.description-th'] {
|
[data-ref='task_table-task.description-th'] {
|
||||||
|
|
@ -352,11 +361,6 @@
|
||||||
width: 6%;
|
width: 6%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.line_total-th'],
|
|
||||||
[data-ref='task_table-task.line_total-td'] {
|
|
||||||
width: 8%;
|
|
||||||
text-align: right !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-radius {
|
.left-radius {
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
|
|
|
||||||
|
|
@ -254,18 +254,18 @@
|
||||||
[data-ref="totals_table-outstanding-label"]{
|
[data-ref="totals_table-outstanding-label"]{
|
||||||
background-color: var(--secondary-color);
|
background-color: var(--secondary-color);
|
||||||
color: white;
|
color: white;
|
||||||
padding-top: 7px;
|
font-size:120%;
|
||||||
padding-bottom: 7px;
|
font-weight:bold;
|
||||||
padding-right: 7px;
|
padding: 1rem;
|
||||||
border-top-left-radius: 7px;
|
border-top-left-radius: 7px;
|
||||||
border-bottom-left-radius: 7px;
|
border-bottom-left-radius: 7px;
|
||||||
}
|
}
|
||||||
[data-ref="totals_table-outstanding"] {
|
[data-ref="totals_table-outstanding"] {
|
||||||
background-color: var(--secondary-color);
|
background-color: var(--secondary-color);
|
||||||
color: white;
|
color: white;
|
||||||
padding-top: 7px;
|
font-size:120%;
|
||||||
padding-bottom: 7px;
|
font-weight:bold;
|
||||||
padding-right: 7px;
|
padding: 1rem;
|
||||||
border-top-right-radius: 7px;
|
border-top-right-radius: 7px;
|
||||||
border-bottom-right-radius: 7px;
|
border-bottom-right-radius: 7px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@
|
||||||
[data-ref='product_table-product.item-th'],
|
[data-ref='product_table-product.item-th'],
|
||||||
[data-ref='product_table-product.unit_cost-th'],
|
[data-ref='product_table-product.unit_cost-th'],
|
||||||
[data-ref='product_table-product.quantity-th'] {
|
[data-ref='product_table-product.quantity-th'] {
|
||||||
width: 10%;
|
width: 12%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.tax1-th'] {
|
[data-ref='product_table-product.tax1-th'] {
|
||||||
|
|
@ -289,7 +289,7 @@
|
||||||
[data-ref='task_table-task.discount-th'],
|
[data-ref='task_table-task.discount-th'],
|
||||||
[data-ref='task_table-task.cost-th'],
|
[data-ref='task_table-task.cost-th'],
|
||||||
[data-ref='task_table-task.quantity-th'] {
|
[data-ref='task_table-task.quantity-th'] {
|
||||||
width: 10%;
|
width: 12%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.tax1-th'] {
|
[data-ref='task_table-task.tax1-th'] {
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,53 @@
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[data-ref='product_table-product.description-th'],
|
||||||
|
[data-ref='product_table-product.description-td'] {
|
||||||
|
min-width: 150px !important;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.item-td']{
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.item-th'],
|
||||||
|
[data-ref='product_table-product.unit_cost-th'],
|
||||||
|
[data-ref='product_table-product.quantity-th'] {
|
||||||
|
width: 12%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.tax1-th'] {
|
||||||
|
width: 6%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.line_total-th'] {
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='task_table-task.description-th'],
|
||||||
|
[data-ref='task_table-task.description-td'] {
|
||||||
|
min-width: 100px !important;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='task_table-task.hours-th'],
|
||||||
|
[data-ref='task_table-task.service-th'],
|
||||||
|
[data-ref='task_table-task.discount-th'],
|
||||||
|
[data-ref='task_table-task.cost-th'],
|
||||||
|
[data-ref='task_table-task.quantity-th'] {
|
||||||
|
width: 12%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='task_table-task.tax1-th'] {
|
||||||
|
width: 6%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='task_table-task.line_total-th'] {
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
[data-ref="table"] > thead {
|
[data-ref="table"] > thead {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@
|
||||||
|
|
||||||
#table-totals > * > :last-child {
|
#table-totals > * > :last-child {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 1rem;
|
padding-right: 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
|
|
@ -255,7 +255,14 @@
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.description-td'] {
|
[data-ref='task_table-task.service-th'],
|
||||||
|
[data-ref='product_table-product.item-th'] {
|
||||||
|
padding-left:1rem !important;
|
||||||
|
width:14%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.description-td'],
|
||||||
|
[data-ref="task_table-task.description-td"] {
|
||||||
min-width:100px;
|
min-width:100px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
@ -266,17 +273,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref="product_table-product.unit_cost-td"],
|
[data-ref="product_table-product.unit_cost-td"],
|
||||||
[data-ref="product_table-product.unit_cost-th"]{
|
[data-ref="product_table-product.unit_cost-th"],
|
||||||
text-align: center;
|
[data-ref='task_table-task.cost-th'],
|
||||||
|
[data-ref='task_table-task.cost-td']{
|
||||||
|
text-align: center !important;
|
||||||
width: 10%;
|
width: 10%;
|
||||||
padding-left:0 !important;
|
padding-left:0 !important;
|
||||||
padding-right:0 !important;
|
padding-right:0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref="product_table-product.quantity-th"],
|
[data-ref="product_table-product.quantity-th"],
|
||||||
[data-ref="product_table-product.quantity-td"]{
|
[data-ref="product_table-product.quantity-td"],
|
||||||
|
[data-ref='task_table-task.hours-th'],
|
||||||
|
[data-ref='task_table-task.hours-td'] {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
text-align: center;
|
text-align: center !important;
|
||||||
padding-left:0 !important;
|
padding-left:0 !important;
|
||||||
padding-right:0 !important;
|
padding-right:0 !important;
|
||||||
}
|
}
|
||||||
|
|
@ -295,21 +306,8 @@
|
||||||
width: 13%;
|
width: 13%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.hours-th'],
|
|
||||||
[data-ref='task_table-task.hours-td'] {
|
|
||||||
text-align: center;
|
|
||||||
padding-left:0 !important;
|
|
||||||
padding-right:0 !important;
|
|
||||||
width: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='task_table-task.cost-th'],
|
|
||||||
[data-ref='task_table-task.cost-td'] {
|
|
||||||
text-align: center;
|
|
||||||
padding-left:0 !important;
|
|
||||||
padding-right:0 !important;
|
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref="task_table-task.line_total-th"],
|
[data-ref="task_table-task.line_total-th"],
|
||||||
[data-ref="task_table-task.line_total-td"] {
|
[data-ref="task_table-task.line_total-td"] {
|
||||||
|
|
@ -317,7 +315,16 @@
|
||||||
width: 13%;
|
width: 13%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref="totals_table-outstanding"] { color: var(--primary-color); }
|
[data-ref="totals_table-outstanding-label"] {
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref="totals_table-outstanding"] {
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:120%;
|
||||||
|
}
|
||||||
|
|
||||||
[data-ref="statement-totals"] {
|
[data-ref="statement-totals"] {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
|
|
@ -344,8 +351,6 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.stamp {
|
.stamp {
|
||||||
transform: rotate(12deg);
|
transform: rotate(12deg);
|
||||||
color: #555;
|
color: #555;
|
||||||
|
|
@ -487,18 +492,18 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="product-table" cellspacing="0" data-ref="table"></table>
|
<table id="product-table" cellspacing="0" data-ref="table"></table>
|
||||||
<table id="task-table" cellspacing="0" data-ref="table"></table>
|
<table id="task-table" cellspacing="0" data-ref="table"></table>
|
||||||
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
|
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
|
||||||
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
|
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
|
||||||
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
|
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
|
||||||
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
|
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
|
||||||
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
|
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
|
||||||
<table id="statement-credit-table" cellspacing="0" data-ref="table"></table>
|
<table id="statement-credit-table" cellspacing="0" data-ref="table"></table>
|
||||||
<div id="statement-credit-table-totals" data-ref="statement-totals"></div>
|
<div id="statement-credit-table-totals" data-ref="statement-totals"></div>
|
||||||
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
|
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
|
||||||
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
|
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
|
||||||
<div id="table-totals" cellspacing="0">$status_logo</div>
|
<div id="table-totals" cellspacing="0">$status_logo</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
||||||
|
|
@ -173,31 +173,36 @@
|
||||||
margin-top: 0rem;
|
margin-top: 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-content {
|
.footer-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
width: calc(100% - 2rem);
|
||||||
width: 100%;
|
margin: 0 1rem;
|
||||||
/* grid-template-columns: 1fr 1fr 1fr; */
|
|
||||||
color: #fff4e9;
|
color: #fff4e9;
|
||||||
max-height: 140px;
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 0.5rem;
|
align-items: flex-start;
|
||||||
margin-left: 0.5rem;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.footer-company-details-address-wrapper {
|
/* Main footer text area */
|
||||||
display: flex;
|
.footer-content > div:first-child {
|
||||||
gap: 0px;
|
width: 50%;
|
||||||
margin-right: 60px;
|
margin-right: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#company-address,
|
/* Company details/address wrapper */
|
||||||
#company-details {
|
.footer-company-details-address-wrapper {
|
||||||
|
width: 50%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#company-details,
|
||||||
|
#company-address {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-bottom: 0rem;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#company-address > *,
|
#company-address > *,
|
||||||
#company-details > * {
|
#company-details > * {
|
||||||
|
|
@ -302,25 +307,7 @@
|
||||||
[data-ref='product_table-product.product1-th'],
|
[data-ref='product_table-product.product1-th'],
|
||||||
[data-ref='product_table-product.product2-th'],
|
[data-ref='product_table-product.product2-th'],
|
||||||
[data-ref='product_table-product.product3-th'],
|
[data-ref='product_table-product.product3-th'],
|
||||||
[data-ref='product_table-product.product4-th'] {
|
[data-ref='product_table-product.product4-th'],
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='product_table-product.tax1-th'] {
|
|
||||||
width: 6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='product_table-product.line_total-th'],
|
|
||||||
[data-ref='product_table-product.line_total-td'] {
|
|
||||||
width: 8%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='task_table-task.description-th'] {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
min-width: 100px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='task_table-task.hours-th'],
|
[data-ref='task_table-task.hours-th'],
|
||||||
[data-ref='task_table-task.discount-th'],
|
[data-ref='task_table-task.discount-th'],
|
||||||
[data-ref='task_table-task.cost-th'],
|
[data-ref='task_table-task.cost-th'],
|
||||||
|
|
@ -329,7 +316,24 @@
|
||||||
[data-ref='task_table-task.task2-th'],
|
[data-ref='task_table-task.task2-th'],
|
||||||
[data-ref='task_table-task.task3-th'],
|
[data-ref='task_table-task.task3-th'],
|
||||||
[data-ref='task_table-task.task4-th'] {
|
[data-ref='task_table-task.task4-th'] {
|
||||||
width: 8%;
|
width: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.tax1-th'] {
|
||||||
|
width: 6%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='product_table-product.line_total-th'],
|
||||||
|
[data-ref='product_table-product.line_total-td'],
|
||||||
|
[data-ref='task_table-task.line_total-th'],
|
||||||
|
[data-ref='task_table-task.line_total-td'] {
|
||||||
|
width: 12%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-ref='task_table-task.description-th'] {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
min-width: 100px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.service-th']{
|
[data-ref='task_table-task.service-th']{
|
||||||
|
|
@ -340,13 +344,6 @@
|
||||||
width: 6%;
|
width: 6%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.line_total-th'],
|
|
||||||
[data-ref='task_table-task.line_total-td'] {
|
|
||||||
width: 8%;
|
|
||||||
text-align: right !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.stamp {
|
.stamp {
|
||||||
transform: rotate(12deg);
|
transform: rotate(12deg);
|
||||||
color: #555;
|
color: #555;
|
||||||
|
|
@ -483,10 +480,8 @@ $entity_images
|
||||||
|
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
<div style="width: 70%; margin-left: 2rem;">
|
<div class="footer-text">
|
||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-company-details-address-wrapper">
|
<div class="footer-company-details-address-wrapper">
|
||||||
<div id="company-details"></div>
|
<div id="company-details"></div>
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref="table"]>thead>tr>th {
|
[data-ref="table"]>thead>tr>th {
|
||||||
padding: 0.5rem;
|
padding: 0.75rem;
|
||||||
background-color: #e6e6e6;
|
background-color: #e6e6e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,25 +238,28 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.description-td']{
|
[data-ref='product_table-product.description-td'],
|
||||||
|
[data-ref='task_table-task.description-th']{
|
||||||
min-width: 100px !important;
|
min-width: 100px !important;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.item-th']{
|
|
||||||
width: 10%;
|
[data-ref='product_table-product.item-th'],
|
||||||
}
|
[data-ref='product_table-product.unit_cost-th'],
|
||||||
|
[data-ref='task_table-task.service-th'],
|
||||||
[data-ref='product_table-product.unit_cost-th']{
|
[data-ref='task_table-task.cost-th']{
|
||||||
width: 10%;
|
width: 12%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.quantity-th'],
|
[data-ref='product_table-product.quantity-th'],
|
||||||
|
[data-ref='task_table-task.hours-th'],
|
||||||
|
[data-ref='task_table-task.quantity-th'],
|
||||||
[data-ref='product_table-product.product1-th'],
|
[data-ref='product_table-product.product1-th'],
|
||||||
[data-ref='product_table-product.product2-th'],
|
[data-ref='product_table-product.product2-th'],
|
||||||
[data-ref='product_table-product.product3-th'],
|
[data-ref='product_table-product.product3-th'],
|
||||||
[data-ref='product_table-product.product4-th'] {
|
[data-ref='product_table-product.product4-th'] {
|
||||||
width: 8%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.tax1-th'] {
|
[data-ref='product_table-product.tax1-th'] {
|
||||||
|
|
@ -264,43 +267,27 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.line_total-th'],
|
[data-ref='product_table-product.line_total-th'],
|
||||||
[data-ref='product_table-product.line_total-td'] {
|
[data-ref='product_table-product.line_total-td'],
|
||||||
width: 8%;
|
[data-ref='task_table-task.line_total-th'],
|
||||||
|
[data-ref='task_table-task.line_total-td'] {
|
||||||
|
width: 12%;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.description-th'] {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
min-width: 100px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[data-ref='task_table-task.hours-th'],
|
|
||||||
[data-ref='task_table-task.discount-th'],
|
[data-ref='task_table-task.discount-th'],
|
||||||
[data-ref='task_table-task.cost-th'],
|
|
||||||
[data-ref='task_table-task.quantity-th'],
|
|
||||||
[data-ref='task_table-task.task1-th'],
|
[data-ref='task_table-task.task1-th'],
|
||||||
[data-ref='task_table-task.task2-th'],
|
[data-ref='task_table-task.task2-th'],
|
||||||
[data-ref='task_table-task.task3-th'],
|
[data-ref='task_table-task.task3-th'],
|
||||||
[data-ref='task_table-task.task4-th'] {
|
[data-ref='task_table-task.task4-th'] {
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='task_table-task.service-th']{
|
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[data-ref='task_table-task.tax1-th'] {
|
[data-ref='task_table-task.tax1-th'] {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.line_total-th'],
|
|
||||||
[data-ref='task_table-task.line_total-td'] {
|
|
||||||
width: 8%;
|
|
||||||
text-align: right !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.stamp {
|
.stamp {
|
||||||
transform: rotate(12deg);
|
transform: rotate(12deg);
|
||||||
color: #555;
|
color: #555;
|
||||||
|
|
|
||||||
|
|
@ -277,20 +277,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[data-ref='product_table-product.description-td']{
|
[data-ref='product_table-product.description-td'],
|
||||||
|
[data-ref='task_table-task.description-td']{
|
||||||
min-width: 100px !important;
|
min-width: 100px !important;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.item-th']{
|
[data-ref='product_table-product.item-th'],
|
||||||
|
[data-ref='task_table-task.service-th']{
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.unit_cost-th']{
|
[data-ref='product_table-product.unit_cost-th'],
|
||||||
|
[data-ref='task_table-task.cost-th'] {
|
||||||
width: 13%;
|
width: 13%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='product_table-product.quantity-th'],
|
[data-ref='product_table-product.quantity-th'],
|
||||||
|
[data-ref='task_table-task.hours-th'],
|
||||||
[data-ref='product_table-product.product1-th'],
|
[data-ref='product_table-product.product1-th'],
|
||||||
[data-ref='product_table-product.product2-th'],
|
[data-ref='product_table-product.product2-th'],
|
||||||
[data-ref='product_table-product.product3-th'],
|
[data-ref='product_table-product.product3-th'],
|
||||||
|
|
@ -308,26 +312,15 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-ref='task_table-task.description-th'] {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
min-width: 100px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[data-ref='task_table-task.hours-th'],
|
|
||||||
[data-ref='task_table-task.discount-th'],
|
[data-ref='task_table-task.discount-th'],
|
||||||
[data-ref='task_table-task.cost-th'],
|
|
||||||
[data-ref='task_table-task.quantity-th'],
|
[data-ref='task_table-task.quantity-th'],
|
||||||
[data-ref='task_table-task.task1-th'],
|
[data-ref='task_table-task.task1-th'],
|
||||||
[data-ref='task_table-task.task2-th'],
|
[data-ref='task_table-task.task2-th'],
|
||||||
[data-ref='task_table-task.task3-th'],
|
[data-ref='task_table-task.task3-th'],
|
||||||
[data-ref='task_table-task.task4-th'] {
|
[data-ref='task_table-task.task4-th'] {
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-ref='task_table-task.service-th']{
|
|
||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[data-ref='task_table-task.tax1-th'] {
|
[data-ref='task_table-task.tax1-th'] {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,36 @@ class RecurringInvoiceTest extends TestCase
|
||||||
$this->makeTestData();
|
$this->makeTestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUniqueNumber()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
'frequency_id' => 5,
|
||||||
|
'next_send_date' => now()->addMonth()->format('Y-m-d'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/recurring_invoices', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$arr = $response->json();
|
||||||
|
|
||||||
|
$this->assertNotNull($arr['data']['number']);
|
||||||
|
|
||||||
|
$data['number'] = $arr['data']['number'];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/recurring_invoices', $data)
|
||||||
|
->assertStatus(422);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testBulkUpdatesTaxes()
|
public function testBulkUpdatesTaxes()
|
||||||
{
|
{
|
||||||
RecurringInvoice::factory(5)->create([
|
RecurringInvoice::factory(5)->create([
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace Tests\Unit;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
|
|
@ -36,6 +37,32 @@ class ClientSettingsTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testBadProps()
|
||||||
|
{
|
||||||
|
$client = \App\Models\Client::factory()->create([
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'settings' => ClientSettings::defaults(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertNotNull($client);
|
||||||
|
|
||||||
|
$settings = $client->settings;
|
||||||
|
|
||||||
|
$settings->timezone_id = '15';
|
||||||
|
|
||||||
|
$client->saveSettings($settings, $client);
|
||||||
|
|
||||||
|
$this->assertNotNull($client);
|
||||||
|
|
||||||
|
$settings->something_crazy_here = '5424234234';
|
||||||
|
|
||||||
|
$client->saveSettings($settings, $client);
|
||||||
|
|
||||||
|
$this->assertFalse(property_exists($client->settings, 'something_crazy_here'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testClientValidSettingsWithBadProps()
|
public function testClientValidSettingsWithBadProps()
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue