merge conflict from source

This commit is contained in:
karneaud 2024-08-15 21:13:07 -04:00
commit ee77bb11fc
72 changed files with 1936 additions and 460 deletions

View File

@ -8,7 +8,7 @@ assignees: ''
--- ---
<!-- Before posting please check our "Troubleshooting" category in the docs: <!-- Before posting please check our "Troubleshooting" category in the docs:
https://invoiceninja.github.io/docs/self-host-troubleshooting/ --> https://invoiceninja.github.io/en/self-host-troubleshooting/ -->
## Setup ## Setup
- Version: <!-- i.e. v4.5.25 / v5.0.30 --> - Version: <!-- i.e. v4.5.25 / v5.0.30 -->

View File

@ -1 +1 @@
5.10.19 5.10.24

View File

@ -130,9 +130,8 @@ class BaseRule implements RuleInterface
return $this; return $this;
} }
public function shouldCalcTax(): bool public function shouldCalcTax(): bool {
{ return $this->should_calc_tax && $this->checkIfInvoiceLocked();
return $this->should_calc_tax;
} }
/** /**
* Initializes the tax rule for the entity. * Initializes the tax rule for the entity.
@ -215,7 +214,7 @@ class BaseRule implements RuleInterface
$this->invoice->tax_data = $tax_data; $this->invoice->tax_data = $tax_data;
if(\DB::transactionLevel() == 0) { if(\DB::transactionLevel() == 0 && isset($this->invoice->id)) {
try { try {
$this->invoice->saveQuietly(); $this->invoice->saveQuietly();
@ -400,4 +399,36 @@ class BaseRule implements RuleInterface
return ! in_array($iso_3166_2, array_merge($this->eu_country_codes, array_keys($this->region_codes))); return ! in_array($iso_3166_2, array_merge($this->eu_country_codes, array_keys($this->region_codes)));
} }
private function checkIfInvoiceLocked(): bool
{
$lock_invoices = $this->client->getSetting('lock_invoices');
switch ($lock_invoices) {
case 'off':
return true;
case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) {
return false;
}
return true;
case 'when_paid':
if ($this->invoice->status_id == Invoice::STATUS_PAID) {
return false;
}
return true;
//if now is greater than the end of month the invoice was dated - do not modify
case 'end_of_month':
if(\Carbon\Carbon::parse($this->invoice->date)->setTimezone($this->invoice->company->timezone()->name)->endOfMonth()->lte(now())) {
return false;
}
return true;
default:
return true;
}
}
} }

View File

@ -43,6 +43,8 @@ class Rule extends BaseRule implements RuleInterface
public float $reduced_tax_rate = 0; public float $reduced_tax_rate = 0;
public string $tax_name1 = 'MwSt.'; public string $tax_name1 = 'MwSt.';
private string $tax_name;
/** /**
* Initializes the rules and builds any required data. * Initializes the rules and builds any required data.
* *
@ -50,6 +52,7 @@ class Rule extends BaseRule implements RuleInterface
*/ */
public function init(): self public function init(): self
{ {
$this->tax_name = $this->tax_name1;
$this->calculateRates(); $this->calculateRates();
return $this; return $this;
@ -91,6 +94,7 @@ class Rule extends BaseRule implements RuleInterface
*/ */
public function reverseTax($item): self public function reverseTax($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = 0; $this->tax_rate1 = 0;
return $this; return $this;
@ -103,6 +107,8 @@ class Rule extends BaseRule implements RuleInterface
*/ */
public function taxReduced($item): self public function taxReduced($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = $this->reduced_tax_rate; $this->tax_rate1 = $this->reduced_tax_rate;
return $this; return $this;
@ -115,6 +121,8 @@ class Rule extends BaseRule implements RuleInterface
*/ */
public function zeroRated($item): self public function zeroRated($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = 0; $this->tax_rate1 = 0;
return $this; return $this;
@ -142,6 +150,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxDigital($item): self public function taxDigital($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = $this->tax_rate; $this->tax_rate1 = $this->tax_rate;
return $this; return $this;
@ -155,6 +164,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxService($item): self public function taxService($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = $this->tax_rate; $this->tax_rate1 = $this->tax_rate;
return $this; return $this;
@ -168,6 +178,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxShipping($item): self public function taxShipping($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = $this->tax_rate; $this->tax_rate1 = $this->tax_rate;
return $this; return $this;
@ -181,6 +192,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxPhysical($item): self public function taxPhysical($item): self
{ {
$this->tax_name1 = $this->tax_name;
$this->tax_rate1 = $this->tax_rate; $this->tax_rate1 = $this->tax_rate;
return $this; return $this;

View File

@ -451,6 +451,7 @@ class BaseExport
'project' => 'task.project_id', 'project' => 'task.project_id',
'billable' => 'task.billable', 'billable' => 'task.billable',
'item_notes' => 'task.item_notes', 'item_notes' => 'task.item_notes',
'time_log' => 'task.time_log',
]; ];
protected array $forced_client_fields = [ protected array $forced_client_fields = [

View File

@ -156,7 +156,7 @@ class TaskExport extends BaseExport
$entity[$key] = $transformed_entity[$parts[1]]; $entity[$key] = $transformed_entity[$parts[1]];
} elseif (array_key_exists($key, $transformed_entity)) { } elseif (array_key_exists($key, $transformed_entity)) {
$entity[$key] = $transformed_entity[$key]; $entity[$key] = $transformed_entity[$key];
} elseif (in_array($key, ['task.start_date', 'task.end_date', 'task.duration', 'task.billable', 'task.item_notes'])) { } elseif (in_array($key, ['task.start_date', 'task.end_date', 'task.duration', 'task.billable', 'task.item_notes', 'task.time_log'])) {
$entity[$key] = ''; $entity[$key] = '';
} else { } else {
$entity[$key] = $this->decorator->transform($key, $task); $entity[$key] = $this->decorator->transform($key, $task);
@ -207,6 +207,9 @@ class TaskExport extends BaseExport
$seconds = $task->calcDuration(); $seconds = $task->calcDuration();
$entity['task.duration'] = $seconds; $entity['task.duration'] = $seconds;
$entity['task.duration_words'] = $seconds > 86400 ? CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans() : now()->startOfDay()->addSeconds($seconds)->format('H:i:s'); $entity['task.duration_words'] = $seconds > 86400 ? CarbonInterval::seconds($seconds)->locale($this->company->locale())->cascade()->forHumans() : now()->startOfDay()->addSeconds($seconds)->format('H:i:s');
$entity['task.time_log'] = (isset($item[1]) && $item[1] != 0) ? $item[1] - $item[0] : ctrans('texts.is_running');
} }
if (in_array('task.billable', $this->input['report_keys']) || in_array('billable', $this->input['report_keys'])) { if (in_array('task.billable', $this->input['report_keys']) || in_array('billable', $this->input['report_keys'])) {

View File

@ -98,7 +98,14 @@ class CreditFilters extends QueryFilters
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}) })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']); ->orWhereRaw("
JSON_UNQUOTE(JSON_EXTRACT(
JSON_ARRAY(
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')),
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].product_key'))
), '$[*]')
) LIKE ?", ['%'.$filter.'%']);
// ->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -158,6 +158,18 @@ class ExpenseFilters extends QueryFilters
return $this->builder; return $this->builder;
} }
public function categories(string $categories = ''): Builder
{
$categories_exploded = explode(",", $categories);
if(empty($categories) || count(array_filter($categories_exploded)) == 0)
return $this->builder;
$categories_keys = $this->transformKeys($categories_exploded);
return $this->builder->whereIn('category_id', $categories_keys);
}
public function number(string $number = ''): Builder public function number(string $number = ''): Builder
{ {
if (strlen($number) == 0) { if (strlen($number) == 0) {

View File

@ -125,7 +125,14 @@ class InvoiceFilters extends QueryFilters
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}) })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']); ->orWhereRaw("
JSON_UNQUOTE(JSON_EXTRACT(
JSON_ARRAY(
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')),
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].product_key'))
), '$[*]')
) LIKE ?", ['%'.$filter.'%']);
// ->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -96,7 +96,14 @@ class PurchaseOrderFilters extends QueryFilters
->orWhere('custom_value4', 'like', '%'.$filter.'%') ->orWhere('custom_value4', 'like', '%'.$filter.'%')
->orWhereHas('vendor', function ($q) use ($filter) { ->orWhereHas('vendor', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%'); $q->where('name', 'like', '%'.$filter.'%');
}); })
->orWhereRaw("
JSON_UNQUOTE(JSON_EXTRACT(
JSON_ARRAY(
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')),
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].product_key'))
), '$[*]')
) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -46,7 +46,14 @@ class QuoteFilters extends QueryFilters
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}) })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']); ->orWhereRaw("
JSON_UNQUOTE(JSON_EXTRACT(
JSON_ARRAY(
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')),
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].product_key'))
), '$[*]')
) LIKE ?", ['%'.$filter.'%']);
// ->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -49,7 +49,14 @@ class RecurringInvoiceFilters extends QueryFilters
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}) })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']); ->orWhereRaw("
JSON_UNQUOTE(JSON_EXTRACT(
JSON_ARRAY(
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')),
JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].product_key'))
), '$[*]')
) LIKE ?", ['%'.$filter.'%']);
//->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -85,6 +85,10 @@ class TaskFilters extends QueryFilters
$this->builder->whereNull('invoice_id'); $this->builder->whereNull('invoice_id');
} }
if (in_array('is_running', $status_parameters)) {
$this->builder->where('is_running', true);
}
return $this->builder; return $this->builder;
} }

View File

@ -51,9 +51,9 @@ class EmailHistoryController extends BaseController
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
$data = SystemLog::where('company_id', $user->company()->id) $data = SystemLog::where('company_id', $user->company()->id)
->where('category_id', SystemLog::CATEGORY_MAIL) ->where('category_id', SystemLog::CATEGORY_MAIL)
->whereJsonContains('log->history->entity', $request->entity)
->whereJsonContains('log->history->entity_id', $this->encodePrimaryKey($request->entity_id)) ->whereJsonContains('log->history->entity_id', $this->encodePrimaryKey($request->entity_id))
->orderBy('id', 'DESC') ->orderBy('id', 'DESC')
->cursor() ->cursor()

View File

@ -40,10 +40,10 @@ class BulkInvoiceRequest extends Request
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|".$this->input('action', 0)."|".json_encode($this->input('ids', ''))."|".$user->company()->company_key)) if(\Illuminate\Support\Facades\Cache::has($this->ip()."|".$this->input('action', 0)."|".$user->company()->company_key))
throw new DuplicatePaymentException('Duplicate request.', 429); throw new DuplicatePaymentException('Duplicate request.', 429);
\Illuminate\Support\Facades\Cache::put(($this->ip()."|".$this->input('action', 0)."|".json_encode($this->input('ids', ''))."|".$user->company()->company_key), true, 1); \Illuminate\Support\Facades\Cache::put(($this->ip()."|".$this->input('action', 0)."|".$user->company()->company_key), true, 1);
} }

View File

@ -67,7 +67,7 @@ class UpdateTaskRequest extends Request
if(is_string($values)) { if(is_string($values)) {
$values = json_decode($values, true); $values = json_decode($values, true);
} }
if(!is_array($values)) { if(!is_array($values)) {
$fail('The '.$attribute.' must be a valid array.'); $fail('The '.$attribute.' must be a valid array.');
return; return;
@ -133,7 +133,7 @@ class UpdateTaskRequest extends Request
} }
if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}') { if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}' || $input['time_log'] == '[""]') {
$input['time_log'] = json_encode([]); $input['time_log'] = json_encode([]);
} }

View File

@ -53,7 +53,6 @@ class ContactComponent extends Component
public function render() public function render()
{ {
\Debugbar::debug($this->attributes->getAttributes() + $this->defaults);
return render('gateways.rotessa.components.contact', $this->attributes->getAttributes() + $this->defaults ); return render('gateways.rotessa.components.contact', $this->attributes->getAttributes() + $this->defaults );
} }
} }

View File

@ -254,7 +254,7 @@ class NinjaMailerJob implements ShouldQueue
private function incrementEmailCounter(): void private function incrementEmailCounter(): void
{ {
if(in_array($this->mailer, ['default','mailgun','postmark'])) { if(in_array($this->nmo->settings->email_sending_method, ['default','mailgun','postmark'])) {
Cache::increment("email_quota".$this->company->account->key); Cache::increment("email_quota".$this->company->account->key);
} }

View File

@ -79,7 +79,7 @@ class AdjustEmailQuota implements ShouldQueue
/** Use redis pipelines to execute bulk deletes efficiently */ /** Use redis pipelines to execute bulk deletes efficiently */
$redis = Redis::connection('sentinel-cache'); $redis = Redis::connection('sentinel-cache');
$prefix = config('cache.prefix'). ":email_quota*"; $prefix = config('cache.prefix'). "email_quota*";
$keys = $redis->keys($prefix); $keys = $redis->keys($prefix);
@ -92,7 +92,7 @@ class AdjustEmailQuota implements ShouldQueue
} }
$keys = null; $keys = null;
$prefix = config('cache.prefix'). ":throttle_notified*"; $prefix = config('cache.prefix'). "throttle_notified*";
$keys = $redis->keys($prefix); $keys = $redis->keys($prefix);

View File

@ -58,10 +58,6 @@ class EmailPayment implements ShouldQueue
*/ */
public function handle() public function handle()
{ {
if ($this->company->is_disabled || (!$this->contact?->email ?? false)) {
nlog("company disabled - or - contact email not found");
return;
}
MultiDB::setDb($this->company->db); MultiDB::setDb($this->company->db);
@ -71,6 +67,11 @@ class EmailPayment implements ShouldQueue
$this->contact = $this->payment->client->contacts()->orderBy('is_primary', 'desc')->first(); $this->contact = $this->payment->client->contacts()->orderBy('is_primary', 'desc')->first();
} }
if ($this->company->is_disabled || (!$this->contact?->email ?? false)) {
nlog("company disabled - or - contact email not found");
return;
}
$this->contact->load('client'); $this->contact->load('client');
$email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build(); $email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build();

View File

@ -349,7 +349,11 @@ class BillingPortalPurchase extends Component
} }
if ((int)$this->price == 0) { if ((int)$this->price == 0) {
$this->steps['payment_required'] = false; $this->steps['payment_required'] = false;
$this->steps['fetched_payment_methods'] = false;
$this->heading_text = ctrans('texts.payment_methods');
return $this;
} else { } else {
// $this->steps['fetched_payment_methods'] = true; // $this->steps['fetched_payment_methods'] = true;
} }

View File

@ -262,6 +262,7 @@ class PaymentEmailEngine extends BaseEmailEngine
$data['$client.email'] = &$data['$email']; $data['$client.email'] = &$data['$email'];
$data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
$data['$client.payment_balance'] = ['value' => Number::formatMoney($this->client->payment_balance, $this->client), 'label' => ctrans('texts.payment_balance_on_file')];
$data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; $data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
$data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; $data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')]; $data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];

View File

@ -431,7 +431,7 @@ class Invoice extends BaseModel
public function isPayable(): bool public function isPayable(): bool
{ {
if($this->is_deleted) if($this->is_deleted || $this->status_id == self::STATUS_PAID)
return false; return false;
elseif ($this->status_id == self::STATUS_DRAFT && $this->is_deleted == false) { elseif ($this->status_id == self::STATUS_DRAFT && $this->is_deleted == false) {
return true; return true;
@ -614,17 +614,17 @@ class Invoice extends BaseModel
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
case 'reminder1': case 'reminder1':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
break; break;
case 'reminder2': case 'reminder2':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
break; break;
case 'reminder3': case 'reminder3':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
break; break;
case 'reminder_endless': case 'reminder_endless':
case 'endless_reminder': case 'endless_reminder':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
break; break;
case 'custom1': case 'custom1':
case 'custom2': case 'custom2':

View File

@ -232,7 +232,7 @@ class BaseDriver extends AbstractPaymentDriver
* *
* @param ClientGatewayToken $cgt The client gateway token object * @param ClientGatewayToken $cgt The client gateway token object
* @param PaymentHash $payment_hash The Payment hash containing the payment meta data * @param PaymentHash $payment_hash The Payment hash containing the payment meta data
* @return void The payment response * @return ?Payment|bool The payment response
*/ */
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
{ {
@ -305,7 +305,7 @@ class BaseDriver extends AbstractPaymentDriver
public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment
{ {
if (in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING])) { if (in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING])) {
$this->confirmGatewayFee(); $this->confirmGatewayFee($data);
} }
/*Never create a payment with a duplicate transaction reference*/ /*Never create a payment with a duplicate transaction reference*/
@ -388,10 +388,9 @@ class BaseDriver extends AbstractPaymentDriver
* *
* @return void Success/Failure * @return void Success/Failure
*/ */
public function confirmGatewayFee(): void public function confirmGatewayFee($data = []): void
{ {
/*Payment invoices*/ nlog("confirming gateway fee");
$payment_invoices = $this->payment_hash->invoices();
/*Fee charged at gateway*/ /*Fee charged at gateway*/
$fee_total = $this->payment_hash->fee_total; $fee_total = $this->payment_hash->fee_total;
@ -399,21 +398,16 @@ class BaseDriver extends AbstractPaymentDriver
if(!$fee_total || $fee_total == 0) if(!$fee_total || $fee_total == 0)
return; return;
$invoices = Invoice::query() $invoice = $this->payment_hash->fee_invoice;
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
->whereJsonContains('line_items', ['type_id' => '3'])
->withTrashed();
if($invoices->count() == 0){ $fee_count = collect($invoice->line_items)
->whereIn('type_id', ['3','4'])
->where('gross_line_total', $fee_total)
->count();
$invoice = Invoice::query() if($invoice && $fee_count == 0){
->whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))
->orderBy('id','desc')
->withTrashed()
->first();
if(!$invoice) nlog("apparently no fee, so injecting here!");
return;
$balance = $invoice->balance; $balance = $invoice->balance;
@ -432,6 +426,16 @@ class BaseDriver extends AbstractPaymentDriver
$invoice_items = (array) $invoice->line_items; $invoice_items = (array) $invoice->line_items;
$invoice_items[] = $invoice_item; $invoice_items[] = $invoice_item;
if (isset($data['gateway_type_id']) && $fees_and_limits = $this->company_gateway->getFeesAndLimits($data['gateway_type_id'])) {
$invoice_item->tax_rate1 = $fees_and_limits->fee_tax_rate1;
$invoice_item->tax_name1 = $fees_and_limits->fee_tax_name1;
$invoice_item->tax_rate2 = $fees_and_limits->fee_tax_rate2;
$invoice_item->tax_name2 = $fees_and_limits->fee_tax_name2;
$invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3;
$invoice_item->tax_name3 = $fees_and_limits->fee_tax_name3;
$invoice_item->tax_id = (string)\App\Models\Product::PRODUCT_TYPE_OVERRIDE_TAX;
}
$invoice->line_items = $invoice_items; $invoice->line_items = $invoice_items;
/**Refresh Invoice values*/ /**Refresh Invoice values*/
@ -452,15 +456,10 @@ class BaseDriver extends AbstractPaymentDriver
} }
else { else {
$invoices $invoice->service()->toggleFeesPaid()->save();
->cursor()
->each(function ($i){
$i->service()->toggleFeesPaid()->save();
});
} }
} }
/** /**
@ -472,11 +471,8 @@ class BaseDriver extends AbstractPaymentDriver
*/ */
public function unWindGatewayFees(PaymentHash $payment_hash) public function unWindGatewayFees(PaymentHash $payment_hash)
{ {
$invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); if($payment_hash->fee_invoice)
$payment_hash->fee_invoice->service()->removeUnpaidGatewayFees();
$invoices->each(function ($invoice) {
$invoice->service()->removeUnpaidGatewayFees();
});
} }
/** /**

View File

@ -241,7 +241,6 @@ class BraintreePaymentDriver extends BaseDriver
]); ]);
if ($result->success) { if ($result->success) {
$this->confirmGatewayFee();
$data = [ $data = [
'payment_type' => PaymentType::parseCardType(strtolower($result->transaction->creditCard['cardType'])), 'payment_type' => PaymentType::parseCardType(strtolower($result->transaction->creditCard['cardType'])),
@ -249,6 +248,8 @@ class BraintreePaymentDriver extends BaseDriver
'transaction_reference' => $result->transaction->id, 'transaction_reference' => $result->transaction->id,
'gateway_type_id' => GatewayType::CREDIT_CARD, 'gateway_type_id' => GatewayType::CREDIT_CARD,
]; ];
$this->confirmGatewayFee($data);
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, Payment::STATUS_COMPLETED);

View File

@ -242,7 +242,12 @@ class CreditCard implements MethodInterface
} }
if ($response['status'] == 'Pending') { if ($response['status'] == 'Pending') {
$this->checkout->confirmGatewayFee();
$data = [
'gateway_type_id' => GatewayType::CREDIT_CARD,
];
$this->checkout->confirmGatewayFee($data);
return $this->processPendingPayment($response); return $this->processPendingPayment($response);
} }

View File

@ -406,15 +406,17 @@ class CheckoutComPaymentDriver extends BaseDriver
$response = $this->gateway->getPaymentsClient()->requestPayment($paymentRequest); $response = $this->gateway->getPaymentsClient()->requestPayment($paymentRequest);
if ($response['status'] == 'Authorized') { if ($response['status'] == 'Authorized') {
$this->confirmGatewayFee($request);
$data = [ $data = [
'payment_method' => $response['source']['id'], 'payment_method' => $response['source']['id'],
'payment_type' => PaymentType::parseCardType(strtolower($response['source']['scheme'])), 'payment_type' => PaymentType::parseCardType(strtolower($response['source']['scheme'])),
'amount' => $amount, 'amount' => $amount,
'transaction_reference' => $response['id'], 'transaction_reference' => $response['id'],
'gateway_type_id' => GatewayType::CREDIT_CARD,
]; ];
$this->confirmGatewayFee($data);
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, Payment::STATUS_COMPLETED);
SystemLogger::dispatch( SystemLogger::dispatch(

View File

@ -17,6 +17,54 @@ use App\Models\Company;
class ForteCustomerFactory class ForteCustomerFactory
{ {
public function convertToForte(Client $client): array
{
return [
"first_name" => $client->present()->first_name(),
"last_name" => $client->present()->last_name(),
"company_name" => $client->present()->name(),
"addresses" => [
[
"label" => "Billing Address",
"first_name" => $client->present()->first_name(),
"last_name" => $client->present()->last_name(),
"company_name" => $client->present()->name(),
"phone" => $client->present()->phone(),
"email" => $client->present()->email(),
"shipping_address_type" => "commercial",
"address_type" => "default_shipping",
"physical_address" => [
"street_line1" => $client->address2,
"street_line2" => $client->address1,
"locality" => $client->city,
"region" => $client->state,
"postal_code" => $client->postal_code
]
],
// [
// "label" => "Brown Billing",
// "first_name" => "Emmett",
// "last_name" => "Brown",
// "company_name" => "Brown Associates",
// "phone" => "444-444-4444",
// "email" => "e.brown@forte.net",
// "shipping_address_type" => "commercial",
// "address_type" => "default_billing",
// "physical_address" => [
// "street_line1" => "500 Delorean Dr",
// "street_line2" => "Suite 200",
// "locality" => "Hill Valley",
// "region" => "CA",
// "postal_code" => "95420"
// ]
// ]
]
];
}
public function convertToNinja(array $customer, Company $company): array public function convertToNinja(array $customer, Company $company): array
{ {
return return

View File

@ -12,6 +12,7 @@
namespace App\PaymentDrivers\Forte; namespace App\PaymentDrivers\Forte;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Jobs\Util\SystemLogger; use App\Jobs\Util\SystemLogger;
use App\Models\GatewayType; use App\Models\GatewayType;
@ -59,22 +60,99 @@ class CreditCard
public function authorizeResponse($request) public function authorizeResponse($request)
{ {
$payment_meta = new \stdClass(); $cst = $this->forte->findOrCreateCustomer();
$payment_meta->exp_month = (string) $request->expire_month;
$payment_meta->exp_year = (string) $request->expire_year;
$payment_meta->brand = (string) $request->card_type;
$payment_meta->last4 = (string) $request->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [ $data = [
'payment_meta' => $payment_meta, "label" => $request->card_holders_name." " .$request->card_type,
'token' => $request->one_time_token, "notes" => $request->card_holders_name." " .$request->card_type,
'payment_method_id' => $request->payment_method_id, "card" => [
"one_time_token" => $request->one_time_token,
"name_on_card" => $request->card_holders_name
],
]; ];
$this->forte->storeGatewayToken($data); $response = $this->forte->stubRequest()
->post("{$this->forte->baseUri()}/organizations/{$this->forte->getOrganisationId()}/locations/{$this->forte->getLocationId()}/customers/{$cst}/paymethods", $data);
if($response->successful()){
$token = $response->object();
$payment_meta = new \stdClass();
$payment_meta->exp_month = (string) $request->expire_month;
$payment_meta->exp_year = (string) $request->expire_year;
$payment_meta->brand = (string) $request->card_brand;
$payment_meta->last4 = (string) $request->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [
'payment_meta' => $payment_meta,
'token' => $token->paymethod_token,
'payment_method_id' => $request->payment_method_id,
];
$this->forte->storeGatewayToken($data, ['gateway_customer_reference' => $cst]);
return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
}
$error = $response->object();
$message = [
'server_message' => $error->response->response_desc,
'server_response' => $response->json(),
'data' => $data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_FORTE,
$this->client,
$this->client->company,
);
throw new \App\Exceptions\PaymentFailed("Unable to store payment method: {$error->response->response_desc}", 400);
}
private function createPaymentToken($request)
{
$cst = $this->forte->findOrCreateCustomer();
$data = [
"label" => $this->forte->client->present()->name(),
"notes" => $this->forte->client->present()->name(),
"card" => [
"one_time_token" => $request->payment_token,
"name_on_card" => $this->forte->client->present()->first_name(). " ". $this->forte->client->present()->last_name()
],
];
$response = $this->forte->stubRequest()
->post("{$this->forte->baseUri()}/organizations/{$this->forte->getOrganisationId()}/locations/{$this->forte->getLocationId()}/customers/{$cst}/paymethods", $data);
if($response->successful()){
$token = $response->object();
$payment_meta = new \stdClass();
$payment_meta->exp_month = (string) $request->expire_month;
$payment_meta->exp_year = (string) $request->expire_year;
$payment_meta->brand = (string) $request->card_brand;
$payment_meta->last4 = (string) $request->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [
'payment_meta' => $payment_meta,
'token' => $token->paymethod_token,
'payment_method_id' => $request->payment_method_id,
];
$this->forte->storeGatewayToken($data, ['gateway_customer_reference' => $cst]);
}
return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
} }
public function paymentView(array $data) public function paymentView(array $data)
@ -88,7 +166,20 @@ class CreditCard
public function paymentResponse(PaymentResponseRequest $request) public function paymentResponse(PaymentResponseRequest $request)
{ {
$payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->firstOrFail(); $payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->firstOrFail();
if(strlen($request->token ?? '') > 3){
$cgt = \App\Models\ClientGatewayToken::find($this->decodePrimaryKey($request->token));
$payment = $this->forte->tokenBilling($cgt, $payment_hash);
return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
}
$amount_with_fee = $payment_hash->data->total->amount_with_fee; $amount_with_fee = $payment_hash->data->total->amount_with_fee;
$invoice_totals = $payment_hash->data->total->invoice_totals; $invoice_totals = $payment_hash->data->total->invoice_totals;
$fee_total = null; $fee_total = null;
@ -126,8 +217,8 @@ class CreditCard
"authorization_amount":'.$amount_with_fee.', "authorization_amount":'.$amount_with_fee.',
"service_fee_amount":'.$fee_total.', "service_fee_amount":'.$fee_total.',
"billing_address":{ "billing_address":{
"first_name":"'.$this->forte->client->name.'", "first_name":"'.$this->forte->client->present()->first_name().'",
"last_name":"'.$this->forte->client->name.'" "last_name":"'.$this->forte->client->present()->last_name().'"
}, },
"card":{ "card":{
"one_time_token":"'.$request->payment_token.'" "one_time_token":"'.$request->payment_token.'"
@ -146,6 +237,7 @@ class CreditCard
curl_close($curl); curl_close($curl);
$response = json_decode($response); $response = json_decode($response);
} catch (\Throwable $th) { } catch (\Throwable $th) {
throw $th; throw $th;
} }
@ -187,7 +279,11 @@ class CreditCard
'gateway_type_id' => GatewayType::CREDIT_CARD, 'gateway_type_id' => GatewayType::CREDIT_CARD,
]; ];
$payment = $this->forte->createPayment($data, Payment::STATUS_COMPLETED); $payment = $this->forte->createPayment($data, Payment::STATUS_COMPLETED);
// return redirect('client/invoices')->withSuccess('Invoice paid.');
if($request->store_card) {
$this->createPaymentToken($request);
}
return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]); return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
} }

View File

@ -11,6 +11,7 @@
namespace App\PaymentDrivers; namespace App\PaymentDrivers;
use App\Exceptions\PaymentFailed;
use App\Models\Payment; use App\Models\Payment;
use App\Models\SystemLog; use App\Models\SystemLog;
use App\Models\GatewayType; use App\Models\GatewayType;
@ -224,7 +225,7 @@ class FortePaymentDriver extends BaseDriver
return $forte_base_uri; return $forte_base_uri;
} }
private function getOrganisationId(): string public function getOrganisationId(): string
{ {
return $this->company_gateway->getConfigField('organizationId'); return $this->company_gateway->getConfigField('organizationId');
} }
@ -247,12 +248,90 @@ class FortePaymentDriver extends BaseDriver
private function getClient(?string $email) private function getClient(?string $email)
{ {
if(!$email)
return false;
return ClientContact::query() return ClientContact::query()
->where('company_id', $this->company_gateway->company_id) ->where('company_id', $this->company_gateway->company_id)
->where('email', $email) ->where('email', $email)
->first(); ->first();
} }
public function tokenBilling(\App\Models\ClientGatewayToken $cgt, \App\Models\PaymentHash $payment_hash)
{
$amount_with_fee = $payment_hash->data->amount_with_fee;
$fee_total = $payment_hash->fee_total;
$data =
[
"action" => "sale",
"authorization_amount" => $amount_with_fee,
"paymethod_token" => $cgt->token,
"billing_address" => [
"first_name" => $this->client->present()->first_name(),
"last_name" => $this->client->present()->last_name()
],
];
if($fee_total > 0){
$data["service_fee_amount"] = $fee_total;
}
$response = $this->stubRequest()
->post("{$this->baseUri()}/organizations/{$this->getOrganisationId()}/locations/{$this->getLocationId()}/transactions", $data);
$forte_response = $response->object();
if($response->successful()){
$data = [
'payment_method' => $cgt->gateway_type_id,
'payment_type' => $cgt->gateway_type_id == 2 ? \App\Models\PaymentType::ACH : \App\Models\PaymentType::CREDIT_CARD_OTHER,
'amount' => $payment_hash->data->amount_with_fee,
'transaction_reference' => $forte_response->transaction_id,
'gateway_type_id' => $cgt->gateway_type_id,
];
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED);
$message = [
'server_message' => $forte_response->response->response_desc,
'server_response' => $response->json(),
'data' => $data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_FORTE,
$this->client,
$this->client->company,
);
return $payment;
}
$message = [
'server_message' => $forte_response->response->response_desc,
'server_response' => $response->json(),
'data' => $data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_FORTE,
$this->client,
$this->client->company,
);
throw new PaymentFailed($forte_response->response->response_desc, 500);
}
public function getLocation() public function getLocation()
{ {
@ -264,6 +343,8 @@ class FortePaymentDriver extends BaseDriver
return $response->json(); return $response->json();
} }
// return $response->body();
return false; return false;
} }
@ -297,6 +378,43 @@ class FortePaymentDriver extends BaseDriver
} }
public function findOrCreateCustomer()
{
$client_gateway_token = \App\Models\ClientGatewayToken::query()
->where('client_id', $this->client->id)
->where('company_gateway_id', $this->company_gateway->id)
->whereNotLike('token', 'ott_%')
->first();
if($client_gateway_token){
return $client_gateway_token->gateway_customer_reference;
}
else {
$factory = new ForteCustomerFactory();
$data = $factory->convertToForte($this->client);
$response = $this->stubRequest()
->post("{$this->baseUri()}/organizations/{$this->getOrganisationId()}/locations/{$this->getLocationId()}/customers/", $data);
//create customer
if($response->successful()){
$customer = $response->object();
nlog($customer);
return $customer->customer_token;
}
nlog($response->body());
throw new PaymentFailed("Unable to create customer in Forte", 400);
//@todo add syslog here
}
}
public function importCustomers() public function importCustomers()
{ {

View File

@ -165,8 +165,7 @@ class GoCardlessPaymentDriver extends BaseDriver
]); ]);
if (in_array($payment->status, ['submitted', 'pending_submission'])) { if (in_array($payment->status, ['submitted', 'pending_submission'])) {
$this->confirmGatewayFee();
$data = [ $data = [
'payment_method' => $cgt->hashed_id, 'payment_method' => $cgt->hashed_id,
'payment_type' => PaymentType::ACH, 'payment_type' => PaymentType::ACH,
@ -175,6 +174,8 @@ class GoCardlessPaymentDriver extends BaseDriver
'gateway_type_id' => GatewayType::BANK_TRANSFER, 'gateway_type_id' => GatewayType::BANK_TRANSFER,
]; ];
$this->confirmGatewayFee($data);
$payment = $this->createPayment($data, Payment::STATUS_PENDING); $payment = $this->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch( SystemLogger::dispatch(

View File

@ -171,7 +171,7 @@ class MolliePaymentDriver extends BaseDriver
]; ];
} catch (ApiException $e) { } catch (ApiException $e) {
SystemLogger::dispatch( SystemLogger::dispatch(
['server_response' => $refund, 'data' => request()->all()], ['server_response' => $e->getMessage(), 'data' => request()->all()],
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_MOLLIE, SystemLog::TYPE_MOLLIE,
@ -223,7 +223,7 @@ class MolliePaymentDriver extends BaseDriver
]); ]);
if ($payment->status === 'paid') { if ($payment->status === 'paid') {
$this->confirmGatewayFee($request);
$data = [ $data = [
'payment_method' => $cgt->token, 'payment_method' => $cgt->token,
@ -233,6 +233,8 @@ class MolliePaymentDriver extends BaseDriver
'gateway_type_id' => GatewayType::CREDIT_CARD, 'gateway_type_id' => GatewayType::CREDIT_CARD,
]; ];
$this->confirmGatewayFee($data);
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, Payment::STATUS_COMPLETED);
SystemLogger::dispatch( SystemLogger::dispatch(
@ -284,7 +286,7 @@ class MolliePaymentDriver extends BaseDriver
public function processWebhookRequest(PaymentWebhookRequest $request) public function processWebhookRequest(PaymentWebhookRequest $request)
{ {
// Allow app to catch up with webhook request. // Allow app to catch up with webhook request.
sleep(2); sleep(4);
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'id' => ['required', 'starts_with:tr'], 'id' => ['required', 'starts_with:tr'],
@ -335,6 +337,8 @@ class MolliePaymentDriver extends BaseDriver
'transaction_reference' => $payment->id, 'transaction_reference' => $payment->id,
]; ];
$this->confirmGatewayFee($data);
$record = $this->createPayment( $record = $this->createPayment(
$data, $data,
$codes[$payment->status] $codes[$payment->status]

View File

@ -115,10 +115,9 @@ class PayPalBasePaymentDriver extends BaseDriver
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com'; $this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
if(\App\Utils\Ninja::isHosted()) { if(\App\Utils\Ninja::isHosted() && $this->company_gateway->gateway_key != '80af24a6a691230bbec33e930ab40665') {
$secret = config('ninja.paypal.secret'); $secret = config('ninja.paypal.secret');
$client_id = config('ninja.paypal.client_id'); $client_id = config('ninja.paypal.client_id');
} }
else { else {

View File

@ -100,8 +100,17 @@ class PaymentMethod implements MethodInterface
$customer = array_merge(['address' => $request->only('address_1','address_2','city','postal_code','province_code','country'), 'custom_identifier' => $request->input('custom_identifier') ], $request->all()); $customer = array_merge(['address' => $request->only('address_1','address_2','city','postal_code','province_code','country'), 'custom_identifier' => $request->input('custom_identifier') ], $request->all());
$this->rotessa->findOrCreateCustomer($customer); try{
$this->rotessa->findOrCreateCustomer($customer);
}
catch(\Exception $e){
$message = json_decode($e->getMessage(), true);
return redirect()->route('client.payment_methods.index')->withErrors(array_values($message['errors']));
}
return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added'));
} }

View File

@ -202,7 +202,6 @@ class RotessaPaymentDriver extends BaseDriver
public function findOrCreateCustomer(array $data) public function findOrCreateCustomer(array $data)
{ {
nlog($data);
$result = null; $result = null;
try { try {
@ -219,7 +218,6 @@ class RotessaPaymentDriver extends BaseDriver
if(!isset($data['id'])) { if(!isset($data['id'])) {
nlog("no id, lets goo");
$result = $this->gatewayRequest('post', 'customers', $data); $result = $this->gatewayRequest('post', 'customers', $data);
if($result->failed()) if($result->failed())
@ -252,9 +250,16 @@ class RotessaPaymentDriver extends BaseDriver
'code' => 500 'code' => 500
]; ];
SystemLogger::dispatch(['server_response' => is_null($result) ? '' : $result->getMessage(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company); SystemLogger::dispatch(['server_response' => $data, 'data' => []], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company);
throw $th; try{
$errors = explode("422:", $th->getMessage())[1];
}
catch(\Exception){
$errors = 'Unknown error occured';
}
throw new \Exception($errors, $th->getCode());
} }
} }

View File

@ -58,7 +58,7 @@ class BaseRepository
$className = $this->getEventClass($entity, 'Archived'); $className = $this->getEventClass($entity, 'Archived');
if (class_exists($className)) { if (class_exists($className)) {
event(new $className($entity, $entity->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new $className($entity, $entity->company, Ninja::eventVars(auth()->guard('api')->user() ? auth()->guard('api')->user()->id : null)));
} }
} }
@ -84,7 +84,7 @@ class BaseRepository
$className = $this->getEventClass($entity, 'Restored'); $className = $this->getEventClass($entity, 'Restored');
if (class_exists($className)) { if (class_exists($className)) {
event(new $className($entity, $fromDeleted, $entity->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new $className($entity, $fromDeleted, $entity->company, Ninja::eventVars(auth()->guard('api')->user() ? auth()->guard('api')->user()->id : null)));
} }
} }
@ -105,7 +105,7 @@ class BaseRepository
$className = $this->getEventClass($entity, 'Deleted'); $className = $this->getEventClass($entity, 'Deleted');
if (class_exists($className) && !($entity instanceof Company)) { if (class_exists($className) && !($entity instanceof Company)) {
event(new $className($entity, $entity->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); event(new $className($entity, $entity->company, Ninja::eventVars(auth()->guard('api')->user() ? auth()->guard('api')->user()->id : null)));
} }
} }

View File

@ -147,6 +147,10 @@ class TaskRepository extends BaseRepository
$task->calculated_start_date = $this->harvestStartDate($time_log, $task); $task->calculated_start_date = $this->harvestStartDate($time_log, $task);
if(isset(end($time_log)[1])){
$task->is_running = end($time_log)[1] == 0;
}
$task->time_log = json_encode($time_log); $task->time_log = json_encode($time_log);
$task->saveQuietly(); $task->saveQuietly();
@ -259,7 +263,7 @@ class TaskRepository extends BaseRepository
$log = array_merge($log, [$new]); $log = array_merge($log, [$new]);
$task->time_log = json_encode($log); $task->time_log = json_encode($log);
$task->is_running = true;
$task->saveQuietly(); $task->saveQuietly();
} }
@ -303,6 +307,7 @@ class TaskRepository extends BaseRepository
$log = array_merge($log, [$last]);//check at this point, it may be prepending here. $log = array_merge($log, [$last]);//check at this point, it may be prepending here.
$task->time_log = json_encode($log); $task->time_log = json_encode($log);
$task->is_running = false;
$task->saveQuietly(); $task->saveQuietly();
} }
@ -418,4 +423,4 @@ class TaskRepository extends BaseRepository
} }
} }

View File

@ -137,24 +137,29 @@ class Storecove {
} }
public function sendDocument($document) public function sendDocument(string $document, int $routing_id, array $override_payload = [])
{ {
$payload = [ $payload = [
"legalEntityId"=> 290868, "legalEntityId" => $routing_id,
"idempotencyGuid"=> \Illuminate\Support\Str::uuid(), "idempotencyGuid"=> \Illuminate\Support\Str::uuid(),
"routing" => [ "routing" => [
"eIdentifiers" => [], "eIdentifiers" => [],
"emails" => ["david@invoiceninja.com"] "emails" => ["david@invoiceninja.com"]
], ],
"document"=> [ "document"=> [
'documentType' => 'invoice',
"rawDocumentData"=> [ ],
];
$payload = array_merge($payload, $override_payload);
$payload['document']['documentType'] = 'invoice';
$payload['document']["rawDocumentData"] = [
"document" => base64_encode($document), "document" => base64_encode($document),
"parse" => true, "parse" => true,
"parseStrategy"=> "ubl", "parseStrategy"=> "ubl",
],
],
]; ];
$uri = "document_submissions"; $uri = "document_submissions";

View File

@ -13,22 +13,25 @@ namespace App\Services\EDocument\Standards;
use App\Models\Company; use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Helpers\Invoice\Taxer;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSum;
use InvoiceNinja\EInvoice\EInvoice; use InvoiceNinja\EInvoice\EInvoice;
use App\Utils\Traits\NumberFormatter;
use App\Helpers\Invoice\InvoiceSumInclusive; use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Helpers\Invoice\Taxer;
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans; use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item; use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party; use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
use InvoiceNinja\EInvoice\Models\Peppol\PriceType\Price; use InvoiceNinja\EInvoice\Models\Peppol\PriceType\Price;
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID;
use InvoiceNinja\EInvoice\Models\Peppol\AddressType\Address; use InvoiceNinja\EInvoice\Models\Peppol\AddressType\Address;
use InvoiceNinja\EInvoice\Models\Peppol\ContactType\Contact; use InvoiceNinja\EInvoice\Models\Peppol\ContactType\Contact;
use InvoiceNinja\EInvoice\Models\Peppol\CountryType\Country; use InvoiceNinja\EInvoice\Models\Peppol\CountryType\Country;
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxAmount; use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxAmount;
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
use InvoiceNinja\EInvoice\Models\Peppol\TaxTotalType\TaxTotal; use InvoiceNinja\EInvoice\Models\Peppol\TaxTotalType\TaxTotal;
use App\Services\EDocument\Standards\Settings\PropertyResolver; use App\Services\EDocument\Standards\Settings\PropertyResolver;
use App\Utils\Traits\NumberFormatter;
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\PriceAmount; use InvoiceNinja\EInvoice\Models\Peppol\AmountType\PriceAmount;
use InvoiceNinja\EInvoice\Models\Peppol\PartyNameType\PartyName; use InvoiceNinja\EInvoice\Models\Peppol\PartyNameType\PartyName;
use InvoiceNinja\EInvoice\Models\Peppol\TaxSchemeType\TaxScheme; use InvoiceNinja\EInvoice\Models\Peppol\TaxSchemeType\TaxScheme;
@ -42,14 +45,13 @@ use InvoiceNinja\EInvoice\Models\Peppol\TaxScheme as PeppolTaxScheme;
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxExclusiveAmount; use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxExclusiveAmount;
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxInclusiveAmount; use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxInclusiveAmount;
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\LineExtensionAmount; use InvoiceNinja\EInvoice\Models\Peppol\AmountType\LineExtensionAmount;
use InvoiceNinja\EInvoice\Models\Peppol\OrderReferenceType\OrderReference;
use InvoiceNinja\EInvoice\Models\Peppol\MonetaryTotalType\LegalMonetaryTotal; use InvoiceNinja\EInvoice\Models\Peppol\MonetaryTotalType\LegalMonetaryTotal;
use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\ClassifiedTaxCategory; use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\ClassifiedTaxCategory;
use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerParty; use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerParty;
use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty; use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount; use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID; use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID;
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
class Peppol extends AbstractService class Peppol extends AbstractService
{ {
@ -57,6 +59,12 @@ class Peppol extends AbstractService
use NumberFormatter; use NumberFormatter;
/** /**
* Assumptions:
*
* Line Item Taxes Only
* Exclusive Taxes
*
*
* used as a proxy for * used as a proxy for
* the schemeID of partyidentification * the schemeID of partyidentification
* property - for Storecove only: * property - for Storecove only:
@ -82,7 +90,7 @@ class Peppol extends AbstractService
'NO' => 'VAT', 'NO' => 'VAT',
'AD' => 'VAT', 'AD' => 'VAT',
'AL' => 'VAT', 'AL' => 'VAT',
'AT' => 'VAT', 'AT' => 'VAT', //Tested - Routing GOV + Business
'BA' => 'VAT', 'BA' => 'VAT',
'BE' => 'VAT', 'BE' => 'VAT',
'BG' => 'VAT', 'BG' => 'VAT',
@ -94,12 +102,12 @@ class Peppol extends AbstractService
'SA' => 'TIN', //South Africa 'SA' => 'TIN', //South Africa
'CY' => 'VAT', 'CY' => 'VAT',
'CZ' => 'VAT', 'CZ' => 'VAT',
'DE' => 'VAT', //tested - requires Payment Means to be defined. 'DE' => 'VAT', //tested - Requires Payment Means to be defined.
'DK' => 'ERST', 'DK' => 'ERST',
'EE' => 'VAT', 'EE' => 'VAT',
'ES' => 'VAT', 'ES' => 'VAT', //tested - B2G pending
'FI' => 'VAT', 'FI' => 'VAT',
'FR' => 'VAT', 'FR' => 'VAT', //tested - Need to ensure Siren/Siret routing
'GR' => 'VAT', 'GR' => 'VAT',
'HR' => 'VAT', 'HR' => 'VAT',
'HU' => 'VAT', 'HU' => 'VAT',
@ -147,11 +155,96 @@ class Peppol extends AbstractService
"896" => "Debit note related to self-billed invoice" "896" => "Debit note related to self-billed invoice"
]; ];
// 0 1 2 3
// ["Country" => ["B2X","Legal","Tax","Routing"],
private array $routing_rules = [
"US" => ["B","DUNS, GLN, LEI","US:EIN, US:SSN","DUNS, GLN, LEI"],
"CA" => ["B","CA:CBN","","CA:CBN"],
"MX" => ["B","MX:RFC","","MX:RFC"],
"AU" => ["B+G","AU:ABN","","AU:ABN"],
"NZ" => ["B+G","GLN","NZ:GST","GLN"],
"CH" => ["B+G","CH:UIDB","CH:VAT","CH:UIDB"],
"IS" => ["B+G","IS:KTNR","IS:VAT","IS:KTNR"],
"LI" => ["B+G","","LI:VAT","LI:VAT"],
"NO" => ["B+G","NO:ORG","NO:VAT","NO:ORG"],
"AD" => ["B+G","","AD:VAT","AD:VAT"],
"AL" => ["B+G","","AL:VAT","AL:VAT"],
"AT" => [
["G","AT:GOV","","9915:b"],
["B","","AT:VAT","AT:VAT"],
],
"BA" => ["B+G","","BA:VAT","BA:VAT"],
"BE" => ["B+G","BE:EN","BE:VAT","BE:EN"],
"BG" => ["B+G","","BG:VAT","BG:VAT"],
"CY" => ["B+G","","CY:VAT","CY:VAT"],
"CZ" => ["B+G","","CZ:VAT","CZ:VAT"],
"DE" => [
["G","DE:LWID","","DE:LWID"],
["B","","DE:VAT","DE:VAT"],
],
"DK" => ["B+G","DK:DIGST","DK:ERST","DK:DIGST"],
"EE" => ["B+G","EE:CC","EE:VAT","EE:CC"],
"ES" => ["B","","ES:VAT","ES:VAT"],
"FI" => ["B+G","FI:OVT","FI:VAT","FI:OVT"],
"FR" => [
["G","FR:SIRET + customerAssignedAccountIdValue","","0009:11000201100044"],
["B","FR:SIRENE or FR:SIRET","FR:VAT","FR:SIRENE or FR:SIRET"],
],
"GR" => ["B+G","","GR:VAT","GR:VAT"],
"HR" => ["B+G","","HR:VAT","HR:VAT"],
"HU" => ["B+G","","HU:VAT","HU:VAT"],
"IE" => ["B+G","","IE:VAT","IE:VAT"],
"IT" => [
["G (Peppol)","","IT:IVA","IT:CUUO"],
["B (SDI)","","IT:CF and/or IT:IVA","IT:CUUO"],
["C (SDI)","","IT:CF","Email"],
["G (SDI)","","IT:IVA","IT:CUUO"],
],
"LT" => ["B+G","LT:LEC","LT:VAT","LT:LEC"],
"LU" => ["B+G","LU:MAT","LU:VAT","LU:VAT"],
"LV" => ["B+G","","LV:VAT","LV:VAT"],
"MC" => ["B+G","","MC:VAT","MC:VAT"],
"ME" => ["B+G","","ME:VAT","ME:VAT"],
"MK" => ["B+G","","MK:VAT","MK:VAT"],
"MT" => ["B+G","","MT:VAT","MT:VAT"],
"NL" => ["G","NL:OINO","","NL:OINO"],
"NL" => ["B","NL:KVK","NL:VAT","NL:KVK or NL:VAT"],
"PL" => ["G+B","","PL:VAT","PL:VAT"],
"PT" => ["G+B","","PT:VAT","PT:VAT"],
"RO" => ["G+B","","RO:VAT","RO:VAT"],
"RS" => ["G+B","","RS:VAT","RS:VAT"],
"SE" => ["G+B","SE:ORGNR","SE:VAT","SE:ORGNR"],
"SI" => ["G+B","","SI:VAT","SI:VAT"],
"SK" => ["G+B","","SK:VAT","SK:VAT"],
"SM" => ["G+B","","SM:VAT","SM:VAT"],
"TR" => ["G+B","","TR:VAT","TR:VAT"],
"VA" => ["G+B","","VA:VAT","VA:VAT"],
"IN" => ["B","","IN:GSTIN","Email"],
"JP" => ["B","JP:SST","JP:IIN","JP:SST"],
"MY" => ["B","MY:EIF","MY:TIN","MY:EIF"],
"SG" => [
["G","SG:UEN","","0195:SGUENT08GA0028A"],
["B","SG:UEN","SG:GST (optional)","SG:UEN"],
],
"GB" => ["B","","GB:VAT","GB:VAT"],
"SA" => ["B","","SA:TIN","Email"],
"Other" => ["B","DUNS, GLN, LEI","","DUNS, GLN, LEI"],
];
private Company $company; private Company $company;
private InvoiceSum | InvoiceSumInclusive $calc; private InvoiceSum | InvoiceSumInclusive $calc;
private \InvoiceNinja\EInvoice\Models\Peppol\Invoice $p_invoice; private \InvoiceNinja\EInvoice\Models\Peppol\Invoice $p_invoice;
private ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_client_settings;
private ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_company_settings;
private EInvoice $e;
private array $storecove_meta = [];
/** /**
* @param Invoice $invoice * @param Invoice $invoice
*/ */
@ -159,18 +252,21 @@ class Peppol extends AbstractService
{ {
$this->company = $invoice->company; $this->company = $invoice->company;
$this->calc = $this->invoice->calc(); $this->calc = $this->invoice->calc();
$this->setInvoice(); $this->e = new EInvoice();
$this->setSettings()->setInvoice();
} }
/**
* Rehydrates an existing e invoice - or - scaffolds a new one
*
* @return self
*/
private function setInvoice(): self private function setInvoice(): self
{ {
if($this->invoice->e_invoice){ if($this->invoice->e_invoice){
$this->p_invoice = $this->e->decode('Peppol', json_encode($this->invoice->e_invoice->Invoice), 'json');
$e = new EInvoice();
$this->p_invoice = $e->decode('Peppol', json_encode($this->invoice->e_invoice->Invoice), 'json');
return $this; return $this;
@ -182,6 +278,21 @@ class Peppol extends AbstractService
return $this; return $this;
} }
/**
* Transforms the settings props into usable models we can merge.
*
* @return self
*/
private function setSettings(): self
{
$this->_client_settings = isset($this->invoice->client->e_invoice->Invoice) ? $this->e->decode('Peppol', json_encode($this->invoice->client->e_invoice->Invoice), 'json') : null;
$this->_company_settings = isset($this->invoice->company->e_invoice->Invoice) ? $this->e->decode('Peppol', json_encode($this->invoice->company->e_invoice->Invoice), 'json') : null;
return $this;
}
public function getInvoice(): \InvoiceNinja\EInvoice\Models\Peppol\Invoice public function getInvoice(): \InvoiceNinja\EInvoice\Models\Peppol\Invoice
{ {
@ -211,8 +322,7 @@ class Peppol extends AbstractService
$json = $e->encode($this->p_invoice, 'json'); $json = $e->encode($this->p_invoice, 'json');
return $json; return $json;
// $prefixes = str_ireplace(["cac:","cbc:"], "", $json);
// return str_ireplace(["InvoiceLine", "PostalAddress", "PartyName"], ["invoiceLines","address", "companyName"], $prefixes);
} }
public function toArray(): array public function toArray(): array
@ -224,15 +334,20 @@ class Peppol extends AbstractService
{ {
$this->p_invoice->ID = $this->invoice->number; $this->p_invoice->ID = $this->invoice->number;
$this->p_invoice->IssueDate = new \DateTime($this->invoice->date); $this->p_invoice->IssueDate = new \DateTime($this->invoice->date);
if($this->invoice->due_date)
$this->p_invoice->DueDate = new \DateTime($this->invoice->due_date);
$this->p_invoice->InvoiceTypeCode = 380; // $this->p_invoice->InvoiceTypeCode = 380; //
$this->p_invoice->AccountingSupplierParty = $this->getAccountingSupplierParty(); $this->p_invoice->AccountingSupplierParty = $this->getAccountingSupplierParty();
$this->p_invoice->AccountingCustomerParty = $this->getAccountingCustomerParty(); $this->p_invoice->AccountingCustomerParty = $this->getAccountingCustomerParty();
$this->p_invoice->InvoiceLine = $this->getInvoiceLines(); $this->p_invoice->InvoiceLine = $this->getInvoiceLines();
$this->p_invoice->TaxTotal = $this->getTotalTaxes(); // $this->p_invoice->TaxTotal = $this->getTotalTaxes(); it only wants the aggregate here!!
$this->p_invoice->LegalMonetaryTotal = $this->getLegalMonetaryTotal(); $this->p_invoice->LegalMonetaryTotal = $this->getLegalMonetaryTotal();
$this->countryLevelMutators(); $this->senderSpecificLevelMutators()
->receiverSpecificLevelMutators();
return $this; return $this;
@ -340,7 +455,7 @@ class Peppol extends AbstractService
$tax_total = new TaxTotal(); $tax_total = new TaxTotal();
$tax_total->TaxAmount = $tax_amount; $tax_total->TaxAmount = $tax_amount;
$tax_total->TaxSubtotal = $tax_subtotal; $tax_total->TaxSubtotal[] = $tax_subtotal;
$taxes[] = $tax_total; $taxes[] = $tax_total;
@ -372,7 +487,7 @@ class Peppol extends AbstractService
$tax_total = new TaxTotal(); $tax_total = new TaxTotal();
$tax_total->TaxAmount = $tax_amount; $tax_total->TaxAmount = $tax_amount;
$tax_total->TaxSubtotal = $tax_subtotal; $tax_total->TaxSubtotal[] = $tax_subtotal;
$taxes[] = $tax_total; $taxes[] = $tax_total;
@ -615,7 +730,7 @@ class Peppol extends AbstractService
{ {
$acp = new AccountingCustomerParty(); $acp = new AccountingCustomerParty();
$party = new Party(); $party = new Party();
if(strlen($this->invoice->client->vat_number ?? '') > 1) { if(strlen($this->invoice->client->vat_number ?? '') > 1) {
@ -706,7 +821,38 @@ class Peppol extends AbstractService
return $total; return $total;
} }
///////////////// Helper Methods /////////////////////////
private function getClientRoutingCode(): string
{
$receiver_identifiers = $this->routing_rules[$this->invoice->client->country->iso_3166_2];
$client_classification = $this->invoice->client->classification == 'government' ? 'G' : 'B';
if(count($receiver_identifiers) > 1) {
foreach($receiver_identifiers as $ident)
{
if(str_contains($ident[0], $client_classification))
{
return $ident[3];
}
}
}
elseif(count($receiver_identifiers) == 1)
return $receiver_identifiers[3];
throw new \Exception("e-invoice generation halted:: Could not resolve the Tax Code for this client? {$this->invoice->client->hashed_id}");
}
/**
* setInvoiceDefaults
*
* Stubs a default einvoice
* @return self
*/
public function setInvoiceDefaults(): self public function setInvoiceDefaults(): self
{ {
$settings = [ $settings = [
@ -735,22 +881,39 @@ class Peppol extends AbstractService
return $this; return $this;
} }
/**
* getSetting
*
* Attempts to harvest and return a preconfigured prop from company / client / invoice settings
*
* @param string $property_path
* @return mixed
*/
public function getSetting(string $property_path): mixed public function getSetting(string $property_path): mixed
{ {
if($prop_value = PropertyResolver::resolve($this->invoice->e_invoice, $property_path)) if($prop_value = PropertyResolver::resolve($this->p_invoice, $property_path)) {
return $prop_value; return $prop_value;
elseif($prop_value = PropertyResolver::resolve($this->invoice->client->e_invoice, $property_path)) }elseif($prop_value = PropertyResolver::resolve($this->_client_settings, $property_path)) {
return $prop_value; return $prop_value;
elseif($prop_value = PropertyResolver::resolve($this->invoice->company->e_invoice, $property_path)) }elseif($prop_value = PropertyResolver::resolve($this->_company_settings, $property_path)) {
return $prop_value; return $prop_value;
}
return null; return null;
} }
public function countryLevelMutators():self /**
* senderSpecificLevelMutators
*
* Runs sender level specific requirements for the e-invoice,
*
* ie, mutations that are required by the senders country.
*
* @return self
*/
private function senderSpecificLevelMutators():self
{ {
if(method_exists($this, $this->invoice->company->country()->iso_3166_2)) if(method_exists($this, $this->invoice->company->country()->iso_3166_2))
@ -758,60 +921,272 @@ class Peppol extends AbstractService
return $this; return $this;
} }
private function setPaymentMeans(bool $required = false): self /**
* receiverSpecificLevelMutators
*
* Runs receiver level specific requirements for the e-invoice
*
* ie mutations that are required by the receiving country
* @return self
*/
private function receiverSpecificLevelMutators():self
{ {
if($this->p_invoice->PaymentMeans)
return $this;
elseif(!isset($this->p_invoice->PaymentMeans) && $paymentMeans = $this->getSetting('Invoice.PaymentMeans')){
$this->p_invoice->PaymentMeans = is_array($paymentMeans) ? $paymentMeans : [$paymentMeans];
return $this;
}
if($required) if(method_exists($this, "client_{$this->invoice->company->country()->iso_3166_2}"))
throw new \Exception('e-invoice generation halted:: Payment Means required'); $this->{"client_{$this->invoice->company->country()->iso_3166_2}"}();
return $this; return $this;
} }
/**
* setPaymentMeans
*
* Sets the payment means - if it exists
* @param bool $required
* @return self
*/
private function setPaymentMeans(bool $required = false): self
{
if(isset($this->p_invoice->PaymentMeans))
return $this;
elseif($paymentMeans = $this->getSetting('Invoice.PaymentMeans')){
$this->p_invoice->PaymentMeans = is_array($paymentMeans) ? $paymentMeans : [$paymentMeans];
return $this;
}
return $this->checkRequired($required, "Payment Means");
}
/**
* setOrderReference
*
* sets the order reference - if it exists (Never rely on settings for this)
*
* @param bool $required
* @return self
*/
private function setOrderReference(bool $required = false): self
{
$this->p_invoice->BuyerReference = $this->invoice->po_number ?? '';
if(strlen($this->invoice->po_number ?? '') > 1)
{
$order_reference = new OrderReference();
$id = new ID();
$id->value = $this->invoice->po_number;
$order_reference->ID = $id;
$this->p_invoice->OrderReference = $order_reference;
// $this->setStorecoveMeta(["document" => [
// "invoice" => [
// [
// "references" => [
// "documentType" => "purchase_order",
// "documentId" => $this->invoice->po_number,
// ],
// ],
// ],
// ]
// ]);
return $this;
}
return $this->checkRequired($required, 'Order Reference');
}
/**
* setCustomerAssignedAccountId
*
* Sets the client id_number CAN rely on settings
*
* @param bool $required
* @return self
*/
private function setCustomerAssignedAccountId(bool $required = false): self
{
//@phpstan-ignore-next-line
if(isset($this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID)){
return $this;
}
elseif($customer_assigned_account_id = $this->getSetting('Invoice.AccountingCustomerParty.CustomerAssignedAccountID')){
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
return $this;
}
elseif(strlen($this->invoice->client->id_number ?? '') > 1){
$customer_assigned_account_id = new CustomerAssignedAccountID();
$customer_assigned_account_id->value = $this->invoice->client->id_number;
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
return $this;
}
//@phpstan-ignore-next-line
return $this->checkRequired($required, 'Client ID Number');
}
/**
* Check Required
*
* Throws if a required field is missing.
*
* @param bool $required
* @param string $section
* @return self
*/
private function checkRequired(bool $required, string $section): self
{
return $required ? throw new \Exception("e-invoice generation halted:: {$section} required") : $this;
}
/**
* Builds the Routing object for StoreCove
*
* @param string $schemeId
* @param string $id
* @return array
*/
private function buildRouting(string $schemeId, string $id): array
{
return
[
"routing" => [
"publicIdentifiers" => [
[
"scheme" => $schemeId,
"id" => $id
]
]
]
];
}
/**
* setStorecoveMeta
*
* updates the storecove payload for sending documents
*
* @param array $meta
* @return self
*/
private function setStorecoveMeta(array $meta): self
{
$this->storecove_meta = array_merge($this->storecove_meta, $meta);
return $this;
}
public function getStorecoveMeta(): array
{
return $this->storecove_meta;
}
////////////////////////// Country level mutators /////////////////////////////////////
/**
* DE
*
* @Completed
* @Tested
*
* @return self
*/
private function DE(): self private function DE(): self
{ {
// accountingsupplierparty.party.contact MUST be set - Name / Telephone / Electronic Mail
// this is forced by default.
$this->setPaymentMeans(true); $this->setPaymentMeans(true);
return $this; return $this;
} }
/**
* CH
*
* @Completed
*
* Completed - QR-Bill to be implemented at a later date.
* @return self
*/
private function CH(): self private function CH(): self
{ {
//if QR-Bill support required - then special flow required.... optional.
return $this; return $this;
} }
/**
* AT
*
* @Pending
*
* Need to ensure when sending to government entities that we route appropriately
* Also need to ensure customerAssignedAccountIdValue is set so that the sender can be resolved.
*
* Need a way to define if the client is a government entity.
*
* @return self
*/
private function AT(): self private function AT(): self
{ {
//special fields for sending to AT:GOV //special fields for sending to AT:GOV
if($this->invoice->client->classification == 'government') {
//routing "b" for production "test" for test environment
$this->setStorecoveMeta($this->buildRouting('AT:GOV', "b"));
//for government clients this must be set.
$this->setCustomerAssignedAccountId(true);
}
return $this; return $this;
} }
private function AU(): self private function AU(): self
{ {
//if payment means are included, they must be the same `type` //if payment means are included, they must be the same `type`
return $this; return $this;
} }
/**
* ES
*
* @Pending
* B2G configuration
* B2G Testing
*
* testing. // routing identifier - 293098
*
* @return self
*/
private function ES(): self private function ES(): self
{ {
// For B2B, provide an ES:DIRE routing identifier and an ES:VAT tax identifier. if(!isset($this->invoice->due_date))
// both sender and receiver must be an ES company; $this->p_invoice->DueDate = new \DateTime($this->invoice->date);
// you must have a "credit_transfer" PaymentMean;
// the "dueDate" property is mandatory. if($this->invoice->client->classification == 'business' && $this->invoice->company->getSetting('classification') == 'business') {
//must have a paymentmeans as credit_transfer
$this->setPaymentMeans(true);
}
// For B2G, provide three ES:FACE identifiers in the routing object, // For B2G, provide three ES:FACE identifiers in the routing object,
// as well as the ES:VAT tax identifier in the accountingCustomerParty.publicIdentifiers. // as well as the ES:VAT tax identifier in the accountingCustomerParty.publicIdentifiers.
@ -848,41 +1223,100 @@ class Peppol extends AbstractService
return $this; return $this;
} }
/**
* FR
* @Pending - clarification on codes needed
*
* @return self
*/
private function FR(): self private function FR(): self
{ {
// When sending invoices to the French government (Chorus Pro): // When sending invoices to the French government (Chorus Pro):
// All invoices have to be routed to SIRET 0009:11000201100044. There is no test environment for sending to public entities. // All invoices have to be routed to SIRET 0009:11000201100044. There is no test environment for sending to public entities.
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array. // The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
if($this->invoice->client->classification == 'government'){
//route to SIRET 0009:11000201100044
$this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:11000201100044"));
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
$this->setCustomerAssignedAccountId(true);
}
if(strlen($this->invoice->client->id_number ?? '') == 9) {
//SIREN
$this->setStorecoveMeta($this->buildRouting('FR:SIREN', "0002:{$this->invoice->client->id_number}"));
}
else {
//SIRET
$this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:{$this->invoice->client->id_number}"));
}
// Apparently this is not a special field according to support
// sounds like it is optional
// The service code must be sent in invoice.buyerReference (deprecated) or the invoice.references array (documentType buyer_reference) // The service code must be sent in invoice.buyerReference (deprecated) or the invoice.references array (documentType buyer_reference)
// The commitment number must be sent in the invoice.orderReference (deprecated) or the invoice.references array (documentType purchase_order). if(strlen($this->invoice->po_number ?? '') >1) {
$this->setOrderReference(false);
}
// Invoices to companies (SIRET / 0009 or SIRENE / 0002) are routed directly to that identifier.
return $this; return $this;
} }
private function IT(): self private function IT(): self
{ {
// IT Sender, IT Receiver, B2B/B2G // IT Sender, IT Receiver, B2B/B2G
// Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario) // Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario)
if($this->invoice->client->classification == 'government' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
$this->setStorecoveMeta($this->buildRouting('IT:VAT', $this->invoice->client->routing_id));
return $this;
}
// IT Sender, IT Receiver, B2C // IT Sender, IT Receiver, B2C
// Provide the receiver IT:CF and the receiver IT:CUUO (codice destinatario) // Provide the receiver IT:CF and the receiver IT:CUUO (codice destinatario)
if($this->invoice->client->classification == 'individual' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
$this->setStorecoveMeta($this->buildRouting('IT:CF', $this->invoice->client->routing_id));
return $this;
}
// IT Sender, non-IT Receiver // IT Sender, non-IT Receiver
// Provide the receiver tax identifier and any routing identifier applicable to the receiving country (see Receiver Identifiers). // Provide the receiver tax identifier and any routing identifier applicable to the receiving country (see Receiver Identifiers).
if($this->invoice->client->country->iso_3166_2 != 'IT' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
$code = $this->getClientRoutingCode();
$this->setStorecoveMeta($this->buildRouting($code, $this->invoice->client->vat_number));
return $this;
}
return $this;
}
private function client_IT(): self
{
// non-IT Sender, IT Receiver, B2C
// Provide the receiver IT:CF and an optional email. The invoice will be eReported and sent via email. Note that this cannot be a PEC email address.
if(in_array($this->invoice->client->classification, ['individual']) && $this->invoice->company->country()->iso_3166_2 != 'IT') {
return $this;
}
// non-IT Sender, IT Receiver, B2B/B2G // non-IT Sender, IT Receiver, B2B/B2G
// Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario) // Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario)
// non-IT Sender, IT Receiver, B2C
// Provide the receiver IT:CF and an optional email. The invoice will be eReported and sent via email. Note that this cannot be a PEC email address.
return $this; return $this;
} }
private function MY(): self private function MY(): self

View File

@ -250,7 +250,7 @@ class Email implements ShouldQueue
private function incrementEmailCounter(): void private function incrementEmailCounter(): void
{ {
if(in_array($this->mailer, ['default','mailgun','postmark'])) { if(in_array($this->email_object->settings->email_sending_method, ['default','mailgun','postmark'])) {
Cache::increment("email_quota".$this->company->account->key); Cache::increment("email_quota".$this->company->account->key);
} }
} }

View File

@ -17,6 +17,7 @@ use App\Models\Invoice;
use App\Services\AbstractService; use App\Services\AbstractService;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use App\Models\Product;
class AddGatewayFee extends AbstractService class AddGatewayFee extends AbstractService
{ {
@ -80,6 +81,7 @@ class AddGatewayFee extends AbstractService
$invoice_item->tax_name2 = $fees_and_limits->fee_tax_name2; $invoice_item->tax_name2 = $fees_and_limits->fee_tax_name2;
$invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3; $invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3;
$invoice_item->tax_name3 = $fees_and_limits->fee_tax_name3; $invoice_item->tax_name3 = $fees_and_limits->fee_tax_name3;
$invoice_item->tax_id = (string)Product::PRODUCT_TYPE_OVERRIDE_TAX;
} }
$invoice_items = (array) $this->invoice->line_items; $invoice_items = (array) $this->invoice->line_items;

View File

@ -1260,6 +1260,7 @@ class SubscriptionService
return Subscription::query() return Subscription::query()
->where('company_id', $this->subscription->company_id) ->where('company_id', $this->subscription->company_id)
->where('group_id', $this->subscription->group_id) ->where('group_id', $this->subscription->group_id)
->whereNotNull('group_id')
->where('id', '!=', $this->subscription->id) ->where('id', '!=', $this->subscription->id)
->get(); ->get();
} }

View File

@ -507,7 +507,9 @@ class HtmlEngine
$data['$client.lang_2'] = ['value' => optional($this->client->language())->locale, 'label' => '']; $data['$client.lang_2'] = ['value' => optional($this->client->language())->locale, 'label' => ''];
$data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
$data['$client.payment_balance'] = ['value' => Number::formatMoney($this->client->payment_balance, $this->client), 'label' => ctrans('texts.payment_balance_on_file')];
$data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; $data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')]; $data['$paid_to_date'] = ['value' => Number::formatMoney($this->entity->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];

View File

@ -20,12 +20,18 @@ class PDF extends FPDI
public function Footer() public function Footer()
{ {
$this->SetXY(0, -6); $this->SetXY(0, -6);
$this->SetFont('Arial', 'I', 9); $this->SetFont('Arial', 'I', 9);
$this->SetTextColor(135, 135, 135); $this->SetTextColor(135, 135, 135);
$trans = ctrans('texts.pdf_page_info', ['current' => $this->PageNo(), 'total' => '{nb}']); $trans = ctrans('texts.pdf_page_info', ['current' => $this->PageNo(), 'total' => '{nb}']);
// $trans = iconv('UTF-8', 'ISO-8859-7', $trans);
try {
$trans = mb_convert_encoding($trans, 'ISO-8859-1', 'UTF-8');
}
catch(\Exception $e){}
$this->Cell(0, 5, $trans, 0, 0, $this->text_alignment); $this->Cell(0, 5, $trans, 0, 0, $this->text_alignment);
} }

View File

@ -40,6 +40,7 @@
"asm/php-ansible": "dev-main", "asm/php-ansible": "dev-main",
"authorizenet/authorizenet": "^2.0", "authorizenet/authorizenet": "^2.0",
"awobaz/compoships": "^2.1", "awobaz/compoships": "^2.1",
"aws/aws-sdk-php": "^3.319",
"bacon/bacon-qr-code": "^2.0", "bacon/bacon-qr-code": "^2.0",
"beganovich/snappdf": "dev-master", "beganovich/snappdf": "dev-master",
"braintree/braintree_php": "^6.0", "braintree/braintree_php": "^6.0",
@ -203,4 +204,4 @@
], ],
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true "prefer-stable": true
} }

17
composer.lock generated
View File

@ -535,16 +535,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.317.1", "version": "3.319.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9" "reference": "a5c408d4cd1945d5fc817f45e46383634b610497"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/dc1e3031c2721a25beb2e8fbb175b576e3d60ab9", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a5c408d4cd1945d5fc817f45e46383634b610497",
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9", "reference": "a5c408d4cd1945d5fc817f45e46383634b610497",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -597,7 +597,10 @@
], ],
"psr-4": { "psr-4": {
"Aws\\": "src/" "Aws\\": "src/"
} },
"exclude-from-classmap": [
"src/data/"
]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
@ -624,9 +627,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.317.1" "source": "https://github.com/aws/aws-sdk-php/tree/3.319.0"
}, },
"time": "2024-08-02T18:09:42+00:00" "time": "2024-08-07T18:05:51+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",

View File

@ -1,19 +1,22 @@
<?php <?php
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus; use Imdhemy\Purchases\Events\AppStore\Cancel;
use Imdhemy\Purchases\Events\AppStore\DidFailToRenew;
use Imdhemy\Purchases\Events\AppStore\DidRenew;
use Imdhemy\Purchases\Events\AppStore\InitialBuy;
use Imdhemy\Purchases\Events\AppStore\InteractiveRenewal;
use Imdhemy\Purchases\Events\AppStore\Refund; use Imdhemy\Purchases\Events\AppStore\Refund;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionCanceled; use Imdhemy\Purchases\Events\AppStore\DidRenew;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired; use Imdhemy\Purchases\Events\AppStore\DidRecover;
use Imdhemy\Purchases\Events\AppStore\InitialBuy;
use Imdhemy\Purchases\Events\AppStore\DidFailToRenew;
use Imdhemy\Purchases\Events\AppStore\InteractiveRenewal;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused; use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
use Imdhemy\Purchases\Events\AppStore\Subscribed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionCanceled;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased; use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered; use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRestarted; use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRestarted;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
return [ return [
/* /*
@ -108,9 +111,10 @@ return [
\App\Listeners\GooglePlay\SubscriptionRecovered::class, \App\Listeners\GooglePlay\SubscriptionRecovered::class,
],*/ ],*/
Subscribed::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleSubscribed::class) ? [\Modules\Admin\Listeners\Subscription\AppleSubscribed::class] : [],
DidRenew::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class] : [], DidRenew::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class] : [],
SubscriptionRenewed::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class] : [], SubscriptionRenewed::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class] : [],
DidChangeRenewalStatus::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class) ? [\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class] : [], // DidChangeRenewalStatus::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class) ? [\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class] : [],
DidFailToRenew::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class] : [], DidFailToRenew::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class] : [],
Refund::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleRefund::class) ? [\Modules\Admin\Listeners\Subscription\AppleRefund::class] : [], Refund::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleRefund::class) ? [\Modules\Admin\Listeners\Subscription\AppleRefund::class] : [],
SubscriptionRecovered::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class] : [], SubscriptionRecovered::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class] : [],

View File

@ -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.10.19'), 'app_version' => env('APP_VERSION', '5.10.24'),
'app_tag' => env('APP_TAG', '5.10.19'), 'app_tag' => env('APP_TAG', '5.10.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),

View File

@ -5311,6 +5311,9 @@ $lang = array(
'customer_type' => 'Customer Type', 'customer_type' => 'Customer Type',
'process_date' => 'Process Date', 'process_date' => 'Process Date',
'forever_free' => 'Forever Free', 'forever_free' => 'Forever Free',
'comments_only' => 'Comments Only',
'payment_balance_on_file' => 'Payment Balance On File',
'ubl_email_attachment_help' => 'For more e-invoice settings please navigate :here',
); );
return $lang; return $lang;

View File

@ -199,7 +199,7 @@ $lang = array(
'removed_logo' => 'Logo eliminado correctamente', 'removed_logo' => 'Logo eliminado correctamente',
'sent_message' => 'Mensaje enviado correctamente', 'sent_message' => 'Mensaje enviado correctamente',
'invoice_error' => 'Seleccionar cliente y corregir errores.', 'invoice_error' => 'Seleccionar cliente y corregir errores.',
'limit_clients' => 'You\'ve hit the :count client limit on Free accounts. Congrats on your success!', 'limit_clients' => 'Has alcanzado el límite de :count clientes en cuentas gratuitas. ¡Felicitaciones por tu éxito!',
'payment_error' => 'Ha habido un error en el proceso de tu Pago. Inténtalo de nuevo más tarde.', 'payment_error' => 'Ha habido un error en el proceso de tu Pago. Inténtalo de nuevo más tarde.',
'registration_required' => 'Se requiere registro', 'registration_required' => 'Se requiere registro',
'confirmation_required' => 'Por favor, confirma tu dirección de correo electrónico, :link para reenviar el email de confirmación.', 'confirmation_required' => 'Por favor, confirma tu dirección de correo electrónico, :link para reenviar el email de confirmación.',
@ -1095,7 +1095,7 @@ $lang = array(
'invoice_embed_documents' => 'Documentos anexados', 'invoice_embed_documents' => 'Documentos anexados',
'invoice_embed_documents_help' => 'Incluye imagenes adjuntas en la factura', 'invoice_embed_documents_help' => 'Incluye imagenes adjuntas en la factura',
'document_email_attachment' => 'Adjuntar documentos', 'document_email_attachment' => 'Adjuntar documentos',
'ubl_email_attachment' => 'Attach UBL/E-Invoice', 'ubl_email_attachment' => 'Adjuntar UBL/E-Invoice',
'download_documents' => 'Descargar documentos (:size)', 'download_documents' => 'Descargar documentos (:size)',
'documents_from_expenses' => 'De los Gastos:', 'documents_from_expenses' => 'De los Gastos:',
'dropzone_default_message' => 'Arrastra ficheros aquí o Haz clic para subir', 'dropzone_default_message' => 'Arrastra ficheros aquí o Haz clic para subir',
@ -2691,7 +2691,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'no_assets' => 'Sin imágenes, arrastra aquí para subir', 'no_assets' => 'Sin imágenes, arrastra aquí para subir',
'add_image' => 'Añadir Imagen', 'add_image' => 'Añadir Imagen',
'select_image' => 'Seleccionar Imagen', 'select_image' => 'Seleccionar Imagen',
'upgrade_to_upload_images' => 'Upgrade to the Enterprise Plan to upload files & images', 'upgrade_to_upload_images' => 'Actualice al plan Enterprise para cargar archivos e imágenes',
'delete_image' => 'Borrar Imagen', 'delete_image' => 'Borrar Imagen',
'delete_image_help' => 'Atención: borrar la imagen la eliminará de todas las propuestas.', 'delete_image_help' => 'Atención: borrar la imagen la eliminará de todas las propuestas.',
'amount_variable_help' => 'Nota: el campo de la factura $amount usará el campo parcial/depósito si se indica, de otra forma se usará el balance de la factura.', 'amount_variable_help' => 'Nota: el campo de la factura $amount usará el campo parcial/depósito si se indica, de otra forma se usará el balance de la factura.',
@ -2909,13 +2909,13 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'mime_types' => 'Tipos de ficheros', 'mime_types' => 'Tipos de ficheros',
'mime_types_placeholder' => '.pdf , .docx, .jpg', 'mime_types_placeholder' => '.pdf , .docx, .jpg',
'mime_types_help' => 'Lista separada por comas de los tipos mime de fichero aceptados, déjalo en blanco para todos', 'mime_types_help' => 'Lista separada por comas de los tipos mime de fichero aceptados, déjalo en blanco para todos',
'ticket_number_start_help' => 'Ticket number must be greater than the current ticket number', 'ticket_number_start_help' => 'El número de ticket debe ser mayor que el número de ticket actual',
'new_ticket_template_id' => 'New ticket', 'new_ticket_template_id' => 'Nuevo Ticket',
'new_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a new ticket is created', 'new_ticket_autoresponder_help' => 'Al seleccionar una plantilla se enviará una respuesta automática a un cliente/contacto cuando se cree un nuevo ticket.',
'update_ticket_template_id' => 'Updated ticket', 'update_ticket_template_id' => 'Ticket actualizado',
'update_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is updated', 'update_ticket_autoresponder_help' => 'Al seleccionar una plantilla se enviará una respuesta automática a un cliente/contacto cuando se actualice un ticket.',
'close_ticket_template_id' => 'Closed ticket', 'close_ticket_template_id' => 'Ticket cerrado',
'close_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is closed', 'close_ticket_autoresponder_help' => 'Al seleccionar una plantilla se enviará una respuesta automática a un cliente/contacto cuando se cierre un ticket.',
'default_priority' => 'Prioridad por defecto', 'default_priority' => 'Prioridad por defecto',
'alert_new_comment_id' => 'Nuevo comentario', 'alert_new_comment_id' => 'Nuevo comentario',
'update_ticket_notification_list' => 'Notificaciones de nuevo comentario adicionales', 'update_ticket_notification_list' => 'Notificaciones de nuevo comentario adicionales',
@ -3041,7 +3041,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'portal_mode' => 'Modo portal', 'portal_mode' => 'Modo portal',
'attach_pdf' => 'Adjuntar PDF', 'attach_pdf' => 'Adjuntar PDF',
'attach_documents' => 'Adjuntar Documentos', 'attach_documents' => 'Adjuntar Documentos',
'attach_ubl' => 'Attach UBL/E-Invoice', 'attach_ubl' => 'Adjuntar UBL/E-Invoice',
'email_style' => 'Estilo de correo electrónico', 'email_style' => 'Estilo de correo electrónico',
'processed' => 'Procesado', 'processed' => 'Procesado',
'fee_amount' => 'Importe de la cuota', 'fee_amount' => 'Importe de la cuota',
@ -3782,7 +3782,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'entity_number_placeholder' => ':entity # :entity_number', 'entity_number_placeholder' => ':entity # :entity_number',
'email_link_not_working' => 'Si el botón de arriba no te está funcionando, por favor pulsa en el enlace', 'email_link_not_working' => 'Si el botón de arriba no te está funcionando, por favor pulsa en el enlace',
'display_log' => 'Mostrar Registro', 'display_log' => 'Mostrar Registro',
'send_fail_logs_to_our_server' => 'Report errors to help improve the app', 'send_fail_logs_to_our_server' => 'Informar errores para ayudar a mejorar la aplicación',
'setup' => 'Instalación', 'setup' => 'Instalación',
'quick_overview_statistics' => 'Vistazo rápido y estadísticas', 'quick_overview_statistics' => 'Vistazo rápido y estadísticas',
'update_your_personal_info' => 'Actualiza tu información personal', 'update_your_personal_info' => 'Actualiza tu información personal',
@ -4371,7 +4371,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'client_shipping_country' => 'País de envío del cliente', 'client_shipping_country' => 'País de envío del cliente',
'load_pdf' => 'Cargar PDF', 'load_pdf' => 'Cargar PDF',
'start_free_trial' => 'Iniciar prueba gratuita', 'start_free_trial' => 'Iniciar prueba gratuita',
'start_free_trial_message' => 'Start your FREE 14 day trial of the Pro Plan', 'start_free_trial_message' => 'Comience su prueba GRATUITA de 14 días del Plan Pro',
'due_on_receipt' => 'Adeudado a la recepción', 'due_on_receipt' => 'Adeudado a la recepción',
'is_paid' => 'Está pagado', 'is_paid' => 'Está pagado',
'age_group_paid' => 'Pagado', 'age_group_paid' => 'Pagado',
@ -5082,7 +5082,7 @@ De lo contrario, este campo deberá dejarse en blanco.',
'payment_refund_receipt' => 'Recibo de reembolso de pago Nº :number', 'payment_refund_receipt' => 'Recibo de reembolso de pago Nº :number',
'payment_receipt' => 'Recibo de pago Nº :number', 'payment_receipt' => 'Recibo de pago Nº :number',
'load_template_description' => 'La plantilla se aplicará a lo siguiente:', 'load_template_description' => 'La plantilla se aplicará a lo siguiente:',
'run_template' => 'Run Template', 'run_template' => 'Ejecutar plantilla',
'statement_design' => 'Diseño de Estado de Cuenta', 'statement_design' => 'Diseño de Estado de Cuenta',
'delivery_note_design' => 'Diseño de albarán de entrega', 'delivery_note_design' => 'Diseño de albarán de entrega',
'payment_receipt_design' => 'Diseño de recibo de pago', 'payment_receipt_design' => 'Diseño de recibo de pago',
@ -5121,7 +5121,7 @@ De lo contrario, este campo deberá dejarse en blanco.',
'all_contacts' => 'Todos los contactos', 'all_contacts' => 'Todos los contactos',
'insert_below' => 'Insertar abajo', 'insert_below' => 'Insertar abajo',
'nordigen_handler_subtitle' => 'Autenticación de cuenta bancaria. Seleccionar su institución para completar la solicitud con las credenciales de su cuenta.', 'nordigen_handler_subtitle' => 'Autenticación de cuenta bancaria. Seleccionar su institución para completar la solicitud con las credenciales de su cuenta.',
'nordigen_handler_error_heading_unknown' => 'Ha ocurrido un error', 'nordigen_handler_error_heading_unknown' => 'Se ha producido un error',
'nordigen_handler_error_contents_unknown' => '¡Se ha producido un error desconocido! Razón:', 'nordigen_handler_error_contents_unknown' => '¡Se ha producido un error desconocido! Razón:',
'nordigen_handler_error_heading_token_invalid' => 'Token no válido', 'nordigen_handler_error_heading_token_invalid' => 'Token no válido',
'nordigen_handler_error_contents_token_invalid' => 'El token proporcionado no era válido. Póngase en contacto con el soporte para obtener ayuda si este problema persiste.', 'nordigen_handler_error_contents_token_invalid' => 'El token proporcionado no era válido. Póngase en contacto con el soporte para obtener ayuda si este problema persiste.',
@ -5235,69 +5235,79 @@ De lo contrario, este campo deberá dejarse en blanco.',
'local_domain_help' => 'Dominio EHLO (opcional)', 'local_domain_help' => 'Dominio EHLO (opcional)',
'port_help' => 'Ej. 25.587.465', 'port_help' => 'Ej. 25.587.465',
'host_help' => 'Ej. smtp.gmail.com', 'host_help' => 'Ej. smtp.gmail.com',
'always_show_required_fields' => 'Allows show required fields form', 'always_show_required_fields' => 'Mostrar siempre los campos obligatorios del formulario',
'always_show_required_fields_help' => 'Displays the required fields form always at checkout', 'always_show_required_fields_help' => 'Muestra siempre el formulario de campos obligatorios al finalizar la compra',
'advanced_cards' => 'Advanced Cards', 'advanced_cards' => 'Tarjetas avanzadas',
'activity_140' => 'Statement sent to :client', 'activity_140' => 'Declaración enviada a :client',
'invoice_net_amount' => 'Invoice Net Amount', 'invoice_net_amount' => 'Importe neto de la factura',
'round_to_minutes' => 'Round To Minutes', 'round_to_minutes' => 'Redondear a minutos',
'1_second' => '1 Second', '1_second' => '1 segundo',
'1_minute' => '1 Minute', '1_minute' => '1 minuto',
'5_minutes' => '5 Minutes', '5_minutes' => '5 minutos',
'15_minutes' => '15 Minutes', '15_minutes' => '15 minutos',
'30_minutes' => '30 Minutes', '30_minutes' => '30 minutos',
'1_hour' => '1 Hour', '1_hour' => '1 hora',
'1_day' => '1 Day', '1_day' => '1 día',
'round_tasks' => 'Task Rounding Direction', 'round_tasks' => 'Dirección de redondeo de tareas',
'round_tasks_help' => 'Round task times up or down.', 'round_tasks_help' => 'Redondea los tiempos de las tareas hacia arriba o hacia abajo.',
'direction' => 'Direction', 'direction' => 'Dirección',
'round_up' => 'Round Up', 'round_up' => 'Redondeo',
'round_down' => 'Round Down', 'round_down' => 'Redondear a la baja',
'task_round_to_nearest' => 'Round To Nearest', 'task_round_to_nearest' => 'Redondear al más cercano',
'task_round_to_nearest_help' => 'The interval to round the task to.', 'task_round_to_nearest_help' => 'El intervalo al que se debe redondear la tarea.',
'bulk_updated' => 'Successfully updated data', 'bulk_updated' => 'Datos actualizados con éxito',
'bulk_update' => 'Bulk Update', 'bulk_update' => 'Actualización masiva',
'calculate' => 'Calculate', 'calculate' => 'Calcular',
'sum' => 'Sum', 'sum' => 'Suma',
'money' => 'Money', 'money' => 'Dinero',
'web_app' => 'Web App', 'web_app' => 'Aplicación Web',
'desktop_app' => 'Desktop App', 'desktop_app' => 'Aplicación de escritorio',
'disconnected' => 'Disconnected', 'disconnected' => 'Desconectado',
'reconnect' => 'Reconnect', 'reconnect' => 'Reconectar',
'e_invoice_settings' => 'E-Invoice Settings', 'e_invoice_settings' => 'Configuración de factura electrónica',
'btcpay_refund_subject' => 'Refund of your invoice via BTCPay', 'btcpay_refund_subject' => 'Reembolso de su factura a través de BTCPay',
'btcpay_refund_body' => 'A refund intended for you has been issued. To claim it via BTCPay, please click on this link:', 'btcpay_refund_body' => 'Se ha emitido un reembolso destinado a usted. Para reclamarlo a través de BTCPay, haga clic en este enlace:',
'currency_mauritanian_ouguiya' => 'Mauritanian Ouguiya', 'currency_mauritanian_ouguiya' => 'Mauritanian Ouguiya',
'currency_bhutan_ngultrum' => 'Bhutan Ngultrum', 'currency_bhutan_ngultrum' => 'Bhutan Ngultrum',
'end_of_month' => 'End Of Month', 'end_of_month' => 'Fin de mes',
'merge_e_invoice_to_pdf' => 'Merge E-Invoice and PDF', 'merge_e_invoice_to_pdf' => 'Fusionar factura electrónica y PDF',
'task_assigned_subject' => 'New task assignment [Task :task] [ :date ]', 'task_assigned_subject' => 'Nueva asignación de tarea [Tarea :task] [ :date ]',
'task_assigned_body' => 'You have been assigned task :task <br><br> Description: :description <br><br> Client: :client', 'task_assigned_body' => 'Se le ha asignado la tarea :task <br><br> Descripción: :description <br><br> Cliente: :client',
'activity_141' => 'User :user entered note: :notes', 'activity_141' => 'El usuario: :user ingresó la nota: :notes',
'quote_reminder_subject' => 'Reminder: Quote :quote from :company', 'quote_reminder_subject' => 'Recordatorio: Presupuesto :quote de :company',
'quote_reminder_message' => 'Reminder for quote :number for :amount', 'quote_reminder_message' => 'Recordatorio de presupuesto :number por :amount',
'quote_reminder1' => 'First Quote Reminder', 'quote_reminder1' => 'Recordatorio del primer presupuesto',
'before_valid_until_date' => 'Before the valid until date', 'before_valid_until_date' => 'Antes del válido hasta la fecha',
'after_valid_until_date' => 'After the valid until date', 'after_valid_until_date' => 'Después de la fecha de validez hasta',
'after_quote_date' => 'After the quote date', 'after_quote_date' => 'Después de la fecha del presupuesto',
'remind_quote' => 'Remind Quote', 'remind_quote' => 'Recordatorio de presupuesto',
'end_of_month' => 'End Of Month', 'end_of_month' => 'Fin de mes',
'tax_currency_mismatch' => 'Tax currency is different from invoice currency', 'tax_currency_mismatch' => 'La moneda del impuesto es diferente a la moneda de la factura',
'edocument_import_already_exists' => 'The invoice has already been imported on :date', 'edocument_import_already_exists' => 'La factura ya fué importada el :date',
'before_valid_until' => 'Before the valid until', 'before_valid_until' => 'Antes del válido hasta',
'after_valid_until' => 'After the valid until', 'after_valid_until' => 'Después del válido hasta',
'task_assigned_notification' => 'Task Assigned Notification', 'task_assigned_notification' => 'Notificación de tarea asignada',
'task_assigned_notification_help' => 'Send an email when a task is assigned', 'task_assigned_notification_help' => 'Enviar un correo electrónico cuando se asigna una tarea',
'invoices_locked_end_of_month' => 'Invoices are locked at the end of the month', 'invoices_locked_end_of_month' => 'Las facturas se bloquean al final del mes.',
'referral_url' => 'Referral URL', 'referral_url' => 'URL de referencia',
'add_comment' => 'Add Comment', 'add_comment' => 'Agregar comentario',
'added_comment' => 'Successfully saved comment', 'added_comment' => 'Comentario guardado correctamente',
'tickets' => 'Tickets', 'tickets' => 'Tickets',
'assigned_group' => 'Successfully assigned group', 'assigned_group' => 'Grupo asignado exitosamente',
'merge_to_pdf' => 'Merge to PDF', 'merge_to_pdf' => 'Fusionar a PDF',
'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'latest_requires_php_version' => 'Nota: la última versión requiere PHP :version',
'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes' => 'Expandir automáticamente las notas de la tabla de productos',
'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', 'auto_expand_product_table_notes_help' => 'Expande automáticamente la sección de notas dentro de la tabla de productos para mostrar más líneas.',
'institution_number' => 'Número de institución',
'transit_number' => 'Número de Tránsito',
'personal' => 'Personal',
'address_information' => 'Datos del Domicilio',
'enter_the_information_for_the_bank_account' => 'Introduzca la información de la cuenta bancaria',
'account_holder_information' => 'Información del titular de la cuenta',
'enter_information_for_the_account_holder' => 'Introducir información del titular de la cuenta',
'customer_type' => 'Tipo de cliente',
'process_date' => 'Fecha de procesamiento',
'forever_free' => 'Forever Free',
); );
return $lang; return $lang;

View File

@ -5235,7 +5235,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'local_domain_help' => 'Domaine EHLO (facultatif)', 'local_domain_help' => 'Domaine EHLO (facultatif)',
'port_help' => 'ex. 25,587,465', 'port_help' => 'ex. 25,587,465',
'host_help' => 'ex. smtp.gmail.com', 'host_help' => 'ex. smtp.gmail.com',
'always_show_required_fields' => 'Permet l\'affichage des champs requis d\'un formulaire', 'always_show_required_fields' => 'Toujours afficher les champs requis d\'un formulaire',
'always_show_required_fields_help' => 'Affiche toujours les champs requis d\'un formulaire au paiement', 'always_show_required_fields_help' => 'Affiche toujours les champs requis d\'un formulaire au paiement',
'advanced_cards' => 'Cartes avancées', 'advanced_cards' => 'Cartes avancées',
'activity_140' => 'État de compte envoyé à :client', 'activity_140' => 'État de compte envoyé à :client',
@ -5298,7 +5298,20 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'latest_requires_php_version' => 'Note: La dernière version requiert PHP :version', 'latest_requires_php_version' => 'Note: La dernière version requiert PHP :version',
'auto_expand_product_table_notes' => 'Développer automatiquement les notes du tableau de produits', 'auto_expand_product_table_notes' => 'Développer automatiquement les notes du tableau de produits',
'auto_expand_product_table_notes_help' => '  'auto_expand_product_table_notes_help' => ' 
Développe automatiquement la section des notes dans le tableau de produits pour afficher plus de lignes.' Développe automatiquement la section des notes dans le tableau de produits pour afficher plus de lignes.',
'institution_number' => 'Numéro d\'institution',
'transit_number' => 'Numéro de transit',
'personal' => 'Personnel',
'address_information' => 'Information d\'adresse',
'enter_the_information_for_the_bank_account' => 'Entrez l\'information du compte de banque',
'account_holder_information' => 'Information sur le détenteur du compte',
'enter_information_for_the_account_holder' => 'Entrez l\'information du détenteur du compte',
'customer_type' => 'Type de client',
'process_date' => 'Date de traitement',
'forever_free' => 'Gratuit pour toujours',
'comments_only' => 'Commentaires seulement',
'payment_balance_on_file' => 'Payer le solde inscrit au dossier',
'ubl_email_attachment_help' => 'Plus de paramètres pour E-facture, cliquez :here',
); );
return $lang; return $lang;

View File

@ -3428,7 +3428,7 @@ adva :date',
'reminder2_sent' => 'Emlékeztető 2 elküldve', 'reminder2_sent' => 'Emlékeztető 2 elküldve',
'reminder3_sent' => 'Emlékeztető 3 elküldve', 'reminder3_sent' => 'Emlékeztető 3 elküldve',
'reminder_last_sent' => 'Utolsó emlékeztető elküldve', 'reminder_last_sent' => 'Utolsó emlékeztető elküldve',
'pdf_page_info' => 'PDF oldal információ', 'pdf_page_info' => 'PDF oldal :current / :total',
'emailed_credits' => 'E-mailezett jóváírások', 'emailed_credits' => 'E-mailezett jóváírások',
'view_in_stripe' => 'Megtekintés a Stripe-ban', 'view_in_stripe' => 'Megtekintés a Stripe-ban',
'rows_per_page' => 'Sorok száma oldalanként', 'rows_per_page' => 'Sorok száma oldalanként',
@ -5108,7 +5108,7 @@ adva :date',
'all_contacts' => 'Minden névjegy', 'all_contacts' => 'Minden névjegy',
'insert_below' => 'Beszúrás alább', 'insert_below' => 'Beszúrás alább',
'nordigen_handler_subtitle' => 'Bankszámla hitelesítés. Intézményének kiválasztása a kérelem kitöltéséhez a fiók hitelesítő adataival.', 'nordigen_handler_subtitle' => 'Bankszámla hitelesítés. Intézményének kiválasztása a kérelem kitöltéséhez a fiók hitelesítő adataival.',
'nordigen_handler_error_heading_unknown' => 'Hiba történt', 'nordigen_handler_error_heading_unknown' => 'An error has occurred',
'nordigen_handler_error_contents_unknown' => 'Ismeretlen hiba lépett fel! Ok:', 'nordigen_handler_error_contents_unknown' => 'Ismeretlen hiba lépett fel! Ok:',
'nordigen_handler_error_heading_token_invalid' => 'Érvénytelen kód', 'nordigen_handler_error_heading_token_invalid' => 'Érvénytelen kód',
'nordigen_handler_error_contents_token_invalid' => 'A megadott token érvénytelen. Ha a probléma továbbra is fennáll, forduljon az ügyfélszolgálathoz.', 'nordigen_handler_error_contents_token_invalid' => 'A megadott token érvénytelen. Ha a probléma továbbra is fennáll, forduljon az ügyfélszolgálathoz.',
@ -5222,7 +5222,7 @@ adva :date',
'local_domain_help' => 'EHLO domain (optional)', 'local_domain_help' => 'EHLO domain (optional)',
'port_help' => 'ie. 25,587,465', 'port_help' => 'ie. 25,587,465',
'host_help' => 'ie. smtp.gmail.com', 'host_help' => 'ie. smtp.gmail.com',
'always_show_required_fields' => 'Allows show required fields form', 'always_show_required_fields' => 'Always show required fields form',
'always_show_required_fields_help' => 'Displays the required fields form always at checkout', 'always_show_required_fields_help' => 'Displays the required fields form always at checkout',
'advanced_cards' => 'Advanced Cards', 'advanced_cards' => 'Advanced Cards',
'activity_140' => 'Statement sent to :client', 'activity_140' => 'Statement sent to :client',
@ -5285,6 +5285,16 @@ adva :date',
'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'latest_requires_php_version' => 'Note: the latest version requires PHP :version',
'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes' => 'Automatically expand products table notes',
'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.',
'institution_number' => 'Institution Number',
'transit_number' => 'Transit Number',
'personal' => 'Personal',
'address_information' => 'Address Information',
'enter_the_information_for_the_bank_account' => 'Enter the Information for the Bank Account',
'account_holder_information' => 'Account Holder Information',
'enter_information_for_the_account_holder' => 'Enter Information for the Account Holder',
'customer_type' => 'Customer Type',
'process_date' => 'Process Date',
'forever_free' => 'Forever Free',
); );
return $lang; return $lang;

View File

@ -4946,7 +4946,7 @@ $lang = array(
'tax_exempt' => 'Esente da tasse', 'tax_exempt' => 'Esente da tasse',
'late_fee_added_locked_invoice' => 'Penale per ritardo Fattura :invoice aggiunta su :date', 'late_fee_added_locked_invoice' => 'Penale per ritardo Fattura :invoice aggiunta su :date',
'lang_Khmer' => 'Khmer', 'lang_Khmer' => 'Khmer',
'routing_id' => 'ID di instradamento', 'routing_id' => 'Codice Destinario',
'enable_e_invoice' => 'Abilita E- Fattura', 'enable_e_invoice' => 'Abilita E- Fattura',
'e_invoice_type' => 'Tipo di Fattura E', 'e_invoice_type' => 'Tipo di Fattura E',
'reduced_tax' => 'Tassa ridotta', 'reduced_tax' => 'Tassa ridotta',
@ -5115,7 +5115,7 @@ $lang = array(
'all_contacts' => 'Tutti i contatti', 'all_contacts' => 'Tutti i contatti',
'insert_below' => 'Inserisci sotto', 'insert_below' => 'Inserisci sotto',
'nordigen_handler_subtitle' => 'Autenticazione del conto bancario. Seleziona il tuo istituto per completare la richiesta con le credenziali del tuo account.', 'nordigen_handler_subtitle' => 'Autenticazione del conto bancario. Seleziona il tuo istituto per completare la richiesta con le credenziali del tuo account.',
'nordigen_handler_error_heading_unknown' => 'C&#39;è stato un errore', 'nordigen_handler_error_heading_unknown' => 'An error has occurred',
'nordigen_handler_error_contents_unknown' => 'Si è verificato un errore sconosciuto! Motivo:', 'nordigen_handler_error_contents_unknown' => 'Si è verificato un errore sconosciuto! Motivo:',
'nordigen_handler_error_heading_token_invalid' => 'gettone non valido', 'nordigen_handler_error_heading_token_invalid' => 'gettone non valido',
'nordigen_handler_error_contents_token_invalid' => 'Il token fornito non era valido. contatto il supporto per assistenza, se il problema persiste.', 'nordigen_handler_error_contents_token_invalid' => 'Il token fornito non era valido. contatto il supporto per assistenza, se il problema persiste.',
@ -5229,7 +5229,7 @@ $lang = array(
'local_domain_help' => 'EHLO domain (optional)', 'local_domain_help' => 'EHLO domain (optional)',
'port_help' => 'ie. 25,587,465', 'port_help' => 'ie. 25,587,465',
'host_help' => 'ie. smtp.gmail.com', 'host_help' => 'ie. smtp.gmail.com',
'always_show_required_fields' => 'Allows show required fields form', 'always_show_required_fields' => 'Always show required fields form',
'always_show_required_fields_help' => 'Displays the required fields form always at checkout', 'always_show_required_fields_help' => 'Displays the required fields form always at checkout',
'advanced_cards' => 'Advanced Cards', 'advanced_cards' => 'Advanced Cards',
'activity_140' => 'Statement sent to :client', 'activity_140' => 'Statement sent to :client',
@ -5292,6 +5292,19 @@ $lang = array(
'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'latest_requires_php_version' => 'Note: the latest version requires PHP :version',
'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes' => 'Automatically expand products table notes',
'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.',
'institution_number' => 'Institution Number',
'transit_number' => 'Transit Number',
'personal' => 'Personal',
'address_information' => 'Address Information',
'enter_the_information_for_the_bank_account' => 'Enter the Information for the Bank Account',
'account_holder_information' => 'Account Holder Information',
'enter_information_for_the_account_holder' => 'Enter Information for the Account Holder',
'customer_type' => 'Customer Type',
'process_date' => 'Process Date',
'forever_free' => 'Forever Free',
'comments_only' => 'Comments Only',
'payment_balance_on_file' => 'Payment Balance On File',
'ubl_email_attachment_help' => 'For more e-invoice settings please navigate :here',
); );
return $lang; return $lang;

View File

@ -3444,7 +3444,7 @@ $lang = array(
'reminder2_sent' => 'ແຈ້ງເຕືອນ 2 ສົ່ງແລ້ວ', 'reminder2_sent' => 'ແຈ້ງເຕືອນ 2 ສົ່ງແລ້ວ',
'reminder3_sent' => 'ເຕືອນ 3 ສົ່ງແລ້ວ', 'reminder3_sent' => 'ເຕືອນ 3 ສົ່ງແລ້ວ',
'reminder_last_sent' => 'ເຕືອນທີ່ສົ່ງຫຼ້າສຸດ', 'reminder_last_sent' => 'ເຕືອນທີ່ສົ່ງຫຼ້າສຸດ',
'pdf_page_info' => 'ໜ້າ :ປັດຈຸບັນຂອງ :ທັງໝົດ', 'pdf_page_info' => 'ໜ້າ :current :total',
'emailed_credits' => 'ເຄຣດິດທີ່ສົ່ງອີເມວສຳເລັດແລ້ວ', 'emailed_credits' => 'ເຄຣດິດທີ່ສົ່ງອີເມວສຳເລັດແລ້ວ',
'view_in_stripe' => 'ເບິ່ງເປັນເສັ້ນດ່າງ', 'view_in_stripe' => 'ເບິ່ງເປັນເສັ້ນດ່າງ',
'rows_per_page' => 'ແຖວຕໍ່ໜ້າ', 'rows_per_page' => 'ແຖວຕໍ່ໜ້າ',
@ -5124,7 +5124,7 @@ $lang = array(
'all_contacts' => 'ຕິດຕໍ່ພົວພັນທັງໝົດ', 'all_contacts' => 'ຕິດຕໍ່ພົວພັນທັງໝົດ',
'insert_below' => 'ໃສ່ທາງລຸ່ມ', 'insert_below' => 'ໃສ່ທາງລຸ່ມ',
'nordigen_handler_subtitle' => 'ການຢືນຢັນບັນຊີທະນາຄານ. ການເລືອກສະຖາບັນຂອງທ່ານເພື່ອເຮັດສໍາເລັດຄໍາຮ້ອງຂໍທີ່ມີຂໍ້ມູນປະຈໍາບັນຊີຂອງທ່ານ.', 'nordigen_handler_subtitle' => 'ການຢືນຢັນບັນຊີທະນາຄານ. ການເລືອກສະຖາບັນຂອງທ່ານເພື່ອເຮັດສໍາເລັດຄໍາຮ້ອງຂໍທີ່ມີຂໍ້ມູນປະຈໍາບັນຊີຂອງທ່ານ.',
'nordigen_handler_error_heading_unknown' => 'ເກີດຄວາມຜິດພາດຂຶ້ນ', 'nordigen_handler_error_heading_unknown' => 'An error has occurred',
'nordigen_handler_error_contents_unknown' => 'ມີຄວາມຜິດພາດທີ່ບໍ່ຮູ້ຈັກເກີດຂຶ້ນ! ເຫດ​ຜົນ:', 'nordigen_handler_error_contents_unknown' => 'ມີຄວາມຜິດພາດທີ່ບໍ່ຮູ້ຈັກເກີດຂຶ້ນ! ເຫດ​ຜົນ:',
'nordigen_handler_error_heading_token_invalid' => 'ໂທເຄັນບໍ່ຖືກຕ້ອງ', 'nordigen_handler_error_heading_token_invalid' => 'ໂທເຄັນບໍ່ຖືກຕ້ອງ',
'nordigen_handler_error_contents_token_invalid' => 'ໂທເຄັນທີ່ໃຫ້ມາບໍ່ຖືກຕ້ອງ. ຕິດຕໍ່ຝ່າຍຊ່ວຍເຫຼືອເພື່ອຂໍຄວາມຊ່ວຍເຫຼືອ, ຖ້າບັນຫານີ້ຍັງຄົງຢູ່.', 'nordigen_handler_error_contents_token_invalid' => 'ໂທເຄັນທີ່ໃຫ້ມາບໍ່ຖືກຕ້ອງ. ຕິດຕໍ່ຝ່າຍຊ່ວຍເຫຼືອເພື່ອຂໍຄວາມຊ່ວຍເຫຼືອ, ຖ້າບັນຫານີ້ຍັງຄົງຢູ່.',
@ -5238,7 +5238,7 @@ $lang = array(
'local_domain_help' => 'EHLO domain (optional)', 'local_domain_help' => 'EHLO domain (optional)',
'port_help' => 'ie. 25,587,465', 'port_help' => 'ie. 25,587,465',
'host_help' => 'ie. smtp.gmail.com', 'host_help' => 'ie. smtp.gmail.com',
'always_show_required_fields' => 'ອະນຸຍາດໃຫ້ສະແດງແບບຟອມທີ່ຕ້ອງການ', 'always_show_required_fields' => 'Always show required fields form',
'always_show_required_fields_help' => 'ສະແດງແບບຟອມຊ່ອງຂໍ້ມູນທີ່ຕ້ອງການຢູ່ສະເໝີໃນເວລາຈ່າຍເງິນ', 'always_show_required_fields_help' => 'ສະແດງແບບຟອມຊ່ອງຂໍ້ມູນທີ່ຕ້ອງການຢູ່ສະເໝີໃນເວລາຈ່າຍເງິນ',
'advanced_cards' => 'ບັດຂັ້ນສູງ', 'advanced_cards' => 'ບັດຂັ້ນສູງ',
'activity_140' => 'Statement sent to :client', 'activity_140' => 'Statement sent to :client',
@ -5301,6 +5301,16 @@ $lang = array(
'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'latest_requires_php_version' => 'Note: the latest version requires PHP :version',
'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes' => 'Automatically expand products table notes',
'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.',
'institution_number' => 'Institution Number',
'transit_number' => 'Transit Number',
'personal' => 'Personal',
'address_information' => 'Address Information',
'enter_the_information_for_the_bank_account' => 'Enter the Information for the Bank Account',
'account_holder_information' => 'Account Holder Information',
'enter_information_for_the_account_holder' => 'Enter Information for the Account Holder',
'customer_type' => 'Customer Type',
'process_date' => 'Process Date',
'forever_free' => 'Forever Free',
); );
return $lang; return $lang;

View File

@ -233,7 +233,7 @@ $lang = array(
'updated_vendor' => 'De leverancier is gewijzigd', 'updated_vendor' => 'De leverancier is gewijzigd',
'created_vendor' => 'De leverancier is aangemaakt', 'created_vendor' => 'De leverancier is aangemaakt',
'archived_vendor' => 'De leverancier is gearchiveerd', 'archived_vendor' => 'De leverancier is gearchiveerd',
'archived_vendors' => 'Succesvol :count leveranciers gearchiveerd', 'archived_vendors' => 'Succesvol gerachiveerd: :count leverancier(s)',
'deleted_vendor' => 'De leverancier is verwijderd', 'deleted_vendor' => 'De leverancier is verwijderd',
'deleted_vendors' => 'Succesvol :count leveranciers verwijderd', 'deleted_vendors' => 'Succesvol :count leveranciers verwijderd',
'confirmation_subject' => 'Bevestiging account', 'confirmation_subject' => 'Bevestiging account',
@ -468,7 +468,7 @@ $lang = array(
'deleted_gateway' => 'De betaalprovider is verwijderd', 'deleted_gateway' => 'De betaalprovider is verwijderd',
'pay_with_paypal' => 'PayPal', 'pay_with_paypal' => 'PayPal',
'pay_with_card' => 'Creditcard', 'pay_with_card' => 'Creditcard',
'change_password' => 'Verander wachtwoord', 'change_password' => 'Wachtwoord wijzigen',
'current_password' => 'Huidig wachtwoord', 'current_password' => 'Huidig wachtwoord',
'new_password' => 'Nieuw wachtwoord', 'new_password' => 'Nieuw wachtwoord',
'confirm_password' => 'Bevestig wachtwoord', 'confirm_password' => 'Bevestig wachtwoord',
@ -883,13 +883,13 @@ $lang = array(
'expense' => 'Uitgave', 'expense' => 'Uitgave',
'expenses' => 'Uitgaven', 'expenses' => 'Uitgaven',
'new_expense' => 'Nieuwe uitgave', 'new_expense' => 'Nieuwe uitgave',
'new_vendor' => 'Nieuwe leverancier', 'new_vendor' => 'Nieuwe Leverancier',
'payment_terms_net' => 'Betaaltermijn', 'payment_terms_net' => 'Betaaltermijn',
'vendor' => 'Leverancier', 'vendor' => 'Leverancier',
'edit_vendor' => 'Bewerk leverancier', 'edit_vendor' => 'Bewerk Leverancier',
'archive_vendor' => 'Archiveer leverancier', 'archive_vendor' => 'Archiveer Leverancier',
'delete_vendor' => 'Verwijder leverancier', 'delete_vendor' => 'Verwijder Leverancier',
'view_vendor' => 'Bekijk leverancier', 'view_vendor' => 'Bekijk Leverancier',
'deleted_expense' => 'De uitgave is verwijderd', 'deleted_expense' => 'De uitgave is verwijderd',
'archived_expense' => 'De uitgave is gearchiveerd', 'archived_expense' => 'De uitgave is gearchiveerd',
'deleted_expenses' => 'De uitgaven zijn verwijderd', 'deleted_expenses' => 'De uitgaven zijn verwijderd',
@ -1046,7 +1046,7 @@ $lang = array(
'enable_portal_password' => 'Facturen beveiligen met een wachtwoord', 'enable_portal_password' => 'Facturen beveiligen met een wachtwoord',
'enable_portal_password_help' => 'Geeft u de mogelijkheid om een wachtwoord in te stellen voor elke contactpersoon. Als er een wachtwoord is ingesteld moet de contactpersoon het wachtwoord invoeren voordat deze facturen kan bekijken.', 'enable_portal_password_help' => 'Geeft u de mogelijkheid om een wachtwoord in te stellen voor elke contactpersoon. Als er een wachtwoord is ingesteld moet de contactpersoon het wachtwoord invoeren voordat deze facturen kan bekijken.',
'send_portal_password' => 'Genereer automatisch', 'send_portal_password' => 'Genereer automatisch',
'send_portal_password_help' => 'Als er geen wachtwoord is ingesteld zal deze automatisch worden gegenereerd en verzonden bij de eerste factuur.', 'send_portal_password_help' => 'Als er geen wachtwoord is ingesteld zal dit automatisch worden gegenereerd en verzonden bij de eerste factuur.',
'expired' => 'Verlopen', 'expired' => 'Verlopen',
'invalid_card_number' => 'Het creditcardnummer is niet geldig.', 'invalid_card_number' => 'Het creditcardnummer is niet geldig.',
@ -1063,7 +1063,7 @@ $lang = array(
'user_view_all' => 'Bekijken van klanten, facturen, enz.', 'user_view_all' => 'Bekijken van klanten, facturen, enz.',
'user_edit_all' => 'Bewerken van alle klanten, facturen, enz.', 'user_edit_all' => 'Bewerken van alle klanten, facturen, enz.',
'partial_due' => 'Voorschot', 'partial_due' => 'Voorschot',
'restore_vendor' => 'Herstel leverancier', 'restore_vendor' => 'Herstel Leverancier',
'restored_vendor' => 'De leverancier is hersteld', 'restored_vendor' => 'De leverancier is hersteld',
'restored_expense' => 'De uitgave is hersteld', 'restored_expense' => 'De uitgave is hersteld',
'permissions' => 'Rechten', 'permissions' => 'Rechten',
@ -1114,9 +1114,9 @@ $lang = array(
'document_size' => 'Grootte', 'document_size' => 'Grootte',
'enable_client_portal' => 'Dashboard', 'enable_client_portal' => 'Dashboard',
'enable_client_portal_help' => 'Toon/verberg het klantenportaal.', 'enable_client_portal_help' => 'Toon of verberg het klantenportaal.',
'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard' => 'Dashboard',
'enable_client_portal_dashboard_help' => 'Toon/verberg de dashboard pagina in het klantenportaal.', 'enable_client_portal_dashboard_help' => 'Toon of verberg de dashboardpagina in het klantenportaal.',
// Plans // Plans
'account_management' => 'Accountbeheer', 'account_management' => 'Accountbeheer',
@ -1168,7 +1168,7 @@ $lang = array(
'live_preview_disabled' => 'Live voorbeeld weergave is uitgeschakeld om het geselecteerde lettertype te ondersteunen.', 'live_preview_disabled' => 'Live voorbeeld weergave is uitgeschakeld om het geselecteerde lettertype te ondersteunen.',
'invoice_number_padding' => 'Marge', 'invoice_number_padding' => 'Marge',
'preview' => 'Voorbeeld', 'preview' => 'Voorbeeld',
'list_vendors' => 'Toon leveranciers', 'list_vendors' => 'Toon Leveranciers',
'add_users_not_supported' => 'Upgrade naar het Enterprise-abonnement om extra gebruikers aan uw account toe te voegen.', 'add_users_not_supported' => 'Upgrade naar het Enterprise-abonnement om extra gebruikers aan uw account toe te voegen.',
'enterprise_plan_features' => 'Het Enterprise Plan voegt ondersteuning toe voor meerdere gebruikers en bestandsbijlagen, :link om de volledige lijst met functies te zien.', 'enterprise_plan_features' => 'Het Enterprise Plan voegt ondersteuning toe voor meerdere gebruikers en bestandsbijlagen, :link om de volledige lijst met functies te zien.',
'return_to_app' => 'Terug naar de app', 'return_to_app' => 'Terug naar de app',
@ -2487,7 +2487,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'self_host_login' => 'Self-Host login', 'self_host_login' => 'Self-Host login',
'set_self_hoat_url' => 'Self-Host URL', 'set_self_hoat_url' => 'Self-Host URL',
'local_storage_required' => 'Fout: lokale opslag is niet beschikbaar.', 'local_storage_required' => 'Fout: lokale opslag is niet beschikbaar.',
'your_password_reset_link' => 'Uw wachtwoord reset koppeling', 'your_password_reset_link' => 'Uw Wachtwoord Resetlink',
'subdomain_taken' => 'Het subdomein is al in gebruik', 'subdomain_taken' => 'Het subdomein is al in gebruik',
'client_login' => 'Klantenlogin', 'client_login' => 'Klantenlogin',
'converted_amount' => 'Omgezet bedrag', 'converted_amount' => 'Omgezet bedrag',
@ -2544,8 +2544,8 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'subscription_event_10' => 'Klant bijgewerkt', 'subscription_event_10' => 'Klant bijgewerkt',
'subscription_event_11' => 'Klant verwijderd', 'subscription_event_11' => 'Klant verwijderd',
'subscription_event_12' => 'Betaling verwijderd', 'subscription_event_12' => 'Betaling verwijderd',
'subscription_event_13' => 'Verkoper bijgewerkt', 'subscription_event_13' => 'Leverancier bijgewerkt',
'subscription_event_14' => 'Verkoper verwijderd', 'subscription_event_14' => 'Leverancier verwijderd',
'subscription_event_15' => 'Uitgave aangemaakt', 'subscription_event_15' => 'Uitgave aangemaakt',
'subscription_event_16' => 'Uitgave bijgewerkt', 'subscription_event_16' => 'Uitgave bijgewerkt',
'subscription_event_17' => 'Uitgave verwijderen', 'subscription_event_17' => 'Uitgave verwijderen',
@ -2565,7 +2565,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'module_credit' => 'Creditfacturen', 'module_credit' => 'Creditfacturen',
'module_quote' => 'Offertes & voorstellen', 'module_quote' => 'Offertes & voorstellen',
'module_task' => 'Taken & projecten', 'module_task' => 'Taken & projecten',
'module_expense' => 'Uitgaven & leveranciers', 'module_expense' => 'Uitgaven & Leveranciers',
'module_ticket' => 'Tickets', 'module_ticket' => 'Tickets',
'reminders' => 'Herinneringen', 'reminders' => 'Herinneringen',
'send_client_reminders' => 'Verzend e-mailherinneringen', 'send_client_reminders' => 'Verzend e-mailherinneringen',
@ -2904,7 +2904,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'from_name_placeholder' => 'Support centrum', 'from_name_placeholder' => 'Support centrum',
'attachments' => 'Bijlagen', 'attachments' => 'Bijlagen',
'client_upload' => 'Klant uploads', 'client_upload' => 'Klant uploads',
'enable_client_upload_help' => 'Laat klanten documenten/bijlagen uploaden', 'enable_client_upload_help' => 'Klanten toestaan om documenten/bijlagen te uploaden',
'max_file_size_help' => 'De maximale bestandsgrootte (KB) wordt beperkt door de post_max_size en upload_max_filesize variabelen zoals ingesteld in uw PHP.INI', 'max_file_size_help' => 'De maximale bestandsgrootte (KB) wordt beperkt door de post_max_size en upload_max_filesize variabelen zoals ingesteld in uw PHP.INI',
'max_file_size' => 'Maximale bestandsgrootte', 'max_file_size' => 'Maximale bestandsgrootte',
'mime_types' => 'MIME-types', 'mime_types' => 'MIME-types',
@ -3078,7 +3078,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'filtered_by_group' => 'Filteren op groep', 'filtered_by_group' => 'Filteren op groep',
'filtered_by_invoice' => 'Filteren op factuur', 'filtered_by_invoice' => 'Filteren op factuur',
'filtered_by_client' => 'Filteren op klant', 'filtered_by_client' => 'Filteren op klant',
'filtered_by_vendor' => 'Filteren op leverancier', 'filtered_by_vendor' => 'Gefilterd op Leverancier',
'group_settings' => 'Groepsinstellingen', 'group_settings' => 'Groepsinstellingen',
'groups' => 'Groep', 'groups' => 'Groep',
'new_group' => 'Nieuwe groep', 'new_group' => 'Nieuwe groep',
@ -3174,7 +3174,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'applied' => 'Toegepast', 'applied' => 'Toegepast',
'include_recent_errors' => 'Voeg recente fouten uit de logboeken toe', 'include_recent_errors' => 'Voeg recente fouten uit de logboeken toe',
'your_message_has_been_received' => 'We hebben uw bericht ontvangen, en zullen zo spoedig mogelijk reageren. ', 'your_message_has_been_received' => 'We hebben uw bericht ontvangen, en zullen zo spoedig mogelijk reageren. ',
'show_product_details' => 'toon product details', 'show_product_details' => 'Toon Productdetails',
'show_product_details_help' => 'Neem de beschrijving en kosten op in de vervolgkeuzelijst met producten', 'show_product_details_help' => 'Neem de beschrijving en kosten op in de vervolgkeuzelijst met producten',
'pdf_min_requirements' => 'De PDF renderaar vereist :version', 'pdf_min_requirements' => 'De PDF renderaar vereist :version',
'adjust_fee_percent' => 'Pas Vergoedingspercentage Aan', 'adjust_fee_percent' => 'Pas Vergoedingspercentage Aan',
@ -3182,7 +3182,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'about' => 'Over', 'about' => 'Over',
'credit_email' => 'Krediet E-mail', 'credit_email' => 'Krediet E-mail',
'domain_url' => 'Domein URL', 'domain_url' => 'Domein URL',
'password_is_too_easy' => 'Het wachtwoord moet een hoofdletter en een nummer bevatten', 'password_is_too_easy' => 'Het wachtwoord moet een hoofdletter en een cijfer bevatten',
'client_portal_tasks' => 'Klantenportaal taken', 'client_portal_tasks' => 'Klantenportaal taken',
'client_portal_dashboard' => 'Klantenportaal dashboard', 'client_portal_dashboard' => 'Klantenportaal dashboard',
'please_enter_a_value' => 'Voer alstublieft een waarde in', 'please_enter_a_value' => 'Voer alstublieft een waarde in',
@ -3227,7 +3227,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'multi_line_text' => 'Multi-regelige tekst', 'multi_line_text' => 'Multi-regelige tekst',
'dropdown' => 'Dropdown', 'dropdown' => 'Dropdown',
'field_type' => 'Veld type', 'field_type' => 'Veld type',
'recover_password_email_sent' => 'Een wachtwoord herstel mail is verzonden', 'recover_password_email_sent' => 'Een e-mail voor wachtwoordherstel werd verzonden',
'removed_user' => 'Gebruiker verwijderd', 'removed_user' => 'Gebruiker verwijderd',
'freq_three_years' => 'Drie jaar', 'freq_three_years' => 'Drie jaar',
'military_time_help' => '24-uurs weergave', 'military_time_help' => '24-uurs weergave',
@ -3297,9 +3297,9 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'custom_surcharge3' => 'Aangepaste toeslag 3', 'custom_surcharge3' => 'Aangepaste toeslag 3',
'custom_surcharge4' => 'Aangepaste toeslag 4', 'custom_surcharge4' => 'Aangepaste toeslag 4',
'is_deleted' => 'Is verwijderd', 'is_deleted' => 'Is verwijderd',
'vendor_city' => 'Stad van de klant', 'vendor_city' => 'Leverancier Stad',
'vendor_state' => 'Leverancier provincie', 'vendor_state' => 'Leverancier Provincie',
'vendor_country' => 'Land van de verkoper', 'vendor_country' => 'Leverancier Land',
'credit_footer' => 'Voettekst creditfactuur', 'credit_footer' => 'Voettekst creditfactuur',
'credit_terms' => 'Voorwaarden creditfactuur', 'credit_terms' => 'Voorwaarden creditfactuur',
'untitled_company' => 'Naamloos bedrijf', 'untitled_company' => 'Naamloos bedrijf',
@ -3402,7 +3402,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'search_products' => 'Producten zoeken', 'search_products' => 'Producten zoeken',
'search_quotes' => 'Offertes zoeken', 'search_quotes' => 'Offertes zoeken',
'search_credits' => 'Zoek creditfactuur', 'search_credits' => 'Zoek creditfactuur',
'search_vendors' => 'Zoek leveranciers', 'search_vendors' => 'Zoek Leveranciers',
'search_users' => 'Zoek gebruikers', 'search_users' => 'Zoek gebruikers',
'search_tax_rates' => 'Zoek belastingstarieven', 'search_tax_rates' => 'Zoek belastingstarieven',
'search_tasks' => 'Zoek taken', 'search_tasks' => 'Zoek taken',
@ -3431,7 +3431,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'failure' => 'Fout', 'failure' => 'Fout',
'quota_exceeded' => 'Limiet bereikt', 'quota_exceeded' => 'Limiet bereikt',
'upstream_failure' => 'Upload mislukt', 'upstream_failure' => 'Upload mislukt',
'system_logs' => 'Systeem log', 'system_logs' => 'Systeemlogboek',
'copy_link' => 'Link kopiëren', 'copy_link' => 'Link kopiëren',
'welcome_to_invoice_ninja' => 'Welkom bij Invoice Ninja', 'welcome_to_invoice_ninja' => 'Welkom bij Invoice Ninja',
'optin' => 'Inschrijven', 'optin' => 'Inschrijven',
@ -3519,7 +3519,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'search_product' => 'Zoek 1 product', 'search_product' => 'Zoek 1 product',
'search_quote' => 'Zoek 1 offerte', 'search_quote' => 'Zoek 1 offerte',
'search_credit' => 'Zoek 1 creditfactuur', 'search_credit' => 'Zoek 1 creditfactuur',
'search_vendor' => 'Zoek 1 leverancier', 'search_vendor' => 'Zoek 1 Leverancier',
'search_user' => 'Zoek 1 gebruiker', 'search_user' => 'Zoek 1 gebruiker',
'search_tax_rate' => 'Zoek 1 BTW-tarief', 'search_tax_rate' => 'Zoek 1 BTW-tarief',
'search_task' => 'Zoek 1 taak', 'search_task' => 'Zoek 1 taak',
@ -3691,10 +3691,10 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'archived_groups' => 'Succesvol gearchiveerd: waarde groepen', 'archived_groups' => 'Succesvol gearchiveerd: waarde groepen',
'deleted_groups' => 'Succesvol verwijderd: waarde groepen', 'deleted_groups' => 'Succesvol verwijderd: waarde groepen',
'restored_groups' => 'Succesvol hersteld: waarde groepen', 'restored_groups' => 'Succesvol hersteld: waarde groepen',
'archived_documents' => 'Succesvol gearchiveerd: waarde documenten', 'archived_documents' => 'Succesvol gearchiveerd: :value document(en)',
'deleted_documents' => 'Succesvol verwijderd: waarde documenten', 'deleted_documents' => 'Succesvol verwijderd: :value document(en)',
'restored_documents' => 'Succesvol hersteld: waarde documenten', 'restored_documents' => 'Succesvol hersteld: :value document(en)',
'restored_vendors' => 'Succesvol hersteld: waarde leveranciers', 'restored_vendors' => 'Succesvol hersteld: :value leveranciers',
'restored_expenses' => 'Succesvol hersteld: waarde uitgaven', 'restored_expenses' => 'Succesvol hersteld: waarde uitgaven',
'restored_tasks' => 'Succesvol hersteld: waarde taken', 'restored_tasks' => 'Succesvol hersteld: waarde taken',
'restored_projects' => 'Succesvol hersteld: waarde projecten', 'restored_projects' => 'Succesvol hersteld: waarde projecten',
@ -3729,8 +3729,8 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'save_and_email' => 'Opslaan en e-mail versturen', 'save_and_email' => 'Opslaan en e-mail versturen',
'converted_balance' => 'Omgezet saldo', 'converted_balance' => 'Omgezet saldo',
'is_sent' => 'Is verzonden', 'is_sent' => 'Is verzonden',
'document_upload' => 'Document uploaden', 'document_upload' => 'Documenten uploaden',
'document_upload_help' => 'Laat klanten documenten uploaden', 'document_upload_help' => 'Klanten toestaan om documenten te uploaden',
'expense_total' => 'Totale uitgave', 'expense_total' => 'Totale uitgave',
'enter_taxes' => 'Voer belastingen in', 'enter_taxes' => 'Voer belastingen in',
'by_rate' => 'Op tarief', 'by_rate' => 'Op tarief',
@ -3827,7 +3827,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'per_page' => 'Per pagina', 'per_page' => 'Per pagina',
'of' => 'Of', 'of' => 'Of',
'view_credit' => 'Toon creditfactuur', 'view_credit' => 'Toon creditfactuur',
'to_view_entity_password' => 'Om de :entity te zien moet u een wachtwoord invoeren.', 'to_view_entity_password' => 'Om de :entity te bekijken moet u een wachtwoord invoeren.',
'showing_x_of' => 'Toont de :first tot :last van de :total resultaten', 'showing_x_of' => 'Toont de :first tot :last van de :total resultaten',
'no_results' => 'Geen resultaten gevonden.', 'no_results' => 'Geen resultaten gevonden.',
'payment_failed_subject' => 'Betaling mislukt voor klant :klant', 'payment_failed_subject' => 'Betaling mislukt voor klant :klant',
@ -3966,7 +3966,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'payment_message_extended' => 'Bedankt voor uw betaling van :amount voor :invoice', 'payment_message_extended' => 'Bedankt voor uw betaling van :amount voor :invoice',
'online_payments_minimum_note' => 'Opmerking: online-betalingen worden alleen ondersteund als het bedrag hoger is dan € 1,- of het equivalent in een andere valuta.', 'online_payments_minimum_note' => 'Opmerking: online-betalingen worden alleen ondersteund als het bedrag hoger is dan € 1,- of het equivalent in een andere valuta.',
'payment_token_not_found' => 'Betalingstoken niet gevonden. Probeer het opnieuw. Als het probleem zich blijft voordoen, probeer het dan met een andere betaalmethode', 'payment_token_not_found' => 'Betalingstoken niet gevonden. Probeer het opnieuw. Als het probleem zich blijft voordoen, probeer het dan met een andere betaalmethode',
'vendor_address1' => 'Leverancier straatnaam', 'vendor_address1' => 'Leverancier Straatnaam',
'vendor_address2' => 'Leverancier appartement/busnr.', 'vendor_address2' => 'Leverancier appartement/busnr.',
'partially_unapplied' => 'Gedeeltelijk niet toegepast', 'partially_unapplied' => 'Gedeeltelijk niet toegepast',
'select_a_gmail_user' => 'Selecteer een gebruiker die is geverifieerd met Gmail', 'select_a_gmail_user' => 'Selecteer een gebruiker die is geverifieerd met Gmail',
@ -4022,7 +4022,7 @@ Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en
'disconnected_google' => 'Account succesvol losgekoppeld', 'disconnected_google' => 'Account succesvol losgekoppeld',
'delivered' => 'Afgeleverd', 'delivered' => 'Afgeleverd',
'spam' => 'Spam', 'spam' => 'Spam',
'view_docs' => 'Bekijk documenten', 'view_docs' => 'Bekijk documentatie',
'enter_phone_to_enable_two_factor' => 'Geef een mobiel telefoonnummer op om tweefactorauthenticatie in te schakelen', 'enter_phone_to_enable_two_factor' => 'Geef een mobiel telefoonnummer op om tweefactorauthenticatie in te schakelen',
'send_sms' => 'Verzend SMS', 'send_sms' => 'Verzend SMS',
'sms_code' => 'SMS Code', 'sms_code' => 'SMS Code',
@ -4368,7 +4368,7 @@ E-mail: :email<b><br><b>',
'to_view_entity_set_password' => 'Om de :entity te bekijken, moet u een wachtwoord instellen.', 'to_view_entity_set_password' => 'Om de :entity te bekijken, moet u een wachtwoord instellen.',
'unsubscribe' => 'Afmelden', 'unsubscribe' => 'Afmelden',
'unsubscribed' => 'Afgemeld', 'unsubscribed' => 'Afgemeld',
'unsubscribed_text' => 'U bent verwijderd uit meldingen voor dit document', 'unsubscribed_text' => 'U ontvangt geen notificaties meer voor dit document',
'client_shipping_state' => 'Staat/provincie leveringsadres klant', 'client_shipping_state' => 'Staat/provincie leveringsadres klant',
'client_shipping_city' => 'Stad leveringsadres klant', 'client_shipping_city' => 'Stad leveringsadres klant',
'client_shipping_postal_code' => 'Postcode leveringsadres klant', 'client_shipping_postal_code' => 'Postcode leveringsadres klant',
@ -4476,13 +4476,13 @@ E-mail: :email<b><br><b>',
'view_purchase_order' => 'Bekijk inkooporder', 'view_purchase_order' => 'Bekijk inkooporder',
'purchase_orders_backup_subject' => 'Uw inkooporders zijn gereed om te downloaden', 'purchase_orders_backup_subject' => 'Uw inkooporders zijn gereed om te downloaden',
'notification_purchase_order_viewed_subject' => 'Inkooporder :invoice is bekeken door :client', 'notification_purchase_order_viewed_subject' => 'Inkooporder :invoice is bekeken door :client',
'notification_purchase_order_viewed' => 'De volgende leverancier :client heeft inkooporder :invoice voor :amount bekeken.', 'notification_purchase_order_viewed' => 'De leverancier :client heeft inkooporder :invoice van :amount bekeken.',
'purchase_order_date' => 'Datum inkooporder', 'purchase_order_date' => 'Datum inkooporder',
'purchase_orders' => 'Inkooporders', 'purchase_orders' => 'Inkooporders',
'purchase_order_number_placeholder' => 'Inkooporder #:purchase_order', 'purchase_order_number_placeholder' => 'Inkooporder #:purchase_order',
'accepted' => 'Geaccepteerd', 'accepted' => 'Geaccepteerd',
'activity_137' => ':contact geaccepteerde bestelling :purchase_order', 'activity_137' => ':contact geaccepteerde bestelling :purchase_order',
'vendor_information' => 'Informatie verkoper', 'vendor_information' => 'Leveracier Informatie',
'notification_purchase_order_accepted_subject' => 'Inkooporder :purchase_order is geaccepteerd door :vendor', 'notification_purchase_order_accepted_subject' => 'Inkooporder :purchase_order is geaccepteerd door :vendor',
'notification_purchase_order_accepted' => 'De volgende leverancier :vendor heeft inkooporder :purchase_order geaccepteerd voor :amount.', 'notification_purchase_order_accepted' => 'De volgende leverancier :vendor heeft inkooporder :purchase_order geaccepteerd voor :amount.',
'amount_received' => 'Bedrag ontvangen', 'amount_received' => 'Bedrag ontvangen',
@ -4491,9 +4491,9 @@ E-mail: :email<b><br><b>',
'add_to_inventory' => 'Toevoegen aan inventaris', 'add_to_inventory' => 'Toevoegen aan inventaris',
'added_purchase_order_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd', 'added_purchase_order_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd',
'added_purchase_orders_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd', 'added_purchase_orders_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd',
'client_document_upload' => 'Uploaden klantdocument', 'client_document_upload' => 'Klantendocumenten uploaden',
'vendor_document_upload' => 'Verkoopdocument uploaden', 'vendor_document_upload' => 'Leverancier Document Upload',
'vendor_document_upload_help' => 'Leveranciers in staat stellen documenten te uploaden', 'vendor_document_upload_help' => 'Leveranciers toestaan om documenten te uploaden',
'are_you_enjoying_the_app' => 'Bevalt de app?', 'are_you_enjoying_the_app' => 'Bevalt de app?',
'yes_its_great' => 'Ja, het is geweldig!', 'yes_its_great' => 'Ja, het is geweldig!',
'not_so_much' => 'Niet zo veel', 'not_so_much' => 'Niet zo veel',
@ -4505,12 +4505,12 @@ E-mail: :email<b><br><b>',
'last_sent_template' => 'Laatst verzonden sjabloon', 'last_sent_template' => 'Laatst verzonden sjabloon',
'enable_flexible_search' => 'Flexibel zoeken inschakelen', 'enable_flexible_search' => 'Flexibel zoeken inschakelen',
'enable_flexible_search_help' => 'Overeenkomen met niet-aangrenzende tekens, dwz. "ct" komt overeen met "kat"', 'enable_flexible_search_help' => 'Overeenkomen met niet-aangrenzende tekens, dwz. "ct" komt overeen met "kat"',
'vendor_details' => 'Details verkoper', 'vendor_details' => 'Leverancier Details',
'purchase_order_details' => 'Details inkooporder', 'purchase_order_details' => 'Details inkooporder',
'qr_iban' => 'QR IBAN', 'qr_iban' => 'QR IBAN',
'besr_id' => 'BESR-ID', 'besr_id' => 'BESR-ID',
'clone_to_purchase_order' => 'Kloon naar PO', 'clone_to_purchase_order' => 'Kloon naar PO',
'vendor_email_not_set' => 'Verkoper heeft geen e-mailadres ingesteld', 'vendor_email_not_set' => 'Leverancier heeft geen e-mailadres ingesteld',
'bulk_send_email' => 'Verzend e-mail', 'bulk_send_email' => 'Verzend e-mail',
'marked_purchase_order_as_sent' => 'Inkooporder succesvol gemarkeerd als verzonden', 'marked_purchase_order_as_sent' => 'Inkooporder succesvol gemarkeerd als verzonden',
'marked_purchase_orders_as_sent' => 'Inkooporders zijn gemarkeerd als verzonden', 'marked_purchase_orders_as_sent' => 'Inkooporders zijn gemarkeerd als verzonden',
@ -4518,7 +4518,7 @@ E-mail: :email<b><br><b>',
'accepted_purchase_orders' => 'Succesvol geaccepteerde inkooporders', 'accepted_purchase_orders' => 'Succesvol geaccepteerde inkooporders',
'cancelled_purchase_order' => 'Inkooporder succesvol geannuleerd', 'cancelled_purchase_order' => 'Inkooporder succesvol geannuleerd',
'cancelled_purchase_orders' => 'Inkooporders succesvol geannuleerd', 'cancelled_purchase_orders' => 'Inkooporders succesvol geannuleerd',
'please_select_a_vendor' => 'Gelieve een verkoper te selecteren', 'please_select_a_vendor' => 'Gelieve een leverancier te selecteren',
'purchase_order_total' => 'Totaal inkooporder', 'purchase_order_total' => 'Totaal inkooporder',
'email_purchase_order' => 'E-mail inkooporder', 'email_purchase_order' => 'E-mail inkooporder',
'bulk_email_purchase_order' => 'E-mail inkooporder', 'bulk_email_purchase_order' => 'E-mail inkooporder',
@ -4637,7 +4637,7 @@ E-mail: :email<b><br><b>',
'category_type' => 'Categorietype', 'category_type' => 'Categorietype',
'bank_transaction' => 'Transactie', 'bank_transaction' => 'Transactie',
'bulk_print' => 'Druk PDF af', 'bulk_print' => 'Druk PDF af',
'vendor_postal_code' => 'Postcode leverancier', 'vendor_postal_code' => 'Leverancier Postcode',
'preview_location' => 'Voorbeeldlocatie', 'preview_location' => 'Voorbeeldlocatie',
'bottom' => 'Onderkant', 'bottom' => 'Onderkant',
'side' => 'Kant', 'side' => 'Kant',
@ -4754,7 +4754,7 @@ E-mail: :email<b><br><b>',
'backup_restore' => 'Back-up | Herstellen', 'backup_restore' => 'Back-up | Herstellen',
'export_company' => 'Maak bedrijfsback-up', 'export_company' => 'Maak bedrijfsback-up',
'backup' => 'Back-up', 'backup' => 'Back-up',
'notification_purchase_order_created_body' => 'De volgende purchase_order :purchase_order is gemaakt voor vendor :vendor for :amount.', 'notification_purchase_order_created_body' => 'Inkooporder :purchase_order van :amount is aangemaakt voor leverancier :vendor.',
'notification_purchase_order_created_subject' => 'Inkooporder :purchase_order is aangemaakt voor :vendor', 'notification_purchase_order_created_subject' => 'Inkooporder :purchase_order is aangemaakt voor :vendor',
'notification_purchase_order_sent_subject' => 'Inkooporder :purchase_order is verzonden naar :vendor', 'notification_purchase_order_sent_subject' => 'Inkooporder :purchase_order is verzonden naar :vendor',
'notification_purchase_order_sent' => 'De volgende leverancier :vendor kreeg een inkooporder per e-mail :purchase_order voor :amount.', 'notification_purchase_order_sent' => 'De volgende leverancier :vendor kreeg een inkooporder per e-mail :purchase_order voor :amount.',
@ -5020,7 +5020,7 @@ E-mail: :email<b><br><b>',
'currency_swazi_lilangeni' => 'Swazische Lilangeni', 'currency_swazi_lilangeni' => 'Swazische Lilangeni',
'income' => 'Inkomen', 'income' => 'Inkomen',
'amount_received_help' => 'Vul hier een waarde in als het totaal ontvangen bedrag MEER was dan het factuurbedrag, of bij het vastleggen van een betaling zonder facturen. Anders moet dit veld leeg worden gelaten.', 'amount_received_help' => 'Vul hier een waarde in als het totaal ontvangen bedrag MEER was dan het factuurbedrag, of bij het vastleggen van een betaling zonder facturen. Anders moet dit veld leeg worden gelaten.',
'vendor_phone' => 'Verkoper telefoon', 'vendor_phone' => 'Leverancier Telefoonnummer',
'mercado_pago' => 'Mercado Pago', 'mercado_pago' => 'Mercado Pago',
'mybank' => 'Mijn bank', 'mybank' => 'Mijn bank',
'paypal_paylater' => 'Betaal in 4', 'paypal_paylater' => 'Betaal in 4',
@ -5065,7 +5065,7 @@ E-mail: :email<b><br><b>',
'charity' => 'Goed doel', 'charity' => 'Goed doel',
'government' => 'Overheid', 'government' => 'Overheid',
'in_stock_quantity' => 'Voorraadhoeveelheid', 'in_stock_quantity' => 'Voorraadhoeveelheid',
'vendor_contact' => 'Contactpersoon leverancier', 'vendor_contact' => 'Leverancier Contactpersoon',
'expense_status_4' => 'Onbetaald', 'expense_status_4' => 'Onbetaald',
'expense_status_5' => 'Betaald', 'expense_status_5' => 'Betaald',
'ziptax_help' => 'Let op: deze functie vereist een Zip-Tax API-sleutel om de Amerikaanse omzetbelasting op adres op te zoeken', 'ziptax_help' => 'Let op: deze functie vereist een Zip-Tax API-sleutel om de Amerikaanse omzetbelasting op adres op te zoeken',
@ -5111,7 +5111,7 @@ E-mail: :email<b><br><b>',
'payment_email_all_contacts_help' => 'Stuurt de betalings-e-mail naar alle contacten indien ingeschakeld', 'payment_email_all_contacts_help' => 'Stuurt de betalings-e-mail naar alle contacten indien ingeschakeld',
'add_line' => 'Lijn toevoegen', 'add_line' => 'Lijn toevoegen',
'activity_139' => 'Melding onkosten :expense verzonden naar :contact', 'activity_139' => 'Melding onkosten :expense verzonden naar :contact',
'vendor_notification_subject' => 'Bevestiging van betaling :amount verzonden naar :vendor', 'vendor_notification_subject' => 'Bevestiging van betaling van :amount verzonden naar :vendor',
'vendor_notification_body' => 'Betaling verwerkt voor :amount gedateerd :payment _date.<br> [Transactiereferentie: :transaction_reference ]', 'vendor_notification_body' => 'Betaling verwerkt voor :amount gedateerd :payment _date.<br> [Transactiereferentie: :transaction_reference ]',
'receipt' => 'Ontvangst', 'receipt' => 'Ontvangst',
'charges' => 'Kosten', 'charges' => 'Kosten',
@ -5309,7 +5309,11 @@ E-mail: :email<b><br><b>',
'account_holder_information' => 'Rekeninghouderinformatie', 'account_holder_information' => 'Rekeninghouderinformatie',
'enter_information_for_the_account_holder' => 'Voer de gegevens in van de rekeninghouder', 'enter_information_for_the_account_holder' => 'Voer de gegevens in van de rekeninghouder',
'customer_type' => 'Klanttype', 'customer_type' => 'Klanttype',
'process_date' => 'Verwerkingsdatum' 'process_date' => 'Verwerkingsdatum',
'forever_free' => 'Voor altijd gratis',
'comments_only' => 'Alleen opmerkingen',
'payment_balance_on_file' => 'Huidig saldo',
'ubl_email_attachment_help' => 'Voor meer e-factuurinstellingen, navigeer naar :here',
); );
return $lang; return $lang;

View File

@ -1646,7 +1646,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'country_Turkey' => 'Turquia', 'country_Turkey' => 'Turquia',
'country_Turkmenistan' => 'Turcomenistão', 'country_Turkmenistan' => 'Turcomenistão',
'country_Turks and Caicos Islands' => 'Ilhas Turks e Caicos', 'country_Turks and Caicos Islands' => 'Ilhas Turks e Caicos',
'country_Tuvalu' => 'Tuvalu', 'country_Tuvalu' => ' Tuvalu',
'country_Uganda' => 'Uganda', 'country_Uganda' => 'Uganda',
'country_Ukraine' => 'Ucrânia', 'country_Ukraine' => 'Ucrânia',
'country_Macedonia, the former Yugoslav Republic of' => 'Macedônia, antiga República Iugoslava', 'country_Macedonia, the former Yugoslav Republic of' => 'Macedônia, antiga República Iugoslava',
@ -3441,7 +3441,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'reminder2_sent' => 'Lembrete 2 Enviado', 'reminder2_sent' => 'Lembrete 2 Enviado',
'reminder3_sent' => 'Lembrete 3 Enviado', 'reminder3_sent' => 'Lembrete 3 Enviado',
'reminder_last_sent' => 'Último Lembrete Enviado', 'reminder_last_sent' => 'Último Lembrete Enviado',
'pdf_page_info' => 'Página: atual de: total', 'pdf_page_info' => 'Página: :current de: :total',
'emailed_credits' => 'Créditos enviados por e-mail com sucesso', 'emailed_credits' => 'Créditos enviados por e-mail com sucesso',
'view_in_stripe' => 'Ver em Listra', 'view_in_stripe' => 'Ver em Listra',
'rows_per_page' => 'Linhas por Página', 'rows_per_page' => 'Linhas por Página',
@ -5121,7 +5121,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'all_contacts' => 'Todos os contatos', 'all_contacts' => 'Todos os contatos',
'insert_below' => 'Inserir abaixo', 'insert_below' => 'Inserir abaixo',
'nordigen_handler_subtitle' => 'Autenticação de conta bancária. Selecionando sua instituição para concluir a solicitação com as credenciais de sua conta.', 'nordigen_handler_subtitle' => 'Autenticação de conta bancária. Selecionando sua instituição para concluir a solicitação com as credenciais de sua conta.',
'nordigen_handler_error_heading_unknown' => 'Ocorreu um erro', 'nordigen_handler_error_heading_unknown' => 'An error has occurred',
'nordigen_handler_error_contents_unknown' => 'Um erro desconhecido ocorreu! Razão:', 'nordigen_handler_error_contents_unknown' => 'Um erro desconhecido ocorreu! Razão:',
'nordigen_handler_error_heading_token_invalid' => 'Token inválido', 'nordigen_handler_error_heading_token_invalid' => 'Token inválido',
'nordigen_handler_error_contents_token_invalid' => 'O token fornecido era inválido. Entre em contato com o suporte para obter ajuda, se o problema persistir.', 'nordigen_handler_error_contents_token_invalid' => 'O token fornecido era inválido. Entre em contato com o suporte para obter ajuda, se o problema persistir.',
@ -5235,7 +5235,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'local_domain_help' => 'EHLO domain (optional)', 'local_domain_help' => 'EHLO domain (optional)',
'port_help' => 'ie. 25,587,465', 'port_help' => 'ie. 25,587,465',
'host_help' => 'ie. smtp.gmail.com', 'host_help' => 'ie. smtp.gmail.com',
'always_show_required_fields' => 'Allows show required fields form', 'always_show_required_fields' => 'Always show required fields form',
'always_show_required_fields_help' => 'Displays the required fields form always at checkout', 'always_show_required_fields_help' => 'Displays the required fields form always at checkout',
'advanced_cards' => 'Advanced Cards', 'advanced_cards' => 'Advanced Cards',
'activity_140' => 'Statement sent to :client', 'activity_140' => 'Statement sent to :client',
@ -5298,6 +5298,16 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'latest_requires_php_version' => 'Note: the latest version requires PHP :version',
'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes' => 'Automatically expand products table notes',
'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.',
'institution_number' => 'Institution Number',
'transit_number' => 'Transit Number',
'personal' => 'Personal',
'address_information' => 'Address Information',
'enter_the_information_for_the_bank_account' => 'Enter the Information for the Bank Account',
'account_holder_information' => 'Account Holder Information',
'enter_information_for_the_account_holder' => 'Enter Information for the Account Holder',
'customer_type' => 'Customer Type',
'process_date' => 'Process Date',
'forever_free' => 'Forever Free',
); );
return $lang; return $lang;

View File

@ -3443,7 +3443,7 @@ debitar da sua conta de acordo com essas instruções. Está elegível a um reem
'reminder2_sent' => 'Lembrete 2 Enviado', 'reminder2_sent' => 'Lembrete 2 Enviado',
'reminder3_sent' => 'Lembrete 3 Enviado', 'reminder3_sent' => 'Lembrete 3 Enviado',
'reminder_last_sent' => 'Último Lembrete Enviado', 'reminder_last_sent' => 'Último Lembrete Enviado',
'pdf_page_info' => 'Página: atual de: total', 'pdf_page_info' => 'Página: :current de: :total',
'emailed_credits' => 'Créditos enviados por e-mail com sucesso', 'emailed_credits' => 'Créditos enviados por e-mail com sucesso',
'view_in_stripe' => 'Ver em Formato Lista', 'view_in_stripe' => 'Ver em Formato Lista',
'rows_per_page' => 'Colunas por Página', 'rows_per_page' => 'Colunas por Página',

View File

@ -1,9 +0,0 @@
var a=Object.defineProperty;var d=(n,e,t)=>e in n?a(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var r=(n,e,t)=>(d(n,typeof e!="symbol"?e+"":e,t),t);/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/class o{constructor(e){r(this,"handleAuthorization",()=>{var e=$("#my-card"),t={api_login_id:this.apiLoginId,card_number:e.CardJs("cardNumber").replace(/[^\d]/g,""),expire_year:e.CardJs("expiryYear").replace(/[^\d]/g,""),expire_month:e.CardJs("expiryMonth").replace(/[^\d]/g,""),cvv:document.getElementById("cvv").value.replace(/[^\d]/g,"")};return document.getElementById("pay-now")&&(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden")),forte.createToken(t).success(this.successResponseHandler).error(this.failedResponseHandler),!1});r(this,"successResponseHandler",e=>(document.getElementById("payment_token").value=e.onetime_token,document.getElementById("card_brand").value=e.card_type,document.getElementById("server_response").submit(),!1));r(this,"failedResponseHandler",e=>{var t='<div class="alert alert-failure mb-4"><ul><li>'+e.response_description+"</li></ul></div>";return document.getElementById("forte_errors").innerHTML=t,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden"),!1});r(this,"handle",()=>{let e=document.getElementById("pay-now");return e&&e.addEventListener("click",t=>{this.handleAuthorization()}),this});this.apiLoginId=e,this.cardHolderName=document.getElementById("cardholder_name")}}const s=document.querySelector('meta[name="forte-api-login-id"]').content;new o(s).handle();

View File

@ -0,0 +1,9 @@
var r=Object.defineProperty;var l=(n,e,t)=>e in n?r(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(l(n,typeof e!="symbol"?e+"":e,t),t);/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/class c{constructor(e){d(this,"handleAuthorization",()=>{var e=$("#my-card"),t={api_login_id:this.apiLoginId,card_number:e.CardJs("cardNumber").replace(/[^\d]/g,""),expire_year:e.CardJs("expiryYear").replace(/[^\d]/g,""),expire_month:e.CardJs("expiryMonth").replace(/[^\d]/g,""),cvv:document.getElementById("cvv").value.replace(/[^\d]/g,"")};return document.getElementById("pay-now")&&(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden")),forte.createToken(t).success(this.successResponseHandler).error(this.failedResponseHandler),!1});d(this,"successResponseHandler",e=>{document.getElementById("payment_token").value=e.onetime_token,document.getElementById("card_brand").value=e.card_type,document.getElementById("expire_year").value=e.expire_year,document.getElementById("expire_month").value=e.expire_month,document.getElementById("last_4").value=e.last_4;let t=document.querySelector("input[name=token-billing-checkbox]:checked");return t&&(document.getElementById("store_card").value=t.value),document.getElementById("server_response").submit(),!1});d(this,"failedResponseHandler",e=>{var t='<div class="alert alert-failure mb-4"><ul><li>'+e.response_description+"</li></ul></div>";return document.getElementById("forte_errors").innerHTML=t,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden"),!1});d(this,"handle",()=>{Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(o=>o.addEventListener("click",a=>{document.getElementById("save-card--container").style.display="none",document.getElementById("forte--credit-card-container").style.display="none",document.getElementById("token").value=a.target.dataset.token}));let e=document.getElementById("toggle-payment-with-credit-card");e&&e.addEventListener("click",()=>{document.getElementById("save-card--container").style.display="grid",document.getElementById("forte--credit-card-container").style.display="flex",document.getElementById("token").value=null});let t=document.getElementById("pay-now");return t&&t.addEventListener("click",o=>{let a=document.getElementById("token");a.value?this.handlePayNowAction(a.value):this.handleAuthorization()}),this});this.apiLoginId=e,this.cardHolderName=document.getElementById("cardholder_name")}handlePayNowAction(e){document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),document.getElementById("token").value=e,document.getElementById("server_response").submit()}}const i=document.querySelector('meta[name="forte-api-login-id"]').content;new c(i).handle();

View File

@ -86,7 +86,7 @@
"src": "resources/js/clients/payments/forte-ach-payment.js" "src": "resources/js/clients/payments/forte-ach-payment.js"
}, },
"resources/js/clients/payments/forte-credit-card-payment.js": { "resources/js/clients/payments/forte-credit-card-payment.js": {
"file": "assets/forte-credit-card-payment-b605ccf2.js", "file": "assets/forte-credit-card-payment-d2571506.js",
"isEntry": true, "isEntry": true,
"src": "resources/js/clients/payments/forte-credit-card-payment.js" "src": "resources/js/clients/payments/forte-credit-card-payment.js"
}, },

View File

@ -41,8 +41,18 @@ class ForteAuthorizeCard {
}; };
successResponseHandler = (response) => { successResponseHandler = (response) => {
document.getElementById('payment_token').value = response.onetime_token; document.getElementById('payment_token').value = response.onetime_token;
document.getElementById('card_brand').value = response.card_type; document.getElementById('card_brand').value = response.card_brand;
document.getElementById('expire_year').value = response.expire_year;
document.getElementById('expire_month').value = response.expire_month;
document.getElementById('last_4').value = response.last_4;
let storeCard = document.querySelector('input[name=token-billing-checkbox]:checked');
if (storeCard) {
document.getElementById("store_card").value = storeCard.value;
}
document.getElementById('server_response').submit(); document.getElementById('server_response').submit();
@ -62,17 +72,94 @@ class ForteAuthorizeCard {
return false; return false;
}; };
handlePayNowAction(token_hashed_id) {
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
document.getElementById("token").value = token_hashed_id;
document.getElementById("server_response").submit();
}
handle = () => { handle = () => {
Array
.from(document.getElementsByClassName('toggle-payment-with-token'))
.forEach((element) => element.addEventListener('click', (e) => {
document
.getElementById('save-card--container').style.display = 'none';
document
.getElementById('forte--credit-card-container').style.display = 'none';
document
.getElementById('token').value = e.target.dataset.token;
}));
let payWithCreditCardToggle = document.getElementById('toggle-payment-with-credit-card');
if (payWithCreditCardToggle) {
payWithCreditCardToggle
.addEventListener('click', () => {
document
.getElementById('save-card--container').style.display = 'grid';
document
.getElementById('forte--credit-card-container').style.display = 'flex';
document
.getElementById('token').value = null;
});
}
let payNowButton = document.getElementById('pay-now'); let payNowButton = document.getElementById('pay-now');
if (payNowButton) { if (payNowButton) {
payNowButton.addEventListener('click', (e) => { payNowButton
this.handleAuthorization(); .addEventListener('click', (e) => {
}); let token = document.getElementById('token');
token.value
? this.handlePayNowAction(token.value)
: this.handleAuthorization();
});
} }
return this; return this;
}; }
} }
const apiLoginId = document.querySelector( const apiLoginId = document.querySelector(

View File

@ -2,6 +2,13 @@
@section('meta_title', ctrans('texts.dashboard')) @section('meta_title', ctrans('texts.dashboard'))
@section('body') @section('body')
@if($client->getSetting('custom_message_dashboard'))
@component('portal.ninja2020.components.message')
<pre>{{ $client->getSetting('custom_message_dashboard') }}</pre>
@endcomponent
@endif
<div class="flex flex-col xl:flex-row gap-4"> <div class="flex flex-col xl:flex-row gap-4">
<div class="w-full rounded-md border border-[#E5E7EB] bg-white p-5 text-sm text-[#6C727F]"> <div class="w-full rounded-md border border-[#E5E7EB] bg-white p-5 text-sm text-[#6C727F]">
<h3 class="mb-4 text-xl font-semibold text-[#212529]">{{ $contact->first_name }} {{ $contact->last_name }}</h3> <h3 class="mb-4 text-xl font-semibold text-[#212529]">{{ $contact->first_name }} {{ $contact->last_name }}</h3>

View File

@ -12,6 +12,9 @@
<form action="{{ route('client.payments.response') }}" method="post" id="server_response"> <form action="{{ route('client.payments.response') }}" method="post" id="server_response">
@csrf @csrf
<input type="hidden" name="card_brand" id="card_brand"> <input type="hidden" name="card_brand" id="card_brand">
<input type="hidden" name="expire_year" id="expire_year">
<input type="hidden" name="expire_month" id="expire_month">
<input type="hidden" name="last_4" id="last_4">
<input type="hidden" name="payment_token" id="payment_token"> <input type="hidden" name="payment_token" id="payment_token">
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}"> <input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}"> <input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
@ -32,10 +35,39 @@
@include('portal.ninja2020.gateways.includes.payment_details') @include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => 'Pay with Credit Card']) @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
@include('portal.ninja2020.gateways.forte.includes.credit_card') <ul class="list-none">
@if(count($tokens) > 0)
@foreach($tokens as $token)
<li class="py-2">
<label class="mr-4 cursor-pointer">
<input
type="radio"
data-token="{{ $token->hashed_id }}"
name="payment-type"
class="form-radio cursor-pointer toggle-payment-with-token"/>
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
</label>
</li>
@endforeach
@endisset
<li class="py-2">
<label class="mr-4 cursor-pointer">
<input
type="radio"
id="toggle-payment-with-credit-card"
class="form-radio cursor-pointer"
name="payment-type"
checked/>
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
</label>
</li>
</ul>
@endcomponent @endcomponent
@include('portal.ninja2020.gateways.includes.save_card')
@include('portal.ninja2020.gateways.forte.includes.credit_card')
@include('portal.ninja2020.gateways.includes.pay_now') @include('portal.ninja2020.gateways.includes.pay_now')
@endsection @endsection

View File

@ -1,5 +1,5 @@
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6" <div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
style="display: flex!important; justify-content: center!important;" id="authorize--credit-card-container"> style="display: flex!important; justify-content: center!important;" id="forte--credit-card-container">
<div class="card-js" id="my-card" data-capture-name="true"> <div class="card-js" id="my-card" data-capture-name="true">
<input class="name" id="cardholder_name" name="card_holders_name" placeholder="{{ ctrans('texts.name')}}"> <input class="name" id="cardholder_name" name="card_holders_name" placeholder="{{ ctrans('texts.name')}}">
<input class="card-number my-custom-class" id="card_number"> <input class="card-number my-custom-class" id="card_number">

View File

@ -51,10 +51,10 @@
@include('portal.ninja2020.gateways.includes.payment_details') @include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
<ul class="list-none hover:list-disc"> <ul class="list-none">
@if(count($tokens) > 0) @if(count($tokens) > 0)
@foreach($tokens as $token) @foreach($tokens as $token)
<li class="py-2 hover:text-blue hover:bg-blue-600"> <li class="py-2 cursor-pointer">
<label class="mr-4"> <label class="mr-4">
<input <input
type="radio" type="radio"
@ -67,7 +67,7 @@
@endforeach @endforeach
@endisset @endisset
<li class="py-2 hover:text-blue hover:bg-blue-600"> <li class="py-2 cursor-pointer">
<label> <label>
<input <input
type="radio" type="radio"

View File

@ -2,6 +2,17 @@
@section('meta_title', ctrans('texts.payment_methods')) @section('meta_title', ctrans('texts.payment_methods'))
@section('body') @section('body')
@section('header')
@if($errors->any())
<div class="alert alert-failure mb-4">
@foreach($errors->all() as $error)
<p>{{ $error }}</p>
@endforeach
</div>
@endif
@endsection
<div class="flex flex-col"> <div class="flex flex-col">
@livewire('payment-methods-table', ['client_id' => $client->id, 'db' => $company->db]) @livewire('payment-methods-table', ['client_id' => $client->id, 'db' => $company->db])
</div> </div>

View File

@ -67,10 +67,8 @@ class PeppolTest extends TestCase
$settings->country_id = '276'; $settings->country_id = '276';
$settings->currency_id = '3'; $settings->currency_id = '3';
$einvoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice(); $einvoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
$fib = new FinancialInstitutionBranch(); $fib = new FinancialInstitutionBranch();
$fib->ID = "DEUTDEMMXXX"; //BIC $fib->ID = "DEUTDEMMXXX"; //BIC
$fib->Name = 'Deutsche Bank'; $fib->Name = 'Deutsche Bank';
@ -88,10 +86,13 @@ class PeppolTest extends TestCase
$pm->PayeeFinancialAccount = $pfa; $pm->PayeeFinancialAccount = $pfa;
$einvoice->PaymentMeans[] = $pm; $einvoice->PaymentMeans[] = $pm;
$stub = new \stdClass;
$stub->Invoice = $einvoice;
$company = Company::factory()->create([ $company = Company::factory()->create([
'account_id' => $this->account->id, 'account_id' => $this->account->id,
'settings' => $settings, 'settings' => $settings,
'e_invoice' => $einvoice, 'e_invoice' => $stub,
]); ]);
$cu = CompanyUserFactory::create($this->user->id, $company->id, $this->account->id); $cu = CompanyUserFactory::create($this->user->id, $company->id, $this->account->id);
@ -149,11 +150,12 @@ class PeppolTest extends TestCase
$this->assertEquals(119, $invoice->amount); $this->assertEquals(119, $invoice->amount);
$peppol = new Peppol($invoice); $peppol = new Peppol($invoice);
$peppol->setInvoiceDefaults(); $peppol->setInvoiceDefaults();
$peppol->run(); $peppol->run();
nlog($peppol->toXml());
$de_invoice = $peppol->getInvoice(); $de_invoice = $peppol->getInvoice();
$this->assertNotNull($de_invoice); $this->assertNotNull($de_invoice);
@ -207,10 +209,14 @@ class PeppolTest extends TestCase
$pm->PayeeFinancialAccount = $pfa; $pm->PayeeFinancialAccount = $pfa;
$einvoice->PaymentMeans[] = $pm; $einvoice->PaymentMeans[] = $pm;
$stub = new \stdClass();
$stub->Invoice = $einvoice;
$company = Company::factory()->create([ $company = Company::factory()->create([
'account_id' => $this->account->id, 'account_id' => $this->account->id,
'settings' => $settings, 'settings' => $settings,
'e_invoice' => $einvoice, 'e_invoice' => $stub,
]); ]);
$cu = CompanyUserFactory::create($this->user->id, $company->id, $this->account->id); $cu = CompanyUserFactory::create($this->user->id, $company->id, $this->account->id);

View File

@ -314,21 +314,23 @@ class ExpenseApiTest extends TestCase
public function testExpenseBulkCategorize() public function testExpenseBulkCategorize()
{ {
$eXX = Expense::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
]);
$e = Expense::factory()->create([ $e = Expense::factory()->create([
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'user_id' => $this->user->id, 'user_id' => $this->user->id,
]); ]);
$ec = ExpenseCategory::factory()->create([ $ec = ExpenseCategory::factory()->create([
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'name' => 'Test Category', 'name' => 'Test Category',
]); ]);
nlog("expense category id = {$ec->hashed_id}");
$data = [ $data = [
'category_id' => $ec->hashed_id, 'category_id' => $ec->hashed_id,
'action' => 'bulk_categorize', 'action' => 'bulk_categorize',
@ -341,11 +343,32 @@ class ExpenseApiTest extends TestCase
])->post('/api/v1/expenses/bulk', $data); ])->post('/api/v1/expenses/bulk', $data);
$arr = $response->json(); $arr = $response->json();
nlog($arr);
$this->assertEquals($ec->hashed_id, $arr['data'][0]['category_id']); $this->assertEquals($ec->hashed_id, $arr['data'][0]['category_id']);
}
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->get("/api/v1/expenses");
$response->assertStatus(200);
$arr = $response->json();
$this->assertGreaterThan(1, count($arr['data']));
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->get("/api/v1/expenses?categories={$ec->hashed_id}");
$response->assertStatus(200);
$arr = $response->json();
$this->assertCount(1, $arr['data']);
}
public function testAddingExpense() public function testAddingExpense()
{ {

View File

@ -69,7 +69,7 @@ class InvoiceEmailTest extends TestCase
$system_log->log = [ $system_log->log = [
'history' => [ 'history' => [
'entity_id' => $this->invoice->hashed_id, 'entity_id' => $this->invoice->hashed_id,
'entity_type' => 'invoice', 'entity' => 'invoice',
'subject' => 'Invoice #1', 'subject' => 'Invoice #1',
'events' => [ 'events' => [
[ [
@ -96,7 +96,7 @@ class InvoiceEmailTest extends TestCase
$arr = $response->json(); $arr = $response->json();
$this->assertEquals('invoice', $arr[0]['entity_type']); $this->assertEquals('invoice', $arr[0]['entity']);
$count = SystemLog::where('client_id', $this->client->id) $count = SystemLog::where('client_id', $this->client->id)
->where('category_id', SystemLog::CATEGORY_MAIL) ->where('category_id', SystemLog::CATEGORY_MAIL)
@ -117,7 +117,7 @@ class InvoiceEmailTest extends TestCase
$system_log->log = [ $system_log->log = [
'history' => [ 'history' => [
'entity_id' => $this->invoice->hashed_id, 'entity_id' => $this->invoice->hashed_id,
'entity_type' => 'invoice', 'entity' => 'invoice',
'subject' => 'Invoice #1', 'subject' => 'Invoice #1',
'events' => [ 'events' => [
[ [
@ -147,8 +147,8 @@ class InvoiceEmailTest extends TestCase
$response->assertStatus(200); $response->assertStatus(200);
$arr = $response->json(); $arr = $response->json();
nlog($arr);
$this->assertEquals('invoice', $arr[0]['entity_type']); $this->assertEquals('invoice', $arr[0]['entity']);
$this->assertEquals($this->invoice->hashed_id, $arr[0]['entity_id']); $this->assertEquals($this->invoice->hashed_id, $arr[0]['entity_id']);
$count = SystemLog::where('company_id', $this->company->id) $count = SystemLog::where('company_id', $this->company->id)

View File

@ -224,6 +224,25 @@ class TaskApiTest extends TestCase
])->postJson("/api/v1/tasks", $data); ])->postJson("/api/v1/tasks", $data);
$response->assertStatus(200); $response->assertStatus(200);
$arr = $response->json();
$data = [
'client_id' => $this->client->hashed_id,
'description' => 'Test Task',
'time_log' => '[""]',
'assigned_user' => [],
'project' => [],
'user' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->putJson("/api/v1/tasks/".$arr['data']['id'], $data);
$response->assertStatus(200);
} }
public function testUserFilters() public function testUserFilters()

View File

@ -28,7 +28,7 @@ class StorecoveTest extends TestCase
use MockAccountData; use MockAccountData;
use DatabaseTransactions; use DatabaseTransactions;
private string $routing_id = ''; private int $routing_id;
protected function setUp(): void protected function setUp(): void
{ {
@ -43,27 +43,27 @@ class StorecoveTest extends TestCase
// public function testCreateLegalEntity() // public function testCreateLegalEntity()
// { // {
// $data = [ // $data = [
// 'acts_as_receiver' => true, // 'acts_as_receiver' => true,
// 'acts_as_sender' => true, // 'acts_as_sender' => true,
// 'advertisements' => ['invoice'], // 'advertisements' => ['invoice'],
// 'city' => $this->company->settings->city, // 'city' => $this->company->settings->city,
// 'country' => 'DE', // 'country' => 'DE',
// 'county' => $this->company->settings->state, // 'county' => $this->company->settings->state,
// 'line1' => $this->company->settings->address1, // 'line1' => $this->company->settings->address1,
// 'line2' => $this->company->settings->address2, // 'line2' => $this->company->settings->address2,
// 'party_name' => $this->company->present()->name(), // 'party_name' => $this->company->present()->name(),
// 'tax_registered' => true, // 'tax_registered' => true,
// 'tenant_id' => $this->company->company_key, // 'tenant_id' => $this->company->company_key,
// 'zip' => $this->company->settings->postal_code, // 'zip' => $this->company->settings->postal_code,
// 'peppol_identifiers' => [ // 'peppol_identifiers' => [
// 'scheme' => 'DE:VAT', // 'scheme' => 'DE:VAT',
// 'id' => 'DE:VAT' // 'id' => 'DE:VAT'
// ], // ],
// ]; // ];
// $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove(); // $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
// $r = $sc->createLegalEntity($data, $this->company); // $r = $sc->createLegalEntity($data, $this->company);
// $this->assertIsArray($r); // $this->assertIsArray($r);
@ -352,11 +352,11 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove(); $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($x); $sc->sendDocument($x, 290868);
} }
*/ */
public function testCreateCHClient() public function XXestCreateCHClient()
{ {
Client::unguard(); Client::unguard();
@ -398,29 +398,29 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
} }
private function createDEData() private function createESData()
{ {
$this->routing_id = 293098;
$this->routing_id = '290868';
$settings = CompanySettings::defaults(); $settings = CompanySettings::defaults();
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png'; $settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
$settings->website = 'www.invoiceninja.de'; $settings->website = 'www.invoiceninja.de';
$settings->address1 = 'Musterstraße 1'; $settings->address1 = 'Calle Gran Vía, 28';
$settings->address2 = 'Etage 2, Büro 3'; $settings->address2 = 'Edificio Telefónica';
$settings->city = 'Berlin'; $settings->city = 'Madrid';
$settings->state = 'Berlin'; $settings->state = 'Madrid';
$settings->postal_code = '10115'; $settings->postal_code = '28013';
$settings->phone = '030 1234567'; $settings->phone = '030 1234567';
$settings->email = $this->faker->unique()->safeEmail(); $settings->email = $this->faker->unique()->safeEmail();
$settings->country_id = '276'; // Germany's ISO country code $settings->country_id = '724'; // Germany's ISO country code
$settings->vat_number = 'DE123456789'; $settings->vat_number = 'ESB16645678';
$settings->id_number = 'HRB 12345'; $settings->id_number = 'HRB 12345';
$settings->use_credits_payment = 'always'; $settings->use_credits_payment = 'always';
$settings->timezone_id = '1'; // CET (Central European Time) $settings->timezone_id = '1'; // CET (Central European Time)
$settings->entity_send_time = 0; $settings->entity_send_time = 0;
$settings->e_invoice_type = 'PEPPOL'; $settings->e_invoice_type = 'PEPPOL';
$settings->currency_id = '3'; $settings->currency_id = '3';
$settings->classification = 'business';
$company = Company::factory()->create([ $company = Company::factory()->create([
'account_id' => $this->account->id, 'account_id' => $this->account->id,
@ -437,76 +437,432 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
'settings' => null, 'settings' => null,
]); ]);
Client::unguard(); Client::unguard();
$c = $c =
Client::create([ Client::create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'name' => 'Beispiel Firma GmbH',
'website' => 'https://www.beispiel-firma.de',
'private_notes' => 'Dies sind private Notizen zum Testkunden.',
'balance' => 0,
'paid_to_date' => 0,
'vat_number' => 'DE654321987',
'id_number' => 'HRB 12345', // Typical format for German company registration numbers
'custom_value1' => '2024-07-22 10:00:00',
'custom_value2' => 'blau',
'custom_value3' => 'musterwort',
'custom_value4' => 'test@example.com',
'address1' => 'Musterstraße 123',
'address2' => '2. Etage, Büro 45',
'city' => 'München',
'state' => 'Bayern',
'postal_code' => '80331',
'country_id' => '276', // Germany
'shipping_address1' => 'Musterstraße 123',
'shipping_address2' => '2. Etage, Büro 45',
'shipping_city' => 'München',
'shipping_state' => 'Bayern',
'shipping_postal_code' => '80331',
'shipping_country_id' => '276', // Germany
'settings' => ClientSettings::Defaults(),
'client_hash' => \Illuminate\Support\Str::random(32),
'routing_id' => '',
]);
$item = new InvoiceItem();
$item->product_key = "Product Key";
$item->notes = "Product Description";
$item->cost = 10;
$item->quantity = 10;
$item->tax_rate1 = 19;
$item->tax_name1 = 'mwst';
$invoice = Invoice::factory()->create([
'company_id' => $company->id, 'company_id' => $company->id,
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'client_id' => $c->id, 'name' => 'Empresa Ejemplo S.A.',
'discount' => 0, 'website' => 'https://www.empresa-ejemplo.es',
'uses_inclusive_taxes' => false, 'private_notes' => 'Estas son notas privadas para el cliente de prueba.',
'status_id' => 1, 'balance' => 0,
'tax_rate1' => 0, 'paid_to_date' => 0,
'tax_name1' => '', 'vat_number' => 'ESB12345678', // Spanish VAT number with ES prefix
'tax_rate2' => 0, 'id_number' => 'B12345678', // Typical format for Spanish company registration numbers
'tax_rate3' => 0, 'custom_value1' => '2024-07-22 10:00:00',
'tax_name2' => '', 'custom_value2' => 'azul', // Spanish for blue
'tax_name3' => '', 'custom_value3' => 'palabraejemplo', // Spanish for sample word
'line_items' => [$item], 'custom_value4' => 'test@ejemplo.com',
'number' => 'DE-'.rand(1000, 100000), 'address1' => 'Calle Ejemplo 123',
'date' => now()->format('Y-m-d') 'address2' => '2ª Planta, Oficina 45',
]); 'city' => 'Madrid',
'state' => 'Madrid',
'postal_code' => '28013',
'country_id' => '724', // Spain
'shipping_address1' => 'Calle Ejemplo 123',
'shipping_address2' => '2ª Planta, Oficina 45',
'shipping_city' => 'Madrid',
'shipping_state' => 'Madrid',
'shipping_postal_code' => '28013',
'shipping_country_id' => '724', // Spain
'settings' => ClientSettings::Defaults(),
'client_hash' => \Illuminate\Support\Str::random(32),
'routing_id' => '',
]);
$invoice = $invoice->calc()->getInvoice(); $item = new InvoiceItem();
$invoice->service()->markSent()->save(); $item->product_key = "Product Key";
$item->notes = "Product Description";
$item->cost = 10;
$item->quantity = 10;
$item->tax_rate1 = 21;
$item->tax_name1 = 'IVA';
$invoice = Invoice::factory()->create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'client_id' => $c->id,
'discount' => 0,
'uses_inclusive_taxes' => false,
'status_id' => 1,
'tax_rate1' => 0,
'tax_name1' => '',
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name2' => '',
'tax_name3' => '',
'line_items' => [$item],
'number' => 'ES-'.rand(1000, 100000),
'date' => now()->format('Y-m-d'),
'due_date' => now()->addDays(14)->format('Y-m-d'),
]);
$invoice = $invoice->calc()->getInvoice();
$invoice->service()->markSent()->save();
return $invoice; return $invoice;
} }
public function testDeRules() private function createFRData()
{
$this->routing_id = 293338;
$settings = CompanySettings::defaults();
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
$settings->website = 'www.invoiceninja.de';
$settings->address1 = '10 Rue de la Paix';
$settings->address2 = 'Bâtiment A, Bureau 5';
$settings->city = 'Paris';
$settings->state = 'Île-de-France';
$settings->postal_code = '75002';
$settings->phone = '01 23456789';
$settings->email = $this->faker->unique()->safeEmail();
$settings->country_id = '250'; // France's ISO country code
$settings->vat_number = 'FR82345678911';
$settings->id_number = '12345678900010';
$settings->classification = 'business';
$settings->use_credits_payment = 'always';
$settings->timezone_id = '1'; // CET (Central European Time)
$settings->entity_send_time = 0;
$settings->e_invoice_type = 'PEPPOL';
$settings->currency_id = '3';
$company = Company::factory()->create([
'account_id' => $this->account->id,
'settings' => $settings,
]);
$this->user->companies()->attach($company->id, [
'account_id' => $this->account->id,
'is_owner' => true,
'is_admin' => 1,
'is_locked' => 0,
'permissions' => '',
'notifications' => CompanySettings::notificationAdminDefaults(),
'settings' => null,
]);
Client::unguard();
$c =
Client::create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'name' => 'Exemple Société S.A.',
'website' => 'https://www.exemple-societe.fr',
'private_notes' => 'Ceci est une note privée pour le client test.',
'balance' => 0,
'paid_to_date' => 0,
'vat_number' => 'FR12345678901',
'id_number' => '12345678900010', // Typical format for French company registration numbers
'custom_value1' => '2024-07-22 10:00:00',
'custom_value2' => 'bleu',
'custom_value3' => 'motexemple',
'custom_value4' => 'test@example.com',
'address1' => '123 Rue de l\'Exemple',
'address2' => '2ème étage, Bureau 45',
'city' => 'Paris',
'state' => 'Île-de-France',
'postal_code' => '75001',
'country_id' => '250', // France
'shipping_address1' => '123 Rue de l\'Exemple',
'shipping_address2' => '2ème étage, Bureau 45',
'shipping_city' => 'Paris',
'shipping_state' => 'Île-de-France',
'shipping_postal_code' => '75001',
'shipping_country_id' => '250', // France
'classification' => 'business',
'settings' => ClientSettings::Defaults(),
'client_hash' => \Illuminate\Support\Str::random(32),
'routing_id' => '',
]);
$item = new InvoiceItem();
$item->product_key = "Product Key";
$item->notes = "Product Description";
$item->cost = 10;
$item->quantity = 10;
$item->tax_rate1 = 20;
$item->tax_name1 = 'VAT';
$invoice = Invoice::factory()->create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'client_id' => $c->id,
'discount' => 0,
'uses_inclusive_taxes' => false,
'status_id' => 1,
'tax_rate1' => 0,
'tax_name1' => '',
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name2' => '',
'tax_name3' => '',
'line_items' => [$item],
'number' => 'DE-'.rand(1000, 100000),
'date' => now()->format('Y-m-d'),
'due_date' => now()->addDays(14)->format('Y-m-d'),
]);
$invoice = $invoice->calc()->getInvoice();
$invoice->service()->markSent()->save();
return $invoice;
}
private function createATData(bool $is_gov = false)
{
$this->routing_id = 293801;
$settings = CompanySettings::defaults();
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
$settings->website = 'www.invoiceninja.at';
$settings->address1 = 'Musterstraße 1';
$settings->address2 = 'Stockwerk 2, Büro 3';
$settings->city = 'Vienna';
$settings->state = 'Vienna';
$settings->postal_code = '1010';
$settings->phone = '+43 1 23456789';
$settings->email = $this->faker->unique()->safeEmail();
$settings->country_id = '40'; // Austria's ISO country code
$settings->vat_number = 'ATU92335648';
$settings->id_number = 'FN 123456x';
$settings->use_credits_payment = 'always';
$settings->timezone_id = '1'; // CET (Central European Time)
$settings->entity_send_time = 0;
$settings->e_invoice_type = 'PEPPOL';
$settings->currency_id = '3';
$company = Company::factory()->create([
'account_id' => $this->account->id,
'settings' => $settings,
]);
$this->user->companies()->attach($company->id, [
'account_id' => $this->account->id,
'is_owner' => true,
'is_admin' => 1,
'is_locked' => 0,
'permissions' => '',
'notifications' => CompanySettings::notificationAdminDefaults(),
'settings' => null,
]);
Client::unguard();
$c =
Client::create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'name' => 'Beispiel Firma GmbH',
'website' => 'https://www.beispiel-firma.at',
'private_notes' => 'Dies sind private Notizen zum Testkunden.',
'balance' => 0,
'paid_to_date' => 0,
'vat_number' => 'ATU87654321',
'id_number' => $is_gov ? 'ATU12312321' : 'FN 123456x', // Example format for Austrian company registration numbers
'custom_value1' => '2024-07-22 10:00:00',
'custom_value2' => 'blau',
'custom_value3' => 'musterwort',
'custom_value4' => 'test@example.com',
'address1' => 'Musterstraße 123',
'address2' => '2. Etage, Büro 45',
'city' => 'Vienna',
'state' => 'Vienna',
'postal_code' => '1010',
'country_id' => '40', // Austria
'shipping_address1' => 'Musterstraße 123',
'shipping_address2' => '2. Etage, Büro 45',
'shipping_city' => 'Vienna',
'shipping_state' => 'Vienna',
'shipping_postal_code' => '1010',
'shipping_country_id' => '40', // Austria
'settings' => ClientSettings::Defaults(),
'client_hash' => \Illuminate\Support\Str::random(32),
'routing_id' => '',
'classification' => $is_gov ? 'government' : 'business',
]);
$item = new InvoiceItem();
$item->product_key = "Product Key";
$item->notes = "Product Description";
$item->cost = 10;
$item->quantity = 10;
$item->tax_rate1 = 20;
$item->tax_name1 = 'VAT';
$invoice = Invoice::factory()->create([
'company_id' => $company->id,
'user_id' => $this->user->id,
'client_id' => $c->id,
'discount' => 0,
'uses_inclusive_taxes' => false,
'status_id' => 1,
'tax_rate1' => 0,
'tax_name1' => '',
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name2' => '',
'tax_name3' => '',
'line_items' => [$item],
'number' => 'DE-'.rand(1000, 100000),
'date' => now()->format('Y-m-d'),
'due_date' => now()->addDays(14)->format('Y-m-d'),
]);
$invoice = $invoice->calc()->getInvoice();
$invoice->service()->markSent()->save();
return $invoice;
}
public function testAtGovernmentRules()
{
$this->routing_id = 293801;
$invoice = $this->createATData(true);
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
foreach($stub as $key => $value) {
$e_invoice->{$key} = $value;
}
$invoice->e_invoice = $e_invoice;
$invoice->save();
$this->assertInstanceOf(Invoice::class, $invoice);
$this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
$p = new Peppol($invoice);
$p->run();
$xml = $p->toXml();
nlog($xml);
$identifiers = $p->getStorecoveMeta();
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml, $this->routing_id, $identifiers);
}
public function PestAtRules()
{
$this->routing_id = 293801;
$invoice = $this->createATData();
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
foreach($stub as $key => $value) {
$e_invoice->{$key} = $value;
}
$invoice->e_invoice = $e_invoice;
$invoice->save();
$this->assertInstanceOf(Invoice::class, $invoice);
$this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
$p = new Peppol($invoice);
$p->run();
$xml = $p->toXml();
nlog($xml);
$identifiers = $p->getStorecoveMeta();
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml, $this->routing_id, $identifiers);
}
public function RestFrRules()
{
$invoice = $this->createFRData();
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
foreach($stub as $key => $value) {
$e_invoice->{$key} = $value;
}
$invoice->e_invoice = $e_invoice;
$invoice->save();
$this->assertInstanceOf(Invoice::class, $invoice);
$this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
$p = new Peppol($invoice);
$p->run();
$xml = $p->toXml();
nlog($xml);
$identifiers = $p->getStorecoveMeta();
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml, $this->routing_id, $identifiers);
}
public function RtestEsRules()
{
$invoice = $this->createESData();
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
foreach($stub as $key => $value) {
$e_invoice->{$key} = $value;
}
$invoice->e_invoice = $e_invoice;
$invoice->save();
$this->assertInstanceOf(Invoice::class, $invoice);
$this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
$p = new Peppol($invoice);
$p->run();
$xml = $p->toXml();
nlog($xml);
$identifiers = [
"routing" => [
"eIdentifiers" => [
[
'scheme' => 'ES:VAT',
'id' => 'ESB53625999'
],
]
]
];
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml, $this->routing_id, $identifiers);
}
public function RtestDeRules()
{ {
$invoice = $this->createDEData(); $invoice = $this->createDEData();
@ -527,8 +883,20 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
$p->run(); $p->run();
$xml = $p->toXml(); $xml = $p->toXml();
nlog($xml); nlog($xml);
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml); $identifiers = [
"routing" => [
"eIdentifiers" => [
[
'scheme' => 'DE:VAT',
'id' => 'DE010101010'
]
]
]
];
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
$sc->sendDocument($xml, $this->routing_id, $identifiers);
} }

View File

@ -13,8 +13,8 @@ export default defineConfig({
rollupOptions: { rollupOptions: {
output: { output: {
// This will output a single bundle file // This will output a single bundle file
entryFileNames: 'bundle.js', entryFileNames: 'bundle.[hash].js',
chunkFileNames: 'bundle.js' chunkFileNames: 'bundle.[hash].js'
} }
}, },
}, },