From fe891a42934bcbd31549f23c079eb03ea1548b49 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 2 Aug 2024 14:44:12 +1000 Subject: [PATCH 01/30] Fixes for Rotessa Import Customers + Payments --- .../Components/Rotessa/AccountComponent.php | 5 +- .../Components/Rotessa/AddressComponent.php | 5 +- .../Components/Rotessa/ContactComponent.php | 4 +- .../Components/RotessaComponents.php | 123 ------------------ app/PaymentDrivers/Rotessa/PaymentMethod.php | 17 +-- app/PaymentDrivers/RotessaPaymentDriver.php | 15 ++- composer.lock | 46 +++---- 7 files changed, 47 insertions(+), 168 deletions(-) delete mode 100644 app/Http/ViewComposers/Components/RotessaComponents.php diff --git a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php index e161b3a1216f..01df934dcf3d 100644 --- a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php @@ -33,10 +33,7 @@ class AccountComponent extends Component "authorization_type" => 'Online' ]; - public array $account; - - public function __construct(array $account) { - $this->account = $account; + public function __construct(public array $account) { $this->attributes = $this->newAttributeBag(Arr::only($this->account, $this->fields) ); } diff --git a/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php b/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php index b26222b18c53..836bbf00ff4f 100644 --- a/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php @@ -25,10 +25,7 @@ class AddressComponent extends Component 'country' => 'US' ]; - public array $address; - - public function __construct(array $address) { - $this->address = $address; + public function __construct(public array $address) { if(strlen($this->address['state']) > 2 ) { $this->address['state'] = $this->address['country'] == 'US' ? array_search($this->address['state'], USStates::$states) : CAProvinces::getAbbreviation($this->address['state']); } diff --git a/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php b/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php index 3557cd05351f..e5419856a6e8 100644 --- a/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php @@ -18,9 +18,9 @@ class ContactComponent extends Component $contact = collect($contact->client->contacts->firstWhere('is_primary', 1)->toArray())->merge([ 'home_phone' =>$contact->client->phone, - 'custom_identifier' => $contact->client->number, + 'custom_identifier' => $contact->client->client_hash, 'name' =>$contact->client->name, - 'id' => $contact->client->contact_key, + 'id' => null, ] )->all(); $this->attributes = $this->newAttributeBag(Arr::only($contact, $this->fields) ); diff --git a/app/Http/ViewComposers/Components/RotessaComponents.php b/app/Http/ViewComposers/Components/RotessaComponents.php deleted file mode 100644 index b984d0bb2339..000000000000 --- a/app/Http/ViewComposers/Components/RotessaComponents.php +++ /dev/null @@ -1,123 +0,0 @@ -client->contacts->firstWhere('is_primary', 1)->toArray())->merge([ - 'home_phone' =>$contact->client->phone, - 'custom_identifier' => $contact->client->number, - 'name' =>$contact->client->name, - 'id' => null - ] )->all(); - - $this->attributes = $this->newAttributeBag(Arr::only($contact, $this->fields) ); - } - - private $fields = [ - 'name', - 'email', - 'home_phone', - 'phone', - 'custom_identifier', - 'customer_type' , - 'id' - ]; - - private $defaults = [ - 'customer_type' => "Business", - 'customer_identifier' => null, - 'id' => null - ]; - - public function render() - { - return render('gateways.rotessa.components.contact', array_merge($this->defaults, $this->attributes->getAttributes() ) ); - } -} - -// Address Component -class AddressComponent extends Component -{ - private $fields = [ - 'address_1', - 'address_2', - 'city', - 'postal_code', - 'province_code', - 'country' - ]; - - private $defaults = [ - 'country' => 'US' - ]; - - public array $address; - - public function __construct(array $address) { - $this->address = $address; - if(strlen($this->address['state']) > 2 ) { - $this->address['state'] = $this->address['country'] == 'US' ? array_search($this->address['state'], USStates::$states) : CAProvinces::getAbbreviation($this->address['state']); - } - - $this->attributes = $this->newAttributeBag( - Arr::only(Arr::mapWithKeys($this->address, function ($item, $key) { - return in_array($key, ['address1','address2','state'])?[ (['address1'=>'address_1','address2'=>'address_2','state'=>'province_code'])[$key] => $item ] :[ $key => $item ]; - }), - $this->fields) ); - } - - - public function render() - { - return render('gateways.rotessa.components.address',array_merge( $this->defaults, $this->attributes->getAttributes() ) ); - } -} - -// AmericanBankInfo Component -class AccountComponent extends Component -{ - private $fields = [ - 'bank_account_type', - 'routing_number', - 'institution_number', - 'transit_number', - 'bank_name', - 'country', - 'account_number' - ]; - - private $defaults = [ - 'bank_account_type' => null, - 'routing_number' => null, - 'institution_number' => null, - 'transit_number' => null, - 'bank_name' => ' ', - 'account_number' => null, - 'country' => 'US', - "authorization_type" => 'Online' - ]; - - public array $account; - - public function __construct(array $account) { - $this->account = $account; - $this->attributes = $this->newAttributeBag(Arr::only($this->account, $this->fields) ); - } - - public function render() - { - return render('gateways.rotessa.components.account', array_merge($this->attributes->getAttributes(), $this->defaults) ); - } -} diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 09717a0da75c..9cb90c7adf0a 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -37,11 +37,9 @@ use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; class PaymentMethod implements MethodInterface { - protected RotessaPaymentDriver $rotessa; - public function __construct(RotessaPaymentDriver $rotessa) + public function __construct(protected RotessaPaymentDriver $rotessa) { - $this->rotessa = $rotessa; $this->rotessa->init(); } @@ -60,9 +58,6 @@ class PaymentMethod implements MethodInterface 'id' => null ] )->all(); $data['gateway'] = $this->rotessa; - // Set gateway type according to client country - // $data['gateway_type_id'] = $data['client']->country->iso_3166_2 == 'US' ? GatewayType::BANK_TRANSFER : ( $data['client']->country->iso_3166_2 == 'CA' ? GatewayType::ACSS : (int) request('method')); - // TODO: detect GatewayType based on client country USA vs CAN $data['gateway_type_id'] = GatewayType::ACSS ; $data['account'] = [ 'routing_number' => $data['client']->routing_id, @@ -104,6 +99,7 @@ class PaymentMethod implements MethodInterface 'customer_id'=>['required_without:custom_identifier','integer'], ]); $customer = new Customer( ['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->resolve()); return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); @@ -142,8 +138,10 @@ class PaymentMethod implements MethodInterface */ public function paymentResponse(PaymentResponseRequest $request) { + $response= null; $customer = null; + try { $request->validate([ 'source' => ['required','string','exists:client_gateway_tokens,token'], @@ -153,17 +151,20 @@ class PaymentMethod implements MethodInterface $customer = ClientGatewayToken::query() ->where('company_gateway_id', $this->rotessa->company_gateway->id) ->where('client_id', $this->rotessa->client->id) + ->where('is_deleted', 0) ->where('token', $request->input('source')) ->first(); + if(!$customer) throw new \Exception('Client gateway token not found!', SystemLog::TYPE_ROTESSA); $transaction = new Transaction($request->only('frequency' ,'installments','amount','process_date') + ['comment' => $this->rotessa->getDescription(false) ]); $transaction->additional(['customer_id' => $customer->gateway_customer_reference]); $transaction = array_filter( $transaction->resolve()); $response = $this->rotessa->gateway->capture($transaction)->send(); + if(!$response->isSuccessful()) throw new \Exception($response->getMessage(), (int) $response->getCode()); - return $this->processPendingPayment($response->getParameter('id'), (float) $response->getParameter('amount'), (int) $customer->gateway_type_id , $customer->token); + return $this->processPendingPayment($response->getParameter('id'), (float) $response->getParameter('amount'), PaymentType::ACSS , $customer->token); } catch(\Throwable $e) { $this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) ); } @@ -194,7 +195,7 @@ class PaymentMethod implements MethodInterface /** * Handle unsuccessful payment for Rotessa. * - * @param Exception $exception + * @param \Exception $exception * @throws PaymentFailed * @return void */ diff --git a/app/PaymentDrivers/RotessaPaymentDriver.php b/app/PaymentDrivers/RotessaPaymentDriver.php index 23915c758c05..585503d16d54 100644 --- a/app/PaymentDrivers/RotessaPaymentDriver.php +++ b/app/PaymentDrivers/RotessaPaymentDriver.php @@ -11,6 +11,7 @@ namespace App\PaymentDrivers; +use App\DataMapper\ClientSettings; use Omnipay\Omnipay; use App\Models\Client; use App\Models\Payment; @@ -183,6 +184,9 @@ class RotessaPaymentDriver extends BaseDriver "updated_at": "2015-02-10T23:50:45.000-06:00" } */ + $settings = ClientSettings::defaults(); + $settings->currency_id = $this->company_gateway->company->getSetting('currency_id'); + $client = (\App\Factory\ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id))->fill( [ 'address1' => $customer->address['address_1'] ?? '', @@ -192,7 +196,8 @@ class RotessaPaymentDriver extends BaseDriver 'state' => $customer->address['province_code'] ?? '', 'country_id' => empty($customer->transit_number) ? 840 : 124, 'routing_id' => empty(($r = $customer->routing_number))? null : $r, - "number" => str_pad($customer->account_number,3,'0',STR_PAD_LEFT) + "number" => str_pad($customer->account_number,3,'0',STR_PAD_LEFT), + "settings" => $settings, ] ); $client->saveQuietly(); @@ -234,8 +239,9 @@ class RotessaPaymentDriver extends BaseDriver $existing = ClientGatewayToken::query() ->where('company_gateway_id', $this->company_gateway->id) ->where('client_id', $this->client->id) + ->where('is_deleted',0) ->orWhere(function (Builder $query) use ($data) { - $query->where('token', encrypt(join(".", Arr::only($data, 'id','custom_identifier'))) ) + $query->where('token', join(".", Arr::only($data, ['id','custom_identifier']))) ->where('gateway_customer_reference', Arr::only($data,'id')); }) ->exists(); @@ -246,14 +252,15 @@ class RotessaPaymentDriver extends BaseDriver $customer = new Customer($result->getData()); $data = array_filter($customer->resolve()); + } // $payment_method_id = Arr::has($data,'address.postal_code') && ((int) $data['address']['postal_code'])? GatewayType::BANK_TRANSFER: GatewayType::ACSS; // TODO: Check/ Validate postal code between USA vs CAN $payment_method_id = GatewayType::ACSS; $gateway_token = $this->storeGatewayToken( [ - 'payment_meta' => $data + ['brand' => 'Rotessa', 'last4' => $data['bank_name'], 'type' => $data['bank_account_type'] ], - 'token' => encrypt(join(".", Arr::only($data, 'id','custom_identifier'))), + 'payment_meta' => $data + ['brand' => 'Bank Transfer', 'last4' => substr($data['account_number'], -4), 'type' => GatewayType::ACSS ], + 'token' => join(".", Arr::only($data, ['id','custom_identifier'])), 'payment_method_id' => $payment_method_id , ], ['gateway_customer_reference' => $data['id'] diff --git a/composer.lock b/composer.lock index fa1c4b178c59..25bf656a3940 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.316.10", + "version": "3.317.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "eeb8df6ff6caa428e8bcd631ad2a96430900a249" + "reference": "6d46c8e00c22f66349b8a509bd2c5ced72cceff2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/eeb8df6ff6caa428e8bcd631ad2a96430900a249", - "reference": "eeb8df6ff6caa428e8bcd631ad2a96430900a249", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6d46c8e00c22f66349b8a509bd2c5ced72cceff2", + "reference": "6d46c8e00c22f66349b8a509bd2c5ced72cceff2", "shasum": "" }, "require": { @@ -624,9 +624,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.316.10" + "source": "https://github.com/aws/aws-sdk-php/tree/3.317.0" }, - "time": "2024-07-30T18:10:20+00:00" + "time": "2024-08-01T18:12:34+00:00" }, { "name": "bacon/bacon-qr-code", @@ -4758,16 +4758,16 @@ }, { "name": "laravel/pint", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "4dba80c1de4b81dc4c4fb10ea6f4781495eb29f5" + "reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/4dba80c1de4b81dc4c4fb10ea6f4781495eb29f5", - "reference": "4dba80c1de4b81dc4c4fb10ea6f4781495eb29f5", + "url": "https://api.github.com/repos/laravel/pint/zipball/b5b6f716db298671c1dfea5b1082ec2c0ae7064f", + "reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f", "shasum": "" }, "require": { @@ -4820,7 +4820,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-07-23T16:40:20+00:00" + "time": "2024-08-01T09:06:33+00:00" }, { "name": "laravel/prompts", @@ -16968,16 +16968,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.8", + "version": "1.11.9", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec" + "reference": "e370bcddadaede0c1716338b262346f40d296f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", - "reference": "6adbd118e6c0515dd2f36b06cde1d6da40f1b8ec", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82", + "reference": "e370bcddadaede0c1716338b262346f40d296f82", "shasum": "" }, "require": { @@ -17022,7 +17022,7 @@ "type": "github" } ], - "time": "2024-07-24T07:01:22+00:00" + "time": "2024-08-01T16:25:18+00:00" }, { "name": "phpunit/php-code-coverage", @@ -19031,16 +19031,16 @@ }, { "name": "spatie/flare-client-php", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/spatie/flare-client-php.git", - "reference": "097040ff51e660e0f6fc863684ac4b02c93fa234" + "reference": "180f8ca4c0d0d6fc51477bd8c53ce37ab5a96122" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/097040ff51e660e0f6fc863684ac4b02c93fa234", - "reference": "097040ff51e660e0f6fc863684ac4b02c93fa234", + "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/180f8ca4c0d0d6fc51477bd8c53ce37ab5a96122", + "reference": "180f8ca4c0d0d6fc51477bd8c53ce37ab5a96122", "shasum": "" }, "require": { @@ -19058,7 +19058,7 @@ "phpstan/extension-installer": "^1.1", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", - "spatie/phpunit-snapshot-assertions": "^4.0|^5.0" + "spatie/pest-plugin-snapshots": "^1.0|^2.0" }, "type": "library", "extra": { @@ -19088,7 +19088,7 @@ ], "support": { "issues": "https://github.com/spatie/flare-client-php/issues", - "source": "https://github.com/spatie/flare-client-php/tree/1.7.0" + "source": "https://github.com/spatie/flare-client-php/tree/1.8.0" }, "funding": [ { @@ -19096,7 +19096,7 @@ "type": "github" } ], - "time": "2024-06-12T14:39:14+00:00" + "time": "2024-08-01T08:27:26+00:00" }, { "name": "spatie/ignition", From dfff9370310a2e3ec04ee8a07a2cc0c32a18791f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 2 Aug 2024 17:11:33 +1000 Subject: [PATCH 02/30] Minor fixes --- app/Jobs/Mailgun/ProcessMailgunWebhook.php | 6 ++++-- app/PaymentDrivers/Rotessa/PaymentMethod.php | 3 +-- app/Providers/RouteServiceProvider.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/Jobs/Mailgun/ProcessMailgunWebhook.php b/app/Jobs/Mailgun/ProcessMailgunWebhook.php index 69be326cd288..b0f1ed65aaac 100644 --- a/app/Jobs/Mailgun/ProcessMailgunWebhook.php +++ b/app/Jobs/Mailgun/ProcessMailgunWebhook.php @@ -94,7 +94,9 @@ class ProcessMailgunWebhook implements ShouldQueue } MultiDB::findAndSetDbByCompanyKey($this->request['event-data']['tags'][0]); - $company = Company::query()->where('company_key', $this->request['event-data']['tags'][0])->first(); + + /** @var \App\Models\Company $company */ + $company = Company::where('company_key', $this->request['event-data']['tags'][0])->first(); if ($company && $this->request['event-data']['event'] == 'complained' && config('ninja.notification.slack')) { $company->notification(new EmailSpamNotification($company))->ninja(); @@ -195,7 +197,7 @@ class ProcessMailgunWebhook implements ShouldQueue 'date' => \Carbon\Carbon::parse($this->request['event-data']['timestamp'])->format('Y-m-d H:i:s') ?? '', ]; - if($sl) { + if($sl instanceof SystemLog) { $data = $sl->log; $data['history']['events'][] = $event; $this->updateSystemLog($sl, $data); diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 9cb90c7adf0a..87c9e2499fb0 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -108,7 +108,7 @@ class PaymentMethod implements MethodInterface return $this->rotessa->processInternallyFailedPayment($this->rotessa, new ClientPortalAuthorizationException( get_class( $e) . " : {$e->getMessage()}", (int) $e->getCode() )); } - return back()->withMessage(ctrans('texts.unable_to_verify_payment_method')); + // return back()->withMessage(ctrans('texts.unable_to_verify_payment_method')); } /** @@ -134,7 +134,6 @@ class PaymentMethod implements MethodInterface * Handle payments page for Rotessa. * * @param PaymentResponseRequest $request - * @return void */ public function paymentResponse(PaymentResponseRequest $request) { diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index ab1b40ca2ed2..8b447788b7be 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -65,7 +65,7 @@ class RouteServiceProvider extends ServiceProvider if (Ninja::isSelfHost()) { return Limit::none(); } else { - return Limit::perMinute(300)->by($request->ip()); + return Limit::perMinute(500)->by($request->ip()); } }); From 83fe0521ca6c70fe03814fc609c257c23158c6fe Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 07:45:37 +1000 Subject: [PATCH 03/30] Update calculations for project duration --- app/Console/Kernel.php | 4 - app/Jobs/Cron/UpdateCalculatedFields.php | 105 ------------------ .../Subscription/CleanStaleInvoiceOrder.php | 2 + app/Models/Task.php | 2 +- app/Observers/TaskObserver.php | 1 + app/PaymentDrivers/BaseDriver.php | 4 - .../src/Omnipay/Rotessa/Http/Client.php | 4 +- app/Repositories/TaskRepository.php | 78 ++++++++++++- 8 files changed, 80 insertions(+), 120 deletions(-) delete mode 100644 app/Jobs/Cron/UpdateCalculatedFields.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 2c1a731228ad..99f6378f3ad5 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -15,7 +15,6 @@ use App\Jobs\Cron\AutoBillCron; use App\Jobs\Cron\RecurringExpensesCron; use App\Jobs\Cron\RecurringInvoicesCron; use App\Jobs\Cron\SubscriptionCron; -use App\Jobs\Cron\UpdateCalculatedFields; use App\Jobs\Invoice\InvoiceCheckLateWebhook; use App\Jobs\Ninja\AdjustEmailQuota; use App\Jobs\Ninja\BankTransactionSync; @@ -68,9 +67,6 @@ class Kernel extends ConsoleKernel /* Stale Invoice Cleanup*/ $schedule->job(new CleanStaleInvoiceOrder())->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); - /* Stale Invoice Cleanup*/ - $schedule->job(new UpdateCalculatedFields())->hourlyAt(40)->withoutOverlapping()->name('update-calculated-fields-job')->onOneServer(); - /* Checks for large companies and marked them as is_large */ $schedule->job(new CompanySizeCheck())->dailyAt('23:20')->withoutOverlapping()->name('company-size-job')->onOneServer(); diff --git a/app/Jobs/Cron/UpdateCalculatedFields.php b/app/Jobs/Cron/UpdateCalculatedFields.php deleted file mode 100644 index 465108c96800..000000000000 --- a/app/Jobs/Cron/UpdateCalculatedFields.php +++ /dev/null @@ -1,105 +0,0 @@ -with('tasks')->whereHas('tasks', function ($query) { - $query->where('updated_at', '>', now()->subHours(2)); - }) - ->cursor() - ->each(function ($project) { - - $project->current_hours = $this->calculateDuration($project); - $project->save(); - }); - - - - } else { - //multiDB environment, need to - foreach (MultiDB::$dbs as $db) { - MultiDB::setDB($db); - - - Project::query()->with('tasks')->whereHas('tasks', function ($query) { - $query->where('updated_at', '>', now()->subHours(2)); - }) - ->cursor() - ->each(function ($project) { - $project->current_hours = $this->calculateDuration($project); - $project->save(); - }); - - //Clean password resets table - \DB::connection($db)->table('password_resets')->where('created_at', '<', now()->subHour())->delete(); - - } - } - } - - private function calculateDuration($project): int - { - $duration = 0; - - $project->tasks->each(function ($task) use (&$duration) { - - if(is_iterable(json_decode($task->time_log))) { - - foreach(json_decode($task->time_log) as $log) { - - if(!is_array($log)) - continue; - - $start_time = $log[0]; - $end_time = $log[1] == 0 ? time() : $log[1]; - - $duration += $end_time - $start_time; - - } - } - - }); - - return (int) round(($duration / 60 / 60), 0); - - } -} diff --git a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php index ddf7ce404856..d8295ed9f54d 100644 --- a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php +++ b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php @@ -95,6 +95,8 @@ class CleanStaleInvoiceOrder implements ShouldQueue ->each(function ($invoice) { $invoice->service()->removeUnpaidGatewayFees(); }); + + \DB::connection($db)->table('password_resets')->where('created_at', '<', now()->subHours(12))->delete(); } } diff --git a/app/Models/Task.php b/app/Models/Task.php index 8479ec26f6f6..0df362e4d529 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -137,7 +137,7 @@ class Task extends BaseModel // 'project', ]; - protected $touches = []; + protected $touches = ['project']; public function getEntityType() { diff --git a/app/Observers/TaskObserver.php b/app/Observers/TaskObserver.php index 96dc353159e8..b9eaf49e5936 100644 --- a/app/Observers/TaskObserver.php +++ b/app/Observers/TaskObserver.php @@ -82,6 +82,7 @@ class TaskObserver if ($subscriptions) { WebhookHandler::dispatch(Webhook::EVENT_ARCHIVE_TASK, $task, $task->company)->delay(0); } + } /** diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 3b134ba355d3..4c7dd2691013 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -586,10 +586,6 @@ class BaseDriver extends AbstractPaymentDriver $invoices = Invoice::query()->whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); - // $invoices->each(function ($invoice) { - // $invoice->service()->deletePdf(); - // }); - $invoices->first()->invitations->each(function ($invitation) use ($nmo) { if ((bool) $invitation->contact->send_email !== false && $invitation->contact->email) { $nmo->to_user = $invitation->contact; diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php index 4c8ea0d29075..1e0abbe8aba0 100644 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php @@ -72,9 +72,9 @@ class Client extends HttpClient $response = $this->httpClient->sendRequest( $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion)); else $response = $this->httpClient->request($method, $uri, compact('body','headers')); } catch (\Http\Client\Exception\NetworkException $networkException) { - throw new NetworkException($networkException->getMessage(), $request, $networkException); + throw new \Exception($networkException->getMessage()); } catch (\Exception $exception) { - throw new RequestException($exception->getMessage(), $request, $exception); + throw new \Exception($exception->getMessage()); } return $response; diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index 0c1e3aeaae9e..ec96ed0670b0 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -46,16 +46,16 @@ class TaskRepository extends BaseRepository $this->new_task = false; } - if(isset($data['assigned_user_id']) && $data['assigned_user_id'] != $task->assigned_user_id){ - TaskAssigned::dispatch($task, $task->company->db)->delay(2); - } - if(!is_numeric($task->rate) && !isset($data['rate'])) $data['rate'] = 0; $task->fill($data); $task->saveQuietly(); + if(isset($data['assigned_user_id']) && $data['assigned_user_id'] != $task->assigned_user_id) { + TaskAssigned::dispatch($task, $task->company->db)->delay(2); + } + $this->init($task); if ($this->new_task && ! $task->status_id) { @@ -155,6 +155,8 @@ class TaskRepository extends BaseRepository $this->saveDocuments($data['documents'], $task); } + $this->calculateProjectDuration($task); + return $task; } @@ -261,6 +263,8 @@ class TaskRepository extends BaseRepository $task->saveQuietly(); } + $this->calculateProjectDuration($task); + return $task; } @@ -302,7 +306,10 @@ class TaskRepository extends BaseRepository $task->saveQuietly(); } + $this->calculateProjectDuration($task); + return $task; + } public function triggeredActions($request, $task) @@ -348,4 +355,67 @@ class TaskRepository extends BaseRepository return $task->number; } + + private function calculateProjectDuration(Task $task) + { + + if($task->project) { + + $duration = 0; + + $task->project->tasks->each(function ($task) use (&$duration) { + + if(is_iterable(json_decode($task->time_log))) { + + foreach(json_decode($task->time_log) as $log) { + + if(!is_array($log)) { + continue; + } + + $start_time = $log[0]; + $end_time = $log[1] == 0 ? time() : $log[1]; + + $duration += $end_time - $start_time; + + } + } + + }); + + $task->project->current_hours = (int) round(($duration / 60 / 60), 0); + $task->push(); + } + } + + /** + * @param $entity + */ + public function restore($task) + { + if (!$task->trashed()) { + return; + } + + parent::restore($task); + + $this->calculateProjectDuration($task); + + } + + /** + * @param $entity + */ + public function delete($task) + { + if ($task->is_deleted) { + return; + } + + parent::delete($task); + + $this->calculateProjectDuration($task); + + } + } From da9e587f67a948ee0ab5740fdbc16377cdc0a378 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 09:36:46 +1000 Subject: [PATCH 04/30] Fixes for api docs + hyperlinks to document downloads in emails --- app/Mail/TemplateEmail.php | 2 +- openapi/api-docs.yaml | 13780 ++++++++-------- openapi/paths.yaml | 28 +- .../views/email/template/client.blade.php | 15 +- 4 files changed, 6940 insertions(+), 6885 deletions(-) diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index 78f45c372d1d..1c5be18e9859 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -65,7 +65,7 @@ class TemplateEmail extends Mailable } $link_string = '
    '; - + $link_string .= "
  • {ctrans('texts.download_files')}
  • "; foreach ($this->build_email->getAttachmentLinks() as $link) { $link_string .= "
  • {$link}
  • "; } diff --git a/openapi/api-docs.yaml b/openapi/api-docs.yaml index e43d4191c3a6..a736d98853be 100644 --- a/openapi/api-docs.yaml +++ b/openapi/api-docs.yaml @@ -1088,7 +1088,7 @@ paths: post: tags: - bank_transactions - summary: "Performs bulk actions on an array of bank_transations" + summary: "Bulk actions" description: "" operationId: bulkBankTransactions parameters: @@ -1132,8 +1132,30 @@ paths: post: tags: - bank_transactions - summary: "Performs match actions on an array of bank_transactions" - description: "" + summary: "Match transactions" + description: | + Matching invoices or a payment to a bank transactions. + + The API expects the id of the transaction along with either a comma separated list of invoice ids OR the payment id to associate the transaction to. + + Example for matching a transaction to two invoices: + + {"transactions":[{"id":"olejRl5ejN","invoice_ids":"JxboYBLegw,JxboYBLeXX"}]} + + Example for matching a transaction and a paymente: + + {"transactions":[{"id":"olejRl5ejN","payment_id":"JxboYBLeXf"}]} + + Matching expenses. + + You can match an existing expense within Invoice Ninja - or - create a new expense using the following: + + {"transactions":[{"id":"open5pld7A","vendor_id":"gl9avJnaG1","ninja_category_id":""}]} + + To match to an existing expense: + + {"transactions":[{"id":"Jxbo2qKagw","expense_id":"7N1aMM1aWm"}]} + operationId: matchBankTransactions parameters: - $ref: "#/components/parameters/X-API-TOKEN" @@ -8608,21 +8630,20 @@ paths: default: $ref: "#/components/responses/default" - /api/v1/vendors: + /api/v1/credits: get: tags: - - vendors - summary: "List vendors" - description: "Lists vendors, search and filters allow fine grained lists to be generated.\n\n Query parameters can be added to performed more fine grained filtering of the vendors, these are handled by the VendorFilters class which defines the methods available" - operationId: getVendors + - credits + summary: "List credits" + description: "Lists credits, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the credits, these are handled by the CreditFilters class which defines the methods available" + operationId: getCredits parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - - $ref: "#/components/parameters/index" responses: 200: - description: "A list of vendors" + description: "A list of credits" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8638,7 +8659,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/Vendor' + $ref: '#/components/schemas/Credit' meta: type: object $ref: '#/components/schemas/Meta' @@ -8656,17 +8677,17 @@ paths: $ref: "#/components/responses/default" post: tags: - - vendors - summary: "Create vendor" - description: "Adds a vendor to a company" - operationId: storeVendor + - credits + summary: "Create credit" + description: "Adds an credit to the system" + operationId: storeCredit parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "Returns the saved clivendorent object" + description: "Returns the saved credit object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8677,7 +8698,374 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/Credit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + + "/api/v1/credits/{id}": + get: + tags: + - credits + summary: "Show credit" + description: "Displays an credit by id" + operationId: showCredit + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Credit Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the credit object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Credit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + put: + tags: + - Credits + summary: "Update credit" + description: "Handles the updating of an Credit by id" + operationId: updateCredit + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Credit Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the Credit object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Credit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + delete: + tags: + - credits + summary: "Delete credit" + description: "Handles the deletion of an credit by id" + operationId: deleteCredit + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Credit Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns a HTTP status" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/credits/{id}/edit": + get: + tags: + - credits + summary: "Edit credit" + description: "Displays an credit by id" + operationId: editCredit + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Invoice Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the credit object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Invoice" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/credits/create: + get: + tags: + - credits + summary: "Blank credit" + description: "Returns a blank object with default values" + operationId: getCreditsCreate + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "A blank credit object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Credit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/credits/bulk: + post: + tags: + - credits + summary: "Bulk credit actions" + description: "" + operationId: bulkCredits + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/index" + requestBody: + description: "User credentials" + required: true + content: + application/json: + schema: + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned" + type: string + example: '[D2J234DFA,D2J234DFA,D2J234DFA]' + responses: + 200: + description: "The Bulk Action response" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/credit/{invitation_key}/download": + get: + tags: + - quotes + summary: "Download quote PDF" + description: "Downloads a specific quote" + operationId: downloadCredit + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: invitation_key + in: path + description: "The Credit Invitation Key" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the credit pdf" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/credits/{id}/upload": + post: + tags: + - credits + summary: "Upload a credit document" + description: "Handles the uploading of a document to a credit" + operationId: uploadCredits + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Credit Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + requestBody: + description: "File Upload Body" + required: true + content: + multipart/form-data: + schema: + type: object + properties: + _method: + type: string + example: PUT + documents: + type: array + items: + description: "Array of binary documents for upload" + type: string + format: binary + responses: + 200: + description: "Returns the Credit object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Credit" 401: $ref: "#/components/responses/401" 403: @@ -8690,28 +9078,103 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/vendors/{id}": + /api/v1/recurring_invoices: get: tags: - - vendors - summary: "Show vendor" - description: "Displays a vendor by id" - operationId: showVendor + - Recurring Invoices + summary: "List recurring invoices" + description: | + Lists invoices with the option to chain multiple query parameters allowing fine grained filtering of the list. + + operationId: getRecurringInvoices parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The vendor Hashed ID" - required: true + - $ref: "#/components/parameters/client_id" + - $ref: "#/components/parameters/created_at" + - $ref: "#/components/parameters/updated_at" + - $ref: "#/components/parameters/is_deleted" + - $ref: "#/components/parameters/filter_deleted_clients" + - $ref: "#/components/parameters/vendor_id" + - name: filter + in: query + description: | + Searches across a range of columns including: + - custom_value1 + - custom_value2 + - custom_value3 + - custom_value4 + required: false schema: type: string - format: string - example: D2J234DFA + example: ?filter=bob + - name: client_status + in: query + description: | + A comma separated list of invoice status strings. Valid options include: + - all + - active + - paused + - completed + required: false + schema: + type: string + example: ?client_status=active,paused + - name: sort + in: query + description: Returns the list sorted by column in ascending or descending order. + required: false + schema: + type: string + example: id|desc number|desc balance|asc responses: 200: - description: "Returns the vendor object" + description: "A list of recurring_invoices" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/RecurringInvoice' + meta: + type: object + $ref: '#/components/schemas/Meta' + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + post: + tags: + - Recurring Invoices + summary: "Create recurring invoice" + description: "Adds a Recurring Invoice to the system" + operationId: storeRecurringInvoice + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "Returns the saved RecurringInvoice object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8722,7 +9185,53 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + + "/api/v1/recurring_invoices/{id}": + get: + tags: + - Recurring Invoices + summary: "Show recurring invoice" + description: "Displays an RecurringInvoice by id" + operationId: showRecurringInvoice + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The RecurringInvoice Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the RecurringInvoice object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/RecurringInvoice" 401: $ref: "#/components/responses/401" 403: @@ -8737,17 +9246,17 @@ paths: $ref: "#/components/responses/default" put: tags: - - vendors - summary: "Update vendor" - description: "Handles the updating of a vendor by id" - operationId: updateVendor + - Recurring Invoices + summary: "Update recurring invoice" + description: "Handles the updating of an RecurringInvoice by id" + operationId: updateRecurringInvoice parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Vendor Hashed ID" + description: "The RecurringInvoice Hashed ID" required: true schema: type: string @@ -8755,7 +9264,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the vendor object" + description: "Returns the RecurringInvoice object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8766,7 +9275,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" 401: $ref: "#/components/responses/401" 403: @@ -8781,17 +9290,17 @@ paths: $ref: "#/components/responses/default" delete: tags: - - vendors - summary: "Delete vendor" - description: "Handles the deletion of a vendor by id" - operationId: deleteVendor + - Recurring Invoices + summary: "Delete recurring invoice" + description: "Handles the deletion of an RecurringInvoice by id" + operationId: deleteRecurringInvoice parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Vendor Hashed ID" + description: "The RecurringInvoice Hashed ID" required: true schema: type: string @@ -8819,20 +9328,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/vendors/{id}/edit": + "/api/v1/recurring_invoices/{id}/edit": get: tags: - - vendors - summary: "Edit vendor" - description: "Displays a vendor by id" - operationId: editVendor + - Recurring Invoices + summary: "Edit recurring invoice" + description: "Displays an RecurringInvoice by id" + operationId: editRecurringInvoice parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Vendor Hashed ID" + description: "The RecurringInvoice Hashed ID" required: true schema: type: string @@ -8840,7 +9349,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the vendor object" + description: "Returns the RecurringInvoice object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8851,7 +9360,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" 401: $ref: "#/components/responses/401" 403: @@ -8864,20 +9373,21 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/vendors/create: + + /api/v1/recurring_invoices/create: get: tags: - - vendors - summary: "Blank vendor" - description: "Returns a blank vendor with default values" - operationId: getVendorsCreate + - Recurring Invoices + summary: "Blank recurring invoice" + description: "Returns a blank object with default values" + operationId: getRecurringInvoicesCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank vendor object" + description: "A blank RecurringInvoice object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8888,7 +9398,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" 401: $ref: "#/components/responses/401" 403: @@ -8901,31 +9411,55 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/vendors/bulk: + /api/v1/recurring_invoices/bulk: post: tags: - - vendors - summary: "Bulk vendor actions" - description: "" - operationId: bulkVendors + - Recurring Invoices + summary: "Bulk recurring invoice actions" + description: | + There are multiple actions that are available including: + + operationId: bulkRecurringInvoices parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: "User credentials" + description: "Bulk action details" required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + type: object + properties: + action: + type: string + description: | + The action to be performed, options include: + - `start` + Starts (or restarts) the recurring invoice. **note** if the recurring invoice has been stopped for a long time, it will attempt to catch back up firing a new Invoice every hour per interval that has been missed. + If you do not wish to have the recurring invoice catch up, you should set the next_send_date to the correct date you wish the recurring invoice to commence from. + - `stop` + Stops the recurring invoice. + - `send_now` + Force sends the recurring invoice - this option is only available when the recurring invoice is in a draft state. + - `restore` + Restores the recurring invoice from an archived or deleted state. + - `archive` + Archives the recurring invoice. The recurring invoice will not fire in this state. + - `delete` + Deletes a recurring invoice. + ids: + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned - ['D2J234DFA','D2J234DFA','D2J234DFA']" + type: string + example: + action: start + ids: "['D2J234DFA','D2J234DFA','D2J234DFA']" responses: 200: - description: "The Vendor User response" + description: "The RecurringInvoice response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8936,7 +9470,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" 401: $ref: "#/components/responses/401" 403: @@ -8949,20 +9483,115 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/vendors/{id}/upload": - post: + "/api/v1/recurring_invoices/{id}/{action}": + get: + deprecated: true tags: - - vendors - summary: "Uploads a vendor document" - description: "Handles the uploading of a document to a vendor" - operationId: uploadVendor + - Recurring Invoices + summary: "Custom recurring invoice action" + description: "Performs a custom action on an RecurringInvoice.\n\n The current range of actions are as follows\n - clone_to_RecurringInvoice\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" + operationId: actionRecurringInvoice parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Vendor Hashed ID" + description: "The RecurringInvoice Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + - name: action + in: path + description: "The action string to be performed" + required: true + schema: + type: string + format: string + example: clone_to_quote + responses: + 200: + description: "Returns the RecurringInvoice object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/RecurringInvoice" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/recurring_invoice/{invitation_key}/download": + get: + tags: + - Recurring Invoices + summary: "Download recurring invoice PDF" + description: "Downloads a specific invoice" + operationId: downloadRecurringInvoice + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: invitation_key + in: path + description: "The Recurring Invoice Invitation Key" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the recurring invoice pdf" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/recurring_invoices/{id}/upload": + post: + tags: + - Recurring Invoices + summary: "Add recurring invoice document" + description: "Handles the uploading of a document to a recurring_invoice" + operationId: uploadRecurringInvoice + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The RecurringInvoice Hashed ID" required: true schema: type: string @@ -8987,7 +9616,7 @@ paths: format: binary responses: 200: - description: "Returns the Vendor object" + description: "Returns the RecurringInvoice object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -8998,7 +9627,989 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Vendor" + $ref: "#/components/schemas/RecurringInvoice" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/tasks: + get: + tags: + - tasks + summary: "List tasks" + description: "Lists tasks, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the tasks, these are handled by the TaskFilters class which defines the methods available" + operationId: getTasks + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - $ref: "#/components/parameters/index" + responses: + 200: + description: "A list of tasks" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Task' + meta: + type: object + $ref: '#/components/schemas/Meta' + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + post: + tags: + - tasks + summary: "Create task" + description: "Adds an task to a company" + operationId: storeTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "Returns the saved task object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/tasks/{id}": + get: + tags: + - tasks + summary: "Show task" + description: "Displays a task by id" + operationId: showTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Task Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the task object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + put: + tags: + - tasks + summary: "Update task" + description: "Handles the updating of a task by id" + operationId: updateTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The task Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the task object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + delete: + tags: + - tasks + summary: "Delete task" + description: "Handles the deletion of a task by id" + operationId: deleteTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Task Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns a HTTP status" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/tasks/{id}/edit": + get: + tags: + - tasks + summary: "Edit task" + description: "Displays a task by id" + operationId: editTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Task Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the client object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/tasks/create: + get: + tags: + - tasks + summary: "Blank task" + description: "Returns a blank task with default values" + operationId: getTasksCreate + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "A blank task object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/tasks/bulk: + post: + tags: + - tasks + summary: "Bulk task actions" + description: "" + operationId: bulkTasks + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/index" + requestBody: + description: "User credentials" + required: true + content: + application/json: + schema: + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned" + type: integer + example: "[0,1,2,3]" + responses: + 200: + description: "The Task User response" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/tasks/{id}/upload": + post: + tags: + - tasks + summary: "Uploads a task document" + description: "Handles the uploading of a document to a task" + operationId: uploadTask + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Task Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + requestBody: + description: "File Upload Body" + required: true + content: + multipart/form-data: + schema: + type: object + properties: + _method: + type: string + example: PUT + documents: + type: array + items: + description: "Array of binary documents for upload" + type: string + format: binary + responses: + 200: + description: "Returns the Task object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Task" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/tasks/sort: + post: + tags: + - tasks + summary: "Sort tasks on KanBan" + description: "Sorts tasks after drag and drop on the KanBan." + operationId: sortTasks + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "Returns an Ok, 200 HTTP status" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/quotes: + get: + tags: + - quotes + summary: "List quotes" + description: "Lists quotes, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters class which defines the methods available" + operationId: getQuotes + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - $ref: "#/components/parameters/status" + - $ref: "#/components/parameters/client_id" + - $ref: "#/components/parameters/created_at" + - $ref: "#/components/parameters/updated_at" + - $ref: "#/components/parameters/is_deleted" + - $ref: "#/components/parameters/filter_deleted_clients" + - $ref: "#/components/parameters/vendor_id" + - name: filter + in: query + description: | + Searches across a range of columns including: + - number + - custom_value1 + - custom_value2 + - custom_value3 + - custom_value4 + required: false + schema: + type: string + example: ?filter=bob + - name: client_status + in: query + description: | + A comma separated list of quote status strings. Valid options include: + - all + - draft + - sent + - approved + - expired + - upcoming + required: false + schema: + type: string + example: ?client_status=paid,unpaid + - name: number + in: query + description: | + Search quote by quote number + required: false + schema: + type: string + example: ?number=Q-001 + - name: sort + in: query + description: Returns the list sorted by column in ascending or descending order. + required: false + schema: + type: string + example: id|desc number|desc balance|asc + responses: + 200: + description: "A list of quotes" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Quote' + meta: + type: object + $ref: '#/components/schemas/Meta' + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + post: + tags: + - quotes + summary: "Create quote" + description: "Adds an Quote to the system" + operationId: storeQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "Returns the saved Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/quotes/{id}": + get: + tags: + - quotes + summary: "Show quote" + description: "Displays an Quote by id" + operationId: showQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + put: + tags: + - quotes + summary: "Update quote" + description: "Handles the updating of an Quote by id" + operationId: updateQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + delete: + tags: + - quotes + summary: "Delete quote" + description: "Handles the deletion of an Quote by id" + operationId: deleteQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns a HTTP status" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/quotes/{id}/edit": + get: + tags: + - quotes + summary: "Edit quote" + description: "Displays an Quote by id" + operationId: editQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/quotes/create: + get: + tags: + - quotes + summary: "Blank quote" + description: "Returns a blank object with default values" + operationId: getQuotesCreate + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + responses: + 200: + description: "A blank Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/quotes/bulk: + post: + tags: + - quotes + summary: "Bulk quote actions" + description: "" + operationId: bulkQuotes + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/index" + requestBody: + description: "Hashed ids" + required: true + content: + application/json: + schema: + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned" + type: integer + example: "[0,1,2,3]" + responses: + 200: + description: "The Quote response" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/quotes/{id}/{action}": + get: + deprecated: true + tags: + - quotes + summary: "Performs a custom action on an Quote" + description: "Performs a custom action on an Quote.\n\n The current range of actions are as follows\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - convert\n - convert_to_invoice\n - email" + operationId: actionQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + - name: action + in: path + description: "The action string to be performed" + required: true + schema: + type: string + format: string + example: clone_to_quote + responses: + 200: + description: "Returns the Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/quote/{invitation_key}/download": + get: + tags: + - quotes + summary: "Download quote PDF" + description: "Downloads a specific quote" + operationId: downloadQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: invitation_key + in: path + description: "The Quote Invitation Key" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the quote pdf" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/quotes/{id}/upload": + post: + tags: + - quotes + summary: "Upload a quote document" + description: "Handles the uploading of a document to a quote" + operationId: uploadQuote + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Quote Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + requestBody: + description: "File Upload Body" + required: true + content: + multipart/form-data: + schema: + type: object + properties: + _method: + type: string + example: PUT + documents: + type: array + items: + description: "Array of binary documents for upload" + type: string + format: binary + responses: + 200: + description: "Returns the Quote object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Quote" 401: $ref: "#/components/responses/401" 403: @@ -9722,20 +11333,21 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/credits: + /api/v1/projects: get: tags: - - credits - summary: "List credits" - description: "Lists credits, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the credits, these are handled by the CreditFilters class which defines the methods available" - operationId: getCredits + - projects + summary: "List projects" + description: "Lists projects" + operationId: getProjects parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" + - $ref: "#/components/parameters/index" responses: 200: - description: "A list of credits" + description: "A list of projects" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -9751,7 +11363,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/Credit' + $ref: '#/components/schemas/Project' meta: type: object $ref: '#/components/schemas/Meta' @@ -9769,17 +11381,17 @@ paths: $ref: "#/components/responses/default" post: tags: - - credits - summary: "Create credit" - description: "Adds an credit to the system" - operationId: storeCredit + - projects + summary: "Create project" + description: "Adds an project to a company" + operationId: storeProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "Returns the saved credit object" + description: "Returns the saved project object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -9790,12 +11402,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Credit" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -9804,21 +11415,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - - "/api/v1/credits/{id}": + "/api/v1/projects/{id}": get: tags: - - credits - summary: "Show credit" - description: "Displays an credit by id" - operationId: showCredit + - projects + summary: "Show project" + description: "Displays a project by id" + operationId: showProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Credit Hashed ID" + description: "The Project Hashed ID" required: true schema: type: string @@ -9826,7 +11436,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the credit object" + description: "Returns the expense object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -9837,12 +11447,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Credit" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -9853,17 +11462,17 @@ paths: $ref: "#/components/responses/default" put: tags: - - Credits - summary: "Update credit" - description: "Handles the updating of an Credit by id" - operationId: updateCredit + - projects + summary: "Update project" + description: "Handles the updating of a project by id" + operationId: updateProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Credit Hashed ID" + description: "The Project Hashed ID" required: true schema: type: string @@ -9871,7 +11480,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the Credit object" + description: "Returns the project object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -9882,12 +11491,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Credit" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -9898,17 +11506,17 @@ paths: $ref: "#/components/responses/default" delete: tags: - - credits - summary: "Delete credit" - description: "Handles the deletion of an credit by id" - operationId: deleteCredit + - projects + summary: "Delete project" + description: "Handles the deletion of a project by id" + operationId: deleteProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Credit Hashed ID" + description: "The Project Hashed ID" required: true schema: type: string @@ -9928,7 +11536,6 @@ paths: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -9937,20 +11544,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/credits/{id}/edit": + "/api/v1/projects/{id}/edit": get: tags: - - credits - summary: "Edit credit" - description: "Displays an credit by id" - operationId: editCredit + - projects + summary: "Edit project" + description: "Displays a project by id" + operationId: editProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Invoice Hashed ID" + description: "The Project Hashed ID" required: true schema: type: string @@ -9958,7 +11565,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the credit object" + description: "Returns the project object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -9969,12 +11576,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Invoice" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -9983,20 +11589,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/credits/create: + /api/v1/projects/create: get: tags: - - credits - summary: "Blank credit" + - projects + summary: "Blank project" description: "Returns a blank object with default values" - operationId: getCreditsCreate + operationId: getProjectsCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank credit object" + description: "A blank project object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10007,12 +11613,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Credit" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -10021,13 +11626,13 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/credits/bulk: + /api/v1/projects/bulk: post: tags: - - credits - summary: "Bulk credit actions" + - projects + summary: "Bulk project actions" description: "" - operationId: bulkCredits + operationId: bulkProjects parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" @@ -10041,11 +11646,11 @@ paths: type: array items: description: "Array of hashed IDs to be bulk 'actioned" - type: string - example: '[D2J234DFA,D2J234DFA,D2J234DFA]' + type: integer + example: "[0,1,2,3]" responses: 200: - description: "The Bulk Action response" + description: "The Project User response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10053,11 +11658,14 @@ paths: $ref: "#/components/headers/X-RateLimit-Remaining" X-RateLimit-Limit: $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: $ref: "#/components/responses/403" - 422: $ref: '#/components/responses/422' 429: @@ -10066,62 +11674,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/credit/{invitation_key}/download": - get: - tags: - - quotes - summary: "Download quote PDF" - description: "Downloads a specific quote" - operationId: downloadCredit - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: invitation_key - in: path - description: "The Credit Invitation Key" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the credit pdf" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/credits/{id}/upload": + "/api/v1/projects/{id}/upload": post: tags: - - credits - summary: "Upload a credit document" - description: "Handles the uploading of a document to a credit" - operationId: uploadCredits + - projects + summary: "Uploads a project document" + description: "Handles the uploading of a document to a project" + operationId: uploadProject parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Credit Hashed ID" + description: "The Project Hashed ID" required: true schema: type: string @@ -10146,7 +11712,7 @@ paths: format: binary responses: 200: - description: "Returns the Credit object" + description: "Returns the Project object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10157,7 +11723,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Credit" + $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: @@ -10170,69 +11736,21 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/products: + /api/v1/vendors: get: tags: - - products - summary: "List products" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X GET 'https://invoicing.co/api/v1/products?filter=search&per_page=20&page=1&include=documents' \ - -H "X-API-TOKEN:company-token-test" \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: go - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $products = $ninja->products->all([ - 'filter' => 'search', - 'per_page' => 20, - 'page' => 1, - 'include' => 'documents' - ]); - description: | - Lists products within your company. - - You can search and filter the result set using query parameters. These can be chained together allowing fine grained lists to be generated. - - operationId: getProducts + - vendors + summary: "List vendors" + description: "Lists vendors, search and filters allow fine grained lists to be generated.\n\n Query parameters can be added to performed more fine grained filtering of the vendors, these are handled by the VendorFilters class which defines the methods available" + operationId: getVendors parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - - $ref: "#/components/parameters/status" - - $ref: "#/components/parameters/client_id" - - $ref: "#/components/parameters/created_at" - - $ref: "#/components/parameters/updated_at" - - $ref: "#/components/parameters/is_deleted" - - $ref: "#/components/parameters/filter_deleted_clients" - - $ref: "#/components/parameters/vendor_id" - - name: filter - in: query - description: Filter by product name - required: false - schema: - type: string - example: bob - - name: product_key - in: query - description: Filter by product key - required: false - schema: - type: string - example: bob - - name: sort - in: query - description: Returns the list sorted by column in ascending or descending order. - required: false - schema: - type: string - example: id|desc product_key|desc + - $ref: "#/components/parameters/index" responses: 200: - description: "A list of products" + description: "A list of vendors" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10248,14 +11766,14 @@ paths: data: type: array items: - $ref: '#/components/schemas/Product' + $ref: '#/components/schemas/Vendor' meta: type: object $ref: '#/components/schemas/Meta' 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10263,46 +11781,20 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' + $ref: "#/components/responses/default" post: tags: - - products - summary: "Create Product" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X POST 'https://invoicing.co/api/v1/products' \ - -H "X-API-TOKEN:company-token-test" \ - -H "Content-Type:application/json" \ - -d '{"product_key":"sku_1","notes":"product description","cost":1,"price":10}' \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: go - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $products = $ninja->products->create([ - 'product_key' => "sku_1", - 'notes' => "product description", - 'cost' => 1, - 'price' => 10 - ]); - description: "Adds a product to a company" - operationId: storeProduct + - vendors + summary: "Create vendor" + description: "Adds a vendor to a company" + operationId: storeVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - requestBody: - description: Product object that needs to be added to the company - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ProductRequest' responses: 200: - description: "Returns the saved product object" + description: "Returns the saved clivendorent object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10313,11 +11805,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10325,33 +11817,21 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - "/api/v1/products/{id}": + $ref: "#/components/responses/default" + "/api/v1/vendors/{id}": get: tags: - - products - summary: "Show product" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X GET 'https://invoicing.co/api/v1/products/{id}' \ - -H "X-API-TOKEN:company-token-test" \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: php - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $product = $ninja->products->get("{id}"); - description: "Displays a product by id" - operationId: showProduct + - vendors + summary: "Show vendor" + description: "Displays a vendor by id" + operationId: showVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Product Hashed ID" + description: "The vendor Hashed ID" required: true schema: type: string @@ -10359,7 +11839,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the product object" + description: "Returns the vendor object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10370,11 +11850,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10382,56 +11862,28 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' + $ref: "#/components/responses/default" put: tags: - - products - summary: "Update product" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X PUT 'https://invoicing.co/api/v1/products/{id}' \ - -H "X-API-TOKEN:company-token-test" \ - -H "Content-Type: application/json" \ - -d '{ - "product_key": "Updated Product", - "price": 150.0, - "notes": "An updated description of the product" - }' - - lang: go - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $product = $ninja->products->update("id", [ - "name" => "Updated Product", - "price" => 150.0, - "description" => "An updated description of the product" - ]); - description: "Handles the updating of a product by id" - operationId: updateProduct + - vendors + summary: "Update vendor" + description: "Handles the updating of a vendor by id" + operationId: updateVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Product Hashed ID" + description: "The Vendor Hashed ID" required: true schema: type: string format: string example: D2J234DFA - requestBody: - description: Product object that needs to be added to the company - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ProductRequest' responses: 200: - description: "Returns the Product object" + description: "Returns the vendor object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10442,11 +11894,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10454,32 +11906,20 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' + $ref: "#/components/responses/default" delete: tags: - - products - summary: "Delete product" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X DELETE 'https://invoicing.co/api/v1/products/{id}' \ - -H "X-API-TOKEN:company-token-test" \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: go - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $ninja->products->bulk("delete", "id"); - description: "Handles the deletion of a product by id" - operationId: deleteProduct + - vendors + summary: "Delete vendor" + description: "Handles the deletion of a vendor by id" + operationId: deleteVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Product Hashed ID" + description: "The Vendor Hashed ID" required: true schema: type: string @@ -10496,9 +11936,9 @@ paths: X-RateLimit-Limit: $ref: "#/components/headers/X-RateLimit-Limit" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10506,33 +11946,21 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - "/api/v1/products/{id}/edit": + $ref: "#/components/responses/default" + "/api/v1/vendors/{id}/edit": get: tags: - - products - summary: "Edit product" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X GET 'https://invoicing.co/api/v1/products/{id}/edit' \ - -H "X-API-TOKEN:company-token-test" \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: php - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $product = $ninja->products->get("{id}"); - description: "Displays an Product by id" - operationId: editProduct + - vendors + summary: "Edit vendor" + description: "Displays a vendor by id" + operationId: editVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Product Hashed ID" + description: "The Vendor Hashed ID" required: true schema: type: string @@ -10540,7 +11968,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the Product object" + description: "Returns the vendor object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10551,11 +11979,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10563,21 +11991,21 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - "/api/v1/products/create": + $ref: "#/components/responses/default" + /api/v1/vendors/create: get: tags: - - products - summary: "Blank product" - description: "Returns a blank product object with default values" - operationId: getProductsCreate + - vendors + summary: "Blank vendor" + description: "Returns a blank vendor with default values" + operationId: getVendorsCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank Product object" + description: "A blank vendor object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10588,11 +12016,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10600,43 +12028,32 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - - /api/v1/products/bulk: + $ref: "#/components/responses/default" + /api/v1/vendors/bulk: post: tags: - - products - summary: "Bulk product actions" - x-code-samples: - - lang: curl - label: Curl - source: | - curl -X GET 'https://invoicing.co/api/v1/products/bulk' \ - -H "Content-Type:application/json" \ - -d '{"action":"archive","ids":["id","id2"]}' \ - -H "X-API-TOKEN:company-token-test" \ - -H "X-Requested-With: XMLHttpRequest"; - - lang: php - label: PHP - source: | - $ninja = new InvoiceNinja("your_token"); - $product = $ninja->products->bulk("action", ["id","id2"]); - description: "Archive / Restore / Delete / Set tax id in bulk" - operationId: bulkProducts + - vendors + summary: "Bulk vendor actions" + description: "" + operationId: bulkVendors parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: 'Bulk action array' + description: "User credentials" required: true content: application/json: schema: - $ref: '#/components/schemas/ProductBulkAction' + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned" + type: integer + example: "[0,1,2,3]" responses: 200: - description: "The Product response" + description: "The Vendor User response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10647,11 +12064,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10659,28 +12076,28 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - - "/api/v1/products/{id}/upload": + $ref: "#/components/responses/default" + "/api/v1/vendors/{id}/upload": post: tags: - - products - summary: "Add product document" - description: "Handles the uploading of a document to a product" - operationId: uploadProduct + - vendors + summary: "Uploads a vendor document" + description: "Handles the uploading of a document to a vendor" + operationId: uploadVendor parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/client_include" + - $ref: "#/components/parameters/include" - name: id in: path - description: "The Product Hashed ID" + description: "The Vendor Hashed ID" required: true schema: type: string format: string example: D2J234DFA requestBody: + description: "File Upload Body" required: true content: multipart/form-data: @@ -10689,14 +12106,16 @@ paths: properties: _method: type: string - example: POST + example: PUT documents: type: array items: + description: "Array of binary documents for upload" + type: string format: binary responses: 200: - description: "Returns the Product object" + description: "Returns the Vendor object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10707,11 +12126,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Product" + $ref: "#/components/schemas/Vendor" 401: - $ref: '#/components/responses/401' + $ref: "#/components/responses/401" 403: - $ref: '#/components/responses/403' + $ref: "#/components/responses/403" 422: $ref: '#/components/responses/422' 429: @@ -10719,15 +12138,14 @@ paths: 5XX: description: 'Server error' default: - $ref: '#/components/responses/default' - - /api/v1/quotes: + $ref: "#/components/responses/default" + /api/v1/payments: get: tags: - - quotes - summary: "List quotes" - description: "Lists quotes, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters class which defines the methods available" - operationId: getQuotes + - payments + summary: "List payments" + description: "Lists payments, search and filters allow fine grained lists to be generated.\n\n Query parameters can be added to performed more fine grained filtering of the payments, these are handled by the PaymentFilters class which defines the methods available" + operationId: getPayments parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" @@ -10743,7 +12161,8 @@ paths: in: query description: | Searches across a range of columns including: - - number + - amount + - date - custom_value1 - custom_value2 - custom_value3 @@ -10751,29 +12170,15 @@ paths: required: false schema: type: string - example: ?filter=bob - - name: client_status - in: query - description: | - A comma separated list of quote status strings. Valid options include: - - all - - draft - - sent - - approved - - expired - - upcoming - required: false - schema: - type: string - example: ?client_status=paid,unpaid + example: ?filter=10 - name: number in: query description: | - Search quote by quote number + Search payments by payment number required: false schema: type: string - example: ?number=Q-001 + example: ?number=0001 - name: sort in: query description: Returns the list sorted by column in ascending or descending order. @@ -10783,7 +12188,7 @@ paths: example: id|desc number|desc balance|asc responses: 200: - description: "A list of quotes" + description: "A list of payments" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -10799,7 +12204,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/Quote' + $ref: '#/components/schemas/Payment' meta: type: object $ref: '#/components/schemas/Meta' @@ -10817,276 +12222,24 @@ paths: $ref: "#/components/responses/default" post: tags: - - quotes - summary: "Create quote" - description: "Adds an Quote to the system" - operationId: storeQuote + - payments + summary: "Create payment" + description: "Adds an Payment to the system" + operationId: storePayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - responses: - 200: - description: "Returns the saved Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/quotes/{id}": - get: - tags: - - quotes - summary: "Show quote" - description: "Displays an Quote by id" - operationId: showQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - put: - tags: - - quotes - summary: "Update quote" - description: "Handles the updating of an Quote by id" - operationId: updateQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - delete: - tags: - - quotes - summary: "Delete quote" - description: "Handles the deletion of an Quote by id" - operationId: deleteQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns a HTTP status" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/quotes/{id}/edit": - get: - tags: - - quotes - summary: "Edit quote" - description: "Displays an Quote by id" - operationId: editQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/quotes/create: - get: - tags: - - quotes - summary: "Blank quote" - description: "Returns a blank object with default values" - operationId: getQuotesCreate - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "A blank Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/quotes/bulk: - post: - tags: - - quotes - summary: "Bulk quote actions" - description: "" - operationId: bulkQuotes - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/index" requestBody: - description: "Hashed ids" + description: "The payment request" required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + $ref: "#/components/schemas/Payment" responses: 200: - description: "The Quote response" + description: "Returns the saved Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11097,245 +12250,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/quotes/{id}/{action}": - get: - deprecated: true - tags: - - quotes - summary: "Performs a custom action on an Quote" - description: "Performs a custom action on an Quote.\n\n The current range of actions are as follows\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - convert\n - convert_to_invoice\n - email" - operationId: actionQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - - name: action - in: path - description: "The action string to be performed" - required: true - schema: - type: string - format: string - example: clone_to_quote - responses: - 200: - description: "Returns the Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/quote/{invitation_key}/download": - get: - tags: - - quotes - summary: "Download quote PDF" - description: "Downloads a specific quote" - operationId: downloadQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: invitation_key - in: path - description: "The Quote Invitation Key" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the quote pdf" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/quotes/{id}/upload": - post: - tags: - - quotes - summary: "Upload a quote document" - description: "Handles the uploading of a document to a quote" - operationId: uploadQuote - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Quote Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - requestBody: - description: "File Upload Body" - required: true - content: - multipart/form-data: - schema: - type: object - properties: - _method: - type: string - example: PUT - documents: - type: array - items: - description: "Array of binary documents for upload" - type: string - format: binary - responses: - 200: - description: "Returns the Quote object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Quote" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/purchase_orders: - get: - tags: - - Purchase Orders - summary: "List purchase orders" - description: "Lists purchase orders, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the purchase orders, these are handled by the PurchaseOrderFilters class which defines the methods available" - operationId: getPurchaseOrders - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "A list of purchase orders" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/PurchaseOrder' - meta: - type: object - $ref: '#/components/schemas/Meta' - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - post: - tags: - - Purchase Orders - summary: "Create purchase order" - description: "Adds an purchase order to the system" - operationId: storePurchaseOrder - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "Returns the saved purchase order object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11349,20 +12264,20 @@ paths: default: $ref: "#/components/responses/default" - "/api/v1/purchase_orders/{id}": + "/api/v1/payments/{id}": get: tags: - - Purchase Orders - summary: "Show purchase order" - description: "Displays an purchase order by id" - operationId: showPurchaseOrder + - payments + summary: "Show payment" + description: "Displays an Payment by id" + operationId: showPayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Purchase order Hashed ID" + description: "The Payment Hashed ID" required: true schema: type: string @@ -11370,7 +12285,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the purchase order object" + description: "Returns the Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11381,7 +12296,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11394,20 +12309,19 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/purchase_order/{id}": put: tags: - - Purchase Orders - summary: "Update purchase order" - description: "Handles the updating of an purchase order by id" - operationId: updatePurchaseOrder + - payments + summary: "Update payment" + description: "Handles the updating of an Payment by id" + operationId: updatePayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The purchase order Hashed ID" + description: "The Payment Hashed ID" required: true schema: type: string @@ -11415,7 +12329,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the purchase order object" + description: "Returns the Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11426,7 +12340,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11441,17 +12355,17 @@ paths: $ref: "#/components/responses/default" delete: tags: - - Purchase Orders - summary: "Delete purchase order" - description: "Handles the deletion of an purchase orders by id" - operationId: deletePurchaseOrder + - payments + summary: "Delete payment" + description: "Handles the deletion of an Payment by id" + operationId: deletePayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The purhcase order Hashed ID" + description: "The Payment Hashed ID" required: true schema: type: string @@ -11479,20 +12393,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/purchase_orders/{id}/edit": + "/api/v1/payments/{id}/edit": get: tags: - - Purchase Orders - summary: "Edit purchase order" - description: "Displays an purchase order by id" - operationId: editPurchaseOrder + - payments + summary: "Edit payment" + description: "Displays an Payment by id" + operationId: editPayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The purchase order Hashed ID" + description: "The Payment Hashed ID" required: true schema: type: string @@ -11500,7 +12414,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the purchase order object" + description: "Returns the Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11511,7 +12425,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11524,21 +12438,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - - /api/v1/purchase_orders/create: + /api/v1/payments/create: get: tags: - - Purchase Orders - summary: "Blank purchase order" + - payments + summary: "Blank payment" description: "Returns a blank object with default values" - operationId: getPurchaseOrderCreate + operationId: getPaymentsCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank purchase order object" + description: "A blank Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11549,7 +12462,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11562,81 +12475,27 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/purchase_orders/bulk: + /api/v1/payments/refund: post: tags: - - Purchase Orders - summary: "Bulk purchase order action" - description: "" - operationId: bulkPurchaseOrderss + - payments + summary: "Refund payment" + description: "Adds an Refund to the system" + operationId: storeRefund parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/index" + - $ref: "#/components/parameters/include" requestBody: - description: "Purchase Order IDS" + description: "The refund request" required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + $ref: "#/components/schemas/Payment" responses: 200: - description: "The Bulk Action response" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/purchase_orders/{id}/{action}": - get: - deprecated: true - tags: - - Purchase Orders - summary: "Custom purchase order actions" - description: "Performs a custom action on an purchase order.\n *\n * The current range of actions are as follows\n * - mark_paid\n * - download\n * - archive\n * - delete\n * - email" - operationId: actionPurchaseOrder - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Purchase Order Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - - name: action - in: path - description: "The action string to be performed" - required: true - schema: - type: string - format: string - example: clone_to_quote - responses: - 200: - description: "Returns the purchase order object" + description: "Returns the saved Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -11647,7 +12506,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/PurchaseOrder" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -11660,409 +12519,13 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/purchase_orders/{id}/upload": + /api/v1/payments/bulk: post: tags: - - Purchase Orders - summary: "Uploads a purchase order document" - description: "Handles the uploading of a document to a purchase_order" - operationId: uploadPurchaseOrder - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Purchase Order Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - requestBody: - description: "File Upload Body" - required: true - content: - multipart/form-data: - schema: - type: object - properties: - _method: - type: string - example: PUT - documents: - type: array - items: - description: "Array of binary documents for upload" - type: string - format: binary - responses: - 200: - description: "Returns the Purchase Order object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/PurchaseOrder" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/purchase_order/{invitation_key}/download": - get: - tags: - - Purchase Orders - summary: "Download a purchase order PDF" - description: "Downloads a specific purchase order" - operationId: downloadPurchaseOrder - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: invitation_key - in: path - description: "The Purchase Order Invitation Key" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the Purchase Order pdf" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/tasks: - get: - tags: - - tasks - summary: "List tasks" - description: "Lists tasks, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the tasks, these are handled by the TaskFilters class which defines the methods available" - operationId: getTasks - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - $ref: "#/components/parameters/index" - responses: - 200: - description: "A list of tasks" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Task' - meta: - type: object - $ref: '#/components/schemas/Meta' - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - post: - tags: - - tasks - summary: "Create task" - description: "Adds an task to a company" - operationId: storeTask - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "Returns the saved task object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/tasks/{id}": - get: - tags: - - tasks - summary: "Show task" - description: "Displays a task by id" - operationId: showTask - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Task Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the task object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - put: - tags: - - tasks - summary: "Update task" - description: "Handles the updating of a task by id" - operationId: updateTask - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The task Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the task object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - delete: - tags: - - tasks - summary: "Delete task" - description: "Handles the deletion of a task by id" - operationId: deleteTask - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Task Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns a HTTP status" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/tasks/{id}/edit": - get: - tags: - - tasks - summary: "Edit task" - description: "Displays a task by id" - operationId: editTask - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Task Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the client object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/tasks/create: - get: - tags: - - tasks - summary: "Blank task" - description: "Returns a blank task with default values" - operationId: getTasksCreate - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "A blank task object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/tasks/bulk: - post: - tags: - - tasks - summary: "Bulk task actions" + - payments + summary: "Bulk payment actions" description: "" - operationId: bulkTasks + operationId: bulkPayments parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" @@ -12080,7 +12543,7 @@ paths: example: "[0,1,2,3]" responses: 200: - description: "The Task User response" + description: "The Payment response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -12091,7 +12554,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Task" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -12104,20 +12567,75 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/tasks/{id}/upload": - post: + "/api/v1/payments/{id}/{action}": + get: + deprecated: true tags: - - tasks - summary: "Uploads a task document" - description: "Handles the uploading of a document to a task" - operationId: uploadTask + - payments + summary: "Custom payment actions" + description: "Performs a custom action on an Payment.\n\n The current range of actions are as follows\n - clone_to_Payment\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" + operationId: actionPayment parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Task Hashed ID" + description: "The Payment Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + - name: action + in: path + description: "The action string to be performed" + required: true + schema: + type: string + format: string + example: clone_to_quote + responses: + 200: + description: "Returns the Payment object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/Payment" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + + "/api/v1/payments/{id}/upload": + post: + tags: + - payments + summary: "Upload a payment document" + description: "Handles the uploading of a document to a payment" + operationId: uploadPayment + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Payment Hashed ID" required: true schema: type: string @@ -12142,7 +12660,7 @@ paths: format: binary responses: 200: - description: "Returns the Task object" + description: "Returns the Payment object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -12153,40 +12671,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Task" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/tasks/sort: - post: - tags: - - tasks - summary: "Sort tasks on KanBan" - description: "Sorts tasks after drag and drop on the KanBan." - operationId: sortTasks - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "Returns an Ok, 200 HTTP status" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" + $ref: "#/components/schemas/Payment" 401: $ref: "#/components/responses/401" 403: @@ -12953,21 +13438,20 @@ paths: description: 'Server error' default: $ref: '#/components/responses/default' - /api/v1/projects: + /api/v1/purchase_orders: get: tags: - - projects - summary: "List projects" - description: "Lists projects" - operationId: getProjects + - Purchase Orders + summary: "List purchase orders" + description: "Lists purchase orders, search and filters allow fine grained lists to be generated.\n *\n * Query parameters can be added to performed more fine grained filtering of the purchase orders, these are handled by the PurchaseOrderFilters class which defines the methods available" + operationId: getPurchaseOrders parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - - $ref: "#/components/parameters/index" responses: 200: - description: "A list of projects" + description: "A list of purchase orders" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -12983,7 +13467,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/Project' + $ref: '#/components/schemas/PurchaseOrder' meta: type: object $ref: '#/components/schemas/Meta' @@ -13001,17 +13485,17 @@ paths: $ref: "#/components/responses/default" post: tags: - - projects - summary: "Create project" - description: "Adds an project to a company" - operationId: storeProject + - Purchase Orders + summary: "Create purchase order" + description: "Adds an purchase order to the system" + operationId: storePurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "Returns the saved project object" + description: "Returns the saved purchase order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13022,7 +13506,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13035,20 +13519,21 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/projects/{id}": + + "/api/v1/purchase_orders/{id}": get: tags: - - projects - summary: "Show project" - description: "Displays a project by id" - operationId: showProject + - Purchase Orders + summary: "Show purchase order" + description: "Displays an purchase order by id" + operationId: showPurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Project Hashed ID" + description: "The Purchase order Hashed ID" required: true schema: type: string @@ -13056,7 +13541,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the expense object" + description: "Returns the purchase order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13067,7 +13552,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13080,19 +13565,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" + "/api/v1/purchase_order/{id}": put: tags: - - projects - summary: "Update project" - description: "Handles the updating of a project by id" - operationId: updateProject + - Purchase Orders + summary: "Update purchase order" + description: "Handles the updating of an purchase order by id" + operationId: updatePurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Project Hashed ID" + description: "The purchase order Hashed ID" required: true schema: type: string @@ -13100,7 +13586,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the project object" + description: "Returns the purchase order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13111,7 +13597,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13126,17 +13612,17 @@ paths: $ref: "#/components/responses/default" delete: tags: - - projects - summary: "Delete project" - description: "Handles the deletion of a project by id" - operationId: deleteProject + - Purchase Orders + summary: "Delete purchase order" + description: "Handles the deletion of an purchase orders by id" + operationId: deletePurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Project Hashed ID" + description: "The purhcase order Hashed ID" required: true schema: type: string @@ -13164,20 +13650,20 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/projects/{id}/edit": + "/api/v1/purchase_orders/{id}/edit": get: tags: - - projects - summary: "Edit project" - description: "Displays a project by id" - operationId: editProject + - Purchase Orders + summary: "Edit purchase order" + description: "Displays an purchase order by id" + operationId: editPurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Project Hashed ID" + description: "The purchase order Hashed ID" required: true schema: type: string @@ -13185,7 +13671,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the project object" + description: "Returns the purchase order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13196,7 +13682,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13209,20 +13695,21 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/projects/create: + + /api/v1/purchase_orders/create: get: tags: - - projects - summary: "Blank project" + - Purchase Orders + summary: "Blank purchase order" description: "Returns a blank object with default values" - operationId: getProjectsCreate + operationId: getPurchaseOrderCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank project object" + description: "A blank purchase order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13233,7 +13720,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13246,19 +13733,19 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/projects/bulk: + /api/v1/purchase_orders/bulk: post: tags: - - projects - summary: "Bulk project actions" + - Purchase Orders + summary: "Bulk purchase order action" description: "" - operationId: bulkProjects + operationId: bulkPurchaseOrderss parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: "User credentials" + description: "Purchase Order IDS" required: true content: application/json: @@ -13270,7 +13757,7 @@ paths: example: "[0,1,2,3]" responses: 200: - description: "The Project User response" + description: "The Bulk Action response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13278,10 +13765,6 @@ paths: $ref: "#/components/headers/X-RateLimit-Remaining" X-RateLimit-Limit: $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Project" 401: $ref: "#/components/responses/401" 403: @@ -13294,20 +13777,74 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - "/api/v1/projects/{id}/upload": - post: + "/api/v1/purchase_orders/{id}/{action}": + get: + deprecated: true tags: - - projects - summary: "Uploads a project document" - description: "Handles the uploading of a document to a project" - operationId: uploadProject + - Purchase Orders + summary: "Custom purchase order actions" + description: "Performs a custom action on an purchase order.\n *\n * The current range of actions are as follows\n * - mark_paid\n * - download\n * - archive\n * - delete\n * - email" + operationId: actionPurchaseOrder parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Project Hashed ID" + description: "The Purchase Order Hashed ID" + required: true + schema: + type: string + format: string + example: D2J234DFA + - name: action + in: path + description: "The action string to be performed" + required: true + schema: + type: string + format: string + example: clone_to_quote + responses: + 200: + description: "Returns the purchase order object" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + content: + application/json: + schema: + $ref: "#/components/schemas/PurchaseOrder" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + "/api/v1/purchase_orders/{id}/upload": + post: + tags: + - Purchase Orders + summary: "Uploads a purchase order document" + description: "Handles the uploading of a document to a purchase_order" + operationId: uploadPurchaseOrder + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: id + in: path + description: "The Purchase Order Hashed ID" required: true schema: type: string @@ -13332,7 +13869,7 @@ paths: format: binary responses: 200: - description: "Returns the Project object" + description: "Returns the Purchase Order object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13343,7 +13880,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Project" + $ref: "#/components/schemas/PurchaseOrder" 401: $ref: "#/components/responses/401" 403: @@ -13356,13 +13893,75 @@ paths: description: 'Server error' default: $ref: "#/components/responses/default" - /api/v1/payments: + "/api/v1/purchase_order/{invitation_key}/download": get: tags: - - payments - summary: "List payments" - description: "Lists payments, search and filters allow fine grained lists to be generated.\n\n Query parameters can be added to performed more fine grained filtering of the payments, these are handled by the PaymentFilters class which defines the methods available" - operationId: getPayments + - Purchase Orders + summary: "Download a purchase order PDF" + description: "Downloads a specific purchase order" + operationId: downloadPurchaseOrder + parameters: + - $ref: "#/components/parameters/X-API-TOKEN" + - $ref: "#/components/parameters/X-Requested-With" + - $ref: "#/components/parameters/include" + - name: invitation_key + in: path + description: "The Purchase Order Invitation Key" + required: true + schema: + type: string + format: string + example: D2J234DFA + responses: + 200: + description: "Returns the Purchase Order pdf" + headers: + X-MINIMUM-CLIENT-VERSION: + $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" + X-RateLimit-Remaining: + $ref: "#/components/headers/X-RateLimit-Remaining" + X-RateLimit-Limit: + $ref: "#/components/headers/X-RateLimit-Limit" + 401: + $ref: "#/components/responses/401" + 403: + $ref: "#/components/responses/403" + 422: + $ref: '#/components/responses/422' + 429: + $ref: '#/components/responses/429' + 5XX: + description: 'Server error' + default: + $ref: "#/components/responses/default" + /api/v1/products: + get: + tags: + - products + summary: "List products" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X GET 'https://invoicing.co/api/v1/products?filter=search&per_page=20&page=1&include=documents' \ + -H "X-API-TOKEN:company-token-test" \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: go + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $products = $ninja->products->all([ + 'filter' => 'search', + 'per_page' => 20, + 'page' => 1, + 'include' => 'documents' + ]); + description: | + Lists products within your company. + + You can search and filter the result set using query parameters. These can be chained together allowing fine grained lists to be generated. + + operationId: getProducts parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" @@ -13376,36 +13975,28 @@ paths: - $ref: "#/components/parameters/vendor_id" - name: filter in: query - description: | - Searches across a range of columns including: - - amount - - date - - custom_value1 - - custom_value2 - - custom_value3 - - custom_value4 + description: Filter by product name required: false schema: type: string - example: ?filter=10 - - name: number + example: bob + - name: product_key in: query - description: | - Search payments by payment number + description: Filter by product key required: false schema: type: string - example: ?number=0001 + example: bob - name: sort in: query description: Returns the list sorted by column in ascending or descending order. required: false schema: type: string - example: id|desc number|desc balance|asc + example: id|desc product_key|desc responses: 200: - description: "A list of payments" + description: "A list of products" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13421,14 +14012,14 @@ paths: data: type: array items: - $ref: '#/components/schemas/Payment' + $ref: '#/components/schemas/Product' meta: type: object $ref: '#/components/schemas/Meta' 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13436,27 +14027,46 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" + $ref: '#/components/responses/default' post: tags: - - payments - summary: "Create payment" - description: "Adds an Payment to the system" - operationId: storePayment + - products + summary: "Create Product" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X POST 'https://invoicing.co/api/v1/products' \ + -H "X-API-TOKEN:company-token-test" \ + -H "Content-Type:application/json" \ + -d '{"product_key":"sku_1","notes":"product description","cost":1,"price":10}' \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: go + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $products = $ninja->products->create([ + 'product_key' => "sku_1", + 'notes' => "product description", + 'cost' => 1, + 'price' => 10 + ]); + description: "Adds a product to a company" + operationId: storeProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" requestBody: - description: "The payment request" + description: Product object that needs to be added to the company required: true content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: '#/components/schemas/ProductRequest' responses: 200: - description: "Returns the saved Payment object" + description: "Returns the saved product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13467,11 +14077,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13479,22 +14089,33 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - - "/api/v1/payments/{id}": + $ref: '#/components/responses/default' + "/api/v1/products/{id}": get: tags: - - payments - summary: "Show payment" - description: "Displays an Payment by id" - operationId: showPayment + - products + summary: "Show product" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X GET 'https://invoicing.co/api/v1/products/{id}' \ + -H "X-API-TOKEN:company-token-test" \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: php + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $product = $ninja->products->get("{id}"); + description: "Displays a product by id" + operationId: showProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Payment Hashed ID" + description: "The Product Hashed ID" required: true schema: type: string @@ -13502,7 +14123,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the Payment object" + description: "Returns the product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13513,11 +14134,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13525,28 +14146,56 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" + $ref: '#/components/responses/default' put: tags: - - payments - summary: "Update payment" - description: "Handles the updating of an Payment by id" - operationId: updatePayment + - products + summary: "Update product" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X PUT 'https://invoicing.co/api/v1/products/{id}' \ + -H "X-API-TOKEN:company-token-test" \ + -H "Content-Type: application/json" \ + -d '{ + "product_key": "Updated Product", + "price": 150.0, + "notes": "An updated description of the product" + }' + - lang: go + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $product = $ninja->products->update("id", [ + "name" => "Updated Product", + "price" => 150.0, + "description" => "An updated description of the product" + ]); + description: "Handles the updating of a product by id" + operationId: updateProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Payment Hashed ID" + description: "The Product Hashed ID" required: true schema: type: string format: string example: D2J234DFA + requestBody: + description: Product object that needs to be added to the company + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProductRequest' responses: 200: - description: "Returns the Payment object" + description: "Returns the Product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13557,11 +14206,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13569,20 +14218,32 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" + $ref: '#/components/responses/default' delete: tags: - - payments - summary: "Delete payment" - description: "Handles the deletion of an Payment by id" - operationId: deletePayment + - products + summary: "Delete product" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X DELETE 'https://invoicing.co/api/v1/products/{id}' \ + -H "X-API-TOKEN:company-token-test" \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: go + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $ninja->products->bulk("delete", "id"); + description: "Handles the deletion of a product by id" + operationId: deleteProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Payment Hashed ID" + description: "The Product Hashed ID" required: true schema: type: string @@ -13599,9 +14260,9 @@ paths: X-RateLimit-Limit: $ref: "#/components/headers/X-RateLimit-Limit" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13609,21 +14270,33 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - "/api/v1/payments/{id}/edit": + $ref: '#/components/responses/default' + "/api/v1/products/{id}/edit": get: tags: - - payments - summary: "Edit payment" - description: "Displays an Payment by id" - operationId: editPayment + - products + summary: "Edit product" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X GET 'https://invoicing.co/api/v1/products/{id}/edit' \ + -H "X-API-TOKEN:company-token-test" \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: php + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $product = $ninja->products->get("{id}"); + description: "Displays an Product by id" + operationId: editProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" - name: id in: path - description: "The Payment Hashed ID" + description: "The Product Hashed ID" required: true schema: type: string @@ -13631,7 +14304,7 @@ paths: example: D2J234DFA responses: 200: - description: "Returns the Payment object" + description: "Returns the Product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13642,11 +14315,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13654,21 +14327,21 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - /api/v1/payments/create: + $ref: '#/components/responses/default' + "/api/v1/products/create": get: tags: - - payments - summary: "Blank payment" - description: "Returns a blank object with default values" - operationId: getPaymentsCreate + - products + summary: "Blank product" + description: "Returns a blank product object with default values" + operationId: getProductsCreate parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/include" responses: 200: - description: "A blank Payment object" + description: "A blank Product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13679,11 +14352,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13691,76 +14364,43 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - /api/v1/payments/refund: + $ref: '#/components/responses/default' + + /api/v1/products/bulk: post: tags: - - payments - summary: "Refund payment" - description: "Adds an Refund to the system" - operationId: storeRefund - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - requestBody: - description: "The refund request" - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/Payment" - responses: - 200: - description: "Returns the saved Payment object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Payment" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/payments/bulk: - post: - tags: - - payments - summary: "Bulk payment actions" - description: "" - operationId: bulkPayments + - products + summary: "Bulk product actions" + x-code-samples: + - lang: curl + label: Curl + source: | + curl -X GET 'https://invoicing.co/api/v1/products/bulk' \ + -H "Content-Type:application/json" \ + -d '{"action":"archive","ids":["id","id2"]}' \ + -H "X-API-TOKEN:company-token-test" \ + -H "X-Requested-With: XMLHttpRequest"; + - lang: php + label: PHP + source: | + $ninja = new InvoiceNinja("your_token"); + $product = $ninja->products->bulk("action", ["id","id2"]); + description: "Archive / Restore / Delete / Set tax id in bulk" + operationId: bulkProducts parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: "User credentials" + description: 'Bulk action array' required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + $ref: '#/components/schemas/ProductBulkAction' responses: 200: - description: "The Payment response" + description: "The Product response" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13771,11 +14411,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13783,83 +14423,28 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - "/api/v1/payments/{id}/{action}": - get: - deprecated: true - tags: - - payments - summary: "Custom payment actions" - description: "Performs a custom action on an Payment.\n\n The current range of actions are as follows\n - clone_to_Payment\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" - operationId: actionPayment - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The Payment Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - - name: action - in: path - description: "The action string to be performed" - required: true - schema: - type: string - format: string - example: clone_to_quote - responses: - 200: - description: "Returns the Payment object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/Payment" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - - "/api/v1/payments/{id}/upload": + $ref: '#/components/responses/default' + + "/api/v1/products/{id}/upload": post: tags: - - payments - summary: "Upload a payment document" - description: "Handles the uploading of a document to a payment" - operationId: uploadPayment + - products + summary: "Add product document" + description: "Handles the uploading of a document to a product" + operationId: uploadProduct parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" + - $ref: "#/components/parameters/client_include" - name: id in: path - description: "The Payment Hashed ID" + description: "The Product Hashed ID" required: true schema: type: string format: string example: D2J234DFA requestBody: - description: "File Upload Body" required: true content: multipart/form-data: @@ -13868,16 +14453,14 @@ paths: properties: _method: type: string - example: PUT + example: POST documents: type: array items: - description: "Array of binary documents for upload" - type: string format: binary responses: 200: - description: "Returns the Payment object" + description: "Returns the Product object" headers: X-MINIMUM-CLIENT-VERSION: $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" @@ -13888,11 +14471,11 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/Payment" + $ref: "#/components/schemas/Product" 401: - $ref: "#/components/responses/401" + $ref: '#/components/responses/401' 403: - $ref: "#/components/responses/403" + $ref: '#/components/responses/403' 422: $ref: '#/components/responses/422' 429: @@ -13900,569 +14483,8 @@ paths: 5XX: description: 'Server error' default: - $ref: "#/components/responses/default" - /api/v1/recurring_invoices: - get: - tags: - - Recurring Invoices - summary: "List recurring invoices" - description: | - Lists invoices with the option to chain multiple query parameters allowing fine grained filtering of the list. + $ref: '#/components/responses/default' - operationId: getRecurringInvoices - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - $ref: "#/components/parameters/client_id" - - $ref: "#/components/parameters/created_at" - - $ref: "#/components/parameters/updated_at" - - $ref: "#/components/parameters/is_deleted" - - $ref: "#/components/parameters/filter_deleted_clients" - - $ref: "#/components/parameters/vendor_id" - - name: filter - in: query - description: | - Searches across a range of columns including: - - custom_value1 - - custom_value2 - - custom_value3 - - custom_value4 - required: false - schema: - type: string - example: ?filter=bob - - name: client_status - in: query - description: | - A comma separated list of invoice status strings. Valid options include: - - all - - active - - paused - - completed - required: false - schema: - type: string - example: ?client_status=active,paused - - name: sort - in: query - description: Returns the list sorted by column in ascending or descending order. - required: false - schema: - type: string - example: id|desc number|desc balance|asc - responses: - 200: - description: "A list of recurring_invoices" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/RecurringInvoice' - meta: - type: object - $ref: '#/components/schemas/Meta' - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - post: - tags: - - Recurring Invoices - summary: "Create recurring invoice" - description: "Adds a Recurring Invoice to the system" - operationId: storeRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "Returns the saved RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - - "/api/v1/recurring_invoices/{id}": - get: - tags: - - Recurring Invoices - summary: "Show recurring invoice" - description: "Displays an RecurringInvoice by id" - operationId: showRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - put: - tags: - - Recurring Invoices - summary: "Update recurring invoice" - description: "Handles the updating of an RecurringInvoice by id" - operationId: updateRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - delete: - tags: - - Recurring Invoices - summary: "Delete recurring invoice" - description: "Handles the deletion of an RecurringInvoice by id" - operationId: deleteRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns a HTTP status" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/recurring_invoices/{id}/edit": - get: - tags: - - Recurring Invoices - summary: "Edit recurring invoice" - description: "Displays an RecurringInvoice by id" - operationId: editRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - - /api/v1/recurring_invoices/create: - get: - tags: - - Recurring Invoices - summary: "Blank recurring invoice" - description: "Returns a blank object with default values" - operationId: getRecurringInvoicesCreate - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - responses: - 200: - description: "A blank RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - /api/v1/recurring_invoices/bulk: - post: - tags: - - Recurring Invoices - summary: "Bulk recurring invoice actions" - description: | - There are multiple actions that are available including: - - operationId: bulkRecurringInvoices - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/index" - requestBody: - description: "Bulk action details" - required: true - content: - application/json: - schema: - type: object - properties: - action: - type: string - description: | - The action to be performed, options include: - - `start` - Starts (or restarts) the recurring invoice. **note** if the recurring invoice has been stopped for a long time, it will attempt to catch back up firing a new Invoice every hour per interval that has been missed. - If you do not wish to have the recurring invoice catch up, you should set the next_send_date to the correct date you wish the recurring invoice to commence from. - - `stop` - Stops the recurring invoice. - - `send_now` - Force sends the recurring invoice - this option is only available when the recurring invoice is in a draft state. - - `restore` - Restores the recurring invoice from an archived or deleted state. - - `archive` - Archives the recurring invoice. The recurring invoice will not fire in this state. - - `delete` - Deletes a recurring invoice. - ids: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned - ['D2J234DFA','D2J234DFA','D2J234DFA']" - type: string - example: - action: start - ids: "['D2J234DFA','D2J234DFA','D2J234DFA']" - responses: - 200: - description: "The RecurringInvoice response" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/recurring_invoices/{id}/{action}": - get: - deprecated: true - tags: - - Recurring Invoices - summary: "Custom recurring invoice action" - description: "Performs a custom action on an RecurringInvoice.\n\n The current range of actions are as follows\n - clone_to_RecurringInvoice\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" - operationId: actionRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - - name: action - in: path - description: "The action string to be performed" - required: true - schema: - type: string - format: string - example: clone_to_quote - responses: - 200: - description: "Returns the RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/recurring_invoice/{invitation_key}/download": - get: - tags: - - Recurring Invoices - summary: "Download recurring invoice PDF" - description: "Downloads a specific invoice" - operationId: downloadRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: invitation_key - in: path - description: "The Recurring Invoice Invitation Key" - required: true - schema: - type: string - format: string - example: D2J234DFA - responses: - 200: - description: "Returns the recurring invoice pdf" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" - "/api/v1/recurring_invoices/{id}/upload": - post: - tags: - - Recurring Invoices - summary: "Add recurring invoice document" - description: "Handles the uploading of a document to a recurring_invoice" - operationId: uploadRecurringInvoice - parameters: - - $ref: "#/components/parameters/X-API-TOKEN" - - $ref: "#/components/parameters/X-Requested-With" - - $ref: "#/components/parameters/include" - - name: id - in: path - description: "The RecurringInvoice Hashed ID" - required: true - schema: - type: string - format: string - example: D2J234DFA - requestBody: - description: "File Upload Body" - required: true - content: - multipart/form-data: - schema: - type: object - properties: - _method: - type: string - example: PUT - documents: - type: array - items: - description: "Array of binary documents for upload" - type: string - format: binary - responses: - 200: - description: "Returns the RecurringInvoice object" - headers: - X-MINIMUM-CLIENT-VERSION: - $ref: "#/components/headers/X-MINIMUM-CLIENT-VERSION" - X-RateLimit-Remaining: - $ref: "#/components/headers/X-RateLimit-Remaining" - X-RateLimit-Limit: - $ref: "#/components/headers/X-RateLimit-Limit" - content: - application/json: - schema: - $ref: "#/components/schemas/RecurringInvoice" - 401: - $ref: "#/components/responses/401" - 403: - $ref: "#/components/responses/403" - 422: - $ref: '#/components/responses/422' - 429: - $ref: '#/components/responses/429' - 5XX: - description: 'Server error' - default: - $ref: "#/components/responses/default" components: headers: X-MINIMUM-CLIENT-VERSION: @@ -14557,43 +14579,43 @@ components: # - prev: null # - next: null responses: - 401: - description: 'Authentication error' - content: - application/json: - schema: - $ref: '#/components/schemas/AuthenticationError' - 422: - description: 'Validation error' - content: - application/json: - schema: - $ref: '#/components/schemas/ValidationError' - - 400: - description: 'Invalid user input' - content: - application/json: - schema: - $ref: '#/components/schemas/InvalidInputError' - 403: - description: 'Authorization error' - content: - application/json: - schema: - $ref: '#/components/schemas/AuthorizationError' - 429: - description: 'Rate Limit Exceeded' - content: - application/json: - schema: - $ref: '#/components/schemas/RateLimiterError' default: description: 'Unexpected Error' content: application/json: schema: $ref: '#/components/schemas/Error' + 429: + description: 'Rate Limit Exceeded' + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimiterError' + 400: + description: 'Invalid user input' + content: + application/json: + schema: + $ref: '#/components/schemas/InvalidInputError' + + 401: + description: 'Authentication error' + content: + application/json: + schema: + $ref: '#/components/schemas/AuthenticationError' + 403: + description: 'Authorization error' + content: + application/json: + schema: + $ref: '#/components/schemas/AuthorizationError' + 422: + description: 'Validation error' + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' parameters: X-API-SECRET: name: X-API-SECRET @@ -15177,322 +15199,42 @@ components: type: string example: JSON type: object - User: + Meta: properties: - id: - description: 'The hashed id of the user' - type: string - example: Opnel5aKBz - readOnly: true - first_name: - description: 'The first name of the user' - type: string - example: Brad - last_name: - description: 'The last name of the user' - type: string - example: Pitt - email: - description: 'The users email address' - type: string - example: brad@pitt.com - phone: - description: 'The users phone number' - type: string - example: 555-1233-23232 - signature: - description: 'The users sign off signature' - type: string - example: 'Have a nice day!' - avatar: - description: 'The users avatar' - type: string - example: 'https://url.to.your/avatar.png' - accepted_terms_version: - description: 'The version of the invoice ninja terms that has been accepted by the user' - type: string - example: 1.0.1 - readOnly: true - oauth_user_id: - description: 'The provider id of the oauth entity' - type: string - example: jkhasdf789as6f675sdf768sdfs - readOnly: true - oauth_provider_id: - description: 'The oauth entity id' - type: string - example: google - readOnly: true - language_id: - description: 'The language id of the user' - type: string - example: 1 - verified_phone_number: - description: 'Boolean flag if the user has their phone verified. Required to settings up 2FA' - type: boolean - example: true - readOnly: true - sms_verification_code: - description: 'The sms verification code for the user. Required to settings up 2FA' - type: string - example: '123456' - readOnly: true - oauth_user_token_expiry: - description: 'The expiry date of the oauth token' - type: string - example: '2022-10-10' - readOnly: true - has_password: - description: 'Boolean flag determining if the user has a password' - type: boolean - example: true - readOnly: true - last_confirmed_email_address: - description: 'The last confirmed email address of the user' - type: string - example: 'bob@gmail.com' - readOnly: true - custom_value1: - description: 'A custom value' - type: string - example: 'Custom value 1' - custom_value2: - description: 'A custom value' - type: string - example: '$1000' - custom_value3: - description: 'A custom value' - type: string - example: 'Custom value 3' - custom_value4: - description: 'A custom value' - type: string - example: 'Custom value 4' - is_deleted: - description: 'Boolean flag determining if the user has been deleted' - type: boolean - example: true - readOnly: true - google_2fa_secret: - description: 'The google 2fa secret for the user' - type: string - example: '123456' - readOnly: true - company_user: - $ref: '#/components/schemas/CompanyUserRef' + pagination: + $ref: '#/components/schemas/Pagination' + Pagination: type: object - UserRef: properties: - id: - description: 'The hashed id of the user' - type: string - example: Opnel5aKBz - readOnly: true - first_name: - description: 'The first name of the user' - type: string - example: Brad - last_name: - description: 'The last name of the user' - type: string - example: Pitt - email: - description: 'The users email address' - type: string - example: brad@pitt.com - phone: - description: 'The users phone number' - type: string - example: 555-1233-23232 - signature: - description: 'The users sign off signature' - type: string - example: 'Have a nice day!' - avatar: - description: 'The users avatar' - type: string - example: 'https://url.to.your/avatar.png' - accepted_terms_version: - description: 'The version of the invoice ninja terms that has been accepted by the user' - type: string - example: 1.0.1 - readOnly: true - oauth_user_id: - description: 'The provider id of the oauth entity' - type: string - example: jkhasdf789as6f675sdf768sdfs - readOnly: true - oauth_provider_id: - description: 'The oauth entity id' - type: string - example: google - readOnly: true - language_id: - description: 'The language id of the user' - type: string - example: 1 - verified_phone_number: - description: 'Boolean flag if the user has their phone verified. Required to settings up 2FA' - type: boolean - example: true - readOnly: true - sms_verification_code: - description: 'The sms verification code for the user. Required to settings up 2FA' - type: string - example: '123456' - readOnly: true - oauth_user_token_expiry: - description: 'The expiry date of the oauth token' - type: string - example: '2022-10-10' - readOnly: true - has_password: - description: 'Boolean flag determining if the user has a password' - type: boolean - example: true - readOnly: true - last_confirmed_email_address: - description: 'The last confirmed email address of the user' - type: string - example: 'bob@gmail.com' - readOnly: true - custom_value1: - description: 'A custom value' - type: string - example: 'Custom value 1' - custom_value2: - description: 'A custom value' - type: string - example: '$1000' - custom_value3: - description: 'A custom value' - type: string - example: 'Custom value 3' - custom_value4: - description: 'A custom value' - type: string - example: 'Custom value 4' - is_deleted: - description: 'Boolean flag determining if the user has been deleted' - type: boolean - example: true - readOnly: true - google_2fa_secret: - description: 'The google 2fa secret for the user' - type: string - example: '123456' - readOnly: true - type: object - Task: - properties: - id: - description: 'The hashed id of the task' - type: string - example: Opnel5aKBz - user_id: - description: 'The hashed id of the user who created the task' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The assigned user of the task' - type: string - example: Opnel5aKBz - client_id: - description: 'The hashed if of the client' - type: string - example: Opnel5aKBz - invoice_id: - description: 'The hashed id of the invoice associated with the task' - type: string - example: Opnel5aKBz - project_id: - description: 'The hashed id of the project associated with the task' - type: string - example: Opnel5aKBz - number: - description: 'The number of the task' - type: string - example: TASK-123 - time_log: - description: 'An array of unix time stamps defining the start and end times of the task' - type: string - example: '[[1,2],[3,4]]' - is_running: - description: 'Determines if the task is still running' - type: boolean - example: true - is_deleted: - description: 'Boolean flag determining if the task has been deleted' - type: boolean - example: true - task_status_id: - description: 'The hashed id of the task status' - type: string - example: Opnel5aKBz - description: - description: 'The task description' - type: string - example: 'A wonder task to work on' - duration: - description: 'The task duration in seconds' + total: type: integer - example: '3600' - task_status_order: - description: 'The order of the task' + description: 'The total number of items' + example: 1 + readOnly: true + count: type: integer - example: '4' - rate: - description: 'The task rate' - type: number - example: 10.00 - custom_value1: - description: 'A custom value' - type: string - example: '2022-10-10' - custom_value2: - description: 'A custom value' - type: string - example: $1100 - custom_value3: - description: 'A custom value' - type: string - example: 'I need help' - custom_value4: - description: 'A custom value' - type: string - example: INV-3343 - is_date_based: - description: 'Boolean flag determining if the task is date based' - type: boolean - example: true - calculated_start_date: - description: 'The calculated start date of the task' - type: string - example: '2022-10-10' + description: 'The number of items per page' + example: 1 readOnly: true - invoice_documents: - description: "Boolean flags which determines whether to include the task documents on the invoice" - type: boolean - example: true - created_at: - description: Timestamp - type: number - format: integer - example: '1434342123' + per_page: + type: integer + description: 'The number of items per page' + example: 1 readOnly: true - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' + current_page: + type: integer + description: 'The current page number' + example: 1 readOnly: true - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' + total_pages: + type: integer + description: 'The total number of pages' + example: 1 + readOnly: true + links: + type: object + description: 'The pagination links' readOnly: true - type: object Document: properties: id: @@ -15563,674 +15305,16 @@ components: format: integer example: '134341234234' type: object - ClientGatewayToken: + Error: properties: - id: - description: 'The hashed id of the client gateway token' + message: + description: 'Something terrible went wrong' type: string - example: Opnel5aKBz - client_id: - description: 'The hashed_id of the client' - type: string - example: '2' - token: - description: 'The payment token' - type: string - example: '2' - routing_number: - description: 'THe bank account routing number' - type: string - example: '2' - company_gateway_id: - description: 'The hashed id of the company gateway' - type: string - example: '2' - is_default: - description: 'Flag determining if the token is the default payment method' - type: boolean - example: 'true' - type: object - Invoice: - properties: - id: - description: 'The invoice hashed id' - type: string - example: Opnel5aKBz - readOnly: true - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - readOnly: true - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - status_id: - description: 'The invoice status variable' - type: string - example: '4' - number: - description: 'The invoice number - is a unique alpha numeric number per invoice per company' - type: string - example: INV_101 - po_number: - description: 'The purchase order associated with this invoice' - type: string - example: PO-1234 - terms: - description: 'The invoice terms' - type: string - example: 'These are invoice terms' - public_notes: - description: 'The public notes of the invoice' - type: string - example: 'These are some public notes' - private_notes: - description: 'The private notes of the invoice' - type: string - example: 'These are some private notes' - footer: - description: 'The invoice footer notes' - type: string - example: '' - custom_value1: - description: 'A custom field value' - type: string - example: '2022-10-01' - custom_value2: - description: 'A custom field value' - type: string - example: 'Something custom' - custom_value3: - description: 'A custom field value' - type: string - example: '' - custom_value4: - description: 'A custom field value' - type: string - example: '' - tax_name1: - description: 'The tax name' - type: string - example: '' - tax_name2: - description: 'The tax name' - type: string - example: '' - tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_name3: - description: 'The tax name' - type: string - example: '' - tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '10.00' - total_taxes: - description: 'The total taxes for the invoice' - type: number - format: float - example: '10.00' - line_items: - type: array - description: 'An array of objects which define the line items of the invoice' - items: - $ref: '#/components/schemas/InvoiceItem' - invitations: - type: array - description: 'An array of objects which define the invitations of the invoice' - items: - $ref: '#/components/schemas/InvoiceInvitation' - amount: - description: 'The invoice amount' - type: number - format: float - example: '10.00' - balance: - description: 'The invoice balance' - type: number - format: float - example: '10.00' - paid_to_date: - description: 'The amount paid on the invoice to date' - type: number - format: float - example: '10.00' - discount: - description: 'The invoice discount, can be an amount or a percentage' - type: number - format: float - example: '10.00' - partial: - description: 'The deposit/partial amount' - type: number - format: float - example: '10.00' - is_amount_discount: - description: 'Flag determining if the discount is an amount or a percentage' - type: boolean - example: true - is_deleted: - description: 'Defines if the invoice has been deleted' - type: boolean - example: true - uses_inclusive_taxes: - description: 'Defines the type of taxes used as either inclusive or exclusive' - type: boolean - example: true - date: - description: 'The Invoice Date' - type: string - format: date - example: '1994-07-30' - last_sent_date: - description: 'The last date the invoice was sent out' - type: string - format: date - example: '1994-07-30' - next_send_date: - description: 'The Next date for a reminder to be sent' - type: string - format: date - example: '1994-07-30' - partial_due_date: - description: 'The due date for the deposit/partial amount' - type: string - format: date - example: '1994-07-30' - due_date: - description: 'The due date of the invoice' - type: string - format: date - example: '1994-07-30' - last_viewed: - description: Timestamp - type: number - format: integer - example: '1434342123' - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - custom_surcharge1: - description: 'First Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge2: - description: 'Second Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge3: - description: 'Third Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge4: - description: 'Fourth Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge_tax1: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax2: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax3: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax4: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - project_id: - description: 'The project associated with this invoice' - type: string - example: Opnel5aKBz - auto_bill_tries: - description: 'The number of times the invoice has attempted to be auto billed' + example: 'Unexpected error' + code: + description: 'The HTTP error code, ie 5xx 4xx' type: integer - example: '1' - readOnly: true - auto_bill_enabled: - description: 'Boolean flag determining if the invoice is set to auto bill' - type: boolean - example: true - subscription_id: - description: 'The subscription associated with this invoice' - type: string - example: Opnel5aKBz - - type: object - FillableInvoice: - properties: - assigned_user_id: - description: "The assigned user's hashed ID" - type: string - example: 'a1b2c3d4' - client_id: - description: "The client's hashed ID" - type: string - example: 'x1y2z3a4' - number: - description: "The unique alphanumeric invoice number for each invoice per company" - type: string - example: INV_101 - po_number: - description: "The purchase order number associated with the invoice" - type: string - example: 'PO12345' - terms: - description: "The terms and conditions for the invoice" - type: string - example: 'Net 30' - public_notes: - description: "Public notes visible to the client on the invoice" - type: string - example: 'Thank you for your business.' - private_notes: - description: "Private notes for internal use only" - type: string - example: 'Client is a slow payer.' - footer: - description: "The footer text displayed on the invoice" - type: string - example: 'Authorized Signature' - custom_value1: - description: "First custom value for additional information" - type: string - example: 'Project ABC' - custom_value2: - description: "Second custom value for additional information" - type: string - example: 'Department XYZ' - custom_value3: - description: "Third custom value for additional information" - type: string - example: 'Location 123' - custom_value4: - description: "Fourth custom value for additional information" - type: string - example: 'Currency USD' - tax_name1: - description: "Name of the first tax applied to the invoice" - type: string - example: 'VAT' - tax_name2: - description: "Name of the second tax applied to the invoice" - type: string - example: 'GST' - tax_rate1: - description: "Rate of the first tax applied to the invoice" - type: number - example: 10.00 - tax_rate2: - description: "Rate of the second tax applied to the invoice" - type: number - example: 5.00 - tax_name3: - description: "Name of the third tax applied to the invoice" - type: string - example: 'PST' - tax_rate3: - description: "Rate of the third tax applied to the invoice" - type: number - example: 8.00 - line_items: - type: array - description: 'An array of objects which define the line items of the invoice' - items: - $ref: '#/components/schemas/InvoiceItem' - discount: - description: "The discount applied to the invoice" - type: number - example: 10.00 - partial: - description: "The partial amount applied to the invoice" - type: number - example: 20.00 - is_amount_discount: - description: "Indicates whether the discount applied is a fixed amount or a percentage" - type: boolean - example: true - uses_inclusive_taxes: - description: "Indicates whether the tax rates applied to the invoice are inclusive or exclusive" - type: boolean - example: true - date: - description: "The date the invoice was issued" - type: string - example: '1994-07-30' - partial_due_date: - description: "The due date for the partial payment" - type: string - example: '1994-08-15' - due_date: - description: "The due date for the invoice" - type: string - example: '1994-08-30' - custom_surcharge1: - description: "First custom surcharge applied to the invoice" - type: number - example: 10.00 - custom_surcharge2: - description: "Second custom surcharge applied to the invoice" - type: number - example: 15.00 - custom_surcharge3: - description: "Third custom surcharge applied to the invoice" - type: number - example: 5.00 - custom_surcharge4: - description: "Fourth custom surcharge applied to the invoice" - type: number - example: 20.00 - type: object - CompanyGateway: - properties: - id: - description: 'The hashed id of the company gateway' - type: string - example: Opnel5aKBz - gateway_key: - description: 'The gateway key (hash)' - type: string - example: '2' - accepted_credit_cards: - description: 'Bitmask representation of cards' - type: integer - example: '32' - require_billing_address: - description: 'Determines if the the billing address is required prior to payment.' - type: boolean - example: true - require_shipping_address: - description: 'Determines if the the billing address is required prior to payment.' - type: boolean - example: true - config: - description: 'The configuration map for the gateway' - type: string - example: dfadsfdsafsafd - update_details: - description: 'Determines if the client details should be updated.' - type: boolean - example: true - fees_and_limits: - description: 'A mapped collection of the fees and limits for the configured gateway' - type: array - items: - $ref: '#/components/schemas/FeesAndLimits' - type: object - - - InvoiceInvitation: - properties: - id: - description: 'The entity invitation hashed id' - type: string - example: Opnel5aKBz - readOnly: true - client_contact_id: - description: 'The client contact hashed id' - type: string - example: Opnel5aKBz - key: - description: 'The invitation key' - type: string - example: Opnel5aKBz4343343566236gvbb - readOnly: true - link: - description: 'The invitation link' - type: string - example: 'https://www.example.com/invitations/Opnel5aKBz4343343566236gvbb' - readOnly: true - sent_date: - description: 'The invitation sent date' - type: string - format: date-time - readOnly: true - viewed_date: - description: 'The invitation viewed date' - type: string - format: date-time - readOnly: true - opened_date: - description: 'The invitation opened date' - type: string - format: date-time - readOnly: true - updated_at: - description: 'Timestamp' - type: number - format: integer - example: '1434342123' - readOnly: true - archived_at: - description: 'Timestamp' - type: number - format: integer - example: '1434342123' - readOnly: true - email_error: - description: 'The email error' - type: string - example: 'The email error' - readOnly: true - email_status: - description: 'The email status' - type: string - readOnly: true - - Account: - properties: - id: - description: 'The account hashed id' - type: string - example: AS3df3A - account_sms_verified: - description: 'Boolean flag if the account has been verified by sms' - type: string - example: true - type: object - ExpenseCategory: - properties: - id: - description: 'The expense hashed id' - type: string - example: Opnel5aKBz - name: - description: 'The expense category name' - type: string - example: Accounting - user_id: - description: 'The user hashed id' - type: string - example: XS987sD - is_deleted: - description: 'Flag determining whether the expense category has been deleted' - type: boolean - example: true - updated_at: - description: 'The updated at timestamp' - type: integer - example: '2' - created_at: - description: 'The created at timestamp' - type: integer - example: '2' - type: object - Subscription: - properties: - id: - description: Unique identifier for the subscription - type: string - example: Opnel5aKBz - user_id: - description: Unique identifier for the user associated with the subscription - type: string - example: Ua6Rw4pVbS - product_id: - description: Unique identifier for the product associated with the subscription - type: string - example: Pr5Ft7yBmC - recurring_invoice_id: - description: Unique identifier for the recurring invoice associated with the subscription - type: string - example: Ri2Yt8zJkP - is_recurring: - description: Indicates whether the subscription is recurring - type: boolean - example: 'true' - frequency_id: - description: 'integer const representation of the frequency' - type: string - example: '1' - auto_bill: - description: 'enum setting' - type: string - example: always - promo_code: - description: Promotional code applied to the subscription - type: string - example: PROMOCODE4U - promo_discount: - description: Discount percentage or amount applied to the subscription - type: number - example: 10 - is_amount_discount: - description: Indicates whether the discount is a fixed amount - type: boolean - example: 'true' - allow_cancellation: - description: Indicates whether the subscription can be cancelled - type: boolean - example: 'true' - per_seat_enabled: - description: Indicates whether the subscription pricing is per seat - type: boolean - example: 'true' - currency_id: - description: Unique identifier for the currency used in the subscription - type: integer - example: '1' - max_seats_limit: - description: Maximum number of seats allowed for the subscription - type: integer - example: '100' - trial_enabled: - description: Indicates whether the subscription has a trial period - type: boolean - example: 'true' - trial_duration: - description: Duration of the trial period in days - type: integer - example: '14' - allow_query_overrides: - description: Indicates whether query overrides are allowed for the subscription - type: boolean - example: 'true' - allow_plan_changes: - description: Indicates whether plan changes are allowed for the subscription - type: boolean - example: 'true' - refund_period: - description: Number of days within which refunds can be requested - type: integer - example: '30' - webhook_configuration: - description: Webhook configuration for the subscription - type: string - example: 'expand reference for this' - is_deleted: - description: Indicates whether the subscription has been deleted - type: boolean - example: 'false' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - created_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - updated_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - type: object - BulkAction: - type: array - items: - type: integer - example: '[0,1,2,3,]' - SystemLog: - properties: - id: - description: 'The account hashed id' - type: string - example: AS3df3A - user_id: - description: 'The user_id hashed id' - type: string - example: AS3df3A - client_id: - description: 'The client_id hashed id' - type: string - example: AS3df3A - event_id: - description: 'The Log Type ID' - type: integer - example: 1 - category_id: - description: 'The Category Type ID' - type: integer - example: 1 - type_id: - description: 'The Type Type ID' - type: integer - example: 1 - log: - description: 'The json object of the error' - type: object - example: '{''key'':''value''}' - updated_at: - description: Timestamp - type: string - example: '2' - created_at: - description: Timestamp - type: string - example: '2' + example: '500' type: object InvoiceItem: type: object @@ -16348,6 +15432,954 @@ components: example: '1' default: '1' description: 'The tax ID of the product: 1 product, 2 service, 3 digital, 4 shipping, 5 exempt, 5 reduced tax, 7 override, 8 zero rate, 9 reverse tax' + ExpenseCategory: + properties: + id: + description: 'The expense hashed id' + type: string + example: Opnel5aKBz + name: + description: 'The expense category name' + type: string + example: Accounting + user_id: + description: 'The user hashed id' + type: string + example: XS987sD + is_deleted: + description: 'Flag determining whether the expense category has been deleted' + type: boolean + example: true + updated_at: + description: 'The updated at timestamp' + type: integer + example: '2' + created_at: + description: 'The created at timestamp' + type: integer + example: '2' + type: object + Client: + properties: + id: + description: 'The unique identifier of the client' + type: string + example: Opnel5aKBz + readOnly: true + contacts: + type: array + items: + $ref: '#/components/schemas/ClientContact' + user_id: + description: 'The unique identifier of the user who created the client' + type: string + example: Ua6Rw4pVbS + readOnly: true + assigned_user_id: + description: 'The unique identifier of the user who has been assigned the client' + type: string + example: Ua6Rw4pVbS + name: + description: 'The name of the client company or organization' + type: string + example: "Jim's Housekeeping" + website: + description: 'The website URL of the client company or organization' + type: string + example: 'https://www.jims-housekeeping.com' + private_notes: + description: 'Notes that are only visible to the user who created the client' + type: string + example: 'Client prefers email communication over phone calls' + client_hash: + description: 'A unique hash value for the client' + type: string + example: asdfkjhk342hjhbfdvmnfb1 + readOnly: true + industry_id: + description: 'The unique identifier of the industry the client operates in' + type: number + example: '5' + size_id: + description: 'The unique identifier for the size category of the client company or organization' + type: number + example: '2' + address1: + description: "First line of the client's address" + type: string + example: '123 Main St' + address2: + description: "Second line of the client's address, if needed" + type: string + example: 'Apt 4B' + city: + description: 'The city the client is located in' + type: string + example: 'Beverly Hills' + state: + description: 'The state, province, or locality the client is located in' + type: string + example: 'California' + postal_code: + description: 'The postal code or ZIP code of the client' + type: string + example: '90210' + phone: + description: "The client's phone number" + type: string + example: '555-3434-3434' + country_id: + description: "The unique identifier of the client's country" + type: number + format: integer + example: '1' + custom_value1: + description: 'A custom field for storing additional information' + type: string + example: 'Preferred contact: Email' + custom_value2: + description: 'A custom field for storing additional information' + type: string + example: 'Account manager: John Doe' + custom_value3: + description: 'A custom field for storing additional information' + type: string + example: 'VIP client: Yes' + custom_value4: + description: 'A custom field for storing additional information' + type: string + example: 'Annual contract value: $50,000' + vat_number: + description: "The client's VAT (Value Added Tax) number, if applicable" + type: string + example: 'VAT123456' + id_number: + description: 'A unique identification number for the client, such as a tax ID or business registration number' + type: string + number: + description: 'A system-assigned unique number for the client, typically used for invoicing purposes' + type: string + example: 'CL-0001' + shipping_address1: + description: "First line of the client's shipping address" + type: string + example: '5 Wallaby Way' + shipping_address2: + description: "Second line of the client's shipping address, if needed" + type: string + example: 'Suite 5' + shipping_city: + description: "The city of the client's shipping address" + type: string + example: 'Perth' + shipping_state: + description: "The state, province, or locality of the client's shipping address" + type: string + example: 'Western Australia' + shipping_postal_code: + description: "The postal code or ZIP code of the client's shipping address" + type: string + example: '6110' + shipping_country_id: + description: "The unique identifier of the country for the client's shipping address" + type: number + format: integer + example: '4' + is_deleted: + description: 'A boolean value indicating whether the client has been deleted or not' + type: boolean + example: false + readOnly: true + balance: + description: 'The outstanding balance the client owes' + type: number + format: float + example: '500.00' + readOnly: true + paid_to_date: + description: 'The total amount the client has paid to date' + type: number + format: float + example: '2000.00' + readOnly: true + credit_balance: + description: 'The available credit balance for the client to use on future purchases' + type: number + format: float + example: '100.00' + readOnly: true + last_login: + description: "The timestamp of the client's last login" + type: number + format: integer + example: '1628686031' + readOnly: true + created_at: + description: 'The timestamp when the client was created' + type: number + format: integer + example: '1617629031' + readOnly: true + updated_at: + description: 'The timestamp when the client was last updated' + type: number + format: integer + example: '1628445631' + readOnly: true + group_settings_id: + description: 'The group settings assigned to the client' + type: string + example: Opnel5aKBz + routing_id: + description: 'The routing address id for e-invoicing for this client' + type: string + example: Opnel5aKBz3489-dfkiu-2239-sdsd + is_tax_exempt: + description: 'Flag which defines if the client is exempt from taxes' + type: boolean + example: false + has_valid_vat_number: + description: 'Flag which defines if the client has a valid VAT number' + type: boolean + example: false + readOnly: true + payment_balance: + description: 'Defines the payment balance the client has on file (pre payments / over payments / unapplied amounts)' + type: number + example: 100 + readOnly: true + settings: + $ref: '#/components/schemas/ClientSettings' + type: object + Quote: + properties: + id: + description: 'The unique hashed identifier for the quote' + type: string + example: Opnel5aKBz + user_id: + description: 'The unique hashed identifier for the user who created the quote' + type: string + example: '' + assigned_user_id: + description: 'The unique hashed identifier for the user assigned to the quote' + type: string + example: '' + client_id: + description: 'The unique hashed identifier for the client associated with the quote' + type: string + example: '' + status_id: + description: 'The status of the quote represented by a unique identifier' + type: string + example: '' + number: + description: 'The unique alpha-numeric quote number for the quote per company' + type: string + example: QUOTE_101 + po_number: + description: 'The purchase order number associated with the quote' + type: string + example: PO-1234 + terms: + description: 'The terms and conditions for the quote' + type: string + example: 'These are some quote terms. Valid for 14 days.' + public_notes: + description: 'Publicly visible notes associated with the quote' + type: string + example: 'These are public notes which the client may see' + private_notes: + description: 'Privately visible notes associated with the quote, not disclosed to the client' + type: string + example: 'These are private notes, not to be disclosed to the client' + footer: + description: 'The footer text of the quote' + type: string + example: 'The text goes in the footer of the quote' + custom_value1: + description: 'First custom value field for additional information' + type: string + example: 'A custom value' + custom_value2: + description: 'Second custom value field for additional information' + type: string + example: 'A custom value' + custom_value3: + description: 'Third custom value field for additional information' + type: string + example: 'A custom value' + custom_value4: + description: 'Fourth custom value field for additional information' + type: string + example: 'A custom value' + tax_name1: + description: 'The name of the first tax applied to the quote' + type: string + example: GST + tax_name2: + description: 'The name of the second tax applied to the quote' + type: string + example: VAT + tax_rate1: + description: 'The rate of the first tax applied to the quote' + type: number + format: float + example: 10.00 + tax_rate2: + description: 'The rate of the second tax applied to the quote' + type: number + format: float + example: 10.00 + tax_name3: + description: 'The name of the third tax applied to the quote' + type: string + example: '' + tax_rate3: + description: 'The rate of the third tax applied to the quote' + type: number + format: float + example: 10.00 + total_taxes: + description: 'The total amount of taxes for the quote' + type: number + format: float + example: 10.00 + line_items: + type: array + description: 'An array of objects which define the line items of the quote' + items: + $ref: '#/components/schemas/InvoiceItem' + amount: + description: 'The total amount of the quote before taxes and discounts' + type: number + format: float + example: 10.00 + balance: + description: 'The balance due for the quote after accounting for payments' + type: number + format: float + example: 10.00 + paid_to_date: + description: 'The total amount paid on the quote so far' + type: number + format: float + example: 10.00 + discount: + description: 'The discount amount or percentage applied to the quote' + type: number + format: float + example: 10.00 + partial: + description: 'The partial or deposit amount for the quote' + type: number + format: float + example: 10.00 + is_amount_discount: + description: 'Boolean flag indicating if the discount is a fixed amount or a percentage' + type: boolean + example: true + is_deleted: + description: 'Boolean flag indicating if the quote has been deleted' + type: boolean + example: false + uses_inclusive_taxes: + description: 'Boolean flag indicating if the taxes used are inclusive or exclusive' + type: boolean + example: true + date: + description: 'The date the quote was created' + type: string + format: date + example: '1994-07-30' + last_sent_date: + description: 'The last date the quote was sent to the client' + type: string + format: date + example: '1994-07-30' + next_send_date: + description: 'The next scheduled date for sending a reminder for the quote' + type: string + format: date + example: '1994-07-30' + partial_due_date: + description: 'The due date for the partial or deposit amount' + type: string + format: date + example: '1994-07-30' + due_date: + description: 'The due date for the total amount of the quote' + type: string + format: date + example: '1994-07-30' + settings: + $ref: '#/components/schemas/CompanySettings' + last_viewed: + description: 'The timestamp of the last time the quote was viewed' + type: number + format: integer + example: 1434342123 + updated_at: + description: 'The timestamp of the last update to the quote' + type: number + format: integer + example: 1434342123 + archived_at: + description: 'The timestamp of when the quote was archived' + type: number + format: integer + example: 1434342123 + custom_surcharge1: + description: 'First custom surcharge amount for the quote' + type: number + format: float + example: 10.00 + custom_surcharge2: + description: 'Second custom surcharge amount for the quote' + type: number + format: float + example: 10.00 + custom_surcharge3: + description: 'Third custom surcharge amount for the quote' + type: number + format: float + example: 10.00 + custom_surcharge4: + description: 'Fourth custom surcharge amount for the quote' + type: number + format: float + example: 10.00 + custom_surcharge_tax1: + description: 'Boolean flag indicating if taxes are charged on the first custom surcharge amount' + type: boolean + example: true + custom_surcharge_tax2: + description: 'Boolean flag indicating if taxes are charged on the second custom surcharge amount' + type: boolean + example: true + custom_surcharge_tax3: + description: 'Boolean flag indicating if taxes are charged on the third custom surcharge amount' + type: boolean + example: true + custom_surcharge_tax4: + description: 'Boolean flag indicating if taxes are charged on the fourth custom surcharge amount' + type: boolean + example: true + type: object + InvoiceRequest: + required: + - client_id + properties: + id: + description: 'The invoice hashed id' + type: string + example: Opnel5aKBz + readOnly: true + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The assigned user hashed id' + type: string + example: Opnel5aKBz + client_id: + description: 'The client hashed id' + type: string + example: Opnel5aKBz + status_id: + description: 'The invoice status variable' + type: string + example: '4' + readOnly: true + number: + description: 'The invoice number - is a unique alpha numeric number per invoice per company' + type: string + example: INV_101 + po_number: + description: 'The purchase order associated with this invoice' + type: string + example: PO-1234 + terms: + description: 'The invoice terms' + type: string + example: 'These are invoice terms' + public_notes: + description: 'The public notes of the invoice' + type: string + example: 'These are some public notes' + private_notes: + description: 'The private notes of the invoice' + type: string + example: 'These are some private notes' + footer: + description: 'The invoice footer notes' + type: string + example: '' + custom_value1: + description: 'A custom field value' + type: string + example: '2022-10-01' + custom_value2: + description: 'A custom field value' + type: string + example: 'Something custom' + custom_value3: + description: 'A custom field value' + type: string + example: '' + custom_value4: + description: 'A custom field value' + type: string + example: '' + tax_name1: + description: 'The tax name' + type: string + example: '' + tax_name2: + description: 'The tax name' + type: string + example: '' + tax_rate1: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_rate2: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_name3: + description: 'The tax name' + type: string + example: '' + tax_rate3: + description: 'The tax rate' + type: number + format: float + example: '10.00' + total_taxes: + description: 'The total taxes for the invoice' + type: number + format: float + example: '10.00' + readOnly: true + line_items: + type: array + description: 'An array of objects which define the line items of the invoice' + items: + $ref: '#/components/schemas/InvoiceItem' + invitations: + type: array + description: 'An array of objects which define the invitations of the invoice' + items: + $ref: '#/components/schemas/InvoiceInvitationRequest' + amount: + description: 'The invoice amount' + type: number + format: float + example: '10.00' + readOnly: true + balance: + description: 'The invoice balance' + type: number + format: float + example: '10.00' + readOnly: true + paid_to_date: + description: 'The amount paid on the invoice to date' + type: number + format: float + example: '10.00' + readOnly: true + discount: + description: 'The invoice discount, can be an amount or a percentage' + type: number + format: float + example: '10.00' + partial: + description: 'The deposit/partial amount' + type: number + format: float + example: '10.00' + is_amount_discount: + description: 'Flag determining if the discount is an amount or a percentage' + type: boolean + example: true + is_deleted: + description: 'Defines if the invoice has been deleted' + type: boolean + example: true + readOnly: true + uses_inclusive_taxes: + description: 'Defines the type of taxes used as either inclusive or exclusive' + type: boolean + example: true + date: + description: 'The Invoice Date' + type: string + format: date + example: '1994-07-30' + last_sent_date: + description: 'The last date the invoice was sent out' + type: string + format: date + example: '1994-07-30' + readOnly: true + next_send_date: + description: 'The Next date for a reminder to be sent' + type: string + format: date + example: '1994-07-30' + readOnly: true + partial_due_date: + description: 'The due date for the deposit/partial amount' + type: string + format: date + example: '1994-07-30' + due_date: + description: 'The due date of the invoice' + type: string + format: date + example: '1994-07-30' + last_viewed: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + custom_surcharge1: + description: 'First Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge2: + description: 'Second Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge3: + description: 'Third Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge4: + description: 'Fourth Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge_tax1: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax2: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax3: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax4: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + project_id: + description: 'The project associated with this invoice' + type: string + example: Opnel5aKBz + type: object + ProductRequest: + type: object + properties: + id: + type: string + description: 'The hashed product ID.' + example: eP01N + readOnly: true + assigned_user_id: + type: string + description: 'The hashed ID of the user assigned to this product.' + example: pR0j3 + + project_id: + type: string + description: 'The hashed ID of the project that this product is associated with.' + example: pR0j3 + + vendor_id: + type: string + description: 'The hashed ID of the vendor that this product is associated with.' + example: pR0j3 + + custom_value1: + type: string + description: 'Custom value field 1.' + example: 'Custom value 1' + + custom_value2: + type: string + description: 'Custom value field 2.' + example: 'Custom value 2' + + custom_value3: + type: string + description: 'Custom value field 3.' + example: 'Custom value 3' + + custom_value4: + type: string + description: 'Custom value field 4.' + example: 'Custom value 4' + + product_key: + type: string + description: 'The product key.' + example: '1234' + + notes: + type: string + description: 'Notes about the product.' + example: 'These are some notes about the product.' + + cost: + type: number + format: double + description: 'The cost of the product.' + example: 10.0 + + price: + type: number + format: double + description: 'The price of the product.' + example: 20.0 + + quantity: + type: number + format: double + description: 'The quantity of the product.' + example: 5.0 + + default: 1 + tax_name1: + type: string + description: 'The name of tax 1.' + example: 'Tax 1' + + tax_rate1: + type: number + format: double + description: 'The rate of tax 1.' + example: 10.0 + + tax_name2: + type: string + description: 'The name of tax 2.' + example: 'Tax 2' + + tax_rate2: + type: number + format: double + description: 'The rate of tax 2.' + example: 5.0 + + tax_name3: + type: string + description: 'The name of tax 3.' + example: 'Tax 3' + + tax_rate3: + type: number + format: double + description: 'The rate of tax 3.' + example: 0.0 + + in_stock_quantity: + type: integer + format: int32 + description: | + The quantity of the product that is currently in stock. + + **note** this field is not mutable without passing an extra query parameter which will allow modification of this value. + + The query parameter ?update_in_stock_quantity=true **MUST** be passed if you wish to update this value manually. + + default: 0 + + stock_notification: + type: boolean + description: Indicates whether stock notifications are enabled for this product + default: true + + stock_notification_threshold: + type: integer + format: int32 + description: The minimum quantity threshold for which stock notifications will be triggered + default: 0 + + max_quantity: + type: integer + format: int32 + description: The maximum quantity that can be ordered for this product + + product_image: + type: string + description: The URL of the product image + format: uri-reference + + tax_id: + type: string + default: '1' + + description: | + The tax category id for this product.' + + The following constants are available (default = '1') + + ``` + PRODUCT_TYPE_PHYSICAL = '1' + PRODUCT_TYPE_SERVICE = '2' + PRODUCT_TYPE_DIGITAL = '3' + PRODUCT_TYPE_SHIPPING = '4' + PRODUCT_TYPE_EXEMPT = '5' + PRODUCT_TYPE_REDUCED_TAX = '6' + PRODUCT_TYPE_OVERRIDE_TAX = '7' + PRODUCT_TYPE_ZERO_RATED = '8' + PRODUCT_TYPE_REVERSE_TAX = '9' + ``` + example: '1' + + InvoiceInvitationRequest: + required: + - client_contact_id + properties: + id: + description: 'The entity invitation hashed id' + type: string + example: Opnel5aKBz + readOnly: true + client_contact_id: + description: 'The client contact hashed id' + type: string + example: Opnel5aKBz + key: + description: 'The invitation key' + type: string + example: Opnel5aKBz4343343566236gvbb + readOnly: true + link: + description: 'The invitation link' + type: string + example: 'https://www.example.com/invitations/Opnel5aKBz4343343566236gvbb' + readOnly: true + sent_date: + description: 'The invitation sent date' + type: string + format: date-time + readOnly: true + viewed_date: + description: 'The invitation viewed date' + type: string + format: date-time + readOnly: true + opened_date: + description: 'The invitation opened date' + type: string + format: date-time + readOnly: true + updated_at: + description: 'Timestamp' + type: number + format: integer + example: '1434342123' + readOnly: true + archived_at: + description: 'Timestamp' + type: number + format: integer + example: '1434342123' + readOnly: true + email_error: + description: 'The email error' + type: string + example: 'The email error' + readOnly: true + email_status: + description: 'The email status' + type: string + readOnly: true + + BankIntegration: + properties: + id: + description: 'The bank integration hashed id' + type: string + example: AS3df3A + user_id: + description: 'The user hashed id' + type: string + example: AS3df3A + provider_bank_name: + description: 'The providers bank name' + type: string + example: 'Chase Bank' + bank_account_id: + description: 'The bank account id' + type: integer + example: '1233434' + bank_account_name: + description: 'The name of the account' + type: string + example: 'My Checking Acc' + bank_account_number: + description: 'The account number' + type: string + example: '111 234 2332' + bank_account_status: + description: 'The status of the bank account' + type: string + example: ACTIVE + bank_account_type: + description: 'The type of account' + type: string + example: CREDITCARD + balance: + description: 'The current bank balance if available' + type: number + example: '1000000' + currency: + description: 'iso_3166_3 code' + type: string + example: USD + type: object + CompanyToken: + properties: + name: + description: 'The token name' + type: string + example: 'Token Name' + token: + description: 'The token value' + type: string + example: AS3df3jUUH765fhfd9KJuidj3JShjA + is_system: + description: 'Determines whether the token is created by the system rather than a user' + type: boolean + example: 'true' + type: object PurchaseOrder: properties: id: @@ -16565,98 +16597,1270 @@ components: type: object - CompanyUser: + InvoiceInvitation: properties: - permissions: - description: 'The user permissionsfor this company in a comma separated list' + id: + description: 'The entity invitation hashed id' type: string - example: 'create_invoice,create_client,view_client' - settings: - description: 'Settings that are used for the flutter applications to store user preferences / metadata' - type: object + example: Opnel5aKBz readOnly: true - react_settings: - description: 'Dedicated settings object for the react web application' - type: object + client_contact_id: + description: 'The client contact hashed id' + type: string + example: Opnel5aKBz + key: + description: 'The invitation key' + type: string + example: Opnel5aKBz4343343566236gvbb readOnly: true - is_owner: - description: 'Determines whether the user owns this company' - type: boolean - example: true + link: + description: 'The invitation link' + type: string + example: 'https://www.example.com/invitations/Opnel5aKBz4343343566236gvbb' readOnly: true - is_admin: - description: 'Determines whether the user is the admin of this company' - type: boolean - example: true + sent_date: + description: 'The invitation sent date' + type: string + format: date-time readOnly: true - is_locked: - description: 'Determines whether the users access to this company has been locked' - type: boolean - example: true + viewed_date: + description: 'The invitation viewed date' + type: string + format: date-time + readOnly: true + opened_date: + description: 'The invitation opened date' + type: string + format: date-time readOnly: true updated_at: - description: 'The last time the record was modified, format Unix Timestamp' - type: integer - example: '1231232312321' - deleted_at: - description: 'Timestamp when the user was archived, format Unix Timestamp' - type: integer - example: '12312312321' - account: - $ref: '#/components/schemas/Account' - company: - $ref: '#/components/schemas/Company' - user: - $ref: '#/components/schemas/UserRef' - token: - $ref: '#/components/schemas/CompanyToken' - type: object - CompanyUserRef: - properties: - permissions: - description: 'The user permissionsfor this company in a comma separated list' + description: 'Timestamp' + type: number + format: integer + example: '1434342123' + readOnly: true + archived_at: + description: 'Timestamp' + type: number + format: integer + example: '1434342123' + readOnly: true + email_error: + description: 'The email error' type: string - example: 'create_invoice,create_client,view_client' - settings: - description: 'Settings that are used for the flutter applications to store user preferences / metadata' - type: object + example: 'The email error' readOnly: true - react_settings: - description: 'Dedicated settings object for the react web application' - type: object + email_status: + description: 'The email status' + type: string readOnly: true - is_owner: - description: 'Determines whether the user owns this company' - type: boolean - example: true - readOnly: true - is_admin: - description: 'Determines whether the user is the admin of this company' - type: boolean - example: true - readOnly: true - is_locked: - description: 'Determines whether the users access to this company has been locked' + + VendorContact: + properties: + id: + description: 'The hashed id of the vendor contact' + type: string + example: Opnel5aKBz + readOnly: true + user_id: + description: 'The hashed id of the user id' + type: string + example: Opnel5aKBz + readOnly: true + vendor_id: + description: 'The hashed id of the vendor' + type: string + example: Opnel5aKBz + readOnly: true + first_name: + description: 'The first name of the contact' + type: string + example: Harry + last_name: + description: 'The last name of the contact' + type: string + example: Windsor + contact_key: + description: 'A unique identifier for the contact' + type: string + example: JD0X52bkfZlJRiroCJ0tcSiAjsJTntZ5uqKdiZ0a + readOnly: true + confirmation_code: + description: 'The confirmation code used to authenticate the contacts email address' + type: string + example: 333-sdjkh34gbasd + readOnly: true + phone: + description: 'The contacts phone number' + type: string + example: 555-123-1234 + custom_value1: + description: 'A custom value' + type: string + example: '2022-10-10' + custom_value2: + description: 'A custom value' + type: string + example: $1000 + custom_value3: + description: 'A custom value' + type: string + example: '' + custom_value4: + description: 'A custom value' + type: string + example: '' + email: + description: 'The contact email address' + type: string + example: harry@windsor.com + email_verified_at: + description: 'The date which the contact confirmed their email' + type: number + format: integer + example: '134341234234' + readOnly: true + password: + description: 'The hashed password of the contact' + type: string + example: '*****' + is_primary: + description: 'Boolean flag determining if the contact is the primary contact for the vendor' type: boolean example: true + created_at: + description: Timestamp + type: number + format: integer + example: '134341234234' readOnly: true updated_at: - description: 'The last time the record was modified, format Unix Timestamp' - type: integer - example: '1231232312321' + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true deleted_at: - description: 'Timestamp when the user was archived, format Unix Timestamp' - type: integer - example: '12312312321' - account: - $ref: '#/components/schemas/Account' - company: - $ref: '#/components/schemas/Company' - user: - $ref: '#/components/schemas/UserRef' - token: - $ref: '#/components/schemas/CompanyToken' + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true type: object + ClientGatewayToken: + properties: + id: + description: 'The hashed id of the client gateway token' + type: string + example: Opnel5aKBz + client_id: + description: 'The hashed_id of the client' + type: string + example: '2' + token: + description: 'The payment token' + type: string + example: '2' + routing_number: + description: 'THe bank account routing number' + type: string + example: '2' + company_gateway_id: + description: 'The hashed id of the company gateway' + type: string + example: '2' + is_default: + description: 'Flag determining if the token is the default payment method' + type: boolean + example: 'true' + type: object + Company: + properties: + id: + description: "The unique hashed identifier for the company" + type: string + example: WJxbojagwO + size_id: + description: "The unique identifier representing the company's size category" + type: string + example: '2' + industry_id: + description: "The unique identifier representing the company's industry category" + type: string + example: '5' + slack_webhook_url: + description: "The URL for the company's Slack webhook notifications" + type: string + example: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX' + google_analytics_key: + description: "The company's Google Analytics tracking ID" + type: string + example: 'UA-123456789-1' + portal_mode: + description: "The mode determining how client-facing URLs are structured (e.g., subdomain, domain, or iframe)" + type: string + example: subdomain + subdomain: + description: "The subdomain prefix for the company's domain (e.g., 'acme' in acme.domain.com)" + type: string + example: acme + portal_domain: + description: "The fully qualified domain used for client-facing URLs" + type: string + example: 'https://subdomain.invoicing.co' + enabled_tax_rates: + description: "The number of tax rates used per entity" + type: integer + example: '2' + fill_products: + description: "A flag determining whether to auto-fill product descriptions based on the product key" + type: boolean + example: true + convert_products: + description: "A flag determining whether to convert products between different types or units" + type: boolean + example: true + update_products: + description: "A flag determining whether to update product descriptions when the description changes" + type: boolean + example: true + show_product_details: + description: "A flag determining whether to display product details in the user interface" + type: boolean + example: true + show_product_cost: + description: "A flag determining whether to display product cost is shown in the user interface" + type: boolean + example: true + custom_fields: + description: "A mapping of custom fields for various objects within the company" + type: object + enable_product_cost: + description: "A flag determining whether to show or hide the product cost field in the user interface" + type: boolean + example: true + enable_product_quantity: + description: "A flag determining whether to show or hide the product quantity field in the user interface" + type: boolean + example: true + default_quantity: + description: "A flag determining whether to use a default quantity for products" + type: boolean + example: true + custom_surcharge_taxes1: + description: "A flag determining whether to apply taxes on custom surcharge amounts for the first custom surcharge field" + type: boolean + example: true + custom_surcharge_taxes2: + description: "A flag determining whether to apply taxes on custom surcharge amounts for the second custom surcharge field" + type: boolean + example: true + custom_surcharge_taxes3: + description: "A flag determining whether to apply taxes on custom surcharge amounts for the third custom surcharge field" + type: boolean + example: true + custom_surcharge_taxes4: + description: "A flag determining whether to apply taxes on custom surcharge amounts for the fourth custom" + logo: + description: "The company logo file in binary format" + type: string + format: binary + example: logo.png + company_key: + description: "The static company key hash used to identify the Company" + readOnly: true + type: string + example: "Vnb14bRlwiFjc5ckte6cfbygTRkn5IMQ" + client_can_register: + description: "A flag determining whether clients can register for the client portal" + type: boolean + example: true + enabled_modules: + type: integer + description: | + Bitmask representation of the modules that are enabled in the application + + ``` + self::ENTITY_RECURRING_INVOICE => 1, + self::ENTITY_CREDIT => 2, + self::ENTITY_QUOTE => 4, + self::ENTITY_TASK => 8, + self::ENTITY_EXPENSE => 16, + self::ENTITY_PROJECT => 32, + self::ENTITY_VENDOR => 64, + self::ENTITY_TICKET => 128, + self::ENTITY_PROPOSAL => 256, + self::ENTITY_RECURRING_EXPENSE => 512, + self::ENTITY_RECURRING_TASK => 1024, + self::ENTITY_RECURRING_QUOTE => 2048, + ``` + + The default per_page value is 20. + + example: 2048 + db: + readOnly: true + type: string + example: 'db-ninja-01' + first_day_of_week: + description: "The first day of the week for the company" + type: string + example: '1' + first_month_of_year: + description: "The first month for the company financial year" + type: string + example: '1' + enabled_item_tax_rates: + description: "The number of tax rates used per item" + type: integer + example: 2 + is_large: + description: "A flag determining whether the company is considered large" + type: boolean + example: true + default_auto_bill: + type: string + example: 'always' + description: | + A flag determining whether to auto-bill clients by default + + values: + + - always - Always auto bill + - disabled - Never auto bill + - optin - Allow the client to select their auto bill status with the default being disabled + - optout -Allow the client to select their auto bill status with the default being enabled + mark_expenses_invoiceable: + description: "A flag determining whether to mark expenses as invoiceable by default" + type: boolean + example: true + mark_expenses_paid: + description: "A flag determining whether to mark expenses as paid by default" + type: boolean + example: true + invoice_expense_documents: + description: "A flag determining whether to include expense documents on invoices by default" + type: boolean + example: true + auto_start_tasks: + description: "A flag determining whether to auto-start tasks by default" + type: boolean + example: true + invoice_task_timelog: + description: "A flag determining whether to include task time logs on invoices by default" + type: boolean + example: true + invoice_task_documents: + description: "A flag determining whether to include task documents on invoices by default" + type: boolean + example: true + show_tasks_table: + description: "A flag determining whether to show the tasks table on invoices by default" + type: boolean + example: true + is_disabled: + description: "A flag determining whether the company is disabled" + type: boolean + example: true + default_task_is_date_based: + description: "A flag determining whether to default tasks to be date-based" + type: boolean + example: true + enable_product_discount: + description: "A flag determining whether to show or hide the product discount field in the user interface" + type: boolean + example: true + calculate_expense_tax_by_amount: + description: "A flag determining whether to calculate expense taxes by amount" + type: boolean + example: true + expense_inclusive_taxes: + description: "A flag determining whether to include taxes in the expense amount" + type: boolean + example: true + session_timeout: + description: "The session timeout for the company" + type: integer + example: 60 + oauth_password_required: + description: "A flag determining whether to require a password for `dangerous` actions when using OAuth" + type: boolean + example: true + invoice_task_datelog: + description: "A flag determining whether to include task date logs on invoices by default" + type: boolean + example: true + default_password_timeout: + description: "The default password timeout for the company" + type: integer + example: 60 + show_task_end_date: + description: "A flag determining whether to show the task end date on invoices by default" + type: boolean + example: true + markdown_enabled: + description: "A flag determining whether markdown is enabled for the company" + type: boolean + example: true + report_include_drafts: + description: "A flag determining whether to include draft invoices in reports" + type: boolean + example: true + client_registration_fields: + description: "The client registration fields for the company" + type: object + stop_on_unpaid_recurring: + description: "A flag determining whether to stop recurring invoices when they are unpaid" + type: boolean + example: true + use_quote_terms_on_conversion: + description: "A flag determining whether to use quote terms on conversion to an invoice" + type: boolean + example: true + enable_applying_payments: + description: "A flag determining whether to enable applying payments to invoices" + type: boolean + example: true + track_inventory: + description: "A flag determining whether to track inventory for the company" + type: boolean + example: true + inventory_notification_threshold: + description: "The inventory notification threshold for the company" + type: integer + example: 60 + stock_notification: + description: "A flag determining whether to send stock notifications for the company" + type: boolean + example: true + matomo_url: + description: "The Matomo URL for the company" + type: string + example: 'https://matomo.example.com' + matomo_id: + description: "The Matomo ID for the company" + type: string + example: '1' + enabled_expense_tax_rates: + description: "The number of tax rates used per expense" + type: integer + example: 2 + invoice_task_project: + description: "A flag determining whether to include the project on invoices by default" + type: boolean + example: true + report_include_deleted: + description: "A flag determining whether to include deleted invoices in reports" + type: boolean + example: true + invoice_task_lock: + description: "A flag determining whether to lock tasks when invoiced" + type: boolean + example: true + convert_payment_currency: + description: "A flag determining whether to convert the payment currency" + type: boolean + example: true + convert_expense_currency: + description: "A flag determining whether to convert the expense currency" + type: boolean + example: true + notify_vendor_when_paid: + description: "A flag determining whether to notify the vendor when an expense is paid" + type: boolean + example: true + invoice_task_hours: + description: "A flag determining whether to include the task hours on invoices by default" + type: boolean + example: true + calculate_taxes: + description: "A flag determining whether to calculate taxes for the company" + type: boolean + example: true + tax_data: + description: "The tax data for the company" + type: object + e_invoice_certificate: + description: "The e-invoice certificate for the company" + type: string + example: '-----BEGIN CERTIFICATE-----' + e_invoice_certificate_passphrase: + description: "The e-invoice certificate passphrase for the company" + type: string + example: 'secret' + origin_tax_data: + description: "The origin tax data for the company" + type: object + invoice_task_project_header: + description: "A flag determining whether to include the project header on invoices by default" + type: boolean + example: true + invoice_task_item_description: + description: "A flag determining whether to include the item description on invoices by default" + type: boolean + example: true + + settings: + $ref: '#/components/schemas/CompanySettings' + type: object + CompanyLedger: + properties: + entity_id: + description: 'This field will reference one of the following entity hashed ID payment_id, invoice_id or credit_id' + type: string + example: AS3df3A + notes: + description: 'The notes which reference this entry of the ledger' + type: string + example: 'Credit note for invoice #3212' + balance: + description: 'The client balance' + type: number + format: float + example: '10.00' + adjustment: + description: 'The amount the client balance is adjusted by' + type: number + format: float + example: '10.00' + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + created_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + type: object + RecurringInvoice: + properties: + id: + description: 'The hashed id of the recurring invoice' + type: string + example: Opnel5aKBz + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The assigned user hashed id' + type: string + example: Opnel5aKBz + client_id: + description: 'The client hashed id' + type: string + example: Opnel5aKBz + status_id: + description: 'The invoice status variable' + type: string + example: '4' + frequency_id: + description: 'The recurring invoice frequency' + type: number + example: '4' + remaining_cycles: + description: 'The number of invoices left to be generated' + type: number + example: '4' + number: + description: 'The recurringinvoice number - is a unique alpha numeric number per invoice per company' + type: string + example: INV_101 + po_number: + description: 'The purchase order associated with this recurring invoice' + type: string + example: PO-1234 + terms: + description: 'The invoice terms' + type: string + example: 'These are invoice terms' + public_notes: + description: 'The public notes of the invoice' + type: string + example: 'These are some public notes' + private_notes: + description: 'The private notes of the invoice' + type: string + example: 'These are some private notes' + footer: + description: 'The invoice footer notes' + type: string + example: '' + custom_value1: + description: 'A custom field value' + type: string + example: '2022-10-01' + custom_value2: + description: 'A custom field value' + type: string + example: 'Something custom' + custom_value3: + description: 'A custom field value' + type: string + example: '' + custom_value4: + description: 'A custom field value' + type: string + example: '' + tax_name1: + description: 'The tax name' + type: string + example: '' + tax_name2: + description: 'The tax name' + type: string + example: '' + tax_rate1: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_rate2: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_name3: + description: 'The tax name' + type: string + example: '' + tax_rate3: + description: 'The tax rate' + type: number + format: float + example: '10.00' + total_taxes: + description: 'The total taxes for the invoice' + type: number + format: float + example: '10.00' + line_items: + description: 'An array of objects which define the line items of the invoice' + type: object + example: '' + amount: + description: 'The invoice amount' + type: number + format: float + example: '10.00' + balance: + description: 'The invoice balance' + type: number + format: float + example: '10.00' + paid_to_date: + description: 'The amount paid on the invoice to date' + type: number + format: float + example: '10.00' + discount: + description: 'The invoice discount, can be an amount or a percentage' + type: number + format: float + example: '10.00' + partial: + description: 'The deposit/partial amount' + type: number + format: float + example: '10.00' + is_amount_discount: + description: 'Flag determining if the discount is an amount or a percentage' + type: boolean + example: true + is_deleted: + description: 'Defines if the invoice has been deleted' + type: boolean + example: true + uses_inclusive_taxes: + description: 'Defines the type of taxes used as either inclusive or exclusive' + type: boolean + example: true + date: + description: 'The Invoice Date' + type: string + format: date + example: '1994-07-30' + last_sent_date: + description: 'The last date the invoice was sent out' + type: string + format: date + example: '1994-07-30' + next_send_date: + description: 'The Next date for a reminder to be sent' + type: string + format: date + example: '1994-07-30' + partial_due_date: + description: 'The due date for the deposit/partial amount' + type: string + format: date + example: '1994-07-30' + due_date: + description: 'The due date of the invoice' + type: string + format: date + example: '1994-07-30' + settings: + $ref: '#/components/schemas/CompanySettings' + last_viewed: + description: Timestamp + type: number + format: integer + example: '1434342123' + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + custom_surcharge1: + description: 'First Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge2: + description: 'Second Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge3: + description: 'Third Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge4: + description: 'Fourth Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge_tax1: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax2: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax3: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax4: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + type: object + + Payment: + properties: + id: + description: 'The payment hashed id' + type: string + example: Opnel5aKBz + client_id: + description: 'The client hashed id' + type: string + example: Opnel5aKBz + invitation_id: + description: 'The invitation hashed id' + type: string + example: Opnel5aKBz + client_contact_id: + description: 'The client contact hashed id' + type: string + example: Opnel5aKBz + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + type_id: + description: 'The Payment Type ID' + type: string + example: '1' + date: + description: 'The Payment date' + type: string + example: 1-1-2014 + transaction_reference: + description: 'The transaction reference as defined by the payment gateway' + type: string + example: xcsSxcs124asd + assigned_user_id: + description: 'The assigned user hashed id' + type: string + example: Opnel5aKBz + private_notes: + description: 'The private notes of the payment' + type: string + example: 'The payment was refunded due to error' + is_manual: + description: 'Flags whether the payment was made manually or processed via a gateway' + type: boolean + example: true + is_deleted: + description: 'Defines if the payment has been deleted' + type: boolean + example: true + amount: + description: 'The amount of this payment' + type: number + example: 10 + refunded: + description: 'The refunded amount of this payment' + type: number + example: 10 + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + company_gateway_id: + description: 'The company gateway id' + type: string + example: '3' + paymentables: + $ref: '#/components/schemas/Paymentable' + invoices: + description: '' + type: array + items: + $ref: '#/components/schemas/InvoicePaymentable' + credits: + description: '' + type: array + items: + $ref: '#/components/schemas/CreditPaymentable' + number: + description: 'The payment number - is a unique alpha numeric number per payment per company' + type: string + example: PAY_101 + type: object + + Credit: + properties: + id: + description: "The unique hashed ID of the credit" + type: string + example: Opnel5aKBz + user_id: + description: "The unique hashed ID of the user associated with the credit" + type: string + example: 1a2b3c4d5e + assigned_user_id: + description: "The unique hashed ID of the assigned user responsible for the credit" + type: string + example: 6f7g8h9i0j + client_id: + description: "The unique hashed ID of the client associated with the credit" + type: string + example: p1q2r3s4t5 + status_id: + description: "The ID representing the current status of the credit" + type: string + example: 3 + invoice_id: + description: "The unique hashed ID of the linked invoice to which the credit is applied" + type: string + example: u1v2w3x4y5 + number: + description: "The unique alphanumeric credit number per company" + type: string + example: QUOTE_101 + po_number: + description: "The purchase order number referred to by the credit" + type: string + example: PO_12345 + terms: + description: "The terms associated with the credit" + type: string + example: "Net 30" + public_notes: + description: "Public notes for the credit" + type: string + example: "Thank you for your business." + private_notes: + description: "Private notes for internal use, not visible to the client" + type: string + example: "Client is requesting a discount." + footer: + description: "The footer text for the credit" + type: string + example: "Footer text goes here." + custom_value1: + description: "Custom value 1 for additional credit information" + type: string + example: "Custom data 1" + custom_value2: + description: "Custom value 2 for additional credit information" + type: string + example: "Custom data 2" + custom_value3: + description: "Custom value 3 for additional credit information" + type: string + example: "Custom data 3" + custom_value4: + description: "Custom value 4 for additional credit information" + type: string + example: "Custom data 4" + tax_name1: + description: "The name of the first tax applied to the credit" + type: string + example: "VAT" + tax_name2: + description: "The name of the second tax applied to the credit" + type: string + example: "GST" + tax_rate1: + description: "The rate of the first tax applied to the credit" + type: number + format: float + example: 10.00 + tax_rate2: + description: "The rate of the second tax applied to the credit" + type: number + format: float + example: 5.00 + tax_name3: + description: "The name of the third tax applied to the credit" + type: string + example: "PST" + tax_rate3: + description: "The rate of the third tax applied to the credit" + type: number + format: float + example: 8.00 + total_taxes: + description: "The total amount of taxes for the credit" + type: number + format: float + example: 23.00 + line_items: + type: array + description: 'An array of objects which define the line items of the credit' + items: + $ref: '#/components/schemas/InvoiceItem' + amount: + description: "The total amount of the credit" + type: number + format: float + example: 100.00 + balance: + description: "The outstanding balance of the credit" + type: number + format: float + example: 50.00 + paid_to_date: + description: "The total amount paid to date for the credit" + type: number + format: float + example: 50.00 + discount: + description: "The discount applied to the credit" + type: number + format: float + example: 10.00 + partial: + description: "The partial amount applied to the credit" + type: number + format: float + example: 20.00 + is_amount_discount: + description: "Indicates whether the discount applied is a fixed amount or a percentage" + type: boolean + example: true + is_deleted: + description: "Indicates whether the credit has been deleted" + type: boolean + example: false + uses_inclusive_taxes: + description: "Indicates whether the tax rates applied to the credit are inclusive or exclusive" + type: boolean + example: true + date: + description: "The date the credit was issued" + type: string + format: date + example: "1994-07-30" + last_sent_date: + description: "The date the credit was last sent out" + type: string + format: date + example: "1994-07-30" + next_send_date: + description: "The next scheduled date for sending a credit reminder" + type: string + format: date + example: "1994-07-30" + partial_due_date: + description: "The due date for the partial amount of the credit" + type: string + format: date + example: "1994-07-30" + due_date: + description: "The due date for the total amount of the credit" + type: string + format: date + example: "1994-07-30" + settings: + $ref: "#/components/schemas/CompanySettings" + last_viewed: + description: "The timestamp of the last time the credit was viewed" + type: number + format: integer + example: 1434342123 + updated_at: + description: "The timestamp of the last time the credit was updated" + type: number + format: integer + example: 1434342123 + archived_at: + description: "The timestamp of the last time the credit was archived" + type: number + format: integer + example: 1434342123 + custom_surcharge1: + description: "First custom surcharge amount" + type: number + format: float + example: 10.00 + custom_surcharge2: + description: 'Second Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge3: + description: 'Third Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge4: + description: 'Fourth Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge_tax1: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax2: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax3: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax4: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + type: object + Subscription: + properties: + id: + description: Unique identifier for the subscription + type: string + example: Opnel5aKBz + user_id: + description: Unique identifier for the user associated with the subscription + type: string + example: Ua6Rw4pVbS + product_id: + description: Unique identifier for the product associated with the subscription + type: string + example: Pr5Ft7yBmC + recurring_invoice_id: + description: Unique identifier for the recurring invoice associated with the subscription + type: string + example: Ri2Yt8zJkP + is_recurring: + description: Indicates whether the subscription is recurring + type: boolean + example: 'true' + frequency_id: + description: 'integer const representation of the frequency' + type: string + example: '1' + auto_bill: + description: 'enum setting' + type: string + example: always + promo_code: + description: Promotional code applied to the subscription + type: string + example: PROMOCODE4U + promo_discount: + description: Discount percentage or amount applied to the subscription + type: number + example: 10 + is_amount_discount: + description: Indicates whether the discount is a fixed amount + type: boolean + example: 'true' + allow_cancellation: + description: Indicates whether the subscription can be cancelled + type: boolean + example: 'true' + per_seat_enabled: + description: Indicates whether the subscription pricing is per seat + type: boolean + example: 'true' + currency_id: + description: Unique identifier for the currency used in the subscription + type: integer + example: '1' + max_seats_limit: + description: Maximum number of seats allowed for the subscription + type: integer + example: '100' + trial_enabled: + description: Indicates whether the subscription has a trial period + type: boolean + example: 'true' + trial_duration: + description: Duration of the trial period in days + type: integer + example: '14' + allow_query_overrides: + description: Indicates whether query overrides are allowed for the subscription + type: boolean + example: 'true' + allow_plan_changes: + description: Indicates whether plan changes are allowed for the subscription + type: boolean + example: 'true' + refund_period: + description: Number of days within which refunds can be requested + type: integer + example: '30' + webhook_configuration: + description: Webhook configuration for the subscription + type: string + example: 'expand reference for this' + is_deleted: + description: Indicates whether the subscription has been deleted + type: boolean + example: 'false' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + created_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + updated_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + type: object + BulkAction: + type: array + items: + type: integer + example: '[0,1,2,3,]' + Project: + type: object + properties: + id: + description: 'The project hashed id' + type: string + example: Opnel5aKBz + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + assigned_user_id: + description: The assigned user identifier associated with the project + type: string + example: Opnel5aKBz + client_id: + type: string + example: Opnel5aKBz + description: The client identifier associated with the project + name: + type: string + description: The name of the project + example: 'New Project' + task_rate: + type: number + format: float + example: 10 + description: The default rate per task for the project + due_date: + type: string + format: date + example: '2019-01-01' + description: The due date for the project + private_notes: + type: string + description: Private notes associated with the project + budgeted_hours: + type: number + format: float + description: The number of budgeted hours for the project + custom_value1: + type: string + description: Custom value field 1 + custom_value2: + type: string + description: Custom value field 2 + custom_value3: + type: string + description: Custom value field 3 + custom_value4: + type: string + description: Custom value field 4 + created_at: + type: number + format: integer + example: 134341234234 + description: The timestamp of the project creation + updated_at: + type: number + format: integer + example: 134341234234 + description: The timestamp of the last project update + archived_at: + type: number + format: integer + example: 134341234234 + description: The timestamp of the project deletion + public_notes: + type: string + description: Public notes associated with the project + is_deleted: + type: boolean + description: A flag indicating if the project is deleted + number: + type: string + description: The project number + color: + type: string + description: The color associated with the project + required: + - id + - user_id + - name + - task_rate + - budgeted_hours + - is_deleted + - color + CompanySettings: required: - currency_id @@ -17500,1859 +18704,6 @@ components: example: "individual" type: object - CompanyLedger: - properties: - entity_id: - description: 'This field will reference one of the following entity hashed ID payment_id, invoice_id or credit_id' - type: string - example: AS3df3A - notes: - description: 'The notes which reference this entry of the ledger' - type: string - example: 'Credit note for invoice #3212' - balance: - description: 'The client balance' - type: number - format: float - example: '10.00' - adjustment: - description: 'The amount the client balance is adjusted by' - type: number - format: float - example: '10.00' - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - created_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - type: object - CompanyToken: - properties: - name: - description: 'The token name' - type: string - example: 'Token Name' - token: - description: 'The token value' - type: string - example: AS3df3jUUH765fhfd9KJuidj3JShjA - is_system: - description: 'Determines whether the token is created by the system rather than a user' - type: boolean - example: 'true' - type: object - Activity: - properties: - id: - description: 'The id field of the activity' - type: string - example: Opnel5aKBz - activity_type_id: - description: 'The activity type id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - company_id: - description: 'The company hashed id' - type: string - example: Opnel5aKBz - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - invoice_id: - description: 'The invoice hashed id' - type: string - example: Opnel5aKBz - payment_id: - description: 'The payment hashed id' - type: string - example: Opnel5aKBz - credit_id: - description: 'The credit hashed id' - type: string - example: Opnel5aKBz - updated_at: - description: 'Unixtimestamp the last time the record was updated' - type: integer - example: '343421434' - expense_id: - description: 'The expense hashed id' - type: string - example: Opnel5aKBz - is_system: - description: 'Defines is the activity was performed by the system' - type: boolean - example: true - contact_id: - description: 'The contact hashed id' - type: string - example: Opnel5aKBz - task_id: - description: 'The task hashed id' - type: string - example: Opnel5aKBz - notes: - description: 'Activity Notes' - type: string - example: Opnel5aKBz - token_id: - description: 'The hashed ID of the token who performed the action' - type: string - example: Opnel5aKBz - ip: - description: 'The IP Address of the user who performed the action' - type: string - example: 192.168.1.252 - user: - $ref: '#/components/schemas/User' - client: - $ref: '#/components/schemas/Client' - contact: - $ref: '#/components/schemas/ClientContact' - recurring_invoice: - $ref: '#/components/schemas/RecurringInvoice' - invoice: - $ref: '#/components/schemas/Invoice' - credit: - $ref: '#/components/schemas/Credit' - quote: - $ref: '#/components/schemas/Quote' - payment: - $ref: '#/components/schemas/Payment' - expense: - $ref: '#/components/schemas/Expense' - task: - $ref: '#/components/schemas/Task' - purchase_order: - $ref: '#/components/schemas/PurchaseOrder' - vendor: - $ref: '#/components/schemas/Vendor' - vendor_contact: - $ref: '#/components/schemas/VendorContact' - type: object - Error: - properties: - message: - description: 'Something terrible went wrong' - type: string - example: 'Unexpected error' - code: - description: 'The HTTP error code, ie 5xx 4xx' - type: integer - example: '500' - type: object - - GenericBulkAction: - properties: - action: - type: string - example: archive - description: 'The action to perform ie. archive / restore / delete' - ids: - type: array - items: - format: string - type: string - example: 2J234DFA,D2J234DFA,D2J234DFA - description: string array of client hashed ids - type: object - ClientContact: - properties: - id: - description: 'The hashed if of the contact' - type: string - example: Opnel5aKBz - readOnly: true - user_id: - description: 'The hashed id of the user who created the contact' - type: string - example: Opnel5aKBz - readOnly: true - client_id: - description: 'The hashed id of the client' - type: string - example: Opnel5aKBz - readOnly: true - first_name: - description: 'The first name of the contact' - type: string - example: John - last_name: - description: 'The last name of the contact' - type: string - example: Doe - phone: - description: 'The phone number of the contact' - type: string - example: 555-152-4524 - custom_value1: - description: 'A Custom field value' - type: string - example: '' - custom_value2: - description: 'A Custom field value' - type: string - example: '' - custom_value3: - description: 'A Custom field value' - type: string - example: '' - custom_value4: - description: 'A Custom field value' - type: string - example: '' - email: - description: 'The email of the contact' - type: string - example: '' - accepted_terms_version: - description: 'The terms of service which the contact has accpeted' - type: string - example: 'A long set of ToS' - readOnly: true - password: - description: 'The hashed password of the contact' - type: string - example: '*****' - confirmation_code: - description: 'The confirmation code used to authenticate the contacts email address' - type: string - example: 333-sdjkh34gbasd - readOnly: true - token: - description: 'A uuid based token.' - type: string - example: 333-sdjkh34gbasd - readOnly: true - contact_key: - description: 'A unique identifier for the contact' - type: string - example: JD0X52bkfZlJRiroCJ0tcSiAjsJTntZ5uqKdiZ0a - readOnly: true - is_primary: - description: 'Defines is this contact is the primary contact for the client' - type: boolean - example: true - confirmed: - description: 'Boolean value confirms the user has confirmed their account.' - type: boolean - example: true - is_locked: - description: 'Boolean value defines if the contact has been locked out.' - type: boolean - example: true - send_email: - description: 'Boolean value determines is this contact should receive emails' - type: boolean - example: true - failed_logins: - description: 'The number of failed logins the contact has had' - type: number - format: integer - example: '3' - readOnly: true - email_verified_at: - description: 'The date which the contact confirmed their email' - type: number - format: integer - example: '134341234234' - readOnly: true - last_login: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - created_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - updated_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - deleted_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - type: object - Project: - type: object - properties: - id: - description: 'The project hashed id' - type: string - example: Opnel5aKBz - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - assigned_user_id: - description: The assigned user identifier associated with the project - type: string - example: Opnel5aKBz - client_id: - type: string - example: Opnel5aKBz - description: The client identifier associated with the project - name: - type: string - description: The name of the project - example: 'New Project' - task_rate: - type: number - format: float - example: 10 - description: The default rate per task for the project - due_date: - type: string - format: date - example: '2019-01-01' - description: The due date for the project - private_notes: - type: string - description: Private notes associated with the project - budgeted_hours: - type: number - format: float - description: The number of budgeted hours for the project - custom_value1: - type: string - description: Custom value field 1 - custom_value2: - type: string - description: Custom value field 2 - custom_value3: - type: string - description: Custom value field 3 - custom_value4: - type: string - description: Custom value field 4 - created_at: - type: number - format: integer - example: 134341234234 - description: The timestamp of the project creation - updated_at: - type: number - format: integer - example: 134341234234 - description: The timestamp of the last project update - archived_at: - type: number - format: integer - example: 134341234234 - description: The timestamp of the project deletion - public_notes: - type: string - description: Public notes associated with the project - is_deleted: - type: boolean - description: A flag indicating if the project is deleted - number: - type: string - description: The project number - color: - type: string - description: The color associated with the project - required: - - id - - user_id - - name - - task_rate - - budgeted_hours - - is_deleted - - color - - Credit: - properties: - id: - description: "The unique hashed ID of the credit" - type: string - example: Opnel5aKBz - user_id: - description: "The unique hashed ID of the user associated with the credit" - type: string - example: 1a2b3c4d5e - assigned_user_id: - description: "The unique hashed ID of the assigned user responsible for the credit" - type: string - example: 6f7g8h9i0j - client_id: - description: "The unique hashed ID of the client associated with the credit" - type: string - example: p1q2r3s4t5 - status_id: - description: "The ID representing the current status of the credit" - type: string - example: 3 - invoice_id: - description: "The unique hashed ID of the linked invoice to which the credit is applied" - type: string - example: u1v2w3x4y5 - number: - description: "The unique alphanumeric credit number per company" - type: string - example: QUOTE_101 - po_number: - description: "The purchase order number referred to by the credit" - type: string - example: PO_12345 - terms: - description: "The terms associated with the credit" - type: string - example: "Net 30" - public_notes: - description: "Public notes for the credit" - type: string - example: "Thank you for your business." - private_notes: - description: "Private notes for internal use, not visible to the client" - type: string - example: "Client is requesting a discount." - footer: - description: "The footer text for the credit" - type: string - example: "Footer text goes here." - custom_value1: - description: "Custom value 1 for additional credit information" - type: string - example: "Custom data 1" - custom_value2: - description: "Custom value 2 for additional credit information" - type: string - example: "Custom data 2" - custom_value3: - description: "Custom value 3 for additional credit information" - type: string - example: "Custom data 3" - custom_value4: - description: "Custom value 4 for additional credit information" - type: string - example: "Custom data 4" - tax_name1: - description: "The name of the first tax applied to the credit" - type: string - example: "VAT" - tax_name2: - description: "The name of the second tax applied to the credit" - type: string - example: "GST" - tax_rate1: - description: "The rate of the first tax applied to the credit" - type: number - format: float - example: 10.00 - tax_rate2: - description: "The rate of the second tax applied to the credit" - type: number - format: float - example: 5.00 - tax_name3: - description: "The name of the third tax applied to the credit" - type: string - example: "PST" - tax_rate3: - description: "The rate of the third tax applied to the credit" - type: number - format: float - example: 8.00 - total_taxes: - description: "The total amount of taxes for the credit" - type: number - format: float - example: 23.00 - line_items: - type: array - description: 'An array of objects which define the line items of the credit' - items: - $ref: '#/components/schemas/InvoiceItem' - amount: - description: "The total amount of the credit" - type: number - format: float - example: 100.00 - balance: - description: "The outstanding balance of the credit" - type: number - format: float - example: 50.00 - paid_to_date: - description: "The total amount paid to date for the credit" - type: number - format: float - example: 50.00 - discount: - description: "The discount applied to the credit" - type: number - format: float - example: 10.00 - partial: - description: "The partial amount applied to the credit" - type: number - format: float - example: 20.00 - is_amount_discount: - description: "Indicates whether the discount applied is a fixed amount or a percentage" - type: boolean - example: true - is_deleted: - description: "Indicates whether the credit has been deleted" - type: boolean - example: false - uses_inclusive_taxes: - description: "Indicates whether the tax rates applied to the credit are inclusive or exclusive" - type: boolean - example: true - date: - description: "The date the credit was issued" - type: string - format: date - example: "1994-07-30" - last_sent_date: - description: "The date the credit was last sent out" - type: string - format: date - example: "1994-07-30" - next_send_date: - description: "The next scheduled date for sending a credit reminder" - type: string - format: date - example: "1994-07-30" - partial_due_date: - description: "The due date for the partial amount of the credit" - type: string - format: date - example: "1994-07-30" - due_date: - description: "The due date for the total amount of the credit" - type: string - format: date - example: "1994-07-30" - settings: - $ref: "#/components/schemas/CompanySettings" - last_viewed: - description: "The timestamp of the last time the credit was viewed" - type: number - format: integer - example: 1434342123 - updated_at: - description: "The timestamp of the last time the credit was updated" - type: number - format: integer - example: 1434342123 - archived_at: - description: "The timestamp of the last time the credit was archived" - type: number - format: integer - example: 1434342123 - custom_surcharge1: - description: "First custom surcharge amount" - type: number - format: float - example: 10.00 - custom_surcharge2: - description: 'Second Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge3: - description: 'Third Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge4: - description: 'Fourth Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge_tax1: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax2: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax3: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax4: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - type: object - - ProductBulkAction: - required: - - action - - ids - properties: - action: - type: string - example: archive - description: 'The action to perform ie. archive / restore / delete / set_tax_id' - ids: - type: array - items: - format: string - type: string - example: 2J234DFA,D2J234DFA,D2J234DFA - description: string array of client hashed ids - tax_id: - type: string - example: '1' - description: | - The tax rate id to set on the list of products - - The following constants are available (default = '1') - - ``` - PRODUCT_TYPE_PHYSICAL = '1' - PRODUCT_TYPE_SERVICE = '2' - PRODUCT_TYPE_DIGITAL = '3' - PRODUCT_TYPE_SHIPPING = '4' - PRODUCT_TYPE_EXEMPT = '5' - PRODUCT_TYPE_REDUCED_TAX = '6' - PRODUCT_TYPE_OVERRIDE_TAX = '7' - PRODUCT_TYPE_ZERO_RATED = '8' - PRODUCT_TYPE_REVERSE_TAX = '9' - ``` - type: object - Payment: - properties: - id: - description: 'The payment hashed id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - invitation_id: - description: 'The invitation hashed id' - type: string - example: Opnel5aKBz - client_contact_id: - description: 'The client contact hashed id' - type: string - example: Opnel5aKBz - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - type_id: - description: 'The Payment Type ID' - type: string - example: '1' - date: - description: 'The Payment date' - type: string - example: 1-1-2014 - transaction_reference: - description: 'The transaction reference as defined by the payment gateway' - type: string - example: xcsSxcs124asd - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: Opnel5aKBz - private_notes: - description: 'The private notes of the payment' - type: string - example: 'The payment was refunded due to error' - is_manual: - description: 'Flags whether the payment was made manually or processed via a gateway' - type: boolean - example: true - is_deleted: - description: 'Defines if the payment has been deleted' - type: boolean - example: true - amount: - description: 'The amount of this payment' - type: number - example: 10 - refunded: - description: 'The refunded amount of this payment' - type: number - example: 10 - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - company_gateway_id: - description: 'The company gateway id' - type: string - example: '3' - paymentables: - $ref: '#/components/schemas/Paymentable' - invoices: - description: '' - type: array - items: - $ref: '#/components/schemas/InvoicePaymentable' - credits: - description: '' - type: array - items: - $ref: '#/components/schemas/CreditPaymentable' - number: - description: 'The payment number - is a unique alpha numeric number per payment per company' - type: string - example: PAY_101 - type: object - - BankTransactionRule: - properties: - id: - description: 'The bank transaction rules hashed id' - type: string - example: AS3df3A - user_id: - description: 'The user hashed id' - type: string - example: AS3df3A - name: - description: 'The name of the transaction' - type: string - example: 'Rule 1' - rules: - description: 'A mapped collection of the sub rules for the BankTransactionRule' - type: array - items: - $ref: '#/components/schemas/BTRules' - auto_convert: - description: 'Flags whether the rule converts the transaction automatically' - type: boolean - example: true - matches_on_all: - description: 'Flags whether all subrules are required for the match' - type: boolean - example: true - applies_to: - description: 'Flags whether the rule applies to a CREDIT or DEBIT' - type: string - example: CREDIT - client_id: - description: 'The client hashed id' - type: string - example: AS3df3A - vendor_id: - description: 'The vendor hashed id' - type: string - example: AS3df3A - category_id: - description: 'The category hashed id' - type: string - example: AS3df3A - type: object - RecurringExpense: - properties: - id: - description: 'The hashed id of the recurring expense' - type: string - example: Opnel5aKBz - user_id: - description: 'The hashed id of the user who created the recurring expense' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The hashed id of the user assigned to this recurring expense' - type: string - example: Opnel5aKBz - client_id: - description: 'The hashed id of the client' - type: string - example: Opnel5aKBz - invoice_id: - description: 'The hashed id of the invoice' - type: string - example: Opnel5aKBz - bank_id: - description: 'The id of the bank associated with this recurring expense' - type: string - example: '22' - invoice_currency_id: - description: 'The currency id of the invoice associated with this recurring expense' - type: string - example: '1' - expense_currency_id: - description: 'The currency id of the expense associated with this recurring expense' - type: string - example: '1' - invoice_category_id: - description: 'The category id of the invoice' - type: string - example: '1' - payment_type_id: - description: 'The payment type id' - type: string - example: '1' - private_notes: - description: 'The recurring expense private notes' - type: string - example: 'Private and confidential' - public_notes: - description: 'The recurring expense public notes' - type: string - example: 'This is the best client in the world' - transaction_reference: - description: 'The recurring expense transaction reference' - type: string - example: EXP-1223-2333 - transcation_id: - description: 'The transaction id of the recurring expense' - type: string - example: '1233312312' - custom_value1: - description: 'Custom value field' - type: string - example: $1000 - custom_value2: - description: 'Custom value field' - type: string - example: '2022-10-10' - custom_value3: - description: 'Custom value field' - type: string - example: 'short text' - custom_value4: - description: 'Custom value field' - type: string - example: 'very long text' - tax_name1: - description: 'The tax name' - type: string - example: GST - tax_name2: - description: 'The tax name' - type: string - example: VAT - tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_name3: - description: 'The tax name' - type: string - example: '' - tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '10.00' - amount: - description: 'The total amount of the recurring expense' - type: number - format: float - example: '10.00' - frequency_id: - description: 'The frequency this recurring expense fires' - type: number - format: int - example: '1' - remaining_cycles: - description: 'The number of remaining cycles for this recurring expense' - type: number - format: int - example: '1' - foreign_amount: - description: 'The foreign currency amount of the recurring expense' - type: number - format: float - example: '10.00' - exchange_rate: - description: 'The exchange rate for the expernse' - type: number - format: float - example: '0.80' - date: - description: 'The date of the expense' - type: string - example: '' - payment_date: - description: 'The date the expense was paid' - type: string - example: '' - should_be_invoiced: - description: 'Boolean flag determining if the expense should be invoiced' - type: boolean - example: true - is_deleted: - description: 'Boolean flag determining if the recurring expense is deleted' - type: boolean - example: true - last_sent_date: - description: 'The Date it was sent last' - type: string - format: date - example: '1994-07-30' - next_send_date: - description: 'The next send date' - type: string - format: date - example: '1994-07-30' - invoice_documents: - description: 'Boolean flag determining if the documents associated with this expense should be passed onto the invoice if it is converted to an invoice' - type: boolean - example: true - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - type: object - InvoiceRequest: - required: - - client_id - properties: - id: - description: 'The invoice hashed id' - type: string - example: Opnel5aKBz - readOnly: true - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - status_id: - description: 'The invoice status variable' - type: string - example: '4' - readOnly: true - number: - description: 'The invoice number - is a unique alpha numeric number per invoice per company' - type: string - example: INV_101 - po_number: - description: 'The purchase order associated with this invoice' - type: string - example: PO-1234 - terms: - description: 'The invoice terms' - type: string - example: 'These are invoice terms' - public_notes: - description: 'The public notes of the invoice' - type: string - example: 'These are some public notes' - private_notes: - description: 'The private notes of the invoice' - type: string - example: 'These are some private notes' - footer: - description: 'The invoice footer notes' - type: string - example: '' - custom_value1: - description: 'A custom field value' - type: string - example: '2022-10-01' - custom_value2: - description: 'A custom field value' - type: string - example: 'Something custom' - custom_value3: - description: 'A custom field value' - type: string - example: '' - custom_value4: - description: 'A custom field value' - type: string - example: '' - tax_name1: - description: 'The tax name' - type: string - example: '' - tax_name2: - description: 'The tax name' - type: string - example: '' - tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_name3: - description: 'The tax name' - type: string - example: '' - tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '10.00' - total_taxes: - description: 'The total taxes for the invoice' - type: number - format: float - example: '10.00' - readOnly: true - line_items: - type: array - description: 'An array of objects which define the line items of the invoice' - items: - $ref: '#/components/schemas/InvoiceItem' - invitations: - type: array - description: 'An array of objects which define the invitations of the invoice' - items: - $ref: '#/components/schemas/InvoiceInvitationRequest' - amount: - description: 'The invoice amount' - type: number - format: float - example: '10.00' - readOnly: true - balance: - description: 'The invoice balance' - type: number - format: float - example: '10.00' - readOnly: true - paid_to_date: - description: 'The amount paid on the invoice to date' - type: number - format: float - example: '10.00' - readOnly: true - discount: - description: 'The invoice discount, can be an amount or a percentage' - type: number - format: float - example: '10.00' - partial: - description: 'The deposit/partial amount' - type: number - format: float - example: '10.00' - is_amount_discount: - description: 'Flag determining if the discount is an amount or a percentage' - type: boolean - example: true - is_deleted: - description: 'Defines if the invoice has been deleted' - type: boolean - example: true - readOnly: true - uses_inclusive_taxes: - description: 'Defines the type of taxes used as either inclusive or exclusive' - type: boolean - example: true - date: - description: 'The Invoice Date' - type: string - format: date - example: '1994-07-30' - last_sent_date: - description: 'The last date the invoice was sent out' - type: string - format: date - example: '1994-07-30' - readOnly: true - next_send_date: - description: 'The Next date for a reminder to be sent' - type: string - format: date - example: '1994-07-30' - readOnly: true - partial_due_date: - description: 'The due date for the deposit/partial amount' - type: string - format: date - example: '1994-07-30' - due_date: - description: 'The due date of the invoice' - type: string - format: date - example: '1994-07-30' - last_viewed: - description: Timestamp - type: number - format: integer - example: '1434342123' - readOnly: true - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - readOnly: true - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - readOnly: true - custom_surcharge1: - description: 'First Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge2: - description: 'Second Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge3: - description: 'Third Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge4: - description: 'Fourth Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge_tax1: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax2: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax3: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax4: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - project_id: - description: 'The project associated with this invoice' - type: string - example: Opnel5aKBz - type: object - RecurringQuote: - properties: - id: - description: 'The hashed id of the recurring quote' - type: string - example: Opnel5aKBz - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - status_id: - description: 'The quote status variable' - type: string - example: '4' - frequency_id: - description: 'The recurring quote frequency' - type: number - example: '4' - remaining_cycles: - description: 'The number of quotes left to be generated' - type: number - example: '4' - number: - description: 'The recurringquote number - is a unique alpha numeric number per quote per company' - type: string - example: INV_101 - po_number: - description: 'The purchase order associated with this recurring quote' - type: string - example: PO-1234 - terms: - description: 'The quote terms' - type: string - example: 'These are quote terms' - public_notes: - description: 'The public notes of the quote' - type: string - example: 'These are some public notes' - private_notes: - description: 'The private notes of the quote' - type: string - example: 'These are some private notes' - footer: - description: 'The quote footer notes' - type: string - example: '' - custom_value1: - description: 'A custom field value' - type: string - example: '2022-10-01' - custom_value2: - description: 'A custom field value' - type: string - example: 'Something custom' - custom_value3: - description: 'A custom field value' - type: string - example: '' - custom_value4: - description: 'A custom field value' - type: string - example: '' - tax_name1: - description: 'The tax name' - type: string - example: '' - tax_name2: - description: 'The tax name' - type: string - example: '' - tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_name3: - description: 'The tax name' - type: string - example: '' - tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '10.00' - total_taxes: - description: 'The total taxes for the quote' - type: number - format: float - example: '10.00' - line_items: - description: 'An array of objects which define the line items of the quote' - type: object - example: '' - amount: - description: 'The quote amount' - type: number - format: float - example: '10.00' - balance: - description: 'The quote balance' - type: number - format: float - example: '10.00' - paid_to_date: - description: 'The amount paid on the quote to date' - type: number - format: float - example: '10.00' - discount: - description: 'The quote discount, can be an amount or a percentage' - type: number - format: float - example: '10.00' - partial: - description: 'The deposit/partial amount' - type: number - format: float - example: '10.00' - is_amount_discount: - description: 'Flag determining if the discount is an amount or a percentage' - type: boolean - example: true - is_deleted: - description: 'Defines if the quote has been deleted' - type: boolean - example: true - uses_inclusive_taxes: - description: 'Defines the type of taxes used as either inclusive or exclusive' - type: boolean - example: true - date: - description: 'The quote Date' - type: string - format: date - example: '1994-07-30' - last_sent_date: - description: 'The last date the quote was sent out' - type: string - format: date - example: '1994-07-30' - next_send_date: - description: 'The Next date for a reminder to be sent' - type: string - format: date - example: '1994-07-30' - partial_due_date: - description: 'The due date for the deposit/partial amount' - type: string - format: date - example: '1994-07-30' - due_date: - description: 'The due date of the quote' - type: string - format: date - example: '1994-07-30' - settings: - $ref: '#/components/schemas/CompanySettings' - last_viewed: - description: Timestamp - type: number - format: integer - example: '1434342123' - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - custom_surcharge1: - description: 'First Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge2: - description: 'Second Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge3: - description: 'Third Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge4: - description: 'Fourth Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge_tax1: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax2: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax3: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax4: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - type: object - Client: - properties: - id: - description: 'The unique identifier of the client' - type: string - example: Opnel5aKBz - readOnly: true - contacts: - type: array - items: - $ref: '#/components/schemas/ClientContact' - user_id: - description: 'The unique identifier of the user who created the client' - type: string - example: Ua6Rw4pVbS - readOnly: true - assigned_user_id: - description: 'The unique identifier of the user who has been assigned the client' - type: string - example: Ua6Rw4pVbS - name: - description: 'The name of the client company or organization' - type: string - example: "Jim's Housekeeping" - website: - description: 'The website URL of the client company or organization' - type: string - example: 'https://www.jims-housekeeping.com' - private_notes: - description: 'Notes that are only visible to the user who created the client' - type: string - example: 'Client prefers email communication over phone calls' - client_hash: - description: 'A unique hash value for the client' - type: string - example: asdfkjhk342hjhbfdvmnfb1 - readOnly: true - industry_id: - description: 'The unique identifier of the industry the client operates in' - type: number - example: '5' - size_id: - description: 'The unique identifier for the size category of the client company or organization' - type: number - example: '2' - address1: - description: "First line of the client's address" - type: string - example: '123 Main St' - address2: - description: "Second line of the client's address, if needed" - type: string - example: 'Apt 4B' - city: - description: 'The city the client is located in' - type: string - example: 'Beverly Hills' - state: - description: 'The state, province, or locality the client is located in' - type: string - example: 'California' - postal_code: - description: 'The postal code or ZIP code of the client' - type: string - example: '90210' - phone: - description: "The client's phone number" - type: string - example: '555-3434-3434' - country_id: - description: "The unique identifier of the client's country" - type: number - format: integer - example: '1' - custom_value1: - description: 'A custom field for storing additional information' - type: string - example: 'Preferred contact: Email' - custom_value2: - description: 'A custom field for storing additional information' - type: string - example: 'Account manager: John Doe' - custom_value3: - description: 'A custom field for storing additional information' - type: string - example: 'VIP client: Yes' - custom_value4: - description: 'A custom field for storing additional information' - type: string - example: 'Annual contract value: $50,000' - vat_number: - description: "The client's VAT (Value Added Tax) number, if applicable" - type: string - example: 'VAT123456' - id_number: - description: 'A unique identification number for the client, such as a tax ID or business registration number' - type: string - number: - description: 'A system-assigned unique number for the client, typically used for invoicing purposes' - type: string - example: 'CL-0001' - shipping_address1: - description: "First line of the client's shipping address" - type: string - example: '5 Wallaby Way' - shipping_address2: - description: "Second line of the client's shipping address, if needed" - type: string - example: 'Suite 5' - shipping_city: - description: "The city of the client's shipping address" - type: string - example: 'Perth' - shipping_state: - description: "The state, province, or locality of the client's shipping address" - type: string - example: 'Western Australia' - shipping_postal_code: - description: "The postal code or ZIP code of the client's shipping address" - type: string - example: '6110' - shipping_country_id: - description: "The unique identifier of the country for the client's shipping address" - type: number - format: integer - example: '4' - is_deleted: - description: 'A boolean value indicating whether the client has been deleted or not' - type: boolean - example: false - readOnly: true - balance: - description: 'The outstanding balance the client owes' - type: number - format: float - example: '500.00' - readOnly: true - paid_to_date: - description: 'The total amount the client has paid to date' - type: number - format: float - example: '2000.00' - readOnly: true - credit_balance: - description: 'The available credit balance for the client to use on future purchases' - type: number - format: float - example: '100.00' - readOnly: true - last_login: - description: "The timestamp of the client's last login" - type: number - format: integer - example: '1628686031' - readOnly: true - created_at: - description: 'The timestamp when the client was created' - type: number - format: integer - example: '1617629031' - readOnly: true - updated_at: - description: 'The timestamp when the client was last updated' - type: number - format: integer - example: '1628445631' - readOnly: true - group_settings_id: - description: 'The group settings assigned to the client' - type: string - example: Opnel5aKBz - routing_id: - description: 'The routing address id for e-invoicing for this client' - type: string - example: Opnel5aKBz3489-dfkiu-2239-sdsd - is_tax_exempt: - description: 'Flag which defines if the client is exempt from taxes' - type: boolean - example: false - has_valid_vat_number: - description: 'Flag which defines if the client has a valid VAT number' - type: boolean - example: false - readOnly: true - payment_balance: - description: 'Defines the payment balance the client has on file (pre payments / over payments / unapplied amounts)' - type: number - example: 100 - readOnly: true - settings: - $ref: '#/components/schemas/ClientSettings' - type: object - PaymentTerm: - properties: - num_days: - description: 'The payment term length in days' - type: integer - example: '1' - name: - description: 'The payment term length in string format' - type: string - example: 'NET 1' - created_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - updated_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - archived_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - type: object - Product: - type: object - properties: - id: - type: string - description: 'The hashed product ID.' - example: eP01N - readOnly: true - user_id: - type: string - description: 'The hashed ID of the user that created this product.' - example: n30m4 - readOnly: true - assigned_user_id: - type: string - description: 'The hashed ID of the user assigned to this product.' - example: pR0j3 - project_id: - type: string - description: 'The hashed ID of the project that this product is associated with.' - example: pR0j3 - vendor_id: - type: string - description: 'The hashed ID of the vendor that this product is associated with.' - example: pR0j3 - custom_value1: - type: string - description: 'Custom value field 1.' - example: 'Custom value 1' - custom_value2: - type: string - description: 'Custom value field 2.' - example: 'Custom value 2' - custom_value3: - type: string - description: 'Custom value field 3.' - example: 'Custom value 3' - custom_value4: - type: string - description: 'Custom value field 4.' - example: 'Custom value 4' - product_key: - type: string - description: 'The product key.' - example: '1234' - notes: - type: string - description: 'Notes about the product.' - example: 'These are some notes about the product.' - cost: - type: number - format: double - description: 'The cost of the product. (Your purchase price for this product)' - example: 10.0 - price: - type: number - format: double - description: 'The price of the product that you are charging.' - example: 20.0 - quantity: - type: number - format: double - description: 'The quantity of the product. (used as a default)' - example: 5.0 - tax_name1: - type: string - description: 'The name of tax 1.' - example: 'Tax 1' - tax_rate1: - type: number - format: double - description: 'The rate of tax 1.' - example: 10.0 - tax_name2: - type: string - description: 'The name of tax 2.' - example: 'Tax 2' - tax_rate2: - type: number - format: double - description: 'The rate of tax 2.' - example: 5.0 - tax_name3: - type: string - description: 'The name of tax 3.' - example: 'Tax 3' - tax_rate3: - type: number - format: double - description: 'The rate of tax 3.' - example: 0.0 - archived_at: - type: integer - format: timestamp - description: 'The timestamp when the product was archived.' - example: '2022-03-18T15:00:00Z' - readOnly: true - created_at: - type: integer - format: timestamp - description: 'The timestamp when the product was created.' - example: '2022-03-18T15:00:00Z' - readOnly: true - updated_at: - description: Timestamp - type: integer - format: timestamp - example: '2022-03-18T12:34:56.789Z' - readOnly: true - is_deleted: - type: boolean - description: 'Boolean flag determining if the product has been deleted' - example: false - readOnly: true - in_stock_quantity: - type: integer - format: int32 - description: The quantity of the product that is currently in stock - default: 0 - stock_notification: - type: boolean - description: Indicates whether stock notifications are enabled for this product - default: true - stock_notification_threshold: - type: integer - format: int32 - description: The minimum quantity threshold for which stock notifications will be triggered - default: 0 - max_quantity: - type: integer - format: int32 - description: The maximum quantity that can be ordered for this product - product_image: - type: string - description: The URL of the product image - format: uri-reference - tax_id: - type: string - default: '1' - description: | - The tax category id for this product.' - - The following constants are available (default = '1') - - ``` - PRODUCT_TYPE_PHYSICAL = '1' - PRODUCT_TYPE_SERVICE = '2' - PRODUCT_TYPE_DIGITAL = '3' - PRODUCT_TYPE_SHIPPING = '4' - PRODUCT_TYPE_EXEMPT = '5' - PRODUCT_TYPE_REDUCED_TAX = '6' - PRODUCT_TYPE_OVERRIDE_TAX = '7' - PRODUCT_TYPE_ZERO_RATED = '8' - PRODUCT_TYPE_REVERSE_TAX = '9' - ``` - example: '1' - - Meta: - properties: - pagination: - $ref: '#/components/schemas/Pagination' - Pagination: - type: object - properties: - total: - type: integer - description: 'The total number of items' - example: 1 - readOnly: true - count: - type: integer - description: 'The number of items per page' - example: 1 - readOnly: true - per_page: - type: integer - description: 'The number of items per page' - example: 1 - readOnly: true - current_page: - type: integer - description: 'The current page number' - example: 1 - readOnly: true - total_pages: - type: integer - description: 'The total number of pages' - example: 1 - readOnly: true - links: - type: object - description: 'The pagination links' - readOnly: true - ClientContactRequest: - properties: - id: - description: 'The hashed if of the contact' - type: string - example: Opnel5aKBz - readOnly: true - first_name: - description: 'The first name of the contact' - type: string - example: John - last_name: - description: 'The last name of the contact' - type: string - example: Doe - phone: - description: 'The phone number of the contact' - type: string - example: 555-152-4524 - custom_value1: - description: 'A Custom field value' - type: string - example: '' - custom_value2: - description: 'A Custom field value' - type: string - example: '' - custom_value3: - description: 'A Custom field value' - type: string - example: '' - custom_value4: - description: 'A Custom field value' - type: string - example: '' - email: - description: 'The email of the contact' - type: string - example: '' - password: - description: 'The hashed password of the contact' - type: string - example: '*****' - send_email: - description: 'Boolean value determines is this contact should receive emails' - type: boolean - example: true - type: object Design: properties: id: @@ -19395,1521 +18746,6 @@ components: format: integer example: '134341234234' type: object - Vendor: - properties: - id: - description: 'The hashed id of the vendor. This is a unique identifier for the vendor.' - type: string - example: Opnel5aKBz - readOnly: true - user_id: - description: 'The hashed id of the user who created the vendor. This is a unique identifier for the user.' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The hashed id of the assigned user to this vendor. This is a unique identifier for the user.' - type: string - example: Opnel5aKBz - contacts: - type: array - items: - $ref: '#/components/schemas/VendorContact' - description: 'An array of contacts associated with the vendor.' - name: - description: 'The name of the vendor.' - type: string - example: 'Harry cafe de wheels' - classification: - description: 'The classification of the vendor.' - type: string - example: 'individual' - website: - description: 'The website of the vendor.' - type: string - example: www.harry.com - private_notes: - description: 'The private notes of the vendor. These notes are only visible to users with appropriate permissions.' - type: string - example: 'Shhh, do not tell the vendor' - industry_id: - description: 'The industry id of the vendor. This is a unique identifier for the industry.' - type: string - example: '1' - size_id: - description: 'The size id of the vendor. This is a unique identifier for the size of the vendor.' - type: string - example: '' - address1: - description: 'The first line of the vendor''s address.' - type: string - example: '' - address2: - description: 'The second line of the vendor''s address.' - type: string - example: '' - city: - description: 'The city of the vendor''s address.' - type: string - example: '' - state: - description: 'The state of the vendor''s address.' - type: string - example: '' - postal_code: - description: 'The postal code of the vendor''s address.' - type: string - example: '' - phone: - description: 'The phone number of the vendor.' - type: string - example: 555-3434-3434 - country_id: - description: 'The country id of the vendor. This is a unique identifier for the country.' - type: string - example: '' - currency_id: - description: 'The currency id of the vendor. This is a unique identifier for the currency.' - type: string - example: '4' - custom_value1: - description: 'The value of the first custom field for the vendor.' - type: string - example: '' - custom_value2: - description: 'The value of the second custom field for the vendor.' - type: string - example: '' - custom_value3: - description: 'The value of the third custom field for the vendor.' - type: string - example: '' - custom_value4: - description: 'The value of the fourth custom field for the vendor.' - type: string - example: '' - vat_number: - description: 'The VAT number of the vendor.' - type: string - example: '' - id_number: - description: 'The ID number of the vendor.' - type: string - example: '' - number: - description: 'The number of the vendor' - type: string - example: '11234' - is_deleted: - description: 'Boolean flag determining if the vendor has been deleted' - type: boolean - example: true - language_id: - description: 'The language id of the vendor. This is a unique identifier for the language.' - type: string - example: '1' - vendor_hash: - description: 'The vendor hash of the vendor. This is a unique identifier for the vendor.' - type: string - example: 'aaa-sss-www' - readOnly: true - transaction_name: - description: 'The transaction name of the vendor.' - type: string - example: 'aaa-sss-www' - last_login: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - created_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - updated_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - display_name: - description: 'The display name of the vendor.' - type: string - example: 'Bob the vendor' - readOnly: true - type: object - BTRules: - properties: - data_key: - description: 'The key to search' - type: string - example: 'description,amount' - operator: - description: 'The operator flag of the search' - type: string - example: '>' - value: - description: 'The value to search for' - type: string - example: bob - type: object - ClientRequest: - required: - - contacts - - country_id - properties: - id: - description: 'The unique identifier of the client' - type: string - example: Opnel5aKBz - readOnly: true - contacts: - type: array - description: 'A list of contacts associated with the client' - items: - $ref: '#/components/schemas/ClientContactRequest' - name: - description: 'The name of the client company or organization' - type: string - example: "Jim's Housekeeping" - website: - description: 'The website URL of the client company or organization' - type: string - example: 'https://www.jims-housekeeping.com' - private_notes: - description: 'Notes that are only visible to the user who created the client' - type: string - example: 'Client prefers email communication over phone calls' - industry_id: - description: 'The unique identifier of the industry the client operates in' - type: number - example: '5' - size_id: - description: 'The unique identifier for the size category of the client company or organization' - type: number - example: '2' - address1: - description: "First line of the client's address" - type: string - example: '123 Main St' - address2: - description: "Second line of the client's address, if needed" - type: string - example: 'Apt 4B' - city: - description: 'The city the client is located in' - type: string - example: 'Beverly Hills' - state: - description: 'The state, province, or locality the client is located in' - type: string - example: 'California' - postal_code: - description: 'The postal code or ZIP code of the client' - type: string - example: '90210' - phone: - description: "The client's phone number" - type: string - example: '555-3434-3434' - country_id: - description: "The unique identifier of the client's country" - type: number - format: integer - example: '1' - custom_value1: - description: 'A custom field for storing additional information' - type: string - example: 'Preferred contact: Email' - custom_value2: - description: 'A custom field for storing additional information' - type: string - example: 'Account manager: John Doe' - custom_value3: - description: 'A custom field for storing additional information' - type: string - example: 'VIP client: Yes' - custom_value4: - description: 'A custom field for storing additional information' - type: string - example: 'Annual contract value: $50,000' - vat_number: - description: "The client's VAT (Value Added Tax) number, if applicable" - type: string - example: 'VAT123456' - id_number: - description: 'A unique identification number for the client, such as a tax ID or business registration number' - type: string - number: - description: 'A system-assigned unique number for the client, typically used for invoicing purposes' - type: string - example: 'CL-0001' - shipping_address1: - description: "First line of the client's shipping address" - type: string - example: '5 Wallaby Way' - shipping_address2: - description: "Second line of the client's shipping address, if needed" - type: string - example: 'Suite 5' - shipping_city: - description: "The city of the client's shipping address" - type: string - example: 'Perth' - shipping_state: - description: "The state, province, or locality of the client's shipping address" - type: string - example: 'Western Australia' - shipping_postal_code: - description: "The postal code or ZIP code of the client's shipping address" - type: string - example: '6110' - shipping_country_id: - description: "The unique identifier of the country for the client's shipping address" - type: number - format: integer - example: '4' - is_deleted: - description: 'A boolean value indicating whether the client has been deleted or not' - type: boolean - example: false - readOnly: true - group_settings_id: - description: 'The group settings assigned to the client' - type: string - example: Opnel5aKBz - routing_id: - description: 'The routing address id for e-invoicing for this client' - type: string - example: Opnel5aKBz3489-dfkiu-2239-sdsd - is_tax_exempt: - description: 'Flag which defines if the client is exempt from taxes' - type: boolean - example: false - has_valid_vat_number: - description: 'Flag which defines if the client has a valid VAT number' - type: boolean - example: false - readOnly: true - classification: - description: 'The classification of the client' - type: string - example: 'individual' - settings: - $ref: '#/components/schemas/ClientSettings' - type: object - BankTransaction: - properties: - id: - description: 'The bank integration hashed id' - type: string - example: AS3df3A - user_id: - description: 'The user hashed id' - type: string - example: AS3df3A - transaction_id: - description: 'The id of the transaction rule' - type: integer - example: 343434 - amount: - description: 'The transaction amount' - type: number - example: 10 - currency_id: - description: 'The currency ID of the currency' - type: string - example: '1' - account_type: - description: 'The account type' - type: string - example: creditCard - description: - description: 'The description of the transaction' - type: string - example: 'Potato purchases for kevin' - category_id: - description: 'The category id' - type: integer - example: 1 - category_type: - description: 'The category description' - type: string - example: Expenses - base_type: - description: 'Either CREDIT or DEBIT' - type: string - example: CREDIT - date: - description: 'The date of the transaction' - type: string - example: '2022-09-01' - bank_account_id: - description: 'The ID number of the bank account' - type: integer - example: '1' - type: object - - FeesAndLimits: - properties: - min_limit: - description: 'The minimum amount accepted for this gateway' - type: string - example: '2' - max_limit: - description: 'The maximum amount accepted for this gateway' - type: string - example: '2' - fee_amount: - description: 'The gateway fee amount' - type: number - format: float - example: '2.0' - fee_percent: - description: 'The gateway fee percentage' - type: number - format: float - example: '2.0' - fee_tax_name1: - description: 'Fee tax name' - type: string - example: GST - fee_tax_name2: - description: 'Fee tax name' - type: string - example: VAT - fee_tax_name3: - description: 'Fee tax name' - type: string - example: 'CA Sales Tax' - fee_tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.0' - fee_tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '17.5' - fee_tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '25.0' - fee_cap: - description: 'If set the fee amount will be no higher than this amount' - type: number - format: float - example: '2.0' - adjust_fee_percent: - description: 'Adjusts the fee to match the exact gateway fee.' - type: boolean - example: true - type: object - VendorContact: - properties: - id: - description: 'The hashed id of the vendor contact' - type: string - example: Opnel5aKBz - readOnly: true - user_id: - description: 'The hashed id of the user id' - type: string - example: Opnel5aKBz - readOnly: true - vendor_id: - description: 'The hashed id of the vendor' - type: string - example: Opnel5aKBz - readOnly: true - first_name: - description: 'The first name of the contact' - type: string - example: Harry - last_name: - description: 'The last name of the contact' - type: string - example: Windsor - contact_key: - description: 'A unique identifier for the contact' - type: string - example: JD0X52bkfZlJRiroCJ0tcSiAjsJTntZ5uqKdiZ0a - readOnly: true - confirmation_code: - description: 'The confirmation code used to authenticate the contacts email address' - type: string - example: 333-sdjkh34gbasd - readOnly: true - phone: - description: 'The contacts phone number' - type: string - example: 555-123-1234 - custom_value1: - description: 'A custom value' - type: string - example: '2022-10-10' - custom_value2: - description: 'A custom value' - type: string - example: $1000 - custom_value3: - description: 'A custom value' - type: string - example: '' - custom_value4: - description: 'A custom value' - type: string - example: '' - email: - description: 'The contact email address' - type: string - example: harry@windsor.com - email_verified_at: - description: 'The date which the contact confirmed their email' - type: number - format: integer - example: '134341234234' - readOnly: true - password: - description: 'The hashed password of the contact' - type: string - example: '*****' - is_primary: - description: 'Boolean flag determining if the contact is the primary contact for the vendor' - type: boolean - example: true - created_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - updated_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - deleted_at: - description: Timestamp - type: number - format: integer - example: '134341234234' - readOnly: true - type: object - InvoiceInvitationRequest: - required: - - client_contact_id - properties: - id: - description: 'The entity invitation hashed id' - type: string - example: Opnel5aKBz - readOnly: true - client_contact_id: - description: 'The client contact hashed id' - type: string - example: Opnel5aKBz - key: - description: 'The invitation key' - type: string - example: Opnel5aKBz4343343566236gvbb - readOnly: true - link: - description: 'The invitation link' - type: string - example: 'https://www.example.com/invitations/Opnel5aKBz4343343566236gvbb' - readOnly: true - sent_date: - description: 'The invitation sent date' - type: string - format: date-time - readOnly: true - viewed_date: - description: 'The invitation viewed date' - type: string - format: date-time - readOnly: true - opened_date: - description: 'The invitation opened date' - type: string - format: date-time - readOnly: true - updated_at: - description: 'Timestamp' - type: number - format: integer - example: '1434342123' - readOnly: true - archived_at: - description: 'Timestamp' - type: number - format: integer - example: '1434342123' - readOnly: true - email_error: - description: 'The email error' - type: string - example: 'The email error' - readOnly: true - email_status: - description: 'The email status' - type: string - readOnly: true - - Paymentable: - properties: - id: - description: 'The paymentable hashed id' - type: string - example: AS3df3A - invoice_id: - description: 'The invoice hashed id' - type: string - example: AS3df3A - credit_id: - description: 'The credit hashed id' - type: string - example: AS3df3A - refunded: - description: 'The amount that has been refunded for this payment' - type: number - format: float - example: '10.00' - amount: - description: 'The amount that has been applied to the payment' - type: number - format: float - example: '10.00' - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - created_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - type: object - Company: - properties: - id: - description: "The unique hashed identifier for the company" - type: string - example: WJxbojagwO - size_id: - description: "The unique identifier representing the company's size category" - type: string - example: '2' - industry_id: - description: "The unique identifier representing the company's industry category" - type: string - example: '5' - slack_webhook_url: - description: "The URL for the company's Slack webhook notifications" - type: string - example: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX' - google_analytics_key: - description: "The company's Google Analytics tracking ID" - type: string - example: 'UA-123456789-1' - portal_mode: - description: "The mode determining how client-facing URLs are structured (e.g., subdomain, domain, or iframe)" - type: string - example: subdomain - subdomain: - description: "The subdomain prefix for the company's domain (e.g., 'acme' in acme.domain.com)" - type: string - example: acme - portal_domain: - description: "The fully qualified domain used for client-facing URLs" - type: string - example: 'https://subdomain.invoicing.co' - enabled_tax_rates: - description: "The number of tax rates used per entity" - type: integer - example: '2' - fill_products: - description: "A flag determining whether to auto-fill product descriptions based on the product key" - type: boolean - example: true - convert_products: - description: "A flag determining whether to convert products between different types or units" - type: boolean - example: true - update_products: - description: "A flag determining whether to update product descriptions when the description changes" - type: boolean - example: true - show_product_details: - description: "A flag determining whether to display product details in the user interface" - type: boolean - example: true - show_product_cost: - description: "A flag determining whether to display product cost is shown in the user interface" - type: boolean - example: true - custom_fields: - description: "A mapping of custom fields for various objects within the company" - type: object - enable_product_cost: - description: "A flag determining whether to show or hide the product cost field in the user interface" - type: boolean - example: true - enable_product_quantity: - description: "A flag determining whether to show or hide the product quantity field in the user interface" - type: boolean - example: true - default_quantity: - description: "A flag determining whether to use a default quantity for products" - type: boolean - example: true - custom_surcharge_taxes1: - description: "A flag determining whether to apply taxes on custom surcharge amounts for the first custom surcharge field" - type: boolean - example: true - custom_surcharge_taxes2: - description: "A flag determining whether to apply taxes on custom surcharge amounts for the second custom surcharge field" - type: boolean - example: true - custom_surcharge_taxes3: - description: "A flag determining whether to apply taxes on custom surcharge amounts for the third custom surcharge field" - type: boolean - example: true - custom_surcharge_taxes4: - description: "A flag determining whether to apply taxes on custom surcharge amounts for the fourth custom" - logo: - description: "The company logo file in binary format" - type: string - format: binary - example: logo.png - company_key: - description: "The static company key hash used to identify the Company" - readOnly: true - type: string - example: "Vnb14bRlwiFjc5ckte6cfbygTRkn5IMQ" - client_can_register: - description: "A flag determining whether clients can register for the client portal" - type: boolean - example: true - enabled_modules: - type: integer - description: | - Bitmask representation of the modules that are enabled in the application - - ``` - self::ENTITY_RECURRING_INVOICE => 1, - self::ENTITY_CREDIT => 2, - self::ENTITY_QUOTE => 4, - self::ENTITY_TASK => 8, - self::ENTITY_EXPENSE => 16, - self::ENTITY_PROJECT => 32, - self::ENTITY_VENDOR => 64, - self::ENTITY_TICKET => 128, - self::ENTITY_PROPOSAL => 256, - self::ENTITY_RECURRING_EXPENSE => 512, - self::ENTITY_RECURRING_TASK => 1024, - self::ENTITY_RECURRING_QUOTE => 2048, - ``` - - The default per_page value is 20. - - example: 2048 - db: - readOnly: true - type: string - example: 'db-ninja-01' - first_day_of_week: - description: "The first day of the week for the company" - type: string - example: '1' - first_month_of_year: - description: "The first month for the company financial year" - type: string - example: '1' - enabled_item_tax_rates: - description: "The number of tax rates used per item" - type: integer - example: 2 - is_large: - description: "A flag determining whether the company is considered large" - type: boolean - example: true - default_auto_bill: - type: string - example: 'always' - description: | - A flag determining whether to auto-bill clients by default - - values: - - - always - Always auto bill - - disabled - Never auto bill - - optin - Allow the client to select their auto bill status with the default being disabled - - optout -Allow the client to select their auto bill status with the default being enabled - mark_expenses_invoiceable: - description: "A flag determining whether to mark expenses as invoiceable by default" - type: boolean - example: true - mark_expenses_paid: - description: "A flag determining whether to mark expenses as paid by default" - type: boolean - example: true - invoice_expense_documents: - description: "A flag determining whether to include expense documents on invoices by default" - type: boolean - example: true - auto_start_tasks: - description: "A flag determining whether to auto-start tasks by default" - type: boolean - example: true - invoice_task_timelog: - description: "A flag determining whether to include task time logs on invoices by default" - type: boolean - example: true - invoice_task_documents: - description: "A flag determining whether to include task documents on invoices by default" - type: boolean - example: true - show_tasks_table: - description: "A flag determining whether to show the tasks table on invoices by default" - type: boolean - example: true - is_disabled: - description: "A flag determining whether the company is disabled" - type: boolean - example: true - default_task_is_date_based: - description: "A flag determining whether to default tasks to be date-based" - type: boolean - example: true - enable_product_discount: - description: "A flag determining whether to show or hide the product discount field in the user interface" - type: boolean - example: true - calculate_expense_tax_by_amount: - description: "A flag determining whether to calculate expense taxes by amount" - type: boolean - example: true - expense_inclusive_taxes: - description: "A flag determining whether to include taxes in the expense amount" - type: boolean - example: true - session_timeout: - description: "The session timeout for the company" - type: integer - example: 60 - oauth_password_required: - description: "A flag determining whether to require a password for `dangerous` actions when using OAuth" - type: boolean - example: true - invoice_task_datelog: - description: "A flag determining whether to include task date logs on invoices by default" - type: boolean - example: true - default_password_timeout: - description: "The default password timeout for the company" - type: integer - example: 60 - show_task_end_date: - description: "A flag determining whether to show the task end date on invoices by default" - type: boolean - example: true - markdown_enabled: - description: "A flag determining whether markdown is enabled for the company" - type: boolean - example: true - report_include_drafts: - description: "A flag determining whether to include draft invoices in reports" - type: boolean - example: true - client_registration_fields: - description: "The client registration fields for the company" - type: object - stop_on_unpaid_recurring: - description: "A flag determining whether to stop recurring invoices when they are unpaid" - type: boolean - example: true - use_quote_terms_on_conversion: - description: "A flag determining whether to use quote terms on conversion to an invoice" - type: boolean - example: true - enable_applying_payments: - description: "A flag determining whether to enable applying payments to invoices" - type: boolean - example: true - track_inventory: - description: "A flag determining whether to track inventory for the company" - type: boolean - example: true - inventory_notification_threshold: - description: "The inventory notification threshold for the company" - type: integer - example: 60 - stock_notification: - description: "A flag determining whether to send stock notifications for the company" - type: boolean - example: true - matomo_url: - description: "The Matomo URL for the company" - type: string - example: 'https://matomo.example.com' - matomo_id: - description: "The Matomo ID for the company" - type: string - example: '1' - enabled_expense_tax_rates: - description: "The number of tax rates used per expense" - type: integer - example: 2 - invoice_task_project: - description: "A flag determining whether to include the project on invoices by default" - type: boolean - example: true - report_include_deleted: - description: "A flag determining whether to include deleted invoices in reports" - type: boolean - example: true - invoice_task_lock: - description: "A flag determining whether to lock tasks when invoiced" - type: boolean - example: true - convert_payment_currency: - description: "A flag determining whether to convert the payment currency" - type: boolean - example: true - convert_expense_currency: - description: "A flag determining whether to convert the expense currency" - type: boolean - example: true - notify_vendor_when_paid: - description: "A flag determining whether to notify the vendor when an expense is paid" - type: boolean - example: true - invoice_task_hours: - description: "A flag determining whether to include the task hours on invoices by default" - type: boolean - example: true - calculate_taxes: - description: "A flag determining whether to calculate taxes for the company" - type: boolean - example: true - tax_data: - description: "The tax data for the company" - type: object - e_invoice_certificate: - description: "The e-invoice certificate for the company" - type: string - example: '-----BEGIN CERTIFICATE-----' - e_invoice_certificate_passphrase: - description: "The e-invoice certificate passphrase for the company" - type: string - example: 'secret' - origin_tax_data: - description: "The origin tax data for the company" - type: object - invoice_task_project_header: - description: "A flag determining whether to include the project header on invoices by default" - type: boolean - example: true - invoice_task_item_description: - description: "A flag determining whether to include the item description on invoices by default" - type: boolean - example: true - - settings: - $ref: '#/components/schemas/CompanySettings' - type: object - ProductRequest: - type: object - properties: - id: - type: string - description: 'The hashed product ID.' - example: eP01N - readOnly: true - assigned_user_id: - type: string - description: 'The hashed ID of the user assigned to this product.' - example: pR0j3 - - project_id: - type: string - description: 'The hashed ID of the project that this product is associated with.' - example: pR0j3 - - vendor_id: - type: string - description: 'The hashed ID of the vendor that this product is associated with.' - example: pR0j3 - - custom_value1: - type: string - description: 'Custom value field 1.' - example: 'Custom value 1' - - custom_value2: - type: string - description: 'Custom value field 2.' - example: 'Custom value 2' - - custom_value3: - type: string - description: 'Custom value field 3.' - example: 'Custom value 3' - - custom_value4: - type: string - description: 'Custom value field 4.' - example: 'Custom value 4' - - product_key: - type: string - description: 'The product key.' - example: '1234' - - notes: - type: string - description: 'Notes about the product.' - example: 'These are some notes about the product.' - - cost: - type: number - format: double - description: 'The cost of the product.' - example: 10.0 - - price: - type: number - format: double - description: 'The price of the product.' - example: 20.0 - - quantity: - type: number - format: double - description: 'The quantity of the product.' - example: 5.0 - - default: 1 - tax_name1: - type: string - description: 'The name of tax 1.' - example: 'Tax 1' - - tax_rate1: - type: number - format: double - description: 'The rate of tax 1.' - example: 10.0 - - tax_name2: - type: string - description: 'The name of tax 2.' - example: 'Tax 2' - - tax_rate2: - type: number - format: double - description: 'The rate of tax 2.' - example: 5.0 - - tax_name3: - type: string - description: 'The name of tax 3.' - example: 'Tax 3' - - tax_rate3: - type: number - format: double - description: 'The rate of tax 3.' - example: 0.0 - - in_stock_quantity: - type: integer - format: int32 - description: | - The quantity of the product that is currently in stock. - - **note** this field is not mutable without passing an extra query parameter which will allow modification of this value. - - The query parameter ?update_in_stock_quantity=true **MUST** be passed if you wish to update this value manually. - - default: 0 - - stock_notification: - type: boolean - description: Indicates whether stock notifications are enabled for this product - default: true - - stock_notification_threshold: - type: integer - format: int32 - description: The minimum quantity threshold for which stock notifications will be triggered - default: 0 - - max_quantity: - type: integer - format: int32 - description: The maximum quantity that can be ordered for this product - - product_image: - type: string - description: The URL of the product image - format: uri-reference - - tax_id: - type: string - default: '1' - - description: | - The tax category id for this product.' - - The following constants are available (default = '1') - - ``` - PRODUCT_TYPE_PHYSICAL = '1' - PRODUCT_TYPE_SERVICE = '2' - PRODUCT_TYPE_DIGITAL = '3' - PRODUCT_TYPE_SHIPPING = '4' - PRODUCT_TYPE_EXEMPT = '5' - PRODUCT_TYPE_REDUCED_TAX = '6' - PRODUCT_TYPE_OVERRIDE_TAX = '7' - PRODUCT_TYPE_ZERO_RATED = '8' - PRODUCT_TYPE_REVERSE_TAX = '9' - ``` - example: '1' - - RecurringInvoice: - properties: - id: - description: 'The hashed id of the recurring invoice' - type: string - example: Opnel5aKBz - user_id: - description: 'The user hashed id' - type: string - example: Opnel5aKBz - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: Opnel5aKBz - client_id: - description: 'The client hashed id' - type: string - example: Opnel5aKBz - status_id: - description: 'The invoice status variable' - type: string - example: '4' - frequency_id: - description: 'The recurring invoice frequency' - type: number - example: '4' - remaining_cycles: - description: 'The number of invoices left to be generated' - type: number - example: '4' - number: - description: 'The recurringinvoice number - is a unique alpha numeric number per invoice per company' - type: string - example: INV_101 - po_number: - description: 'The purchase order associated with this recurring invoice' - type: string - example: PO-1234 - terms: - description: 'The invoice terms' - type: string - example: 'These are invoice terms' - public_notes: - description: 'The public notes of the invoice' - type: string - example: 'These are some public notes' - private_notes: - description: 'The private notes of the invoice' - type: string - example: 'These are some private notes' - footer: - description: 'The invoice footer notes' - type: string - example: '' - custom_value1: - description: 'A custom field value' - type: string - example: '2022-10-01' - custom_value2: - description: 'A custom field value' - type: string - example: 'Something custom' - custom_value3: - description: 'A custom field value' - type: string - example: '' - custom_value4: - description: 'A custom field value' - type: string - example: '' - tax_name1: - description: 'The tax name' - type: string - example: '' - tax_name2: - description: 'The tax name' - type: string - example: '' - tax_rate1: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'The tax rate' - type: number - format: float - example: '10.00' - tax_name3: - description: 'The tax name' - type: string - example: '' - tax_rate3: - description: 'The tax rate' - type: number - format: float - example: '10.00' - total_taxes: - description: 'The total taxes for the invoice' - type: number - format: float - example: '10.00' - line_items: - description: 'An array of objects which define the line items of the invoice' - type: object - example: '' - amount: - description: 'The invoice amount' - type: number - format: float - example: '10.00' - balance: - description: 'The invoice balance' - type: number - format: float - example: '10.00' - paid_to_date: - description: 'The amount paid on the invoice to date' - type: number - format: float - example: '10.00' - discount: - description: 'The invoice discount, can be an amount or a percentage' - type: number - format: float - example: '10.00' - partial: - description: 'The deposit/partial amount' - type: number - format: float - example: '10.00' - is_amount_discount: - description: 'Flag determining if the discount is an amount or a percentage' - type: boolean - example: true - is_deleted: - description: 'Defines if the invoice has been deleted' - type: boolean - example: true - uses_inclusive_taxes: - description: 'Defines the type of taxes used as either inclusive or exclusive' - type: boolean - example: true - date: - description: 'The Invoice Date' - type: string - format: date - example: '1994-07-30' - last_sent_date: - description: 'The last date the invoice was sent out' - type: string - format: date - example: '1994-07-30' - next_send_date: - description: 'The Next date for a reminder to be sent' - type: string - format: date - example: '1994-07-30' - partial_due_date: - description: 'The due date for the deposit/partial amount' - type: string - format: date - example: '1994-07-30' - due_date: - description: 'The due date of the invoice' - type: string - format: date - example: '1994-07-30' - settings: - $ref: '#/components/schemas/CompanySettings' - last_viewed: - description: Timestamp - type: number - format: integer - example: '1434342123' - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - custom_surcharge1: - description: 'First Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge2: - description: 'Second Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge3: - description: 'Third Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge4: - description: 'Fourth Custom Surcharge' - type: number - format: float - example: '10.00' - custom_surcharge_tax1: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax2: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax3: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - custom_surcharge_tax4: - description: 'Toggles charging taxes on custom surcharge amounts' - type: boolean - example: true - type: object - - BankIntegration: - properties: - id: - description: 'The bank integration hashed id' - type: string - example: AS3df3A - user_id: - description: 'The user hashed id' - type: string - example: AS3df3A - provider_bank_name: - description: 'The providers bank name' - type: string - example: 'Chase Bank' - bank_account_id: - description: 'The bank account id' - type: integer - example: '1233434' - bank_account_name: - description: 'The name of the account' - type: string - example: 'My Checking Acc' - bank_account_number: - description: 'The account number' - type: string - example: '111 234 2332' - bank_account_status: - description: 'The status of the bank account' - type: string - example: ACTIVE - bank_account_type: - description: 'The type of account' - type: string - example: CREDITCARD - balance: - description: 'The current bank balance if available' - type: number - example: '1000000' - currency: - description: 'iso_3166_3 code' - type: string - example: USD - type: object - Expense: - properties: - id: - description: 'The expense hashed id' - type: string - example: 'Opnel5aKBz' - user_id: - description: 'The user hashed id' - type: string - example: 'Opnel5aKBz' - assigned_user_id: - description: 'The assigned user hashed id' - type: string - example: 'Opnel5aKBz' - project_id: - description: 'The associated project_id' - type: string - example: 'Opnel5aKBz' - client_id: - description: 'The client hashed id' - type: string - example: 'Opnel5aKBz' - invoice_id: - description: 'The related invoice hashed id' - type: string - example: 'Opnel5aKBz' - bank_id: - description: 'The bank id related to this expense' - type: string - example: '' - invoice_currency_id: - description: 'The currency id of the related invoice' - type: string - example: '1' - currency_id: - description: 'The currency id of the expense' - type: string - example: '2' - invoice_category_id: - description: 'The invoice category id' - type: string - example: 'Opnel5aKBz' - payment_type_id: - description: 'The payment type id' - type: string - example: '' - recurring_expense_id: - description: 'The related recurring expense this expense was created from' - type: string - example: 'Opnel5aKBz' - private_notes: - description: 'The private notes of the expense' - type: string - example: '' - public_notes: - description: 'The public notes of the expense' - type: string - example: '' - transaction_reference: - description: 'The transaction references of the expense' - type: string - example: '' - transcation_id: - description: 'The transaction id of the expense' - type: string - example: '' - custom_value1: - description: 'A custom value' - type: string - example: '' - custom_value2: - description: 'A custom value' - type: string - example: '' - custom_value3: - description: 'A custom value' - type: string - example: '' - custom_value4: - description: 'A custom value' - type: string - example: '' - tax_amount: - description: 'The tax amount' - type: number - example: 10.00 - tax_name1: - description: 'Tax Name 1' - type: string - example: 'GST' - tax_name2: - description: 'Tax Name 2' - type: string - example: 'VAT' - tax_name3: - description: 'Tax Name 3' - type: string - example: 'IVA' - tax_rate1: - description: 'Tax rate 1' - type: number - format: float - example: '10.00' - tax_rate2: - description: 'Tax rate 2' - type: number - format: float - example: '10.00' - tax_rate3: - description: 'Tax rate 3' - type: number - format: float - example: '10.00' - amount: - description: 'The total expense amont' - type: number - format: float - example: '10.00' - foreign_amount: - description: 'The total foreign amount of the expense' - type: number - format: float - example: '10.00' - exchange_rate: - description: 'The exchange rate at the time of the expense' - type: number - format: float - example: '0.80' - date: - description: 'The expense date format Y-m-d' - type: string - example: '2022-12-01' - payment_date: - description: 'The date of payment for the expense, format Y-m-d' - type: string - example: '2022-12-01' - should_be_invoiced: - description: 'Flag whether the expense should be invoiced' - type: boolean - example: true - is_deleted: - description: 'Boolean determining whether the expense has been deleted' - type: boolean - example: true - invoice_documents: - description: 'Passing the expense documents over to the invoice' - type: boolean - example: true - updated_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - archived_at: - description: Timestamp - type: number - format: integer - example: '1434342123' - type: object ClientSettings: required: - currency_id @@ -21744,221 +19580,2407 @@ components: type: string example: 'Bob Smith' type: object - Quote: + BTRules: + properties: + data_key: + description: 'The key to search' + type: string + example: 'description,amount' + operator: + description: 'The operator flag of the search' + type: string + example: '>' + value: + description: 'The value to search for' + type: string + example: bob + type: object + Account: properties: id: - description: 'The unique hashed identifier for the quote' + description: 'The account hashed id' + type: string + example: AS3df3A + account_sms_verified: + description: 'Boolean flag if the account has been verified by sms' + type: string + example: true + type: object + Invoice: + properties: + id: + description: 'The invoice hashed id' type: string example: Opnel5aKBz + readOnly: true user_id: - description: 'The unique hashed identifier for the user who created the quote' + description: 'The user hashed id' type: string - example: '' + example: Opnel5aKBz + readOnly: true assigned_user_id: - description: 'The unique hashed identifier for the user assigned to the quote' + description: 'The assigned user hashed id' type: string - example: '' + example: Opnel5aKBz client_id: - description: 'The unique hashed identifier for the client associated with the quote' + description: 'The client hashed id' type: string - example: '' + example: Opnel5aKBz status_id: - description: 'The status of the quote represented by a unique identifier' + description: 'The invoice status variable' type: string - example: '' + example: '4' number: - description: 'The unique alpha-numeric quote number for the quote per company' + description: 'The invoice number - is a unique alpha numeric number per invoice per company' type: string - example: QUOTE_101 + example: INV_101 po_number: - description: 'The purchase order number associated with the quote' + description: 'The purchase order associated with this invoice' type: string example: PO-1234 terms: - description: 'The terms and conditions for the quote' + description: 'The invoice terms' type: string - example: 'These are some quote terms. Valid for 14 days.' + example: 'These are invoice terms' public_notes: - description: 'Publicly visible notes associated with the quote' + description: 'The public notes of the invoice' type: string - example: 'These are public notes which the client may see' + example: 'These are some public notes' private_notes: - description: 'Privately visible notes associated with the quote, not disclosed to the client' + description: 'The private notes of the invoice' type: string - example: 'These are private notes, not to be disclosed to the client' + example: 'These are some private notes' footer: - description: 'The footer text of the quote' + description: 'The invoice footer notes' type: string - example: 'The text goes in the footer of the quote' + example: '' custom_value1: - description: 'First custom value field for additional information' + description: 'A custom field value' type: string - example: 'A custom value' + example: '2022-10-01' custom_value2: - description: 'Second custom value field for additional information' + description: 'A custom field value' type: string - example: 'A custom value' + example: 'Something custom' custom_value3: - description: 'Third custom value field for additional information' + description: 'A custom field value' type: string - example: 'A custom value' + example: '' custom_value4: - description: 'Fourth custom value field for additional information' + description: 'A custom field value' type: string - example: 'A custom value' + example: '' tax_name1: - description: 'The name of the first tax applied to the quote' + description: 'The tax name' type: string - example: GST + example: '' tax_name2: - description: 'The name of the second tax applied to the quote' + description: 'The tax name' type: string - example: VAT + example: '' tax_rate1: - description: 'The rate of the first tax applied to the quote' + description: 'The tax rate' type: number format: float - example: 10.00 + example: '10.00' tax_rate2: - description: 'The rate of the second tax applied to the quote' + description: 'The tax rate' type: number format: float - example: 10.00 + example: '10.00' tax_name3: - description: 'The name of the third tax applied to the quote' + description: 'The tax name' type: string example: '' tax_rate3: - description: 'The rate of the third tax applied to the quote' + description: 'The tax rate' type: number format: float - example: 10.00 + example: '10.00' total_taxes: - description: 'The total amount of taxes for the quote' + description: 'The total taxes for the invoice' type: number format: float - example: 10.00 + example: '10.00' line_items: type: array - description: 'An array of objects which define the line items of the quote' + description: 'An array of objects which define the line items of the invoice' items: $ref: '#/components/schemas/InvoiceItem' + invitations: + type: array + description: 'An array of objects which define the invitations of the invoice' + items: + $ref: '#/components/schemas/InvoiceInvitation' amount: - description: 'The total amount of the quote before taxes and discounts' + description: 'The invoice amount' type: number format: float - example: 10.00 + example: '10.00' balance: - description: 'The balance due for the quote after accounting for payments' + description: 'The invoice balance' type: number format: float - example: 10.00 + example: '10.00' paid_to_date: - description: 'The total amount paid on the quote so far' + description: 'The amount paid on the invoice to date' type: number format: float - example: 10.00 + example: '10.00' discount: - description: 'The discount amount or percentage applied to the quote' + description: 'The invoice discount, can be an amount or a percentage' type: number format: float - example: 10.00 + example: '10.00' partial: - description: 'The partial or deposit amount for the quote' + description: 'The deposit/partial amount' type: number format: float - example: 10.00 + example: '10.00' is_amount_discount: - description: 'Boolean flag indicating if the discount is a fixed amount or a percentage' + description: 'Flag determining if the discount is an amount or a percentage' type: boolean example: true is_deleted: - description: 'Boolean flag indicating if the quote has been deleted' + description: 'Defines if the invoice has been deleted' type: boolean - example: false + example: true uses_inclusive_taxes: - description: 'Boolean flag indicating if the taxes used are inclusive or exclusive' + description: 'Defines the type of taxes used as either inclusive or exclusive' type: boolean example: true date: - description: 'The date the quote was created' + description: 'The Invoice Date' type: string format: date example: '1994-07-30' last_sent_date: - description: 'The last date the quote was sent to the client' + description: 'The last date the invoice was sent out' type: string format: date example: '1994-07-30' next_send_date: - description: 'The next scheduled date for sending a reminder for the quote' + description: 'The Next date for a reminder to be sent' type: string format: date example: '1994-07-30' partial_due_date: - description: 'The due date for the partial or deposit amount' + description: 'The due date for the deposit/partial amount' type: string format: date example: '1994-07-30' due_date: - description: 'The due date for the total amount of the quote' + description: 'The due date of the invoice' + type: string + format: date + example: '1994-07-30' + last_viewed: + description: Timestamp + type: number + format: integer + example: '1434342123' + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + custom_surcharge1: + description: 'First Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge2: + description: 'Second Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge3: + description: 'Third Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge4: + description: 'Fourth Custom Surcharge' + type: number + format: float + example: '10.00' + custom_surcharge_tax1: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax2: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax3: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + custom_surcharge_tax4: + description: 'Toggles charging taxes on custom surcharge amounts' + type: boolean + example: true + project_id: + description: 'The project associated with this invoice' + type: string + example: Opnel5aKBz + auto_bill_tries: + description: 'The number of times the invoice has attempted to be auto billed' + type: integer + example: '1' + readOnly: true + auto_bill_enabled: + description: 'Boolean flag determining if the invoice is set to auto bill' + type: boolean + example: true + subscription_id: + description: 'The subscription associated with this invoice' + type: string + example: Opnel5aKBz + + type: object + ClientRequest: + required: + - contacts + - country_id + properties: + id: + description: 'The unique identifier of the client' + type: string + example: Opnel5aKBz + readOnly: true + contacts: + type: array + description: 'A list of contacts associated with the client' + items: + $ref: '#/components/schemas/ClientContactRequest' + name: + description: 'The name of the client company or organization' + type: string + example: "Jim's Housekeeping" + website: + description: 'The website URL of the client company or organization' + type: string + example: 'https://www.jims-housekeeping.com' + private_notes: + description: 'Notes that are only visible to the user who created the client' + type: string + example: 'Client prefers email communication over phone calls' + industry_id: + description: 'The unique identifier of the industry the client operates in' + type: number + example: '5' + size_id: + description: 'The unique identifier for the size category of the client company or organization' + type: number + example: '2' + address1: + description: "First line of the client's address" + type: string + example: '123 Main St' + address2: + description: "Second line of the client's address, if needed" + type: string + example: 'Apt 4B' + city: + description: 'The city the client is located in' + type: string + example: 'Beverly Hills' + state: + description: 'The state, province, or locality the client is located in' + type: string + example: 'California' + postal_code: + description: 'The postal code or ZIP code of the client' + type: string + example: '90210' + phone: + description: "The client's phone number" + type: string + example: '555-3434-3434' + country_id: + description: "The unique identifier of the client's country" + type: number + format: integer + example: '1' + custom_value1: + description: 'A custom field for storing additional information' + type: string + example: 'Preferred contact: Email' + custom_value2: + description: 'A custom field for storing additional information' + type: string + example: 'Account manager: John Doe' + custom_value3: + description: 'A custom field for storing additional information' + type: string + example: 'VIP client: Yes' + custom_value4: + description: 'A custom field for storing additional information' + type: string + example: 'Annual contract value: $50,000' + vat_number: + description: "The client's VAT (Value Added Tax) number, if applicable" + type: string + example: 'VAT123456' + id_number: + description: 'A unique identification number for the client, such as a tax ID or business registration number' + type: string + number: + description: 'A system-assigned unique number for the client, typically used for invoicing purposes' + type: string + example: 'CL-0001' + shipping_address1: + description: "First line of the client's shipping address" + type: string + example: '5 Wallaby Way' + shipping_address2: + description: "Second line of the client's shipping address, if needed" + type: string + example: 'Suite 5' + shipping_city: + description: "The city of the client's shipping address" + type: string + example: 'Perth' + shipping_state: + description: "The state, province, or locality of the client's shipping address" + type: string + example: 'Western Australia' + shipping_postal_code: + description: "The postal code or ZIP code of the client's shipping address" + type: string + example: '6110' + shipping_country_id: + description: "The unique identifier of the country for the client's shipping address" + type: number + format: integer + example: '4' + is_deleted: + description: 'A boolean value indicating whether the client has been deleted or not' + type: boolean + example: false + readOnly: true + group_settings_id: + description: 'The group settings assigned to the client' + type: string + example: Opnel5aKBz + routing_id: + description: 'The routing address id for e-invoicing for this client' + type: string + example: Opnel5aKBz3489-dfkiu-2239-sdsd + is_tax_exempt: + description: 'Flag which defines if the client is exempt from taxes' + type: boolean + example: false + has_valid_vat_number: + description: 'Flag which defines if the client has a valid VAT number' + type: boolean + example: false + readOnly: true + classification: + description: 'The classification of the client' + type: string + example: 'individual' + settings: + $ref: '#/components/schemas/ClientSettings' + type: object + PaymentTerm: + properties: + num_days: + description: 'The payment term length in days' + type: integer + example: '1' + name: + description: 'The payment term length in string format' + type: string + example: 'NET 1' + created_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + updated_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + archived_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + type: object + ClientContactRequest: + properties: + id: + description: 'The hashed if of the contact' + type: string + example: Opnel5aKBz + readOnly: true + first_name: + description: 'The first name of the contact' + type: string + example: John + last_name: + description: 'The last name of the contact' + type: string + example: Doe + phone: + description: 'The phone number of the contact' + type: string + example: 555-152-4524 + custom_value1: + description: 'A Custom field value' + type: string + example: '' + custom_value2: + description: 'A Custom field value' + type: string + example: '' + custom_value3: + description: 'A Custom field value' + type: string + example: '' + custom_value4: + description: 'A Custom field value' + type: string + example: '' + email: + description: 'The email of the contact' + type: string + example: '' + password: + description: 'The hashed password of the contact' + type: string + example: '*****' + send_email: + description: 'Boolean value determines is this contact should receive emails' + type: boolean + example: true + type: object + + GenericBulkAction: + properties: + action: + type: string + example: archive + description: 'The action to perform ie. archive / restore / delete' + ids: + type: array + items: + format: string + type: string + example: 2J234DFA,D2J234DFA,D2J234DFA + description: string array of client hashed ids + type: object + BankTransactionRule: + properties: + id: + description: 'The bank transaction rules hashed id' + type: string + example: AS3df3A + user_id: + description: 'The user hashed id' + type: string + example: AS3df3A + name: + description: 'The name of the transaction' + type: string + example: 'Rule 1' + rules: + description: 'A mapped collection of the sub rules for the BankTransactionRule' + type: array + items: + $ref: '#/components/schemas/BTRules' + auto_convert: + description: 'Flags whether the rule converts the transaction automatically' + type: boolean + example: true + matches_on_all: + description: 'Flags whether all subrules are required for the match' + type: boolean + example: true + applies_to: + description: 'Flags whether the rule applies to a CREDIT or DEBIT' + type: string + example: CREDIT + client_id: + description: 'The client hashed id' + type: string + example: AS3df3A + vendor_id: + description: 'The vendor hashed id' + type: string + example: AS3df3A + category_id: + description: 'The category hashed id' + type: string + example: AS3df3A + type: object + Product: + type: object + properties: + id: + type: string + description: 'The hashed product ID.' + example: eP01N + readOnly: true + user_id: + type: string + description: 'The hashed ID of the user that created this product.' + example: n30m4 + readOnly: true + assigned_user_id: + type: string + description: 'The hashed ID of the user assigned to this product.' + example: pR0j3 + project_id: + type: string + description: 'The hashed ID of the project that this product is associated with.' + example: pR0j3 + vendor_id: + type: string + description: 'The hashed ID of the vendor that this product is associated with.' + example: pR0j3 + custom_value1: + type: string + description: 'Custom value field 1.' + example: 'Custom value 1' + custom_value2: + type: string + description: 'Custom value field 2.' + example: 'Custom value 2' + custom_value3: + type: string + description: 'Custom value field 3.' + example: 'Custom value 3' + custom_value4: + type: string + description: 'Custom value field 4.' + example: 'Custom value 4' + product_key: + type: string + description: 'The product key.' + example: '1234' + notes: + type: string + description: 'Notes about the product.' + example: 'These are some notes about the product.' + cost: + type: number + format: double + description: 'The cost of the product. (Your purchase price for this product)' + example: 10.0 + price: + type: number + format: double + description: 'The price of the product that you are charging.' + example: 20.0 + quantity: + type: number + format: double + description: 'The quantity of the product. (used as a default)' + example: 5.0 + tax_name1: + type: string + description: 'The name of tax 1.' + example: 'Tax 1' + tax_rate1: + type: number + format: double + description: 'The rate of tax 1.' + example: 10.0 + tax_name2: + type: string + description: 'The name of tax 2.' + example: 'Tax 2' + tax_rate2: + type: number + format: double + description: 'The rate of tax 2.' + example: 5.0 + tax_name3: + type: string + description: 'The name of tax 3.' + example: 'Tax 3' + tax_rate3: + type: number + format: double + description: 'The rate of tax 3.' + example: 0.0 + archived_at: + type: integer + format: timestamp + description: 'The timestamp when the product was archived.' + example: '2022-03-18T15:00:00Z' + readOnly: true + created_at: + type: integer + format: timestamp + description: 'The timestamp when the product was created.' + example: '2022-03-18T15:00:00Z' + readOnly: true + updated_at: + description: Timestamp + type: integer + format: timestamp + example: '2022-03-18T12:34:56.789Z' + readOnly: true + is_deleted: + type: boolean + description: 'Boolean flag determining if the product has been deleted' + example: false + readOnly: true + in_stock_quantity: + type: integer + format: int32 + description: The quantity of the product that is currently in stock + default: 0 + stock_notification: + type: boolean + description: Indicates whether stock notifications are enabled for this product + default: true + stock_notification_threshold: + type: integer + format: int32 + description: The minimum quantity threshold for which stock notifications will be triggered + default: 0 + max_quantity: + type: integer + format: int32 + description: The maximum quantity that can be ordered for this product + product_image: + type: string + description: The URL of the product image + format: uri-reference + tax_id: + type: string + default: '1' + description: | + The tax category id for this product.' + + The following constants are available (default = '1') + + ``` + PRODUCT_TYPE_PHYSICAL = '1' + PRODUCT_TYPE_SERVICE = '2' + PRODUCT_TYPE_DIGITAL = '3' + PRODUCT_TYPE_SHIPPING = '4' + PRODUCT_TYPE_EXEMPT = '5' + PRODUCT_TYPE_REDUCED_TAX = '6' + PRODUCT_TYPE_OVERRIDE_TAX = '7' + PRODUCT_TYPE_ZERO_RATED = '8' + PRODUCT_TYPE_REVERSE_TAX = '9' + ``` + example: '1' + + RecurringQuote: + properties: + id: + description: 'The hashed id of the recurring quote' + type: string + example: Opnel5aKBz + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The assigned user hashed id' + type: string + example: Opnel5aKBz + client_id: + description: 'The client hashed id' + type: string + example: Opnel5aKBz + status_id: + description: 'The quote status variable' + type: string + example: '4' + frequency_id: + description: 'The recurring quote frequency' + type: number + example: '4' + remaining_cycles: + description: 'The number of quotes left to be generated' + type: number + example: '4' + number: + description: 'The recurringquote number - is a unique alpha numeric number per quote per company' + type: string + example: INV_101 + po_number: + description: 'The purchase order associated with this recurring quote' + type: string + example: PO-1234 + terms: + description: 'The quote terms' + type: string + example: 'These are quote terms' + public_notes: + description: 'The public notes of the quote' + type: string + example: 'These are some public notes' + private_notes: + description: 'The private notes of the quote' + type: string + example: 'These are some private notes' + footer: + description: 'The quote footer notes' + type: string + example: '' + custom_value1: + description: 'A custom field value' + type: string + example: '2022-10-01' + custom_value2: + description: 'A custom field value' + type: string + example: 'Something custom' + custom_value3: + description: 'A custom field value' + type: string + example: '' + custom_value4: + description: 'A custom field value' + type: string + example: '' + tax_name1: + description: 'The tax name' + type: string + example: '' + tax_name2: + description: 'The tax name' + type: string + example: '' + tax_rate1: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_rate2: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_name3: + description: 'The tax name' + type: string + example: '' + tax_rate3: + description: 'The tax rate' + type: number + format: float + example: '10.00' + total_taxes: + description: 'The total taxes for the quote' + type: number + format: float + example: '10.00' + line_items: + description: 'An array of objects which define the line items of the quote' + type: object + example: '' + amount: + description: 'The quote amount' + type: number + format: float + example: '10.00' + balance: + description: 'The quote balance' + type: number + format: float + example: '10.00' + paid_to_date: + description: 'The amount paid on the quote to date' + type: number + format: float + example: '10.00' + discount: + description: 'The quote discount, can be an amount or a percentage' + type: number + format: float + example: '10.00' + partial: + description: 'The deposit/partial amount' + type: number + format: float + example: '10.00' + is_amount_discount: + description: 'Flag determining if the discount is an amount or a percentage' + type: boolean + example: true + is_deleted: + description: 'Defines if the quote has been deleted' + type: boolean + example: true + uses_inclusive_taxes: + description: 'Defines the type of taxes used as either inclusive or exclusive' + type: boolean + example: true + date: + description: 'The quote Date' + type: string + format: date + example: '1994-07-30' + last_sent_date: + description: 'The last date the quote was sent out' + type: string + format: date + example: '1994-07-30' + next_send_date: + description: 'The Next date for a reminder to be sent' + type: string + format: date + example: '1994-07-30' + partial_due_date: + description: 'The due date for the deposit/partial amount' + type: string + format: date + example: '1994-07-30' + due_date: + description: 'The due date of the quote' type: string format: date example: '1994-07-30' settings: $ref: '#/components/schemas/CompanySettings' last_viewed: - description: 'The timestamp of the last time the quote was viewed' + description: Timestamp type: number format: integer - example: 1434342123 + example: '1434342123' updated_at: - description: 'The timestamp of the last update to the quote' + description: Timestamp type: number format: integer - example: 1434342123 + example: '1434342123' archived_at: - description: 'The timestamp of when the quote was archived' + description: Timestamp type: number format: integer - example: 1434342123 + example: '1434342123' custom_surcharge1: - description: 'First custom surcharge amount for the quote' + description: 'First Custom Surcharge' type: number format: float - example: 10.00 + example: '10.00' custom_surcharge2: - description: 'Second custom surcharge amount for the quote' + description: 'Second Custom Surcharge' type: number format: float - example: 10.00 + example: '10.00' custom_surcharge3: - description: 'Third custom surcharge amount for the quote' + description: 'Third Custom Surcharge' type: number format: float - example: 10.00 + example: '10.00' custom_surcharge4: - description: 'Fourth custom surcharge amount for the quote' + description: 'Fourth Custom Surcharge' type: number format: float - example: 10.00 + example: '10.00' custom_surcharge_tax1: - description: 'Boolean flag indicating if taxes are charged on the first custom surcharge amount' + description: 'Toggles charging taxes on custom surcharge amounts' type: boolean example: true custom_surcharge_tax2: - description: 'Boolean flag indicating if taxes are charged on the second custom surcharge amount' + description: 'Toggles charging taxes on custom surcharge amounts' type: boolean example: true custom_surcharge_tax3: - description: 'Boolean flag indicating if taxes are charged on the third custom surcharge amount' + description: 'Toggles charging taxes on custom surcharge amounts' type: boolean example: true custom_surcharge_tax4: - description: 'Boolean flag indicating if taxes are charged on the fourth custom surcharge amount' + description: 'Toggles charging taxes on custom surcharge amounts' type: boolean example: true type: object + Paymentable: + properties: + id: + description: 'The paymentable hashed id' + type: string + example: AS3df3A + invoice_id: + description: 'The invoice hashed id' + type: string + example: AS3df3A + credit_id: + description: 'The credit hashed id' + type: string + example: AS3df3A + refunded: + description: 'The amount that has been refunded for this payment' + type: number + format: float + example: '10.00' + amount: + description: 'The amount that has been applied to the payment' + type: number + format: float + example: '10.00' + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + created_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + type: object + SystemLog: + properties: + id: + description: 'The account hashed id' + type: string + example: AS3df3A + user_id: + description: 'The user_id hashed id' + type: string + example: AS3df3A + client_id: + description: 'The client_id hashed id' + type: string + example: AS3df3A + event_id: + description: 'The Log Type ID' + type: integer + example: 1 + category_id: + description: 'The Category Type ID' + type: integer + example: 1 + type_id: + description: 'The Type Type ID' + type: integer + example: 1 + log: + description: 'The json object of the error' + type: object + example: '{''key'':''value''}' + updated_at: + description: Timestamp + type: string + example: '2' + created_at: + description: Timestamp + type: string + example: '2' + type: object + BankTransaction: + properties: + id: + description: 'The bank integration hashed id' + type: string + example: AS3df3A + user_id: + description: 'The user hashed id' + type: string + example: AS3df3A + transaction_id: + description: 'The id of the transaction rule' + type: integer + example: 343434 + amount: + description: 'The transaction amount' + type: number + example: 10 + currency_id: + description: 'The currency ID of the currency' + type: string + example: '1' + account_type: + description: 'The account type' + type: string + example: creditCard + description: + description: 'The description of the transaction' + type: string + example: 'Potato purchases for kevin' + category_id: + description: 'The category id' + type: integer + example: 1 + category_type: + description: 'The category description' + type: string + example: Expenses + base_type: + description: 'Either CREDIT or DEBIT' + type: string + example: CREDIT + date: + description: 'The date of the transaction' + type: string + example: '2022-09-01' + bank_account_id: + description: 'The ID number of the bank account' + type: integer + example: '1' + type: object + + ProductBulkAction: + required: + - action + - ids + properties: + action: + type: string + example: archive + description: 'The action to perform ie. archive / restore / delete / set_tax_id' + ids: + type: array + items: + format: string + type: string + example: 2J234DFA,D2J234DFA,D2J234DFA + description: string array of client hashed ids + tax_id: + type: string + example: '1' + description: | + The tax rate id to set on the list of products + + The following constants are available (default = '1') + + ``` + PRODUCT_TYPE_PHYSICAL = '1' + PRODUCT_TYPE_SERVICE = '2' + PRODUCT_TYPE_DIGITAL = '3' + PRODUCT_TYPE_SHIPPING = '4' + PRODUCT_TYPE_EXEMPT = '5' + PRODUCT_TYPE_REDUCED_TAX = '6' + PRODUCT_TYPE_OVERRIDE_TAX = '7' + PRODUCT_TYPE_ZERO_RATED = '8' + PRODUCT_TYPE_REVERSE_TAX = '9' + ``` + type: object + FillableInvoice: + properties: + assigned_user_id: + description: "The assigned user's hashed ID" + type: string + example: 'a1b2c3d4' + client_id: + description: "The client's hashed ID" + type: string + example: 'x1y2z3a4' + number: + description: "The unique alphanumeric invoice number for each invoice per company" + type: string + example: INV_101 + po_number: + description: "The purchase order number associated with the invoice" + type: string + example: 'PO12345' + terms: + description: "The terms and conditions for the invoice" + type: string + example: 'Net 30' + public_notes: + description: "Public notes visible to the client on the invoice" + type: string + example: 'Thank you for your business.' + private_notes: + description: "Private notes for internal use only" + type: string + example: 'Client is a slow payer.' + footer: + description: "The footer text displayed on the invoice" + type: string + example: 'Authorized Signature' + custom_value1: + description: "First custom value for additional information" + type: string + example: 'Project ABC' + custom_value2: + description: "Second custom value for additional information" + type: string + example: 'Department XYZ' + custom_value3: + description: "Third custom value for additional information" + type: string + example: 'Location 123' + custom_value4: + description: "Fourth custom value for additional information" + type: string + example: 'Currency USD' + tax_name1: + description: "Name of the first tax applied to the invoice" + type: string + example: 'VAT' + tax_name2: + description: "Name of the second tax applied to the invoice" + type: string + example: 'GST' + tax_rate1: + description: "Rate of the first tax applied to the invoice" + type: number + example: 10.00 + tax_rate2: + description: "Rate of the second tax applied to the invoice" + type: number + example: 5.00 + tax_name3: + description: "Name of the third tax applied to the invoice" + type: string + example: 'PST' + tax_rate3: + description: "Rate of the third tax applied to the invoice" + type: number + example: 8.00 + line_items: + type: array + description: 'An array of objects which define the line items of the invoice' + items: + $ref: '#/components/schemas/InvoiceItem' + discount: + description: "The discount applied to the invoice" + type: number + example: 10.00 + partial: + description: "The partial amount applied to the invoice" + type: number + example: 20.00 + is_amount_discount: + description: "Indicates whether the discount applied is a fixed amount or a percentage" + type: boolean + example: true + uses_inclusive_taxes: + description: "Indicates whether the tax rates applied to the invoice are inclusive or exclusive" + type: boolean + example: true + date: + description: "The date the invoice was issued" + type: string + example: '1994-07-30' + partial_due_date: + description: "The due date for the partial payment" + type: string + example: '1994-08-15' + due_date: + description: "The due date for the invoice" + type: string + example: '1994-08-30' + custom_surcharge1: + description: "First custom surcharge applied to the invoice" + type: number + example: 10.00 + custom_surcharge2: + description: "Second custom surcharge applied to the invoice" + type: number + example: 15.00 + custom_surcharge3: + description: "Third custom surcharge applied to the invoice" + type: number + example: 5.00 + custom_surcharge4: + description: "Fourth custom surcharge applied to the invoice" + type: number + example: 20.00 + type: object + CompanyGateway: + properties: + id: + description: 'The hashed id of the company gateway' + type: string + example: Opnel5aKBz + gateway_key: + description: 'The gateway key (hash)' + type: string + example: '2' + accepted_credit_cards: + description: 'Bitmask representation of cards' + type: integer + example: '32' + require_billing_address: + description: 'Determines if the the billing address is required prior to payment.' + type: boolean + example: true + require_shipping_address: + description: 'Determines if the the billing address is required prior to payment.' + type: boolean + example: true + config: + description: 'The configuration map for the gateway' + type: string + example: dfadsfdsafsafd + update_details: + description: 'Determines if the client details should be updated.' + type: boolean + example: true + fees_and_limits: + description: 'A mapped collection of the fees and limits for the configured gateway' + type: array + items: + $ref: '#/components/schemas/FeesAndLimits' + type: object + + + Activity: + properties: + id: + description: 'The id field of the activity' + type: string + example: Opnel5aKBz + activity_type_id: + description: 'The activity type id' + type: string + example: Opnel5aKBz + client_id: + description: 'The client hashed id' + type: string + example: Opnel5aKBz + company_id: + description: 'The company hashed id' + type: string + example: Opnel5aKBz + user_id: + description: 'The user hashed id' + type: string + example: Opnel5aKBz + invoice_id: + description: 'The invoice hashed id' + type: string + example: Opnel5aKBz + payment_id: + description: 'The payment hashed id' + type: string + example: Opnel5aKBz + credit_id: + description: 'The credit hashed id' + type: string + example: Opnel5aKBz + updated_at: + description: 'Unixtimestamp the last time the record was updated' + type: integer + example: '343421434' + expense_id: + description: 'The expense hashed id' + type: string + example: Opnel5aKBz + is_system: + description: 'Defines is the activity was performed by the system' + type: boolean + example: true + contact_id: + description: 'The contact hashed id' + type: string + example: Opnel5aKBz + task_id: + description: 'The task hashed id' + type: string + example: Opnel5aKBz + notes: + description: 'Activity Notes' + type: string + example: Opnel5aKBz + token_id: + description: 'The hashed ID of the token who performed the action' + type: string + example: Opnel5aKBz + ip: + description: 'The IP Address of the user who performed the action' + type: string + example: 192.168.1.252 + user: + $ref: '#/components/schemas/User' + client: + $ref: '#/components/schemas/Client' + contact: + $ref: '#/components/schemas/ClientContact' + recurring_invoice: + $ref: '#/components/schemas/RecurringInvoice' + invoice: + $ref: '#/components/schemas/Invoice' + credit: + $ref: '#/components/schemas/Credit' + quote: + $ref: '#/components/schemas/Quote' + payment: + $ref: '#/components/schemas/Payment' + expense: + $ref: '#/components/schemas/Expense' + task: + $ref: '#/components/schemas/Task' + purchase_order: + $ref: '#/components/schemas/PurchaseOrder' + vendor: + $ref: '#/components/schemas/Vendor' + vendor_contact: + $ref: '#/components/schemas/VendorContact' + type: object + User: + properties: + id: + description: 'The hashed id of the user' + type: string + example: Opnel5aKBz + readOnly: true + first_name: + description: 'The first name of the user' + type: string + example: Brad + last_name: + description: 'The last name of the user' + type: string + example: Pitt + email: + description: 'The users email address' + type: string + example: brad@pitt.com + phone: + description: 'The users phone number' + type: string + example: 555-1233-23232 + signature: + description: 'The users sign off signature' + type: string + example: 'Have a nice day!' + avatar: + description: 'The users avatar' + type: string + example: 'https://url.to.your/avatar.png' + accepted_terms_version: + description: 'The version of the invoice ninja terms that has been accepted by the user' + type: string + example: 1.0.1 + readOnly: true + oauth_user_id: + description: 'The provider id of the oauth entity' + type: string + example: jkhasdf789as6f675sdf768sdfs + readOnly: true + oauth_provider_id: + description: 'The oauth entity id' + type: string + example: google + readOnly: true + language_id: + description: 'The language id of the user' + type: string + example: 1 + verified_phone_number: + description: 'Boolean flag if the user has their phone verified. Required to settings up 2FA' + type: boolean + example: true + readOnly: true + sms_verification_code: + description: 'The sms verification code for the user. Required to settings up 2FA' + type: string + example: '123456' + readOnly: true + oauth_user_token_expiry: + description: 'The expiry date of the oauth token' + type: string + example: '2022-10-10' + readOnly: true + has_password: + description: 'Boolean flag determining if the user has a password' + type: boolean + example: true + readOnly: true + last_confirmed_email_address: + description: 'The last confirmed email address of the user' + type: string + example: 'bob@gmail.com' + readOnly: true + custom_value1: + description: 'A custom value' + type: string + example: 'Custom value 1' + custom_value2: + description: 'A custom value' + type: string + example: '$1000' + custom_value3: + description: 'A custom value' + type: string + example: 'Custom value 3' + custom_value4: + description: 'A custom value' + type: string + example: 'Custom value 4' + is_deleted: + description: 'Boolean flag determining if the user has been deleted' + type: boolean + example: true + readOnly: true + google_2fa_secret: + description: 'The google 2fa secret for the user' + type: string + example: '123456' + readOnly: true + company_user: + $ref: '#/components/schemas/CompanyUserRef' + type: object + UserRef: + properties: + id: + description: 'The hashed id of the user' + type: string + example: Opnel5aKBz + readOnly: true + first_name: + description: 'The first name of the user' + type: string + example: Brad + last_name: + description: 'The last name of the user' + type: string + example: Pitt + email: + description: 'The users email address' + type: string + example: brad@pitt.com + phone: + description: 'The users phone number' + type: string + example: 555-1233-23232 + signature: + description: 'The users sign off signature' + type: string + example: 'Have a nice day!' + avatar: + description: 'The users avatar' + type: string + example: 'https://url.to.your/avatar.png' + accepted_terms_version: + description: 'The version of the invoice ninja terms that has been accepted by the user' + type: string + example: 1.0.1 + readOnly: true + oauth_user_id: + description: 'The provider id of the oauth entity' + type: string + example: jkhasdf789as6f675sdf768sdfs + readOnly: true + oauth_provider_id: + description: 'The oauth entity id' + type: string + example: google + readOnly: true + language_id: + description: 'The language id of the user' + type: string + example: 1 + verified_phone_number: + description: 'Boolean flag if the user has their phone verified. Required to settings up 2FA' + type: boolean + example: true + readOnly: true + sms_verification_code: + description: 'The sms verification code for the user. Required to settings up 2FA' + type: string + example: '123456' + readOnly: true + oauth_user_token_expiry: + description: 'The expiry date of the oauth token' + type: string + example: '2022-10-10' + readOnly: true + has_password: + description: 'Boolean flag determining if the user has a password' + type: boolean + example: true + readOnly: true + last_confirmed_email_address: + description: 'The last confirmed email address of the user' + type: string + example: 'bob@gmail.com' + readOnly: true + custom_value1: + description: 'A custom value' + type: string + example: 'Custom value 1' + custom_value2: + description: 'A custom value' + type: string + example: '$1000' + custom_value3: + description: 'A custom value' + type: string + example: 'Custom value 3' + custom_value4: + description: 'A custom value' + type: string + example: 'Custom value 4' + is_deleted: + description: 'Boolean flag determining if the user has been deleted' + type: boolean + example: true + readOnly: true + google_2fa_secret: + description: 'The google 2fa secret for the user' + type: string + example: '123456' + readOnly: true + type: object + CompanyUser: + properties: + permissions: + description: 'The user permissionsfor this company in a comma separated list' + type: string + example: 'create_invoice,create_client,view_client' + settings: + description: 'Settings that are used for the flutter applications to store user preferences / metadata' + type: object + readOnly: true + react_settings: + description: 'Dedicated settings object for the react web application' + type: object + readOnly: true + is_owner: + description: 'Determines whether the user owns this company' + type: boolean + example: true + readOnly: true + is_admin: + description: 'Determines whether the user is the admin of this company' + type: boolean + example: true + readOnly: true + is_locked: + description: 'Determines whether the users access to this company has been locked' + type: boolean + example: true + readOnly: true + updated_at: + description: 'The last time the record was modified, format Unix Timestamp' + type: integer + example: '1231232312321' + deleted_at: + description: 'Timestamp when the user was archived, format Unix Timestamp' + type: integer + example: '12312312321' + account: + $ref: '#/components/schemas/Account' + company: + $ref: '#/components/schemas/Company' + user: + $ref: '#/components/schemas/UserRef' + token: + $ref: '#/components/schemas/CompanyToken' + type: object + CompanyUserRef: + properties: + permissions: + description: 'The user permissionsfor this company in a comma separated list' + type: string + example: 'create_invoice,create_client,view_client' + settings: + description: 'Settings that are used for the flutter applications to store user preferences / metadata' + type: object + readOnly: true + react_settings: + description: 'Dedicated settings object for the react web application' + type: object + readOnly: true + is_owner: + description: 'Determines whether the user owns this company' + type: boolean + example: true + readOnly: true + is_admin: + description: 'Determines whether the user is the admin of this company' + type: boolean + example: true + readOnly: true + is_locked: + description: 'Determines whether the users access to this company has been locked' + type: boolean + example: true + readOnly: true + updated_at: + description: 'The last time the record was modified, format Unix Timestamp' + type: integer + example: '1231232312321' + deleted_at: + description: 'Timestamp when the user was archived, format Unix Timestamp' + type: integer + example: '12312312321' + account: + $ref: '#/components/schemas/Account' + company: + $ref: '#/components/schemas/Company' + user: + $ref: '#/components/schemas/UserRef' + token: + $ref: '#/components/schemas/CompanyToken' + type: object + RecurringExpense: + properties: + id: + description: 'The hashed id of the recurring expense' + type: string + example: Opnel5aKBz + user_id: + description: 'The hashed id of the user who created the recurring expense' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The hashed id of the user assigned to this recurring expense' + type: string + example: Opnel5aKBz + client_id: + description: 'The hashed id of the client' + type: string + example: Opnel5aKBz + invoice_id: + description: 'The hashed id of the invoice' + type: string + example: Opnel5aKBz + bank_id: + description: 'The id of the bank associated with this recurring expense' + type: string + example: '22' + invoice_currency_id: + description: 'The currency id of the invoice associated with this recurring expense' + type: string + example: '1' + expense_currency_id: + description: 'The currency id of the expense associated with this recurring expense' + type: string + example: '1' + invoice_category_id: + description: 'The category id of the invoice' + type: string + example: '1' + payment_type_id: + description: 'The payment type id' + type: string + example: '1' + private_notes: + description: 'The recurring expense private notes' + type: string + example: 'Private and confidential' + public_notes: + description: 'The recurring expense public notes' + type: string + example: 'This is the best client in the world' + transaction_reference: + description: 'The recurring expense transaction reference' + type: string + example: EXP-1223-2333 + transcation_id: + description: 'The transaction id of the recurring expense' + type: string + example: '1233312312' + custom_value1: + description: 'Custom value field' + type: string + example: $1000 + custom_value2: + description: 'Custom value field' + type: string + example: '2022-10-10' + custom_value3: + description: 'Custom value field' + type: string + example: 'short text' + custom_value4: + description: 'Custom value field' + type: string + example: 'very long text' + tax_name1: + description: 'The tax name' + type: string + example: GST + tax_name2: + description: 'The tax name' + type: string + example: VAT + tax_rate1: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_rate2: + description: 'The tax rate' + type: number + format: float + example: '10.00' + tax_name3: + description: 'The tax name' + type: string + example: '' + tax_rate3: + description: 'The tax rate' + type: number + format: float + example: '10.00' + amount: + description: 'The total amount of the recurring expense' + type: number + format: float + example: '10.00' + frequency_id: + description: 'The frequency this recurring expense fires' + type: number + format: int + example: '1' + remaining_cycles: + description: 'The number of remaining cycles for this recurring expense' + type: number + format: int + example: '1' + foreign_amount: + description: 'The foreign currency amount of the recurring expense' + type: number + format: float + example: '10.00' + exchange_rate: + description: 'The exchange rate for the expernse' + type: number + format: float + example: '0.80' + date: + description: 'The date of the expense' + type: string + example: '' + payment_date: + description: 'The date the expense was paid' + type: string + example: '' + should_be_invoiced: + description: 'Boolean flag determining if the expense should be invoiced' + type: boolean + example: true + is_deleted: + description: 'Boolean flag determining if the recurring expense is deleted' + type: boolean + example: true + last_sent_date: + description: 'The Date it was sent last' + type: string + format: date + example: '1994-07-30' + next_send_date: + description: 'The next send date' + type: string + format: date + example: '1994-07-30' + invoice_documents: + description: 'Boolean flag determining if the documents associated with this expense should be passed onto the invoice if it is converted to an invoice' + type: boolean + example: true + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + type: object + ClientContact: + properties: + id: + description: 'The hashed if of the contact' + type: string + example: Opnel5aKBz + readOnly: true + user_id: + description: 'The hashed id of the user who created the contact' + type: string + example: Opnel5aKBz + readOnly: true + client_id: + description: 'The hashed id of the client' + type: string + example: Opnel5aKBz + readOnly: true + first_name: + description: 'The first name of the contact' + type: string + example: John + last_name: + description: 'The last name of the contact' + type: string + example: Doe + phone: + description: 'The phone number of the contact' + type: string + example: 555-152-4524 + custom_value1: + description: 'A Custom field value' + type: string + example: '' + custom_value2: + description: 'A Custom field value' + type: string + example: '' + custom_value3: + description: 'A Custom field value' + type: string + example: '' + custom_value4: + description: 'A Custom field value' + type: string + example: '' + email: + description: 'The email of the contact' + type: string + example: '' + accepted_terms_version: + description: 'The terms of service which the contact has accpeted' + type: string + example: 'A long set of ToS' + readOnly: true + password: + description: 'The hashed password of the contact' + type: string + example: '*****' + confirmation_code: + description: 'The confirmation code used to authenticate the contacts email address' + type: string + example: 333-sdjkh34gbasd + readOnly: true + token: + description: 'A uuid based token.' + type: string + example: 333-sdjkh34gbasd + readOnly: true + contact_key: + description: 'A unique identifier for the contact' + type: string + example: JD0X52bkfZlJRiroCJ0tcSiAjsJTntZ5uqKdiZ0a + readOnly: true + is_primary: + description: 'Defines is this contact is the primary contact for the client' + type: boolean + example: true + confirmed: + description: 'Boolean value confirms the user has confirmed their account.' + type: boolean + example: true + is_locked: + description: 'Boolean value defines if the contact has been locked out.' + type: boolean + example: true + send_email: + description: 'Boolean value determines is this contact should receive emails' + type: boolean + example: true + failed_logins: + description: 'The number of failed logins the contact has had' + type: number + format: integer + example: '3' + readOnly: true + email_verified_at: + description: 'The date which the contact confirmed their email' + type: number + format: integer + example: '134341234234' + readOnly: true + last_login: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + created_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + updated_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + deleted_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + type: object + Expense: + properties: + id: + description: 'The expense hashed id' + type: string + example: 'Opnel5aKBz' + user_id: + description: 'The user hashed id' + type: string + example: 'Opnel5aKBz' + assigned_user_id: + description: 'The assigned user hashed id' + type: string + example: 'Opnel5aKBz' + project_id: + description: 'The associated project_id' + type: string + example: 'Opnel5aKBz' + client_id: + description: 'The client hashed id' + type: string + example: 'Opnel5aKBz' + invoice_id: + description: 'The related invoice hashed id' + type: string + example: 'Opnel5aKBz' + bank_id: + description: 'The bank id related to this expense' + type: string + example: '' + invoice_currency_id: + description: 'The currency id of the related invoice' + type: string + example: '1' + currency_id: + description: 'The currency id of the expense' + type: string + example: '2' + invoice_category_id: + description: 'The invoice category id' + type: string + example: 'Opnel5aKBz' + payment_type_id: + description: 'The payment type id' + type: string + example: '' + recurring_expense_id: + description: 'The related recurring expense this expense was created from' + type: string + example: 'Opnel5aKBz' + private_notes: + description: 'The private notes of the expense' + type: string + example: '' + public_notes: + description: 'The public notes of the expense' + type: string + example: '' + transaction_reference: + description: 'The transaction references of the expense' + type: string + example: '' + transcation_id: + description: 'The transaction id of the expense' + type: string + example: '' + custom_value1: + description: 'A custom value' + type: string + example: '' + custom_value2: + description: 'A custom value' + type: string + example: '' + custom_value3: + description: 'A custom value' + type: string + example: '' + custom_value4: + description: 'A custom value' + type: string + example: '' + tax_amount: + description: 'The tax amount' + type: number + example: 10.00 + tax_name1: + description: 'Tax Name 1' + type: string + example: 'GST' + tax_name2: + description: 'Tax Name 2' + type: string + example: 'VAT' + tax_name3: + description: 'Tax Name 3' + type: string + example: 'IVA' + tax_rate1: + description: 'Tax rate 1' + type: number + format: float + example: '10.00' + tax_rate2: + description: 'Tax rate 2' + type: number + format: float + example: '10.00' + tax_rate3: + description: 'Tax rate 3' + type: number + format: float + example: '10.00' + amount: + description: 'The total expense amont' + type: number + format: float + example: '10.00' + foreign_amount: + description: 'The total foreign amount of the expense' + type: number + format: float + example: '10.00' + exchange_rate: + description: 'The exchange rate at the time of the expense' + type: number + format: float + example: '0.80' + date: + description: 'The expense date format Y-m-d' + type: string + example: '2022-12-01' + payment_date: + description: 'The date of payment for the expense, format Y-m-d' + type: string + example: '2022-12-01' + should_be_invoiced: + description: 'Flag whether the expense should be invoiced' + type: boolean + example: true + is_deleted: + description: 'Boolean determining whether the expense has been deleted' + type: boolean + example: true + invoice_documents: + description: 'Passing the expense documents over to the invoice' + type: boolean + example: true + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + type: object + Task: + properties: + id: + description: 'The hashed id of the task' + type: string + example: Opnel5aKBz + user_id: + description: 'The hashed id of the user who created the task' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The assigned user of the task' + type: string + example: Opnel5aKBz + client_id: + description: 'The hashed if of the client' + type: string + example: Opnel5aKBz + invoice_id: + description: 'The hashed id of the invoice associated with the task' + type: string + example: Opnel5aKBz + project_id: + description: 'The hashed id of the project associated with the task' + type: string + example: Opnel5aKBz + number: + description: 'The number of the task' + type: string + example: TASK-123 + time_log: + description: 'An array of unix time stamps defining the start and end times of the task' + type: string + example: '[[1,2],[3,4]]' + is_running: + description: 'Determines if the task is still running' + type: boolean + example: true + is_deleted: + description: 'Boolean flag determining if the task has been deleted' + type: boolean + example: true + task_status_id: + description: 'The hashed id of the task status' + type: string + example: Opnel5aKBz + description: + description: 'The task description' + type: string + example: 'A wonder task to work on' + duration: + description: 'The task duration in seconds' + type: integer + example: '3600' + task_status_order: + description: 'The order of the task' + type: integer + example: '4' + rate: + description: 'The task rate' + type: number + example: 10.00 + custom_value1: + description: 'A custom value' + type: string + example: '2022-10-10' + custom_value2: + description: 'A custom value' + type: string + example: $1100 + custom_value3: + description: 'A custom value' + type: string + example: 'I need help' + custom_value4: + description: 'A custom value' + type: string + example: INV-3343 + is_date_based: + description: 'Boolean flag determining if the task is date based' + type: boolean + example: true + calculated_start_date: + description: 'The calculated start date of the task' + type: string + example: '2022-10-10' + readOnly: true + invoice_documents: + description: "Boolean flags which determines whether to include the task documents on the invoice" + type: boolean + example: true + created_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + updated_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + archived_at: + description: Timestamp + type: number + format: integer + example: '1434342123' + readOnly: true + type: object + + FeesAndLimits: + properties: + min_limit: + description: 'The minimum amount accepted for this gateway' + type: string + example: '2' + max_limit: + description: 'The maximum amount accepted for this gateway' + type: string + example: '2' + fee_amount: + description: 'The gateway fee amount' + type: number + format: float + example: '2.0' + fee_percent: + description: 'The gateway fee percentage' + type: number + format: float + example: '2.0' + fee_tax_name1: + description: 'Fee tax name' + type: string + example: GST + fee_tax_name2: + description: 'Fee tax name' + type: string + example: VAT + fee_tax_name3: + description: 'Fee tax name' + type: string + example: 'CA Sales Tax' + fee_tax_rate1: + description: 'The tax rate' + type: number + format: float + example: '10.0' + fee_tax_rate2: + description: 'The tax rate' + type: number + format: float + example: '17.5' + fee_tax_rate3: + description: 'The tax rate' + type: number + format: float + example: '25.0' + fee_cap: + description: 'If set the fee amount will be no higher than this amount' + type: number + format: float + example: '2.0' + adjust_fee_percent: + description: 'Adjusts the fee to match the exact gateway fee.' + type: boolean + example: true + type: object + Vendor: + properties: + id: + description: 'The hashed id of the vendor. This is a unique identifier for the vendor.' + type: string + example: Opnel5aKBz + readOnly: true + user_id: + description: 'The hashed id of the user who created the vendor. This is a unique identifier for the user.' + type: string + example: Opnel5aKBz + assigned_user_id: + description: 'The hashed id of the assigned user to this vendor. This is a unique identifier for the user.' + type: string + example: Opnel5aKBz + contacts: + type: array + items: + $ref: '#/components/schemas/VendorContact' + description: 'An array of contacts associated with the vendor.' + name: + description: 'The name of the vendor.' + type: string + example: 'Harry cafe de wheels' + classification: + description: 'The classification of the vendor.' + type: string + example: 'individual' + website: + description: 'The website of the vendor.' + type: string + example: www.harry.com + private_notes: + description: 'The private notes of the vendor. These notes are only visible to users with appropriate permissions.' + type: string + example: 'Shhh, do not tell the vendor' + industry_id: + description: 'The industry id of the vendor. This is a unique identifier for the industry.' + type: string + example: '1' + size_id: + description: 'The size id of the vendor. This is a unique identifier for the size of the vendor.' + type: string + example: '' + address1: + description: 'The first line of the vendor''s address.' + type: string + example: '' + address2: + description: 'The second line of the vendor''s address.' + type: string + example: '' + city: + description: 'The city of the vendor''s address.' + type: string + example: '' + state: + description: 'The state of the vendor''s address.' + type: string + example: '' + postal_code: + description: 'The postal code of the vendor''s address.' + type: string + example: '' + phone: + description: 'The phone number of the vendor.' + type: string + example: 555-3434-3434 + country_id: + description: 'The country id of the vendor. This is a unique identifier for the country.' + type: string + example: '' + currency_id: + description: 'The currency id of the vendor. This is a unique identifier for the currency.' + type: string + example: '4' + custom_value1: + description: 'The value of the first custom field for the vendor.' + type: string + example: '' + custom_value2: + description: 'The value of the second custom field for the vendor.' + type: string + example: '' + custom_value3: + description: 'The value of the third custom field for the vendor.' + type: string + example: '' + custom_value4: + description: 'The value of the fourth custom field for the vendor.' + type: string + example: '' + vat_number: + description: 'The VAT number of the vendor.' + type: string + example: '' + id_number: + description: 'The ID number of the vendor.' + type: string + example: '' + number: + description: 'The number of the vendor' + type: string + example: '11234' + is_deleted: + description: 'Boolean flag determining if the vendor has been deleted' + type: boolean + example: true + language_id: + description: 'The language id of the vendor. This is a unique identifier for the language.' + type: string + example: '1' + vendor_hash: + description: 'The vendor hash of the vendor. This is a unique identifier for the vendor.' + type: string + example: 'aaa-sss-www' + readOnly: true + transaction_name: + description: 'The transaction name of the vendor.' + type: string + example: 'aaa-sss-www' + last_login: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + created_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + updated_at: + description: Timestamp + type: number + format: integer + example: '134341234234' + readOnly: true + display_name: + description: 'The display name of the vendor.' + type: string + example: 'Bob the vendor' + readOnly: true + type: object tags: - name: login description: | diff --git a/openapi/paths.yaml b/openapi/paths.yaml index e8a45b8fd7f8..64e5e2e549cc 100644 --- a/openapi/paths.yaml +++ b/openapi/paths.yaml @@ -998,7 +998,7 @@ paths: post: tags: - bank_transactions - summary: "Performs bulk actions on an array of bank_transations" + summary: "Bulk actions" description: "" operationId: bulkBankTransactions parameters: @@ -1042,8 +1042,30 @@ paths: post: tags: - bank_transactions - summary: "Performs match actions on an array of bank_transactions" - description: "" + summary: "Match transactions" + description: | + Matching invoices or a payment to a bank transactions. + + The API expects the id of the transaction along with either a comma separated list of invoice ids OR the payment id to associate the transaction to. + + Example for matching a transaction to two invoices: + + {"transactions":[{"id":"olejRl5ejN","invoice_ids":"JxboYBLegw,JxboYBLeXX"}]} + + Example for matching a transaction and a paymente: + + {"transactions":[{"id":"olejRl5ejN","payment_id":"JxboYBLeXf"}]} + + Matching expenses. + + You can match an existing expense within Invoice Ninja - or - create a new expense using the following: + + {"transactions":[{"id":"open5pld7A","vendor_id":"gl9avJnaG1","ninja_category_id":""}]} + + To match to an existing expense: + + {"transactions":[{"id":"Jxbo2qKagw","expense_id":"7N1aMM1aWm"}]} + operationId: matchBankTransactions parameters: - $ref: "#/components/parameters/X-API-TOKEN" diff --git a/resources/views/email/template/client.blade.php b/resources/views/email/template/client.blade.php index e73dfa3630bd..112f5b71c553 100644 --- a/resources/views/email/template/client.blade.php +++ b/resources/views/email/template/client.blade.php @@ -22,6 +22,7 @@ color-scheme: light dark; supported-color-schemes: light dark; } + @if(isset($settings) && $settings->email_style === 'dark') body { background-color: #1a1a1a !important; @@ -48,6 +49,13 @@ hr { border-color: #474849 !important; } + .file_icon { + filter: invert(1); + } + @else + .file_icon { + filter: invert(1); + } @endif /** Content-specific styles. **/ #content .button { @@ -171,9 +179,12 @@ @isset($links)
    -
      +
        + @if(count($links) > 0) +
      • {{ ctrans('texts.download_files')}}
      • + @endif @foreach($links as $link) -
      • {!! $link ?? '' !!}
      • +
      • {!! $link ?? '' !!}
      • @endforeach
    From 4a7a54a9ea2385a7a09ab0d26af27254c4ec4f9d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 12:38:48 +1000 Subject: [PATCH 05/30] Cron checks for Rotessa Paymetns --- .../Controllers/CompanyGatewayController.php | 6 +- .../Components/Rotessa/AccountComponent.php | 2 +- app/Models/CompanyGateway.php | 1 + .../Rotessa/Jobs/TransactionReport.php | 154 ++++++++++++++++++ app/PaymentDrivers/Rotessa/PaymentMethod.php | 15 +- .../Request/PatchTransactionSchedulesId.php | 2 +- .../PostTransactionSchedulesUpdateViaPost.php | 2 +- app/PaymentDrivers/RotessaPaymentDriver.php | 87 ++++++---- .../rotessa/components/address.blade.php | 2 +- 9 files changed, 229 insertions(+), 42 deletions(-) create mode 100644 app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index 56fc9ce0c1ff..552374bfd2bc 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -567,9 +567,9 @@ class CompanyGatewayController extends BaseController { //Throttle here - if (Cache::has("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}")) { - return response()->json(['message' => 'Please wait whilst your previous attempts complete.'], 200); - } + // if (Cache::has("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}")) { + // return response()->json(['message' => 'Please wait whilst your previous attempts complete.'], 200); + // } dispatch(function () use ($company_gateway) { MultiDB::setDb($company_gateway->company->db); diff --git a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php index 01df934dcf3d..c7702b4e66a3 100644 --- a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php @@ -27,7 +27,7 @@ class AccountComponent extends Component 'routing_number' => null, 'institution_number' => null, 'transit_number' => null, - 'bank_name' => ' ', + 'bank_name' => null, 'account_number' => null, 'country' => 'US', "authorization_type" => 'Online' diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 62ba38ee8e41..ce561f31bf0c 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -155,6 +155,7 @@ class CompanyGateway extends BaseModel 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9' => 322, '80af24a6a691230bbec33e930ab40666' => 323, 'vpyfbmdrkqcicpkjqdusgjfluebftuva' => 324, //BTPay + '91be24c7b792230bced33e930ac61676' => 325, ]; protected $touches = []; diff --git a/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php new file mode 100644 index 000000000000..dc8020cca796 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php @@ -0,0 +1,154 @@ +cursor() + ->each(function ($cg){ + + $driver = $cg->driver()->init(); + + //Approved Transactions + $transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Approved', 'start_date' => now()->subMonths(2)->format('Y-m-d')]); + + if($transactions->successful()) + { + $transactions = $transactions->json(); + nlog($transactions); + + Payment::query() + ->where('company_id', $cg->company_id) + ->where('status_id', Payment::STATUS_PENDING) + ->whereIn('transaction_reference', array_column($transactions, "transaction_schedule_id")) + ->cursor() + ->each(function ($payment) use ($transactions) { + + $payment->status_id = Payment::STATUS_COMPLETED; + $payment->save(); + + SystemLogger::dispatch( + ['response' => collect($transactions)->where('id', $payment->transaction_reference)->first()->toArray(), 'data' => []], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_ROTESSA, + $payment->client, + $payment->company, + ); + + }); + + } + + + //Declined / Charged Back Transactions + $declined_transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Declined', 'start_date' => now()->subMonths(2)->format('Y-m-d')]); + $chargeback_transactions = $driver->gatewayRequest("get", "transaction_report", ['page' => 1, 'status' => 'Chargeback', 'start_date' => now()->subMonths(2)->format('Y-m-d')]); + + if($declined_transactions->successful() && $chargeback_transactions->successful()) { + + $transactions = array_merge($declined_transactions->json(), $chargeback_transactions->json()); + + nlog($transactions); + + Payment::query() + ->where('company_id', $cg->company_id) + ->where('status_id', Payment::STATUS_PENDING) + ->whereIn('transaction_reference', array_column($transactions, "transaction_schedule_id")) + ->cursor() + ->each(function ($payment) use ($transactions){ + + + $client = $payment->client; + + $payment->service()->deletePayment(); + + $payment->status_id = Payment::STATUS_FAILED; + $payment->save(); + + $payment_hash = PaymentHash::query()->where('payment_id', $payment->id)->first(); + + if ($payment_hash) { + + App::forgetInstance('translator'); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($client->getMergedSettings())); + App::setLocale($client->locale()); + + $error = ctrans('texts.client_payment_failure_body', [ + 'invoice' => implode(',', $payment->invoices->pluck('number')->toArray()), + 'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total, ]); + } else { + $error = 'Payment for '.$payment->client->present()->name()." for {$payment->amount} failed"; + } + + PaymentFailedMailer::dispatch( + $payment_hash, + $client->company, + $client, + $error + ); + + SystemLogger::dispatch( + ['response' => collect($transactions)->where('id', $payment->transaction_reference)->first()->toArray(), 'data' => []], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_ROTESSA, + $payment->client, + $payment->company, + ); + + }); + } + }); + + } + } + +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 87c9e2499fb0..9fd4d9f094e5 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -81,7 +81,7 @@ class PaymentMethod implements MethodInterface 'country' => ['required'], 'name' => ['required'], 'address_1' => ['required'], - 'address_2' => ['required'], + // 'address_2' => ['required'], 'city' => ['required'], 'email' => ['required','email:filter'], 'province_code' => ['required','size:2','alpha'], @@ -90,7 +90,7 @@ class PaymentMethod implements MethodInterface 'account_number' => ['required'], 'bank_name' => ['required'], 'phone' => ['required'], - 'home_phone' => ['required'], + 'home_phone' => ['required','size:10'], 'bank_account_type'=>['required_if:country,US'], 'routing_number'=>['required_if:country,US'], 'institution_number'=>['required_if:country,CA','numeric'], @@ -159,11 +159,14 @@ class PaymentMethod implements MethodInterface $transaction = new Transaction($request->only('frequency' ,'installments','amount','process_date') + ['comment' => $this->rotessa->getDescription(false) ]); $transaction->additional(['customer_id' => $customer->gateway_customer_reference]); $transaction = array_filter( $transaction->resolve()); - $response = $this->rotessa->gateway->capture($transaction)->send(); + $response = $this->rotessa->gatewayRequest('post','transaction_schedules', $transaction); + + if($response->failed()) + $response->throw(); - if(!$response->isSuccessful()) throw new \Exception($response->getMessage(), (int) $response->getCode()); - - return $this->processPendingPayment($response->getParameter('id'), (float) $response->getParameter('amount'), PaymentType::ACSS , $customer->token); + $response = $response->json(); + nlog($response); + return $this->processPendingPayment($response['id'], (float) $response['amount'], PaymentType::ACSS , $customer->token); } catch(\Throwable $e) { $this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) ); } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php index fa04b9f05da6..9eac3cfabc2d 100644 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php @@ -13,7 +13,7 @@ class PatchTransactionSchedulesId extends BaseRequest implements RequestInterfac public function setId(int $value) { $this->setParameter('id',$value); } - public function setAmount(int $value) { + public function setAmount($value) { $this->setParameter('amount',$value); } public function setComment(string $value) { diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php index e037c5b4d322..afd4596bc9b6 100644 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php @@ -15,7 +15,7 @@ class PostTransactionSchedulesUpdateViaPost extends BaseRequest implements Reque public function setId(int $value) { $this->setParameter('id',$value); } - public function setAmount(int $value) { + public function setAmount($value) { $this->setParameter('amount',$value); } public function setComment(string $value) { diff --git a/app/PaymentDrivers/RotessaPaymentDriver.php b/app/PaymentDrivers/RotessaPaymentDriver.php index 585503d16d54..4326d9280a6f 100644 --- a/app/PaymentDrivers/RotessaPaymentDriver.php +++ b/app/PaymentDrivers/RotessaPaymentDriver.php @@ -30,6 +30,7 @@ use Illuminate\Database\Eloquent\Builder; use App\PaymentDrivers\Rotessa\Resources\Customer; use App\PaymentDrivers\Rotessa\PaymentMethod as Acss; use App\PaymentDrivers\Rotessa\PaymentMethod as BankTransfer; +use Illuminate\Support\Facades\Http; class RotessaPaymentDriver extends BaseDriver { @@ -54,11 +55,6 @@ class RotessaPaymentDriver extends BaseDriver public function init(): self { - - $this->gateway = Omnipay::create( - $this->company_gateway->gateway->provider - ); - $this->gateway->initialize((array) $this->company_gateway->getConfig()); return $this; } @@ -117,30 +113,42 @@ class RotessaPaymentDriver extends BaseDriver } public function importCustomers() { - $this->init(); + try { - if(!$result = Cache::has("rotessa-import_customers-{$this->company_gateway->company->company_key}")) { - $result = $this->gateway->getCustomers()->send(); - if(!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); - // cache results - Cache::put("rotessa-import_customers-{$this->company_gateway->company->company_key}", $result->getData(), 60 * 60 * 24); - } - - $result = Cache::get("rotessa-import_customers-{$this->company_gateway->company->company_key}"); - $customers = collect($result)->unique('email'); + $result = $this->gatewayRequest('get','customers',[]); + + if($result->failed()) + $result->throw(); + + $customers = collect($result->json())->unique('email'); + $client_emails = $customers->pluck('email')->all(); $company_id = $this->company_gateway->company->id; // get existing customers - $client_contacts = ClientContact::where('company_id', $company_id)->whereIn('email', $client_emails )->whereNull('deleted_at')->get(); + $client_contacts = ClientContact::where('company_id', $company_id) + ->whereIn('email', $client_emails ) + ->whereHas('client', function ($q){ + $q->where('is_deleted', false); + }) + ->whereNull('deleted_at') + ->get(); + $client_contacts = $client_contacts->map(function($item, $key) use ($customers) { - return array_merge([], (array) $customers->firstWhere("email", $item->email) , ['custom_identifier' => $item->client->number, 'identifier' => $item->client->number, 'client_id' => $item->client->id ]); + return array_merge($customers->firstWhere("email", $item->email),['custom_identifier' => $item->client->number, 'identifier' => $item->client->number, 'client_id' => $item->client->id ]); } ); + // create payment methods $client_contacts->each( - function($contact) use ($customers) { - $result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send(); + function($contact) { + // $result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send(); + $contact = (object)$contact; + + $result = $this->gatewayRequest("get","customers/{$contact->id}"); + $result = $result->json(); + $this->client = Client::find($contact->client_id); - $customer = (new Customer($result->getData()))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] ); + + $customer = (new Customer($result))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] ); $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); } ); @@ -150,8 +158,8 @@ class RotessaPaymentDriver extends BaseDriver $client_contacts = $customers->filter(function ($value, $key) use ($client_emails) { return !in_array(((object) $value)->email, $client_emails); })->each( function($customer) use ($company_id) { - // create new client contact from rotess customer - $customer = (object) $this->gateway->getCustomersId(['id' => ($customer = (object) $customer)->id])->send()->getData(); + + $customer = $this->gatewayRequest("get", "customers/{$customer['id']}")->json(); /** { "account_number": "11111111" @@ -186,7 +194,7 @@ class RotessaPaymentDriver extends BaseDriver */ $settings = ClientSettings::defaults(); $settings->currency_id = $this->company_gateway->company->getSetting('currency_id'); - + $customer = (object)$customer; $client = (\App\Factory\ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id))->fill( [ 'address1' => $customer->address['address_1'] ?? '', @@ -245,12 +253,18 @@ class RotessaPaymentDriver extends BaseDriver ->where('gateway_customer_reference', Arr::only($data,'id')); }) ->exists(); - if ($existing) return true; + if ($existing) + return true; else if(!Arr::has($data,'id')) { - $result = $this->gateway->authorize($data)->send(); - if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); + // $result = $this->gateway->authorize($data)->send(); + // if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); - $customer = new Customer($result->getData()); + $result = $this->gatewayRequest('post', 'customers', $data); + + if($result->failed()) + $result->throw(); + + $customer = new Customer($result->json()); $data = array_filter($customer->resolve()); } @@ -268,7 +282,6 @@ class RotessaPaymentDriver extends BaseDriver return $data['id']; - throw new \Exception($result->getMessage(), (int) $result->getCode()); } catch (\Throwable $th) { $data = [ @@ -276,7 +289,7 @@ class RotessaPaymentDriver extends BaseDriver 'transaction_response' => $th->getMessage(), 'success' => false, 'description' => $th->getMessage(), - 'code' =>(int) $th->getCode() + '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); @@ -284,4 +297,20 @@ class RotessaPaymentDriver extends BaseDriver throw $th; } } + + public function gatewayRequest($verb, $uri, $payload = []) + { + $r = Http::withToken($this->company_gateway->getConfigField('apiKey')) + ->{$verb}($this->getUrl().$uri, $payload); + + nlog($r->body()); + + return $r; + } + + private function getUrl(): string + { + return $this->company_gateway->getConfigField('testMode') ? 'https://sandbox-api.rotessa.com/v1/' : 'https://api.rotessa.com/v1/'; + } + } diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php index 0d00f32dd036..ef19c8f8b765 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php @@ -22,7 +22,7 @@ {{ ctrans('texts.address2') }}
    - +
    From 80fd353f1417d0a129f2a2a00ee66217d2e558cd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 12:40:21 +1000 Subject: [PATCH 06/30] Add functionality to rotessa to check for payment status --- app/Console/Kernel.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 99f6378f3ad5..bed512e75cd1 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -32,6 +32,7 @@ use App\Jobs\Util\SchedulerCheck; use App\Jobs\Util\UpdateExchangeRates; use App\Jobs\Util\VersionCheck; use App\Models\Account; +use App\PaymentDrivers\Rotessa\Jobs\TransactionReport; use App\Utils\Ninja; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -64,6 +65,9 @@ class Kernel extends ConsoleKernel /* Checks for scheduled tasks */ $schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); + /* Checks Rotessa Transactions */ + $schedule->json(new TransactionReport())->dailyAt('01:48')->withoutOverlapping()->name('rotessa-transaction-report')->onOneServer(); + /* Stale Invoice Cleanup*/ $schedule->job(new CleanStaleInvoiceOrder())->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); From 285618600b55ea1cc9996423f310796013b7a412 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 13:56:46 +1000 Subject: [PATCH 07/30] fixes or scheule --- app/Console/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index bed512e75cd1..382a577102d7 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -66,7 +66,7 @@ class Kernel extends ConsoleKernel $schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); /* Checks Rotessa Transactions */ - $schedule->json(new TransactionReport())->dailyAt('01:48')->withoutOverlapping()->name('rotessa-transaction-report')->onOneServer(); + $schedule->job(new TransactionReport())->dailyAt('01:48')->withoutOverlapping()->name('rotessa-transaction-report')->onOneServer(); /* Stale Invoice Cleanup*/ $schedule->job(new CleanStaleInvoiceOrder())->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); From 186cf16cee3da714b3c40b6b08d006c8a1e6f55f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 3 Aug 2024 14:08:34 +1000 Subject: [PATCH 08/30] v5.10.17 --- VERSION.txt | 2 +- .../Rotessa/Jobs/TransactionReport.php | 3 ++- composer.lock | 24 +++++++++---------- config/ninja.php | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index c0204ea277af..b62d8ef8ec05 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.10.16 \ No newline at end of file +5.10.17 \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php index dc8020cca796..c62c35f1f35d 100644 --- a/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php +++ b/app/PaymentDrivers/Rotessa/Jobs/TransactionReport.php @@ -49,7 +49,8 @@ class TransactionReport implements ShouldQueue { MultiDB::setDB($db); - CompanyGateway::where('gateway_key', '91be24c7b792230bced33e930ac61676') + CompanyGateway::query() + ->where('gateway_key', '91be24c7b792230bced33e930ac61676') ->cursor() ->each(function ($cg){ diff --git a/composer.lock b/composer.lock index 25bf656a3940..c5427c1227ac 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.317.0", + "version": "3.317.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "6d46c8e00c22f66349b8a509bd2c5ced72cceff2" + "reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6d46c8e00c22f66349b8a509bd2c5ced72cceff2", - "reference": "6d46c8e00c22f66349b8a509bd2c5ced72cceff2", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/dc1e3031c2721a25beb2e8fbb175b576e3d60ab9", + "reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9", "shasum": "" }, "require": { @@ -624,9 +624,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.317.0" + "source": "https://github.com/aws/aws-sdk-php/tree/3.317.1" }, - "time": "2024-08-01T18:12:34+00:00" + "time": "2024-08-02T18:09:42+00:00" }, { "name": "bacon/bacon-qr-code", @@ -972,16 +972,16 @@ }, { "name": "checkout/checkout-sdk-php", - "version": "3.2.1", + "version": "3.2.2", "source": { "type": "git", "url": "https://github.com/checkout/checkout-sdk-php.git", - "reference": "91797beb18fd9b1581b1cfe5b96a551c0009417c" + "reference": "ac757648271894e3c30b7bc58ff08ba1b5b84de8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/91797beb18fd9b1581b1cfe5b96a551c0009417c", - "reference": "91797beb18fd9b1581b1cfe5b96a551c0009417c", + "url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/ac757648271894e3c30b7bc58ff08ba1b5b84de8", + "reference": "ac757648271894e3c30b7bc58ff08ba1b5b84de8", "shasum": "" }, "require": { @@ -1034,9 +1034,9 @@ ], "support": { "issues": "https://github.com/checkout/checkout-sdk-php/issues", - "source": "https://github.com/checkout/checkout-sdk-php/tree/3.2.1" + "source": "https://github.com/checkout/checkout-sdk-php/tree/3.2.2" }, - "time": "2024-07-09T16:07:18+00:00" + "time": "2024-08-02T08:07:53+00:00" }, { "name": "clue/stream-filter", diff --git a/config/ninja.php b/config/ninja.php index d2ff07a5bb05..a1fe742fc8dc 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.10.16'), - 'app_tag' => env('APP_TAG', '5.10.16'), + 'app_version' => env('APP_VERSION', '5.10.17'), + 'app_tag' => env('APP_TAG', '5.10.17'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), From 620bd18cf9f957235afba9eb4b8ceb2026463f65 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 07:28:20 +1000 Subject: [PATCH 09/30] Improve data errors for twig --- app/Http/Controllers/PreviewController.php | 3 +++ app/Http/ValidationRules/Design/TwigLint.php | 4 ---- app/Services/Template/TemplateMock.php | 2 +- app/Services/Template/TemplateService.php | 2 ++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index db7b705898f3..02c9692b6292 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -298,6 +298,9 @@ class PreviewController extends BaseController ->mock(); } catch(SyntaxError $e) { } + catch(\Exception $e) { + return response()->json(['message' => 'invalid data access', 'errors' => ['design.design.body' => $e->getMessage()]], 422); + } if (request()->query('html') == 'true') { return $ts->getHtml(); diff --git a/app/Http/ValidationRules/Design/TwigLint.php b/app/Http/ValidationRules/Design/TwigLint.php index 187fd706b51e..a0de3e2d7196 100644 --- a/app/Http/ValidationRules/Design/TwigLint.php +++ b/app/Http/ValidationRules/Design/TwigLint.php @@ -31,12 +31,8 @@ class TwigLint implements ValidationRule try { $twig->parse($twig->tokenize(new \Twig\Source(preg_replace('//s', '', $value), ''))); } catch (\Twig\Error\SyntaxError $e) { - // echo json_encode(['status' => 'error', 'message' => $e->getMessage()]); - nlog($e->getMessage()); $fail($e->getMessage()); - } - } } diff --git a/app/Services/Template/TemplateMock.php b/app/Services/Template/TemplateMock.php index 7bf3b9fd7fdc..7a1ac6592f65 100644 --- a/app/Services/Template/TemplateMock.php +++ b/app/Services/Template/TemplateMock.php @@ -29,7 +29,7 @@ class TemplateMock public string $purchase_order_data = '[{"id":"l4zbq2dprO","user_id":"wMvbmOeYAl","project_id":"","assigned_user_id":"","vendor_id":"xYRdG7dDzO","amount":14,"balance":0,"client_id":"","status_id":"1","design_id":"Wpmbk5ezJn","created_at":1695799265,"updated_at":1695799268,"archived_at":0,"is_deleted":false,"number":"0001","discount":0,"po_number":"","date":"2023-09-27","last_sent_date":"","next_send_date":"","reminder1_sent":"","reminder2_sent":"","reminder3_sent":"","reminder_last_sent":"","due_date":"2023-09-28","terms":"","public_notes":"","private_notes":"","uses_inclusive_taxes":false,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"total_taxes":0,"is_amount_discount":true,"footer":"","partial":0,"partial_due_date":"","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","has_tasks":false,"has_expenses":false,"custom_surcharge1":0,"custom_surcharge2":0,"custom_surcharge3":0,"custom_surcharge4":0,"custom_surcharge_tax1":false,"custom_surcharge_tax2":false,"custom_surcharge_tax3":false,"custom_surcharge_tax4":false,"line_items":[{"_id":"16ae59d4-60a8-4edf-b3a3-58882df1c5bf","quantity":1,"cost":14,"product_key":"enterprise_plan","product_cost":0,"notes":"The Enterprise Plan","discount":0,"is_amount_discount":true,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"sort_id":"0","line_total":14,"gross_line_total":14,"date":"","custom_value1":"https:\/\/picsum.photos\/200","custom_value2":"73","custom_value3":"Nesciunt sequi.","custom_value4":"Ratione inventore.","type_id":"1","tax_id":"1","tax_amount":0,"task_id":"","expense_id":""},{"_id":"c7ef7af8-2713-4376-89c5-6f2c9c148ea7","quantity":0,"cost":0,"product_key":"","product_cost":0,"notes":"","discount":0,"is_amount_discount":true,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"sort_id":"0","line_total":0,"gross_line_total":0,"date":"","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","type_id":"1","tax_id":"1","tax_amount":0,"task_id":"","expense_id":""}],"entity_type":"purchaseOrder","exchange_rate":1,"paid_to_date":0,"subscription_id":"","expense_id":"","currency_id":"","vendor":{"id":"xYRdG7dDzO","user_id":"wMvbmOeYAl","assigned_user_id":"","name":"Dr. Ottilie Gorczany PhD","website":"http:\/\/www.kihn.biz\/","private_notes":"Ullam ullam aut sed accusantium. Et amet ut et cumque. Dolorem rem doloremque eius aut laudantium soluta nihil.","public_notes":"","last_login":0,"address1":"93105","address2":"797 Medhurst Radial Suite 030","phone":"","city":"Lamberttown","state":"Kentucky","postal_code":"86694-1500","country_id":"4","currency_id":"1","custom_value1":"Et similique.","custom_value2":"Ducimus est.","custom_value3":"Ut unde aut quia.","custom_value4":"Rerum odio maxime.","is_deleted":false,"vat_number":"Hic sed vel sint eos et.","id_number":"Quod aut autem.","updated_at":1695796653,"archived_at":0,"created_at":1695796652,"number":"0004","language_id":"","contacts":{"App\\Models\\VendorContact":[{"id":"VolejRRejN","first_name":"Aisha","last_name":"Jerde","send_email":true,"email":"mariam40@example.com","created_at":1695796652,"updated_at":1695796652,"archived_at":0,"is_primary":true,"phone":"+1-828-839-4171","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","link":"http:\/\/ninja.test:8000\/vendor\/key_login\/vqQKXcwO2WsvkN4MPOAS6fpirMZP7gfc","last_login":0},{"id":"WpmbkR5azJ","first_name":"Willy","last_name":"Jacobs","send_email":true,"email":"qwolff@example.org","created_at":1695796652,"updated_at":1695796652,"archived_at":0,"is_primary":false,"phone":"979.822.6527","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","link":"http:\/\/ninja.test:8000\/vendor\/key_login\/A8g2xp3OLbNzpWlfPGIML2lk1LYNFJpx","last_login":0}]},"documents":{"App\\Models\\Document":[]}}},{"id":"kzPdy7aQro","user_id":"wMvbmOeYAl","project_id":"","assigned_user_id":"","vendor_id":"xYRdG7dDzO","amount":24,"balance":24,"client_id":"","status_id":"2","design_id":"Wpmbk5ezJn","created_at":1695799278,"updated_at":1695799290,"archived_at":0,"is_deleted":false,"number":"0002","discount":0,"po_number":"","date":"2023-09-27","last_sent_date":"","next_send_date":"","reminder1_sent":"","reminder2_sent":"","reminder3_sent":"","reminder_last_sent":"","due_date":"2023-09-28","terms":"","public_notes":"","private_notes":"","uses_inclusive_taxes":false,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"total_taxes":0,"is_amount_discount":true,"footer":"","partial":0,"partial_due_date":"","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","has_tasks":false,"has_expenses":false,"custom_surcharge1":0,"custom_surcharge2":0,"custom_surcharge3":0,"custom_surcharge4":0,"custom_surcharge_tax1":false,"custom_surcharge_tax2":false,"custom_surcharge_tax3":false,"custom_surcharge_tax4":false,"line_items":[{"_id":"a9fa64d0-e11b-47ce-8d75-d126769cd17d","quantity":1,"cost":14,"product_key":"enterprise_plan","product_cost":0,"notes":"The Enterprise Plan","discount":0,"is_amount_discount":true,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"sort_id":"0","line_total":14,"gross_line_total":14,"date":"","custom_value1":"https:\/\/picsum.photos\/200","custom_value2":"73","custom_value3":"Nesciunt sequi.","custom_value4":"Ratione inventore.","type_id":"1","tax_id":"1","tax_amount":0,"task_id":"","expense_id":""},{"_id":"6b8a7e41-f140-499a-ac3d-7f1916aa7e00","quantity":1,"cost":10,"product_key":"pro_plan","product_cost":0,"notes":"The Pro Plan","discount":0,"is_amount_discount":true,"tax_name1":"","tax_rate1":0,"tax_name2":"","tax_rate2":0,"tax_name3":"","tax_rate3":0,"sort_id":"0","line_total":10,"gross_line_total":10,"date":"","custom_value1":"https:\/\/picsum.photos\/200","custom_value2":"81","custom_value3":"Enim quis deleniti.","custom_value4":"Numquam quia quas.","type_id":"1","tax_id":"1","tax_amount":0,"task_id":"","expense_id":""}],"entity_type":"purchaseOrder","exchange_rate":1,"paid_to_date":0,"subscription_id":"","expense_id":"","currency_id":"","vendor":{"id":"xYRdG7dDzO","user_id":"wMvbmOeYAl","assigned_user_id":"","name":"Dr. Ottilie Gorczany PhD","website":"http:\/\/www.kihn.biz\/","private_notes":"Ullam ullam aut sed accusantium. Et amet ut et cumque. Dolorem rem doloremque eius aut laudantium soluta nihil.","public_notes":"","last_login":0,"address1":"93105","address2":"797 Medhurst Radial Suite 030","phone":"","city":"Lamberttown","state":"Kentucky","postal_code":"86694-1500","country_id":"4","currency_id":"1","custom_value1":"Et similique.","custom_value2":"Ducimus est.","custom_value3":"Ut unde aut quia.","custom_value4":"Rerum odio maxime.","is_deleted":false,"vat_number":"Hic sed vel sint eos et.","id_number":"Quod aut autem.","updated_at":1695796653,"archived_at":0,"created_at":1695796652,"number":"0004","language_id":"","contacts":{"App\\Models\\VendorContact":[{"id":"VolejRRejN","first_name":"Aisha","last_name":"Jerde","send_email":true,"email":"mariam40@example.com","created_at":1695796652,"updated_at":1695796652,"archived_at":0,"is_primary":true,"phone":"+1-828-839-4171","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","link":"http:\/\/ninja.test:8000\/vendor\/key_login\/vqQKXcwO2WsvkN4MPOAS6fpirMZP7gfc","last_login":0},{"id":"WpmbkR5azJ","first_name":"Willy","last_name":"Jacobs","send_email":true,"email":"qwolff@example.org","created_at":1695796652,"updated_at":1695796652,"archived_at":0,"is_primary":false,"phone":"979.822.6527","custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","link":"http:\/\/ninja.test:8000\/vendor\/key_login\/A8g2xp3OLbNzpWlfPGIML2lk1LYNFJpx","last_login":0}]},"documents":{"App\\Models\\Document":[]}}}]'; - public string $project_data = '[{"name":"Abel Moore","number":"0001","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$107.00","task_rate_raw":"107.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Omnis modi optio maxime ut inventore.","budgeted_hours":339,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":390,"tasks":[{"number":"0002","description":"Et dolorem nihil qui quas asperiores nulla aut praesentium. Ea quasi porro facere eligendi. Et assumenda illum nostrum natus repellat eveniet. Sequi odio nulla perspiciatis doloremque.","duration":966982,"rate":"$76.00","rate_raw":"76.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700492035,"end_date":"20\/Nov\/2023 14:11:55","description":"Nihil voluptas et sint et.","billable":true,"duration":63569},{"start_date_raw":1700492335,"start_date":"20\/Nov\/2023 14:11:55","end_date_raw":1700554011,"end_date":"21\/Nov\/2023 08:11:51","description":"Aut consequuntur aliquam earum aut reiciendis.","billable":false,"duration":61676},{"start_date_raw":1700554311,"start_date":"21\/Nov\/2023 08:11:51","end_date_raw":1700586651,"end_date":"21\/Nov\/2023 17:11:51","description":"Occaecati consectetur temporibus neque rerum sed rem iure.","billable":true,"duration":32340},{"start_date_raw":1700586951,"start_date":"21\/Nov\/2023 17:11:51","end_date_raw":1700644903,"end_date":"22\/Nov\/2023 09:11:43","description":"Ducimus voluptate aliquid aliquam nobis.","billable":true,"duration":57952},{"start_date_raw":1700645203,"start_date":"22\/Nov\/2023 09:11:43","end_date_raw":1700724132,"end_date":"23\/Nov\/2023 07:11:12","description":"Non ipsam consequatur voluptatem illum.","billable":true,"duration":78929},{"start_date_raw":1700724432,"start_date":"23\/Nov\/2023 07:11:12","end_date_raw":1700790596,"end_date":"24\/Nov\/2023 01:11:56","description":"Aspernatur quia voluptate molestias non.","billable":false,"duration":66164},{"start_date_raw":1700790896,"start_date":"24\/Nov\/2023 01:11:56","end_date_raw":1700812808,"end_date":"24\/Nov\/2023 08:11:08","description":"Sed quod omnis officiis asperiores natus facere minus nemo.","billable":false,"duration":21912},{"start_date_raw":1700813108,"start_date":"24\/Nov\/2023 08:11:08","end_date_raw":1700865275,"end_date":"24\/Nov\/2023 22:11:35","description":"Tenetur quaerat ea magni placeat.","billable":false,"duration":52167},{"start_date_raw":1700865575,"start_date":"24\/Nov\/2023 22:11:35","end_date_raw":1700888516,"end_date":"25\/Nov\/2023 05:11:56","description":"Sequi dolor laborum deserunt rerum.","billable":true,"duration":22941},{"start_date_raw":1700888816,"start_date":"25\/Nov\/2023 05:11:56","end_date_raw":1700933259,"end_date":"25\/Nov\/2023 17:11:39","description":"Est qui velit ipsum et nesciunt qui ut.","billable":true,"duration":44443},{"start_date_raw":1700933559,"start_date":"25\/Nov\/2023 17:11:39","end_date_raw":1700979107,"end_date":"26\/Nov\/2023 06:11:47","description":"Sint et quo quo.","billable":false,"duration":45548},{"start_date_raw":1700979407,"start_date":"26\/Nov\/2023 06:11:47","end_date_raw":1701002669,"end_date":"26\/Nov\/2023 12:11:29","description":"Omnis unde sit similique dolor fugit totam.","billable":true,"duration":23262},{"start_date_raw":1701002969,"start_date":"26\/Nov\/2023 12:11:29","end_date_raw":1701071339,"end_date":"27\/Nov\/2023 07:11:59","description":"Ducimus qui voluptas accusamus.","billable":true,"duration":68370},{"start_date_raw":1701071639,"start_date":"27\/Nov\/2023 07:11:59","end_date_raw":1701100825,"end_date":"27\/Nov\/2023 16:11:25","description":"Soluta sit non nobis ab et ad libero sint.","billable":false,"duration":29186},{"start_date_raw":1701101125,"start_date":"27\/Nov\/2023 16:11:25","end_date_raw":1701157799,"end_date":"28\/Nov\/2023 07:11:59","description":"Cumque dignissimos error qui ut.","billable":true,"duration":56674},{"start_date_raw":1701158099,"start_date":"28\/Nov\/2023 07:11:59","end_date_raw":1701214020,"end_date":"28\/Nov\/2023 23:11:00","description":"Molestias omnis aliquid voluptatem cupiditate ut.","billable":true,"duration":55921},{"start_date_raw":1701214320,"start_date":"28\/Nov\/2023 23:11:00","end_date_raw":1701286375,"end_date":"29\/Nov\/2023 19:11:55","description":"Distinctio commodi est ab.","billable":true,"duration":72055},{"start_date_raw":1701286675,"start_date":"29\/Nov\/2023 19:11:55","end_date_raw":1701330081,"end_date":"30\/Nov\/2023 07:11:21","description":"Nisi dolores omnis veritatis.","billable":false,"duration":43406},{"start_date_raw":1701330381,"start_date":"30\/Nov\/2023 07:11:21","end_date_raw":1701398228,"end_date":"01\/Dec\/2023 02:12:08","description":"Qui aut velit quam dolore qui asperiores.","billable":false,"duration":67847},{"start_date_raw":1701398528,"start_date":"01\/Dec\/2023 02:12:08","end_date_raw":1701401148,"end_date":"01\/Dec\/2023 03:12:48","description":"Laudantium est laudantium ea ut repellendus.","billable":true,"duration":2620}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"}},{"number":"0003","description":"Qui excepturi et aut et voluptates eius perferendis. Repellat eum illo quis aliquid occaecati reprehenderit officia. Est earum nihil similique recusandae aut ut est error. Enim molestiae assumenda quaerat neque unde. Consequatur vel placeat commodi molestiae.","duration":259657,"rate":"$9.00","rate_raw":"9.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700498928,"end_date":"20\/Nov\/2023 16:11:48","description":"Animi asperiores velit quaerat sapiente dolorem officiis.","billable":false,"duration":70462},{"start_date_raw":1700499228,"start_date":"20\/Nov\/2023 16:11:48","end_date_raw":1700516753,"end_date":"20\/Nov\/2023 21:11:53","description":"Et facere ut tempora similique et sunt culpa.","billable":false,"duration":17525},{"start_date_raw":1700517053,"start_date":"20\/Nov\/2023 21:11:53","end_date_raw":1700523921,"end_date":"20\/Nov\/2023 23:11:21","description":"Consequatur enim non reprehenderit quia.","billable":false,"duration":6868},{"start_date_raw":1700524221,"start_date":"20\/Nov\/2023 23:11:21","end_date_raw":1700609374,"end_date":"21\/Nov\/2023 23:11:34","description":"Nobis non nesciunt ut reprehenderit at.","billable":false,"duration":85153},{"start_date_raw":1700609674,"start_date":"21\/Nov\/2023 23:11:34","end_date_raw":1700689323,"end_date":"22\/Nov\/2023 21:11:03","description":"Blanditiis repellendus quo voluptatum eveniet iste.","billable":false,"duration":79649}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"}},{"number":"0004","description":"Ipsam tempora id vero perferendis. Nulla laudantium iste qui quod et voluptatem. Aliquam et vel est minus ratione.","duration":179131,"rate":"$146.00","rate_raw":"146.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700446786,"end_date":"20\/Nov\/2023 02:11:46","description":"Ipsam voluptatum sed officiis eos quo.","billable":true,"duration":18320},{"start_date_raw":1700447086,"start_date":"20\/Nov\/2023 02:11:46","end_date_raw":1700520087,"end_date":"20\/Nov\/2023 22:11:27","description":"Et maxime rem provident veritatis.","billable":true,"duration":73001},{"start_date_raw":1700520387,"start_date":"20\/Nov\/2023 22:11:27","end_date_raw":1700603783,"end_date":"21\/Nov\/2023 21:11:23","description":"Deserunt soluta dolorem harum voluptas necessitatibus eum laborum omnis.","billable":false,"duration":83396},{"start_date_raw":1700604083,"start_date":"21\/Nov\/2023 22:11:23","end_date_raw":1700608497,"end_date":"21\/Nov\/2023 23:11:57","description":"Esse et aperiam nobis dolor voluptas.","billable":true,"duration":4414}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"}}],"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},{"name":"Prof. Noah Jaskolski II","number":"0002","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$52.00","task_rate_raw":"52.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Mollitia ut vel quam. Quia et aut minus.","budgeted_hours":660,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":57,"tasks":[{"number":"0006","description":"Dolor quidem aperiam rerum. Voluptates aut vel ut consequatur. Nam et unde cupiditate qui voluptates voluptatum. Temporibus assumenda enim nam neque.","duration":156986,"rate":"$92.00","rate_raw":"92.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428467,"start_date":"19\/Nov\/2023 21:11:27","end_date_raw":1700443047,"end_date":"20\/Nov\/2023 01:11:27","description":"Unde sequi dicta corporis odio.","billable":true,"duration":14580},{"start_date_raw":1700443347,"start_date":"20\/Nov\/2023 01:11:27","end_date_raw":1700489146,"end_date":"20\/Nov\/2023 14:11:46","description":"Qui rem id inventore velit corporis vitae.","billable":false,"duration":45799},{"start_date_raw":1700489446,"start_date":"20\/Nov\/2023 14:11:46","end_date_raw":1700514655,"end_date":"20\/Nov\/2023 21:11:55","description":"Rerum repellat unde et blanditiis sunt animi aliquid accusantium.","billable":false,"duration":25209},{"start_date_raw":1700514955,"start_date":"20\/Nov\/2023 21:11:55","end_date_raw":1700515449,"end_date":"20\/Nov\/2023 21:11:09","description":"Quasi velit sit et explicabo quibusdam nam.","billable":true,"duration":494},{"start_date_raw":1700515749,"start_date":"20\/Nov\/2023 21:11:09","end_date_raw":1700586653,"end_date":"21\/Nov\/2023 17:11:53","description":"Numquam eos aut eum est corrupti dolorem et.","billable":false,"duration":70904}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","vat_number":"VAT123"}},{"number":"0007","description":"Omnis totam eum sed dolores quod rerum. Ducimus voluptate iste quia dolorum consequatur sint. Velit vitae sint qui molestias. Dolores ea rerum voluptates iusto qui natus beatae.","duration":47670,"rate":"$88.00","rate_raw":"88.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428467,"start_date":"19\/Nov\/2023 21:11:27","end_date_raw":1700476137,"end_date":"20\/Nov\/2023 10:11:57","description":"Sint laudantium quia eveniet quod nobis occaecati nihil.","billable":false,"duration":47670}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","vat_number":"VAT123"}}],"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","vat_number":"VAT123"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},{"name":"Mr. Easton Streich","number":"0003","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$153.00","task_rate_raw":"153.000000","due_date":"28\/Nov\/2023","private_notes":"","public_notes":"Debitis sit ut voluptatem eaque veritatis.","budgeted_hours":216,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":496,"tasks":[{"number":"0009","description":"Ipsam numquam nesciunt corporis veritatis vitae porro maiores. Delectus sit itaque dolores. Atque et dolorem nisi est.","duration":439161,"rate":"$120.00","rate_raw":"120.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700434593,"end_date":"19\/Nov\/2023 22:11:33","description":"At unde dolores quasi quia.","billable":true,"duration":6125},{"start_date_raw":1700434893,"start_date":"19\/Nov\/2023 23:11:33","end_date_raw":1700498703,"end_date":"20\/Nov\/2023 16:11:03","description":"Et quae non voluptatum nam quia velit suscipit.","billable":false,"duration":63810},{"start_date_raw":1700499003,"start_date":"20\/Nov\/2023 16:11:03","end_date_raw":1700548104,"end_date":"21\/Nov\/2023 06:11:24","description":"Quidem delectus sed et.","billable":true,"duration":49101},{"start_date_raw":1700548404,"start_date":"21\/Nov\/2023 06:11:24","end_date_raw":1700629022,"end_date":"22\/Nov\/2023 04:11:02","description":"Soluta velit enim explicabo dolorem commodi.","billable":false,"duration":80618},{"start_date_raw":1700629322,"start_date":"22\/Nov\/2023 05:11:02","end_date_raw":1700647716,"end_date":"22\/Nov\/2023 10:11:36","description":"Est magni qui quis.","billable":false,"duration":18394},{"start_date_raw":1700648016,"start_date":"22\/Nov\/2023 10:11:36","end_date_raw":1700731147,"end_date":"23\/Nov\/2023 09:11:07","description":"Saepe aspernatur non molestias dolor ea quos in.","billable":false,"duration":83131},{"start_date_raw":1700731447,"start_date":"23\/Nov\/2023 09:11:07","end_date_raw":1700782753,"end_date":"23\/Nov\/2023 23:11:13","description":"Alias id nihil laboriosam aliquam odio qui excepturi.","billable":true,"duration":51306},{"start_date_raw":1700783053,"start_date":"23\/Nov\/2023 23:11:13","end_date_raw":1700795456,"end_date":"24\/Nov\/2023 03:11:56","description":"Eos numquam et atque quia a qui nesciunt.","billable":false,"duration":12403},{"start_date_raw":1700795756,"start_date":"24\/Nov\/2023 03:11:56","end_date_raw":1700812488,"end_date":"24\/Nov\/2023 07:11:48","description":"Ut voluptas in natus qui.","billable":false,"duration":16732},{"start_date_raw":1700812788,"start_date":"24\/Nov\/2023 07:11:48","end_date_raw":1700842826,"end_date":"24\/Nov\/2023 16:11:26","description":"Est aut magnam ratione.","billable":false,"duration":30038},{"start_date_raw":1700843126,"start_date":"24\/Nov\/2023 16:11:26","end_date_raw":1700870629,"end_date":"25\/Nov\/2023 00:11:49","description":"Exercitationem non odio quasi ut saepe.","billable":true,"duration":27503}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}},{"number":"0010","description":"Quo recusandae optio est saepe consectetur optio. Accusantium eum quia eaque. Voluptatum eligendi similique velit dolor eos rerum cumque quaerat.","duration":425934,"rate":"$98.00","rate_raw":"98.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700463790,"end_date":"20\/Nov\/2023 07:11:10","description":"Culpa aut consequatur earum ut.","billable":false,"duration":35322},{"start_date_raw":1700464090,"start_date":"20\/Nov\/2023 07:11:10","end_date_raw":1700536862,"end_date":"21\/Nov\/2023 03:11:02","description":"Reprehenderit et esse qui hic quia est iusto.","billable":false,"duration":72772},{"start_date_raw":1700537162,"start_date":"21\/Nov\/2023 03:11:02","end_date_raw":1700592394,"end_date":"21\/Nov\/2023 18:11:34","description":"In est enim dolore nesciunt distinctio magni qui.","billable":true,"duration":55232},{"start_date_raw":1700592694,"start_date":"21\/Nov\/2023 18:11:34","end_date_raw":1700635771,"end_date":"22\/Nov\/2023 06:11:31","description":"Est saepe quasi alias aut odit officiis corporis.","billable":true,"duration":43077},{"start_date_raw":1700636071,"start_date":"22\/Nov\/2023 06:11:31","end_date_raw":1700637953,"end_date":"22\/Nov\/2023 07:11:53","description":"Consequuntur ipsa ut voluptate accusamus quibusdam sint sed.","billable":false,"duration":1882},{"start_date_raw":1700638253,"start_date":"22\/Nov\/2023 07:11:53","end_date_raw":1700687668,"end_date":"22\/Nov\/2023 21:11:28","description":"Sunt similique error et nostrum reprehenderit dolor.","billable":false,"duration":49415},{"start_date_raw":1700687968,"start_date":"22\/Nov\/2023 21:11:28","end_date_raw":1700712068,"end_date":"23\/Nov\/2023 04:11:08","description":"Aut rerum quis fugiat nostrum facilis ut.","billable":false,"duration":24100},{"start_date_raw":1700712368,"start_date":"23\/Nov\/2023 04:11:08","end_date_raw":1700783951,"end_date":"23\/Nov\/2023 23:11:11","description":"Aut culpa omnis sint et quos quisquam sint.","billable":true,"duration":71583},{"start_date_raw":1700784251,"start_date":"24\/Nov\/2023 00:11:11","end_date_raw":1700845166,"end_date":"24\/Nov\/2023 16:11:26","description":"Voluptas ut ratione porro eaque iste voluptas.","billable":true,"duration":60915},{"start_date_raw":1700845466,"start_date":"24\/Nov\/2023 17:11:26","end_date_raw":1700857102,"end_date":"24\/Nov\/2023 20:11:22","description":"Qui ipsa minus sed saepe maiores necessitatibus.","billable":true,"duration":11636}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}},{"number":"0011","description":"Eligendi molestiae et quis et tempora esse ut. Sed ut est possimus et minus aut incidunt. Quibusdam rerum incidunt molestias est qui quam temporibus fuga.","duration":637522,"rate":"$120.00","rate_raw":"120.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700499282,"end_date":"20\/Nov\/2023 16:11:42","description":"Quasi temporibus doloremque consequatur minus pariatur facere.","billable":true,"duration":70814},{"start_date_raw":1700499582,"start_date":"20\/Nov\/2023 16:11:42","end_date_raw":1700584386,"end_date":"21\/Nov\/2023 16:11:06","description":"Id distinctio sed eos qui.","billable":true,"duration":84804},{"start_date_raw":1700584686,"start_date":"21\/Nov\/2023 16:11:06","end_date_raw":1700635554,"end_date":"22\/Nov\/2023 06:11:54","description":"Facere explicabo non nostrum.","billable":true,"duration":50868},{"start_date_raw":1700635854,"start_date":"22\/Nov\/2023 06:11:54","end_date_raw":1700672533,"end_date":"22\/Nov\/2023 17:11:13","description":"Numquam sit labore facere voluptatibus quibusdam reiciendis et.","billable":true,"duration":36679},{"start_date_raw":1700672833,"start_date":"22\/Nov\/2023 17:11:13","end_date_raw":1700678587,"end_date":"22\/Nov\/2023 18:11:07","description":"Perspiciatis ad hic nostrum et.","billable":true,"duration":5754},{"start_date_raw":1700678887,"start_date":"22\/Nov\/2023 18:11:07","end_date_raw":1700708730,"end_date":"23\/Nov\/2023 03:11:30","description":"Qui culpa iure eos quaerat voluptatum numquam inventore.","billable":true,"duration":29843},{"start_date_raw":1700709030,"start_date":"23\/Nov\/2023 03:11:30","end_date_raw":1700765439,"end_date":"23\/Nov\/2023 18:11:39","description":"Similique molestiae atque voluptatem debitis dolorem quos quis et.","billable":false,"duration":56409},{"start_date_raw":1700765739,"start_date":"23\/Nov\/2023 18:11:39","end_date_raw":1700831780,"end_date":"24\/Nov\/2023 13:11:20","description":"Nam dolorum optio et omnis.","billable":true,"duration":66041},{"start_date_raw":1700832080,"start_date":"24\/Nov\/2023 13:11:20","end_date_raw":1700844498,"end_date":"24\/Nov\/2023 16:11:18","description":"Non eos amet repellat tempore id.","billable":false,"duration":12418},{"start_date_raw":1700844798,"start_date":"24\/Nov\/2023 16:11:18","end_date_raw":1700899153,"end_date":"25\/Nov\/2023 07:11:13","description":"Iste neque nostrum laudantium officia.","billable":false,"duration":54355},{"start_date_raw":1700899453,"start_date":"25\/Nov\/2023 08:11:13","end_date_raw":1700971949,"end_date":"26\/Nov\/2023 04:11:29","description":"Ut quia ratione sed et.","billable":true,"duration":72496},{"start_date_raw":1700972249,"start_date":"26\/Nov\/2023 04:11:29","end_date_raw":1700984833,"end_date":"26\/Nov\/2023 07:11:13","description":"Sapiente quia magni quisquam eos rerum rem.","billable":false,"duration":12584},{"start_date_raw":1700985133,"start_date":"26\/Nov\/2023 07:11:13","end_date_raw":1701069590,"end_date":"27\/Nov\/2023 07:11:50","description":"Nulla et ducimus doloribus est.","billable":true,"duration":84457}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}},{"number":"0012","description":"Ea cumque amet quas et suscipit. Voluptatum libero enim minus necessitatibus qui voluptatem. Voluptates soluta quae in et aut possimus veniam.","duration":283580,"rate":"$78.00","rate_raw":"78.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700469690,"end_date":"20\/Nov\/2023 08:11:30","description":"Placeat vel sit voluptas architecto sed.","billable":true,"duration":41222},{"start_date_raw":1700469990,"start_date":"20\/Nov\/2023 08:11:30","end_date_raw":1700483859,"end_date":"20\/Nov\/2023 12:11:39","description":"Voluptatem est quo est dolorem.","billable":true,"duration":13869},{"start_date_raw":1700484159,"start_date":"20\/Nov\/2023 12:11:39","end_date_raw":1700541376,"end_date":"21\/Nov\/2023 04:11:16","description":"Perferendis nulla quos omnis inventore sint.","billable":false,"duration":57217},{"start_date_raw":1700541676,"start_date":"21\/Nov\/2023 04:11:16","end_date_raw":1700609280,"end_date":"21\/Nov\/2023 23:11:00","description":"Quia quae ad cum neque.","billable":true,"duration":67604},{"start_date_raw":1700609580,"start_date":"21\/Nov\/2023 23:11:00","end_date_raw":1700668490,"end_date":"22\/Nov\/2023 15:11:50","description":"Pariatur et ipsa cumque consequatur voluptatum nemo.","billable":true,"duration":58910},{"start_date_raw":1700668790,"start_date":"22\/Nov\/2023 15:11:50","end_date_raw":1700690815,"end_date":"22\/Nov\/2023 22:11:55","description":"Officia explicabo illo ex tenetur.","billable":true,"duration":22025},{"start_date_raw":1700691115,"start_date":"22\/Nov\/2023 22:11:55","end_date_raw":1700713848,"end_date":"23\/Nov\/2023 04:11:48","description":"Quasi neque tempore aut at.","billable":true,"duration":22733}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}}],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},{"name":"Elenor Orn","number":"0004","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$39.00","task_rate_raw":"39.000000","due_date":"27\/Nov\/2023","private_notes":"","public_notes":"Distinctio ut voluptas deleniti est sed quae.","budgeted_hours":372,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":331,"tasks":[{"number":"0014","description":"In soluta aliquid et eius. Molestiae veritatis animi culpa et amet porro modi ut. Id sequi nobis itaque modi explicabo voluptatem quam. Non ex voluptatem error aspernatur odit.","duration":346244,"rate":"$70.00","rate_raw":"70.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700458211,"end_date":"20\/Nov\/2023 05:11:11","description":"Voluptate aut dicta recusandae consectetur est ducimus.","billable":false,"duration":29743},{"start_date_raw":1700458511,"start_date":"20\/Nov\/2023 05:11:11","end_date_raw":1700516247,"end_date":"20\/Nov\/2023 21:11:27","description":"Dolores incidunt praesentium rerum.","billable":false,"duration":57736},{"start_date_raw":1700516547,"start_date":"20\/Nov\/2023 21:11:27","end_date_raw":1700549251,"end_date":"21\/Nov\/2023 06:11:31","description":"Perspiciatis consequatur et alias praesentium placeat modi aut.","billable":true,"duration":32704},{"start_date_raw":1700549551,"start_date":"21\/Nov\/2023 06:11:31","end_date_raw":1700618445,"end_date":"22\/Nov\/2023 02:11:45","description":"Esse libero incidunt non rem sunt quisquam repudiandae nisi.","billable":true,"duration":68894},{"start_date_raw":1700618745,"start_date":"22\/Nov\/2023 02:11:45","end_date_raw":1700698086,"end_date":"23\/Nov\/2023 00:11:06","description":"Earum consectetur esse fugit sint autem tempore.","billable":true,"duration":79341},{"start_date_raw":1700698386,"start_date":"23\/Nov\/2023 00:11:06","end_date_raw":1700776212,"end_date":"23\/Nov\/2023 21:11:12","description":"Saepe sit consequatur vel eos ad iusto nobis.","billable":true,"duration":77826}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}},{"number":"0015","description":"Minus accusamus illum quia nihil voluptatum qui mollitia vel. Natus fugiat sequi quod eius occaecati non. Minus rerum ut eos est eveniet quae iure.","duration":410859,"rate":"$13.00","rate_raw":"13.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700506053,"end_date":"20\/Nov\/2023 18:11:33","description":"Iste neque officiis eum maiores.","billable":true,"duration":77585},{"start_date_raw":1700506353,"start_date":"20\/Nov\/2023 18:11:33","end_date_raw":1700572042,"end_date":"21\/Nov\/2023 13:11:22","description":"Minus perferendis quia amet.","billable":true,"duration":65689},{"start_date_raw":1700572342,"start_date":"21\/Nov\/2023 13:11:22","end_date_raw":1700637291,"end_date":"22\/Nov\/2023 07:11:51","description":"Commodi quaerat hic minus et voluptas velit.","billable":true,"duration":64949},{"start_date_raw":1700637591,"start_date":"22\/Nov\/2023 07:11:51","end_date_raw":1700649610,"end_date":"22\/Nov\/2023 10:11:10","description":"Vitae rerum natus aperiam quia explicabo.","billable":false,"duration":12019},{"start_date_raw":1700649910,"start_date":"22\/Nov\/2023 10:11:10","end_date_raw":1700693674,"end_date":"22\/Nov\/2023 22:11:34","description":"Quos sunt dolorum eveniet provident ut.","billable":false,"duration":43764},{"start_date_raw":1700693974,"start_date":"22\/Nov\/2023 22:11:34","end_date_raw":1700775335,"end_date":"23\/Nov\/2023 21:11:35","description":"Animi quibusdam quisquam ea error earum consectetur.","billable":true,"duration":81361},{"start_date_raw":1700775635,"start_date":"23\/Nov\/2023 21:11:35","end_date_raw":1700808126,"end_date":"24\/Nov\/2023 06:11:06","description":"Ratione ipsam molestiae dolorem sit architecto voluptas.","billable":true,"duration":32491},{"start_date_raw":1700808426,"start_date":"24\/Nov\/2023 06:11:06","end_date_raw":1700817758,"end_date":"24\/Nov\/2023 09:11:38","description":"Maxime reprehenderit voluptates culpa.","billable":false,"duration":9332},{"start_date_raw":1700818058,"start_date":"24\/Nov\/2023 09:11:38","end_date_raw":1700841727,"end_date":"24\/Nov\/2023 16:11:07","description":"Atque deleniti et laboriosam molestias repellat accusamus omnis.","billable":false,"duration":23669}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}},{"number":"0016","description":"Temporibus illum voluptatibus molestias quia omnis illo molestias corporis. Hic et hic quia dolores quas sint dolorem. Repellendus minus quae fuga illum amet in voluptatum. Rerum mollitia est eum voluptatum architecto non nisi qui. Est et dolores omnis placeat repellat sed facilis.","duration":435319,"rate":"$89.00","rate_raw":"89.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700496403,"end_date":"20\/Nov\/2023 16:11:43","description":"Sunt unde repellat reiciendis quos porro et dolores.","billable":true,"duration":67934},{"start_date_raw":1700496703,"start_date":"20\/Nov\/2023 16:11:43","end_date_raw":1700551129,"end_date":"21\/Nov\/2023 07:11:49","description":"Voluptatem laborum repudiandae enim asperiores.","billable":false,"duration":54426},{"start_date_raw":1700551429,"start_date":"21\/Nov\/2023 07:11:49","end_date_raw":1700631865,"end_date":"22\/Nov\/2023 05:11:25","description":"Placeat numquam magnam occaecati.","billable":false,"duration":80436},{"start_date_raw":1700632165,"start_date":"22\/Nov\/2023 05:11:25","end_date_raw":1700695854,"end_date":"22\/Nov\/2023 23:11:54","description":"Qui quo et est vero autem reprehenderit.","billable":false,"duration":63689},{"start_date_raw":1700696154,"start_date":"22\/Nov\/2023 23:11:54","end_date_raw":1700736857,"end_date":"23\/Nov\/2023 10:11:17","description":"Et voluptatem distinctio dolor fuga hic ea.","billable":false,"duration":40703},{"start_date_raw":1700737157,"start_date":"23\/Nov\/2023 10:11:17","end_date_raw":1700790692,"end_date":"24\/Nov\/2023 01:11:32","description":"Quo expedita quidem ab dolor quam expedita porro.","billable":true,"duration":53535},{"start_date_raw":1700790992,"start_date":"24\/Nov\/2023 01:11:32","end_date_raw":1700817527,"end_date":"24\/Nov\/2023 09:11:47","description":"Adipisci voluptatem officiis quaerat ut quos facilis.","billable":false,"duration":26535},{"start_date_raw":1700817827,"start_date":"24\/Nov\/2023 09:11:47","end_date_raw":1700865888,"end_date":"24\/Nov\/2023 22:11:48","description":"Tenetur ut dolorem vero.","billable":true,"duration":48061}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"}}],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","vat_number":"VAT123"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},{"name":"Maryjane Macejkovic","number":"0005","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$78.00","task_rate_raw":"78.000000","due_date":"26\/Nov\/2023","private_notes":"","public_notes":"Nesciunt est sit ea explicabo.","budgeted_hours":405,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":194,"tasks":[{"number":"0018","description":"Odit rerum iusto quibusdam. A mollitia cupiditate enim consequatur omnis qui voluptas quibusdam. Recusandae et non ut ipsum asperiores non iusto.","duration":312865,"rate":"$95.00","rate_raw":"95.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700476677,"end_date":"20\/Nov\/2023 10:11:57","description":"Quam dolores ut dolorem quo sint atque.","billable":true,"duration":48208},{"start_date_raw":1700476977,"start_date":"20\/Nov\/2023 10:11:57","end_date_raw":1700520944,"end_date":"20\/Nov\/2023 22:11:44","description":"Unde minus veniam corporis qui laboriosam suscipit quas.","billable":true,"duration":43967},{"start_date_raw":1700521244,"start_date":"20\/Nov\/2023 23:11:44","end_date_raw":1700602639,"end_date":"21\/Nov\/2023 21:11:19","description":"Beatae molestiae molestias sed dolor recusandae et id eligendi.","billable":false,"duration":81395},{"start_date_raw":1700602939,"start_date":"21\/Nov\/2023 21:11:19","end_date_raw":1700682077,"end_date":"22\/Nov\/2023 19:11:17","description":"Repellendus nam perspiciatis exercitationem in iste officia.","billable":true,"duration":79138},{"start_date_raw":1700682377,"start_date":"22\/Nov\/2023 19:11:17","end_date_raw":1700692054,"end_date":"22\/Nov\/2023 22:11:34","description":"Consequatur quaerat dolor consequuntur aperiam enim reiciendis.","billable":true,"duration":9677},{"start_date_raw":1700692354,"start_date":"22\/Nov\/2023 22:11:34","end_date_raw":1700742834,"end_date":"23\/Nov\/2023 12:11:54","description":"Qui quia ut sed accusantium odit reprehenderit quaerat.","billable":true,"duration":50480}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","vat_number":"VAT123"}},{"number":"0019","description":"Eius et dolor libero repellendus iste. Nemo sit error sed necessitatibus architecto et. Aspernatur omnis doloremque animi quas sed.","duration":387217,"rate":"$87.00","rate_raw":"87.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700434042,"end_date":"19\/Nov\/2023 22:11:22","description":"Aut aliquam totam in reprehenderit sint suscipit earum.","billable":false,"duration":5573},{"start_date_raw":1700434342,"start_date":"19\/Nov\/2023 22:11:22","end_date_raw":1700467844,"end_date":"20\/Nov\/2023 08:11:44","description":"Hic aliquid natus est.","billable":false,"duration":33502},{"start_date_raw":1700468144,"start_date":"20\/Nov\/2023 08:11:44","end_date_raw":1700532877,"end_date":"21\/Nov\/2023 02:11:37","description":"Illo atque dolores eligendi minus et ut consequuntur.","billable":false,"duration":64733},{"start_date_raw":1700533177,"start_date":"21\/Nov\/2023 02:11:37","end_date_raw":1700619369,"end_date":"22\/Nov\/2023 02:11:09","description":"Libero ipsa eligendi sit dolor eligendi quibusdam dicta tenetur.","billable":false,"duration":86192},{"start_date_raw":1700619669,"start_date":"22\/Nov\/2023 02:11:09","end_date_raw":1700646879,"end_date":"22\/Nov\/2023 09:11:39","description":"Dolor unde assumenda blanditiis tenetur blanditiis ipsam quis.","billable":true,"duration":27210},{"start_date_raw":1700647179,"start_date":"22\/Nov\/2023 09:11:39","end_date_raw":1700704537,"end_date":"23\/Nov\/2023 01:11:37","description":"Reprehenderit possimus nisi recusandae.","billable":true,"duration":57358},{"start_date_raw":1700704837,"start_date":"23\/Nov\/2023 02:11:37","end_date_raw":1700733175,"end_date":"23\/Nov\/2023 09:11:55","description":"Aut saepe sint qui magni.","billable":false,"duration":28338},{"start_date_raw":1700733475,"start_date":"23\/Nov\/2023 09:11:55","end_date_raw":1700735626,"end_date":"23\/Nov\/2023 10:11:46","description":"Facere repellendus voluptas illo a.","billable":true,"duration":2151},{"start_date_raw":1700735926,"start_date":"23\/Nov\/2023 10:11:46","end_date_raw":1700769798,"end_date":"23\/Nov\/2023 20:11:18","description":"Voluptatem praesentium ipsum soluta earum.","billable":false,"duration":33872},{"start_date_raw":1700770098,"start_date":"23\/Nov\/2023 20:11:18","end_date_raw":1700818386,"end_date":"24\/Nov\/2023 09:11:06","description":"Dicta eum quis dicta quae.","billable":true,"duration":48288}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","vat_number":"VAT123"}}],"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","vat_number":"VAT123"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}}]'; + public string $project_data = '[{"name":"Haleigh Mills","number":"0001","created_at":"01\/Aug\/2024","updated_at":"02\/Aug\/2024","task_rate":"$102.00","task_rate_raw":"102.000000","due_date":"12\/Aug\/2024","private_notes":"","public_notes":"Quisquam adipisci animi ex.","budgeted_hours":970,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":148,"tasks":[{"number":"0002","description":"Culpa sequi est enim minus dignissimos. Nisi dignissimos amet nobis beatae ducimus consequatur magnam. Non ut praesentium delectus autem aliquid minima.","duration":401319,"rate":"$143.00","rate_raw":"143.000000","created_at":"01\/Aug\/2024","updated_at":"02\/Aug\/2024","date":"01\/Aug\/2024","project":[],"time_log":[{"start_date_raw":1722560932,"start_date":"01\/Aug\/2024 14:08:52","end_date_raw":1722594811,"end_date":"01\/Aug\/2024 23:33:31","description":"Eos perferendis harum consequuntur neque.","billable":true,"duration_raw":33879,"duration":"09:24:39"},{"start_date_raw":1722595111,"start_date":"01\/Aug\/2024 23:38:31","end_date_raw":1722670240,"end_date":"02\/Aug\/2024 20:30:40","description":"Saepe ut iste id.","billable":false,"duration_raw":75129,"duration":"20:52:09"},{"start_date_raw":1722670540,"start_date":"02\/Aug\/2024 20:35:40","end_date_raw":1722739180,"end_date":"03\/Aug\/2024 15:39:40","description":"Ea reiciendis voluptatum necessitatibus alias tempora debitis eligendi.","billable":true,"duration_raw":68640,"duration":"19:04:00"},{"start_date_raw":1722739480,"start_date":"03\/Aug\/2024 15:44:40","end_date_raw":1722811869,"end_date":"04\/Aug\/2024 11:51:09","description":"Aut molestiae nisi beatae reprehenderit.","billable":false,"duration_raw":72389,"duration":"20:06:29"},{"start_date_raw":1722812169,"start_date":"04\/Aug\/2024 11:56:09","end_date_raw":1722885015,"end_date":"05\/Aug\/2024 08:10:15","description":"Dignissimos deleniti dolor consectetur fugiat necessitatibus asperiores.","billable":false,"duration_raw":72846,"duration":"20:14:06"},{"start_date_raw":1722885315,"start_date":"05\/Aug\/2024 08:15:15","end_date_raw":1722963751,"end_date":"06\/Aug\/2024 06:02:31","description":"Id repellat consectetur pariatur eaque et exercitationem facere quia.","billable":false,"duration_raw":78436,"duration":"21:47:16"}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Sven Schuster Concepcion Runolfsdottir PhD","email":"small@example.com"},"client":{"name":"Turcotte, Tromp and Hickle","balance":"3333.000000","payment_balance":"0.000000","credit_balance":"331.990000","vat_number":"455233120","currency":"CAD","custom_value1":"2019-10-29 09:56:21","custom_value2":"Indigo","custom_value3":"laboriosam","custom_value4":"hjones@windler.com","address":"470728227 Hoeger Prairie Suite 088Dinatown, Idaho 92489Canada","shipping_address":"48390661 Cremin Meadow Suite 797Lake Eriberto, Pennsylvania 50868-8763Afghanistan","locale":"en"}},{"number":"0003","description":"Hic reprehenderit sed eum et porro. Nesciunt aperiam quia voluptatem inventore ut. Iste corrupti qui dolor ipsam ut.","duration":132254,"rate":"$19.00","rate_raw":"19.000000","created_at":"01\/Aug\/2024","updated_at":"02\/Aug\/2024","date":"31\/Jul\/2024","project":[],"time_log":[{"start_date_raw":1722479429,"start_date":"31\/Jul\/2024 15:30:29","end_date_raw":1722496601,"end_date":"31\/Jul\/2024 20:16:41","description":"Sit voluptas explicabo tempora nesciunt architecto et.","billable":true,"duration_raw":17172,"duration":"04:46:12"},{"start_date_raw":1722496901,"start_date":"31\/Jul\/2024 20:21:41","end_date_raw":1722519879,"end_date":"01\/Aug\/2024 02:44:39","description":"Atque laborum qui praesentium fuga.","billable":true,"duration_raw":22978,"duration":"06:22:58"},{"start_date_raw":1722520179,"start_date":"01\/Aug\/2024 02:49:39","end_date_raw":1722536827,"end_date":"01\/Aug\/2024 07:27:07","description":"Tempore sed quae voluptates officiis doloremque sit ex.","billable":true,"duration_raw":16648,"duration":"04:37:28"},{"start_date_raw":1722537127,"start_date":"01\/Aug\/2024 07:32:07","end_date_raw":1722612560,"end_date":"02\/Aug\/2024 04:29:20","description":"In aut similique quidem aut sit provident.","billable":true,"duration_raw":75433,"duration":"20:57:13"},{"start_date_raw":1722634488,"start_date":"02\/Aug\/2024 10:34:48","end_date_raw":1722634511,"end_date":"02\/Aug\/2024 10:35:11","description":"","billable":false,"duration_raw":23,"duration":"00:00:23"}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Sven Schuster Concepcion Runolfsdottir PhD","email":"small@example.com"},"client":{"name":"Turcotte, Tromp and Hickle","balance":"3333.000000","payment_balance":"0.000000","credit_balance":"331.990000","vat_number":"455233120","currency":"CAD","custom_value1":"2019-10-29 09:56:21","custom_value2":"Indigo","custom_value3":"laboriosam","custom_value4":"hjones@windler.com","address":"470728227 Hoeger Prairie Suite 088Dinatown, Idaho 92489Canada","shipping_address":"48390661 Cremin Meadow Suite 797Lake Eriberto, Pennsylvania 50868-8763Afghanistan","locale":"en"}}],"client":{"name":"Turcotte, Tromp and Hickle","balance":"3333.000000","payment_balance":"0.000000","credit_balance":"331.990000","vat_number":"455233120","currency":"CAD","custom_value1":"2019-10-29 09:56:21","custom_value2":"Indigo","custom_value3":"laboriosam","custom_value4":"hjones@windler.com","address":"470728227 Hoeger Prairie Suite 088Dinatown, Idaho 92489Canada","shipping_address":"48390661 Cremin Meadow Suite 797Lake Eriberto, Pennsylvania 50868-8763Afghanistan","locale":"en"},"user":{"name":"Sven Schuster Concepcion Runolfsdottir PhD","email":"small@example.com"},"invoices":[]}]'; public string $task_data = '[{"number":"0001","description":"Reiciendis itaque molestias blanditiis cupiditate ea. Minus officiis natus itaque. Consectetur et aut veritatis quae ut esse ut. Accusantium dolore quaerat sit qui. Magni quia sunt corporis.","duration":149031,"rate":"$71.00","rate_raw":"71.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700470150,"end_date":"20\/Nov\/2023 08:11:10","description":"Assumenda nihil vitae odio voluptatem iusto ipsam repellendus.","billable":false,"duration":41684},{"start_date_raw":1700470450,"start_date":"20\/Nov\/2023 08:11:10","end_date_raw":1700485036,"end_date":"20\/Nov\/2023 12:11:16","description":"Adipisci amet optio tempore et.","billable":true,"duration":14586},{"start_date_raw":1700485336,"start_date":"20\/Nov\/2023 13:11:16","end_date_raw":1700572291,"end_date":"21\/Nov\/2023 13:11:31","description":"Ratione repellat saepe mollitia perspiciatis optio.","billable":false,"duration":86955},{"start_date_raw":1700572591,"start_date":"21\/Nov\/2023 13:11:31","end_date_raw":1700578397,"end_date":"21\/Nov\/2023 14:11:17","description":"Molestias perferendis ipsa odit id aut sunt.","billable":true,"duration":5806}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","vat_number":"VAT123","currency":"USD"}},{"number":"0002","description":"Et dolorem nihil qui quas asperiores nulla aut praesentium. Ea quasi porro facere eligendi. Et assumenda illum nostrum natus repellat eveniet. Sequi odio nulla perspiciatis doloremque.","duration":966982,"rate":"$76.00","rate_raw":"76.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Abel Moore","number":"0001","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$107.00","task_rate_raw":"107.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Omnis modi optio maxime ut inventore.","budgeted_hours":339,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":390,"tasks":[],"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700492035,"end_date":"20\/Nov\/2023 14:11:55","description":"Nihil voluptas et sint et.","billable":true,"duration":63569},{"start_date_raw":1700492335,"start_date":"20\/Nov\/2023 14:11:55","end_date_raw":1700554011,"end_date":"21\/Nov\/2023 08:11:51","description":"Aut consequuntur aliquam earum aut reiciendis.","billable":false,"duration":61676},{"start_date_raw":1700554311,"start_date":"21\/Nov\/2023 08:11:51","end_date_raw":1700586651,"end_date":"21\/Nov\/2023 17:11:51","description":"Occaecati consectetur temporibus neque rerum sed rem iure.","billable":true,"duration":32340},{"start_date_raw":1700586951,"start_date":"21\/Nov\/2023 17:11:51","end_date_raw":1700644903,"end_date":"22\/Nov\/2023 09:11:43","description":"Ducimus voluptate aliquid aliquam nobis.","billable":true,"duration":57952},{"start_date_raw":1700645203,"start_date":"22\/Nov\/2023 09:11:43","end_date_raw":1700724132,"end_date":"23\/Nov\/2023 07:11:12","description":"Non ipsam consequatur voluptatem illum.","billable":true,"duration":78929},{"start_date_raw":1700724432,"start_date":"23\/Nov\/2023 07:11:12","end_date_raw":1700790596,"end_date":"24\/Nov\/2023 01:11:56","description":"Aspernatur quia voluptate molestias non.","billable":false,"duration":66164},{"start_date_raw":1700790896,"start_date":"24\/Nov\/2023 01:11:56","end_date_raw":1700812808,"end_date":"24\/Nov\/2023 08:11:08","description":"Sed quod omnis officiis asperiores natus facere minus nemo.","billable":false,"duration":21912},{"start_date_raw":1700813108,"start_date":"24\/Nov\/2023 08:11:08","end_date_raw":1700865275,"end_date":"24\/Nov\/2023 22:11:35","description":"Tenetur quaerat ea magni placeat.","billable":false,"duration":52167},{"start_date_raw":1700865575,"start_date":"24\/Nov\/2023 22:11:35","end_date_raw":1700888516,"end_date":"25\/Nov\/2023 05:11:56","description":"Sequi dolor laborum deserunt rerum.","billable":true,"duration":22941},{"start_date_raw":1700888816,"start_date":"25\/Nov\/2023 05:11:56","end_date_raw":1700933259,"end_date":"25\/Nov\/2023 17:11:39","description":"Est qui velit ipsum et nesciunt qui ut.","billable":true,"duration":44443},{"start_date_raw":1700933559,"start_date":"25\/Nov\/2023 17:11:39","end_date_raw":1700979107,"end_date":"26\/Nov\/2023 06:11:47","description":"Sint et quo quo.","billable":false,"duration":45548},{"start_date_raw":1700979407,"start_date":"26\/Nov\/2023 06:11:47","end_date_raw":1701002669,"end_date":"26\/Nov\/2023 12:11:29","description":"Omnis unde sit similique dolor fugit totam.","billable":true,"duration":23262},{"start_date_raw":1701002969,"start_date":"26\/Nov\/2023 12:11:29","end_date_raw":1701071339,"end_date":"27\/Nov\/2023 07:11:59","description":"Ducimus qui voluptas accusamus.","billable":true,"duration":68370},{"start_date_raw":1701071639,"start_date":"27\/Nov\/2023 07:11:59","end_date_raw":1701100825,"end_date":"27\/Nov\/2023 16:11:25","description":"Soluta sit non nobis ab et ad libero sint.","billable":false,"duration":29186},{"start_date_raw":1701101125,"start_date":"27\/Nov\/2023 16:11:25","end_date_raw":1701157799,"end_date":"28\/Nov\/2023 07:11:59","description":"Cumque dignissimos error qui ut.","billable":true,"duration":56674},{"start_date_raw":1701158099,"start_date":"28\/Nov\/2023 07:11:59","end_date_raw":1701214020,"end_date":"28\/Nov\/2023 23:11:00","description":"Molestias omnis aliquid voluptatem cupiditate ut.","billable":true,"duration":55921},{"start_date_raw":1701214320,"start_date":"28\/Nov\/2023 23:11:00","end_date_raw":1701286375,"end_date":"29\/Nov\/2023 19:11:55","description":"Distinctio commodi est ab.","billable":true,"duration":72055},{"start_date_raw":1701286675,"start_date":"29\/Nov\/2023 19:11:55","end_date_raw":1701330081,"end_date":"30\/Nov\/2023 07:11:21","description":"Nisi dolores omnis veritatis.","billable":false,"duration":43406},{"start_date_raw":1701330381,"start_date":"30\/Nov\/2023 07:11:21","end_date_raw":1701398228,"end_date":"01\/Dec\/2023 02:12:08","description":"Qui aut velit quam dolore qui asperiores.","billable":false,"duration":67847},{"start_date_raw":1701398528,"start_date":"01\/Dec\/2023 02:12:08","end_date_raw":1701401148,"end_date":"01\/Dec\/2023 03:12:48","description":"Laudantium est laudantium ea ut repellendus.","billable":true,"duration":2620}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"}},{"number":"0003","description":"Qui excepturi et aut et voluptates eius perferendis. Repellat eum illo quis aliquid occaecati reprehenderit officia. Est earum nihil similique recusandae aut ut est error. Enim molestiae assumenda quaerat neque unde. Consequatur vel placeat commodi molestiae.","duration":259657,"rate":"$9.00","rate_raw":"9.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Abel Moore","number":"0001","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$107.00","task_rate_raw":"107.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Omnis modi optio maxime ut inventore.","budgeted_hours":339,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":390,"tasks":[],"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700498928,"end_date":"20\/Nov\/2023 16:11:48","description":"Animi asperiores velit quaerat sapiente dolorem officiis.","billable":false,"duration":70462},{"start_date_raw":1700499228,"start_date":"20\/Nov\/2023 16:11:48","end_date_raw":1700516753,"end_date":"20\/Nov\/2023 21:11:53","description":"Et facere ut tempora similique et sunt culpa.","billable":false,"duration":17525},{"start_date_raw":1700517053,"start_date":"20\/Nov\/2023 21:11:53","end_date_raw":1700523921,"end_date":"20\/Nov\/2023 23:11:21","description":"Consequatur enim non reprehenderit quia.","billable":false,"duration":6868},{"start_date_raw":1700524221,"start_date":"20\/Nov\/2023 23:11:21","end_date_raw":1700609374,"end_date":"21\/Nov\/2023 23:11:34","description":"Nobis non nesciunt ut reprehenderit at.","billable":false,"duration":85153},{"start_date_raw":1700609674,"start_date":"21\/Nov\/2023 23:11:34","end_date_raw":1700689323,"end_date":"22\/Nov\/2023 21:11:03","description":"Blanditiis repellendus quo voluptatum eveniet iste.","billable":false,"duration":79649}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"}},{"number":"0004","description":"Ipsam tempora id vero perferendis. Nulla laudantium iste qui quod et voluptatem. Aliquam et vel est minus ratione.","duration":179131,"rate":"$146.00","rate_raw":"146.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Abel Moore","number":"0001","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$107.00","task_rate_raw":"107.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Omnis modi optio maxime ut inventore.","budgeted_hours":339,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":390,"tasks":[],"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428466,"start_date":"19\/Nov\/2023 21:11:26","end_date_raw":1700446786,"end_date":"20\/Nov\/2023 02:11:46","description":"Ipsam voluptatum sed officiis eos quo.","billable":true,"duration":18320},{"start_date_raw":1700447086,"start_date":"20\/Nov\/2023 02:11:46","end_date_raw":1700520087,"end_date":"20\/Nov\/2023 22:11:27","description":"Et maxime rem provident veritatis.","billable":true,"duration":73001},{"start_date_raw":1700520387,"start_date":"20\/Nov\/2023 22:11:27","end_date_raw":1700603783,"end_date":"21\/Nov\/2023 21:11:23","description":"Deserunt soluta dolorem harum voluptas necessitatibus eum laborum omnis.","billable":false,"duration":83396},{"start_date_raw":1700604083,"start_date":"21\/Nov\/2023 22:11:23","end_date_raw":1700608497,"end_date":"21\/Nov\/2023 23:11:57","description":"Esse et aperiam nobis dolor voluptas.","billable":true,"duration":4414}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123","currency":"USD"}},{"number":"0005","description":"Enim fugiat at excepturi voluptate debitis ea. Hic officiis quaerat molestiae ullam minus consequuntur ut. Officiis quas consequatur error quae eveniet. Dolorum aliquam provident aperiam asperiores alias modi quae a.","duration":3230,"rate":"$78.00","rate_raw":"78.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428467,"start_date":"19\/Nov\/2023 21:11:27","end_date_raw":1700431697,"end_date":"19\/Nov\/2023 22:11:17","description":"Repudiandae nam et consequatur consequatur.","billable":false,"duration":3230}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Schroeder-Beahan","balance":"60576.340000","payment_balance":"0.000000","credit_balance":"0.000000","currency":"USD"}},{"number":"0006","description":"Dolor quidem aperiam rerum. Voluptates aut vel ut consequatur. Nam et unde cupiditate qui voluptates voluptatum. Temporibus assumenda enim nam neque.","duration":156986,"rate":"$92.00","rate_raw":"92.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Prof. Noah Jaskolski II","number":"0002","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$52.00","task_rate_raw":"52.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Mollitia ut vel quam. Quia et aut minus.","budgeted_hours":660,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":57,"tasks":[],"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428467,"start_date":"19\/Nov\/2023 21:11:27","end_date_raw":1700443047,"end_date":"20\/Nov\/2023 01:11:27","description":"Unde sequi dicta corporis odio.","billable":true,"duration":14580},{"start_date_raw":1700443347,"start_date":"20\/Nov\/2023 01:11:27","end_date_raw":1700489146,"end_date":"20\/Nov\/2023 14:11:46","description":"Qui rem id inventore velit corporis vitae.","billable":false,"duration":45799},{"start_date_raw":1700489446,"start_date":"20\/Nov\/2023 14:11:46","end_date_raw":1700514655,"end_date":"20\/Nov\/2023 21:11:55","description":"Rerum repellat unde et blanditiis sunt animi aliquid accusantium.","billable":false,"duration":25209},{"start_date_raw":1700514955,"start_date":"20\/Nov\/2023 21:11:55","end_date_raw":1700515449,"end_date":"20\/Nov\/2023 21:11:09","description":"Quasi velit sit et explicabo quibusdam nam.","billable":true,"duration":494},{"start_date_raw":1700515749,"start_date":"20\/Nov\/2023 21:11:09","end_date_raw":1700586653,"end_date":"21\/Nov\/2023 17:11:53","description":"Numquam eos aut eum est corrupti dolorem et.","billable":false,"duration":70904}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","currency":"USD"}},{"number":"0007","description":"Omnis totam eum sed dolores quod rerum. Ducimus voluptate iste quia dolorum consequatur sint. Velit vitae sint qui molestias. Dolores ea rerum voluptates iusto qui natus beatae.","duration":47670,"rate":"$88.00","rate_raw":"88.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Prof. Noah Jaskolski II","number":"0002","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$52.00","task_rate_raw":"52.000000","due_date":"25\/Nov\/2023","private_notes":"","public_notes":"Mollitia ut vel quam. Quia et aut minus.","budgeted_hours":660,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":57,"tasks":[],"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428467,"start_date":"19\/Nov\/2023 21:11:27","end_date_raw":1700476137,"end_date":"20\/Nov\/2023 10:11:57","description":"Sint laudantium quia eveniet quod nobis occaecati nihil.","billable":false,"duration":47670}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"cypress","balance":"13866.150000","payment_balance":"0.000000","credit_balance":"1013.630000","currency":"USD"}},{"number":"0008","description":"Molestiae dolor explicabo et in commodi eveniet. Expedita voluptatibus nihil ut. Et porro cumque nisi omnis maxime accusantium earum.","duration":638322,"rate":"$130.00","rate_raw":"130.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700504838,"end_date":"20\/Nov\/2023 18:11:18","description":"Delectus consequatur esse quaerat vel.","billable":false,"duration":76370},{"start_date_raw":1700505138,"start_date":"20\/Nov\/2023 18:11:18","end_date_raw":1700579924,"end_date":"21\/Nov\/2023 15:11:44","description":"Eveniet culpa qui quo architecto recusandae ut occaecati aut.","billable":true,"duration":74786},{"start_date_raw":1700580224,"start_date":"21\/Nov\/2023 15:11:44","end_date_raw":1700646586,"end_date":"22\/Nov\/2023 09:11:46","description":"Delectus quia officiis vero quia corporis.","billable":true,"duration":66362},{"start_date_raw":1700646886,"start_date":"22\/Nov\/2023 09:11:46","end_date_raw":1700732597,"end_date":"23\/Nov\/2023 09:11:17","description":"Non ut placeat dolorum et.","billable":true,"duration":85711},{"start_date_raw":1700732897,"start_date":"23\/Nov\/2023 09:11:17","end_date_raw":1700740803,"end_date":"23\/Nov\/2023 12:11:03","description":"Numquam natus accusantium voluptatem aliquam maxime fugiat voluptatem.","billable":true,"duration":7906},{"start_date_raw":1700741103,"start_date":"23\/Nov\/2023 12:11:03","end_date_raw":1700807283,"end_date":"24\/Nov\/2023 06:11:03","description":"Quae est ut optio atque fugit non.","billable":false,"duration":66180},{"start_date_raw":1700807583,"start_date":"24\/Nov\/2023 06:11:03","end_date_raw":1700889007,"end_date":"25\/Nov\/2023 05:11:07","description":"Natus voluptas quo id nam iure neque eveniet id.","billable":false,"duration":81424},{"start_date_raw":1700889307,"start_date":"25\/Nov\/2023 05:11:07","end_date_raw":1700949728,"end_date":"25\/Nov\/2023 22:11:08","description":"Sed suscipit voluptatem officia reprehenderit qui occaecati saepe veniam.","billable":false,"duration":60421},{"start_date_raw":1700950028,"start_date":"25\/Nov\/2023 22:11:08","end_date_raw":1700972964,"end_date":"26\/Nov\/2023 04:11:24","description":"Officiis sequi aut natus sapiente.","billable":true,"duration":22936},{"start_date_raw":1700973264,"start_date":"26\/Nov\/2023 04:11:24","end_date_raw":1700986155,"end_date":"26\/Nov\/2023 08:11:15","description":"Et similique odit quasi eaque harum.","billable":false,"duration":12891},{"start_date_raw":1700986455,"start_date":"26\/Nov\/2023 08:11:15","end_date_raw":1701069790,"end_date":"27\/Nov\/2023 07:11:10","description":"Qui magnam vero unde nam dolorem qui.","billable":true,"duration":83335}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","currency":"USD"}},{"number":"0009","description":"Ipsam numquam nesciunt corporis veritatis vitae porro maiores. Delectus sit itaque dolores. Atque et dolorem nisi est.","duration":439161,"rate":"$120.00","rate_raw":"120.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Mr. Easton Streich","number":"0003","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$153.00","task_rate_raw":"153.000000","due_date":"28\/Nov\/2023","private_notes":"","public_notes":"Debitis sit ut voluptatem eaque veritatis.","budgeted_hours":216,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":496,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700434593,"end_date":"19\/Nov\/2023 22:11:33","description":"At unde dolores quasi quia.","billable":true,"duration":6125},{"start_date_raw":1700434893,"start_date":"19\/Nov\/2023 23:11:33","end_date_raw":1700498703,"end_date":"20\/Nov\/2023 16:11:03","description":"Et quae non voluptatum nam quia velit suscipit.","billable":false,"duration":63810},{"start_date_raw":1700499003,"start_date":"20\/Nov\/2023 16:11:03","end_date_raw":1700548104,"end_date":"21\/Nov\/2023 06:11:24","description":"Quidem delectus sed et.","billable":true,"duration":49101},{"start_date_raw":1700548404,"start_date":"21\/Nov\/2023 06:11:24","end_date_raw":1700629022,"end_date":"22\/Nov\/2023 04:11:02","description":"Soluta velit enim explicabo dolorem commodi.","billable":false,"duration":80618},{"start_date_raw":1700629322,"start_date":"22\/Nov\/2023 05:11:02","end_date_raw":1700647716,"end_date":"22\/Nov\/2023 10:11:36","description":"Est magni qui quis.","billable":false,"duration":18394},{"start_date_raw":1700648016,"start_date":"22\/Nov\/2023 10:11:36","end_date_raw":1700731147,"end_date":"23\/Nov\/2023 09:11:07","description":"Saepe aspernatur non molestias dolor ea quos in.","billable":false,"duration":83131},{"start_date_raw":1700731447,"start_date":"23\/Nov\/2023 09:11:07","end_date_raw":1700782753,"end_date":"23\/Nov\/2023 23:11:13","description":"Alias id nihil laboriosam aliquam odio qui excepturi.","billable":true,"duration":51306},{"start_date_raw":1700783053,"start_date":"23\/Nov\/2023 23:11:13","end_date_raw":1700795456,"end_date":"24\/Nov\/2023 03:11:56","description":"Eos numquam et atque quia a qui nesciunt.","billable":false,"duration":12403},{"start_date_raw":1700795756,"start_date":"24\/Nov\/2023 03:11:56","end_date_raw":1700812488,"end_date":"24\/Nov\/2023 07:11:48","description":"Ut voluptas in natus qui.","billable":false,"duration":16732},{"start_date_raw":1700812788,"start_date":"24\/Nov\/2023 07:11:48","end_date_raw":1700842826,"end_date":"24\/Nov\/2023 16:11:26","description":"Est aut magnam ratione.","billable":false,"duration":30038},{"start_date_raw":1700843126,"start_date":"24\/Nov\/2023 16:11:26","end_date_raw":1700870629,"end_date":"25\/Nov\/2023 00:11:49","description":"Exercitationem non odio quasi ut saepe.","billable":true,"duration":27503}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"}},{"number":"0010","description":"Quo recusandae optio est saepe consectetur optio. Accusantium eum quia eaque. Voluptatum eligendi similique velit dolor eos rerum cumque quaerat.","duration":425934,"rate":"$98.00","rate_raw":"98.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Mr. Easton Streich","number":"0003","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$153.00","task_rate_raw":"153.000000","due_date":"28\/Nov\/2023","private_notes":"","public_notes":"Debitis sit ut voluptatem eaque veritatis.","budgeted_hours":216,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":496,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700463790,"end_date":"20\/Nov\/2023 07:11:10","description":"Culpa aut consequatur earum ut.","billable":false,"duration":35322},{"start_date_raw":1700464090,"start_date":"20\/Nov\/2023 07:11:10","end_date_raw":1700536862,"end_date":"21\/Nov\/2023 03:11:02","description":"Reprehenderit et esse qui hic quia est iusto.","billable":false,"duration":72772},{"start_date_raw":1700537162,"start_date":"21\/Nov\/2023 03:11:02","end_date_raw":1700592394,"end_date":"21\/Nov\/2023 18:11:34","description":"In est enim dolore nesciunt distinctio magni qui.","billable":true,"duration":55232},{"start_date_raw":1700592694,"start_date":"21\/Nov\/2023 18:11:34","end_date_raw":1700635771,"end_date":"22\/Nov\/2023 06:11:31","description":"Est saepe quasi alias aut odit officiis corporis.","billable":true,"duration":43077},{"start_date_raw":1700636071,"start_date":"22\/Nov\/2023 06:11:31","end_date_raw":1700637953,"end_date":"22\/Nov\/2023 07:11:53","description":"Consequuntur ipsa ut voluptate accusamus quibusdam sint sed.","billable":false,"duration":1882},{"start_date_raw":1700638253,"start_date":"22\/Nov\/2023 07:11:53","end_date_raw":1700687668,"end_date":"22\/Nov\/2023 21:11:28","description":"Sunt similique error et nostrum reprehenderit dolor.","billable":false,"duration":49415},{"start_date_raw":1700687968,"start_date":"22\/Nov\/2023 21:11:28","end_date_raw":1700712068,"end_date":"23\/Nov\/2023 04:11:08","description":"Aut rerum quis fugiat nostrum facilis ut.","billable":false,"duration":24100},{"start_date_raw":1700712368,"start_date":"23\/Nov\/2023 04:11:08","end_date_raw":1700783951,"end_date":"23\/Nov\/2023 23:11:11","description":"Aut culpa omnis sint et quos quisquam sint.","billable":true,"duration":71583},{"start_date_raw":1700784251,"start_date":"24\/Nov\/2023 00:11:11","end_date_raw":1700845166,"end_date":"24\/Nov\/2023 16:11:26","description":"Voluptas ut ratione porro eaque iste voluptas.","billable":true,"duration":60915},{"start_date_raw":1700845466,"start_date":"24\/Nov\/2023 17:11:26","end_date_raw":1700857102,"end_date":"24\/Nov\/2023 20:11:22","description":"Qui ipsa minus sed saepe maiores necessitatibus.","billable":true,"duration":11636}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"}},{"number":"0011","description":"Eligendi molestiae et quis et tempora esse ut. Sed ut est possimus et minus aut incidunt. Quibusdam rerum incidunt molestias est qui quam temporibus fuga.","duration":637522,"rate":"$120.00","rate_raw":"120.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Mr. Easton Streich","number":"0003","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$153.00","task_rate_raw":"153.000000","due_date":"28\/Nov\/2023","private_notes":"","public_notes":"Debitis sit ut voluptatem eaque veritatis.","budgeted_hours":216,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":496,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700499282,"end_date":"20\/Nov\/2023 16:11:42","description":"Quasi temporibus doloremque consequatur minus pariatur facere.","billable":true,"duration":70814},{"start_date_raw":1700499582,"start_date":"20\/Nov\/2023 16:11:42","end_date_raw":1700584386,"end_date":"21\/Nov\/2023 16:11:06","description":"Id distinctio sed eos qui.","billable":true,"duration":84804},{"start_date_raw":1700584686,"start_date":"21\/Nov\/2023 16:11:06","end_date_raw":1700635554,"end_date":"22\/Nov\/2023 06:11:54","description":"Facere explicabo non nostrum.","billable":true,"duration":50868},{"start_date_raw":1700635854,"start_date":"22\/Nov\/2023 06:11:54","end_date_raw":1700672533,"end_date":"22\/Nov\/2023 17:11:13","description":"Numquam sit labore facere voluptatibus quibusdam reiciendis et.","billable":true,"duration":36679},{"start_date_raw":1700672833,"start_date":"22\/Nov\/2023 17:11:13","end_date_raw":1700678587,"end_date":"22\/Nov\/2023 18:11:07","description":"Perspiciatis ad hic nostrum et.","billable":true,"duration":5754},{"start_date_raw":1700678887,"start_date":"22\/Nov\/2023 18:11:07","end_date_raw":1700708730,"end_date":"23\/Nov\/2023 03:11:30","description":"Qui culpa iure eos quaerat voluptatum numquam inventore.","billable":true,"duration":29843},{"start_date_raw":1700709030,"start_date":"23\/Nov\/2023 03:11:30","end_date_raw":1700765439,"end_date":"23\/Nov\/2023 18:11:39","description":"Similique molestiae atque voluptatem debitis dolorem quos quis et.","billable":false,"duration":56409},{"start_date_raw":1700765739,"start_date":"23\/Nov\/2023 18:11:39","end_date_raw":1700831780,"end_date":"24\/Nov\/2023 13:11:20","description":"Nam dolorum optio et omnis.","billable":true,"duration":66041},{"start_date_raw":1700832080,"start_date":"24\/Nov\/2023 13:11:20","end_date_raw":1700844498,"end_date":"24\/Nov\/2023 16:11:18","description":"Non eos amet repellat tempore id.","billable":false,"duration":12418},{"start_date_raw":1700844798,"start_date":"24\/Nov\/2023 16:11:18","end_date_raw":1700899153,"end_date":"25\/Nov\/2023 07:11:13","description":"Iste neque nostrum laudantium officia.","billable":false,"duration":54355},{"start_date_raw":1700899453,"start_date":"25\/Nov\/2023 08:11:13","end_date_raw":1700971949,"end_date":"26\/Nov\/2023 04:11:29","description":"Ut quia ratione sed et.","billable":true,"duration":72496},{"start_date_raw":1700972249,"start_date":"26\/Nov\/2023 04:11:29","end_date_raw":1700984833,"end_date":"26\/Nov\/2023 07:11:13","description":"Sapiente quia magni quisquam eos rerum rem.","billable":false,"duration":12584},{"start_date_raw":1700985133,"start_date":"26\/Nov\/2023 07:11:13","end_date_raw":1701069590,"end_date":"27\/Nov\/2023 07:11:50","description":"Nulla et ducimus doloribus est.","billable":true,"duration":84457}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"}},{"number":"0012","description":"Ea cumque amet quas et suscipit. Voluptatum libero enim minus necessitatibus qui voluptatem. Voluptates soluta quae in et aut possimus veniam.","duration":283580,"rate":"$78.00","rate_raw":"78.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Mr. Easton Streich","number":"0003","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$153.00","task_rate_raw":"153.000000","due_date":"28\/Nov\/2023","private_notes":"","public_notes":"Debitis sit ut voluptatem eaque veritatis.","budgeted_hours":216,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":496,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700469690,"end_date":"20\/Nov\/2023 08:11:30","description":"Placeat vel sit voluptas architecto sed.","billable":true,"duration":41222},{"start_date_raw":1700469990,"start_date":"20\/Nov\/2023 08:11:30","end_date_raw":1700483859,"end_date":"20\/Nov\/2023 12:11:39","description":"Voluptatem est quo est dolorem.","billable":true,"duration":13869},{"start_date_raw":1700484159,"start_date":"20\/Nov\/2023 12:11:39","end_date_raw":1700541376,"end_date":"21\/Nov\/2023 04:11:16","description":"Perferendis nulla quos omnis inventore sint.","billable":false,"duration":57217},{"start_date_raw":1700541676,"start_date":"21\/Nov\/2023 04:11:16","end_date_raw":1700609280,"end_date":"21\/Nov\/2023 23:11:00","description":"Quia quae ad cum neque.","billable":true,"duration":67604},{"start_date_raw":1700609580,"start_date":"21\/Nov\/2023 23:11:00","end_date_raw":1700668490,"end_date":"22\/Nov\/2023 15:11:50","description":"Pariatur et ipsa cumque consequatur voluptatum nemo.","billable":true,"duration":58910},{"start_date_raw":1700668790,"start_date":"22\/Nov\/2023 15:11:50","end_date_raw":1700690815,"end_date":"22\/Nov\/2023 22:11:55","description":"Officia explicabo illo ex tenetur.","billable":true,"duration":22025},{"start_date_raw":1700691115,"start_date":"22\/Nov\/2023 22:11:55","end_date_raw":1700713848,"end_date":"23\/Nov\/2023 04:11:48","description":"Quasi neque tempore aut at.","billable":true,"duration":22733}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000","currency":"USD"}},{"number":"0013","description":"Enim eveniet rem illo sed voluptatem vero dolorem. Sed consequatur quia autem culpa. Sed perspiciatis ullam non.","duration":512814,"rate":"$145.00","rate_raw":"145.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700442008,"end_date":"20\/Nov\/2023 01:11:08","description":"Et et delectus in rerum fuga et ipsam.","billable":true,"duration":13540},{"start_date_raw":1700442308,"start_date":"20\/Nov\/2023 01:11:08","end_date_raw":1700488304,"end_date":"20\/Nov\/2023 13:11:44","description":"In porro et sed eos.","billable":true,"duration":45996},{"start_date_raw":1700488604,"start_date":"20\/Nov\/2023 13:11:44","end_date_raw":1700529328,"end_date":"21\/Nov\/2023 01:11:28","description":"Eveniet similique sint minima voluptatibus voluptatem sunt.","billable":false,"duration":40724},{"start_date_raw":1700529628,"start_date":"21\/Nov\/2023 01:11:28","end_date_raw":1700560989,"end_date":"21\/Nov\/2023 10:11:09","description":"Ut est fuga id qui ut.","billable":false,"duration":31361},{"start_date_raw":1700561289,"start_date":"21\/Nov\/2023 10:11:09","end_date_raw":1700635644,"end_date":"22\/Nov\/2023 06:11:24","description":"Est consequatur nisi itaque.","billable":false,"duration":74355},{"start_date_raw":1700635944,"start_date":"22\/Nov\/2023 06:11:24","end_date_raw":1700650878,"end_date":"22\/Nov\/2023 11:11:18","description":"Ut vitae et velit magnam aut sed ut.","billable":true,"duration":14934},{"start_date_raw":1700651178,"start_date":"22\/Nov\/2023 11:11:18","end_date_raw":1700672376,"end_date":"22\/Nov\/2023 16:11:36","description":"Id odio laudantium quae similique.","billable":false,"duration":21198},{"start_date_raw":1700672676,"start_date":"22\/Nov\/2023 17:11:36","end_date_raw":1700734868,"end_date":"23\/Nov\/2023 10:11:08","description":"Saepe non vel reiciendis autem quidem quos.","billable":true,"duration":62192},{"start_date_raw":1700735168,"start_date":"23\/Nov\/2023 10:11:08","end_date_raw":1700772446,"end_date":"23\/Nov\/2023 20:11:26","description":"Occaecati commodi cupiditate esse molestiae velit.","billable":true,"duration":37278},{"start_date_raw":1700772746,"start_date":"23\/Nov\/2023 20:11:26","end_date_raw":1700785864,"end_date":"24\/Nov\/2023 00:11:04","description":"Quia et cupiditate expedita cumque quas.","billable":true,"duration":13118},{"start_date_raw":1700786164,"start_date":"24\/Nov\/2023 00:11:04","end_date_raw":1700806681,"end_date":"24\/Nov\/2023 06:11:01","description":"Eos consequatur soluta labore soluta ut.","billable":true,"duration":20517},{"start_date_raw":1700806981,"start_date":"24\/Nov\/2023 06:11:01","end_date_raw":1700839054,"end_date":"24\/Nov\/2023 15:11:34","description":"Impedit vel pariatur dicta necessitatibus at harum eius.","billable":true,"duration":32073},{"start_date_raw":1700839354,"start_date":"24\/Nov\/2023 15:11:34","end_date_raw":1700866888,"end_date":"24\/Nov\/2023 23:11:28","description":"Laboriosam nihil veritatis voluptatum qui laboriosam iusto.","billable":true,"duration":27534},{"start_date_raw":1700867188,"start_date":"24\/Nov\/2023 23:11:28","end_date_raw":1700875021,"end_date":"25\/Nov\/2023 01:11:01","description":"Error accusamus sapiente reiciendis.","billable":true,"duration":7833},{"start_date_raw":1700875321,"start_date":"25\/Nov\/2023 01:11:01","end_date_raw":1700886769,"end_date":"25\/Nov\/2023 04:11:49","description":"Impedit eius consequatur quod qui quod expedita quis.","billable":false,"duration":11448},{"start_date_raw":1700887069,"start_date":"25\/Nov\/2023 04:11:49","end_date_raw":1700945782,"end_date":"25\/Nov\/2023 20:11:22","description":"Tempora omnis nesciunt placeat omnis architecto quis.","billable":true,"duration":58713}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"}},{"number":"0014","description":"In soluta aliquid et eius. Molestiae veritatis animi culpa et amet porro modi ut. Id sequi nobis itaque modi explicabo voluptatem quam. Non ex voluptatem error aspernatur odit.","duration":346244,"rate":"$70.00","rate_raw":"70.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Elenor Orn","number":"0004","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$39.00","task_rate_raw":"39.000000","due_date":"27\/Nov\/2023","private_notes":"","public_notes":"Distinctio ut voluptas deleniti est sed quae.","budgeted_hours":372,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":331,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700458211,"end_date":"20\/Nov\/2023 05:11:11","description":"Voluptate aut dicta recusandae consectetur est ducimus.","billable":false,"duration":29743},{"start_date_raw":1700458511,"start_date":"20\/Nov\/2023 05:11:11","end_date_raw":1700516247,"end_date":"20\/Nov\/2023 21:11:27","description":"Dolores incidunt praesentium rerum.","billable":false,"duration":57736},{"start_date_raw":1700516547,"start_date":"20\/Nov\/2023 21:11:27","end_date_raw":1700549251,"end_date":"21\/Nov\/2023 06:11:31","description":"Perspiciatis consequatur et alias praesentium placeat modi aut.","billable":true,"duration":32704},{"start_date_raw":1700549551,"start_date":"21\/Nov\/2023 06:11:31","end_date_raw":1700618445,"end_date":"22\/Nov\/2023 02:11:45","description":"Esse libero incidunt non rem sunt quisquam repudiandae nisi.","billable":true,"duration":68894},{"start_date_raw":1700618745,"start_date":"22\/Nov\/2023 02:11:45","end_date_raw":1700698086,"end_date":"23\/Nov\/2023 00:11:06","description":"Earum consectetur esse fugit sint autem tempore.","billable":true,"duration":79341},{"start_date_raw":1700698386,"start_date":"23\/Nov\/2023 00:11:06","end_date_raw":1700776212,"end_date":"23\/Nov\/2023 21:11:12","description":"Saepe sit consequatur vel eos ad iusto nobis.","billable":true,"duration":77826}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Ready to do","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"}},{"number":"0015","description":"Minus accusamus illum quia nihil voluptatum qui mollitia vel. Natus fugiat sequi quod eius occaecati non. Minus rerum ut eos est eveniet quae iure.","duration":410859,"rate":"$13.00","rate_raw":"13.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Elenor Orn","number":"0004","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$39.00","task_rate_raw":"39.000000","due_date":"27\/Nov\/2023","private_notes":"","public_notes":"Distinctio ut voluptas deleniti est sed quae.","budgeted_hours":372,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":331,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428468,"start_date":"19\/Nov\/2023 21:11:28","end_date_raw":1700506053,"end_date":"20\/Nov\/2023 18:11:33","description":"Iste neque officiis eum maiores.","billable":true,"duration":77585},{"start_date_raw":1700506353,"start_date":"20\/Nov\/2023 18:11:33","end_date_raw":1700572042,"end_date":"21\/Nov\/2023 13:11:22","description":"Minus perferendis quia amet.","billable":true,"duration":65689},{"start_date_raw":1700572342,"start_date":"21\/Nov\/2023 13:11:22","end_date_raw":1700637291,"end_date":"22\/Nov\/2023 07:11:51","description":"Commodi quaerat hic minus et voluptas velit.","billable":true,"duration":64949},{"start_date_raw":1700637591,"start_date":"22\/Nov\/2023 07:11:51","end_date_raw":1700649610,"end_date":"22\/Nov\/2023 10:11:10","description":"Vitae rerum natus aperiam quia explicabo.","billable":false,"duration":12019},{"start_date_raw":1700649910,"start_date":"22\/Nov\/2023 10:11:10","end_date_raw":1700693674,"end_date":"22\/Nov\/2023 22:11:34","description":"Quos sunt dolorum eveniet provident ut.","billable":false,"duration":43764},{"start_date_raw":1700693974,"start_date":"22\/Nov\/2023 22:11:34","end_date_raw":1700775335,"end_date":"23\/Nov\/2023 21:11:35","description":"Animi quibusdam quisquam ea error earum consectetur.","billable":true,"duration":81361},{"start_date_raw":1700775635,"start_date":"23\/Nov\/2023 21:11:35","end_date_raw":1700808126,"end_date":"24\/Nov\/2023 06:11:06","description":"Ratione ipsam molestiae dolorem sit architecto voluptas.","billable":true,"duration":32491},{"start_date_raw":1700808426,"start_date":"24\/Nov\/2023 06:11:06","end_date_raw":1700817758,"end_date":"24\/Nov\/2023 09:11:38","description":"Maxime reprehenderit voluptates culpa.","billable":false,"duration":9332},{"start_date_raw":1700818058,"start_date":"24\/Nov\/2023 09:11:38","end_date_raw":1700841727,"end_date":"24\/Nov\/2023 16:11:07","description":"Atque deleniti et laboriosam molestias repellat accusamus omnis.","billable":false,"duration":23669}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"}},{"number":"0016","description":"Temporibus illum voluptatibus molestias quia omnis illo molestias corporis. Hic et hic quia dolores quas sint dolorem. Repellendus minus quae fuga illum amet in voluptatum. Rerum mollitia est eum voluptatum architecto non nisi qui. Est et dolores omnis placeat repellat sed facilis.","duration":435319,"rate":"$89.00","rate_raw":"89.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Elenor Orn","number":"0004","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$39.00","task_rate_raw":"39.000000","due_date":"27\/Nov\/2023","private_notes":"","public_notes":"Distinctio ut voluptas deleniti est sed quae.","budgeted_hours":372,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":331,"tasks":[],"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700496403,"end_date":"20\/Nov\/2023 16:11:43","description":"Sunt unde repellat reiciendis quos porro et dolores.","billable":true,"duration":67934},{"start_date_raw":1700496703,"start_date":"20\/Nov\/2023 16:11:43","end_date_raw":1700551129,"end_date":"21\/Nov\/2023 07:11:49","description":"Voluptatem laborum repudiandae enim asperiores.","billable":false,"duration":54426},{"start_date_raw":1700551429,"start_date":"21\/Nov\/2023 07:11:49","end_date_raw":1700631865,"end_date":"22\/Nov\/2023 05:11:25","description":"Placeat numquam magnam occaecati.","billable":false,"duration":80436},{"start_date_raw":1700632165,"start_date":"22\/Nov\/2023 05:11:25","end_date_raw":1700695854,"end_date":"22\/Nov\/2023 23:11:54","description":"Qui quo et est vero autem reprehenderit.","billable":false,"duration":63689},{"start_date_raw":1700696154,"start_date":"22\/Nov\/2023 23:11:54","end_date_raw":1700736857,"end_date":"23\/Nov\/2023 10:11:17","description":"Et voluptatem distinctio dolor fuga hic ea.","billable":false,"duration":40703},{"start_date_raw":1700737157,"start_date":"23\/Nov\/2023 10:11:17","end_date_raw":1700790692,"end_date":"24\/Nov\/2023 01:11:32","description":"Quo expedita quidem ab dolor quam expedita porro.","billable":true,"duration":53535},{"start_date_raw":1700790992,"start_date":"24\/Nov\/2023 01:11:32","end_date_raw":1700817527,"end_date":"24\/Nov\/2023 09:11:47","description":"Adipisci voluptatem officiis quaerat ut quos facilis.","billable":false,"duration":26535},{"start_date_raw":1700817827,"start_date":"24\/Nov\/2023 09:11:47","end_date_raw":1700865888,"end_date":"24\/Nov\/2023 22:11:48","description":"Tenetur ut dolorem vero.","billable":true,"duration":48061}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Done","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Walsh-Considine","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1960.450000"}},{"number":"0017","description":"Repudiandae nam labore dolores nihil sunt dolorem recusandae rerum. Ut consequatur vel et aut facilis. Sapiente distinctio cupiditate qui repellat ipsum harum.","duration":835159,"rate":"$65.00","rate_raw":"65.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":[],"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700448921,"end_date":"20\/Nov\/2023 02:11:21","description":"Veniam iusto aperiam quis sunt nihil qui neque.","billable":true,"duration":20452},{"start_date_raw":1700449221,"start_date":"20\/Nov\/2023 03:11:21","end_date_raw":1700480544,"end_date":"20\/Nov\/2023 11:11:24","description":"Molestiae vero ea quis numquam et dicta reprehenderit.","billable":true,"duration":31323},{"start_date_raw":1700480844,"start_date":"20\/Nov\/2023 11:11:24","end_date_raw":1700513241,"end_date":"20\/Nov\/2023 20:11:21","description":"Qui id accusantium eius esse pariatur qui.","billable":false,"duration":32397},{"start_date_raw":1700513541,"start_date":"20\/Nov\/2023 20:11:21","end_date_raw":1700579256,"end_date":"21\/Nov\/2023 15:11:36","description":"Unde porro perspiciatis dolor praesentium dolor.","billable":true,"duration":65715},{"start_date_raw":1700579556,"start_date":"21\/Nov\/2023 15:11:36","end_date_raw":1700631702,"end_date":"22\/Nov\/2023 05:11:42","description":"Laboriosam eligendi deserunt veritatis impedit ipsum rerum voluptas.","billable":false,"duration":52146},{"start_date_raw":1700632002,"start_date":"22\/Nov\/2023 05:11:42","end_date_raw":1700687284,"end_date":"22\/Nov\/2023 21:11:04","description":"Molestiae sint a facere.","billable":true,"duration":55282},{"start_date_raw":1700687584,"start_date":"22\/Nov\/2023 21:11:04","end_date_raw":1700731618,"end_date":"23\/Nov\/2023 09:11:58","description":"Asperiores in repudiandae eligendi sed eveniet sequi quae.","billable":false,"duration":44034},{"start_date_raw":1700731918,"start_date":"23\/Nov\/2023 09:11:58","end_date_raw":1700785496,"end_date":"24\/Nov\/2023 00:11:56","description":"Ratione quia rem odit ea doloremque et.","billable":true,"duration":53578},{"start_date_raw":1700785796,"start_date":"24\/Nov\/2023 00:11:56","end_date_raw":1700814699,"end_date":"24\/Nov\/2023 08:11:39","description":"Deserunt quam alias incidunt sit placeat tenetur.","billable":true,"duration":28903},{"start_date_raw":1700814999,"start_date":"24\/Nov\/2023 08:11:39","end_date_raw":1700889011,"end_date":"25\/Nov\/2023 05:11:11","description":"Libero sed numquam quidem vel esse magni vel laudantium.","billable":false,"duration":74012},{"start_date_raw":1700889311,"start_date":"25\/Nov\/2023 05:11:11","end_date_raw":1700943511,"end_date":"25\/Nov\/2023 20:11:31","description":"Rerum aliquid aliquam error deleniti quo eaque.","billable":true,"duration":54200},{"start_date_raw":1700943811,"start_date":"25\/Nov\/2023 20:11:31","end_date_raw":1701013647,"end_date":"26\/Nov\/2023 15:11:27","description":"Quos vel est rerum nihil id.","billable":false,"duration":69836},{"start_date_raw":1701013947,"start_date":"26\/Nov\/2023 15:11:27","end_date_raw":1701099520,"end_date":"27\/Nov\/2023 15:11:40","description":"Cum quia maxime dignissimos quo.","billable":true,"duration":85573},{"start_date_raw":1701099820,"start_date":"27\/Nov\/2023 15:11:40","end_date_raw":1701163104,"end_date":"28\/Nov\/2023 09:11:24","description":"Amet ea exercitationem quo sed eos corporis.","billable":false,"duration":63284},{"start_date_raw":1701163404,"start_date":"28\/Nov\/2023 09:11:24","end_date_raw":1701220140,"end_date":"29\/Nov\/2023 01:11:00","description":"Sunt voluptas atque odio nesciunt aliquam in earum.","billable":true,"duration":56736},{"start_date_raw":1701220440,"start_date":"29\/Nov\/2023 01:11:00","end_date_raw":1701268128,"end_date":"29\/Nov\/2023 14:11:48","description":"Odio voluptatibus rerum non.","billable":false,"duration":47688}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Hoeger, Hahn and Cole","balance":"0.000000","payment_balance":"0.000000","credit_balance":"1022.550000","vat_number":"VAT123"}},{"number":"0018","description":"Odit rerum iusto quibusdam. A mollitia cupiditate enim consequatur omnis qui voluptas quibusdam. Recusandae et non ut ipsum asperiores non iusto.","duration":312865,"rate":"$95.00","rate_raw":"95.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Maryjane Macejkovic","number":"0005","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$78.00","task_rate_raw":"78.000000","due_date":"26\/Nov\/2023","private_notes":"","public_notes":"Nesciunt est sit ea explicabo.","budgeted_hours":405,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":194,"tasks":[],"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700476677,"end_date":"20\/Nov\/2023 10:11:57","description":"Quam dolores ut dolorem quo sint atque.","billable":true,"duration":48208},{"start_date_raw":1700476977,"start_date":"20\/Nov\/2023 10:11:57","end_date_raw":1700520944,"end_date":"20\/Nov\/2023 22:11:44","description":"Unde minus veniam corporis qui laboriosam suscipit quas.","billable":true,"duration":43967},{"start_date_raw":1700521244,"start_date":"20\/Nov\/2023 23:11:44","end_date_raw":1700602639,"end_date":"21\/Nov\/2023 21:11:19","description":"Beatae molestiae molestias sed dolor recusandae et id eligendi.","billable":false,"duration":81395},{"start_date_raw":1700602939,"start_date":"21\/Nov\/2023 21:11:19","end_date_raw":1700682077,"end_date":"22\/Nov\/2023 19:11:17","description":"Repellendus nam perspiciatis exercitationem in iste officia.","billable":true,"duration":79138},{"start_date_raw":1700682377,"start_date":"22\/Nov\/2023 19:11:17","end_date_raw":1700692054,"end_date":"22\/Nov\/2023 22:11:34","description":"Consequatur quaerat dolor consequuntur aperiam enim reiciendis.","billable":true,"duration":9677},{"start_date_raw":1700692354,"start_date":"22\/Nov\/2023 22:11:34","end_date_raw":1700742834,"end_date":"23\/Nov\/2023 12:11:54","description":"Qui quia ut sed accusantium odit reprehenderit quaerat.","billable":true,"duration":50480}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","currency":"USD"}},{"number":"0019","description":"Eius et dolor libero repellendus iste. Nemo sit error sed necessitatibus architecto et. Aspernatur omnis doloremque animi quas sed.","duration":387217,"rate":"$87.00","rate_raw":"87.000000","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","date":"19\/Nov\/2023","project":{"name":"Maryjane Macejkovic","number":"0005","created_at":"19\/Nov\/2023","updated_at":"19\/Nov\/2023","task_rate":"$78.00","task_rate_raw":"78.000000","due_date":"26\/Nov\/2023","private_notes":"","public_notes":"Nesciunt est sit ea explicabo.","budgeted_hours":405,"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","color":"#fff","current_hours":194,"tasks":[],"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","currency":"USD"},"user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"}},"time_log":[{"start_date_raw":1700428469,"start_date":"19\/Nov\/2023 21:11:29","end_date_raw":1700434042,"end_date":"19\/Nov\/2023 22:11:22","description":"Aut aliquam totam in reprehenderit sint suscipit earum.","billable":false,"duration":5573},{"start_date_raw":1700434342,"start_date":"19\/Nov\/2023 22:11:22","end_date_raw":1700467844,"end_date":"20\/Nov\/2023 08:11:44","description":"Hic aliquid natus est.","billable":false,"duration":33502},{"start_date_raw":1700468144,"start_date":"20\/Nov\/2023 08:11:44","end_date_raw":1700532877,"end_date":"21\/Nov\/2023 02:11:37","description":"Illo atque dolores eligendi minus et ut consequuntur.","billable":false,"duration":64733},{"start_date_raw":1700533177,"start_date":"21\/Nov\/2023 02:11:37","end_date_raw":1700619369,"end_date":"22\/Nov\/2023 02:11:09","description":"Libero ipsa eligendi sit dolor eligendi quibusdam dicta tenetur.","billable":false,"duration":86192},{"start_date_raw":1700619669,"start_date":"22\/Nov\/2023 02:11:09","end_date_raw":1700646879,"end_date":"22\/Nov\/2023 09:11:39","description":"Dolor unde assumenda blanditiis tenetur blanditiis ipsam quis.","billable":true,"duration":27210},{"start_date_raw":1700647179,"start_date":"22\/Nov\/2023 09:11:39","end_date_raw":1700704537,"end_date":"23\/Nov\/2023 01:11:37","description":"Reprehenderit possimus nisi recusandae.","billable":true,"duration":57358},{"start_date_raw":1700704837,"start_date":"23\/Nov\/2023 02:11:37","end_date_raw":1700733175,"end_date":"23\/Nov\/2023 09:11:55","description":"Aut saepe sint qui magni.","billable":false,"duration":28338},{"start_date_raw":1700733475,"start_date":"23\/Nov\/2023 09:11:55","end_date_raw":1700735626,"end_date":"23\/Nov\/2023 10:11:46","description":"Facere repellendus voluptas illo a.","billable":true,"duration":2151},{"start_date_raw":1700735926,"start_date":"23\/Nov\/2023 10:11:46","end_date_raw":1700769798,"end_date":"23\/Nov\/2023 20:11:18","description":"Voluptatem praesentium ipsum soluta earum.","billable":false,"duration":33872},{"start_date_raw":1700770098,"start_date":"23\/Nov\/2023 20:11:18","end_date_raw":1700818386,"end_date":"24\/Nov\/2023 09:11:06","description":"Dicta eum quis dicta quae.","billable":true,"duration":48288}],"custom_value1":"","custom_value2":"","custom_value3":"","custom_value4":"","status":"Backlog","user":{"name":"Laron Weissnat Danika Flatley","email":"small@example.com"},"client":{"name":"Medhurst Inc","balance":"37633.780000","payment_balance":"0.000000","credit_balance":"1025.100000","currency":"USD"}}]'; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index d4459049327c..6e945840edb1 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -482,6 +482,8 @@ class TemplateService default => $processed = [], }; + nlog(json_encode($processed)); + return $processed; })->toArray(); From d7dfd4ab65ddee718b8902373590db75f83566ef Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 16:55:18 +1000 Subject: [PATCH 10/30] Fixes for translations in client portal --- app/Livewire/Profile/Settings/PersonalAddress.php | 6 +----- app/Livewire/Profile/Settings/ShippingAddress.php | 6 +----- app/Models/Currency.php | 5 +++++ app/Utils/TranslationHelper.php | 7 +++++-- .../v3/authentication/register-form.blade.php | 4 ++-- resources/views/portal/ninja2020/auth/register.blade.php | 2 +- .../components/livewire/required-client-info.blade.php | 2 +- .../ninja2020/gateways/forte/ach/authorize.blade.php | 4 ++-- .../ninja2020/gateways/stripe/ach/authorize.blade.php | 6 +++--- .../ninja2020/gateways/stripe/becs/authorize.blade.php | 4 ++-- .../gateways/stripe/przelewy24/authorize.blade.php | 4 ++-- resources/views/portal/ninja2020/plan/trial.blade.php | 2 +- resources/views/portal/ninja2020/profile/index.blade.php | 4 ++-- .../ninja2020/profile/settings/personal-address.blade.php | 2 +- .../ninja2020/profile/settings/shipping-address.blade.php | 2 +- .../views/portal/ninja2020/vendor_profile/edit.blade.php | 2 +- 16 files changed, 31 insertions(+), 31 deletions(-) diff --git a/app/Livewire/Profile/Settings/PersonalAddress.php b/app/Livewire/Profile/Settings/PersonalAddress.php index f067d8177ba5..f0ab4bcc004e 100644 --- a/app/Livewire/Profile/Settings/PersonalAddress.php +++ b/app/Livewire/Profile/Settings/PersonalAddress.php @@ -20,8 +20,6 @@ class PersonalAddress extends Component public $country_id; - public $countries; - public $saved; protected $rules = [ @@ -33,7 +31,7 @@ class PersonalAddress extends Component 'country_id' => ['sometimes'], ]; - public function mount($countries) + public function mount() { $this->fill([ 'profile' => auth()->guard('contact')->user()->client, @@ -43,8 +41,6 @@ class PersonalAddress extends Component 'state' => auth()->guard('contact')->user()->client->state, 'postal_code' => auth()->guard('contact')->user()->client->postal_code, 'country_id' => auth()->guard('contact')->user()->client->country_id, - - 'countries' => $countries, 'saved' => ctrans('texts.save'), ]); } diff --git a/app/Livewire/Profile/Settings/ShippingAddress.php b/app/Livewire/Profile/Settings/ShippingAddress.php index fe23a24fa9cd..41393bc40b48 100644 --- a/app/Livewire/Profile/Settings/ShippingAddress.php +++ b/app/Livewire/Profile/Settings/ShippingAddress.php @@ -20,8 +20,6 @@ class ShippingAddress extends Component public $shipping_country_id; - public $countries; - public $saved; protected $rules = [ @@ -33,7 +31,7 @@ class ShippingAddress extends Component 'shipping_country_id' => ['sometimes'], ]; - public function mount($countries) + public function mount() { $this->fill([ 'profile' => auth()->guard('contact')->user()->client, @@ -43,8 +41,6 @@ class ShippingAddress extends Component 'shipping_state' => auth()->guard('contact')->user()->client->shipping_state, 'shipping_postal_code' => auth()->guard('contact')->user()->client->shipping_postal_code, 'shipping_country_id' => auth()->guard('contact')->user()->client->shipping_country_id, - - 'countries' => $countries, 'saved' => ctrans('texts.save'), ]); } diff --git a/app/Models/Currency.php b/app/Models/Currency.php index 33c3bf27d495..918977effffe 100644 --- a/app/Models/Currency.php +++ b/app/Models/Currency.php @@ -53,4 +53,9 @@ class Currency extends StaticModel 'deleted_at' => 'timestamp', 'precision' => 'integer', ]; + + public function getName(): string + { + return trans('texts.currency_'.$this->name); + } } diff --git a/app/Utils/TranslationHelper.php b/app/Utils/TranslationHelper.php index 6a7f80300180..c80cdbeb19d2 100644 --- a/app/Utils/TranslationHelper.php +++ b/app/Utils/TranslationHelper.php @@ -34,8 +34,10 @@ class TranslationHelper { /** @var \Illuminate\Support\Collection<\App\Models\Country> */ - // $countries = app('countries'); + $countries = app('countries'); + return $countries; + return \App\Models\Country::all()->each(function ($country) { $country->name = ctrans('texts.country_'.$country->name); })->sortBy(function ($country) { @@ -73,7 +75,8 @@ class TranslationHelper { /** @var \Illuminate\Support\Collection<\App\Models\Currency> */ - // $currencies = app('currencies'); + $currencies = app('currencies'); + return $currencies; return \App\Models\Currency::all()->each(function ($currency) { $currency->name = ctrans('texts.currency_'.Str::slug($currency->name, '_')); diff --git a/resources/views/billing-portal/v3/authentication/register-form.blade.php b/resources/views/billing-portal/v3/authentication/register-form.blade.php index 5ebb0a7de21c..83230c043bd8 100644 --- a/resources/views/billing-portal/v3/authentication/register-form.blade.php +++ b/resources/views/billing-portal/v3/authentication/register-form.blade.php @@ -61,7 +61,7 @@ @endforeach @@ -75,7 +75,7 @@ @endforeach diff --git a/resources/views/portal/ninja2020/auth/register.blade.php b/resources/views/portal/ninja2020/auth/register.blade.php index 0dc41c225a32..d0f9d4093b1e 100644 --- a/resources/views/portal/ninja2020/auth/register.blade.php +++ b/resources/views/portal/ninja2020/auth/register.blade.php @@ -83,7 +83,7 @@ @foreach(App\Utils\TranslationHelper::getCountries() as $country) @endforeach diff --git a/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php b/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php index 80070339824d..bbf1165f8056 100644 --- a/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php +++ b/resources/views/portal/ninja2020/components/livewire/required-client-info.blade.php @@ -22,7 +22,7 @@ @foreach($countries as $country) @endforeach diff --git a/resources/views/portal/ninja2020/gateways/forte/ach/authorize.blade.php b/resources/views/portal/ninja2020/gateways/forte/ach/authorize.blade.php index 1eba7a6aa349..f621f353e53d 100644 --- a/resources/views/portal/ninja2020/gateways/forte/ach/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/forte/ach/authorize.blade.php @@ -57,7 +57,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')]) @endcomponent @@ -65,7 +65,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')]) @endcomponent diff --git a/resources/views/portal/ninja2020/gateways/stripe/ach/authorize.blade.php b/resources/views/portal/ninja2020/gateways/stripe/ach/authorize.blade.php index 80b447dfe273..7a9b3c93dc28 100644 --- a/resources/views/portal/ninja2020/gateways/stripe/ach/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/stripe/ach/authorize.blade.php @@ -51,9 +51,9 @@ @foreach($countries as $country) @if($country->iso_3166_2 == 'US') - + @else - + @endif @endforeach @@ -64,7 +64,7 @@ @foreach($currencies as $currency) @if($currency->code == 'USD') - + @else @endif diff --git a/resources/views/portal/ninja2020/gateways/stripe/becs/authorize.blade.php b/resources/views/portal/ninja2020/gateways/stripe/becs/authorize.blade.php index 24af2696f215..6d99320aa665 100644 --- a/resources/views/portal/ninja2020/gateways/stripe/becs/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/stripe/becs/authorize.blade.php @@ -47,7 +47,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')]) @endcomponent @@ -55,7 +55,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')]) @endcomponent diff --git a/resources/views/portal/ninja2020/gateways/stripe/przelewy24/authorize.blade.php b/resources/views/portal/ninja2020/gateways/stripe/przelewy24/authorize.blade.php index 24af2696f215..6d99320aa665 100644 --- a/resources/views/portal/ninja2020/gateways/stripe/przelewy24/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/stripe/przelewy24/authorize.blade.php @@ -47,7 +47,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')]) @endcomponent @@ -55,7 +55,7 @@ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')]) @endcomponent diff --git a/resources/views/portal/ninja2020/plan/trial.blade.php b/resources/views/portal/ninja2020/plan/trial.blade.php index 8db0c4d6ac39..4be765d1bc3a 100644 --- a/resources/views/portal/ninja2020/plan/trial.blade.php +++ b/resources/views/portal/ninja2020/plan/trial.blade.php @@ -1526,7 +1526,7 @@ Ensure the default browser behavior of the `hidden` attribute. diff --git a/resources/views/portal/ninja2020/profile/index.blade.php b/resources/views/portal/ninja2020/profile/index.blade.php index d44b9aeff603..2e2cfd9220ee 100644 --- a/resources/views/portal/ninja2020/profile/index.blade.php +++ b/resources/views/portal/ninja2020/profile/index.blade.php @@ -28,8 +28,8 @@ @livewire('profile.settings.general') - @livewire('profile.settings.personal-address', ['countries' => $countries]) + @livewire('profile.settings.personal-address') - @livewire('profile.settings.shipping-address', ['countries' => $countries]) + @livewire('profile.settings.shipping-address') @endsection diff --git a/resources/views/portal/ninja2020/profile/settings/personal-address.blade.php b/resources/views/portal/ninja2020/profile/settings/personal-address.blade.php index 47a7f09f8198..8e152de46fac 100644 --- a/resources/views/portal/ninja2020/profile/settings/personal-address.blade.php +++ b/resources/views/portal/ninja2020/profile/settings/personal-address.blade.php @@ -61,7 +61,7 @@ @foreach($countries as $country) @endforeach diff --git a/resources/views/portal/ninja2020/profile/settings/shipping-address.blade.php b/resources/views/portal/ninja2020/profile/settings/shipping-address.blade.php index 2742f376f81d..6ce59c890877 100644 --- a/resources/views/portal/ninja2020/profile/settings/shipping-address.blade.php +++ b/resources/views/portal/ninja2020/profile/settings/shipping-address.blade.php @@ -62,7 +62,7 @@ @foreach($countries as $country) @endforeach diff --git a/resources/views/portal/ninja2020/vendor_profile/edit.blade.php b/resources/views/portal/ninja2020/vendor_profile/edit.blade.php index c7cb866f0031..6dccb1298b3b 100644 --- a/resources/views/portal/ninja2020/vendor_profile/edit.blade.php +++ b/resources/views/portal/ninja2020/vendor_profile/edit.blade.php @@ -152,7 +152,7 @@ @foreach($countries as $country) @endforeach From 2373f6e5080f414b03f5038d58c43baa29c238e9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 17:05:03 +1000 Subject: [PATCH 11/30] Remove migration for tax models --- ..._29_235430_2024_30_07_tax_model_migration.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php b/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php index e542bcd2be8a..ca0e7e27904e 100644 --- a/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php +++ b/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php @@ -12,18 +12,18 @@ return new class extends Migration */ public function up(): void { - Company::whereNotNull('tax_data') - ->cursor() - ->each(function($company){ + // Company::whereNotNull('tax_data') + // ->cursor() + // ->each(function($company){ - if($company->tax_data?->version == 'alpha') - { + // if($company->tax_data?->version == 'alpha') + // { - $company->update(['tax_data' => new \App\DataMapper\Tax\TaxModel($company->tax_data)]); + // $company->update(['tax_data' => new \App\DataMapper\Tax\TaxModel($company->tax_data)]); - } + // } - }); + // }); } /** From 5e9ad43281b60ff1d86b94c29ab105f4145bc5de Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 17:11:10 +1000 Subject: [PATCH 12/30] Updated CSS --- public/build/assets/app-02bc3b96.css | 1 - public/build/assets/{app-039bd735.css => app-06521fee.css} | 2 +- public/build/manifest.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 public/build/assets/app-02bc3b96.css rename public/build/assets/{app-039bd735.css => app-06521fee.css} (87%) diff --git a/public/build/assets/app-02bc3b96.css b/public/build/assets/app-02bc3b96.css deleted file mode 100644 index 8c1544d1c4e3..000000000000 --- a/public/build/assets/app-02bc3b96.css +++ /dev/null @@ -1 +0,0 @@ -*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Open Sans,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.form-input,.form-textarea,.form-select,.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}.form-input:focus,.form-textarea:focus,.form-select:focus,.form-multiselect:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}.form-select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-select:where([size]:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}.form-checkbox,.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}.form-checkbox{border-radius:0}.form-radio{border-radius:100%}.form-checkbox:focus,.form-radio:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.form-checkbox:checked,.form-radio:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}.form-checkbox:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-checkbox:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-radio:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-radio:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:checked:hover,.form-checkbox:checked:focus,.form-radio:checked:hover,.form-radio:checked:focus{border-color:transparent;background-color:currentColor}.form-checkbox:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){.form-checkbox:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:indeterminate:hover,.form-checkbox:indeterminate:focus{border-color:transparent;background-color:currentColor}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-left-width:.25rem;border-left-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding:.1875em .375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: 17 24 39;--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: 255 255 255;--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-left:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.button{border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}button:disabled{cursor:not-allowed;opacity:.5}.button-primary{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-primary:hover{font-weight:600}.button-block{display:block;width:100%}.button-danger{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.button-secondary{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.button-secondary:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.button-link{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.button-link:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity));text-decoration-line:underline}.button-link:focus{text-decoration-line:underline;outline:2px solid transparent;outline-offset:2px}.validation{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.25rem .75rem}.validation-fail{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.validation-pass{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.input-label{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.input-slim{padding-top:.5rem;padding-bottom:.5rem}.form-checkbox{cursor:pointer;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.form-select{border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.alert{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.75rem 1rem;font-size:.875rem;line-height:1.25rem}.alert-success{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.alert-failure{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .625rem;font-size:.75rem;font-weight:500;line-height:1rem}.badge-light{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.badge-primary{--tw-bg-opacity: 1;background-color:rgb(191 219 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.badge-danger{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.badge-success{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity))}.badge-secondary{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.badge-warning{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity))}.badge-info{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}@media (min-width: 640px){.dataTables_length{margin-top:1.25rem!important;margin-bottom:1.25rem!important}}@media (min-width: 1024px){.dataTables_length{margin-top:1rem!important;margin-bottom:1rem!important}}.dataTables_length select{margin-left:.5rem!important;margin-right:.5rem!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_length select:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.dataTables_filter{margin-bottom:1rem}.dataTables_filter input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_filter input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}@media (min-width: 1024px){.dataTables_filter{margin-top:-3rem!important}}.dataTables_paginate{padding-bottom:1.5rem!important;padding-top:.5rem!important}.dataTables_paginate .paginate_button{margin-right:.25rem!important;cursor:pointer!important;border-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;font-weight:500!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important;border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dataTables_paginate .current{--tw-bg-opacity: 1 !important;background-color:rgb(37 99 235 / var(--tw-bg-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(255 255 255 / var(--tw-text-opacity))!important}.dataTables_info{font-size:.875rem!important;line-height:1.25rem!important}.dataTables_empty{padding-top:1rem!important;padding-bottom:1rem!important}.pagination{display:flex!important;align-items:center!important}.pagination .page-link{margin-top:-1px!important;display:inline-flex!important;cursor:pointer!important;align-items:center!important;border-top-width:2px!important;border-color:transparent!important;padding-left:1rem!important;padding-right:1rem!important;padding-top:1rem!important;font-size:.875rem!important;font-weight:500!important;line-height:1.25rem!important;--tw-text-opacity: 1 !important;color:rgb(107 114 128 / var(--tw-text-opacity))!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter!important;transition-duration:.15s!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important}.pagination .page-link:hover{--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important}.pagination .page-link:focus{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}.pagination .active>span{--tw-border-opacity: 1 !important;border-color:rgb(37 99 235 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(37 99 235 / var(--tw-text-opacity))!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.top-0{top:0}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-auto{grid-column:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-12{grid-column:span 12 / span 12}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.col-span-6{grid-column:span 6 / span 6}.col-span-8{grid-column:span 8 / span 8}.float-right{float:right}.m-0{margin:0}.m-auto{margin:auto}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.-my-6{margin-top:-1.5rem;margin-bottom:-1.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.mx-\[22px\]{margin-left:22px;margin-right:22px}.mx-\[40px\]{margin-left:40px;margin-right:40px}.mx-\[auto\],.mx-auto{margin-left:auto;margin-right:auto}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-ml-1{margin-left:-.25rem}.-ml-4{margin-left:-1rem}.-ml-px{margin-left:-1px}.-mr-1{margin-right:-.25rem}.-mr-14{margin-right:-3.5rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.mb-0{margin-bottom:0}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[10px\]{margin-bottom:10px}.mb-\[11px\]{margin-bottom:11px}.mb-\[20px\]{margin-bottom:20px}.mb-\[25px\]{margin-bottom:25px}.mb-\[26px\]{margin-bottom:26px}.mb-\[36px\]{margin-bottom:36px}.mb-\[40px\]{margin-bottom:40px}.mb-\[5px\]{margin-bottom:5px}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-5{margin-left:1.25rem}.ml-\[10px\]{margin-left:10px}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mr-5{margin-right:1.25rem}.mt-0{margin-top:0}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[30px\]{margin-top:30px}.mt-\[50px\]{margin-top:50px}.mt-\[auto\]{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-0{height:0px}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-24{height:6rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[40px\]{height:40px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-screen{height:100vh}.min-h-\[450px\]{min-height:450px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/6{width:16.666667%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/5{width:80%}.w-4\/6{width:66.666667%}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[100\%\]{width:100%}.w-\[87px\]{width:87px}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-\[212px\]{max-width:212px}.max-w-\[450px\]{max-width:450px}.max-w-\[625px\]{max-width:625px}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/2{flex-basis:50%}.basis-full{flex-basis:100%}.table-auto{table-layout:auto}.border-collapse{border-collapse:collapse}.origin-top-right{transform-origin:top right}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-end{place-content:end}.place-items-center{place-items:center}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[13px\]{gap:13px}.gap-\[44px\]{gap:44px}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-\[20px\]{row-gap:20px}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-b-lg{border-bottom-right-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-t-4{border-top-width:4px}.border-t-\[0px\]{border-top-width:0px}.border-t-\[10px\]{border-top-width:10px}.border-t-\[1px\]{border-top-width:1px}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-emerald-500{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.border-fuchsia-600{--tw-border-opacity: 1;border-color:rgb(192 38 211 / var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity))}.border-red-900{--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-opacity-50{--tw-border-opacity: .5}.bg-\[\#F2F9FE\]{--tw-bg-opacity: 1;background-color:rgb(242 249 254 / var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity))}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-opacity-100{--tw-bg-opacity: 1}.bg-clip-padding{background-clip:padding-box}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.object-scale-down{-o-object-fit:scale-down;object-fit:scale-down}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.p-\[12px\]{padding:12px}.p-\[20px\]{padding:20px}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-\[12px\]{padding-left:12px;padding-right:12px}.px-\[20px\]{padding-left:20px;padding-right:20px}.px-\[22px\]{padding-left:22px;padding-right:22px}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[33px\]{padding-top:33px;padding-bottom:33px}.py-\[36px\]{padding-top:36px;padding-bottom:36px}.py-\[9\.5px\]{padding-top:9.5px;padding-bottom:9.5px}.pb-10{padding-bottom:2.5rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-\[20px\]{padding-bottom:20px}.pb-\[56px\]{padding-bottom:56px}.pb-\[58px\]{padding-bottom:58px}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-1\.5{padding-left:.375rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-\[18px\]{padding-left:18px}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-\[18px\]{padding-right:18px}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.pt-\[20px\]{padding-top:20px}.pt-\[29px\]{padding-top:29px}.pt-\[35px\]{padding-top:35px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-\[\'Open_Sans\'\]{font-family:Open Sans}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[35px\]{font-size:35px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-\[16px\]{font-weight:16px}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-\[1\.2rem\]{line-height:1.2rem}.leading-\[1\.35em\]{line-height:1.35em}.leading-\[1\.36em\]{line-height:1.36em}.leading-\[1\.375em\]{line-height:1.375em}.leading-\[1\.3em\]{line-height:1.3em}.leading-\[1\.5em\]{line-height:1.5em}.leading-\[1\.75em\]{line-height:1.75em}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[\#212529\]{--tw-text-opacity: 1;color:rgb(33 37 41 / var(--tw-text-opacity))}.text-\[\#6C727F\]{--tw-text-opacity: 1;color:rgb(108 114 127 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-1000{transition-duration:1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:left-\[8px\]:after{content:var(--tw-content);left:8px}.after\:top-\[5px\]:after{content:var(--tw-content);top:5px}.after\:h-\[30px\]:after{content:var(--tw-content);height:30px}.after\:w-\[30px\]:after{content:var(--tw-content);width:30px}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.focus-within\:z-10:focus-within{z-index:10}.hover\:list-disc:hover{list-style-type:disc}.hover\:border-blue-600:hover{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.hover\:border-gray-800:hover{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:bg-red-900:hover{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity))}.hover\:font-semibold:hover{font-weight:600}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.hover\:text-indigo-900:hover{--tw-text-opacity: 1;color:rgb(49 46 129 / var(--tw-text-opacity))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:border-fuchsia-300:focus{--tw-border-opacity: 1;border-color:rgb(240 171 252 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.focus\:bg-gray-600:focus{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.focus\:font-semibold:focus{font-weight:600}.focus\:text-gray-500:focus{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.focus\:text-gray-600:focus{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.focus\:text-gray-900:focus{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.active\:bg-gray-50:active{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.active\:text-gray-800:active{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.active\:outline-none:active{outline:2px solid transparent;outline-offset:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.disabled\:opacity-75:disabled{opacity:.75}.group:hover .group-hover\:border-transparent{border-color:transparent}.group:hover .group-hover\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-\[140\%\]:after{content:var(--tw-content);--tw-translate-x: 140%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}@media (min-width: 640px){.sm\:inset-0{top:0;right:0;bottom:0;left:0}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:col-span-3{grid-column:span 3 / span 3}.sm\:col-span-4{grid-column:span 4 / span 4}.sm\:col-span-6{grid-column:span 6 / span 6}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:ml-6{margin-left:1.5rem}.sm\:mt-0{margin-top:0}.sm\:mt-4{margin-top:1rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-screen{height:100vh}.sm\:w-10{width:2.5rem}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-shrink-0{flex-shrink:0}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-4{gap:1rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-4{grid-column:span 4 / span 4}.md\:col-span-5{grid-column:span 5 / span 5}.md\:col-span-6{grid-column:span 6 / span 6}.md\:col-start-2{grid-column-start:2}.md\:col-start-4{grid-column-start:4}.md\:mx-0,.md\:mx-\[0\]{margin-left:0;margin-right:0}.md\:-mr-1{margin-right:-.25rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-\[46px\]{margin-bottom:46px}.md\:ml-2{margin-left:.5rem}.md\:ml-6{margin-left:1.5rem}.md\:mr-0{margin-right:0}.md\:mr-2{margin-right:.5rem}.md\:mt-0{margin-top:0}.md\:mt-10{margin-top:2.5rem}.md\:mt-5{margin-top:1.25rem}.md\:block{display:block}.md\:flex{display:flex}.md\:grid{display:grid}.md\:hidden{display:none}.md\:min-h-\[411px\]{min-height:411px}.md\:w-1\/2{width:50%}.md\:w-1\/3{width:33.333333%}.md\:max-w-3xl{max-width:48rem}.md\:max-w-xl{max-width:36rem}.md\:flex-shrink-0{flex-shrink:0}.md\:shrink{flex-shrink:1}.md\:grow-0{flex-grow:0}.md\:basis-1\/2{flex-basis:50%}.md\:basis-\[449px\]{flex-basis:449px}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:justify-between{justify-content:space-between}.md\:gap-6{gap:1.5rem}.md\:gap-x-\[21px\]{-moz-column-gap:21px;column-gap:21px}.md\:gap-y-6{row-gap:1.5rem}.md\:border-r{border-right-width:1px}.md\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.md\:p-24{padding:6rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-\[40px\]{padding-left:40px;padding-right:40px}.md\:pb-\[40px\]{padding-bottom:40px}.md\:pl-4{padding-left:1rem}.md\:pl-\[52px\]{padding-left:52px}.md\:pl-\[61px\]{padding-left:61px}.md\:pr-\[20px\]{padding-right:20px}.md\:pr-\[48px\]{padding-right:48px}.md\:pt-0{padding-top:0}.md\:pt-\[58px\]{padding-top:58px}.md\:text-left{text-align:left}.md\:text-center{text-align:center}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-\[30px\]{font-size:30px}.md\:text-\[32px\]{font-size:32px}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-3{grid-column:span 3 / span 3}.lg\:col-span-6{grid-column:span 6 / span 6}.lg\:col-span-7{grid-column:span 7 / span 7}.lg\:col-span-8{grid-column:span 8 / span 8}.lg\:col-start-3{grid-column-start:3}.lg\:col-start-4{grid-column-start:4}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:mt-24{margin-top:6rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:h-screen{height:100vh}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-1\/4{width:25%}.lg\:w-1\/5{width:20%}.lg\:max-w-\[80\%\]{max-width:80%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:items-center{align-items:center}.lg\:gap-4{gap:1rem}.lg\:rounded-lg{border-radius:.5rem}.lg\:px-16{padding-left:4rem;padding-right:4rem}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-2{padding-top:.5rem;padding-bottom:.5rem}}@media (min-width: 1280px){.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:col-span-6{grid-column:span 6 / span 6}.xl\:col-span-8{grid-column:span 8 / span 8}.xl\:col-span-9{grid-column:span 9 / span 9}.xl\:col-start-4{grid-column-start:4}.xl\:ml-5{margin-left:1.25rem}.xl\:mt-0{margin-top:0}.xl\:mt-32{margin-top:8rem}.xl\:flex{display:flex}.xl\:w-auto{width:auto}.xl\:basis-auto{flex-basis:auto}.xl\:flex-row{flex-direction:row}.xl\:flex-nowrap{flex-wrap:nowrap}.xl\:justify-center{justify-content:center}.xl\:border-r{border-right-width:1px}.xl\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.xl\:px-16{padding-left:4rem;padding-right:4rem}.xl\:px-20{padding-left:5rem;padding-right:5rem}.xl\:px-5{padding-left:1.25rem;padding-right:1.25rem}.xl\:pr-20{padding-right:5rem}}@media (prefers-color-scheme: dark){.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}} diff --git a/public/build/assets/app-039bd735.css b/public/build/assets/app-06521fee.css similarity index 87% rename from public/build/assets/app-039bd735.css rename to public/build/assets/app-06521fee.css index b404a6350ce2..ed4a7a525a0d 100644 --- a/public/build/assets/app-039bd735.css +++ b/public/build/assets/app-06521fee.css @@ -1 +1 @@ -*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Open Sans,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.form-input,.form-textarea,.form-select,.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}.form-input:focus,.form-textarea:focus,.form-select:focus,.form-multiselect:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}.form-select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-select:where([size]:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}.form-checkbox,.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}.form-checkbox{border-radius:0}.form-radio{border-radius:100%}.form-checkbox:focus,.form-radio:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.form-checkbox:checked,.form-radio:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}.form-checkbox:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-checkbox:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-radio:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-radio:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:checked:hover,.form-checkbox:checked:focus,.form-radio:checked:hover,.form-radio:checked:focus{border-color:transparent;background-color:currentColor}.form-checkbox:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){.form-checkbox:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:indeterminate:hover,.form-checkbox:indeterminate:focus{border-color:transparent;background-color:currentColor}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-left-width:.25rem;border-left-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding:.1875em .375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: 17 24 39;--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: 255 255 255;--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-left:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.button{border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}button:disabled{cursor:not-allowed;opacity:.5}.button-primary{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-primary:hover{font-weight:600}.button-block{display:block;width:100%}.button-danger{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.button-secondary{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.button-secondary:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.button-link{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.button-link:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity));text-decoration-line:underline}.button-link:focus{text-decoration-line:underline;outline:2px solid transparent;outline-offset:2px}.validation{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.25rem .75rem}.validation-fail{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.validation-pass{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.input-label{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.input-slim{padding-top:.5rem;padding-bottom:.5rem}.form-checkbox{cursor:pointer;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.form-select{border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.alert{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.75rem 1rem;font-size:.875rem;line-height:1.25rem}.alert-success{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.alert-failure{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .625rem;font-size:.75rem;font-weight:500;line-height:1rem}.badge-light{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.badge-primary{--tw-bg-opacity: 1;background-color:rgb(191 219 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.badge-danger{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.badge-success{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity))}.badge-secondary{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.badge-warning{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity))}.badge-info{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}@media (min-width: 640px){.dataTables_length{margin-top:1.25rem!important;margin-bottom:1.25rem!important}}@media (min-width: 1024px){.dataTables_length{margin-top:1rem!important;margin-bottom:1rem!important}}.dataTables_length select{margin-left:.5rem!important;margin-right:.5rem!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_length select:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.dataTables_filter{margin-bottom:1rem}.dataTables_filter input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_filter input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}@media (min-width: 1024px){.dataTables_filter{margin-top:-3rem!important}}.dataTables_paginate{padding-bottom:1.5rem!important;padding-top:.5rem!important}.dataTables_paginate .paginate_button{margin-right:.25rem!important;cursor:pointer!important;border-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;font-weight:500!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important;border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dataTables_paginate .current{--tw-bg-opacity: 1 !important;background-color:rgb(37 99 235 / var(--tw-bg-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(255 255 255 / var(--tw-text-opacity))!important}.dataTables_info{font-size:.875rem!important;line-height:1.25rem!important}.dataTables_empty{padding-top:1rem!important;padding-bottom:1rem!important}.pagination{display:flex!important;align-items:center!important}.pagination .page-link{margin-top:-1px!important;display:inline-flex!important;cursor:pointer!important;align-items:center!important;border-top-width:2px!important;border-color:transparent!important;padding-left:1rem!important;padding-right:1rem!important;padding-top:1rem!important;font-size:.875rem!important;font-weight:500!important;line-height:1.25rem!important;--tw-text-opacity: 1 !important;color:rgb(107 114 128 / var(--tw-text-opacity))!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter!important;transition-duration:.15s!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important}.pagination .page-link:hover{--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important}.pagination .page-link:focus{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}.pagination .active>span{--tw-border-opacity: 1 !important;border-color:rgb(37 99 235 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(37 99 235 / var(--tw-text-opacity))!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.top-0{top:0}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-auto{grid-column:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-12{grid-column:span 12 / span 12}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.col-span-6{grid-column:span 6 / span 6}.col-span-8{grid-column:span 8 / span 8}.float-right{float:right}.m-0{margin:0}.m-auto{margin:auto}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.-my-6{margin-top:-1.5rem;margin-bottom:-1.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.mx-\[22px\]{margin-left:22px;margin-right:22px}.mx-\[40px\]{margin-left:40px;margin-right:40px}.mx-\[auto\],.mx-auto{margin-left:auto;margin-right:auto}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-ml-1{margin-left:-.25rem}.-ml-4{margin-left:-1rem}.-ml-px{margin-left:-1px}.-mr-1{margin-right:-.25rem}.-mr-14{margin-right:-3.5rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.mb-0{margin-bottom:0}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[10px\]{margin-bottom:10px}.mb-\[11px\]{margin-bottom:11px}.mb-\[20px\]{margin-bottom:20px}.mb-\[25px\]{margin-bottom:25px}.mb-\[26px\]{margin-bottom:26px}.mb-\[36px\]{margin-bottom:36px}.mb-\[40px\]{margin-bottom:40px}.mb-\[5px\]{margin-bottom:5px}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-5{margin-left:1.25rem}.ml-\[10px\]{margin-left:10px}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mr-5{margin-right:1.25rem}.mt-0{margin-top:0}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[30px\]{margin-top:30px}.mt-\[50px\]{margin-top:50px}.mt-\[auto\]{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-0{height:0px}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-24{height:6rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[40px\]{height:40px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-screen{height:100vh}.min-h-\[450px\]{min-height:450px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/4{width:25%}.w-1\/6{width:16.666667%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/5{width:80%}.w-4\/6{width:66.666667%}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[100\%\]{width:100%}.w-\[87px\]{width:87px}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-\[212px\]{max-width:212px}.max-w-\[450px\]{max-width:450px}.max-w-\[625px\]{max-width:625px}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/2{flex-basis:50%}.basis-full{flex-basis:100%}.table-auto{table-layout:auto}.border-collapse{border-collapse:collapse}.origin-top-right{transform-origin:top right}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-end{place-content:end}.place-items-center{place-items:center}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[13px\]{gap:13px}.gap-\[44px\]{gap:44px}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-\[20px\]{row-gap:20px}.space-x-0>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(0px * var(--tw-space-x-reverse));margin-left:calc(0px * calc(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-b-lg{border-bottom-right-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-t-4{border-top-width:4px}.border-t-\[0px\]{border-top-width:0px}.border-t-\[10px\]{border-top-width:10px}.border-t-\[1px\]{border-top-width:1px}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-emerald-500{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.border-fuchsia-600{--tw-border-opacity: 1;border-color:rgb(192 38 211 / var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.border-red-900{--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-opacity-50{--tw-border-opacity: .5}.bg-\[\#F2F9FE\]{--tw-bg-opacity: 1;background-color:rgb(242 249 254 / var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity))}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-opacity-100{--tw-bg-opacity: 1}.bg-clip-padding{background-clip:padding-box}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.object-scale-down{-o-object-fit:scale-down;object-fit:scale-down}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.p-\[12px\]{padding:12px}.p-\[20px\]{padding:20px}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-\[12px\]{padding-left:12px;padding-right:12px}.px-\[20px\]{padding-left:20px;padding-right:20px}.px-\[22px\]{padding-left:22px;padding-right:22px}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[33px\]{padding-top:33px;padding-bottom:33px}.py-\[36px\]{padding-top:36px;padding-bottom:36px}.py-\[9\.5px\]{padding-top:9.5px;padding-bottom:9.5px}.pb-10{padding-bottom:2.5rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-\[20px\]{padding-bottom:20px}.pb-\[56px\]{padding-bottom:56px}.pb-\[58px\]{padding-bottom:58px}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-1\.5{padding-left:.375rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-\[18px\]{padding-left:18px}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-\[18px\]{padding-right:18px}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.pt-\[20px\]{padding-top:20px}.pt-\[29px\]{padding-top:29px}.pt-\[35px\]{padding-top:35px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-\[\'Open_Sans\'\]{font-family:Open Sans}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[35px\]{font-size:35px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-\[16px\]{font-weight:16px}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-\[1\.2rem\]{line-height:1.2rem}.leading-\[1\.35em\]{line-height:1.35em}.leading-\[1\.36em\]{line-height:1.36em}.leading-\[1\.375em\]{line-height:1.375em}.leading-\[1\.3em\]{line-height:1.3em}.leading-\[1\.5em\]{line-height:1.5em}.leading-\[1\.75em\]{line-height:1.75em}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[\#212529\]{--tw-text-opacity: 1;color:rgb(33 37 41 / var(--tw-text-opacity))}.text-\[\#6C727F\]{--tw-text-opacity: 1;color:rgb(108 114 127 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-1000{transition-duration:1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:left-\[8px\]:after{content:var(--tw-content);left:8px}.after\:top-\[5px\]:after{content:var(--tw-content);top:5px}.after\:h-\[30px\]:after{content:var(--tw-content);height:30px}.after\:w-\[30px\]:after{content:var(--tw-content);width:30px}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.focus-within\:z-10:focus-within{z-index:10}.hover\:list-disc:hover{list-style-type:disc}.hover\:border-blue-600:hover{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.hover\:border-gray-800:hover{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:bg-red-900:hover{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity))}.hover\:font-semibold:hover{font-weight:600}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.hover\:text-indigo-900:hover{--tw-text-opacity: 1;color:rgb(49 46 129 / var(--tw-text-opacity))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:border-fuchsia-300:focus{--tw-border-opacity: 1;border-color:rgb(240 171 252 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.focus\:bg-gray-600:focus{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.focus\:font-semibold:focus{font-weight:600}.focus\:text-gray-500:focus{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.focus\:text-gray-600:focus{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.focus\:text-gray-900:focus{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.active\:bg-gray-50:active{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.active\:text-gray-800:active{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.active\:outline-none:active{outline:2px solid transparent;outline-offset:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.group:hover .group-hover\:border-transparent{border-color:transparent}.group:hover .group-hover\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-\[140\%\]:after{content:var(--tw-content);--tw-translate-x: 140%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}@media (min-width: 640px){.sm\:inset-0{top:0;right:0;bottom:0;left:0}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:col-span-3{grid-column:span 3 / span 3}.sm\:col-span-4{grid-column:span 4 / span 4}.sm\:col-span-6{grid-column:span 6 / span 6}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:ml-6{margin-left:1.5rem}.sm\:mt-0{margin-top:0}.sm\:mt-4{margin-top:1rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-screen{height:100vh}.sm\:w-10{width:2.5rem}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-shrink-0{flex-shrink:0}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-4{gap:1rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-4{grid-column:span 4 / span 4}.md\:col-span-5{grid-column:span 5 / span 5}.md\:col-span-6{grid-column:span 6 / span 6}.md\:col-start-2{grid-column-start:2}.md\:col-start-4{grid-column-start:4}.md\:mx-0,.md\:mx-\[0\]{margin-left:0;margin-right:0}.md\:-mr-1{margin-right:-.25rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-\[46px\]{margin-bottom:46px}.md\:ml-2{margin-left:.5rem}.md\:ml-6{margin-left:1.5rem}.md\:mr-0{margin-right:0}.md\:mr-2{margin-right:.5rem}.md\:mt-0{margin-top:0}.md\:mt-10{margin-top:2.5rem}.md\:mt-5{margin-top:1.25rem}.md\:block{display:block}.md\:flex{display:flex}.md\:grid{display:grid}.md\:hidden{display:none}.md\:min-h-\[411px\]{min-height:411px}.md\:w-1\/2{width:50%}.md\:w-1\/3{width:33.333333%}.md\:max-w-3xl{max-width:48rem}.md\:max-w-xl{max-width:36rem}.md\:flex-shrink-0{flex-shrink:0}.md\:shrink{flex-shrink:1}.md\:grow-0{flex-grow:0}.md\:basis-1\/2{flex-basis:50%}.md\:basis-\[449px\]{flex-basis:449px}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:justify-between{justify-content:space-between}.md\:gap-6{gap:1.5rem}.md\:gap-x-\[21px\]{-moz-column-gap:21px;column-gap:21px}.md\:gap-y-6{row-gap:1.5rem}.md\:border-r{border-right-width:1px}.md\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.md\:p-24{padding:6rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-\[40px\]{padding-left:40px;padding-right:40px}.md\:pb-\[40px\]{padding-bottom:40px}.md\:pl-4{padding-left:1rem}.md\:pl-\[52px\]{padding-left:52px}.md\:pl-\[61px\]{padding-left:61px}.md\:pr-\[20px\]{padding-right:20px}.md\:pr-\[48px\]{padding-right:48px}.md\:pt-0{padding-top:0}.md\:pt-\[58px\]{padding-top:58px}.md\:text-left{text-align:left}.md\:text-center{text-align:center}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-\[30px\]{font-size:30px}.md\:text-\[32px\]{font-size:32px}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-3{grid-column:span 3 / span 3}.lg\:col-span-6{grid-column:span 6 / span 6}.lg\:col-span-7{grid-column:span 7 / span 7}.lg\:col-span-8{grid-column:span 8 / span 8}.lg\:col-start-3{grid-column-start:3}.lg\:col-start-4{grid-column-start:4}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:mt-24{margin-top:6rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:h-screen{height:100vh}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-1\/4{width:25%}.lg\:w-1\/5{width:20%}.lg\:max-w-\[80\%\]{max-width:80%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:items-center{align-items:center}.lg\:gap-4{gap:1rem}.lg\:rounded-lg{border-radius:.5rem}.lg\:px-16{padding-left:4rem;padding-right:4rem}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-2{padding-top:.5rem;padding-bottom:.5rem}}@media (min-width: 1280px){.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:col-span-6{grid-column:span 6 / span 6}.xl\:col-span-8{grid-column:span 8 / span 8}.xl\:col-span-9{grid-column:span 9 / span 9}.xl\:col-start-4{grid-column-start:4}.xl\:ml-5{margin-left:1.25rem}.xl\:mt-0{margin-top:0}.xl\:mt-32{margin-top:8rem}.xl\:flex{display:flex}.xl\:w-auto{width:auto}.xl\:basis-auto{flex-basis:auto}.xl\:flex-row{flex-direction:row}.xl\:flex-nowrap{flex-wrap:nowrap}.xl\:justify-center{justify-content:center}.xl\:border-r{border-right-width:1px}.xl\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.xl\:px-16{padding-left:4rem;padding-right:4rem}.xl\:px-20{padding-left:5rem;padding-right:5rem}.xl\:px-5{padding-left:1.25rem;padding-right:1.25rem}.xl\:pr-20{padding-right:5rem}}@media (prefers-color-scheme: dark){.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}} +*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Open Sans,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.form-input,.form-textarea,.form-select,.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}.form-input:focus,.form-textarea:focus,.form-select:focus,.form-multiselect:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}.form-select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-select:where([size]:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}.form-checkbox,.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}.form-checkbox{border-radius:0}.form-radio{border-radius:100%}.form-checkbox:focus,.form-radio:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.form-checkbox:checked,.form-radio:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}.form-checkbox:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-checkbox:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-radio:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-radio:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:checked:hover,.form-checkbox:checked:focus,.form-radio:checked:hover,.form-radio:checked:focus{border-color:transparent;background-color:currentColor}.form-checkbox:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){.form-checkbox:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:indeterminate:hover,.form-checkbox:indeterminate:focus{border-color:transparent;background-color:currentColor}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-left-width:.25rem;border-left-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding:.1875em .375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: 17 24 39;--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: 255 255 255;--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-left:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.button{border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}button:disabled{cursor:not-allowed;opacity:.5}.button-primary{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-primary:hover{font-weight:600}.button-block{display:block;width:100%}.button-danger{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.button-secondary{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.button-secondary:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.button-link{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.button-link:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity));text-decoration-line:underline}.button-link:focus{text-decoration-line:underline;outline:2px solid transparent;outline-offset:2px}.validation{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.25rem .75rem}.validation-fail{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.validation-pass{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.input-label{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.input-slim{padding-top:.5rem;padding-bottom:.5rem}.form-checkbox{cursor:pointer;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.form-select{border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.alert{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.75rem 1rem;font-size:.875rem;line-height:1.25rem}.alert-success{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.alert-failure{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .625rem;font-size:.75rem;font-weight:500;line-height:1rem}.badge-light{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.badge-primary{--tw-bg-opacity: 1;background-color:rgb(191 219 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.badge-danger{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.badge-success{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity))}.badge-secondary{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.badge-warning{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity))}.badge-info{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}@media (min-width: 640px){.dataTables_length{margin-top:1.25rem!important;margin-bottom:1.25rem!important}}@media (min-width: 1024px){.dataTables_length{margin-top:1rem!important;margin-bottom:1rem!important}}.dataTables_length select{margin-left:.5rem!important;margin-right:.5rem!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_length select:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.dataTables_filter{margin-bottom:1rem}.dataTables_filter input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_filter input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}@media (min-width: 1024px){.dataTables_filter{margin-top:-3rem!important}}.dataTables_paginate{padding-bottom:1.5rem!important;padding-top:.5rem!important}.dataTables_paginate .paginate_button{margin-right:.25rem!important;cursor:pointer!important;border-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;font-weight:500!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important;border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dataTables_paginate .current{--tw-bg-opacity: 1 !important;background-color:rgb(37 99 235 / var(--tw-bg-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(255 255 255 / var(--tw-text-opacity))!important}.dataTables_info{font-size:.875rem!important;line-height:1.25rem!important}.dataTables_empty{padding-top:1rem!important;padding-bottom:1rem!important}.pagination{display:flex!important;align-items:center!important}.pagination .page-link{margin-top:-1px!important;display:inline-flex!important;cursor:pointer!important;align-items:center!important;border-top-width:2px!important;border-color:transparent!important;padding-left:1rem!important;padding-right:1rem!important;padding-top:1rem!important;font-size:.875rem!important;font-weight:500!important;line-height:1.25rem!important;--tw-text-opacity: 1 !important;color:rgb(107 114 128 / var(--tw-text-opacity))!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter!important;transition-duration:.15s!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important}.pagination .page-link:hover{--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important}.pagination .page-link:focus{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}.pagination .active>span{--tw-border-opacity: 1 !important;border-color:rgb(37 99 235 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(37 99 235 / var(--tw-text-opacity))!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.top-0{top:0}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-auto{grid-column:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-12{grid-column:span 12 / span 12}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.col-span-6{grid-column:span 6 / span 6}.col-span-8{grid-column:span 8 / span 8}.float-right{float:right}.m-0{margin:0}.m-auto{margin:auto}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.-my-6{margin-top:-1.5rem;margin-bottom:-1.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.mx-\[22px\]{margin-left:22px;margin-right:22px}.mx-\[40px\]{margin-left:40px;margin-right:40px}.mx-\[auto\],.mx-auto{margin-left:auto;margin-right:auto}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-ml-1{margin-left:-.25rem}.-ml-4{margin-left:-1rem}.-ml-px{margin-left:-1px}.-mr-1{margin-right:-.25rem}.-mr-14{margin-right:-3.5rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.mb-0{margin-bottom:0}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[10px\]{margin-bottom:10px}.mb-\[11px\]{margin-bottom:11px}.mb-\[20px\]{margin-bottom:20px}.mb-\[25px\]{margin-bottom:25px}.mb-\[26px\]{margin-bottom:26px}.mb-\[36px\]{margin-bottom:36px}.mb-\[40px\]{margin-bottom:40px}.mb-\[5px\]{margin-bottom:5px}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-5{margin-left:1.25rem}.ml-\[10px\]{margin-left:10px}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mr-5{margin-right:1.25rem}.mt-0{margin-top:0}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[30px\]{margin-top:30px}.mt-\[50px\]{margin-top:50px}.mt-\[auto\]{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-0{height:0px}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-24{height:6rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[40px\]{height:40px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-screen{height:100vh}.min-h-\[450px\]{min-height:450px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/4{width:25%}.w-1\/6{width:16.666667%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/5{width:80%}.w-4\/6{width:66.666667%}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[100\%\]{width:100%}.w-\[87px\]{width:87px}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-\[212px\]{max-width:212px}.max-w-\[450px\]{max-width:450px}.max-w-\[625px\]{max-width:625px}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/2{flex-basis:50%}.basis-full{flex-basis:100%}.table-auto{table-layout:auto}.border-collapse{border-collapse:collapse}.origin-top-right{transform-origin:top right}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-end{place-content:end}.place-items-center{place-items:center}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[13px\]{gap:13px}.gap-\[44px\]{gap:44px}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-\[20px\]{row-gap:20px}.space-x-0>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(0px * var(--tw-space-x-reverse));margin-left:calc(0px * calc(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-b-lg{border-bottom-right-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-t-4{border-top-width:4px}.border-t-\[0px\]{border-top-width:0px}.border-t-\[10px\]{border-top-width:10px}.border-t-\[1px\]{border-top-width:1px}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-emerald-500{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.border-fuchsia-600{--tw-border-opacity: 1;border-color:rgb(192 38 211 / var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.border-red-900{--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-opacity-50{--tw-border-opacity: .5}.bg-\[\#F2F9FE\]{--tw-bg-opacity: 1;background-color:rgb(242 249 254 / var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity))}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-opacity-100{--tw-bg-opacity: 1}.bg-clip-padding{background-clip:padding-box}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.object-scale-down{-o-object-fit:scale-down;object-fit:scale-down}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.p-\[12px\]{padding:12px}.p-\[20px\]{padding:20px}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-\[12px\]{padding-left:12px;padding-right:12px}.px-\[20px\]{padding-left:20px;padding-right:20px}.px-\[22px\]{padding-left:22px;padding-right:22px}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[33px\]{padding-top:33px;padding-bottom:33px}.py-\[36px\]{padding-top:36px;padding-bottom:36px}.py-\[9\.5px\]{padding-top:9.5px;padding-bottom:9.5px}.pb-10{padding-bottom:2.5rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-\[20px\]{padding-bottom:20px}.pb-\[56px\]{padding-bottom:56px}.pb-\[58px\]{padding-bottom:58px}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-1\.5{padding-left:.375rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-\[18px\]{padding-left:18px}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-\[18px\]{padding-right:18px}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.pt-\[20px\]{padding-top:20px}.pt-\[29px\]{padding-top:29px}.pt-\[35px\]{padding-top:35px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-\[\'Open_Sans\'\]{font-family:Open Sans}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[35px\]{font-size:35px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-\[16px\]{font-weight:16px}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-\[1\.2rem\]{line-height:1.2rem}.leading-\[1\.35em\]{line-height:1.35em}.leading-\[1\.36em\]{line-height:1.36em}.leading-\[1\.375em\]{line-height:1.375em}.leading-\[1\.3em\]{line-height:1.3em}.leading-\[1\.5em\]{line-height:1.5em}.leading-\[1\.75em\]{line-height:1.75em}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[\#212529\]{--tw-text-opacity: 1;color:rgb(33 37 41 / var(--tw-text-opacity))}.text-\[\#6C727F\]{--tw-text-opacity: 1;color:rgb(108 114 127 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-1000{transition-duration:1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:left-\[8px\]:after{content:var(--tw-content);left:8px}.after\:top-\[5px\]:after{content:var(--tw-content);top:5px}.after\:h-\[30px\]:after{content:var(--tw-content);height:30px}.after\:w-\[30px\]:after{content:var(--tw-content);width:30px}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.focus-within\:z-10:focus-within{z-index:10}.hover\:list-disc:hover{list-style-type:disc}.hover\:border-blue-600:hover{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.hover\:border-gray-800:hover{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:bg-red-900:hover{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity))}.hover\:font-semibold:hover{font-weight:600}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.hover\:text-indigo-900:hover{--tw-text-opacity: 1;color:rgb(49 46 129 / var(--tw-text-opacity))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:border-fuchsia-300:focus{--tw-border-opacity: 1;border-color:rgb(240 171 252 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.focus\:bg-gray-600:focus{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.focus\:font-semibold:focus{font-weight:600}.focus\:text-gray-500:focus{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.focus\:text-gray-600:focus{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.focus\:text-gray-900:focus{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.active\:bg-gray-50:active{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.active\:text-gray-800:active{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.active\:outline-none:active{outline:2px solid transparent;outline-offset:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.disabled\:opacity-75:disabled{opacity:.75}.group:hover .group-hover\:border-transparent{border-color:transparent}.group:hover .group-hover\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-\[140\%\]:after{content:var(--tw-content);--tw-translate-x: 140%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}@media (min-width: 640px){.sm\:inset-0{top:0;right:0;bottom:0;left:0}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:col-span-3{grid-column:span 3 / span 3}.sm\:col-span-4{grid-column:span 4 / span 4}.sm\:col-span-6{grid-column:span 6 / span 6}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:ml-6{margin-left:1.5rem}.sm\:mt-0{margin-top:0}.sm\:mt-4{margin-top:1rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-screen{height:100vh}.sm\:w-10{width:2.5rem}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-shrink-0{flex-shrink:0}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-4{gap:1rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-4{grid-column:span 4 / span 4}.md\:col-span-5{grid-column:span 5 / span 5}.md\:col-span-6{grid-column:span 6 / span 6}.md\:col-start-2{grid-column-start:2}.md\:col-start-4{grid-column-start:4}.md\:mx-0,.md\:mx-\[0\]{margin-left:0;margin-right:0}.md\:-mr-1{margin-right:-.25rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-\[46px\]{margin-bottom:46px}.md\:ml-2{margin-left:.5rem}.md\:ml-6{margin-left:1.5rem}.md\:mr-0{margin-right:0}.md\:mr-2{margin-right:.5rem}.md\:mt-0{margin-top:0}.md\:mt-10{margin-top:2.5rem}.md\:mt-5{margin-top:1.25rem}.md\:block{display:block}.md\:flex{display:flex}.md\:grid{display:grid}.md\:hidden{display:none}.md\:min-h-\[411px\]{min-height:411px}.md\:w-1\/2{width:50%}.md\:w-1\/3{width:33.333333%}.md\:max-w-3xl{max-width:48rem}.md\:max-w-xl{max-width:36rem}.md\:flex-shrink-0{flex-shrink:0}.md\:shrink{flex-shrink:1}.md\:grow-0{flex-grow:0}.md\:basis-1\/2{flex-basis:50%}.md\:basis-\[449px\]{flex-basis:449px}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:justify-between{justify-content:space-between}.md\:gap-6{gap:1.5rem}.md\:gap-x-\[21px\]{-moz-column-gap:21px;column-gap:21px}.md\:gap-y-6{row-gap:1.5rem}.md\:border-r{border-right-width:1px}.md\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.md\:p-24{padding:6rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-\[40px\]{padding-left:40px;padding-right:40px}.md\:pb-\[40px\]{padding-bottom:40px}.md\:pl-4{padding-left:1rem}.md\:pl-\[52px\]{padding-left:52px}.md\:pl-\[61px\]{padding-left:61px}.md\:pr-\[20px\]{padding-right:20px}.md\:pr-\[48px\]{padding-right:48px}.md\:pt-0{padding-top:0}.md\:pt-\[58px\]{padding-top:58px}.md\:text-left{text-align:left}.md\:text-center{text-align:center}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-\[30px\]{font-size:30px}.md\:text-\[32px\]{font-size:32px}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-3{grid-column:span 3 / span 3}.lg\:col-span-6{grid-column:span 6 / span 6}.lg\:col-span-7{grid-column:span 7 / span 7}.lg\:col-span-8{grid-column:span 8 / span 8}.lg\:col-start-3{grid-column-start:3}.lg\:col-start-4{grid-column-start:4}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:mt-24{margin-top:6rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:h-screen{height:100vh}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-1\/4{width:25%}.lg\:w-1\/5{width:20%}.lg\:max-w-\[80\%\]{max-width:80%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:items-center{align-items:center}.lg\:gap-4{gap:1rem}.lg\:rounded-lg{border-radius:.5rem}.lg\:px-16{padding-left:4rem;padding-right:4rem}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-2{padding-top:.5rem;padding-bottom:.5rem}}@media (min-width: 1280px){.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:col-span-6{grid-column:span 6 / span 6}.xl\:col-span-8{grid-column:span 8 / span 8}.xl\:col-span-9{grid-column:span 9 / span 9}.xl\:col-start-4{grid-column-start:4}.xl\:ml-5{margin-left:1.25rem}.xl\:mt-0{margin-top:0}.xl\:mt-32{margin-top:8rem}.xl\:flex{display:flex}.xl\:w-auto{width:auto}.xl\:basis-auto{flex-basis:auto}.xl\:flex-row{flex-direction:row}.xl\:flex-nowrap{flex-wrap:nowrap}.xl\:justify-center{justify-content:center}.xl\:border-r{border-right-width:1px}.xl\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.xl\:px-16{padding-left:4rem;padding-right:4rem}.xl\:px-20{padding-left:5rem;padding-right:5rem}.xl\:px-5{padding-left:1.25rem;padding-right:1.25rem}.xl\:pr-20{padding-right:5rem}}@media (prefers-color-scheme: dark){.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}} diff --git a/public/build/manifest.json b/public/build/manifest.json index f6047f4d4c3c..954c5b5476eb 100644 --- a/public/build/manifest.json +++ b/public/build/manifest.json @@ -240,7 +240,7 @@ "src": "resources/js/setup/setup.js" }, "resources/sass/app.scss": { - "file": "assets/app-039bd735.css", + "file": "assets/app-06521fee.css", "isEntry": true, "src": "resources/sass/app.scss" } From 2214455364b6e5f644c21782572b8d8649c12926 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 17:26:48 +1000 Subject: [PATCH 13/30] Updated CSS --- composer.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 0ee5593b8e1e..801fedde6e00 100644 --- a/composer.json +++ b/composer.json @@ -131,7 +131,9 @@ "app/Helpers/Generic.php", "app/Helpers/ClientPortal.php" ], - "classmap": ["app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/"] + "classmap": [ + "app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/" + ] }, "autoload-dev": { "psr-4": { @@ -184,7 +186,7 @@ "url": "https://github.com/turbo124/apple" }, { - "type":"vcs", + "type": "vcs", "url": "https://github.com/invoiceninja/einvoice" }, { @@ -202,4 +204,4 @@ ], "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file From 0edb03943b90f71ddae2fa18f1da51f4ed9b7d25 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:22:00 +1000 Subject: [PATCH 14/30] Updates for PRedis --- .../Middleware/ThrottleRequestsWithPredis.php | 33 ++++++++++++------- app/Jobs/RecurringInvoice/SendRecurring.php | 4 +-- app/Providers/RouteServiceProvider.php | 19 +++++------ app/Services/Template/TemplateService.php | 2 +- composer.lock | 22 ++++++------- 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/app/Http/Middleware/ThrottleRequestsWithPredis.php b/app/Http/Middleware/ThrottleRequestsWithPredis.php index 365cdad1929d..30388163d103 100644 --- a/app/Http/Middleware/ThrottleRequestsWithPredis.php +++ b/app/Http/Middleware/ThrottleRequestsWithPredis.php @@ -4,15 +4,15 @@ namespace App\Http\Middleware; use Closure; use Illuminate\Cache\RateLimiter; +use Illuminate\Contracts\Redis\Factory as Redis; use Illuminate\Redis\Limiters\DurationLimiter; -use Illuminate\Routing\Middleware\ThrottleRequests; -class ThrottleRequestsWithPredis extends ThrottleRequests +class ThrottleRequestsWithPredis extends \Illuminate\Routing\Middleware\ThrottleRequests { /** * The Redis factory implementation. * - * @var \Illuminate\Redis\Connections\Connection + * @var \Illuminate\Contracts\Redis\Factory */ protected $redis; @@ -34,13 +34,17 @@ class ThrottleRequestsWithPredis extends ThrottleRequests * Create a new request throttler. * * @param \Illuminate\Cache\RateLimiter $limiter + * @param \Illuminate\Contracts\Redis\Factory $redis * @return void */ - public function __construct(RateLimiter $limiter) + public function __construct(RateLimiter $limiter, Redis $redis) { parent::__construct($limiter); $this->redis = \Illuminate\Support\Facades\Redis::connection('sentinel-cache'); + + // $this->redis = $redis; + } /** @@ -56,7 +60,7 @@ class ThrottleRequestsWithPredis extends ThrottleRequests protected function handleRequest($request, Closure $next, array $limits) { foreach ($limits as $limit) { - if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) { + if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decaySeconds)) { throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback); } } @@ -79,16 +83,13 @@ class ThrottleRequestsWithPredis extends ThrottleRequests * * @param string $key * @param int $maxAttempts - * @param int $decayMinutes + * @param int $decaySeconds * @return mixed */ - protected function tooManyAttempts($key, $maxAttempts, $decayMinutes) + protected function tooManyAttempts($key, $maxAttempts, $decaySeconds) { $limiter = new DurationLimiter( - $this->redis, - $key, - $maxAttempts, - $decayMinutes * 60 + $this->getRedisConnection(), $key, $maxAttempts, $decaySeconds ); return tap(! $limiter->acquire(), function () use ($key, $limiter) { @@ -121,4 +122,14 @@ class ThrottleRequestsWithPredis extends ThrottleRequests { return $this->decaysAt[$key] - $this->currentTime(); } + + /** + * Get the Redis connection that should be used for throttling. + * + * @return \Illuminate\Redis\Connections\Connection + */ + protected function getRedisConnection() + { + return $this->redis; + } } diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index a856539a642a..6874e2e980c0 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -176,8 +176,8 @@ class SendRecurring implements ShouldQueue private function createRecurringInvitations($invoice): Invoice { if ($this->recurring_invoice->invitations->count() == 0) { - $this->recurring_invoice->service()->createInvitations()->save(); - $this->recurring_invoice = $this->recurring_invoice->fresh(); + $this->recurring_invoice = $this->recurring_invoice->service()->createInvitations()->save(); + // $this->recurring_invoice = $this->recurring_invoice->fresh(); } $this->recurring_invoice->invitations->each(function ($recurring_invitation) use ($invoice) { diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 8b447788b7be..4a86a210f6ce 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -11,17 +11,16 @@ namespace App\Providers; -use App\Http\Middleware\ThrottleRequestsWithPredis; -use App\Models\Scheduler; use App\Utils\Ninja; +use App\Models\Scheduler; +use Illuminate\Http\Request; use App\Utils\Traits\MakesHash; +use Illuminate\Support\Facades\Route; use Illuminate\Cache\RateLimiting\Limit; +use Illuminate\Support\Facades\RateLimiter; +use App\Http\Middleware\ThrottleRequestsWithPredis; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; -use Illuminate\Http\Request; -use Illuminate\Routing\Middleware\ThrottleRequests; -use Illuminate\Support\Facades\RateLimiter; -use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { @@ -36,11 +35,11 @@ class RouteServiceProvider extends ServiceProvider { parent::boot(); - if (Ninja::isHosted() && !config('ninja.testvars.travis')) { + // if (Ninja::isHosted() && !config('ninja.testvars.travis')) { app('router')->aliasMiddleware('throttle', ThrottleRequestsWithPredis::class); - } else { - app('router')->aliasMiddleware('throttle', ThrottleRequests::class); - } + // } else { + // app('router')->aliasMiddleware('throttle', ThrottleRequests::class); + // } Route::bind('task_scheduler', function ($value) { if (is_numeric($value)) { diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 6e945840edb1..c511409993ca 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -482,7 +482,7 @@ class TemplateService default => $processed = [], }; - nlog(json_encode($processed)); + // nlog(json_encode($processed)); return $processed; diff --git a/composer.lock b/composer.lock index c5427c1227ac..e194aaba1e31 100644 --- a/composer.lock +++ b/composer.lock @@ -16665,23 +16665,23 @@ }, { "name": "nunomaduro/collision", - "version": "v8.3.0", + "version": "v8.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "b49f5b2891ce52726adfd162841c69d4e4c84229" + "reference": "e7d1aa8ed753f63fa816932bbc89678238843b4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/b49f5b2891ce52726adfd162841c69d4e4c84229", - "reference": "b49f5b2891ce52726adfd162841c69d4e4c84229", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/e7d1aa8ed753f63fa816932bbc89678238843b4a", + "reference": "e7d1aa8ed753f63fa816932bbc89678238843b4a", "shasum": "" }, "require": { "filp/whoops": "^2.15.4", "nunomaduro/termwind": "^2.0.1", "php": "^8.2.0", - "symfony/console": "^7.1.2" + "symfony/console": "^7.1.3" }, "conflict": { "laravel/framework": "<11.0.0 || >=12.0.0", @@ -16689,13 +16689,13 @@ }, "require-dev": { "larastan/larastan": "^2.9.8", - "laravel/framework": "^11.16.0", - "laravel/pint": "^1.16.2", - "laravel/sail": "^1.30.2", + "laravel/framework": "^11.19.0", + "laravel/pint": "^1.17.1", + "laravel/sail": "^1.31.0", "laravel/sanctum": "^4.0.2", "laravel/tinker": "^2.9.0", - "orchestra/testbench-core": "^9.2.1", - "pestphp/pest": "^2.34.9 || ^3.0.0", + "orchestra/testbench-core": "^9.2.3", + "pestphp/pest": "^2.35.0 || ^3.0.0", "sebastian/environment": "^6.1.0 || ^7.0.0" }, "type": "library", @@ -16758,7 +16758,7 @@ "type": "patreon" } ], - "time": "2024-07-16T22:41:01+00:00" + "time": "2024-08-03T15:32:23+00:00" }, { "name": "phar-io/manifest", From 689fe9218d2b9520bba3e44224def219543a7052 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:28:27 +1000 Subject: [PATCH 15/30] Roll back routeserviceprovider changes --- app/Providers/RouteServiceProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 4a86a210f6ce..4f447463c7bb 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -35,11 +35,11 @@ class RouteServiceProvider extends ServiceProvider { parent::boot(); - // if (Ninja::isHosted() && !config('ninja.testvars.travis')) { + if (Ninja::isHosted() && !config('ninja.testvars.travis')) { app('router')->aliasMiddleware('throttle', ThrottleRequestsWithPredis::class); - // } else { - // app('router')->aliasMiddleware('throttle', ThrottleRequests::class); - // } + } else { + app('router')->aliasMiddleware('throttle', ThrottleRequests::class); + } Route::bind('task_scheduler', function ($value) { if (is_numeric($value)) { From 7e986b82c764e7fa6de61a6a61a8575659ab47b1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 18:46:37 +1000 Subject: [PATCH 16/30] Add includes --- app/Providers/RouteServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 4f447463c7bb..6421b53ca446 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -19,6 +19,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; use App\Http\Middleware\ThrottleRequestsWithPredis; +use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; From d69d465abf28e16129e476be10e3cea1d2911ebc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 4 Aug 2024 20:21:30 +1000 Subject: [PATCH 17/30] Fixes for recurring invoice queries --- app/Jobs/Cron/RecurringInvoicesCron.php | 43 ++++++++++--------------- app/Jobs/Util/QuoteReminderJob.php | 16 ++++----- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/app/Jobs/Cron/RecurringInvoicesCron.php b/app/Jobs/Cron/RecurringInvoicesCron.php index b9c30656a5c8..f295ea6e446b 100644 --- a/app/Jobs/Cron/RecurringInvoicesCron.php +++ b/app/Jobs/Cron/RecurringInvoicesCron.php @@ -48,12 +48,12 @@ class RecurringInvoicesCron Auth::logout(); if (! config('ninja.db.multi_db_enabled')) { - $recurring_invoices = RecurringInvoice::query()->where('recurring_invoices.status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('recurring_invoices.is_deleted', false) - ->where('recurring_invoices.remaining_cycles', '!=', '0') - ->whereNotNull('recurring_invoices.next_send_date') - ->whereNull('recurring_invoices.deleted_at') - ->where('recurring_invoices.next_send_date', '<=', now()->toDateTimeString()) + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) + ->where('is_deleted', false) + ->where('remaining_cycles', '!=', '0') + ->whereNotNull('next_send_date') + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); @@ -87,27 +87,18 @@ class RecurringInvoicesCron foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - $recurring_invoices = RecurringInvoice::query()->where('recurring_invoices.status_id', RecurringInvoice::STATUS_ACTIVE) - ->where('recurring_invoices.is_deleted', false) - ->where('recurring_invoices.remaining_cycles', '!=', '0') - ->whereNull('recurring_invoices.deleted_at') - ->whereNotNull('recurring_invoices.next_send_date') - ->where('recurring_invoices.next_send_date', '<=', now()->toDateTimeString()) - // ->whereHas('client', function ($query) { - // $query->where('is_deleted', 0) - // ->where('deleted_at', null); - // }) - // ->whereHas('company', function ($query) { - // $query->where('is_disabled', 0); - // }) - ->leftJoin('clients', function ($join) { - $join->on('recurring_invoices.client_id', '=', 'clients.id') - ->where('clients.is_deleted', 0) - ->whereNull('clients.deleted_at'); + $recurring_invoices = RecurringInvoice::query()->where('status_id', RecurringInvoice::STATUS_ACTIVE) + ->where('is_deleted', false) + ->where('remaining_cycles', '!=', '0') + ->whereNull('deleted_at') + ->whereNotNull('next_send_date') + ->where('next_send_date', '<=', now()->toDateTimeString()) + ->whereHas('client', function ($query) { + $query->where('is_deleted', 0) + ->where('deleted_at', null); }) - ->leftJoin('companies', function ($join) { - $join->on('recurring_invoices.company_id', '=', 'companies.id') - ->where('companies.is_disabled', 0); + ->whereHas('company', function ($query) { + $query->where('is_disabled', 0); }) ->with('company') ->cursor(); diff --git a/app/Jobs/Util/QuoteReminderJob.php b/app/Jobs/Util/QuoteReminderJob.php index fdebf50198c7..a583062df824 100644 --- a/app/Jobs/Util/QuoteReminderJob.php +++ b/app/Jobs/Util/QuoteReminderJob.php @@ -61,10 +61,10 @@ class QuoteReminderJob implements ShouldQueue nrlog("Sending quote reminders on ".now()->format('Y-m-d h:i:s')); Quote::query() - ->where('quotes.is_deleted', 0) - ->whereIn('quotes.status_id', [Invoice::STATUS_SENT]) - ->whereNull('quotes.deleted_at') - ->where('quotes.next_send_date', '<=', now()->toDateTimeString()) + ->where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT]) + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); @@ -88,10 +88,10 @@ class QuoteReminderJob implements ShouldQueue nrlog("Sending quote reminders on db {$db} ".now()->format('Y-m-d h:i:s')); Quote::query() - ->where('quotes.is_deleted', 0) - ->whereIn('quotes.status_id', [Invoice::STATUS_SENT]) - ->whereNull('quotes.deleted_at') - ->where('quotes.next_send_date', '<=', now()->toDateTimeString()) + ->where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT]) + ->whereNull('deleted_at') + ->where('next_send_date', '<=', now()->toDateTimeString()) ->whereHas('client', function ($query) { $query->where('is_deleted', 0) ->where('deleted_at', null); From dea57e07809f79268b3e2f75c08892315ff18dc6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 08:37:21 +1000 Subject: [PATCH 18/30] Fixes for recurring invoice queries --- VERSION.txt | 2 +- app/Http/Controllers/ExportController.php | 4 ++-- app/Jobs/Company/CompanyExport.php | 2 +- config/ninja.php | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index b62d8ef8ec05..21a04bbf2c42 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.10.17 \ No newline at end of file +5.10.18 \ No newline at end of file diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index d182e613057d..0aea27594fe8 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -59,9 +59,9 @@ class ExportController extends BaseController /** @var \App\Models\User $user */ $user = auth()->user(); - $hash = Str::uuid(); + $hash = Str::uuid()->toString(); $url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]); - Cache::put($hash, $url, now()->addHour()); + Cache::put($hash, $url, 3600); CompanyExport::dispatch($user->getCompany(), $user, $hash); diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index 3885c05e7df3..9cc901cdf240 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -695,7 +695,7 @@ class CompanyExport implements ShouldQueue $url = Cache::get($this->hash); - Cache::put($this->hash, $storage_path, now()->addHour()); + Cache::put($this->hash, $storage_path, 3600); App::forgetInstance('translator'); $t = app('translator'); diff --git a/config/ninja.php b/config/ninja.php index a1fe742fc8dc..1881afbb4e3a 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.10.17'), - 'app_tag' => env('APP_TAG', '5.10.17'), + 'app_version' => env('APP_VERSION', '5.10.18'), + 'app_tag' => env('APP_TAG', '5.10.18'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), From 90eccfcaa0bb83982096b97a14c5f19cf451b7e1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 08:56:31 +1000 Subject: [PATCH 19/30] Updated company migration --- ..._235430_2024_30_07_tax_model_migration.php | 2 +- ...24_08_04_225558_tax_model_migration_v2.php | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2024_08_04_225558_tax_model_migration_v2.php diff --git a/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php b/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php index ca0e7e27904e..8337c44e1643 100644 --- a/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php +++ b/database/migrations/2024_07_29_235430_2024_30_07_tax_model_migration.php @@ -16,7 +16,7 @@ return new class extends Migration // ->cursor() // ->each(function($company){ - // if($company->tax_data?->version == 'alpha') + // if($company->tax_data?->version == 'alpha' && ($company->tax_data->seller_subregion ?? false)) // { // $company->update(['tax_data' => new \App\DataMapper\Tax\TaxModel($company->tax_data)]); diff --git a/database/migrations/2024_08_04_225558_tax_model_migration_v2.php b/database/migrations/2024_08_04_225558_tax_model_migration_v2.php new file mode 100644 index 000000000000..999e69bdba33 --- /dev/null +++ b/database/migrations/2024_08_04_225558_tax_model_migration_v2.php @@ -0,0 +1,41 @@ +cursor() + ->each(function ($company) { + + if($company->tax_data?->version == 'alpha' && ($company->tax_data->seller_subregion ?? false)) { + + $company->update(['tax_data' => new \App\DataMapper\Tax\TaxModel($company->tax_data)]); + + } + + }); + + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; From 20573b362c106058494bbe421e630387ab30a185 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 11:57:42 +1000 Subject: [PATCH 20/30] Remove paypal express, omnipay --- app/DataProviders/Frequencies.php | 19 - app/Helpers/TranslationHelper.php | 2 +- .../VendorPortal/VendorContactController.php | 16 +- .../Middleware/ThrottleRequestsWithPredis.php | 11 +- app/Http/ViewComposers/PortalComposer.php | 4 +- app/PaymentDrivers/AbstractPaymentDriver.php | 2 +- .../PayPalExpressPaymentDriver.php | 249 ------ app/PaymentDrivers/Rotessa/PaymentMethod.php | 97 ++- .../Rotessa/Resources/Customer.php | 22 - .../Rotessa/Resources/Transaction.php | 23 - .../src/Omnipay/Rotessa/AbstractClient.php | 21 - .../src/Omnipay/Rotessa/ApiTrait.php | 41 - .../src/Omnipay/Rotessa/ClientInterface.php | 11 - .../Omnipay/Rotessa/Exception/Exceptions.php | 43 - .../src/Omnipay/Rotessa/Gateway.php | 74 -- .../src/Omnipay/Rotessa/Http/Client.php | 82 -- .../Rotessa/Http/Response/Response.php | 32 - .../src/Omnipay/Rotessa/IsValidTypeTrait.php | 12 - .../Message/Request/AbstractRequest.php | 52 -- .../Rotessa/Message/Request/BaseRequest.php | 93 --- .../Request/DeleteTransactionSchedulesId.php | 18 - .../Rotessa/Message/Request/GetCustomers.php | 14 - .../Message/Request/GetCustomersId.php | 19 - .../Request/GetTransactionSchedulesId.php | 17 - .../Message/Request/PatchCustomersId.php | 65 -- .../Request/PatchTransactionSchedulesId.php | 22 - .../Rotessa/Message/Request/PostCustomers.php | 60 -- .../PostCustomersShowWithCustomIdentifier.php | 19 - .../Request/PostTransactionSchedules.php | 31 - ...ionSchedulesCreateWithCustomIdentifier.php | 16 - .../PostTransactionSchedulesUpdateViaPost.php | 24 - .../Message/Request/RequestInterface.php | 10 - .../Message/Response/AbstractResponse.php | 16 - .../Rotessa/Message/Response/BaseResponse.php | 44 - .../Message/Response/ResponseInterface.php | 9 - .../Omnipay/Rotessa/Model/AbstractModel.php | 63 -- .../src/Omnipay/Rotessa/Model/BaseModel.php | 24 - .../Omnipay/Rotessa/Model/CustomerModel.php | 94 --- .../Rotessa/Model/CustomerPatchModel.php | 16 - .../Omnipay/Rotessa/Model/ModelInterface.php | 8 - .../Model/TransactionScheduleModel.php | 84 -- .../Model/TransactionSchedulesIdBodyModel.php | 23 - ...sactionSchedulesUpdateViaPostBodyModel.php | 24 - .../src/Omnipay/Rotessa/Object/Address.php | 53 -- .../Rotessa/Object/AuthorizationType.php | 28 - .../Rotessa/Object/BankAccountType.php | 28 - .../src/Omnipay/Rotessa/Object/Country.php | 33 - .../Omnipay/Rotessa/Object/CustomerType.php | 28 - .../src/Omnipay/Rotessa/Object/Frequency.php | 64 -- app/PaymentDrivers/RotessaPaymentDriver.php | 96 +-- app/Utils/TranslationHelper.php | 91 +-- composer.json | 3 - composer.lock | 755 +----------------- .../v3/authentication/register-form.blade.php | 2 +- .../portal/ninja2020/auth/register.blade.php | 2 +- .../rotessa/bank_transfer/pay.blade.php | 4 +- .../rotessa/components/account.blade.php | 7 + .../rotessa/components/address.blade.php | 16 + .../components/banks/CA/bank.blade.php | 6 + .../components/banks/US/bank.blade.php | 9 + .../rotessa/components/contact.blade.php | 15 + .../components/dropdowns/country/CA.blade.php | 4 + .../components/dropdowns/country/US.blade.php | 3 + 63 files changed, 193 insertions(+), 2680 deletions(-) delete mode 100644 app/DataProviders/Frequencies.php delete mode 100644 app/PaymentDrivers/PayPalExpressPaymentDriver.php delete mode 100644 app/PaymentDrivers/Rotessa/Resources/Customer.php delete mode 100644 app/PaymentDrivers/Rotessa/Resources/Transaction.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Exception/Exceptions.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Gateway.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/AbstractRequest.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomersId.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/AbstractResponse.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/BaseResponse.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/AbstractModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/ModelInterface.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionScheduleModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/BankAccountType.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Country.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/CustomerType.php delete mode 100644 app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Frequency.php diff --git a/app/DataProviders/Frequencies.php b/app/DataProviders/Frequencies.php deleted file mode 100644 index 503d40973dc4..000000000000 --- a/app/DataProviders/Frequencies.php +++ /dev/null @@ -1,19 +0,0 @@ - $vendor_contact->vendor->company->settings, 'company' => $vendor_contact->vendor->company, 'sidebar' => $this->sidebarMenu(), - 'countries' => TranslationHelper::getCountries(), + 'countries' => app('countries'), ]); } - public function update(VendorContact $vendor_contact) + public function update(Request $request, VendorContact $vendor_contact) { - $vendor_contact->fill(request()->all()); - $vendor_contact->vendor->fill(request()->all()); + $vendor_contact->fill($request->all()); + $vendor_contact->vendor->fill($request->all()); $vendor_contact->push(); return back()->withSuccess(ctrans('texts.profile_updated_successfully')); @@ -76,16 +76,10 @@ class VendorContactController extends Controller $enabled_modules = auth()->guard('vendor')->user()->company->enabled_modules; $data = []; - // TODO: Enable dashboard once it's completed. - // $this->settings->enable_client_portal_dashboard - // $data[] = [ 'title' => ctrans('texts.dashboard'), 'url' => 'client.dashboard', 'icon' => 'activity']; - if (self::MODULE_PURCHASE_ORDERS & $enabled_modules) { $data[] = ['title' => ctrans('texts.purchase_orders'), 'url' => 'vendor.purchase_orders.index', 'icon' => 'file-text']; } - // $data[] = ['title' => ctrans('texts.documents'), 'url' => 'client.documents.index', 'icon' => 'download']; - return $data; } } diff --git a/app/Http/Middleware/ThrottleRequestsWithPredis.php b/app/Http/Middleware/ThrottleRequestsWithPredis.php index 30388163d103..6d7cad13fb76 100644 --- a/app/Http/Middleware/ThrottleRequestsWithPredis.php +++ b/app/Http/Middleware/ThrottleRequestsWithPredis.php @@ -32,19 +32,15 @@ class ThrottleRequestsWithPredis extends \Illuminate\Routing\Middleware\Throttle /** * Create a new request throttler. - * - * @param \Illuminate\Cache\RateLimiter $limiter - * @param \Illuminate\Contracts\Redis\Factory $redis * @return void */ + + /** @phpstan-ignore-next-line */ public function __construct(RateLimiter $limiter, Redis $redis) { parent::__construct($limiter); - + /** @phpstan-ignore-next-line */ $this->redis = \Illuminate\Support\Facades\Redis::connection('sentinel-cache'); - - // $this->redis = $redis; - } /** @@ -126,7 +122,6 @@ class ThrottleRequestsWithPredis extends \Illuminate\Routing\Middleware\Throttle /** * Get the Redis connection that should be used for throttling. * - * @return \Illuminate\Redis\Connections\Connection */ protected function getRedisConnection() { diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index 15c8016a5f89..6b0790a0f4ff 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -88,11 +88,11 @@ class PortalComposer $data['sidebar'] = $this->sidebarMenu(); $data['header'] = []; $data['footer'] = []; - $data['countries'] = TranslationHelper::getCountries(); + $data['countries'] = app('countries'); $data['company'] = auth()->guard('contact')->user()->company; $data['client'] = auth()->guard('contact')->user()->client; $data['settings'] = $this->settings; - $data['currencies'] = TranslationHelper::getCurrencies(); + $data['currencies'] = app('currencies'); $data['contact'] = auth()->guard('contact')->user(); $data['multiple_contacts'] = session()->get('multiple_contacts') ?: collect(); diff --git a/app/PaymentDrivers/AbstractPaymentDriver.php b/app/PaymentDrivers/AbstractPaymentDriver.php index 05fdf566e918..acdc9eb9c6b8 100644 --- a/app/PaymentDrivers/AbstractPaymentDriver.php +++ b/app/PaymentDrivers/AbstractPaymentDriver.php @@ -20,7 +20,7 @@ abstract class AbstractPaymentDriver { abstract public function authorizeView(array $data); - abstract public function authorizeResponse(Request $request); + abstract public function authorizeResponse(\App\Http\Requests\Request | Request $request); abstract public function processPaymentView(array $data); diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php deleted file mode 100644 index ea3cdc8c8bf7..000000000000 --- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php +++ /dev/null @@ -1,249 +0,0 @@ -omnipay_gateway = Omnipay::create( - $this->company_gateway->gateway->provider - ); - - $this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig()); - } - - public function setPaymentMethod($payment_method_id) - { - // PayPal doesn't have multiple ways of paying. - // There's just one, off-site redirect. - - return $this; - } - - public function authorizeView($payment_method) - { - // PayPal doesn't support direct authorization. - - return $this; - } - - public function authorizeResponse($request) - { - // PayPal doesn't support direct authorization. - - return $this; - } - - public function processPaymentView($data) - { - $this->initializeOmnipayGateway(); - - $this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]); - $this->payment_hash->save(); - - $response = $this->omnipay_gateway - ->purchase($this->generatePaymentDetails($data)) - ->setItems($this->generatePaymentItems($data)) - ->send(); - - if ($response->isRedirect()) { - return $response->redirect(); - } - - // $this->sendFailureMail($response->getMessage() ?: ''); - - $message = [ - 'server_response' => $response->getMessage(), - 'data' => $this->payment_hash->data, - ]; - - SystemLogger::dispatch( - $message, - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_FAILURE, - SystemLog::TYPE_PAYPAL, - $this->client, - $this->client->company, - ); - - throw new PaymentFailed($response->getMessage(), $response->getCode()); - } - - public function processPaymentResponse($request) - { - $this->initializeOmnipayGateway(); - - $response = $this->omnipay_gateway - ->completePurchase(['amount' => $this->payment_hash->data->amount, 'currency' => $this->client->getCurrencyCode()]) - ->send(); - - if ($response->isCancelled() && $this->client->getSetting('enable_client_portal')) { - return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled')); - } elseif($response->isCancelled() && !$this->client->getSetting('enable_client_portal')) { - redirect()->route('client.invoices.show', ['invoice' => $this->payment_hash->fee_invoice])->with('warning', ctrans('texts.status_cancelled')); - } - - if ($response->isSuccessful()) { - $data = [ - 'payment_method' => $response->getData()['TOKEN'], - 'payment_type' => PaymentType::PAYPAL, - 'amount' => $this->payment_hash->data->amount, - 'transaction_reference' => $response->getTransactionReference(), - 'gateway_type_id' => GatewayType::PAYPAL, - ]; - - $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); - - SystemLogger::dispatch( - ['response' => (array) $response->getData(), 'data' => $data], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_SUCCESS, - SystemLog::TYPE_PAYPAL, - $this->client, - $this->client->company, - ); - - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); - } - - if (! $response->isSuccessful()) { - $data = $response->getData(); - - $this->sendFailureMail($response->getMessage() ?: ''); - - $message = [ - 'server_response' => $data['L_LONGMESSAGE0'], - 'data' => $this->payment_hash->data, - ]; - - SystemLogger::dispatch( - $message, - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_FAILURE, - SystemLog::TYPE_PAYPAL, - $this->client, - $this->client->company, - ); - - throw new PaymentFailed($response->getMessage(), $response->getCode()); - } - } - - public function generatePaymentDetails(array $data) - { - $_invoice = collect($this->payment_hash->data->invoices)->first(); - $invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id)); - - // $this->fee = $this->feeCalc($invoice, $data['total']['amount_with_fee']); - - return [ - 'currency' => $this->client->getCurrencyCode(), - 'transactionType' => 'Purchase', - 'clientIp' => request()->getClientIp(), - // 'amount' => round(($data['total']['amount_with_fee'] + $this->fee),2), - 'amount' => round($data['total']['amount_with_fee'], 2), - 'returnUrl' => route('client.payments.response', [ - 'company_gateway_id' => $this->company_gateway->id, - 'payment_hash' => $this->payment_hash->hash, - 'payment_method_id' => GatewayType::PAYPAL, - ]), - 'cancelUrl' => $this->client->company->domain()."/client/invoices/{$invoice->hashed_id}", - 'description' => implode(',', collect($this->payment_hash->data->invoices) - ->map(function ($invoice) { - return sprintf('%s: %s', ctrans('texts.invoice_number'), $invoice->invoice_number); - })->toArray()), - 'transactionId' => $this->payment_hash->hash.'-'.time(), - 'ButtonSource' => 'InvoiceNinja_SP', - 'solutionType' => 'Sole', - 'no_shipping' => $this->company_gateway->require_shipping_address ? 0 : 1, - ]; - } - - public function generatePaymentItems(array $data) - { - $_invoice = collect($this->payment_hash->data->invoices)->first(); - $invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id)); - - $items = []; - - $items[] = new Item([ - 'name' => ' ', - 'description' => ctrans('texts.invoice_number').'# '.$invoice->number, - 'price' => $data['total']['amount_with_fee'], - 'quantity' => 1, - ]); - - return $items; - } - - private function feeCalc($invoice, $invoice_total) - { - $invoice->service()->removeUnpaidGatewayFees(); - $invoice = $invoice->fresh(); - - $balance = floatval($invoice->balance); - - $_updated_invoice = $invoice->service()->addGatewayFee($this->company_gateway, GatewayType::PAYPAL, $invoice_total)->save(); - - if (floatval($_updated_invoice->balance) > $balance) { - $fee = floatval($_updated_invoice->balance) - $balance; - - $this->payment_hash->fee_total = $fee; - $this->payment_hash->save(); - - return $fee; - } - - return 0; - } -} diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 9fd4d9f094e5..9ac26feae87d 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -12,14 +12,11 @@ namespace App\PaymentDrivers\Rotessa; -use Carbon\Carbon; -use App\Models\Client; use App\Models\Payment; use App\Models\SystemLog; use Illuminate\View\View; use App\Models\GatewayType; use App\Models\PaymentType; -use Illuminate\Support\Arr; use Illuminate\Http\Request; use App\Jobs\Util\SystemLogger; use App\Exceptions\PaymentFailed; @@ -28,16 +25,18 @@ use App\Models\ClientGatewayToken; use Illuminate\Http\RedirectResponse; use App\PaymentDrivers\RotessaPaymentDriver; use App\PaymentDrivers\Common\MethodInterface; -use App\PaymentDrivers\Rotessa\Resources\Customer; -use App\PaymentDrivers\Rotessa\Resources\Transaction; -use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Common\Exception\InvalidResponseException; -use App\Exceptions\Ninja\ClientPortalAuthorizationException; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; class PaymentMethod implements MethodInterface { + private array $transaction = [ + "financial_transactions" => [], + "frequency" =>'Once', + "installments" =>1 + ]; + public function __construct(protected RotessaPaymentDriver $rotessa) { $this->rotessa->init(); @@ -51,7 +50,7 @@ class PaymentMethod implements MethodInterface */ public function authorizeView(array $data): View { - $data['contact'] = collect($data['client']->contacts->firstWhere('is_primary', 1)->toArray())->merge([ + $data['contact'] = collect($data['client']->contacts->first()->toArray())->merge([ 'home_phone' => $data['client']->phone, 'custom_identifier' => $data['client']->number, 'name' => $data['client']->name, @@ -73,42 +72,38 @@ class PaymentMethod implements MethodInterface * @param Request $request * @return RedirectResponse */ - public function authorizeResponse(Request $request): RedirectResponse + public function authorizeResponse($request) { - try { - $request->validate([ - 'gateway_type_id' => ['required','integer'], - 'country' => ['required'], - 'name' => ['required'], - 'address_1' => ['required'], - // 'address_2' => ['required'], - 'city' => ['required'], - 'email' => ['required','email:filter'], - 'province_code' => ['required','size:2','alpha'], - 'postal_code' => ['required'], - 'authorization_type' => ['required'], - 'account_number' => ['required'], - 'bank_name' => ['required'], - 'phone' => ['required'], - 'home_phone' => ['required','size:10'], - 'bank_account_type'=>['required_if:country,US'], - 'routing_number'=>['required_if:country,US'], - 'institution_number'=>['required_if:country,CA','numeric'], - 'transit_number'=>['required_if:country,CA','numeric'], - 'custom_identifier'=>['required_without:customer_id'], - 'customer_id'=>['required_without:custom_identifier','integer'], - ]); - $customer = new Customer( ['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->resolve()); - - return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); + $request->validate([ + 'gateway_type_id' => ['required','integer'], + 'country' => ['required','in:US,CA,United States,Canada'], + 'name' => ['required'], + 'address_1' => ['required'], + 'city' => ['required'], + 'email' => ['required','email:filter'], + 'province_code' => ['required','size:2','alpha'], + 'postal_code' => ['required'], + 'authorization_type' => ['required'], + 'account_number' => ['required'], + 'bank_name' => ['required'], + 'phone' => ['required'], + 'home_phone' => ['required','size:10'], + 'bank_account_type'=>['required_if:country,US'], + 'routing_number'=>['required_if:country,US'], + 'institution_number'=>['required_if:country,CA','numeric','digits:3'], + 'transit_number'=>['required_if:country,CA','numeric','digits:5'], + 'custom_identifier'=>['required_without:customer_id'], + 'customer_id'=>['required_without:custom_identifier','integer'], + 'customer_type' => ['required', 'in:Personal,Business'], + ]); - } catch (\Throwable $e) { - return $this->rotessa->processInternallyFailedPayment($this->rotessa, new ClientPortalAuthorizationException( get_class( $e) . " : {$e->getMessage()}", (int) $e->getCode() )); - } + $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); + + return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); - // return back()->withMessage(ctrans('texts.unable_to_verify_payment_method')); } /** @@ -124,7 +119,7 @@ class PaymentMethod implements MethodInterface $data['due_date'] = date('Y-m-d', min(max(strtotime($data['invoices']->max('due_date')), strtotime('now')), strtotime('+1 day'))); $data['process_date'] = $data['due_date']; $data['currency'] = $this->rotessa->client->getCurrencyCode(); - $data['frequency'] = Frequencies::getOnePayment(); + $data['frequency'] = 'Once'; $data['installments'] = 1; $data['invoice_nums'] = $data['invoices']->pluck('invoice_number')->join(', '); return render('gateways.rotessa.bank_transfer.pay', $data ); @@ -142,11 +137,7 @@ class PaymentMethod implements MethodInterface $customer = null; try { - $request->validate([ - 'source' => ['required','string','exists:client_gateway_tokens,token'], - 'amount' => ['required','numeric'], - 'process_date'=> ['required','date','after_or_equal:today'], - ]); + $customer = ClientGatewayToken::query() ->where('company_gateway_id', $this->rotessa->company_gateway->id) ->where('client_id', $this->rotessa->client->id) @@ -156,16 +147,20 @@ class PaymentMethod implements MethodInterface if(!$customer) throw new \Exception('Client gateway token not found!', SystemLog::TYPE_ROTESSA); - $transaction = new Transaction($request->only('frequency' ,'installments','amount','process_date') + ['comment' => $this->rotessa->getDescription(false) ]); - $transaction->additional(['customer_id' => $customer->gateway_customer_reference]); - $transaction = array_filter( $transaction->resolve()); + $transaction = array_merge($this->transaction,[ + 'amount' => $request->input('amount'), + 'process_date' => now()->addSeconds($customer->client->utc_offset())->format('Y-m-d'), + 'comment' => $this->rotessa->getDescription(false), + 'customer_id' => $customer->gateway_customer_reference, + ]); + $response = $this->rotessa->gatewayRequest('post','transaction_schedules', $transaction); - + if($response->failed()) $response->throw(); $response = $response->json(); - nlog($response); + return $this->processPendingPayment($response['id'], (float) $response['amount'], PaymentType::ACSS , $customer->token); } catch(\Throwable $e) { $this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) ); diff --git a/app/PaymentDrivers/Rotessa/Resources/Customer.php b/app/PaymentDrivers/Rotessa/Resources/Customer.php deleted file mode 100644 index c2514dfdd8c1..000000000000 --- a/app/PaymentDrivers/Rotessa/Resources/Customer.php +++ /dev/null @@ -1,22 +0,0 @@ -resource->jsonSerialize(); - } - - function toArray(Request $request) : array { - return $this->additional + parent::toArray($request); - } -} diff --git a/app/PaymentDrivers/Rotessa/Resources/Transaction.php b/app/PaymentDrivers/Rotessa/Resources/Transaction.php deleted file mode 100644 index 84ce332860f8..000000000000 --- a/app/PaymentDrivers/Rotessa/Resources/Transaction.php +++ /dev/null @@ -1,23 +0,0 @@ -resource->jsonSerialize(); - } - - function toArray(Request $request) : array { - return $this->additional + parent::toArray($request); - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php deleted file mode 100644 index c84a97322717..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php +++ /dev/null @@ -1,21 +0,0 @@ -default_parameters; - } - - public function setDefaultParameters(array $params) { - $this->default_parameters = $params; - } - -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php deleted file mode 100644 index 5fc947713f3a..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php +++ /dev/null @@ -1,41 +0,0 @@ -createRequest('GetCustomers', [] ); - } - public function postCustomers(array $params) : RequestInterface { - return $this->createRequest('PostCustomers', $params ); - } - public function getCustomersId(array $params) : RequestInterface { - return $this->createRequest('GetCustomersId', $params ); - } - public function patchCustomersId(array $params) : RequestInterface { - return $this->createRequest('PatchCustomersId', $params ); - } - public function postCustomersShowWithCustomIdentifier(array $params) : RequestInterface { - return $this->createRequest('PostCustomersShowWithCustomIdentifier', $params ); - } - public function getTransactionSchedulesId(array $params) : RequestInterface { - return $this->createRequest('GetTransactionSchedulesId', $params ); - } - public function deleteTransactionSchedulesId(array $params) : RequestInterface { - return $this->createRequest('DeleteTransactionSchedulesId', $params ); - } - public function patchTransactionSchedulesId(array $params) : RequestInterface { - return $this->createRequest('PatchTransactionSchedulesId', $params ); - } - public function postTransactionSchedules(array $params) : RequestInterface { - return $this->createRequest('PostTransactionSchedules', $params ); - } - public function postTransactionSchedulesCreateWithCustomIdentifier(array $params) : RequestInterface { - return $this->createRequest('PostTransactionSchedulesCreateWithCustomIdentifier', $params ); - } - public function postTransactionSchedulesUpdateViaPost(array $params) : RequestInterface { - return $this->createRequest('PostTransactionSchedulesUpdateViaPost', $params ); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php deleted file mode 100644 index 4d08fb0441f2..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php +++ /dev/null @@ -1,11 +0,0 @@ - 1234567890 ]; - - protected $test_mode = true; - - protected $api_key; - - public function getName() - { - return 'Rotessa'; - } - - public function getDefaultParameters() : array - { - return array_merge($this->default_parameters, array('api_key' => $this->api_key, 'test_mode' => $this->test_mode ) ); - } - - public function setTestMode($value) { - $this->test_mode = $value; - } - - public function getTestMode() { - return $this->test_mode; - } - - protected function createRequest($class_name, ?array $parameters = [] ) :RequestInterface { - $class = null; - $class_name = "Omnipay\\Rotessa\\Message\\Request\\$class_name"; - $parameters = $class_name::hasModel() ? (($parameters = ($class_name::getModel($parameters)))->validate() ? $parameters->jsonSerialize() : null ) : $parameters; - try { - $class = new $class_name($this->httpClient, $this->httpRequest, $this->getDefaultParameters() + $parameters ); - } catch (\Throwable $th) { - throw $th; - } - - return $class; - } - - function setApiKey($value) { - $this->api_key = $value; - } - - function getApiKey() { - return $this->api_key; - } - - function authorize(array $options = []) : RequestInterface { - return $this->postCustomers($options); - } - - function capture(array $options = []) : RequestInterface { - return array_key_exists('customer_id', $options)? $this->postTransactionSchedules($options) : $this->postTransactionSchedulesCreateWithCustomIdentifier($options) ; - } - - function updateCustomer(array $options) : RequestInterface { - return $this->patchCustomersId($options); - } - - function fetchTransaction($id = null) : RequestInterface { - return $this->getTransactionSchedulesId(compact('id')); - } - -} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php deleted file mode 100644 index 1e0abbe8aba0..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php +++ /dev/null @@ -1,82 +0,0 @@ -httpClient = $httpClient ?: HttpClientDiscovery::find(); - $this->requestFactory = $requestFactory ?: MessageFactoryDiscovery::find(); - parent::__construct($httpClient, $requestFactory); - } - - /** - * @param $method - * @param $uri - * @param array $headers - * @param string|array|resource|StreamInterface|null $body - * @param string $protocolVersion - * @return ResponseInterface - * @throws \Http\Client\Exception - */ - public function request( - $method, - $uri, - array $headers = [], - $body = null, - $protocolVersion = '1.1' - ) { - return $this->sendRequest($method, $uri, $headers, $body, $protocolVersion); - - } - - /** - * @param RequestInterface $request - * @return ResponseInterface - * @throws \Http\Client\Exception - */ - private function sendRequest( $method, - $uri, - array $headers = [], - $body = null, - $protocolVersion = '1.1') - { - - $response = null; - - try { - if( method_exists($this->httpClient, 'sendRequest')) - $response = $this->httpClient->sendRequest( $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion)); - else $response = $this->httpClient->request($method, $uri, compact('body','headers')); - } catch (\Http\Client\Exception\NetworkException $networkException) { - throw new \Exception($networkException->getMessage()); - } catch (\Exception $exception) { - throw new \Exception($exception->getMessage()); - } - - return $response; - } -} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php deleted file mode 100644 index 8d665ac8546e..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php +++ /dev/null @@ -1,32 +0,0 @@ -content, true) )) { - $data = $data['errors'][0]; - $this->reason_phrase = $data['error_message'] ; - $this->reason_code = $data['error_message'] ; - } - } - - public function getReasonPhrase() { - return $this->reason_phrase; - } - - public function getReasonCode() { - return $this->reason_code; - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php deleted file mode 100644 index 266ba3036d9d..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php +++ /dev/null @@ -1,12 +0,0 @@ -api_key = $value; - } - - public function getData() { - try { - if(empty($this->api_key)) throw new \Exception('No Api Key Found!'); - $this->validate( ...array_keys($data = $this->getParameters())); - } catch (\Throwable $th) { - throw new \Omnipay\Rotessa\Exception\ValidationException($th->getMessage() , 600, $th); - } - - return (array) $data; - } - - abstract public function sendData($data) : ResponseInterface; - - abstract protected function sendRequest(string $method, string $endpoint, array $headers = [], array $data = [] ); - - abstract protected function createResponse(array $data) : ResponseInterface; - - abstract public function getEndpointUrl(): string; - - public function getEndpoint() : string { - return $this->endpoint; - } - - public function getTestMode() { - return $this->test_mode; - } - - public function setTestMode($mode) { - $this->test_mode = $mode; - } - } \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php deleted file mode 100644 index 4b68cf0aa2ff..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php +++ /dev/null @@ -1,93 +0,0 @@ -initialize($model); - } - - protected function sendRequest(string $method, string $endpoint, array $headers = [], array $data = []) - { - /** - * @param $method - * @param $uri - * @param array $headers - * @param string|resource|StreamInterface|null $body - * @param string $protocolVersion - * @return ResponseInterface - * @throws \Http\Client\Exception - */ - $response = $this->httpClient->request($method, $endpoint, $headers, json_encode($data) ) ; - $this->response = new Response ($response->getBody()->getContents(), $response->getStatusCode(), $response->getHeaders(), true); - } - - - protected function createResponse(array $data): ResponseInterface { - - return new BaseResponse($this, $data, $this->response->getStatusCode(), $this->response->getReasonPhrase()); - } - - protected function replacePlaceholder($string, $array) { - $pattern = "/\{([^}]+)\}/"; - $replacement = function($matches) use($array) { - $key = $matches[1]; - if (array_key_exists($key, $array)) { - return $array[$key]; - } else { - return $matches[0]; - } - }; - - return preg_replace_callback($pattern, $replacement, $string); - } - - public function sendData($data) :ResponseInterface { - $headers = [ - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'Authorization' => "Token token={$this->api_key}" - ]; - - $this->sendRequest( - $this->method, - $this->getEndpointUrl(), - $headers, - $data); - - return $this->createResponse(json_decode($this->response->getContent(), true)); - } - - public function getEndpoint() : string { - return $this->replacePlaceholder($this->endpoint, $this->getParameters()); - } - - public function getEndpointUrl() : string { - return sprintf('https://%s.%s/v%d%s',$this->test_mode ? self::ENVIRONMENT_SANDBOX : self::ENVIRONMENT_LIVE ,$this->base_url, $this->api_version, $this->getEndpoint()); - } - - public static function hasModel() : bool { - return (bool) static::$model; - } - - public static function getModel($parameters = []) { - $class_name = static::$model; - $class_name = "Omnipay\\Rotessa\\Model\\{$class_name}Model"; - return new $class_name($parameters); - } -} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php deleted file mode 100644 index 7c03c42b0dc6..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php +++ /dev/null @@ -1,18 +0,0 @@ -setParameter('id',$value); - } - -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php deleted file mode 100644 index 17ffde5355d9..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php +++ /dev/null @@ -1,14 +0,0 @@ -setParameter('id',$value); - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php deleted file mode 100644 index 47578d06eb8b..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php +++ /dev/null @@ -1,17 +0,0 @@ -setParameter('id',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php deleted file mode 100644 index 092e378b9fd5..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php +++ /dev/null @@ -1,65 +0,0 @@ -setParameter('id',$value); - } - public function setCustomIdentifier(string $value) { - $this->setParameter('custom_identifier',$value); - } - public function setName(string $value) { - $this->setParameter('name',$value); - } - public function setEmail(string $value) { - $this->setParameter('email',$value); - } - public function setCustomerType(string $value) { - $this->setParameter('customer_type',$value); - } - public function setHomePhone(string $value) { - $this->setParameter('home_phone',$value); - } - public function setPhone(string $value) { - $this->setParameter('phone',$value); - } - public function setBankName(string $value) { - $this->setParameter('bank_name',$value); - } - public function setInstitutionNumber(string $value) { - $this->setParameter('institution_number',$value); - } - public function setTransitNumber(string $value) { - $this->setParameter('transit_number',$value); - } - public function setBankAccountType(string $value) { - $this->setParameter('bank_account_type',$value); - } - public function setAuthorizationType(string $value) { - $this->setParameter('authorization_type',$value); - } - public function setRoutingNumber(string $value) { - $this->setParameter('routing_number',$value); - } - public function setAccountNumber(string $value) { - $this->setParameter('account_number',$value); - } - public function setAddress(array $value) { - $this->setParameter('address',$value); - } - public function setTransactionSchedules(array $value) { - $this->setParameter('transaction_schedules',$value); - } - public function setFinancialTransactions(array $value) { - $this->setParameter('financial_transactions',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php deleted file mode 100644 index 9eac3cfabc2d..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php +++ /dev/null @@ -1,22 +0,0 @@ -setParameter('id',$value); - } - public function setAmount($value) { - $this->setParameter('amount',$value); - } - public function setComment(string $value) { - $this->setParameter('comment',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php deleted file mode 100644 index a0c54fe65ca9..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php +++ /dev/null @@ -1,60 +0,0 @@ -setParameter('id',$value); - } - public function setCustomIdentifier(string $value) { - $this->setParameter('custom_identifier',$value); - } - public function setName(string $value) { - $this->setParameter('name',$value); - } - public function setEmail(string $value) { - $this->setParameter('email',$value); - } - public function setCustomerType(string $value) { - $this->setParameter('customer_type',$value); - } - public function setHomePhone(string $value) { - $this->setParameter('home_phone',$value); - } - public function setPhone(string $value) { - $this->setParameter('phone',$value); - } - public function setBankName(string $value) { - $this->setParameter('bank_name',$value); - } - public function setInstitutionNumber(string $value = '') { - $this->setParameter('institution_number',$value); - } - public function setTransitNumber(string $value = '') { - $this->setParameter('transit_number',$value); - } - public function setBankAccountType(string $value) { - $this->setParameter('bank_account_type',$value); - } - public function setAuthorizationType(string $value = '') { - $this->setParameter('authorization_type',$value); - } - public function setRoutingNumber(string $value = '') { - $this->setParameter('routing_number',$value); - } - public function setAccountNumber(string $value) { - $this->setParameter('account_number',$value); - } - public function setAddress(array $value) { - $this->setParameter('address',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php deleted file mode 100644 index d590cb618526..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php +++ /dev/null @@ -1,19 +0,0 @@ -setParameter('custom_identifier',$value); - } - -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php deleted file mode 100644 index 80e28a7f5083..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php +++ /dev/null @@ -1,31 +0,0 @@ -setParameter('customer_id',$value); - } - public function setProcessDate(string $value) { - $this->setParameter('process_date',$value); - } - public function setFrequency(string $value) { - $this->setParameter('frequency',$value); - } - public function setInstallments(int $value) { - $this->setParameter('installments',$value); - } - public function setComment(string $value) { - $this->setParameter('comment',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php deleted file mode 100644 index fd5111dc9a74..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php +++ /dev/null @@ -1,16 +0,0 @@ -setParameter('custom_identifier',$value); - } - -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php deleted file mode 100644 index afd4596bc9b6..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php +++ /dev/null @@ -1,24 +0,0 @@ -setParameter('id',$value); - } - public function setAmount($value) { - $this->setParameter('amount',$value); - } - public function setComment(string $value) { - $this->setParameter('comment',$value); - } - } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php deleted file mode 100644 index cfbcf0095b24..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -code = $code; - $this->message = $message; - } - - public function getData() { - return $this->getParameters(); - } - - public function getCode() { - return (int) $this->code; - } - - public function isSuccessful() { - return $this->code < 300; - } - - public function getMessage() { - return $this->message; - } - - protected function getParameters() { - return $this->data; - } - - public function getParameter(string $key) { - return $this->getParameters()[$key]; - } -} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php deleted file mode 100644 index 080eaab504b1..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -required), array_filter($this->getParameters()) ); - if(!empty($required)) throw new ValidationException("Could not validate " . implode(",", array_keys($required)) ); - - return true; - } - - public function __get($key) { - return array_key_exists($key, $this->attributes) ? $this->getParameter($key) : null; - } - - public function __set($key, $value) { - if(array_key_exists($key, $this->attributes)) $this->setParameter($key, $value); - } - - public function __toString() : string { - return json_encode($this); - } - - public function toString() : string { - return $this->__toString(); - } - - public function __toArray() : array { - return $this->getParameters(); - } - - - public function toArray() : array { - return $this->__toArray(); - } - - public function initialize(array $params = []) { - $this->parameters = new ParameterBag; - $parameters = array_merge($this->defaults, $params); - if ($parameters) { - foreach ($this->attributes as $param => $type) { - $value = @$parameters[$param]; - if($value){ - settype($value, $type); - $this->setParameter($param, $value); - } - } - } - - return $this; - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php deleted file mode 100644 index 8064662068c4..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php +++ /dev/null @@ -1,24 +0,0 @@ - "string" - ]; - protected $required = ['id']; - protected $defaults = ['id' => 0 ]; - - public function __construct($parameters = array()) { - $this->initialize($parameters); - } - - public function jsonSerialize() : array { - return array_intersect_key($this->toArray(), array_flip($this->required) ); - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php deleted file mode 100644 index 0fd67aea9441..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php +++ /dev/null @@ -1,94 +0,0 @@ - "string", - "custom_identifier" => "string", - "name" => "string", - "email" => "string", - "customer_type" => "string", - "home_phone" => "string", - "phone" => "string", - "bank_name" => "string", - "institution_number" => "string", - "transit_number" => "string", - "bank_account_type" => "string", - "authorization_type" => "string", - "routing_number" => "string", - "account_number" => "string", - "address" => "object", - "transaction_schedules" => "array", - "financial_transactions" => "array", - "active" => "bool" - ]; - - protected $defaults = ["active" => false,"customer_type" =>'Business',"bank_account_type" =>'Savings',"authorization_type" =>'Online',]; - protected $required = ["name","email","customer_type","home_phone","phone","bank_name","institution_number","transit_number","bank_account_type","authorization_type","routing_number","account_number","address",'custom_identifier']; - - public function validate() : bool { - try { - $country = $this->address->country; - if(!self::isValidCountry($country)) throw new \Exception("Invalid country!"); - - $this->required = array_diff($this->required, Country::isAmerican($country) ? ["institution_number", "transit_number"] : ["bank_account_type", "routing_number"]); - parent::validate(); - if(Country::isCanadian($country) ) { - if(!self::isValidTransitNumber($this->getParameter('transit_number'))) throw new \Exception("Invalid transit number!"); - if(!self::isValidInstitutionNumber($this->getParameter('institution_number'))) throw new \Exception("Invalid institution number!"); - } - if(!self::isValidCustomerType($this->getParameter('customer_type'))) throw new \Exception("Invalid customer type!"); - if(!self::isValidBankAccountType($this->getParameter('bank_account_type'))) throw new \Exception("Invalid bank account type!"); - if(!self::isValidAuthorizationType($this->getParameter('authorization_type'))) throw new \Exception("Invalid authorization type!"); - } catch (\Throwable $th) { - throw new ValidationException($th->getMessage()); - } - - return true; - } - - public static function isValidCountry(string $country ) : bool { - return Country::isValidCountryCode($country) || Country::isValidCountryName($country); - } - - public static function isValidTransitNumber(string $value ) : bool { - return strlen($value) == 5; - } - - public static function isValidInstitutionNumber(string $value ) : bool { - return strlen($value) == 3; - } - - public static function isValidCustomerType(string $value ) : bool { - return CustomerType::isValid($value); - } - - public static function isValidBankAccountType(string $value ) : bool { - return BankAccountType::isValid($value); - } - - public static function isValidAuthorizationType(string $value ) : bool { - return AuthorizationType::isValid($value); - } - - public function toArray() : array { - return [ 'address' => (array) $this->getParameter('address') ] + parent::toArray(); - } - - public function jsonSerialize() : array { - $address = (array) $this->getParameter('address'); - unset($address['country']); - - return compact('address') + parent::jsonSerialize(); - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php deleted file mode 100644 index c2e51d50b135..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php +++ /dev/null @@ -1,16 +0,0 @@ - "string", - "amount" => "float", - "comment" => "string", - "created_at" => "date", - "financial_transactions" => "array", - "frequency" => "string", - "installments" => "integer", - "next_process_date" => "date", - "process_date" => "date", - "updated_at" => "date", - "customer_id" => "string", - "custom_identifier" => "string", - ]; - - public const DATE_FORMAT = 'F j, Y'; - - protected $defaults = ["amount" =>0.00,"comment" =>' ',"financial_transactions" =>0,"frequency" =>'Once',"installments" =>1]; - - protected $required = ["amount","comment","frequency","installments","process_date"]; - - public function validate() : bool { - try { - parent::validate(); - if(!self::isValidDate($this->process_date)) throw new \Exception("Could not validate date "); - if(!self::isValidFrequency($this->frequency)) throw new \Exception("Invalid frequency"); - if(is_null($this->customer_id) && is_null($this->custom_identifier)) throw new \Exception("customer id or custom identifier is invalid"); - } catch (\Throwable $th) { - throw new ValidationException($th->getMessage()); - } - - return true; - } - - public function jsonSerialize() : array { - return ['customer_id' => $this->getParameter('customer_id'), 'custom_identifier' => $this->getParameter('custom_identifier') ] + parent::jsonSerialize() ; - } - - public function __toArray() : array { - return parent::__toArray() ; - } - - public function initialize(array $params = [] ) { - $o_params = array_intersect_key( - $params = array_intersect_key($params, $this->attributes), - ($attr = array_filter($this->attributes, fn($p) => $p != "date")) - ); - parent::initialize($o_params); - $d_params = array_diff_key($params, $attr); - array_walk($d_params, function($v,$k) { - $this->setParameter($k, self::formatDate( $v) ); - }, ); - - return $this; - } - - public static function isValidDate($date) : bool { - $d = DateTime::createFromFormat(self::DATE_FORMAT, $date); - // Check if the date is valid and matches the format - return $d && $d->format(self::DATE_FORMAT) === $date; - } - - public static function isValidFrequency($value) : bool { - return Frequency::isValid($value); - } - - protected static function formatDate($date) : string { - $d = new DateTime($date); - return $d->format(self::DATE_FORMAT); - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php deleted file mode 100644 index 119ac03999cb..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php +++ /dev/null @@ -1,23 +0,0 @@ - "int", - "comment" => "string", - ]; - - public const DATE_FORMAT = 'Y-m-d H:i:s'; - - private $_is_error = false; - - protected $defaults = ["amount" =>0,"comment" =>'0',]; - - protected $required = ["amount","comment",]; -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php deleted file mode 100644 index 749ae2f6b967..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php +++ /dev/null @@ -1,24 +0,0 @@ - "int", - "amount" => "int", - "comment" => "string", - ]; - - public const DATE_FORMAT = 'Y-m-d H:i:s'; - - private $_is_error = false; - - protected $defaults = ["amount" =>0,"comment" =>'0',]; - - protected $required = ["amount","comment",]; -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php deleted file mode 100644 index 1c5952b112ef..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php +++ /dev/null @@ -1,53 +0,0 @@ - "string", - "address_2" => "string", - "city" => "string", - "id" => "int", - "postal_code" => "string", - "province_code" => "string", - "country" => "string" - ]; - - protected $required = ["address_1","address_2","city","postal_code","province_code",]; - - public function jsonSerialize() { - return array_intersect_key($this->getParameters(), array_flip($this->required)); - } - - public function getCountry() : string { - return $this->getParameter('country'); - } - - public function initialize(array $parameters) { - foreach($this->attributes as $param => $type) { - $value = @$parameters[$param] ; - settype($value, $type); - $value = $value ?? null; - $this->parameters->set($param, $value); - } - } - - public function __toArray() : array { - return $this->getParameters(); - } - - public function __toString() : string { - return $this->getFullAddress(); - } - - public function getFullAddress() :string { - $full_address = $this->getParameters(); - extract($full_address); - - return "$address_1 $address_2, $city, $postal_code $province_code, $country"; - } -} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php deleted file mode 100644 index 39dcebfa342f..000000000000 --- a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php +++ /dev/null @@ -1,28 +0,0 @@ - BankTransfer::class, - //GatewayType::BACS => Bacs::class, GatewayType::ACSS => Acss::class, - // GatewayType::DIRECT_DEBIT => DirectDebit::class ]; public function init(): self @@ -115,14 +104,15 @@ class RotessaPaymentDriver extends BaseDriver public function importCustomers() { try { - $result = $this->gatewayRequest('get','customers',[]); + $result = $this->gatewayRequest('get','customers',[]); //Rotessa customers if($result->failed()) $result->throw(); - $customers = collect($result->json())->unique('email'); + $customers = collect($result->json())->unique('email'); //Rotessa customer emails $client_emails = $customers->pluck('email')->all(); + $company_id = $this->company_gateway->company->id; // get existing customers $client_contacts = ClientContact::where('company_id', $company_id) @@ -138,9 +128,9 @@ class RotessaPaymentDriver extends BaseDriver } ); // create payment methods - $client_contacts->each( + collect($client_contacts)->each( function($contact) { - // $result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send(); + $contact = (object)$contact; $result = $this->gatewayRequest("get","customers/{$contact->id}"); @@ -148,50 +138,24 @@ class RotessaPaymentDriver extends BaseDriver $this->client = Client::find($contact->client_id); - $customer = (new Customer($result))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] ); - $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); + $customer = array_merge($result, ['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ]); + // $customer = (new Customer($result))->additional( ['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ]); //creates a new customer in rotessa + // $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); + + $this->findOrCreateCustomer($customer); + } ); // create new clients from rotessa customers $client_emails = $client_contacts->pluck('email')->all(); + $client_contacts = $customers->filter(function ($value, $key) use ($client_emails) { return !in_array(((object) $value)->email, $client_emails); })->each( function($customer) use ($company_id) { $customer = $this->gatewayRequest("get", "customers/{$customer['id']}")->json(); - /** - { - "account_number": "11111111" - "active": true, - "address": { - "address_1": "123 Main Street", - "address_2": "Unit 4", - "city": "Birmingham", - "id": 114397, - "postal_code": "36016", - "province_code": "AL" - }, - "authorization_type": "Online", - "bank_account_type": "Checking", - "bank_name": "Scotiabank", - "created_at": "2015-02-10T23:50:45.000-06:00", - "custom_identifier": "Mikey", - "customer_type": "Personal", - "email": "mikesmith@test.com", - "financial_transactions": [], - "home_phone": "(204) 555 5555", - "id": 1, - "identifier": "Mikey", - "institution_number": "", - "name": "Mike Smith", - "phone": "(204) 555 4444", - "routing_number": "111111111", - "transaction_schedules": [], - "transit_number": "", - "updated_at": "2015-02-10T23:50:45.000-06:00" - } - */ + $settings = ClientSettings::defaults(); $settings->currency_id = $this->company_gateway->company->getSetting('currency_id'); $customer = (object)$customer; @@ -220,8 +184,7 @@ class RotessaPaymentDriver extends BaseDriver $client->contacts()->saveMany([$contact]); $contact = $client->contacts()->first(); $this->client = $client; - $customer = (new Customer((array) $customer))->additional(['id' => $customer->id, 'custom_identifier' => $customer->custom_identifier ?? $contact->id ] ); - $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); + }); } catch (\Throwable $th) { $data = [ @@ -241,6 +204,8 @@ class RotessaPaymentDriver extends BaseDriver public function findOrCreateCustomer(array $data) { + nlog($data); + $result = null; try { @@ -248,37 +213,34 @@ class RotessaPaymentDriver extends BaseDriver ->where('company_gateway_id', $this->company_gateway->id) ->where('client_id', $this->client->id) ->where('is_deleted',0) - ->orWhere(function (Builder $query) use ($data) { - $query->where('token', join(".", Arr::only($data, ['id','custom_identifier']))) - ->where('gateway_customer_reference', Arr::only($data,'id')); - }) + ->where('gateway_customer_reference', Arr::only($data,'id')) ->exists(); + if ($existing) return true; - else if(!Arr::has($data,'id')) { - // $result = $this->gateway->authorize($data)->send(); - // if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); + + if(!isset($data['id'])) { + nlog("no id, lets goo"); $result = $this->gatewayRequest('post', 'customers', $data); if($result->failed()) $result->throw(); - $customer = new Customer($result->json()); - $data = array_filter($customer->resolve()); - + $data = $result->json(); + nlog($data); } - // $payment_method_id = Arr::has($data,'address.postal_code') && ((int) $data['address']['postal_code'])? GatewayType::BANK_TRANSFER: GatewayType::ACSS; - // TODO: Check/ Validate postal code between USA vs CAN $payment_method_id = GatewayType::ACSS; + $gateway_token = $this->storeGatewayToken( [ - 'payment_meta' => $data + ['brand' => 'Bank Transfer', 'last4' => substr($data['account_number'], -4), 'type' => GatewayType::ACSS ], + 'payment_meta' => ['brand' => 'Bank Transfer', 'last4' => substr($data['account_number'], -4), 'type' => GatewayType::ACSS ], 'token' => join(".", Arr::only($data, ['id','custom_identifier'])), 'payment_method_id' => $payment_method_id , - ], ['gateway_customer_reference' => - $data['id'] - , 'routing_number' => Arr::has($data,'routing_number') ? $data['routing_number'] : $data['transit_number'] ]); + ], [ + 'gateway_customer_reference' => $data['id'], + 'routing_number' => Arr::has($data,'routing_number') ? $data['routing_number'] : $data['transit_number'] + ]); return $data['id']; diff --git a/app/Utils/TranslationHelper.php b/app/Utils/TranslationHelper.php index c80cdbeb19d2..ad0f06d7b1df 100644 --- a/app/Utils/TranslationHelper.php +++ b/app/Utils/TranslationHelper.php @@ -17,80 +17,67 @@ use Illuminate\Support\Str; class TranslationHelper { - public static function getIndustries() - { + // public static function getIndustries() + // { - /** @var \Illuminate\Support\Collection<\App\Models\Currency> */ - $industries = app('industries'); + // /** @var \Illuminate\Support\Collection<\App\Models\Currency> */ + // $industries = app('industries'); - return $industries->each(function ($industry) { - $industry->name = ctrans('texts.industry_'.$industry->name); - })->sortBy(function ($industry) { - return $industry->name; - }); - } + // return $industries->each(function ($industry) { + // $industry->name = ctrans('texts.industry_'.$industry->name); + // })->sortBy(function ($industry) { + // return $industry->name; + // }); + // } public static function getCountries() { /** @var \Illuminate\Support\Collection<\App\Models\Country> */ - $countries = app('countries'); + return app('countries'); - return $countries; - - return \App\Models\Country::all()->each(function ($country) { - $country->name = ctrans('texts.country_'.$country->name); - })->sortBy(function ($country) { - return $country->iso_3166_2; - }); } - public static function getPaymentTypes() - { + // public static function getPaymentTypes() + // { - /** @var \Illuminate\Support\Collection<\App\Models\PaymentType> */ - // $payment_types = app('payment_types'); + // /** @var \Illuminate\Support\Collection<\App\Models\PaymentType> */ + // // $payment_types = app('payment_types'); - return \App\Models\PaymentType::all()->each(function ($pType) { - $pType->name = ctrans('texts.payment_type_'.$pType->name); - })->sortBy(function ($pType) { - return $pType->name; - }); - } + // return \App\Models\PaymentType::all()->each(function ($pType) { + // $pType->name = ctrans('texts.payment_type_'.$pType->name); + // })->sortBy(function ($pType) { + // return $pType->name; + // }); + // } - public static function getLanguages() - { + // public static function getLanguages() + // { - /** @var \Illuminate\Support\Collection<\App\Models\Language> */ - // $languages = app('languages'); + // /** @var \Illuminate\Support\Collection<\App\Models\Language> */ + // // $languages = app('languages'); - return \App\Models\Language::all()->each(function ($lang) { - $lang->name = ctrans('texts.lang_'.$lang->name); - })->sortBy(function ($lang) { - return $lang->name; - }); - } + // return \App\Models\Language::all()->each(function ($lang) { + // $lang->name = ctrans('texts.lang_'.$lang->name); + // })->sortBy(function ($lang) { + // return $lang->name; + // }); + // } public static function getCurrencies() { /** @var \Illuminate\Support\Collection<\App\Models\Currency> */ - $currencies = app('currencies'); - return $currencies; + return app('currencies'); - return \App\Models\Currency::all()->each(function ($currency) { - $currency->name = ctrans('texts.currency_'.Str::slug($currency->name, '_')); - })->sortBy(function ($currency) { - return $currency->name; - }); } - public static function getPaymentTerms() - { - return PaymentTerm::getCompanyTerms()->map(function ($term) { - $term['name'] = ctrans('texts.payment_terms_net').' '.$term['num_days']; + // public static function getPaymentTerms() + // { + // return PaymentTerm::getCompanyTerms()->map(function ($term) { + // $term['name'] = ctrans('texts.payment_terms_net').' '.$term['num_days']; - return $term; - }); - } + // return $term; + // }); + // } } diff --git a/composer.json b/composer.json index 801fedde6e00..f33899c9ee3c 100644 --- a/composer.json +++ b/composer.json @@ -73,14 +73,12 @@ "league/csv": "^9.6", "league/flysystem-aws-s3-v3": "^3.0", "league/fractal": "^0.20.0", - "league/omnipay": "^3.1", "livewire/livewire": "^3", "microsoft/microsoft-graph": "^1.69", "mollie/mollie-api-php": "^2.36", "nelexa/zip": "^4.0", "nordigen/nordigen-php": "^1.1", "nwidart/laravel-modules": "^11.0", - "omnipay/paypal": "^3.0", "phpoffice/phpspreadsheet": "^1.29", "pragmarx/google2fa": "^8.0", "predis/predis": "^2", @@ -132,7 +130,6 @@ "app/Helpers/ClientPortal.php" ], "classmap": [ - "app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/" ] }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index e194aaba1e31..55d090faa651 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8fdb8245fbc563f8c09da161876f52a7", + "content-hash": "6eda3a2962158b87dab46711e65a8438", "packages": [ { "name": "adrienrn/php-mimetyper", @@ -1038,72 +1038,6 @@ }, "time": "2024-08-02T08:07:53+00:00" }, - { - "name": "clue/stream-filter", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/clue/stream-filter.git", - "reference": "049509fef80032cb3f051595029ab75b49a3c2f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7", - "reference": "049509fef80032cb3f051595029ab75b49a3c2f7", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "Clue\\StreamFilter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - } - ], - "description": "A simple and modern approach to stream filtering in PHP", - "homepage": "https://github.com/clue/stream-filter", - "keywords": [ - "bucket brigade", - "callback", - "filter", - "php_user_filter", - "stream", - "stream_filter_append", - "stream_filter_register" - ], - "support": { - "issues": "https://github.com/clue/stream-filter/issues", - "source": "https://github.com/clue/stream-filter/tree/v1.7.0" - }, - "funding": [ - { - "url": "https://clue.engineering/support", - "type": "custom" - }, - { - "url": "https://github.com/clue", - "type": "github" - } - ], - "time": "2023-12-20T15:40:13+00:00" - }, { "name": "composer/ca-bundle", "version": "1.5.1", @@ -2585,7 +2519,7 @@ }, { "name": "google/apiclient-services", - "version": "v0.366.0", + "version": "v0.367.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", @@ -2623,7 +2557,7 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.366.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.367.0" }, "time": "2024-07-11T01:08:44+00:00" }, @@ -6008,69 +5942,6 @@ }, "time": "2022-04-15T14:02:14+00:00" }, - { - "name": "league/omnipay", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/omnipay.git", - "reference": "38f66a0cc043ed51d6edf7956d6439a2f263501f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay/zipball/38f66a0cc043ed51d6edf7956d6439a2f263501f", - "reference": "38f66a0cc043ed51d6edf7956d6439a2f263501f", - "shasum": "" - }, - "require": { - "omnipay/common": "^3.1", - "php": "^7.2|^8.0", - "php-http/discovery": "^1.14", - "php-http/guzzle7-adapter": "^1" - }, - "require-dev": { - "omnipay/tests": "^3|^4" - }, - "type": "metapackage", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Adrian Macneil", - "email": "adrian@adrianmacneil.com" - }, - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "description": "Omnipay payment processing library", - "homepage": "https://omnipay.thephpleague.com/", - "keywords": [ - "checkout", - "creditcard", - "omnipay", - "payment" - ], - "support": { - "issues": "https://github.com/thephpleague/omnipay/issues", - "source": "https://github.com/thephpleague/omnipay/tree/v3.2.1" - }, - "funding": [ - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2021-06-05T11:34:12+00:00" - }, { "name": "livewire/livewire", "version": "v3.5.4", @@ -6546,94 +6417,6 @@ }, "time": "2024-07-17T08:02:14+00:00" }, - { - "name": "moneyphp/money", - "version": "v4.5.0", - "source": { - "type": "git", - "url": "https://github.com/moneyphp/money.git", - "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/moneyphp/money/zipball/a1daa7daf159b4044e3d0c34c41fe2be5860e850", - "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "ext-filter": "*", - "ext-json": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" - }, - "require-dev": { - "cache/taggable-cache": "^1.1.0", - "doctrine/coding-standard": "^12.0", - "doctrine/instantiator": "^1.5.0 || ^2.0", - "ext-gmp": "*", - "ext-intl": "*", - "florianv/exchanger": "^2.8.1", - "florianv/swap": "^4.3.0", - "moneyphp/crypto-currencies": "^1.1.0", - "moneyphp/iso-currencies": "^3.4", - "php-http/message": "^1.16.0", - "php-http/mock-client": "^1.6.0", - "phpbench/phpbench": "^1.2.5", - "phpunit/phpunit": "^10.5.9", - "psalm/plugin-phpunit": "^0.18.4", - "psr/cache": "^1.0.1 || ^2.0 || ^3.0", - "vimeo/psalm": "~5.20.0" - }, - "suggest": { - "ext-gmp": "Calculate without integer limits", - "ext-intl": "Format Money objects with intl", - "florianv/exchanger": "Exchange rates library for PHP", - "florianv/swap": "Exchange rates library for PHP", - "psr/cache-implementation": "Used for Currency caching" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Money\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mathias Verraes", - "email": "mathias@verraes.net", - "homepage": "http://verraes.net" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - }, - { - "name": "Frederik Bosch", - "email": "f.bosch@genkgo.nl" - } - ], - "description": "PHP implementation of Fowler's Money pattern", - "homepage": "http://moneyphp.org", - "keywords": [ - "Value Object", - "money", - "vo" - ], - "support": { - "issues": "https://github.com/moneyphp/money/issues", - "source": "https://github.com/moneyphp/money/tree/v4.5.0" - }, - "time": "2024-02-15T19:47:21+00:00" - }, { "name": "monolog/monolog", "version": "3.7.0", @@ -7727,164 +7510,6 @@ ], "time": "2023-11-13T09:31:12+00:00" }, - { - "name": "omnipay/common", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/omnipay-common.git", - "reference": "2eca3823e9069e2c36b6007a090577d5584f9518" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/2eca3823e9069e2c36b6007a090577d5584f9518", - "reference": "2eca3823e9069e2c36b6007a090577d5584f9518", - "shasum": "" - }, - "require": { - "moneyphp/money": "^3.1|^4.0.3", - "php": "^7.2|^8", - "php-http/client-implementation": "^1", - "php-http/discovery": "^1.14", - "php-http/message": "^1.5", - "php-http/message-factory": "^1.1", - "symfony/http-foundation": "^2.1|^3|^4|^5|^6|^7" - }, - "require-dev": { - "http-interop/http-factory-guzzle": "^1.1", - "omnipay/tests": "^4.1", - "php-http/guzzle7-adapter": "^1", - "php-http/mock-client": "^1.6", - "squizlabs/php_codesniffer": "^3.8.1" - }, - "suggest": { - "league/omnipay": "The default Omnipay package provides a default HTTP Adapter." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Omnipay\\Common\\": "src/Common" - }, - "classmap": [ - "src/Omnipay.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Adrian Macneil", - "email": "adrian@adrianmacneil.com" - }, - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - }, - { - "name": "Jason Judge", - "email": "jason.judge@consil.co.uk" - }, - { - "name": "Del" - }, - { - "name": "Omnipay Contributors", - "homepage": "https://github.com/thephpleague/omnipay-common/contributors" - } - ], - "description": "Common components for Omnipay payment processing library", - "homepage": "https://github.com/thephpleague/omnipay-common", - "keywords": [ - "gateway", - "merchant", - "omnipay", - "pay", - "payment", - "purchase" - ], - "support": { - "issues": "https://github.com/thephpleague/omnipay-common/issues", - "source": "https://github.com/thephpleague/omnipay-common/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2024-03-08T11:56:40+00:00" - }, - { - "name": "omnipay/paypal", - "version": "v3.0.2", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/omnipay-paypal.git", - "reference": "519db61b32ff0c1e56cbec94762b970ee9674f65" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-paypal/zipball/519db61b32ff0c1e56cbec94762b970ee9674f65", - "reference": "519db61b32ff0c1e56cbec94762b970ee9674f65", - "shasum": "" - }, - "require": { - "omnipay/common": "^3" - }, - "require-dev": { - "omnipay/tests": "^3", - "phpro/grumphp": "^0.14", - "squizlabs/php_codesniffer": "^3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Omnipay\\PayPal\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Adrian Macneil", - "email": "adrian@adrianmacneil.com" - }, - { - "name": "Omnipay Contributors", - "homepage": "https://github.com/thephpleague/omnipay-paypal/contributors" - } - ], - "description": "PayPal gateway for Omnipay payment processing library", - "homepage": "https://github.com/thephpleague/omnipay-paypal", - "keywords": [ - "gateway", - "merchant", - "omnipay", - "pay", - "payment", - "paypal", - "purchase" - ], - "support": { - "issues": "https://github.com/thephpleague/omnipay-paypal/issues", - "source": "https://github.com/thephpleague/omnipay-paypal/tree/v3.0.2" - }, - "time": "2018-05-15T10:35:58+00:00" - }, { "name": "paragonie/constant_time_encoding", "version": "v2.7.0", @@ -8178,380 +7803,6 @@ }, "time": "2024-04-08T12:52:34+00:00" }, - { - "name": "php-http/discovery", - "version": "1.19.4", - "source": { - "type": "git", - "url": "https://github.com/php-http/discovery.git", - "reference": "0700efda8d7526335132360167315fdab3aeb599" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", - "reference": "0700efda8d7526335132360167315fdab3aeb599", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0|^2.0", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "nyholm/psr7": "<1.0", - "zendframework/zend-diactoros": "*" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "*", - "psr/http-factory-implementation": "*", - "psr/http-message-implementation": "*" - }, - "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "graham-campbell/phpspec-skip-example-extension": "^5.0", - "php-http/httplug": "^1.0 || ^2.0", - "php-http/message-factory": "^1.0", - "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", - "sebastian/comparator": "^3.0.5 || ^4.0.8", - "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" - }, - "type": "composer-plugin", - "extra": { - "class": "Http\\Discovery\\Composer\\Plugin", - "plugin-optional": true - }, - "autoload": { - "psr-4": { - "Http\\Discovery\\": "src/" - }, - "exclude-from-classmap": [ - "src/Composer/Plugin.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", - "homepage": "http://php-http.org", - "keywords": [ - "adapter", - "client", - "discovery", - "factory", - "http", - "message", - "psr17", - "psr7" - ], - "support": { - "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.19.4" - }, - "time": "2024-03-29T13:00:05+00:00" - }, - { - "name": "php-http/guzzle7-adapter", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/guzzle7-adapter.git", - "reference": "fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/guzzle7-adapter/zipball/fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01", - "reference": "fb075a71dbfa4847cf0c2938c4e5a9c478ef8b01", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^7.0", - "php": "^7.2 | ^8.0", - "php-http/httplug": "^2.0", - "psr/http-client": "^1.0" - }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0", - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "php-http/client-integration-tests": "^3.0", - "phpunit/phpunit": "^8.0|^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Http\\Adapter\\Guzzle7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "Guzzle 7 HTTP Adapter", - "homepage": "http://httplug.io", - "keywords": [ - "Guzzle", - "http" - ], - "support": { - "issues": "https://github.com/php-http/guzzle7-adapter/issues", - "source": "https://github.com/php-http/guzzle7-adapter/tree/1.0.0" - }, - "time": "2021-03-09T07:35:15+00:00" - }, - { - "name": "php-http/httplug", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/httplug.git", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "php-http/promise": "^1.1", - "psr/http-client": "^1.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0", - "phpspec/phpspec": "^5.1 || ^6.0 || ^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Eric GELOEN", - "email": "geloen.eric@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "HTTPlug, the HTTP client abstraction for PHP", - "homepage": "http://httplug.io", - "keywords": [ - "client", - "http" - ], - "support": { - "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.4.0" - }, - "time": "2023-04-14T15:10:03+00:00" - }, - { - "name": "php-http/message", - "version": "1.16.1", - "source": { - "type": "git", - "url": "https://github.com/php-http/message.git", - "reference": "5997f3289332c699fa2545c427826272498a2088" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", - "reference": "5997f3289332c699fa2545c427826272498a2088", - "shasum": "" - }, - "require": { - "clue/stream-filter": "^1.5", - "php": "^7.2 || ^8.0", - "psr/http-message": "^1.1 || ^2.0" - }, - "provide": { - "php-http/message-factory-implementation": "1.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.6", - "ext-zlib": "*", - "guzzlehttp/psr7": "^1.0 || ^2.0", - "laminas/laminas-diactoros": "^2.0 || ^3.0", - "php-http/message-factory": "^1.0.2", - "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", - "slim/slim": "^3.0" - }, - "suggest": { - "ext-zlib": "Used with compressor/decompressor streams", - "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", - "laminas/laminas-diactoros": "Used with Diactoros Factories", - "slim/slim": "Used with Slim Framework PSR-7 implementation" - }, - "type": "library", - "autoload": { - "files": [ - "src/filters.php" - ], - "psr-4": { - "Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "HTTP Message related tools", - "homepage": "http://php-http.org", - "keywords": [ - "http", - "message", - "psr-7" - ], - "support": { - "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.16.1" - }, - "time": "2024-03-07T13:22:09+00:00" - }, - { - "name": "php-http/message-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/message-factory.git", - "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/message-factory/zipball/4d8778e1c7d405cbb471574821c1ff5b68cc8f57", - "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Factory interfaces for PSR-7 HTTP Message", - "homepage": "http://php-http.org", - "keywords": [ - "factory", - "http", - "message", - "stream", - "uri" - ], - "support": { - "issues": "https://github.com/php-http/message-factory/issues", - "source": "https://github.com/php-http/message-factory/tree/1.1.0" - }, - "abandoned": "psr/http-factory", - "time": "2023-04-14T14:16:17+00:00" - }, - { - "name": "php-http/promise", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/php-http/promise.git", - "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83", - "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", - "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Joel Wurtz", - "email": "joel.wurtz@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Promise used for asynchronous HTTP requests", - "homepage": "http://httplug.io", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.3.1" - }, - "time": "2024-03-15T13:55:21+00:00" - }, { "name": "php-jsonpointer/php-jsonpointer", "version": "v3.0.2", diff --git a/resources/views/billing-portal/v3/authentication/register-form.blade.php b/resources/views/billing-portal/v3/authentication/register-form.blade.php index 83230c043bd8..fcead1bf59df 100644 --- a/resources/views/billing-portal/v3/authentication/register-form.blade.php +++ b/resources/views/billing-portal/v3/authentication/register-form.blade.php @@ -47,7 +47,7 @@ @foreach(App\Utils\TranslationHelper::getCurrencies() as $currency) @endforeach diff --git a/resources/views/portal/ninja2020/auth/register.blade.php b/resources/views/portal/ninja2020/auth/register.blade.php index d0f9d4093b1e..7418b1f0b087 100644 --- a/resources/views/portal/ninja2020/auth/register.blade.php +++ b/resources/views/portal/ninja2020/auth/register.blade.php @@ -70,7 +70,7 @@ @foreach(App\Utils\TranslationHelper::getCurrencies() as $currency) @endforeach diff --git a/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/pay.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/pay.blade.php index af0158e0716d..f614ca0e30aa 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/pay.blade.php @@ -24,8 +24,8 @@ - {{ App\Models\GatewayType::getAlias($token->gateway_type_id) }} ({{ $token->meta->brand }}) -   {{ ctrans('texts.account_number') }}#: {{ $token->meta->account_number }} + {{ App\Models\GatewayType::getAlias($token->gateway_type_id) }} ({{ $token->meta->brand ?? 'Bank Transfer' }}) +   {{ ctrans('texts.account_number') }}#: {{ $token->meta?->last4 ?? '' }}
    @endforeach diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/account.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/account.blade.php index e994cc64fcc1..6f6fa93e9742 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/account.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/account.blade.php @@ -13,6 +13,10 @@
    + + @error('bank_name') +

    {{ $message }}

    + @enderror
    @@ -22,6 +26,9 @@
    + @error('account_number') +

    {{ $message }}

    + @enderror
    diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php index ef19c8f8b765..7f95a7455a14 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/address.blade.php @@ -14,6 +14,9 @@
    + @error('address_1') +

    {{ $message }}

    + @enderror
    @@ -23,6 +26,9 @@
    + @error('address_2') +

    {{ $message }}

    + @enderror
    @@ -32,6 +38,9 @@
    + @error('city') +

    {{ $message }}

    + @enderror
    @@ -41,6 +50,9 @@
    + @error('postal_code') +

    {{ $message }}

    + @enderror
    @@ -56,6 +68,10 @@
    @endif + + @error('country') +

    {{ $message }}

    + @enderror diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/banks/CA/bank.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/banks/CA/bank.blade.php index 6ad256c3e6a3..3ea417b4672f 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/banks/CA/bank.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/banks/CA/bank.blade.php @@ -4,6 +4,9 @@
    + @error('transit_number') +

    {{ $message }}

    + @enderror
    @@ -13,5 +16,8 @@
    + @error('institution_number') +

    {{ $message }}

    + @enderror
    diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/banks/US/bank.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/banks/US/bank.blade.php index da8b7f45e6d7..7bdd6f7e7a86 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/banks/US/bank.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/banks/US/bank.blade.php @@ -4,6 +4,9 @@
    + @error('routing_number') +

    {{ $message }}

    + @enderror
    @@ -16,10 +19,16 @@
    + @error('bank_account_type') +

    {{ $message }}

    + @enderror
    + @error('bank_account_type') + ed-500 text-sm mt-1">{{ $message }}

    + @enderror
    diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/contact.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/contact.blade.php index ce0655938b8a..b50c00e1137c 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/contact.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/contact.blade.php @@ -14,6 +14,9 @@
    + @error('name') +

    {{ $message }}

    + @enderror
    @@ -23,6 +26,9 @@
    + @error('email') +

    {{ $message }}

    + @enderror
    @@ -32,6 +38,9 @@
    + @error('home_phone') +

    {{ $message }}

    + @enderror
    @@ -41,6 +50,9 @@
    + @error('phone') +

    {{ $message }}

    + @enderror
    @@ -59,6 +71,9 @@ + @error('customer_type') +

    {{ $message }}

    + @enderror diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/CA.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/CA.blade.php index 248ce5b5c316..070931b3eeba 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/CA.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/CA.blade.php @@ -8,5 +8,9 @@ @endforeach + + @error('province_code') +

    {{ $message }}

    + @enderror diff --git a/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/US.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/US.blade.php index b47e8694d339..f2f4f86e095a 100644 --- a/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/US.blade.php +++ b/resources/views/portal/ninja2020/gateways/rotessa/components/dropdowns/country/US.blade.php @@ -8,5 +8,8 @@ @endforeach + @error('province_code') +

    {{ $message }}

    + @enderror From b81eb577440ebcacb517a78227b65c54b200daa3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 14:02:58 +1000 Subject: [PATCH 21/30] Updates / copyright --- app/DataProviders/CAProvinces.php | 9 +++++++++ app/Http/Middleware/ContactRegister.php | 2 +- .../Components/Rotessa/AccountComponent.php | 9 +++++++++ .../Components/Rotessa/AddressComponent.php | 9 +++++++++ .../Components/Rotessa/ContactComponent.php | 9 +++++++++ app/Http/ViewComposers/RotessaComposer.php | 10 +++++++++- app/Providers/ComposerServiceProvider.php | 1 - 7 files changed, 46 insertions(+), 3 deletions(-) diff --git a/app/DataProviders/CAProvinces.php b/app/DataProviders/CAProvinces.php index 251f6e7c9262..6e19b1d74fa1 100644 --- a/app/DataProviders/CAProvinces.php +++ b/app/DataProviders/CAProvinces.php @@ -1,4 +1,13 @@ route()->parameter('company_key') && Ninja::isSelfHost()) { - $company = Account::query()->first()->default_company; + $company = Account::query()->first()->default_company ?? Account::query()->first()->companies->first(); if (! $company->client_can_register) { abort(400, 'Registration disabled'); diff --git a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php index c7702b4e66a3..61b7538c8cf0 100644 --- a/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php +++ b/app/Http/ViewComposers/Components/Rotessa/AccountComponent.php @@ -1,4 +1,13 @@ with('states', $states); }); -// CAProvinces View Composer View::composer(['*.rotessa.components.address','*.rotessa.components.banks.CA.bank','*.rotessa.components.dropdowns.country.CA'], function ($view) { $provinces = CAProvinces::get(); $view->with('provinces', $provinces); diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index 9d8d5a94b0bc..ea8b773ee820 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -33,7 +33,6 @@ class ComposerServiceProvider extends ServiceProvider $view->with('states', $states); }); - // CAProvinces View Composer view()->composer(['*.rotessa.components.address','*.rotessa.components.banks.CA.bank','*.rotessa.components.dropdowns.country.CA'], function ($view) { $provinces = CAProvinces::get(); $view->with('provinces', $provinces); From 08f9443c820e724995fceb5086fc10079eb6101e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 14:04:05 +1000 Subject: [PATCH 22/30] Static analysis --- app/PaymentDrivers/Rotessa/PaymentMethod.php | 2 +- app/PaymentDrivers/RotessaPaymentDriver.php | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php index 9ac26feae87d..3e617f76f963 100755 --- a/app/PaymentDrivers/Rotessa/PaymentMethod.php +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -163,7 +163,7 @@ class PaymentMethod implements MethodInterface return $this->processPendingPayment($response['id'], (float) $response['amount'], PaymentType::ACSS , $customer->token); } catch(\Throwable $e) { - $this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) ); + $this->processUnsuccessfulPayment( new \Exception($e->getMessage(), (int) $e->getCode()) ); } } diff --git a/app/PaymentDrivers/RotessaPaymentDriver.php b/app/PaymentDrivers/RotessaPaymentDriver.php index 26df1ee36e7f..040a8c65e935 100644 --- a/app/PaymentDrivers/RotessaPaymentDriver.php +++ b/app/PaymentDrivers/RotessaPaymentDriver.php @@ -136,11 +136,9 @@ class RotessaPaymentDriver extends BaseDriver $result = $this->gatewayRequest("get","customers/{$contact->id}"); $result = $result->json(); - $this->client = Client::find($contact->client_id); + $this->client = Client::query()->find($contact->client_id); $customer = array_merge($result, ['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ]); - // $customer = (new Customer($result))->additional( ['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ]); //creates a new customer in rotessa - // $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); $this->findOrCreateCustomer($customer); From 02c85e9330478b2fa30a3ef51f94047cbca3b6a0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 15:04:22 +1000 Subject: [PATCH 23/30] Improved error handling with paypal --- .../gateways/paypal/ppcp/card.blade.php | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php index 0171c295ba2c..2ba326b2dcb7 100644 --- a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php +++ b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php @@ -15,8 +15,8 @@ @endphp @section('gateway_head') @@ -171,8 +171,18 @@ document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`; document.getElementById('errors').hidden = false; + + document.getElementById('pay-now').disabled = false; + document.querySelector('#pay-now > svg').classList.add('hidden'); + document.querySelector('#pay-now > span').classList.remove('hidden'); + }); + }, + onError: function(error) { + + throw new Error(error); + }, onCancel: function() { @@ -231,14 +241,12 @@ cardField.submit().then(() => { }).catch((error) => { - - console.log(error); let msg; if(!['INVALID_NUMBER','INVALID_CVV','INVALID_EXPIRY'].includes(error.message)) { - const errorM = parseError(error.message); + const errorM = parseError(error); msg = handle422Error(errorM); } @@ -255,7 +263,7 @@ else if(error.message == 'INVALID_EXPIRY') { document.getElementById('errors').textContent = "{{ ctrans('texts.invalid_cvv') }}"; } - else if(msg.description){ + else if(msg?.description){ document.getElementById('errors').textContent = msg?.description; } document.getElementById('errors').hidden = false; @@ -270,7 +278,7 @@ } function handle422Error(errorData) { - const errorDetails = errorData.details || []; + const errorDetails = errorData?.details || []; const detail = errorDetails[0]; return detail; } From a8362bf5b009395bb611ec04e7a1998cd0c0af3c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 15:08:33 +1000 Subject: [PATCH 24/30] Updated translations --- lang/en/texts.php | 3 +- lang/nl/texts.php | 1425 +++++++++++++++++++++++---------------------- 2 files changed, 719 insertions(+), 709 deletions(-) diff --git a/lang/en/texts.php b/lang/en/texts.php index eeab2f9c1673..8a0abf6d6bd4 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5309,7 +5309,8 @@ $lang = array( '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' + 'process_date' => 'Process Date', + 'forever_free' => 'Forever Free', ); return $lang; diff --git a/lang/nl/texts.php b/lang/nl/texts.php index 37700fdabaa6..b3fdcb5f44da 100644 --- a/lang/nl/texts.php +++ b/lang/nl/texts.php @@ -2,14 +2,14 @@ $lang = array( 'organization' => 'Organisatie', - 'name' => 'Bedrijfsnaam', + 'name' => 'Naam', 'website' => 'Website', 'work_phone' => 'Telefoonnummer', 'address' => 'Adres', 'address1' => 'Straat', - 'address2' => 'Appartement / Busnr.', + 'address2' => 'Appartement/busnr.', 'city' => 'Stad', - 'state' => 'Staat/Provincie', + 'state' => 'Staat/provincie', 'postal_code' => 'Postcode', 'country_id' => 'Land', 'contacts' => 'Contactpersonen', @@ -21,7 +21,7 @@ $lang = array( 'payment_terms' => 'Betalingsvoorwaarden', 'currency_id' => 'Valuta', 'size_id' => 'Bedrijfsgrootte', - 'industry_id' => 'Industrie/Branche', + 'industry_id' => 'Sector/branche', 'private_notes' => 'Privénotities', 'invoice' => 'Factuur', 'client' => 'Klant', @@ -46,7 +46,7 @@ $lang = array( 'balance_due' => 'Te voldoen', 'invoice_design_id' => 'Ontwerp', 'terms' => 'Voorwaarden', - 'your_invoice' => 'Jouw factuur', + 'your_invoice' => 'Uw factuur', 'remove_contact' => 'Contact verwijderen', 'add_contact' => 'Contact toevoegen', 'create_new_client' => 'Klant aanmaken', @@ -75,7 +75,7 @@ $lang = array( 'clients' => 'Klanten', 'invoices' => 'Facturen', 'payments' => 'Betalingen', - 'credits' => 'Kredieten', + 'credits' => 'Creditfacturen', 'history' => 'Geschiedenis', 'search' => 'Zoeken', 'sign_up' => 'Registreren', @@ -95,7 +95,7 @@ $lang = array( 'provide_email' => 'Geef een geldig e-mailadres op', 'powered_by' => 'Factuur gemaakt met', 'no_items' => 'Geen artikelen', - 'recurring_invoices' => 'Herhalende facturen', + 'recurring_invoices' => 'Terugkerende facturen', 'recurring_help' => '

    Stuur klanten automatisch wekelijks, twee keer per maand, maandelijks, per kwartaal of jaarlijks dezelfde facturen.

    Gebruik :MONTH, :QUARTER of :YEAR voor dynamische datums. Basis wiskunde werkt ook, bijvoorbeeld :MONTH-1.

    Voorbeelden van dynamische factuur variabelen:

    @@ -104,10 +104,10 @@ $lang = array(
  • "Jaarlijks abonnement :YEAR+1" >> "Jaarlijks abonnement 2015"
  • "Aanbetaling voor :QUARTER+1" >> "Aanbetaling voor Q2"
', - 'recurring_quotes' => 'Herhalende offertes', + 'recurring_quotes' => 'Terugkerende offertes', 'in_total_revenue' => 'totale inkomsten', - 'billed_client' => 'Gefactureerde klant', - 'billed_clients' => 'Gefactureerde klanten', + 'billed_client' => 'gefactureerde klant', + 'billed_clients' => 'gefactureerde klanten', 'active_client' => 'Actieve klant', 'active_clients' => 'Actieve klanten', 'invoices_past_due' => 'Vervallen facturen', @@ -159,7 +159,7 @@ $lang = array( 'date' => 'Datum', 'message' => 'Bericht', 'adjustment' => 'Aanpassing', - 'are_you_sure' => 'Weet je het zeker?', + 'are_you_sure' => 'Weet u het zeker?', 'payment_type_id' => 'Betalingswijze', 'amount' => 'Bedrag', 'work_email' => 'E-mailadres', @@ -171,8 +171,8 @@ $lang = array( 'localization' => 'Lokalisatie', 'remove_logo' => 'Logo verwijderen', 'logo_help' => 'Ondersteund: JPEG, GIF en PNG', - 'payment_gateway' => 'Betalingsgateway', - 'gateway_id' => 'Gateway', + 'payment_gateway' => 'Betaalprovider', + 'gateway_id' => 'Betaalprovider', 'email_notifications' => 'E-mailmeldingen', 'email_viewed' => 'E-mail mij wanneer een factuur is bekeken', 'email_paid' => 'E-mail mij wanneer een factuur is betaald', @@ -199,7 +199,7 @@ $lang = array( 'removed_logo' => 'Het logo is verwijderd', 'sent_message' => 'Het bericht is verzonden', 'invoice_error' => 'Selecteer een klant en verbeter eventuele fouten', - 'limit_clients' => 'You\'ve hit the :count client limit on Free accounts. Congrats on your success!', + 'limit_clients' => 'U heeft de klantlimiet van :count voor gratis accounts bereikt. Gefeliciteerd met uw succes!', 'payment_error' => 'Er was een fout bij het verwerken van de betaling. Probeer het later opnieuw.', 'registration_required' => 'Registratie verplicht', 'confirmation_required' => 'Bevestig het e-mailadres, :link om de bevestigingsmail opnieuw te ontvangen.', @@ -224,11 +224,11 @@ $lang = array( 'deleted_payment' => 'De betaling is verwijderd', 'deleted_payments' => 'Succesvol :count betalingen verwijderd', 'applied_payment' => 'De betaling is toegepast', - 'created_credit' => 'De creditnota is aangemaakt', - 'archived_credit' => 'De creditnota is gearchiveerd', - 'archived_credits' => 'Succesvol :count creditnota\'s gearchiveerd', - 'deleted_credit' => 'De creditnota is verwijderd', - 'deleted_credits' => 'Succesvol :count creditnota\'s verwijderd', + 'created_credit' => 'De creditfactuur is aangemaakt', + 'archived_credit' => 'De creditfactuur is gearchiveerd', + 'archived_credits' => 'Succesvol :count creditfacturen gearchiveerd', + 'deleted_credit' => 'De creditfactuur is verwijderd', + 'deleted_credits' => 'Succesvol :count creditfacturen verwijderd', 'imported_file' => 'Het bestand is geïmporteerd', 'updated_vendor' => 'De leverancier is gewijzigd', 'created_vendor' => 'De leverancier is aangemaakt', @@ -268,10 +268,10 @@ $lang = array( 'email_taken' => 'Dit e-mailadres is al geregistreerd', 'working' => 'Werkend', 'success' => 'Succes', - 'success_message' => 'Je bent nu geregistreerd! Klik op de link in de zojuist ontvangen bevestigingsmail om je e-mailadres te bevestigen.', + 'success_message' => 'U bent nu geregistreerd! Klik op de link in de zojuist ontvangen bevestigingsmail om uw e-mailadres te bevestigen.', 'erase_data' => 'Dit account is niet geregistreerd, de opgegeven data zal permanent worden verwijderd.', 'password' => 'Wachtwoord', - 'pro_plan_product' => 'Pro Plan', + 'pro_plan_product' => 'Pro-abonnement', 'unsaved_changes' => 'Er zijn wijzigingen aangebracht die nog niet zijn opgeslagen', 'custom_fields' => 'Aangepaste velden', 'company_fields' => 'Bedrijfsvelden', @@ -294,15 +294,15 @@ $lang = array( 'updated_product' => 'Het product is gewijzigd', 'created_product' => 'Het product is aangemaakt', 'archived_product' => 'Het product is gearchiveerd', - 'pro_plan_custom_fields' => ':link om aangepaste velden in te schakelen door het Pro Plan te nemen', + 'pro_plan_custom_fields' => ':link om aangepaste velden in te schakelen door het Pro-abonnement te nemen', 'advanced_settings' => 'Geavanceerde instellingen', - 'pro_plan_advanced_settings' => ':link om de geavanceerde instellingen te activeren door het Pro Plan te nemen', + 'pro_plan_advanced_settings' => ':link om de geavanceerde instellingen te activeren door het Pro-abonnement te nemen', 'invoice_design' => 'Factuurontwerp', 'specify_colors' => 'Kies kleuren', 'specify_colors_label' => 'Kies de kleuren die in de factuur gebruikt worden', 'chart_builder' => 'Grafiekbouwer', 'ninja_email_footer' => 'Gemaakt door :site | Aanmaken. Verzenden. Betaald krijgen.', - 'go_pro' => 'Go Pro', + 'go_pro' => 'Ga voor het Pro-abonnement', 'quote' => 'Offerte', 'quotes' => 'Offertes', 'quote_number' => 'Offertenummer', @@ -344,7 +344,7 @@ $lang = array( 'invoice_fields' => 'Factuurvelden', 'invoice_options' => 'Factuuropties', 'hide_paid_to_date' => 'Verberg "Reeds betaald"', - 'hide_paid_to_date_help' => 'Toon alleen het "Reeds betaald" gebied op je facturen als er een betaling gemaakt is.', + 'hide_paid_to_date_help' => 'Toon alleen het "Reeds betaald" gebied op uw facturen als er een betaling gemaakt is.', 'charge_taxes' => 'BTW berekenen', 'user_management' => 'Gebruikersbeheer', 'add_user' => 'Nieuwe gebruiker', @@ -381,33 +381,33 @@ $lang = array( 'mark_sent' => 'Markeer als verzonden', 'more_designs' => 'Meer ontwerpen', 'more_designs_title' => 'Aanvullende factuurontwerpen', - 'more_designs_cloud_header' => 'Neem Pro Plan voor meer factuurontwerpen', + 'more_designs_cloud_header' => 'Neem het Pro-abonnement voor meer factuurontwerpen', 'more_designs_cloud_text' => '', 'more_designs_self_host_text' => '', 'buy' => 'Kopen', 'bought_designs' => 'Aanvullende factuurontwerpen zijn toegevoegd', 'sent' => 'Verzonden', 'vat_number' => 'BTW-nummer', - 'payment_title' => 'Geef het betalingsadres en de creditcardgegevens op', + 'payment_title' => 'Geef het factuuradres en de creditcardgegevens op', 'payment_cvv' => '*Dit is het cijfer van 3-4 tekens op de achterkant van de creditcard', - 'payment_footer1' => '*Betalingsadres moet overeenkomen met het adres dat aan uw kaart gekoppeld is.', - 'payment_footer2' => '*Klik alsjeblieft slechts één keer op "PAY NOW" - deze verwerking kan tot 1 minuut duren.', + 'payment_footer1' => '*Factuuradres moet overeenkomen met het adres dat aan uw kaart gekoppeld is.', + 'payment_footer2' => '*Klik alstublieft slechts één keer op "PAY NOW" - deze verwerking kan tot 1 minuut duren.', 'id_number' => 'KVK-nummer', 'white_label_link' => 'Whitelabel', 'white_label_header' => 'Whitelabel', - 'bought_white_label' => 'Whitelabel licentie is geactiveerd', - 'white_labeled' => 'White labeled', + 'bought_white_label' => 'Whitelabel-licentie is geactiveerd', + 'white_labeled' => 'White-labeled', 'restore' => 'Herstel', 'restore_invoice' => 'Herstel factuur', 'restore_quote' => 'Herstel offerte', 'restore_client' => 'Herstel klant', - 'restore_credit' => 'Herstel creditnota', + 'restore_credit' => 'Herstel creditfactuur', 'restore_payment' => 'Herstel betaling', 'restored_invoice' => 'De factuur is hersteld', 'restored_quote' => 'De offerte is hersteld', 'restored_client' => 'De klant is hersteld', 'restored_payment' => 'De betaling is hersteld', - 'restored_credit' => 'De creditnota is hersteld', + 'restored_credit' => 'De creditfactuur is hersteld', 'reason_for_canceling' => 'Help ons om onze site te verbeteren door ons te vertellen waarom u weggaat.', 'discount_percent' => 'Percentage', 'discount_amount' => 'Bedrag', @@ -436,7 +436,7 @@ $lang = array( 'token_billing_checkbox' => 'Sla creditcardgegevens op', 'view_in_gateway' => 'In :gateway bekijken', 'use_card_on_file' => 'Gebruik opgeslagen kaart', - 'edit_payment_details' => 'Wijzig betalingsgegevens', + 'edit_payment_details' => 'Wijzig betaalgegevens', 'token_billing' => 'Kaartgegevens opslaan', 'token_billing_secure' => 'Kaartgegevens worden veilig opgeslagen door :link', 'support' => 'Ondersteuning', @@ -447,7 +447,7 @@ $lang = array( 'billing_method' => 'Betaalmethode', 'order_overview' => 'Besteloverzicht', 'match_address' => '*Adres moet overeenkomen met adres van creditcard.', - 'click_once' => '*Klik alstublieft maar één keer; het kan een minuut duren om de betaling te verwerken.', + 'click_once' => '*Klik alstublieft slechts één keer; het kan 1 minuut duren om de betaling te verwerken.', 'invoice_footer' => 'Factuurvoettekst', 'save_as_default_footer' => 'Bewaar als standaard voettekst', 'token_management' => 'Tokenbeheer', @@ -460,12 +460,12 @@ $lang = array( 'edit_token' => 'Wijzig token', 'delete_token' => 'Verwijder token', 'token' => 'Token', - 'add_gateway' => 'Betalingsgateway toevoegen', - 'delete_gateway' => 'Betalingsgateway verwijderen', - 'edit_gateway' => 'Betalingsgateway bewerken', - 'updated_gateway' => 'De gateway is gewijzigd', - 'created_gateway' => 'De gateway is aangemaakt', - 'deleted_gateway' => 'De gateway is verwijderd', + 'add_gateway' => 'Betaalprovider toevoegen', + 'delete_gateway' => 'Betaalprovider verwijderen', + 'edit_gateway' => 'Betaalprovider bewerken', + 'updated_gateway' => 'De betaalprovider is gewijzigd', + 'created_gateway' => 'De betaalprovider is aangemaakt', + 'deleted_gateway' => 'De betaalprovider is verwijderd', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Creditcard', 'change_password' => 'Verander wachtwoord', @@ -544,7 +544,7 @@ $lang = array( 'stop' => 'Stop', 'now' => 'Nu', 'timer' => 'Timer', - 'manual' => 'Manueel', + 'manual' => 'Handmatig', 'date_and_time' => 'Datum en tijd', 'second' => 'Seconde', 'seconds' => 'Seconden', @@ -586,7 +586,7 @@ $lang = array( 'pro_plan_feature5' => 'Multi-user toegang & activeit tracking', 'pro_plan_feature6' => 'Maak offertes & Pro-forma facturen aan', 'pro_plan_feature7' => 'Pas factuur veldtitels & nummering aan', - 'pro_plan_feature8' => 'Optie om PDFs toe te voegen aan de emails naar klanten', + 'pro_plan_feature8' => 'Optie om PDFs toe te voegen aan de e-mails naar klanten', 'resume' => 'Doorgaan', 'break_duration' => 'Pauze', 'edit_details' => 'Wijzig details', @@ -663,7 +663,7 @@ $lang = array( 'status_unpaid' => 'Onbetaald', 'status_all' => 'Alles', 'show_line_item_tax' => 'BTW-tarieven per regel tonen', - 'auto_bill' => 'Automatische incasso', + 'auto_bill' => 'Automatische betaling', 'military_time' => '24-uurs klok', 'last_sent' => 'Laatst verstuurd', 'reminder_emails' => 'Herinneringsmails', @@ -702,7 +702,7 @@ $lang = array( 'verify_email' => 'Klik alstublieft op de link in de accountbevestigings-e-mail om uw e-mailadres te bevestigen.', 'basic_settings' => 'Basisinstellingen', 'pro' => 'Pro', - 'gateways' => 'Betalingsverwerkers', + 'gateways' => 'Betaalproviders', 'next_send_on' => 'Verstuur volgende: :date', 'no_longer_running' => 'Deze factuur is niet ingepland', 'general_settings' => 'Algemene instellingen', @@ -738,7 +738,7 @@ $lang = array( 'activity_7' => ':contact heeft factuur :invoice voor :client bekeken', 'activity_8' => ':user heeft factuur :invoice gearchiveerd', 'activity_9' => ':user heeft factuur :invoice verwijderd', - 'activity_10' => ':user ingevoerde betaling :payment voor :payment _bedrag op factuur :invoice voor :client', + 'activity_10' => ':user heeft betaling :payment ingevoerd voor een bedrag van:payment_amount voor factuur :invoice voor :client', 'activity_11' => ':user heeft betaling :payment bijgewerkt', 'activity_12' => ':user heeft betaling :payment gearchiveerd', 'activity_13' => ':user heeft betaling :payment verwijderd', @@ -772,11 +772,11 @@ $lang = array( 'activity_45' => ':user heeft taak :task verwijderd', 'activity_46' => ':user heeft taak :task hersteld', 'activity_47' => ':user heeft uitgave :expense bijgewerkt', - 'activity_48' => ':user heeft de gebruiker: :user aangemaakt', - 'activity_49' => ':user heeft de gebruiker: :user aangepast', - 'activity_50' => ':user heeft de gebruiker: :user gearchiveerd', - 'activity_51' => ':user heeft de gebruiker: :user verwijderd', - 'activity_52' => ':user heeft de gebruiker: :user hersteld', + 'activity_48' => ':user heeft de gebruiker :user aangemaakt', + 'activity_49' => ':user heeft de gebruiker :user aangepast', + 'activity_50' => ':user heeft de gebruiker :user gearchiveerd', + 'activity_51' => ':user heeft de gebruiker :user verwijderd', + 'activity_52' => ':user heeft de gebruiker :user hersteld', 'activity_53' => ':user heeft factuur :invoice als verstuurd gemarkeerd', 'activity_54' => ':user betaalde factuur :invoice', 'activity_55' => ':contact heeft op ticket :ticket gereageerd', @@ -788,8 +788,8 @@ $lang = array( 'default_messages' => 'Standaardberichten', 'quote_terms' => 'Offertevoorwaarden', 'default_quote_terms' => 'Standaard offertevoorwaarden', - 'default_invoice_terms' => 'Stel standaard factuurvoorwaarden in', - 'default_invoice_footer' => 'Stel standaard factuurfvoettekst in', + 'default_invoice_terms' => 'Stel standaardvoorwaarden voor factuur in', + 'default_invoice_footer' => 'Stel standaardvoettekst voor factuur in', 'quote_footer' => 'Offertevoettekst', 'free' => 'Gratis', 'quote_is_approved' => 'Akkoord', @@ -799,8 +799,8 @@ $lang = array( 'archived_token' => 'Het token is gearchiveerd', 'archive_user' => 'Archiveer gebruiker', 'archived_user' => 'De gebruiker is gearchiveerd', - 'archive_account_gateway' => 'Gateway verwijderen', - 'archived_account_gateway' => 'De betalingsverwerker is gearchiveerd', + 'archive_account_gateway' => 'Betaalprovider verwijderen', + 'archived_account_gateway' => 'De betaalprovider is gearchiveerd', 'archive_recurring_invoice' => 'Archiveer terugkerende factuur', 'archived_recurring_invoice' => 'De terugkerende factuur is gearchiveerd', 'delete_recurring_invoice' => 'Verwijder terugkerende factuur', @@ -823,7 +823,7 @@ $lang = array( 'user' => 'Gebruiker', 'country' => 'Land', 'include' => 'Voeg in', - 'logo_too_large' => 'Je logo is :size groot, voor betere PDF prestaties raden we je aan om een afbeelding kleiner dan 200KB te uploaden.', + 'logo_too_large' => 'Uw logo is :size groot, voor betere PDF-prestaties raden we u aan om een afbeelding kleiner dan 200KB te uploaden.', 'import_freshbooks' => 'Importeren van FreshBooks', 'import_data' => 'Importeer data', 'source' => 'Bron', @@ -839,12 +839,12 @@ $lang = array( 'show_archived_users' => 'Toon gearchiveerde gebruikers', 'notes' => 'Notities', 'invoice_will_create' => 'Factuur zal worden aangemaakt', - 'invoices_will_create' => 'factuur zal worden aangemaakt', - 'failed_to_import' => 'De volgende regels konden niet worden geïmporteerd, ze bestaan al of missen verplichte velden.', + 'invoices_will_create' => 'facturen zullen worden aangemaakt', + 'failed_to_import' => 'De volgende regels konden niet worden geïmporteerd, ze bestaan al of missen verplichte velden.', 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'E-mail Ontwerp', + 'email_design' => 'E-mailontwerp', 'due_by' => 'Vervaldatum :date', 'enable_email_markup' => 'Opmaak inschakelen', 'enable_email_markup_help' => 'Maak het gemakkelijker voor uw klanten om te betalen door schema.org opmaak toe te voegen aan uw e-mails.', @@ -857,7 +857,7 @@ $lang = array( 'dark' => 'Donker', 'industry_help' => 'Wordt gebruikt om een vergelijking te kunnen maken met de gemiddelden van andere bedrijven uit dezelfde sector en van dezelfde grootte.', 'subdomain_help' => 'Stel het subdomein in of toon de factuur op uw eigen website.', - 'website_help' => 'Toon de factuur in een iFrame op uw eigen website', + 'website_help' => 'Toon de factuur in een iframe op uw eigen website', 'invoice_number_help' => 'Kies een voorvoegsel of gebruik een patroon om het factuurnummer dynamisch te genereren.', 'quote_number_help' => 'Kies een voorvoegsel of gebruik een patroon om het offertenummer dynamisch te genereren.', 'custom_client_fields_helps' => 'Voeg een veld toe bij het creëren van een klant en toon het label en de waarde op de PDF.', @@ -865,13 +865,13 @@ $lang = array( 'custom_invoice_fields_helps' => 'Voeg een veld toe bij het creëren van een factuur en toon het label en de waarde op de PDF.', 'custom_invoice_charges_helps' => 'Plaatst een tekstveld op de factuur aanmaak-/bewerkpagina en verwerkt de facturatiekosten in het subtotaal.', 'token_expired' => 'De validatie token is verlopen. Probeer het opnieuw.', - 'invoice_link' => 'Factuur Link', - 'button_confirmation_message' => 'Bevestig uw email.', + 'invoice_link' => 'Factuurlink', + 'button_confirmation_message' => 'Bevestig uw e-mailadres.', 'confirm' => 'Bevestigen', 'email_preferences' => 'E-mailvoorkeuren', 'created_invoices' => 'Succesvol :count factuur(en) aangemaakt', - 'next_invoice_number' => 'Het volgende factuurnummer is :number.', - 'next_quote_number' => 'Het volgende offertenummer is :number.', + 'next_invoice_number' => 'Het eerstvolgende factuurnummer is :number.', + 'next_quote_number' => 'Het eerstvolgende offertenummer is :number.', 'days_before' => 'dagen voor de', 'days_after' => 'dagen na de', 'field_due_date' => 'vervaldatum', @@ -879,7 +879,7 @@ $lang = array( 'schedule' => 'Schema', 'email_designs' => 'E-mailontwerpen', 'assigned_when_sent' => 'Toegewezen zodra verzonden', - 'white_label_purchase_link' => 'Koop een whitelabel licentie', + 'white_label_purchase_link' => 'Koop een whitelabel-licentie', 'expense' => 'Uitgave', 'expenses' => 'Uitgaven', 'new_expense' => 'Nieuwe uitgave', @@ -935,7 +935,7 @@ $lang = array(
  • Vandaag is het vrijdag, de vervaldatum is ingesteld op de 1e vrijdag erna. De vervaldatum zal volgende week vrijdag zijn, niet vandaag.
  • ', 'due' => 'Vervaldatum', - 'next_due_on' => 'Vervaldatum volgende: :date', + 'next_due_on' => 'Eerstvolgende vervaldatum: :date', 'use_client_terms' => 'Gebruik betalingsvoorwaarden klant', 'day_of_month' => ':ordinal dag van de maand', 'last_day_of_month' => 'Laatste dag van de maand', @@ -955,7 +955,7 @@ $lang = array( 'invoice_message_button' => 'Klik op de onderstaande link om uw factuur van :amount te bekijken.', 'quote_message_button' => 'Klik op de onderstaande link om uw offerte van :amount te bekijken.', 'payment_message_button' => 'Bedankt voor uw betaling van :amount.', - 'payment_type_direct_debit' => 'Automatisch incasso', + 'payment_type_direct_debit' => 'Automatische incasso', 'bank_accounts' => 'Bankrekeningen', 'add_bank_account' => 'Bankrekening toevoegen', 'setup_account' => 'Rekening instellen', @@ -991,16 +991,16 @@ $lang = array( 'last_page' => 'laatste pagina', 'all_pages_header' => 'Toon koptekst op', 'all_pages_footer' => 'Toon footer op', - 'invoice_currency' => 'Factuur valuta', + 'invoice_currency' => 'Factuurvaluta', 'enable_https' => 'We raden u dringend aan om HTTPS te gebruiken om creditcard informatie digitaal te accepteren.', 'quote_issued_to' => 'Offerte uitgeschreven voor', 'show_currency_code' => 'Valutacode', - 'free_year_message' => 'Uw account is gratis geüpgraded naar een pro account voor één jaar.', - 'trial_message' => 'Uw account zal een gratis twee weken durende probeerversie van ons pro plan krijgen.', - 'trial_footer' => 'Uw gratis probeerversie duurt nog :count dagen, :link om direct te upgraden.', - 'trial_footer_last_day' => 'Dit is de laatste dag van uw gratis probeerversie, :link om direct te upgraden.', + 'free_year_message' => 'Uw account is gratis geüpgraded naar een Pro-abonnement voor één jaar.', + 'trial_message' => 'Uw account zal een gratis twee weken durende probeerversie van ons Pro-abonnement krijgen.', + 'trial_footer' => 'Uw gratis probeerversie duurt nog :count dagen, navigeer naar :link om direct te upgraden.', + 'trial_footer_last_day' => 'Dit is de laatste dag van uw gratis probeerversie, navigeer naar :link om direct te upgraden.', 'trial_call_to_action' => 'Start gratis probeerversie', - 'trial_success' => 'De gratis twee weken durende probeerversie van het pro plan is geactiveerd.', + 'trial_success' => 'De gratis, twee weken durende, proefperiode van het Pro-abonnement is gestart.', 'overdue' => 'Verlopen', 'white_label_text' => 'Koop een white label licentie voor één jaar voor $:price om de Invoice Ninja reclame te verwijderen van facturen en het klantenportaal.', 'user_email_footer' => 'Ga alstublieft naar :link om uw e-mail notificatie instellingen aan te passen', @@ -1010,7 +1010,7 @@ $lang = array( 'old_browser' => 'Gelieve een :link te gebruiken', 'newer_browser' => 'nieuwere browser', 'white_label_custom_css' => ':link voor $:price om eigen opmaak te gebruiken en ons project te ondersteunen.', - 'pro_plan_remove_logo' => ':link om het Invoice Ninja logo te verwijderen door het pro plan te nemen', + 'pro_plan_remove_logo' => ':link om het Invoice Ninja logo te verwijderen door het Pro-abonnement te nemen', 'pro_plan_remove_logo_link' => 'Klik hier', 'invitation_status_sent' => 'Verzonden', 'invitation_status_opened' => 'Geopend', @@ -1018,22 +1018,22 @@ $lang = array( 'email_error_inactive_client' => 'E-mails kunnen niet worden verstuurd naar inactieve klanten', 'email_error_inactive_contact' => 'E-mails kunnen niet worden verstuurd naar inactieve contactpersonen', 'email_error_inactive_invoice' => 'E-mails kunnen niet worden verstuurd naar inactieve facturen', - 'email_error_inactive_proposal' => 'Emails kunnen niet verzonden worden naar inactieve voorstellen', + 'email_error_inactive_proposal' => 'E-mails kunnen niet verzonden worden naar inactieve voorstellen', 'email_error_user_unregistered' => 'Registreer een account om e-mails te kunnen versturen', 'email_error_user_unconfirmed' => 'Bevestig uw account om e-mails te kunnen versturen', 'email_error_invalid_contact_email' => 'Ongeldig e-mailadres van contactpersoon', 'navigation' => 'Navigatie', - 'list_invoices' => 'Toon Facturen', - 'list_clients' => 'Toon Klanten', - 'list_quotes' => 'Toon Offertes', - 'list_tasks' => 'Toon Taken', - 'list_expenses' => 'Toon Uitgaven', - 'list_recurring_invoices' => 'Toon Terugkerende Facturen', - 'list_payments' => 'Toon Betalingen', - 'list_credits' => 'Toon Kredieten', + 'list_invoices' => 'Toon facturen', + 'list_clients' => 'Toon klanten', + 'list_quotes' => 'Toon offertes', + 'list_tasks' => 'Toon taken', + 'list_expenses' => 'Toon uitgaven', + 'list_recurring_invoices' => 'Toon terugkerende facturen', + 'list_payments' => 'Toon betalingen', + 'list_credits' => 'Toon kredieten', 'tax_name' => 'Belasting naam', 'report_settings' => 'Rapport instellingen', - 'new_user' => 'Nieuwe Gebruiker', + 'new_user' => 'Nieuwe gebruiker', 'new_product' => 'Nieuw product', 'new_tax_rate' => 'Nieuw BTW-tarief', 'invoiced_amount' => 'Gefactureerd bedrag', @@ -1096,18 +1096,18 @@ $lang = array( 'invoice_embed_documents' => 'Documenten invoegen', 'invoice_embed_documents_help' => 'Bijgevoegde afbeeldingen weergeven in de factuur.', 'document_email_attachment' => 'Documenten bijvoegen', - 'ubl_email_attachment' => 'Attach UBL/E-Invoice', + 'ubl_email_attachment' => 'UBL en/of e-factuur bijvoegen', 'download_documents' => 'Documenten downloaden (:size)', 'documents_from_expenses' => 'Van uitgaven:', 'dropzone_default_message' => 'Sleep bestanden hierheen of klik om te uploaden', 'dropzone_default_message_disabled' => 'Uploads uitgeschakeld', - 'dropzone_fallback_message' => 'Je browser ondersteunt het slepen van bestanden niet.', - 'dropzone_fallback_text' => 'Gebruik de onderstaande optie om je bestanden te uploaden.', + 'dropzone_fallback_message' => 'Uw browser ondersteunt het slepen van bestanden niet.', + 'dropzone_fallback_text' => 'Gebruik de onderstaande optie om uw bestanden te uploaden.', 'dropzone_file_too_big' => 'Het bestand is te groot ({{filesize}}MiB). Maximale grootte: {{maxFilesize}}MiB.', - 'dropzone_invalid_file_type' => 'Je kan geen bestanden van dit type uploaden.', + 'dropzone_invalid_file_type' => 'U kunt geen bestanden van dit type uploaden.', 'dropzone_response_error' => 'De server gaf foutcode {{statusCode}} terug.', 'dropzone_cancel_upload' => 'Upload annuleren', - 'dropzone_cancel_upload_confirmation' => 'Weet je zeker dat je deze upload wilt annuleren?', + 'dropzone_cancel_upload_confirmation' => 'Weet u zeker dat u deze upload wilt annuleren?', 'dropzone_remove_file' => 'Bestand verwijderen', 'documents' => 'Documenten', 'document_date' => 'Documentdatum', @@ -1123,7 +1123,7 @@ $lang = array( 'plan_status' => 'Status abonnement', 'plan_upgrade' => 'Upgraden', - 'plan_change' => 'Plan beheren', + 'plan_change' => 'Abonnement beheren', 'pending_change_to' => 'Veranderd naar', 'plan_changes_to' => ':plan op :date', 'plan_term_changes_to' => ':plan (:term) op :date', @@ -1137,7 +1137,7 @@ $lang = array( 'plan_free' => 'Gratis', 'plan_pro' => 'Pro', 'plan_enterprise' => 'Zakelijk', - 'plan_white_label' => 'Zelf gehost (White label)', + 'plan_white_label' => 'Zelf gehost (white-label)', 'plan_free_self_hosted' => 'Zelf gehost (Gratis)', 'plan_trial' => 'Proefabonnement', 'plan_term' => 'Duur', @@ -1152,13 +1152,13 @@ $lang = array( 'plan_started' => 'Abonnement gestart', 'plan_expires' => 'Abonnement verloopt', - 'white_label_button' => 'Whitelabel kopen', + 'white_label_button' => 'Whitelabel-licentie kopen', 'pro_plan_year_description' => 'Jaarabonnement op Invoice Ninja Pro.', 'pro_plan_month_description' => 'Maandabonnement op Invoice Ninja Pro.', - 'enterprise_plan_product' => 'Zakelijk abonnement', - 'enterprise_plan_year_description' => 'Jaarabonnement op Invoice Ninja zakelijk.', - 'enterprise_plan_month_description' => 'Maandabonnement op Invoice Ninja zakelijk.', + 'enterprise_plan_product' => 'Enterprise-abonnement', + 'enterprise_plan_year_description' => 'Jaarabonnement op Invoice Ninja Enterprise.', + 'enterprise_plan_month_description' => 'Maandabonnement op Invoice Ninja Enterprise.', 'plan_credit_product' => 'Krediet', 'plan_credit_description' => 'Krediet voor ongebruikte tijd', 'plan_pending_monthly' => 'Zal omgezet wordt in maandelijks op :date', @@ -1169,7 +1169,7 @@ $lang = array( 'invoice_number_padding' => 'Marge', 'preview' => 'Voorbeeld', 'list_vendors' => 'Toon leveranciers', - 'add_users_not_supported' => 'Upgrade naar het Enterprise Plan 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.', 'return_to_app' => 'Terug naar de app', @@ -1210,7 +1210,7 @@ $lang = array( 'ach' => 'ACH', 'enable_ach' => 'Accepteer US bank transacties', 'stripe_ach_help' => 'ACH ondersteuning moet ook ingeschakeld zijn in :link.', - 'ach_disabled' => 'Er is al een andere gateway geconfigureerd voor directe afschrijving.', + 'ach_disabled' => 'Er is al een andere betaalprovider geconfigureerd voor directe afschrijvingen.', 'plaid' => 'Plaid', 'client_id' => 'Klantnummer', @@ -1231,58 +1231,58 @@ $lang = array( 'company_account' => 'Bedrijfsrekening', 'account_holder_name' => 'Rekeninghouder', 'add_account' => 'Rekening toevoegen', - 'payment_methods' => 'Betalingsmethode', + 'payment_methods' => 'Betaalmethode', 'complete_verification' => 'Verificatie voltooien', 'verification_amount1' => 'Bedrag 1', 'verification_amount2' => 'Bedrag 2', 'payment_method_verified' => 'Verificatie voltooid', 'verification_failed' => 'Verificatie mislukt', - 'remove_payment_method' => 'Betalingsmethode verwijderen', - 'confirm_remove_payment_method' => 'Weet u zeker dat u deze betalingsmethode wilt verwijderen?', + 'remove_payment_method' => 'Betaalmethode verwijderen', + 'confirm_remove_payment_method' => 'Weet u zeker dat u deze betaalmethode wilt verwijderen?', 'remove' => 'Verwijderen', - 'payment_method_removed' => 'Betalingsmethode verwijderd.', + 'payment_method_removed' => 'Betaalmethode verwijderd.', 'bank_account_verification_help' => 'We hebben twee bedragen met de omschrijving "VERIFICATION" overgeboekt naar uw rekening. Het duurt 1 à 2 werkdagen voordat deze overschrijvingen zichtbaar zijn op uw afschriften. Voer de bedragen hieronder in.', 'bank_account_verification_next_steps' => 'We hebben twee bedragen met de omschrijving "VERIFICATION" overgeboekt naar uw rekening. Het duurt 1 à 2 werkdagen voordat deze overschrijvingen zichtbaar zijn op uw afschriften. -Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen en klik op "Verificatie voltooien" direct naast de rekening.', +Kom terug naar deze betaalmethode pagina zodra u de bedragen heeft ontvangen en klik op "Verificatie voltooien" direct naast de rekening.', 'unknown_bank' => 'Onbekende bank', 'ach_verification_delay_help' => 'U kunt de rekening gebruiken na het voltooien van de verificatie. Verificatie duurt doorgaans 1 à 2 werkdagen.', 'add_credit_card' => 'Creditcard toevoegen', - 'payment_method_added' => 'Betalingsmethode toegevoegd.', - 'use_for_auto_bill' => 'Gebruiken voor Autobill', - 'used_for_auto_bill' => 'Autobill betalingsmethode', - 'payment_method_set_as_default' => 'Autobill betalingsmethode instellen.', + 'payment_method_added' => 'Betaalmethode toegevoegd.', + 'use_for_auto_bill' => 'Gebruiken voor automatische betaling', + 'used_for_auto_bill' => 'Betaalmethode voor automatische betalingen', + 'payment_method_set_as_default' => 'Betaalmethode voor automatische betalingen instellen.', 'activity_41' => 'Betaling van :payment_amount mislukt (:payment)', 'webhook_url' => 'Webhook URL', 'stripe_webhook_help' => 'U moet :link.', 'stripe_webhook_help_link_text' => 'deze URL toevoegen als een endpoint in Stripe', 'gocardless_webhook_help_link_text' => 'deze URL toevoegen als een endpoint in GoCardless', - 'payment_method_error' => 'Er is een fout opgetreden bij het toevoegen van de betalingsmethode. Probeer het later opnieuw.', + 'payment_method_error' => 'Er is een fout opgetreden bij het toevoegen van de betaalmethode. Probeer het later opnieuw.', 'notification_invoice_payment_failed_subject' => 'Betaling mislukt voor factuur :invoice', 'notification_invoice_payment_failed' => 'Een betaling van :client voor factuur :invoice is mislukt. De betaling is gemarkeerd als mislukt en het :amount is toegevoegd aan het krediet van de klant.', 'link_with_plaid' => 'Rekening direct koppelen met Plaid', 'link_manually' => 'Handmatig koppelen', 'secured_by_plaid' => 'Beveiligd met Plaid', 'plaid_linked_status' => 'Uw bankrekening bij :bank', - 'add_payment_method' => 'Betalingsmethode toevoegen', + 'add_payment_method' => 'Betaalmethode toevoegen', 'account_holder_type' => 'Type rekeninghouder', - 'ach_authorization' => 'Ik geef :company toestemming om mijn bankrekening te gebruiken voor toekomstige betalingen en, indien nodig, te crediteren op mijn rekening om foutieve afschrijvingen te corrigeren. I begrijp dat ik deze toestemming te allen tijde mag annuleren door de betalingsmethode te verwijderen of door contact op te nemen via :email.', - 'ach_authorization_required' => 'U moet toestemming geven voor ACH overschrijvingen.', + 'ach_authorization' => 'Ik geef :company toestemming om mijn bankrekening te gebruiken voor toekomstige betalingen en, indien nodig, te crediteren op mijn rekening om foutieve afschrijvingen te corrigeren. Ik begrijp dat ik deze toestemming te allen tijde mag intrekken door de betaalmethode te verwijderen of door contact op te nemen via :email.', + 'ach_authorization_required' => 'U moet toestemming geven voor ACH-overschrijvingen.', 'off' => 'Uit', - 'opt_in' => 'Meedoen', + 'opt_in' => 'Inschrijven', 'opt_out' => 'Terugtrekken', 'always' => 'Altijd', 'opted_out' => 'Teruggetrokken', 'opted_in' => 'Meegedaan', - 'manage_auto_bill' => 'Beheer Autobill', + 'manage_auto_bill' => 'Beheer automatische betalingen', 'enabled' => 'Ingeschakeld', 'paypal' => 'PayPal', 'braintree_enable_paypal' => 'PayPal betalingen via BrainTree inschakelen', - 'braintree_paypal_disabled_help' => 'De PayPal gateway verwerkt PayPal betalingen', + 'braintree_paypal_disabled_help' => 'De PayPal-gateway verwerkt PayPal-betalingen', 'braintree_paypal_help' => 'U moet ook :link.', 'braintree_paypal_help_link_text' => 'PayPal koppelen aan uw BrainTree account', - 'token_billing_braintree_paypal' => 'Betalingsgegevens opslaan', + 'token_billing_braintree_paypal' => 'Betaalgegevens opslaan', 'add_paypal_account' => 'PayPal rekening toevoegen', - 'no_payment_method_specified' => 'Geen betalingsmethode gespecificeerd', + 'no_payment_method_specified' => 'Geen betaalmethode gespecificeerd', 'chart_type' => 'Grafiektype', 'format' => 'Formaat', 'import_ofx' => 'OFX importeren', @@ -1305,21 +1305,21 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'created_wepay_confirmation_required' => 'Controleer uw e-mail en bevestig uw e-mailadres met WePay.', 'switch_to_wepay' => 'Overschakelen naar WePay', 'switch' => 'Overschakelen', - 'restore_account_gateway' => 'Herstel gateway', - 'restored_account_gateway' => 'De gateway is hersteld', + 'restore_account_gateway' => 'Herstel betaalprovider', + 'restored_account_gateway' => 'De betaalprovider is hersteld', 'united_states' => 'Verenigde Staten', 'canada' => 'Canada', 'accept_debit_cards' => 'Accepteer betaalkaart', 'debit_cards' => 'Betaalkaarten', - 'warn_start_date_changed' => 'Het volgende factuur zal verzonden worden op de nieuwe startdatum.', - 'warn_start_date_changed_not_sent' => 'Het volgende factuur zal aangemaakt worden op de nieuwe startdatum.', + 'warn_start_date_changed' => 'De volgende factuur zal verzonden worden op de nieuwe startdatum.', + 'warn_start_date_changed_not_sent' => 'De volgende factuur zal aangemaakt worden op de nieuwe startdatum.', 'original_start_date' => 'Oorspronkelijke startdatum', 'new_start_date' => 'Nieuwe startdatum', 'security' => 'Beveiliging', 'see_whats_new' => 'Bekijk wat veranderde in v:version', 'wait_for_upload' => 'Gelieve te wachten tot de upload van het document compleet is.', - 'upgrade_for_permissions' => 'Upgrade naar ons Enterprise Plan om machtigingen in te schakelen.', + 'upgrade_for_permissions' => 'Upgrade naar ons Enterprise-abonnement om machtigingen in te schakelen.', 'enable_second_tax_rate' => 'Het opgeven van een tweede extra belastingregel aanzetten', 'payment_file' => 'Betalingsbestand', 'expense_file' => 'Uitgavenbestand', @@ -1330,43 +1330,43 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'created_products' => 'Succesvol :count product(en) aangemaakt/bijgewerkt', 'export_help' => 'Gebruik JSON als u van plan bent om de gegevens te importeren in Invoice Ninja.
    Het bestand omvat klanten, producten, facturen, offertes en betalingen.', 'selfhost_export_help' => '
    We raden mysqldump aan om een volledige backup te maken.', - 'JSON_file' => 'JSON bestand', + 'JSON_file' => 'JSON-bestand', 'view_dashboard' => 'Bekijk dashboard', 'client_session_expired' => 'Sessie verlopen', 'client_session_expired_message' => 'Uw sessie is verlopen. Gelieve de link in de e-mail opnieuw te openen.', - 'auto_bill_notification' => 'Deze factuur zal automatisch worden gefactureerd aan uw opgeslagen betalingsmethode op de vervaldag.', + 'auto_bill_notification' => 'Deze factuur zal op :due_date automatisch worden voldaan via :payment_method.', 'auto_bill_payment_method_bank_transfer' => 'Bankrekening', 'auto_bill_payment_method_credit_card' => 'creditcard', - 'auto_bill_payment_method_paypal' => 'PayPal account', - 'auto_bill_notification_placeholder' => 'Deze factuur zal automatisch worden gefactureerd aan uw creditcard op de vervaldag.', + 'auto_bill_payment_method_paypal' => 'PayPal-account', + 'auto_bill_notification_placeholder' => 'Voor deze factuur zal uw opgeslagen creditcard automatisch worden belast op de vervaldag.', 'payment_settings' => 'Betalingsinstellingen', 'on_send_date' => 'Op verzendingsdatum', 'on_due_date' => 'Op vervaldatum', - 'auto_bill_ach_date_help' => 'ACH automatische facturatie zal atijd uitgevoerd worden op de vervaldag', - 'warn_change_auto_bill' => 'Vanwege NACHA regels kunnen aanpassingen aan dit factuur ACH automatische facturatie voorkomen.', + 'auto_bill_ach_date_help' => 'De ACH-incasso zal altijd worden uitgevoerd op de vervaldag.', + 'warn_change_auto_bill' => 'Vanwege NACHA-regelgeving kunnen aanpassingen aan deze factuur voorkomen dat ACH-incasso\'s uitgevoerd kunnen worden.', 'bank_account' => 'Bankrekening', - 'payment_processed_through_wepay' => 'ACH betalingen zullen verwerkt worden met WePay.', + 'payment_processed_through_wepay' => 'ACH-betalingen zullen verwerkt worden met WePay.', 'privacy_policy' => 'Privacybeleid', - 'ach_email_prompt' => 'Gelieve uw e-maildres in te vullen:', + 'ach_email_prompt' => 'Gelieve uw e-mailadres in te vullen:', 'verification_pending' => 'Verificatie in afwachting', 'update_font_cache' => 'Forceer het vernieuwen van de pagina om de font cache bij te werken.', 'more_options' => 'Meer opties', 'credit_card' => 'Creditcard', 'bank_transfer' => 'Overschrijving', - 'no_transaction_reference' => 'We ontvingen geen betalingstransactie referentie van de gateway.', + 'no_transaction_reference' => 'We hebben geen betalingsreferentie ontvangen van de betaalprovider.', 'use_bank_on_file' => 'Gebruik opgeslagen bank', - 'auto_bill_email_message' => 'Deze factuur zal automatisch worden gefactureerd aan uw opgeslagen betalingsmethode op de vervaldag.', + 'auto_bill_email_message' => 'Deze factuur zal, op de vervaldag, automatisch worden betaald met de door u gekozen voorkeursbetaalmethode.', 'bitcoin' => 'Bitcoin', 'gocardless' => 'GoCardless', 'added_on' => 'Toegevoegd op :date', - 'failed_remove_payment_method' => 'Verwijderen van betalingsmethode mislukt', - 'gateway_exists' => 'Deze gateway bestaat reeds', - 'manual_entry' => 'Manuele invoer', + 'failed_remove_payment_method' => 'Verwijderen van betaalmethode mislukt', + 'gateway_exists' => 'Deze betaalprovider bestaat reeds', + 'manual_entry' => 'Handmatige invoer', 'start_of_week' => 'Eerste dag van de week', // Frequencies @@ -1384,7 +1384,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'freq_two_years' => 'Twee jaar', // Payment types - 'payment_type_Apply Credit' => 'Krediet toepassen', + 'payment_type_Apply Credit' => 'Krediet gebruiken', 'payment_type_Bank Transfer' => 'Overschrijving', 'payment_type_Cash' => 'Contant', 'payment_type_Debit' => 'Debet', @@ -1571,7 +1571,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'country_Curaçao' => 'Curaçao', 'country_Aruba' => 'Aruba', 'country_Sint Maarten (Dutch part)' => 'Sint Maarten', - 'country_Bonaire, Sint Eustatius and Saba' => 'Caribisch Nederland', + 'country_Bonaire, Sint Eustatius and Saba' => 'Bonaire, Sint Eustatius en Saba', 'country_New Caledonia' => 'Nieuw-Caledonië', 'country_Vanuatu' => 'Vanuatu', 'country_New Zealand' => 'Nieuw-Zeeland', @@ -1701,7 +1701,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'lang_Chinese - Taiwan' => 'Chinees - Taiwan', 'lang_Serbian' => 'Servisch', 'lang_Bulgarian' => 'Bulgaars', - 'lang_Russian (Russia)' => 'Russisch', + 'lang_Russian (Russia)' => 'Russisch (Rusland)', // Industries @@ -1749,12 +1749,12 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'archive_expense_category' => 'Archiveer categorie', 'expense_categories' => 'Uitgavecategorie', 'list_expense_categories' => 'Toon uitgavecategorieën', - 'updated_expense_category' => 'De uitgaven categorie is gewijzigd', - 'created_expense_category' => 'De uitgaven categorie is aangemaakt', - 'archived_expense_category' => 'De uitgaven categorie is gearchiveerd', - 'archived_expense_categories' => ':count uitgave-categorieën gearchiveerd', + 'updated_expense_category' => 'De uitgavencategorie is gewijzigd', + 'created_expense_category' => 'De uitgavencategorie is aangemaakt', + 'archived_expense_category' => 'De uitgavencategorie is gearchiveerd', + 'archived_expense_categories' => ':count uitgavecategorieën gearchiveerd', 'restore_expense_category' => 'Herstel uitgavecategorie', - 'restored_expense_category' => 'De uitgaven categorie hersteld', + 'restored_expense_category' => 'De uitgavecategorie is hersteld', 'apply_taxes' => 'Pas belasting toe', 'min_to_max_users' => ':min tot :max gebruikers', 'max_users_reached' => 'Het maximale aantal gebruikers is bereikt.', @@ -1766,17 +1766,17 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'fields' => 'Velden', 'dwolla' => 'Dwolla', 'buy_now_buttons_warning' => 'Opmerking: de klant en factuur worden aangemaakt ook al is de transactie niet afgerond.', - 'buy_now_buttons_disabled' => 'Deze functie vereist dat een product is aangemaakt en een betalingsgateway is geconfigureerd.', + 'buy_now_buttons_disabled' => 'Deze functie vereist dat een product is aangemaakt en een betaalprovider is geconfigureerd.', 'enable_buy_now_buttons_help' => 'Ondersteuning inschakelen voor koop nu knoppen', 'changes_take_effect_immediately' => 'Opmerking: wijzigingen zijn onmiddelijk van kracht', - 'wepay_account_description' => 'Betalingsgateway voor Invoice Ninja', + 'wepay_account_description' => 'Betaalprovider voor Invoice Ninja', 'payment_error_code' => 'Er trad een fout op tijdens het verwerken van uw betaling [:code]. Gelieve het later opnieuw te proberen.', - 'standard_fees_apply' => 'Toeslag: 2.9%/1.2% [kredietkaart/overschijving] + $0.30 per succesvolle aanrekening.', + 'standard_fees_apply' => 'Toeslag: 2.9%/1.2% [creditcard/bankoverschijving] + $0.30 per succesvolle transactie.', 'limit_import_rows' => 'Data dient geïmporteerd te worden in delen van :count rijen of minder', 'error_title' => 'Er ging iets mis', 'error_contact_text' => 'Indien u hulp wenst gelieve ons te contacteren op :mailaddress', 'no_undo' => 'Waarschuwing: dit kan niet ongedaan gemaakt worden.', - 'no_contact_selected' => 'Gelieve een contact te selecteren', + 'no_contact_selected' => 'Gelieve een contactpersoon te selecteren', 'no_client_selected' => 'Gelieve een klant te selecteren', 'gateway_config_error' => 'Het kan helpen om nieuwe wachtwoorden in te stellen of nieuwe API sleutels te genereren.', @@ -1787,8 +1787,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'client_not_found' => 'Ik was niet in staat om de klant te vinden', 'not_allowed' => 'Sorry, u heeft niet de benodigde machtigingen', 'bot_emailed_invoice' => 'Uw factuur is verzonden.', - 'bot_emailed_notify_viewed' => 'Ik e-mail u als het bekeken is.', - 'bot_emailed_notify_paid' => 'Ik e-mail u als het betaald is.', + 'bot_emailed_notify_viewed' => 'Ik e-mail u zodra het bekeken is.', + 'bot_emailed_notify_paid' => 'Ik e-mail u zodra het betaald is.', 'add_product_to_invoice' => 'Voeg 1 :product toe', 'not_authorized' => 'U bent niet gemachtigd', 'email_not_found' => 'Ik was niet in staat om een beschikbaar account te vinden voor :email', @@ -1812,13 +1812,13 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'unassigned' => 'Niet toegewezen', 'task' => 'Taak', 'contact_name' => 'Contactnaam', - 'city_state_postal' => 'Stad/Provincie/Postcode', - 'postal_city' => 'Postcode/Stad', + 'city_state_postal' => 'Stad/provincie/postcode', + 'postal_city' => 'Postcode/stad', 'custom_field' => 'Aangepast veld', 'account_fields' => 'Velden bedrijf', 'facebook_and_twitter' => 'Facebook en Twitter', 'facebook_and_twitter_help' => 'Volg onze feeds om ons te helpen met het project', - 'reseller_text' => 'Opmerking: de white-label licentie is bedoeld voor persoonlijk gebruik, gelieve ons te contacteren op :email indien u de app door wilt verkopen.', + 'reseller_text' => 'Let op: de white-label licentie is bedoeld voor persoonlijk gebruik, gelieve ons te contacteren op :email indien u de app door wilt verkopen.', 'unnamed_client' => 'Onbenoemde klant', 'day' => 'Dag', @@ -1840,7 +1840,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'enable_max' => 'Max inschakelen', 'min' => 'Min', 'max' => 'Max', - 'limits_not_met' => 'Dit factuur voldoet niet aan de limieten voor die betalingsmethode.', + 'limits_not_met' => 'Deze factuur voldoet niet aan de limieten voor die betaalmethode.', 'date_range' => 'Datumbereik', 'raw' => 'Onbewerkt', @@ -1861,8 +1861,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'translate_app' => 'Help onze vertalingen te verbeteren met :link', 'expense_category' => 'Uitgavecategorie', - 'go_ninja_pro' => 'Ga Ninja Pro!', - 'go_enterprise' => 'Ga zakelijk!', + 'go_ninja_pro' => 'Ga voor Ninja Pro!', + 'go_enterprise' => 'Ga voor Enterprise!', 'upgrade_for_features' => 'Upgrade voor meer mogelijkheden', 'pay_annually_discount' => 'Betaal jaarlijks voor 10 maanden en krijg er 2 gratis!', 'pro_upgrade_title' => 'Ninja Pro', @@ -1871,7 +1871,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'enterprise_upgrade_feature1' => 'Stel machtigingen in voor meerdere gebruikers', 'enterprise_upgrade_feature2' => 'Voeg externe documenten toe aan facturen & uitgaven', 'much_more' => 'Veel meer!', - 'all_pro_fetaures' => 'Plus alle pro functies!', + 'all_pro_fetaures' => 'Plus alle pro-functionaliteit!', 'currency_symbol' => 'Symbool', 'currency_code' => 'Code', @@ -1887,17 +1887,17 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'authentication' => 'Authenticatie', 'checkbox' => 'Checkbox', 'invoice_signature' => 'Handtekening', - 'show_accept_invoice_terms' => 'Factuurvoorwaarden checkbox', + 'show_accept_invoice_terms' => 'Checkbox factuurvoorwaarden', 'show_accept_invoice_terms_help' => 'Verplicht de klant om akkoord te gaan met de factuurvoorwaarden.', - 'show_accept_quote_terms' => 'Offertevoorwaarden checkbox', + 'show_accept_quote_terms' => 'Checkbox offertevoorwaarden', 'show_accept_quote_terms_help' => 'Verplicht de klant om akkoord te gaan met de offertevoorwaarden.', - 'require_invoice_signature' => 'Factuur handtekening', + 'require_invoice_signature' => 'Handtekening op factuur', 'require_invoice_signature_help' => 'Verplicht de klant om zijn handtekening te zetten.', - 'require_quote_signature' => 'Offerte handtekening', + 'require_quote_signature' => 'Handtekening op offerte', 'require_quote_signature_help' => 'Verplicht de klant zijn handtekening te zetten.', 'i_agree' => 'Ik ga akkoord met de voorwaarden', 'sign_here' => 'Gelieve hier te tekenen:', - 'sign_here_ux_tip' => 'Gebruik de muis of uw touchpad om uw handtekening te traceren.', + 'sign_here_ux_tip' => 'Gebruik uw muis of touchpad om uw handtekening te zetten.', 'authorization' => 'Autorisatie', 'signed' => 'Getekend', @@ -1920,7 +1920,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'delete_project' => 'Verwijder project', 'deleted_project' => 'Het project is verwijderd', 'deleted_projects' => 'Succesvol :count projecten verwijderd', - 'delete_expense_category' => 'Verwijderen categorie', + 'delete_expense_category' => 'Verwijder categorie', 'deleted_expense_category' => 'De categorie is verwijderd', 'delete_product' => 'Verwijder product', 'deleted_product' => 'Het product is verwijderd', @@ -1929,23 +1929,23 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'update_credit' => 'Krediet bijwerken', 'updated_credit' => 'Het krediet is gewijzigd', 'edit_credit' => 'Wijzig krediet', - 'realtime_preview' => 'Realtime Voorbeeld', - 'realtime_preview_help' => 'Toon een realtime PDF voorbeeld op de factuur pagina bij het bewerken van facturen.
    Schakel dit uit om de prestaties te verbeteren tijdens het bewerken van facturen.', - 'live_preview_help' => 'Toon een live PDF voorbeeld op de factuur pagina.', - 'force_pdfjs_help' => 'Vervang de ingebouwde PDF viewer in :chrome_link en :firefox_link.
    Schakel dit in als je browser de PDF automatisch download.', + 'realtime_preview' => 'Realtime voorbeeld', + 'realtime_preview_help' => 'Toon een realtime PDF-voorbeeld op de factuurpagina bij het bewerken van facturen.
    Schakel dit uit om de prestaties te verbeteren tijdens het bewerken van facturen.', + 'live_preview_help' => 'Toon een live PDF-voorbeeld op de factuurpagina.', + 'force_pdfjs_help' => 'Vervang de ingebouwde PDF-viewer in :chrome_link en :firefox_link.
    Schakel dit in als uw browser de PDF automatisch download.', 'force_pdfjs' => 'Download voorkomen', - 'redirect_url' => 'Redirect URL', + 'redirect_url' => 'Redirect-URL', 'redirect_url_help' => 'Optioneel kan een URL opgegeven worden om naar door te verwijzen nadat een betaling is ingevoerd.', 'save_draft' => 'Concept opslaan', - 'refunded_credit_payment' => 'Gecrediteerde krediet betaling', + 'refunded_credit_payment' => 'Krediet is terugbetaald', 'keyboard_shortcuts' => 'Toetsenbord sneltoetsen', - 'toggle_menu' => 'Toggle menu', + 'toggle_menu' => 'Menu in-/uitklappen', 'new_...' => 'Nieuw...', 'list_...' => 'Lijst...', 'created_at' => 'Aanmaakdatum', 'contact_us' => 'Contacteer ons', 'user_guide' => 'Gebruikershandleiding', - 'promo_message' => 'Upgrade voor :expires en krijg :amount korting op je eerste jaar met onze Pro en Enterprise pakketten.', + 'promo_message' => 'Upgrade voor :expires en krijg :amount korting op uw eerste jaar met onze Pro- en Enterprise-abonnementen.', 'discount_message' => ':amount korting vervalt :expires', 'mark_paid' => 'Markeer als betaald', 'marked_sent_invoice' => 'De factuur is gemarkeerd als verzonden', @@ -1966,34 +1966,34 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'debug' => 'Debug', 'https' => 'HTTPS', 'require' => 'Vereis', - 'license_expiring' => 'Opmerking: uw licentie zal vervallen in :count dagen, :link om het te verlengen.', + 'license_expiring' => 'Opmerking: uw licentie komt te vervallen in :count dagen, navigeer naar :link om uw licentie te verlengen.', 'security_confirmation' => 'Uw e-mailadres is bevestigd.', - 'white_label_expired' => 'Uw white label licentie is verlopen, gelieve te overwegen om dit te vernieuwen om zo ons project mee te helpen ondersteunen.', + 'white_label_expired' => 'Uw whitelabel-licentie is verlopen, gelieve te overwegen om dit te vernieuwen om zo ons project mee te helpen ondersteunen.', 'renew_license' => 'Licentie vernieuwen', 'iphone_app_message' => 'Overweeg onze :link te downloaden', 'iphone_app' => 'iPhone app', 'android_app' => 'Android app', 'logged_in' => 'Aangemeld', - 'switch_to_primary' => 'Schakel over naar uw primair bedrijf (:name) om uw abonnement te beheren.', + 'switch_to_primary' => 'Schakel over naar uw primaire bedrijf (:name) om uw abonnement te beheren.', 'inclusive' => 'Inclusief', 'exclusive' => 'Exclusief', - 'postal_city_state' => 'Postcode/Stad/Provincie', + 'postal_city_state' => 'Postcode/stad/provincie', 'phantomjs_help' => 'In sommige gevallen gebruikt de app :link_phantom om het PDF-bestand te genereren, installeer :link_docs om het lokaal te genereren.', 'phantomjs_local' => 'Lokaal PhantomJS gebruiken', 'client_number' => 'Klantnummer', 'client_number_help' => 'Geef een voorvoegsel of een aangepast patroon om klantnummers dynamisch te genereren.', - 'next_client_number' => 'Het volgende klantnummer is :number.', + 'next_client_number' => 'Het eerstvolgende klantnummer is :number.', 'generated_numbers' => 'Gegenereerde nummers', 'notes_reminder1' => 'Eerste herinnering', 'notes_reminder2' => 'Tweede herinnering', 'notes_reminder3' => 'Derde herinnering', 'notes_reminder4' => 'Herinnering', - 'bcc_email' => 'BCC Email', + 'bcc_email' => 'BCC e-mail', 'tax_quote' => 'BTW offerte', 'tax_invoice' => 'BTW factuur', 'emailed_invoices' => 'De facturen zijn gemaild', 'emailed_quotes' => 'De offertes zijn gemaild', - 'website_url' => 'Website URL', + 'website_url' => 'Website-URL', 'domain' => 'Domein', 'domain_help' => 'Wordt gebruikt in het klantenportaal en bij het versturen van e-mails.', 'domain_help_website' => 'Wordt gebruikt bij het versturen van e-mails.', @@ -2070,7 +2070,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'create_project' => 'Project aanmaken', 'create_vendor' => 'Leverancier aanmaken', 'create_expense_category' => 'Categorie aanmaken', - 'pro_plan_reports' => ':link om rapporten te activeren door te abonneren op het Pro Plan', + 'pro_plan_reports' => ':link om rapporten te activeren door te abonneren op het Pro-abonnement', 'mark_ready' => 'Markeer als gereed', 'limits' => 'Limieten', @@ -2081,7 +2081,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'fees_sample' => 'De toeslag voor een :amount factuur is :total.', 'discount_sample' => 'De korting voor een :amount factuur is :total.', 'no_fees' => 'Geen transactiekosten', - 'gateway_fees_disclaimer' => 'Waarschuwing: niet alle staten/betalingsgateways laten het toe om kosten toe te voegen, gelieve lokale wetten/servicevoorwaarden te raadplegen.', + 'gateway_fees_disclaimer' => 'Waarschuwing: niet alle jurisdicties/betaalproviders staan het toe om kosten toe te voegen. Gelieve lokale wetgeving en/of servicevoorwaarden te raadplegen.', 'percent' => 'Procent', 'location' => 'Locatie', 'line_item' => 'Regelitem', @@ -2090,10 +2090,10 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'location_second_surcharge' => 'Ingeschakeld - Tweede toeslag', 'location_line_item' => 'Ingeschakeld - Regelitem', 'online_payment_surcharge' => 'Online betalingstoeslag', - 'gateway_fees' => 'Transactiekosten Gateway', + 'gateway_fees' => 'Transactiekosten betaalprovider', 'fees_disabled' => 'Transactiekosten zijn uitgeschakeld', 'gateway_fees_help' => 'Online betalingstoeslag/korting automatisch toevoegen.', - 'gateway' => 'Gateway', + 'gateway' => 'Betaalprovider', 'gateway_fee_change_warning' => 'Als er onbetaalde facturen met transactiekosten zijn, moeten die handmatig bijgewerkt worden.', 'fees_surcharge_help' => 'Toeslag aanpassen :link.', 'label_and_taxes' => 'label en belastingen', @@ -2109,18 +2109,18 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'reset_counter_help' => 'De factuur en offerte tellers automatisch resetten.', 'auto_bill_failed' => 'Autofacturatie voor factuur :invoice_number mislukt', 'online_payment_discount' => 'Online betalingskorting', - 'created_new_company' => 'Nieuw bedrijf succesfol aangemaakt', - 'fees_disabled_for_gateway' => 'Transactiekosten zijn uitgeschakeld voor deze gateway.', + 'created_new_company' => 'Nieuw bedrijf succesvol aangemaakt', + 'fees_disabled_for_gateway' => 'Transactiekosten zijn uitgeschakeld voor deze betaalprovider.', 'logout_and_delete' => 'Uitloggen/account opzeggen', 'tax_rate_type_help' => 'Inbegrepen belastingstarieven passen de kosten van het regelitem aan wanneer deze worden geselecteerd.
    Alleen de niet inbegrepen belastingtarieven kunnen als standaard worden gebruikt.', - 'credit_note' => 'Creditnota', + 'credit_note' => 'Creditfactuur', 'credit_issued_to' => 'Krediet afgegeven aan', 'credit_to' => 'Krediet aan', 'your_credit' => 'Uw krediet', 'credit_number' => 'Creditnummer', - 'create_credit_note' => 'Creditnota aanmaken', + 'create_credit_note' => 'Creditfactuur aanmaken', 'menu' => 'Menu', - 'error_incorrect_gateway_ids' => 'Fout: De gateway tabel heeft foutieve id\'s.', + 'error_incorrect_gateway_ids' => 'Fout: de betaalprovider-tabel bevat foutieve id\'s.', 'purge_data' => 'Wis gegevens', 'delete_data' => 'Verwijder gegevens', 'purge_data_help' => 'Alle gegevens permanent verwijderen, maar behoud het account en instellingen.', @@ -2128,11 +2128,11 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'purge_successful' => 'De bedrijfsgegevens zijn gewist', 'forbidden' => 'Verboden', 'purge_data_message' => 'Waarschuwing: Dit zal uw gegevens verwijderen. Er is geen manier om dit ongedaan te maken.', - 'contact_phone' => 'Contact telefoon', - 'contact_email' => 'Contact e-mail', - 'reply_to_email' => 'Antwoord naar e-mail', - 'reply_to_email_help' => 'Geef het antwoord-aan adres voor klant e-mails.', - 'bcc_email_help' => 'Dit adres heimelijk gebruiken met klant e-mails.', + 'contact_phone' => 'Telefoon contactpersoon', + 'contact_email' => 'E-mailadres contactpersoon', + 'reply_to_email' => 'Reply-To e-mailadres', + 'reply_to_email_help' => 'Specificeer het antwoordadres voor e-mails van klanten.', + 'bcc_email_help' => 'Gebruik dit adres als BCC-adres voor e-mails naar klanten.', 'import_complete' => 'Het importeren is uitgevoerd.', 'confirm_account_to_import' => 'Gelieve uw account te bevestigen om de gegevens te importeren.', 'import_started' => 'Het importeren is gestart, we sturen u een e-mail van zodra het proces afgerond is.', @@ -2146,9 +2146,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'contact_fields' => 'Contact velden', 'custom_contact_fields_help' => 'Voeg een veld toe bij het creëren van een contact en toon het label en de waarde op de PDF.', 'datatable_info' => ':start tot :end van :total items worden getoond', - 'credit_total' => 'Totaal Credit', - 'mark_billable' => 'Markeer als factureerbaar', - 'billed' => 'Gefactureerd', + 'credit_total' => 'Totaal krediet', + 'mark_billable' => 'Markeer als inbaar', + 'billed' => 'Geïnd', 'company_variables' => 'Bedrijfsvariabelen', 'client_variables' => 'Klant variabelen', 'invoice_variables' => 'Factuur variabelen', @@ -2157,13 +2157,13 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'invalid_file' => 'Ongeldig bestandstype', 'add_documents_to_invoice' => 'Voeg documenten toe aan uw factuur', 'mark_expense_paid' => 'Markeer als betaald', - 'white_label_license_error' => 'De licentie validatie is mislukt. De licentie is verlopen of te vaak geactiveerd. Email contact@invoiceninja.com voor meer informatie.', - 'plan_price' => 'Plan prijs', + 'white_label_license_error' => 'De licentie validatie is mislukt. De licentie is verlopen of te vaak geactiveerd. E-mail contact@invoiceninja.com voor meer informatie.', + 'plan_price' => 'Abonnementsprijs', 'wrong_confirmation' => 'Incorrecte bevestigingscode', 'oauth_taken' => 'Het account is al geregistreerd', 'emailed_payment' => 'De betaling is per mail verstuurd', 'email_payment' => 'E-mail betaling', - 'invoiceplane_import' => 'Gebruik :link om uw data te migreren van InvoicePlane.', + 'invoiceplane_import' => 'Gebruik :link om uw data te migreren vanuit InvoicePlane.', 'duplicate_expense_warning' => 'Waarschuwing: Deze :link kan een duplicaat zijn', 'expense_link' => 'uitgave', 'resume_task' => 'Hervat taak', @@ -2194,12 +2194,12 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'mailgun_private_key' => 'Mailgun privésleutel', 'brevo_domain' => 'Brevo-domein', 'brevo_private_key' => 'Brevo-privésleutel', - 'send_test_email' => 'Send Test Email', + 'send_test_email' => 'Verstuur teste-mail', 'select_label' => 'Selecteer label', 'label' => 'Label', 'service' => 'Service', - 'update_payment_details' => 'Betalingsdetails bijwerken', - 'updated_payment_details' => 'De betalingsdetails zijn gewijzigd', + 'update_payment_details' => 'Betaalgegevens bijwerken', + 'updated_payment_details' => 'De betaalgegevens zijn gewijzigd', 'update_credit_card' => 'Krediet kaart bijwerken', 'recurring_expenses' => 'Terugkerende uitgaven', 'recurring_expense' => 'Terugkerende uitgave', @@ -2220,7 +2220,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'recurring_prefix' => 'Terugkerend voorvoegsel', 'options' => 'Opties', 'credit_number_help' => 'Geef een voorvoegsel of een aangepast patroon om kredietnummers dynamisch te genereren.', - 'next_credit_number' => 'Het volgende kredietnummer is :number.', + 'next_credit_number' => 'Het eerstvolgende kredietnummer is :number.', 'padding_help' => 'Het aantal nullen om het nummer op te vullen.', 'import_warning_invalid_date' => 'Waarschuwing: het datumformaat lijkt ongeldig te zijn.', 'product_notes' => 'Productopmerkingen', @@ -2361,14 +2361,14 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'currency_gold_troy_ounce' => 'Gouden Troy Ounce', 'currency_nicaraguan_córdoba' => 'Nicaraguaans Córdoba', 'currency_malagasy_ariary' => 'Malagassische ariarium', - "currency_tongan_paanga" => "Tongan Pa'anga", + "currency_tongan_paanga" => "Tongaanse pa'anga", - 'review_app_help' => 'We hopen dat je het leuk vindt om de app te gebruiken.
    Als je zou overwegen :link, zouden we dat zeer op prijs stellen!', + 'review_app_help' => 'We hopen dat u veel gemak heeft aan het gebruik van deze app.
    Als u :link zou overwegen, stellen wij dat zeer op prijs!', 'writing_a_review' => 'een recensie schrijven', 'tax1' => 'Eerste belasting', 'tax2' => 'Tweede belasting', - 'fee_help' => 'Gateway vergoedingen zijn de kosten die gelden voor toegang tot de financiële netwerken die de verwerking van online betalingen behandelen.', + 'fee_help' => 'Transactiekosten omvatten de kosten die gelden voor toegang tot de financiële netwerken die de verwerking van online betalingen behandelen.', 'format_export' => 'Uitvoerformaat', 'custom1' => 'Eerste aangepaste', 'custom2' => 'Tweede aangepaste', @@ -2390,8 +2390,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'item_tax2' => 'Artikel belasting 2', 'delete_company' => 'Verwijder bedrijf', - 'delete_company_help' => 'Permanent je bedrijf verwijderen inclusief alle gegevens en instellingen.', - 'delete_company_message' => 'Waarschuwing: Hiermee verwijder je permanent je bedrijf, dit kan niet worden ontdaan.', + 'delete_company_help' => 'Permanent uw bedrijf verwijderen, inclusief alle gegevens en instellingen.', + 'delete_company_message' => 'Waarschuwing: Hiermee verwijdert u permanent uw bedrijf, dit kan niet ongedaan worden gemaakt.', 'applied_discount' => 'De kortingscode is toegevoegd, de prijs van het gekozen plan is verlaagd met :discount%.', 'applied_free_year' => 'De kortingsbon is toegepast, uw account is gedurende een jaar geüpgraded naar pro.', @@ -2408,8 +2408,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'purge_details' => 'De gegevens in het account (:account) zijn gewist', 'deleted_company' => 'Het bedrijf is verwijderd', 'deleted_account' => 'Account geannuleerd', - 'deleted_company_details' => 'Je bedrijf (:account) is verwijderd', - 'deleted_account_details' => 'Je account (:account) is verwijderd', + 'deleted_company_details' => 'Uw bedrijf (:account) is verwijderd', + 'deleted_account_details' => 'Uw account (:account) is verwijderd', 'alipay' => 'Alipay', 'sofort' => 'Sofort', @@ -2417,11 +2417,11 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'name_without_special_characters' => 'Geef een naam op met enkel letters van a-z en spaties', 'enable_alipay' => 'Accepteer Alipay', 'enable_sofort' => 'Accepteer Europese banktransacties', - 'stripe_alipay_help' => 'Deze gateways moeten ook worden geactiveerd in :link.', + 'stripe_alipay_help' => 'Deze betaalprovider moeten ook worden geactiveerd in :link.', 'calendar' => 'Kalender', - 'pro_plan_calendar' => ':link om de kalender in te schakelen door lid te worden van het Pro Plan', + 'pro_plan_calendar' => ':link om de kalender in te schakelen door te abonneren op het Pro-abonnement', - 'what_are_you_working_on' => 'Waar werk je aan?', + 'what_are_you_working_on' => 'Waar werkt u aan?', 'time_tracker' => 'Tijdregistratie', 'refresh' => 'Verversen', 'filter_sort' => 'Filter/Sorteer', @@ -2449,7 +2449,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'time_hr' => 'uur', 'time_hrs' => 'uren', 'clear' => 'Wis', - 'warn_payment_gateway' => 'Opmerking: voor het accepteren van online betalingen is een betalingsgateway vereist. :link om er een toe te voegen.', + 'warn_payment_gateway' => 'Opmerking: voor het accepteren van online betalingen is een betaalprovider vereist. :link om er een toe te voegen.', 'task_rate' => 'Taak tarief', 'task_rate_help' => 'Stel het standaardtarief in voor gefactureerde taken.', 'past_due' => 'Verlopen', @@ -2465,7 +2465,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'recover' => 'Herstel', 'apply' => 'Toepassen', 'recover_white_label_header' => 'Herstel whitelabel-licentie', - 'apply_white_label_header' => 'Whitelabel licentie toepassen', + 'apply_white_label_header' => 'Whitelabel-licentie toepassen', 'videos' => 'Video\'s', 'video' => 'Video', 'return_to_invoice' => 'Terug naar factuur', @@ -2475,7 +2475,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'custom_value1' => 'Aangepaste waarde 1', 'custom_value2' => 'Aangepaste waarde 2', 'enable_two_factor' => 'Tweestaps-authenticatie', - 'enable_two_factor_help' => 'Gebruik je telefoon om je identiteit te bevestigen bij het inloggen', + 'enable_two_factor_help' => 'Gebruik uw telefoon om uw identiteit te bevestigen bij het inloggen', 'two_factor_setup' => 'Tweestaps-authenticatie instellen', 'two_factor_setup_help' => 'Scan de streepjescode met een :link compatibele app.', 'one_time_password' => 'Eenmalig wachtwoord', @@ -2494,18 +2494,18 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'default' => 'Standaard', 'shipping_address' => 'Leveringsadres', 'bllling_address' => 'Factuuradres', - 'billing_address1' => 'Facturatie straat', - 'billing_address2' => 'Facturatie Apt/Suite', - 'billing_city' => 'Facturatiestad', - 'billing_state' => 'Facturatie Staat/Provincie', - 'billing_postal_code' => 'Facturatie Postcode', - 'billing_country' => 'Facturatieland', - 'shipping_address1' => 'Leveringsstraat', - 'shipping_address2' => 'Leverings Apt/Suite', - 'shipping_city' => 'Leveringsstad', - 'shipping_state' => 'Leverings Staat/Provincie', - 'shipping_postal_code' => 'Leverings Postcode', - 'shipping_country' => 'Leveringsland', + 'billing_address1' => 'Straat factuuradres', + 'billing_address2' => 'Appartement/busnr. factuuradres', + 'billing_city' => 'Stad factuuradres', + 'billing_state' => 'Staat/provincie factuuradres', + 'billing_postal_code' => 'Postcode factuuradres', + 'billing_country' => 'Land factuuradres', + 'shipping_address1' => 'Straat leveringsadres', + 'shipping_address2' => 'Appartement/busnr. leveringsadres', + 'shipping_city' => 'Stad leveringsadres', + 'shipping_state' => 'Staat/provincie leveringsadres', + 'shipping_postal_code' => 'Postcode leveringsadres', + 'shipping_country' => 'Land leveringsadres', 'classify' => 'Classificeren', 'show_shipping_address_help' => 'Vereisen dat de klant zijn leveringsadres opgeeft', 'ship_to_billing_address' => 'Verzend naar factuuradres', @@ -2521,13 +2521,13 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'invalid_one_time_password' => 'Eenmalig wachtwoord ongeldig', 'apple_pay' => 'Apple/Google Pay', 'enable_apple_pay' => 'Accepteer Apple Pay en Pay met Google', - 'requires_subdomain' => 'Deze betalingsmethode vereist dat een :link.', + 'requires_subdomain' => 'Deze betaalmethode vereist dat een :link.', 'subdomain_is_set' => 'subdomein is ingesteld', 'verification_file' => 'Verificatiebestand', 'verification_file_missing' => 'Het verificatiebestand is nodig om betalingen te accepteren.', 'apple_pay_domain' => 'Gebruik :domain als het domein in :link.', 'apple_pay_not_supported' => 'Sorry, Apple/Google Pay wordt niet ondersteund door uw browser', - 'optional_payment_methods' => 'Optionele betalingsmethodes', + 'optional_payment_methods' => 'Optionele betaalmethoden', 'add_subscription' => 'Abonnement toevoegen', 'target_url' => 'Doel', 'target_url_help' => 'Wanneer de geselecteerde gebeurtenis plaatsvindt, zal de app de entiteit op de doel-URL posten.', @@ -2562,7 +2562,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'project_error_multiple_clients' => 'De projecten kunnen niet tot meerdere klanten behoren', 'invoice_project' => 'Factureer project', 'module_recurring_invoice' => 'Terugkerende facturen', - 'module_credit' => 'Creditnota\'s', + 'module_credit' => 'Creditfacturen', 'module_quote' => 'Offertes & voorstellen', 'module_task' => 'Taken & projecten', 'module_expense' => 'Uitgaven & leveranciers', @@ -2571,7 +2571,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'send_client_reminders' => 'Verzend e-mailherinneringen', 'can_view_tasks' => 'Taken zijn zichtbaar in de portaal', 'is_not_sent_reminders' => 'Herinneringen worden niet verzonden', - 'promotion_footer' => 'Uw promotie verloopt binnenkort, :link om nu te upgraden.', + 'promotion_footer' => 'Uw korting verloopt binnenkort, :link om nu te upgraden.', 'unable_to_delete_primary' => 'Opmerking: om dit bedrijf te verwijderen, verwijdert u eerst alle gekoppelde bedrijven.', 'please_register' => 'Gelieve uw account te registreren', 'processing_request' => 'Aanvraag wordt verwerkt', @@ -2580,8 +2580,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'inclusive_taxes_help' => 'Neem belastingen op in de uitgave', 'inclusive_taxes_notice' => 'Deze instelling kan niet worden gewijzigd nadat een factuur is aangemaakt.', 'inclusive_taxes_warning' => 'Waarschuwing: bestaande facturen moeten opnieuw worden opgeslagen', - 'copy_shipping' => 'Levering kopiëren', - 'copy_billing' => 'Facturatie kopiëren', + 'copy_shipping' => 'Leveringsadres kopiëren', + 'copy_billing' => 'Factuuradres kopiëren', 'quote_has_expired' => 'De offerte is verlopen, neem contact op met de verkoper.', 'empty_table_footer' => '0 tot 0 van 0 vermeldingen tonen', 'do_not_trust' => 'Dit apparaat niet onthouden', @@ -2605,7 +2605,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'signature_on_invoice_help' => 'Voeg de volgende code toe om de handtekening van de klant op de PDF weer te geven.', 'signature_on_pdf' => 'Weergeven op PDF', 'signature_on_pdf_help' => 'Toon de handtekening van de klant op de factuur/offerte PDF.', - 'expired_white_label' => 'De whitelabel licentie is verlopen', + 'expired_white_label' => 'De whitelabel-licentie is verlopen', 'return_to_login' => 'Terug naar login', 'convert_products_tip' => 'Opmerking: voeg een :link met de naam ":name" toe om de wisselkoers te zien.', 'amount_greater_than_balance' => 'Het bedrag is groter dan het factuursaldo, er wordt een creditfactuur aangemaakt met het resterende bedrag.', @@ -2692,15 +2692,15 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'no_assets' => 'Geen afbeeldingen, slepen om te uploaden', 'add_image' => 'Afbeelding toevoegen', 'select_image' => 'Afbeelding selecteren', - 'upgrade_to_upload_images' => 'Upgrade to the Enterprise Plan to upload files & images', + 'upgrade_to_upload_images' => 'Upgrade naar het Enterprise-abonnement om bestanden en afbeeldingen te uploaden', 'delete_image' => 'Afbeelding verwijderen', - 'delete_image_help' => 'Waarschuwing: als je de afbeelding verwijdert, wordt deze uit alle voorstellen verwijderd.', + 'delete_image_help' => 'Waarschuwing: als u de afbeelding verwijdert, dan wordt deze uit alle voorstellen verwijderd.', 'amount_variable_help' => 'Opmerking: Het veld $amount op de factuur wordt gebruikt als gedeeltelijke betaling als dit is ingesteld, anders wordt het factuur saldo gebruikt.', 'taxes_are_included_help' => 'Opmerking: inbegrepen heffingen/belastingen zijn ingeschakeld.', 'taxes_are_not_included_help' => 'Opmerking: inbegrepen heffingen/belastingen zijn niet ingeschakeld.', 'change_requires_purge' => 'Het aanzetten van deze instelling vereist :link van de accountgegevens.', 'purging' => 'opschonen', - 'warning_local_refund' => 'De terugbetaling zal worden geregistreerd in de app, maar zal NIET worden verwerkt door de betalingsgateway.', + 'warning_local_refund' => 'De terugbetaling zal worden geregistreerd in de app, maar zal NIET worden verwerkt door de betaalprovider.', 'email_address_changed' => 'E-mailadres is gewijzigd', 'email_address_changed_message' => 'Het e-mailadres voor uw account is gewijzigd van :old_email in :new_email.', 'test' => 'Test', @@ -2726,17 +2726,17 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'group' => 'Groep', 'subgroup' => 'Subgroep', 'unset' => 'Unset', - 'received_new_payment' => 'Je hebt een nieuwe betaling ontvangen!', + 'received_new_payment' => 'U hebt een nieuwe betaling ontvangen!', 'slack_webhook_help' => 'Ontvang betalingsmeldingen via :link.', 'slack_incoming_webhooks' => 'Slack incoming webhooks', 'accept' => 'Accepteer', 'accepted_terms' => 'Nieuwe servicevoorwaarden geaccepteerd', 'invalid_url' => 'Ongeldige URL', - 'workflow_settings' => 'Workflow instellingen', + 'workflow_settings' => 'Workflowinstellingen', 'auto_email_invoice' => 'Automatisch e-mailen', 'auto_email_invoice_help' => 'Converteer een offerte automatisch naar een factuur wanneer deze goedgekeurd is.', 'auto_archive_invoice' => 'Automatisch archiveren', - 'auto_archive_invoice_help' => 'Archiveer facturen automatisch indien betaald', + 'auto_archive_invoice_help' => 'Facturen automatisch archiveren bij betaling', 'auto_archive_quote' => 'Automatisch archiveren', 'auto_archive_quote_help' => 'Archiveer offertes automatisch indien omgezet naar factuur', 'require_approve_quote' => 'Verplicht goedkeuring offerte', @@ -2751,7 +2751,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'purge_client_warning' => 'Alle gerelateerde gegevens (facturen, taken, uitgaven, documenten, enz.) worden ook gewist.', 'clone_product' => 'Dupliceer product', 'item_details' => 'Onderdeel details', - 'send_item_details_help' => 'Verzend regelitemdetails naar de betalingsgateway.', + 'send_item_details_help' => 'Deel factuurregels met de betaalprovider.', 'view_proposal' => 'Toon voorstel', 'view_in_portal' => 'Toon in portaal', 'cookie_message' => 'Deze website maakt gebruik van cookies om ervoor te zorgen dat u de beste ervaring op onze website krijgt.', @@ -2768,7 +2768,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'project_field' => 'Project veld', 'expense_field' => 'Uitgave veld', 'vendor_field' => 'Leverancier veld', - 'company_field' => 'Bedrijf veld', + 'company_field' => 'Bedrijfsveld', 'invoice_field' => 'Factuur veld', 'invoice_surcharge' => 'Factuurkost', 'custom_task_fields_help' => 'Voeg een veld toe bij het maken van een taak.', @@ -2793,9 +2793,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'proposal_editor' => 'voorstel editor', 'background' => 'Achtergrond', 'guide' => 'Gids', - 'gateway_fee_item' => 'Heffingsitem Gateway', - 'gateway_fee_description' => 'Heffingstoeslag Gateway', - 'gateway_fee_discount_description' => 'Heffingskorting Gateway', + 'gateway_fee_item' => 'Toeslagdetails betaalprovider', + 'gateway_fee_description' => 'Toeslag betaalprovider', + 'gateway_fee_discount_description' => 'Heffingskorting betaalprovider', 'show_payments' => 'Toon betalingen', 'show_aging' => 'Toon toekomstige', 'reference' => 'Referentie', @@ -2849,7 +2849,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'refresh_data' => 'Gegevens verversen', 'blank_contact' => 'Leeg contact', 'no_records_found' => 'Geen gegevens gevonden', - 'industry' => 'Industrie', + 'industry' => 'Sector', 'size' => 'Grootte', 'net' => 'Betaaltermijn', 'show_tasks' => 'Toon taken', @@ -2898,25 +2898,25 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'local_part_unavailable' => 'Naam reeds in gebruik', 'local_part_available' => 'Naam beschikbaar', 'local_part_invalid' => 'Ongeldige naam (alleen alfanumeriek, geen spaties', - 'local_part_help' => 'Personaliseer het eerste deel van het inkomende e-mailadres, vb. YOUR_NAME@support.invoiceninja', + 'local_part_help' => 'Personaliseer het eerste deel van het inkomende e-mailadres, bijv. YOUR_NAME@support.invoiceninja', 'from_name_help' => 'De \'van\'-naam is de herkenbare afzender die wordt getoond in plaats van het e-mailadres, zoals Helpdesk', - 'local_part_placeholder' => 'JOUW_NAAM', + 'local_part_placeholder' => 'UW_NAAM', 'from_name_placeholder' => 'Support centrum', 'attachments' => 'Bijlagen', 'client_upload' => 'Klant uploads', 'enable_client_upload_help' => 'Laat klanten documenten/bijlagen uploaden', - 'max_file_size_help' => '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', 'mime_types' => 'MIME-types', 'mime_types_placeholder' => '.pdf, .docx, .jpg', 'mime_types_help' => 'Komma-gescheiden lijst met toegestane MIME-types, laat leeg voor alle', - 'ticket_number_start_help' => 'Ticket number must be greater than the current ticket number', - 'new_ticket_template_id' => 'New ticket', - 'new_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a new ticket is created', - 'update_ticket_template_id' => 'Updated ticket', - 'update_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is updated', - 'close_ticket_template_id' => 'Closed ticket', - 'close_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is closed', + 'ticket_number_start_help' => 'Ticketnummer moet hoger of gelijk zijn aan het huidige ticketnummer', + 'new_ticket_template_id' => 'Nieuw ticket', + 'new_ticket_autoresponder_help' => 'Door een sjabloon te selecteren wordt er, zodra een nieuw ticket is aangemaakt, een automatische respons gestuurd naar de klant of contactpersoon', + 'update_ticket_template_id' => 'Bijgewerkt ticket', + 'update_ticket_autoresponder_help' => 'Door een sjabloon te selecteren wordt er, zodra een ticket is bijgewerkt, een automatische respons gestuurd naar de klant of contactpersoon', + 'close_ticket_template_id' => 'Gesloten ticket', + 'close_ticket_autoresponder_help' => 'Door een sjabloon te selecteren wordt er, zodra een ticket is gesloten, een automatische respons gestuurd naar de klant of contactpersoon', 'default_priority' => 'Prioriteit', 'alert_new_comment_id' => 'Nieuwe opmerking', 'update_ticket_notification_list' => 'Additionele notificaties bij nieuwe opmerkingen', @@ -2945,7 +2945,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'hosted_login' => 'Hosted login', 'selfhost_login' => 'Self-Host login', 'google_login' => 'Google Login', - 'thanks_for_patience' => 'Bedankt voor uw geduld terwijl we werken aan de implementatie van deze functies.

    We hopen ze in de komende maanden af te ronden.

    Tot die tijd blijven wij de stichting steunen', + 'thanks_for_patience' => 'Bedankt voor uw geduld terwijl we werken aan het implementeren van deze functies.

    We hopen de functionaliteit in de komende maanden toe te kunnen voegen.

    Tot die tijd ondersteunen wij de', 'legacy_mobile_app' => 'oude mobiele app', 'today' => 'Vandaag', 'current' => 'Huidige', @@ -2967,8 +2967,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'show_product_notes_help' => 'Voeg de beschrijving en kosten toe aan de productkeuzelijst', 'important' => 'Belangrijk', 'thank_you_for_using_our_app' => 'Bedankt voor het gebruik van onze app!', - 'if_you_like_it' => 'Als je het leuk vindt alsjeblieft ', - 'to_rate_it' => 'om een score te geven.', + 'if_you_like_it' => 'Als u het waardeert alstublieft ', + 'to_rate_it' => 'om een beoordeling te geven.', 'average' => 'Gemiddeld', 'unapproved' => 'Afgekeurd', 'authenticate_to_change_setting' => 'Gelieve te authenticeren om deze instelling te wijzigen', @@ -2976,7 +2976,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'authenticate' => 'Authenticeer', 'please_authenticate' => 'Gelieve te authenticeren', 'biometric_authentication' => 'Biometrische authenticatie', - 'auto_start_tasks' => 'Automatisch Startende Taken', + 'auto_start_tasks' => 'Automatisch startende taken', 'budgeted' => 'Begroot', 'please_enter_a_name' => 'Geef a.u.b. een naam op', 'click_plus_to_add_time' => 'Klik + om tijd toe te voegen', @@ -3007,19 +3007,19 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'back' => 'Terug', 'past_purchases' => 'Voorbije aankopen', 'annual_subscription' => 'Jaarlijks abonnement', - 'pro_plan' => 'Pro Plan', - 'enterprise_plan' => 'Enterprise Plan', + 'pro_plan' => 'Pro-abonnement', + 'enterprise_plan' => 'Enterprise-abonnement', 'count_users' => ':count gebruikers', 'upgrade' => 'Upgrade', - 'please_enter_a_first_name' => 'Vul een voornaam in aub', - 'please_enter_a_last_name' => 'Vul een naam in aub', + 'please_enter_a_first_name' => 'Vul een voornaam in a.u.b.', + 'please_enter_a_last_name' => 'Vul een naam in a.u.b.', 'please_agree_to_terms_and_privacy' => 'Ga akkoord met de servicevoorwaarden en het privacybeleid om een account aan te maken.', 'i_agree_to_the' => 'Ik ga akkoord met', 'terms_of_service_link' => 'de servicevoorwaarden', 'privacy_policy_link' => 'het privacybeleid', 'view_website' => 'Bekijk website', 'create_account' => 'Account aanmaken', - 'email_login' => 'Email login', + 'email_login' => 'E-mail login', 'late_fees' => 'Late vergoedingen', 'payment_number' => 'Betalingsnummer', 'before_due_date' => 'Voor de vervaldatum', @@ -3042,8 +3042,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'portal_mode' => 'portaalmodus', 'attach_pdf' => 'PDF bijvoegen', 'attach_documents' => 'Document bijvoegen', - 'attach_ubl' => 'Attach UBL/E-Invoice', - 'email_style' => 'Email opmaak', + 'attach_ubl' => 'UBL en/of e-factuur bijvoegen', + 'email_style' => 'E-mail opmaak', 'processed' => 'Verwerkt', 'fee_amount' => 'Vergoedingsbedrag', 'fee_percent' => 'Vergoedingspercentage', @@ -3055,15 +3055,15 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'deleted_tax_rate' => 'De BTW heffing is verwijderd', 'restored_tax_rate' => 'De BTW heffing is teruggezet', 'provider' => 'Provider', - 'company_gateway' => 'Betalingsgateway', - 'company_gateways' => 'Betalingsgateway', - 'new_company_gateway' => 'Nieuwe instantie aanmaken', - 'edit_company_gateway' => 'Huidige instantie bewerken', - 'created_company_gateway' => 'De nieuwe instantie is aangemaakt', - 'updated_company_gateway' => 'De nieuwe instantie is bijgewerkt', - 'archived_company_gateway' => 'De nieuwe instantie is gearchiveerd', - 'deleted_company_gateway' => 'De nieuwe instantie is verwijderd', - 'restored_company_gateway' => 'De nieuwe instantie is hersteld', + 'company_gateway' => 'Betaalprovider', + 'company_gateways' => 'Betaalproviders', + 'new_company_gateway' => 'Nieuwe betaalprovider aanmaken', + 'edit_company_gateway' => 'Huidige betaalprovider bewerken', + 'created_company_gateway' => 'De nieuwe betaalprovider is aangemaakt', + 'updated_company_gateway' => 'De nieuwe betaalprovider is bijgewerkt', + 'archived_company_gateway' => 'De nieuwe betaalprovider is gearchiveerd', + 'deleted_company_gateway' => 'De nieuwe betaalprovider is verwijderd', + 'restored_company_gateway' => 'De nieuwe betaalprovider is hersteld', 'continue_editing' => 'Bewerk verder', 'default_value' => 'Standaard waarde', 'currency_format' => 'Munt formaat', @@ -3094,7 +3094,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'device_settings' => 'Apparaatinstellingen', 'credit_cards_and_banks' => 'Credit Cards & Banken', 'price' => 'Prijs', - 'email_sign_up' => 'Aanmelden voor email', + 'email_sign_up' => 'Aanmelden voor e-mail', 'google_sign_up' => 'Aanmelden bij Google', 'sign_up_with_google' => 'Aanmelden met Google', 'long_press_multiselect' => 'Lang indrukken multiselect', @@ -3126,10 +3126,10 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'task2' => 'Aangepaste Taak 2', 'task3' => 'Aangepaste Taak 3', 'task4' => 'Aangepaste Taak 4', - 'project1' => 'Aangepast Project 1', - 'project2' => 'Aangepast Project 2', - 'project3' => 'Aangepast Project 3', - 'project4' => 'Aangepast Project 4', + 'project1' => 'Aangepast project 1', + 'project2' => 'Aangepast project 2', + 'project3' => 'Aangepast project 3', + 'project4' => 'Aangepast project 4', 'expense1' => 'Aangepaste Uitgave 1', 'expense2' => 'Aangepaste Uitgave 2', 'expense3' => 'Aangepaste Uitgave 3', @@ -3190,7 +3190,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'generate_number' => 'Genereer nummer', 'when_saved' => 'Als opgeslagen', 'when_sent' => 'Als verzonden', - 'select_company' => 'Selecteer Bedrijf', + 'select_company' => 'Selecteer bedrijf', 'float' => 'Float', 'collapse' => 'Inklappen', 'show_or_hide' => 'Laten zien/Verbergen', @@ -3217,7 +3217,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'invoice_tax' => 'Factuur BTW-tarief', 'line_item_tax' => 'Regelitem BTW-tarief', 'inclusive_taxes' => 'Inclusief belasting', - 'invoice_tax_rates' => 'Factuur belastingtarief', + 'invoice_tax_rates' => 'Belastingtarief facturen', 'item_tax_rates' => 'Product belastingtarief', 'configure_rates' => 'Tarieven instellen', 'tax_settings_rates' => 'BTW-tarieven', @@ -3238,7 +3238,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'activity_57' => 'Systeem kon de factuur niet mailen :invoice', 'custom_value3' => 'Aangepaste waarde 3', 'custom_value4' => 'Aangepaste waarde 4', - 'email_style_custom' => 'Aangepaste Email Stijl', + 'email_style_custom' => 'Aangepaste e-mailstijl', 'custom_message_dashboard' => 'Aangepast bericht Dashboard', 'custom_message_unpaid_invoice' => 'Aangepast bericht Onbetaalde Factuur', 'custom_message_paid_invoice' => 'Aangepast bericht Betaalde Factuur', @@ -3279,29 +3279,29 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'client_country' => 'Land van de klant', 'client_is_active' => 'Klant is actief', 'client_balance' => 'Klanten balans', - 'client_address1' => 'Klant straat', - 'client_address2' => 'Klant apt/suite', - 'client_shipping_address1' => 'Klant leveringsadres', - 'client_shipping_address2' => 'Klant leverings Apt/Suite', + 'client_address1' => 'Straat klant', + 'client_address2' => 'Appartement/busnr. klant', + 'client_shipping_address1' => 'Leveringsadres klant', + 'client_shipping_address2' => 'Appartement/busnr. leveringsadres klant', 'tax_rate1' => 'BTW-tarief 1', 'tax_rate2' => 'BTW-tarief 2', 'tax_rate3' => 'BTW-tarief 3', 'archived_at' => 'Gearchiveerd op', 'has_expenses' => 'Heeft uitgaves', - 'custom_taxes1' => 'Aangepaste Belastingen 1', - 'custom_taxes2' => 'Aangepaste Belastingen 2', - 'custom_taxes3' => 'Aangepaste Belastingen 3', - 'custom_taxes4' => 'Aangepaste Belastingen 4', - 'custom_surcharge1' => 'Aangepaste Toeslag 1', - 'custom_surcharge2' => 'Aangepaste Toeslag 2', - 'custom_surcharge3' => 'Aangepaste Toeslag 3', - 'custom_surcharge4' => 'Aangepaste Toeslag 4', + 'custom_taxes1' => 'Aangepaste belastingen 1', + 'custom_taxes2' => 'Aangepaste belastingen 2', + 'custom_taxes3' => 'Aangepaste belastingen 3', + 'custom_taxes4' => 'Aangepaste belastingen 4', + 'custom_surcharge1' => 'Aangepaste toeslag 1', + 'custom_surcharge2' => 'Aangepaste toeslag 2', + 'custom_surcharge3' => 'Aangepaste toeslag 3', + 'custom_surcharge4' => 'Aangepaste toeslag 4', 'is_deleted' => 'Is verwijderd', 'vendor_city' => 'Stad van de klant', 'vendor_state' => 'Leverancier provincie', 'vendor_country' => 'Land van de verkoper', - 'credit_footer' => 'Krediet voettekst', - 'credit_terms' => 'Kredietvoorwaarden', + 'credit_footer' => 'Voettekst creditfactuur', + 'credit_terms' => 'Voorwaarden creditfactuur', 'untitled_company' => 'Naamloos bedrijf', 'added_company' => 'Bedrijf toegevoegd', 'supported_events' => 'Ondersteunde gebeurtenissen', @@ -3313,7 +3313,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'saved_design' => 'Ontwerp opgeslagen', 'client_details' => 'Klantgegevens', 'company_address' => 'Bedrijfs-adres', - 'quote_details' => 'Offerte Details', + 'quote_details' => 'Details offerte', 'credit_details' => 'Kredietgegevens', 'product_columns' => 'Product kolommen', 'task_columns' => 'Taak kolommen', @@ -3322,20 +3322,20 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'owned' => 'Eigendom', 'payment_success' => 'Betaling is gelukt', 'payment_failure' => 'Betalingsfout', - 'quote_sent' => 'Offerte Verzonden', - 'credit_sent' => 'Factuur verzonden', + 'quote_sent' => 'Offerte verzonden', + 'credit_sent' => 'Creditfactuur verzonden', 'invoice_viewed' => 'Factuur bekeken', - 'quote_viewed' => 'Offerte Bekeken', - 'credit_viewed' => 'Krediet bekeken', - 'quote_approved' => 'Offerte Goedgekeurd', + 'quote_viewed' => 'Offerte bekeken', + 'credit_viewed' => 'Creditfactuur bekeken', + 'quote_approved' => 'Offerte goedgekeurd', 'receive_all_notifications' => 'Ontvang alle notificaties', 'purchase_license' => 'Licentie aanschaffen', 'enable_modules' => 'Modules inschakelen', 'converted_quote' => 'Offerte omgezet', - 'credit_design' => 'Krediet ontwerp', + 'credit_design' => 'Ontwerp creditfactuur', 'includes' => 'Inclusief', 'css_framework' => 'CSS Framework', - 'custom_designs' => 'Aangepaste Ontwerpen', + 'custom_designs' => 'Aangepaste ontwerpen', 'designs' => 'Ontwerpen', 'new_design' => 'Nieuw ontwerp', 'edit_design' => 'Ontwerp aanpassen', @@ -3345,31 +3345,31 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'deleted_design' => 'Ontwerp verwijderd', 'removed_design' => 'Ontwerp verwijderd', 'restored_design' => 'Ontwerp teruggehaald', - 'recurring_tasks' => 'Terugkerende Taken', - 'removed_credit' => 'Krediet is verwijders', + 'recurring_tasks' => 'Terugkerende taken', + 'removed_credit' => 'Creditfactuur is verwijderd', 'latest_version' => 'Laatste versie', 'update_now' => 'Nu updaten', - 'a_new_version_is_available' => 'Een nieuwe versie van de web applicatie is beschikbaar', + 'a_new_version_is_available' => 'Een nieuwe versie van de webapplicatie is beschikbaar', 'update_available' => 'Update beschikbaar', - 'app_updated' => 'Update met succes voltooid', + 'app_updated' => 'Update is gelukt', 'integrations' => 'Integraties', 'tracking_id' => 'Tracering Id', 'slack_webhook_url' => 'Slack Webhook URL', 'partial_payment' => 'Gedeeltelijke betaling', 'partial_payment_email' => 'E-mail voor gedeeltelijke betaling', - 'clone_to_credit' => 'Klonen naar krediet', - 'emailed_credit' => 'Krediet is verzonden', - 'marked_credit_as_sent' => 'Krediet is gemarkeerd als verzonden', + 'clone_to_credit' => 'Klonen naar creditfactuur', + 'emailed_credit' => 'Creditfactuur is verzonden', + 'marked_credit_as_sent' => 'Creditfactuur is gemarkeerd als verzonden', 'email_subject_payment_partial' => 'E-mail gedeeltelijke betalingsonderwerp', 'is_approved' => 'Is goedgekeurd', - 'migration_went_wrong' => 'Oeps, er is iets misgegaan! Zorg dat je een Invoice Ninja V5 instance hebt opgezet voordat je met de migratie begint.', + 'migration_went_wrong' => 'Oeps, er is iets misgegaan! Zorg dat u een Invoice Ninja V5 instance hebt opgezet voordat u met de migratie begint.', 'cross_migration_message' => 'Migratie tussen accounts is niet toegestaan. Lees er hier meer over: https://invoiceninja.github.io/docs/migration/#troubleshooting', - 'email_credit' => 'E-mail Krediet', + 'email_credit' => 'E-mail creditfactuur', 'client_email_not_set' => 'Er is geen e-mailadres ingesteld voor de klant', 'ledger' => 'Grootboek', 'view_pdf' => 'Bekijk PDF', 'all_records' => 'Alle gegevens', - 'owned_by_user' => 'Owned door gebruiker', + 'owned_by_user' => 'Eigendom van gebruiker', 'credit_remaining' => 'Resterend krediet', 'use_default' => 'Gebruik standaard', 'reminder_endless' => 'Eindeloze herinneringen', @@ -3381,7 +3381,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'removed_payment_term' => 'betalingstermijn met succes verwijderd', 'restored_payment_term' => 'betalingstermijn met succes hersteld', 'full_width_editor' => 'Volledige breedte-editor', - 'full_height_filter' => 'Volledige Hoogte Filter', + 'full_height_filter' => 'Volledige hoogte-filter', 'email_sign_in' => 'Log in met e-mail', 'change' => 'Aanpassen', 'change_to_mobile_layout' => 'Verander naar de mobiele layout?', @@ -3391,9 +3391,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'cancelled' => 'Geannuleerd', 'quote_amount' => 'Offertebedrag', 'hosted' => 'Gehost', - 'selfhosted' => 'Zelf-Gehost', + 'selfhosted' => 'Zelf-gehost', 'hide_menu' => 'Verberg menu', - 'show_menu' => 'Toon Menu', + 'show_menu' => 'Toon menu', 'partially_refunded' => 'Gedeeltelijk terugbetaald', 'search_documents' => 'Documenten zoeken', 'search_designs' => 'Ontwerpen zoeken', @@ -3401,17 +3401,17 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'search_clients' => 'Klanten zoeken', 'search_products' => 'Producten zoeken', 'search_quotes' => 'Offertes zoeken', - 'search_credits' => 'Zoek Krediet', - 'search_vendors' => 'Zoek Leveranciers', - 'search_users' => 'Zoek Gebruikers', - 'search_tax_rates' => 'Zoek Belastingstarieven', - 'search_tasks' => 'Zoek Taken', - 'search_settings' => 'Zoek Instellingen', - 'search_projects' => 'Zoek Projecten', - 'search_expenses' => 'Zoek Uitgaven', - 'search_payments' => 'Zoek Betalingen', - 'search_groups' => 'Zoek Groepen', - 'search_company' => 'Zoek Bedrijf', + 'search_credits' => 'Zoek creditfactuur', + 'search_vendors' => 'Zoek leveranciers', + 'search_users' => 'Zoek gebruikers', + 'search_tax_rates' => 'Zoek belastingstarieven', + 'search_tasks' => 'Zoek taken', + 'search_settings' => 'Zoek instellingen', + 'search_projects' => 'Zoek projecten', + 'search_expenses' => 'Zoek uitgaven', + 'search_payments' => 'Zoek betalingen', + 'search_groups' => 'Zoek groepen', + 'search_company' => 'Zoek bedrijf', 'cancelled_invoice' => 'Factuur succesvol geannuleerd', 'cancelled_invoices' => 'Facturen succesvol geannuleerd', 'reversed_invoice' => 'Factuur succesvol teruggedraaid', @@ -3423,9 +3423,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'activity_59' => ':gebruiker heeft factuur :invoice geannuleerd', 'payment_reconciliation_failure' => 'Koppelen mislukt', 'payment_reconciliation_success' => 'Koppelen gelukt', - 'gateway_success' => 'Gateway geslaagd', - 'gateway_failure' => 'Gateway gefaald', - 'gateway_error' => 'Gateway fout', + 'gateway_success' => 'Betaalprovider geslaagd', + 'gateway_failure' => 'Betaalprovider gefaald', + 'gateway_error' => 'Betaalprovider fout', 'email_send' => 'E-mail verzonden', 'email_retry_queue' => 'E-mail wachtrij voor opnieuw versturen', 'failure' => 'Fout', @@ -3442,7 +3442,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'reminder3_sent' => '3de herinnering verstuurd', 'reminder_last_sent' => 'Laatste herinnering verstuurd', 'pdf_page_info' => 'Pagina :current van :total', - 'emailed_credits' => 'Creditnota is succesvol gemaild', + 'emailed_credits' => 'Creditfactuur is succesvol gemaild', 'view_in_stripe' => 'Bekijk in Stripe', 'rows_per_page' => 'Regels per pagina', 'apply_payment' => 'Betaling toepassen', @@ -3457,7 +3457,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'last_login_at' => 'Voor het laatst ingelogd', 'company_key' => 'Bedrijfssleutel', 'storefront' => 'Storefront', - 'storefront_help' => 'Activeer third-party applicaties om facturen te maken', + 'storefront_help' => 'Sta applicaties van derden toe om facturen aan te maken', 'count_records_selected' => ':count records geselecteerd', 'count_record_selected' => ':count record geselecteerd', 'client_created' => 'Klant aangemaakt', @@ -3487,11 +3487,11 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'expires_on' => 'Verloopt op', 'show_sidebar' => 'Laat zijbalk zien', 'hide_sidebar' => 'Verberg zijbalk', - 'event_type' => 'Event Type', + 'event_type' => 'Eventtype', 'copy' => 'Kopieer', - 'must_be_online' => 'Herstart alsjeblieft de applicatie wanneer er verbinding is met het internet', + 'must_be_online' => 'Herstart alstublieft de applicatie wanneer er verbinding is met het internet', 'crons_not_enabled' => 'De crons moeten geactiveerd worden', - 'api_webhooks' => 'API Webhooks', + 'api_webhooks' => 'API-webhooks', 'search_webhooks' => 'Zoek :count webhooks', 'search_webhook' => 'Zoek 1 webhook', 'webhook' => 'Webhook', @@ -3509,16 +3509,16 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'new_token' => 'Nieuwe token', 'removed_token' => 'Token succesvol verwijderd', 'restored_token' => 'Token succesvol hersteld', - 'client_registration' => 'Klant registratie', + 'client_registration' => 'Klantregistratie', 'client_registration_help' => 'Zelfregistratie voor klanten in het portaal toestaan', - 'customize_and_preview' => 'Pas aan & Weergeven', + 'customize_and_preview' => 'Pas aan & weergeven', 'search_document' => 'Zoek 1 document', 'search_design' => 'Zoek 1 ontwerp', 'search_invoice' => 'Zoek 1 factuur', 'search_client' => 'Zoek 1 klant', 'search_product' => 'Zoek 1 product', 'search_quote' => 'Zoek 1 offerte', - 'search_credit' => 'Zoek 1 krediet', + 'search_credit' => 'Zoek 1 creditfactuur', 'search_vendor' => 'Zoek 1 leverancier', 'search_user' => 'Zoek 1 gebruiker', 'search_tax_rate' => 'Zoek 1 BTW-tarief', @@ -3530,47 +3530,47 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'created_on' => 'Aangemaakt op', 'payment_status_-1' => 'Niet toegepast', 'lock_invoices' => 'Vergrendel facturen', - 'show_table' => 'Weergeef als tabel', - 'show_list' => 'Weergeef als lijst', + 'show_table' => 'Weergeven als tabel', + 'show_list' => 'Weergeven als lijst', 'view_changes' => 'Bekijk wijzigingen', 'force_update' => 'Forceer een update', 'force_update_help' => 'De applicatie draait op de laatste versie, maar wellicht zijn er nog een aantal fixes beschikbaar.', - 'mark_paid_help' => 'Volg de uitgave dat betaald is', + 'mark_paid_help' => 'Volg de uitgave die betaald is', 'mark_invoiceable_help' => 'Sta toe dat de uitgave gefactureerd kan worden', 'add_documents_to_invoice_help' => 'Maak de documenten zichtbaar voor de klant', 'convert_currency_help' => 'Stel een ruilwaarde in van de valuta', - 'expense_settings' => 'Uitgave instellingen', + 'expense_settings' => 'Uitgave-instellingen', 'clone_to_recurring' => 'Maak een kopie voor herhaling', 'crypto' => 'Crypto', - 'user_field' => 'Gebruiker Veld', + 'user_field' => 'Gebruikersveld', 'variables' => 'Variabelen', 'show_password' => 'Wachtwoord weergeven', 'hide_password' => 'Wachtwoord verbergen', 'copy_error' => 'Fout kopiëren', - 'capture_card' => 'Capture Kaart', + 'capture_card' => 'Creditcard belasten (capture)', 'auto_bill_enabled' => 'Automatisch betalen ingeschakeld', - 'total_taxes' => 'Totale belasting', + 'total_taxes' => 'Totaal belasting', 'line_taxes' => 'Regelitem belastingen', 'total_fields' => 'Totaal velden', - 'stopped_recurring_invoice' => 'Herhalend factuur succesvol stopgezet', - 'started_recurring_invoice' => 'Herhalend factuur succesvol gestart', - 'resumed_recurring_invoice' => 'Herhalend factuur succesvol hervat', - 'gateway_refund' => 'Gateway terugbetaling', - 'gateway_refund_help' => 'Verwerk een terugbetaling via de betalingsgateway', + 'stopped_recurring_invoice' => 'Terugkerende factuur succesvol stopgezet', + 'started_recurring_invoice' => 'Terugkerende factuur succesvol gestart', + 'resumed_recurring_invoice' => 'Terugkerende factuur succesvol hervat', + 'gateway_refund' => 'Terugbetaling via betaalprovider', + 'gateway_refund_help' => 'Verwerk een terugbetaling via de betaalprovider', 'due_date_days' => 'Verloopdatum', 'paused' => 'Gepauzeerd', 'day_count' => 'Dag :count', 'first_day_of_the_month' => 'Eerste dag van de maand', 'last_day_of_the_month' => 'Laatste dag van de maand', - 'use_payment_terms' => 'Gebruik betalingseisen', + 'use_payment_terms' => 'Gebruik betaalvoorwaarden', 'endless' => 'Eindeloos', - 'next_send_date' => 'Volgende verzenddatum', + 'next_send_date' => 'Eerstvolgende verzenddatum', 'remaining_cycles' => 'Resterende keren', - 'created_recurring_invoice' => 'Herhalend factuur succesvol aangemaakt', - 'updated_recurring_invoice' => 'Herhalend factuur succesvol bijgewerkt', - 'removed_recurring_invoice' => 'Herhalend factuur succesvol verwijderd', - 'search_recurring_invoice' => 'Zoek 1 herhalend factuur', - 'search_recurring_invoices' => 'Zoek :count herhalende facturen', + 'created_recurring_invoice' => 'Terugkerende factuur succesvol aangemaakt', + 'updated_recurring_invoice' => 'Terugkerende factuur succesvol bijgewerkt', + 'removed_recurring_invoice' => 'Terugkerende factuur succesvol verwijderd', + 'search_recurring_invoice' => 'Zoek 1 terugkerende factuur', + 'search_recurring_invoices' => 'Zoek :count terugkerende facturen', 'send_date' => 'Verzenddatum', 'auto_bill_on' => 'Automatische betaling aan', 'minimum_under_payment_amount' => 'Minimum onder het te betalen bedrag', @@ -3578,29 +3578,29 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'allow_over_payment_help' => 'Draag bij aan extra betalen om fooi te accepteren', 'allow_under_payment' => 'Onderbetaling toestaan', 'allow_under_payment_help' => 'Ondersteun het betalen van een minimaal gedeeltelijk / aanbetalingsbedrag', - 'test_mode' => 'Test modus', + 'test_mode' => 'Testmodus', 'calculated_rate' => 'Berekend tarief', 'default_task_rate' => 'Standaard taak tarief', 'clear_cache' => 'Maak cache leeg', - 'sort_order' => 'Sorteer volgorde', + 'sort_order' => 'Sorteervolgorde', 'task_status' => 'Status', - 'task_statuses' => 'Taak status', - 'new_task_status' => 'Nieuwe taak status', - 'edit_task_status' => 'Taak status aanpassen', - 'created_task_status' => 'Succesvol een taak status aangemaakt', - 'archived_task_status' => 'Succesvol een taak status gearchiveerd', - 'deleted_task_status' => 'Succesvol een taak status verwijderd', - 'removed_task_status' => 'Succesvol een taak status verwijderd', - 'restored_task_status' => 'Succesvol een taak status hersteld', - 'search_task_status' => 'Zoek 1 taak status', - 'search_task_statuses' => 'Zoek :count taak statussen', - 'show_tasks_table' => 'Taken tabel tonen', - 'show_tasks_table_help' => 'Weergeef de taken wanneer een factuur wordt aangemaakt', - 'invoice_task_timelog' => 'Factuur taak tijdlog', + 'task_statuses' => 'Taakstatus', + 'new_task_status' => 'Nieuwe taakstatus', + 'edit_task_status' => 'Taakstatus aanpassen', + 'created_task_status' => 'Succesvol een taakstatus aangemaakt', + 'archived_task_status' => 'Succesvol een taakstatus gearchiveerd', + 'deleted_task_status' => 'Succesvol een taakstatus verwijderd', + 'removed_task_status' => 'Succesvol een taakstatus verwijderd', + 'restored_task_status' => 'Succesvol een taakstatus hersteld', + 'search_task_status' => 'Zoek 1 taakstatus', + 'search_task_statuses' => 'Zoek :count taakstatussen', + 'show_tasks_table' => 'Takentabel tonen', + 'show_tasks_table_help' => 'Geef de taken weer zodra een factuur is aangemaakt', + 'invoice_task_timelog' => 'Tijdlogboek factuurtaken', 'invoice_task_timelog_help' => 'Voeg de tijd omschrijvingen toe aan de factuur producten', 'auto_start_tasks_help' => 'Start taken voordat het wordt opgeslagen', 'configure_statuses' => 'Status instellen', - 'task_settings' => 'Taak instellingen', + 'task_settings' => 'Taakinstellingen', 'configure_categories' => 'Categorieën instellen', 'edit_expense_category' => 'Bewerk uitgavencategorie', 'removed_expense_category' => 'De uitgavencategorie is verwijderd', @@ -3610,7 +3610,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'show_option' => 'Toon optie', 'negative_payment_error' => 'Het kredietbedrag mag niet hoger zijn als het te betalen bedrag', 'should_be_invoiced_help' => 'Maak het mogelijk de uitgave te factureren', - 'configure_gateways' => 'Configureer Gateways', + 'configure_gateways' => 'Configureer betaalproviders', 'payment_partial' => 'Gedeeltelijke betaling', 'is_running' => 'Word uitgevoerd', 'invoice_currency_id' => 'Factuur valuta ID', @@ -3628,9 +3628,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'company_disabled_warning' => 'Waarschuwing: dit bedrijf is nog niet geactiveerd', 'late_invoice' => 'Late factuur', 'expired_quote' => 'Verlopen offerte', - 'remind_invoice' => 'Herinnering Factuur', - 'client_phone' => 'Klant telefoon', - 'required_fields' => 'Verreisde velden', + 'remind_invoice' => 'Stuur factuurherinnering', + 'client_phone' => 'Telefoon klant', + 'required_fields' => 'Vereiste velden', 'enabled_modules' => 'Ingeschakelde modules', 'activity_60' => ':contact heeft de offerte :quote bekeken', 'activity_61' => ':user heeft de klant :client aangepast', @@ -3640,9 +3640,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'activity_65' => ':user heeft de derde herinnering voor factuur :invoice naar :contact verzonden', 'activity_66' => ':user heeft eindeloze herinneringen voor factuur :invoice naar :contact verzonden', 'expense_category_id' => 'Uitgave categorie ID', - 'view_licenses' => 'Bekijk Licenties', + 'view_licenses' => 'Bekijk licenties', 'fullscreen_editor' => 'Editor volledig scherm', - 'sidebar_editor' => 'Zijbalk Editor', + 'sidebar_editor' => 'Zijbalk editor', 'please_type_to_confirm' => 'Typ ":value" om te bevestigen', 'purge' => 'Wissen', 'clone_to' => 'Dupliceer naar', @@ -3650,7 +3650,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'labels' => 'Labels', 'add_custom' => 'Aangepast toevoegen', 'payment_tax' => 'Betalingsbelasting', - 'white_label' => 'White Label', + 'white_label' => 'Whitelabel', 'sent_invoices_are_locked' => 'Verzonden facturen zijn vergrendeld', 'paid_invoices_are_locked' => 'Betaalde facturen zijn vergrendeld', 'source_code' => 'Broncode', @@ -3660,7 +3660,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'restored_task_statuses' => 'Succesvol taak statussen :value hersteld', 'deleted_expense_categories' => 'Succesvol uitgave categorieën :value verwijderd', 'restored_expense_categories' => 'Uitgave succesvol hersteld: waarde categorieën ', - 'archived_recurring_invoices' => 'Terugkerende succesvol gearchiveerd: waarde facturen', + 'archived_recurring_invoices' => 'Terugkerende facturen succesvol gearchiveerd: :value', 'deleted_recurring_invoices' => 'Terugkerende succesvol verwijderd: waarde facturen', 'restored_recurring_invoices' => 'Terugkerende succesvol hersteld: waarde facturen', 'archived_webhooks' => 'Succesvol gearchiveerd: waarde webhooks', @@ -3685,9 +3685,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'archived_tax_rates' => 'Succesvol gearchiveerd: waarde belastingstarieven', 'deleted_tax_rates' => 'Succesvol verwijderd: waarde belastingtarieven', 'restored_tax_rates' => 'Succesvol hersteld: waarde belastingtarieven', - 'archived_company_gateways' => 'Succesvol gearchiveerd: waarde gateways', - 'deleted_company_gateways' => 'Succesvol verwijderd: waarde gateways', - 'restored_company_gateways' => 'Succesvol hersteld: waarde gateways', + 'archived_company_gateways' => 'Succesvol gearchiveerd: :value betaalproviders', + 'deleted_company_gateways' => 'Succesvol verwijderd: :value betaalproviders', + 'restored_company_gateways' => 'Succesvol hersteld: :value betaalproviders', 'archived_groups' => 'Succesvol gearchiveerd: waarde groepen', 'deleted_groups' => 'Succesvol verwijderd: waarde groepen', 'restored_groups' => 'Succesvol hersteld: waarde groepen', @@ -3703,18 +3703,18 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'restored_invoices' => 'Succesvol hersteld: waarde facturen', 'restored_payments' => 'Succesvol hersteld: waarde betalingen', 'restored_quotes' => 'Succesvol hersteld: waarde offertes', - 'update_app' => 'Update App', + 'update_app' => 'Update app', 'started_import' => 'Succesvol begonnen met importeren', 'duplicate_column_mapping' => 'Dubbele kolommapping', 'uses_inclusive_taxes' => 'Gebruik inclusieve belastingen', - 'is_amount_discount' => 'Is bedrag korting', + 'is_amount_discount' => 'Is het bedrag een korting', 'map_to' => 'Map naar', 'first_row_as_column_names' => 'Gebruik eerste rij als kolomnaam', 'no_file_selected' => 'Geen bestand geselecteerd', 'import_type' => 'Importeer type', - 'draft_mode' => 'Concept modus', + 'draft_mode' => 'Conceptmodus', 'draft_mode_help' => 'Toon aanpassingen sneller maar minder nauwkeurig', - 'show_product_discount' => 'Toon product korting', + 'show_product_discount' => 'Toon productkorting', 'show_product_discount_help' => 'Geef een regelitem kortingssveld weer', 'tax_name3' => 'BTW naam 3', 'debug_mode_is_enabled' => 'Foutopsporingsmodus is ingeschakeld', @@ -3725,9 +3725,9 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'upcoming_expenses' => 'Aankomende uitgaven', 'search_payment_term' => 'Zoek betalingstermijn 1', 'search_payment_terms' => 'Zoek :count betalingstermijnen', - 'save_and_preview' => 'Opslaan en bekijk voorbeeld', - 'save_and_email' => 'Opslaan en verstuur email', - 'converted_balance' => 'Omgekeerd balans', + 'save_and_preview' => 'Opslaan en voorbeeld bekijken', + 'save_and_email' => 'Opslaan en e-mail versturen', + 'converted_balance' => 'Omgezet saldo', 'is_sent' => 'Is verzonden', 'document_upload' => 'Document uploaden', 'document_upload_help' => 'Laat klanten documenten uploaden', @@ -3741,31 +3741,31 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'color' => 'Kleur', 'show' => 'Tonen', 'empty_columns' => 'Lege kolommen', - 'project_name' => 'Project naam', + 'project_name' => 'Projectnaam', 'counter_pattern_error' => 'Om :client_counter te gebruiken, voeg ofwel :client_number of :client_id_number toe om conflicten te voorkomen', 'this_quarter' => 'Dit kwartaal', 'to_update_run' => 'Om bij te werken voer', - 'registration_url' => 'Registratie link', - 'show_product_cost' => 'Laat product kosten zien', + 'registration_url' => 'Registratielink', + 'show_product_cost' => 'Laat productkosten zien', 'complete' => 'Voltooi', 'next' => 'Volgende', 'next_step' => 'Volgende stap', - 'notification_credit_sent_subject' => 'Krediet :invoice is verzonden naar :client', - 'notification_credit_viewed_subject' => 'Krediet :invoice is bekeken door :client', - 'notification_credit_sent' => 'De volgende klant :client heeft een email ontvangen voor een krediet :invoice van :amount', - 'notification_credit_viewed' => 'Klant :client heeft offerte :invoice voor :amount bekeken.', + 'notification_credit_sent_subject' => 'Creditfactuur :invoice is verzonden naar :client', + 'notification_credit_viewed_subject' => 'Creditfactuur :invoice is bekeken door :client', + 'notification_credit_sent' => 'De volgende klant :client heeft een e-mail ontvangen voor creditfactuur :invoice van :amount', + 'notification_credit_viewed' => 'Klant :client heeft creditfactuur :credit van :amount bekeken.', 'reset_password_text' => 'Voer uw e-mailadres in om uw wachtwoord opnieuw in te stellen.', 'password_reset' => 'Wachtwoord opnieuw instellen', - 'account_login_text' => 'Welkom! Leuk om je te zien.', + 'account_login_text' => 'Welkom! Fijn dat u er bent.', 'request_cancellation' => 'Annulering aanvragen', - 'delete_payment_method' => 'Verwijder betalingsmethode', - 'about_to_delete_payment_method' => 'U staat op het punt om de betalingsmethode te verwijderen.', + 'delete_payment_method' => 'Verwijder betaalmethode', + 'about_to_delete_payment_method' => 'U staat op het punt om de betaalmethode te verwijderen.', 'action_cant_be_reversed' => 'Actie kan niet terug gedraaid worden', 'profile_updated_successfully' => 'Het profiel is succesvol bijgewerkt.', 'currency_ethiopian_birr' => 'Ethiopische birr', 'client_information_text' => 'Gebruik een permanent adres waar u post kan ontvangen.', 'status_id' => 'Factuur status', - 'email_already_register' => 'Dit emailadres is al aan een account gelinkt', + 'email_already_register' => 'Dit e-mailadres is al aan een account gelinkt', 'locations' => 'Locaties', 'freq_indefinitely' => 'Oneindig', 'cycles_remaining' => 'RESTERENDE CYCLI', @@ -3774,24 +3774,24 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'download_timeframe' => 'Gebruik deze link om uw bestanden te downloaden, de link vervalt over 1 uur.', 'new_signup' => 'Nieuwe aanmelding', 'new_signup_text' => 'Een nieuw account is aangemaakt door :user - :email vanaf IP-adres :ip', - 'notification_payment_paid_subject' => 'Betaling werd gedaan door: klant', - 'notification_partial_payment_paid_subject' => 'Gedeeltelijke betaling werd gedaan door: klant', + 'notification_payment_paid_subject' => 'Betaling is gedaan door: klant', + 'notification_partial_payment_paid_subject' => 'Gedeeltelijke betaling is gedaan door: klant', 'notification_payment_paid' => 'Een betaling voor :amount is gemaakt door klant :client voor Factuur :invoice.', - 'notification_partial_payment_paid' => 'Een gedeeltelijke betaling van :amount werd gedaan door klant :client voor :invoice', + 'notification_partial_payment_paid' => 'Een gedeeltelijke betaling van :amount is gedaan door klant :client voor :invoice', 'notification_bot' => 'Notificatie bot', 'invoice_number_placeholder' => 'Factuur # :invoice', 'entity_number_placeholder' => ':entity # :entity_number', 'email_link_not_working' => 'Indien de bovenstaande knop niet werkt voor u, gelieve op de link te klikken', 'display_log' => 'Toon logboek', - 'send_fail_logs_to_our_server' => 'Report errors to help improve the app', + 'send_fail_logs_to_our_server' => 'Rapporteer foutmeldingen om de app te verbeteren', 'setup' => 'Setup', 'quick_overview_statistics' => 'Snel overzicht & statistieken', - 'update_your_personal_info' => 'Update jouw persoonlijke informatie', + 'update_your_personal_info' => 'Update uw persoonlijke informatie', 'name_website_logo' => 'Naam, website & logo', 'make_sure_use_full_link' => 'Zorg ervoor dat u de volledige link gebruikt naar uw website', 'personal_address' => 'Persoonlijk adres', 'enter_your_personal_address' => 'Voer uw persoonlijk adres in', - 'enter_your_shipping_address' => 'Voer uw verzendadres in', + 'enter_your_shipping_address' => 'Voer uw leveringsadres in', 'list_of_invoices' => 'Lijst van facturen', 'with_selected' => 'Met geselecteerde', 'invoice_still_unpaid' => 'Deze factuur is nog niet betaald. Klik op de knop om de betaling te vervolledigen', @@ -3804,15 +3804,15 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'list_of_payments' => 'Lijst met betalingen', 'payment_details' => 'Details van de betaling', 'list_of_payment_invoices' => 'Facturen koppelen', - 'list_of_payment_methods' => 'Lijst met betalingsmethodes', - 'payment_method_details' => 'Details van betalingsmethodes', - 'permanently_remove_payment_method' => 'Verwijder deze betalingsmethode definitief', + 'list_of_payment_methods' => 'Lijst met betaalmethoden', + 'payment_method_details' => 'Details van betaalmethodes', + 'permanently_remove_payment_method' => 'Verwijder deze betaalmethode definitief', 'warning_action_cannot_be_reversed' => 'Waarschuwing! Deze aanpassing kan niet terug worden gedraaid!', 'confirmation' => 'Bevestiging', 'list_of_quotes' => 'Offertes', 'waiting_for_approval' => 'Wachten op goedkeuren', 'quote_still_not_approved' => 'Deze offerte is nog steeds niet goedgekeurd', - 'list_of_credits' => 'Kredieten', + 'list_of_credits' => 'Creditfacturen', 'required_extensions' => 'Vereiste extensies', 'php_version' => 'PHP versie', 'writable_env_file' => 'Aanpasbaar .env bestand', @@ -3822,11 +3822,11 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'oops_issues' => 'Oeps, er klopt iets niet!', 'open_in_new_tab' => 'Open in nieuw tabblad', 'complete_your_payment' => 'Voltooi betaling', - 'authorize_for_future_use' => 'Autoriseer de betalingsmethode voor toekomstig gebruik', + 'authorize_for_future_use' => 'Autoriseer de betaalmethode voor toekomstig gebruik', 'page' => 'Pagina', 'per_page' => 'Per pagina', 'of' => 'Of', - 'view_credit' => 'Toon krediet', + 'view_credit' => 'Toon creditfactuur', 'to_view_entity_password' => 'Om de :entity te zien moet u een wachtwoord invoeren.', 'showing_x_of' => 'Toont de :first tot :last van de :total resultaten', 'no_results' => 'Geen resultaten gevonden.', @@ -3839,19 +3839,19 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'complete_your_bank_account_verification' => 'De bankaccount moet geverifieerd worden voor gebruik.', 'checkout_com' => 'Checkout.com', 'footer_label' => 'Copyright © :year :company.', - 'credit_card_invalid' => 'Het opgegeven kredietkaart nummer is niet geldig.', + 'credit_card_invalid' => 'Het opgegeven creditcard-nummer is niet geldig.', 'month_invalid' => 'Opgegeven maand is niet geldig.', 'year_invalid' => 'Opgegeven jaar is niet geldig.', 'https_required' => 'HTTP is vereist, anders zal het formulier mislukken', 'if_you_need_help' => 'Als u hulp nodig heeft, kunt u een bericht sturen naar onze', 'update_password_on_confirm' => 'Uw account zal bevestigd worden na het wijzigen van uw wachtwoord.', - 'bank_account_not_linked' => 'Om te betalen met een bankrekening moet u deze eerst toevoegen als betalingsmethode.', + 'bank_account_not_linked' => 'Om te betalen met een bankrekening moet u deze eerst toevoegen als betaalmethode.', 'application_settings_label' => 'Laat ons basis informatie over uw Invoice Ninja opslaan!', 'recommended_in_production' => 'Aanbevolen in productie', 'enable_only_for_development' => 'Enkel te activeren voor ontwikkeling', 'test_pdf' => 'Test PDF', - 'checkout_authorize_label' => 'Checkout.com kan opgeslagen worden als betalingsmethode na de eerste transactie. Vergeet "Sla kredietkaart details op" aan te vinken tijdens betalingsproces.', - 'sofort_authorize_label' => 'Overschrijving (SOFORT) kan opgeslagen worden als betalingsmethode voor toekomstig gebruik na de eerste transactie. Vergeet "Sla gegevens op" aan te vinken tijdens betalingsproces.', + 'checkout_authorize_label' => 'Checkout.com kan opgeslagen worden als betaalmethode na de eerste transactie. Vergeet "Sla creditcard details op" aan te vinken tijdens betalingsproces.', + 'sofort_authorize_label' => 'Overschrijving (SOFORT) kan opgeslagen worden als betaalmethode voor toekomstig gebruik na de eerste transactie. Vergeet "Sla gegevens op" aan te vinken tijdens betalingsproces.', 'node_status' => 'Node status', 'npm_status' => 'NPM status', 'node_status_not_found' => 'Kan Node nergens vinden. Is het geïnstalleerd?', @@ -3867,23 +3867,23 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'payment_error_code_20087' => '20087: Bad Track Data (ongeldige CVV en/of vervaldatum)', 'download_selected' => 'Download geselecteerde', 'to_pay_invoices' => 'Om facturen te betalen moet u', - 'add_payment_method_first' => 'Voeg betalingsmethode toe', + 'add_payment_method_first' => 'Voeg betaalmethode toe', 'no_items_selected' => 'Geen artikelen geselecteerd.', 'payment_due' => 'Betaling verschuldigd', 'account_balance' => 'Account Saldo', 'thanks' => 'Dank u wel', 'minimum_required_payment' => 'Minimaal vereiste betaling is :amount', 'under_payments_disabled' => 'Het bedrijf ondersteunt geen onderbetalingen.', - 'over_payments_disabled' => 'Het bedrijf ondersteunt geen te hoge betalingen.', + 'over_payments_disabled' => 'Het bedrijf ondersteunt geen overbetalingen.', 'saved_at' => 'Opgeslagen op :time', 'credit_payment' => 'Krediet toegepast op factuur :invoice_number', - 'credit_subject' => 'Nieuw krediet :number van :account', + 'credit_subject' => 'Nieuwe creditfactuur :number van :account', 'credit_message' => 'Klik op onderstaande link om uw factuur van :amount in te zien.', 'payment_type_Crypto' => 'Cryptogeld', 'payment_type_Credit' => 'Krediet', 'store_for_future_use' => 'Bewaar voor toekomstig gebruik', 'pay_with_credit' => 'Betaal met krediet', - 'payment_method_saving_failed' => 'Betalingsmethode kan niet opgeslagen worden voor toekomstig gebruik.', + 'payment_method_saving_failed' => 'Betaalmethode kan niet opgeslagen worden voor toekomstig gebruik.', 'pay_with' => 'Betaal met', 'n/a' => 'Nvt', 'by_clicking_next_you_accept_terms' => 'Door op "Volgende stap" te klikken, accepteert u de voorwaarden.', @@ -3896,48 +3896,48 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'notification_invoice_reminder2_sent_subject' => 'Herinnering 2 voor factuur :invoice is verzonden naar :client', 'notification_invoice_reminder3_sent_subject' => 'Herinnering 3 voor factuur :invoice is verzonden naar :client', 'notification_invoice_custom_sent_subject' => 'Aangepaste herinnering voor factuur :invoice is verzonden naar :client', - 'notification_invoice_reminder_endless_sent_subject' => 'Eindeloze herinnering voor factuur :invoice werd verstuurd naar :client', + 'notification_invoice_reminder_endless_sent_subject' => 'Eindeloze herinnering voor factuur :invoice is verstuurd naar :client', 'assigned_user' => 'Toegewezen gebruiker', - 'setup_steps_notice' => 'Zorg ervoor dat u elke sectie test om door te gaan naar de volgende stap.', + 'setup_steps_notice' => 'Zorg ervoor dat u elk onderdeel test om door te gaan naar de volgende stap.', 'setup_phantomjs_note' => 'Opmerking over Phantom JS. Lees verder.', - 'minimum_payment' => 'Minimum betaling', - 'no_action_provided' => 'Geen actie voorzien. Als u denkt dat dit niet klopt, neem dan contact op met uw support.', - 'no_payable_invoices_selected' => 'Geen te betalen facturen geselecteerd. Zorg ervoor dat u niet probeert om een conceptfactuur of factuur met geen openstaande betaling te betalen.', - 'required_payment_information' => 'Vereiste betalingsgegevens', - 'required_payment_information_more' => 'Om de betaling te voltooien, hebben we meer details van je nodig.', - 'required_client_info_save_label' => 'Dit wordt opgeslagen, zodat je dit later niet meer hoeft in te vullen', - 'notification_credit_bounced' => 'We konden offerte :invoice niet afleveren bij :contact.', - 'notification_credit_bounced_subject' => 'Kan krediet :invoice niet verzenden', + 'minimum_payment' => 'Minimumbetaling', + 'no_action_provided' => 'Geen actie opgegeven. Als u denkt dat dit niet klopt, neem dan contact op met uw ondersteuningspunt.', + 'no_payable_invoices_selected' => 'Geen te betalen facturen geselecteerd. Zorg ervoor dat u niet probeert om een conceptfactuur of factuur zonder openstaande betaling te betalen.', + 'required_payment_information' => 'Vereiste betaalgegevens', + 'required_payment_information_more' => 'Om de betaling te voltooien, hebben we meer details van u nodig.', + 'required_client_info_save_label' => 'Dit wordt opgeslagen, zodat u dit later niet meer hoeft in te vullen', + 'notification_credit_bounced' => 'We konden creditfactuur :invoice niet afleveren bij :contact.', + 'notification_credit_bounced_subject' => 'Kan creditfactuur :invoice niet verzenden', 'save_payment_method_details' => 'Bewaar betaalmethode', 'new_card' => 'Nieuwe betaalkaart', 'new_bank_account' => 'Voeg een bankrekening toe', 'company_limit_reached' => 'Limiet van :limit companies per account.', - 'credits_applied_validation' => 'Het totaal aan toegepaste credits kan niet MEER zijn dan het totaal van de facturen', + 'credits_applied_validation' => 'Het totaal aan toegepast krediet mag niet HOGER zijn dan het totaal van de facturen', 'credit_number_taken' => 'Kredietnummer is al in gebruik', - 'credit_not_found' => 'Krediet niet gevonden', + 'credit_not_found' => 'Creditfactuur niet gevonden', 'invoices_dont_match_client' => 'Geselecteerde facturen zijn niet van één enkele klant', - 'duplicate_credits_submitted' => 'Dubbele kredieten ingediend.', + 'duplicate_credits_submitted' => 'Dubbele creditfacturen ingediend.', 'duplicate_invoices_submitted' => 'Dubbele facturen ingediend.', 'credit_with_no_invoice' => 'U moet een factuur hebben ingesteld wanneer u een krediet gebruikt in een betaling', - 'client_id_required' => 'Klant id is verplicht', + 'client_id_required' => 'Klant-id is verplicht', 'expense_number_taken' => 'Uitgavenummer reeds in gebruik', 'invoice_number_taken' => 'Factuurnummer reeds in gebruik', 'payment_id_required' => 'Betalings-id verplicht', 'unable_to_retrieve_payment' => 'Niet in staat om gevraagde betaling op te halen', 'invoice_not_related_to_payment' => 'Factuur ID :invoice is niet herleidbaar naar deze betaling', - 'credit_not_related_to_payment' => 'Krediet ID :credit is niet verwant aan deze betaling', + 'credit_not_related_to_payment' => 'Creditfactuur ID :credit is niet verwant aan deze betaling', 'max_refundable_invoice' => 'Poging tot terugbetaling is groter dan toegestaan voor invoice id :invoice, maximum terug te betalen bedrag is :amount', 'refund_without_invoices' => 'Als u probeert een betaling met bijgevoegde facturen terug te betalen, geef dan geldige facturen op die moeten worden terugbetaald.', 'refund_without_credits' => 'Als u probeert een betaling met bijgevoegde tegoeden terug te betalen, geef dan geldige tegoeden op die moeten worden terugbetaald.', 'max_refundable_credit' => 'Bedrag van terugbetaling overschrijdt het credit bedrag :credit, het maximum toegelaten teruggave is beperkt tot :amount', - 'project_client_do_not_match' => 'Project klant komt niet overeen met entiteit klant', + 'project_client_do_not_match' => 'Projectklant komt niet overeen met de klant van de entiteit', 'quote_number_taken' => 'Offertenummer reeds in gebruik', - 'recurring_invoice_number_taken' => 'Terugkerend factuurnummer :number al in gebruik', + 'recurring_invoice_number_taken' => 'Terugkerend factuurnummer :number is al in gebruik', 'user_not_associated_with_account' => 'Gebruiker niet geassocieerd met deze account', 'amounts_do_not_balance' => 'Bedragen zijn niet correct.', 'insufficient_applied_amount_remaining' => 'Onvoldoende toegepast bedrag om de betaling te dekken.', - 'insufficient_credit_balance' => 'Onvoldoende balans op krediet.', - 'one_or_more_invoices_paid' => 'één of meer van deze facturen werden betaald', + 'insufficient_credit_balance' => 'Onvoldoende balans.', + 'one_or_more_invoices_paid' => 'één of meer van deze facturen zijn betaald', 'invoice_cannot_be_refunded' => 'Factuur-ID :number kan niet worden terugbetaald', 'attempted_refund_failed' => 'Poging tot terugbetaling van het bedrag van :amount. Het maximale terugbetaling os gelimiteerd tot :refundable_amount', 'user_not_associated_with_this_account' => 'Deze gebruiker kan niet aan dit bedrijf worden gekoppeld. Misschien hebben ze al een gebruiker geregistreerd op een ander account?', @@ -3953,7 +3953,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'no_group_settings_found' => 'Geen groep instellingen gevonden', 'access_denied' => 'Onvoldoende rechten om deze bron te openen / wijzigen', 'invoice_cannot_be_marked_paid' => 'Factuur kan niet als betaald worden gemarkeerd', - 'invoice_license_or_environment' => 'Ongeldige licentie of ongeldige omgeving :omgeving', + 'invoice_license_or_environment' => 'Ongeldige licentie of ongeldige omgeving :environment', 'route_not_available' => 'Route niet beschikbaar', 'invalid_design_object' => 'Ongeldig aangepast ontwerpobject', 'quote_not_found' => 'Offerte/s niet gevonden', @@ -3964,10 +3964,10 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'user_detached' => 'Gebruiker losgekoppeld van bedrijf', 'create_webhook_failure' => 'Maken van webhook is mislukt', 'payment_message_extended' => 'Bedankt voor uw betaling van :amount voor :invoice', - 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', + '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', 'vendor_address1' => 'Leverancier straatnaam', - 'vendor_address2' => 'Leverancier Apt / Suite', + 'vendor_address2' => 'Leverancier appartement/busnr.', 'partially_unapplied' => 'Gedeeltelijk niet toegepast', 'select_a_gmail_user' => 'Selecteer een gebruiker die is geverifieerd met Gmail', 'list_long_press' => 'Lijst lang indrukken', @@ -3996,8 +3996,8 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'count_days' => ':count dagen', 'web_session_timeout' => 'Time-out van websessie', 'security_settings' => 'Veiligheidsinstellingen', - 'resend_email' => 'Email opnieuw verzenden', - 'confirm_your_email_address' => 'Bevestig je e-mailadres', + 'resend_email' => 'E-mail opnieuw verzenden', + 'confirm_your_email_address' => 'Bevestig uw e-mailadres', 'freshbooks' => 'FreshBooks', 'invoice2go' => 'Invoice2go', 'invoicely' => 'Invoicely', @@ -4007,7 +4007,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'required_files_missing' => 'Geef alle CSV\'s op.', 'migration_auth_label' => 'Laten we verder gaan door te authenticeren.', 'api_secret' => 'API geheim', - 'migration_api_secret_notice' => 'Je kan de API_SECRET terugvinden in het .env bestand van Invoice Ninja V5. Als de waarde ontbreekt, laat het veld leeg.', + 'migration_api_secret_notice' => 'U kunt de API_SECRET terugvinden in het .env bestand van Invoice Ninja V5. Als de waarde ontbreekt, laat het veld leeg.', 'billing_coupon_notice' => 'Uw korting zal bij afrekenen toegepast worden', 'use_last_email' => 'Gebruik laatste e-mail', 'activate_company' => 'Activeer bedrijf', @@ -4023,33 +4023,33 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'delivered' => 'Afgeleverd', 'spam' => 'Spam', 'view_docs' => 'Bekijk documenten', - 'enter_phone_to_enable_two_factor' => 'Geef een mobiel telefoonnummer op om tweefactor authenticatie in te schakelen', + 'enter_phone_to_enable_two_factor' => 'Geef een mobiel telefoonnummer op om tweefactorauthenticatie in te schakelen', 'send_sms' => 'Verzend SMS', 'sms_code' => 'SMS Code', 'connect_google' => 'Verbind met Google', 'disconnect_google' => 'Verwijder Google', - 'disable_two_factor' => 'Schakel twee factor authenticatie uit', + 'disable_two_factor' => 'Schakel tweefactorauthenticatie uit', 'invoice_task_datelog' => 'Factuur taak datumlog', 'invoice_task_datelog_help' => 'Voeg datumdetails toe aan de factuurregelitems', 'promo_code' => 'Promocode', 'recurring_invoice_issued_to' => 'Terugkerende factuur gericht naar', 'subscription' => 'Abonnement', - 'new_subscription' => 'Nieuw Abonnement', + 'new_subscription' => 'Nieuw abonnement', 'deleted_subscription' => 'Succesvol abonnement verwijderd', 'removed_subscription' => 'Succesvol abonnement verwijderd', 'restored_subscription' => 'Succesvol abonnement hersteld', 'search_subscription' => 'Zoek 1 abonnement ', 'search_subscriptions' => 'Zoek :count abonnementen', 'subdomain_is_not_available' => 'Subdomein is niet beschikbaar', - 'connect_gmail' => 'Verbind Gmail', - 'disconnect_gmail' => 'Verbreek Gmail', + 'connect_gmail' => 'Verbinden met Gmail', + 'disconnect_gmail' => 'Verbreek de verbinding met Gmail', 'connected_gmail' => 'Succesvol verbonden met Gmail', - 'disconnected_gmail' => 'Succesvol verbroken met Gmail', - 'update_fail_help' => 'Wijzigingen aan de code kunnen leiden tot een blokkade tijdens het updaten. Door het volgende commando kan je de wijzigingen verwijderen:', + 'disconnected_gmail' => 'Succesvol verbinding verbroken met Gmail', + 'update_fail_help' => 'Wijzigingen aan de code kunnen leiden tot een blokkade tijdens het updaten. Door het volgende commando kunt u de wijzigingen verwijderen:', 'client_id_number' => 'Klant-id nummer', 'count_minutes' => ':count minuten', 'password_timeout' => 'Wachtwoord timeout', - 'shared_invoice_credit_counter' => 'Deel factuur/creditnota teller', + 'shared_invoice_credit_counter' => 'Deel factuur/creditfactuur tellers', 'activity_80' => ':user heeft abonnement :subscription aangemaakt', 'activity_81' => ':user heeft abonnement :subscription bijgewerkt', 'activity_82' => ':user heeft abonnement :subscription gearchiveerd', @@ -4060,13 +4060,13 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'notification_invoice_created_body' => 'Het volgende factuur :invoice was aangemaakt voor klant :client voor een bedrag :amount.', 'notification_invoice_created_subject' => 'Factuur :invoice aangemaakt voor :client', 'notification_quote_created_body' => 'Volgende voorstel :invoice is aangemaakt voor klant :client voor het bedrag van :amount', - 'notification_quote_created_subject' => 'Offerte :invoice werd aangemaakt voor :client', - 'notification_credit_created_body' => 'De volgende kredietfactuur :invoice werd aangemaakt voor client :client ter waarde van :amount.', - 'notification_credit_created_subject' => 'Kredietfactuur :invoice werd aangemaakt voor :client', + 'notification_quote_created_subject' => 'Offerte :invoice is aangemaakt voor :client', + 'notification_credit_created_body' => 'De volgende creditfactuur :invoice is aangemaakt voor klant :client ter waarde van :amount.', + 'notification_credit_created_subject' => 'Creditfactuur :invoice is aangemaakt voor :client', 'max_companies' => 'Maximaal gemigreerde bedrijven', 'max_companies_desc' => 'U heeft uw maximale aantal bedrijven bereikt. Verwijder bestaande bedrijven om nieuwe te migreren.', 'migration_already_completed' => 'Bedrijf is reeds gemigreerd', - 'migration_already_completed_desc' => 'Het ziet er naar uit dat je :company_name reeds hebt gemigreerd naar versie V5 van Invoice Ninja. Indien je opnieuw wilt beginnen, kan je de migratie forceren door bestaande data te laten verwijderen.', + 'migration_already_completed_desc' => 'Het ziet er naar uit dat u :company_name reeds hebt gemigreerd naar versie V5 van Invoice Ninja. Indien u opnieuw wilt beginnen, kunt u de migratie forceren door bestaande data te laten verwijderen.', 'payment_method_cannot_be_authorized_first' => 'Deze betaalmethode kan worden opgeslagen voor toekomstig gebruik, zodra u uw eerste transactie voltooit. Vergeet tijdens het betalingsproces niet "Winkelgegevens" aan te vinken.', 'new_account' => 'Nieuwe bankrekening', 'activity_100' => ':user heeft terugkerend factuur :recurring_invoice aangemaakt', @@ -4075,51 +4075,51 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'activity_103' => ':user heeft terugkerend factuur :recurring_invoice verwijderd', 'activity_104' => ':user heeft terugkerend factuur :recurring_invoice teruggezet', 'new_login_detected' => 'Nieuwe login gedetecteerd voor uw account.', - 'new_login_description' => 'Je bent recent ingelogd geweest in jouw Invoice Ninja account van een nieuwe locatie of toestel:

    -IP: :ip -Tijd: :time
    -Email: :email
    ', + 'new_login_description' => 'U bent recent ingelogd geweest in uw Invoice Ninja account van een nieuwe locatie of toestel:

    +IP-adres: :ip +Tijdstip: :time
    +E-mail: :email
    ', 'contact_details' => 'Contactgegevens', 'download_backup_subject' => 'De backup van uw bedrijf is beschikbaar om te downloaden.', 'account_passwordless_login' => 'Toegang zonder wachtwoord', 'user_duplicate_error' => 'Kan dezelfde gebruiker niet aan hetzelfde bedrijf toevoegen', 'user_cross_linked_error' => 'Gebruiker bestaat reeds maar kan niet gekoppeld worden aan meerdere accounts', - 'ach_verification_notification_label' => 'ACH verificatie', - 'ach_verification_notification' => 'Voor het koppelen van bankrekeningen is verificatie vereist. De betalingsgateway stuurt hiervoor automatisch twee kleine stortingen. Het duurt 1-2 werkdagen voordat deze stortingen op het online afschrift van de klant verschijnen.', + 'ach_verification_notification_label' => 'ACH-verificatie', + 'ach_verification_notification' => 'Voor het koppelen van bankrekeningen is verificatie vereist. De betaalprovider stuurt hiervoor automatisch twee kleine stortingen. Het duurt 1-2 werkdagen voordat deze stortingen op het online-afschrift van de klant verschijnen.', 'login_link_requested_label' => 'Inloglink opgevraagd', 'login_link_requested' => 'Er was een aanvraag om in te loggen door middel van een link. Als u dit niet bent geweest kunt u dit negeren.', 'invoices_backup_subject' => 'Uw facturen zijn klaar om te downloaden', 'migration_failed_label' => 'Integratie mislukt', 'migration_failed' => 'Er is iets fout gegaan tijdens de migratie van het volgende bedrijf:', 'client_email_company_contact_label' => 'Als u vragen heeft kunt u contact met ons opnemen, wij zijn hier om te helpen!', - 'quote_was_approved_label' => 'Offerde werd goedgekeurd', + 'quote_was_approved_label' => 'Offerte is goedgekeurd', 'quote_was_approved' => 'We willen u laten weten dat de offerte is goedgekeurd.', 'company_import_failure_subject' => 'Fout bij het importeren van :company', 'company_import_failure_body' => 'Er was een probleem bij het importeren van de bedrijfsdata, de foutmelding was:', 'recurring_invoice_due_date' => 'Vervaldatum', - 'amount_cents' => 'Bedrag in pennies, pence of centen. Voorbeeld: voor €0.10 voer 10 in', - 'default_payment_method_label' => 'Standaard betalingsmethode', - 'default_payment_method' => 'Maak dit uw favoriete manier van betalen.', - 'already_default_payment_method' => 'Dit is jouw voorkeurs manier van betalen.', - 'auto_bill_disabled' => 'Automatisch Betalen Uitgeschakeld', - 'select_payment_method' => 'Selecteer een betalingsmethode:', + 'amount_cents' => 'Bedrag in centen, pennies of pence. Voorbeeld: voor €0,10 voer 10 in', + 'default_payment_method_label' => 'Standaard betaalmethode', + 'default_payment_method' => 'Maak dit uw voorkeursbetaalmethode.', + 'already_default_payment_method' => 'Dit is uw voorkeursbetaalmethode.', + 'auto_bill_disabled' => 'Automatisch betalen uitgeschakeld', + 'select_payment_method' => 'Selecteer een betaalmethode:', 'login_without_password' => 'Inloggen zonder wachtwoord', 'email_sent' => 'E-mail mij wanneer een factuur is verzonden', 'one_time_purchases' => 'Eenmalige aankopen', 'recurring_purchases' => 'Terugkerende aankopen', - 'you_might_be_interested_in_following' => 'Misschien bent u geïnteresseerd in het volgende', - 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved. Expired quotes cannot be approved.', + 'you_might_be_interested_in_following' => 'Wellicht bent u geïnteresseerd in het volgende', + 'quotes_with_status_sent_can_be_approved' => 'Alleen offertes met de status "Verzonden" kunnen worden goedgekeurd. Verlopen offertes kunnen niet worden goedgekeurd.', 'no_quotes_available_for_download' => 'Geen offertes beschikbaar om te downloaden.', 'copyright' => 'Copyright', 'user_created_user' => ':user heeft :created_user aangemaakt om :time', 'company_deleted' => 'Bedrijf verwijderd', - 'company_deleted_body' => 'Bedrijf [ :company ] werd verwijderd door :user', + 'company_deleted_body' => 'Bedrijf [ :company ] is verwijderd door :user', 'back_to' => 'Terug naar :url', - 'stripe_connect_migration_title' => 'Verbind uw Stripe account', - 'stripe_connect_migration_desc' => 'Invoice Ninja v5 maakt gebruik van Stripe Connect om uw Stripe account te koppelen aan Invoice Ninja. Dit zorgt voor een extra beveiligingslaag voor uw account. Nu je gegevens zijn gemigreerd, dien je Stripe te autoriseren om betalingen te accepteren in v5.

    Om dit te doen gaat u naar Instellingen > Online Betalingen > Gateways configureren. Klik op Stripe Connect en vervolgens onder Settings op Setup Gateway. Dit brengt u naar Stripe om Invoice Ninja te autoriseren en bij terugkomst zal uw account succesvol gekoppeld zijn!', + 'stripe_connect_migration_title' => 'Verbind met uw Stripe-account', + 'stripe_connect_migration_desc' => 'Invoice Ninja v5 maakt gebruik van Stripe Connect om uw Stripe-account te koppelen aan Invoice Ninja. Dit zorgt voor een extra beveiligingslaag voor uw account. Nu uw gegevens zijn gemigreerd, dient u Stripe te autoriseren om betalingen te accepteren in v5.

    Om dit te doen gaat u naar Instellingen > Online Betalingen > Betaalproviders configureren. Klik op Stripe Connect en vervolgens onder Settings op Setup Gateway. Dit brengt u naar Stripe om Invoice Ninja te autoriseren en bij terugkomst zal uw account succesvol gekoppeld zijn!', 'email_quota_exceeded_subject' => 'Account e-mail quota overschreden.', - 'email_quota_exceeded_body' => 'U heeft in een periode van 24 uur :quota emails verstuurd.
    Uw uitgaande emails zijn hierbij gepauzeerd.

    Uw email quotum zal resetten om 23:00 UTC.', - 'auto_bill_option' => 'Kies ervoor om deze factuur automatisch te laten aanrekenen of niet.', + 'email_quota_exceeded_body' => 'U heeft in een periode van 24 uur :quota e-mails verstuurd.
    Uw uitgaande e-mails zijn hierbij gepauzeerd.

    Uw email quotum zal resetten om 23:00 UTC.', + 'auto_bill_option' => 'Kies ervoor om deze factuur al dan niet automatisch te laten verrekenen.', 'lang_Arabic' => 'Arabisch', 'lang_Persian' => 'Perzisch', 'lang_Latvian' => 'Lets', @@ -4130,13 +4130,13 @@ Email: :email
    ', 'locality' => 'Lokatie', 'checking' => 'Betaalrekening', 'savings' => 'Spaarrekening', - 'unable_to_verify_payment_method' => 'Kan de betalingsmethode niet verifiëren.', - 'generic_gateway_error' => 'Gateway-configuratiefout. Controleer uw inloggegevens.', + 'unable_to_verify_payment_method' => 'Kan de betaalmethode niet verifiëren.', + 'generic_gateway_error' => 'Configuratiefout betaalprovider. Controleer uw inloggegevens.', 'my_documents' => 'Mijn documenten', 'payment_method_cannot_be_preauthorized' => 'Deze betaalmethode kan niet vooraf worden geautoriseerd.', 'kbc_cbc' => 'KBC/CBC', 'bancontact' => 'Bancontact', - 'sepa_mandat' => 'Door uw IBAN op te geven en deze betaling te bevestigen, machtigt u :company en Stripe, onze betalingsdienstaanbieder, om instructies naar uw bank te sturen om uw rekening te debiteren en uw bank om uw rekening te debiteren in overeenstemming met die instructies. U heeft recht op terugbetaling door uw bank volgens de voorwaarden van uw overeenkomst met uw bank. Een terugbetaling moet worden aangevraagd binnen 8 weken vanaf de datum waarop uw rekening is afgeschreven.', + 'sepa_mandat' => 'Door uw IBAN op te geven en deze betaling te bevestigen, machtigt u :company en Stripe, onze betaalprovider, om instructies naar uw bank te sturen om uw bankrekening te debiteren in overeenstemming met voornoemde voorwaarden. U heeft recht op terugbetaling door uw bank volgens de voorwaarden van uw overeenkomst met uw bank. Een terugbetaling moet worden aangevraagd binnen 8 weken vanaf de datum waarop het bedrag van uw rekening is afgeschreven.', 'ideal' => 'iDEAL', 'bank_account_holder' => 'Rekeninghouder', 'aio_checkout' => 'Klik en betaal', @@ -4149,8 +4149,8 @@ Email: :email
    ', 'becs' => 'BECS Direct Debit', 'bacs' => 'BACS-incasso', 'payment_type_BACS' => 'BACS-incasso', - 'missing_payment_method' => 'Voeg eerst een betaalmethode toe voordat je probeert te betalen.', - 'becs_mandate' => 'Door uw bankrekeninggegevens op te geven, gaat u akkoord met dit automatische incasso-verzoek en de automatische incasso-serviceovereenkomst , en autoriseert u Stripe Payments Australia Pty Ltd ACN 160 180 343 automatische incasso gebruikers-ID-nummer 507156 ("Stripe") om uw rekening te debiteren via het Bulk Electronic Clearing System (BECS) namens :company (de "Handelaar") voor alle bedragen die afzonderlijk door de Handelaar aan u zijn meegedeeld. U verklaart dat u ofwel een rekeninghouder ofwel een tekenbevoegde bent op de hierboven vermelde rekening.', + 'missing_payment_method' => 'Voeg eerst een betaalmethode toe voordat u probeert te betalen.', + 'becs_mandate' => 'Door uw bankrekeninggegevens te delen, gaat u akkoord met dit verzoek tot automatische incasso en serviceovereenkomst betreffende de automatische incasso, en autoriseert u Stripe Payments Australia Pty Ltd ACN 160 180 343 automatische incasso gebruikers-ID-nummer 507156 ("Stripe") om uw rekening te debiteren via het Bulk Electronic Clearing System (BECS) namens :company (de "Handelaar") voor alle bedragen die afzonderlijk door de Handelaar aan u zijn meegedeeld. U verklaart dat u ofwel een rekeninghouder ofwel een tekenbevoegde bent op de hierboven vermelde rekening.', 'you_need_to_accept_the_terms_before_proceeding' => 'U moet de voorwaarden accepteren voordat u verder gaat.', 'direct_debit' => 'Automatische Incasso', 'clone_to_expense' => 'Dupliceer naar uitgave', @@ -4159,7 +4159,7 @@ Email: :email
    ', 'invalid_amount' => 'Ongeldige hoeveelheid. Alleen getallen/decimale waarden.', 'client_payment_failure_body' => 'Betaling voor factuur :invoice voor een bedrag van :amount is mislukt.', 'browser_pay' => 'Google Pay, Apple Pay, Microsoft Pay', - 'no_available_methods' => 'Er kan geen credit card worden gevonden op uw apparaat. Lees hier meer over. ', + 'no_available_methods' => 'Er kan geen creditcard worden gevonden op uw apparaat. Lees hier meer over. ', 'gocardless_mandate_not_ready' => 'Betalingsopdracht nog niet gereed. Probeer het later nog eens.', 'payment_type_instant_bank_pay' => 'Instant Bank Pay', 'payment_type_iDEAL' => 'iDEAL', @@ -4191,20 +4191,20 @@ Email: :email
    ', 'please_set_a_password' => 'Voer een account wachtwoord in', 'recommend_desktop' => 'Wij raden de desktop app aan voor de beste werking.', 'recommend_mobile' => 'Wij raden de mobiele app aan voor de beste werking.', - 'disconnected_gateway' => 'Gateway succesvol ontkoppeld', + 'disconnected_gateway' => 'Betaalprovider succesvol ontkoppeld', 'disconnect' => 'Verbreek verbinding', 'add_to_invoices' => 'Voeg toe aan facturen', 'bulk_download' => 'Download', 'persist_data_help' => 'Sla gegevens lokaal op om de app sneller te laten starten. Uitschakelen kan de prestaties in grote accounts verbeteren', 'persist_ui' => 'Interface voorkeuren opslaan', 'persist_ui_help' => 'Sla de UI-status lokaal op om de app op de laatste locatie te laten starten. Uitschakelen kan de prestaties verbeteren', - 'client_postal_code' => 'Klant postcode', - 'client_vat_number' => 'Klant BTW-nummer', + 'client_postal_code' => 'Postcode klant', + 'client_vat_number' => 'BTW-nummer klant', 'has_tasks' => 'Heeft taken', 'registration' => 'Registratie', 'unauthorized_stripe_warning' => 'Autoriseer Stripe om online betalingen te accepteren.', 'update_all_records' => 'Alle records bijwerken', - 'set_default_company' => 'Stel in als standaard bedrijf', + 'set_default_company' => 'Stel in als standaardbedrijf', 'updated_company' => 'Bedrijf succesvol geüpdatet', 'kbc' => 'KBC', 'why_are_you_leaving' => 'Help ons door aan te geven waarom (optioneel)', @@ -4213,23 +4213,23 @@ Email: :email
    ', 'error_cross_client_expenses' => 'Kosten moeten allemaal behoren tot dezelfde klant', 'app' => 'App', 'for_best_performance' => 'Download voor de beste prestaties de :app-app', - 'bulk_email_invoice' => 'Email factuur', - 'bulk_email_quote' => 'Email offerte', - 'bulk_email_credit' => 'Email krediet', - 'removed_recurring_expense' => 'Terugkerende onkosten zijn verwijderd', + 'bulk_email_invoice' => 'E-mail factuur', + 'bulk_email_quote' => 'E-mail offerte', + 'bulk_email_credit' => 'E-mail creditfactuur', + 'removed_recurring_expense' => 'Terugkerende uitgaven zijn verwijderd', 'search_recurring_expense' => 'Zoek terugkerende uitgave', 'search_recurring_expenses' => 'Zoek terugkerende uitgaven', 'last_sent_date' => 'Recentste verzenddatum', 'include_drafts' => 'Voeg concepten toe', 'include_drafts_help' => 'Neem conceptrecords op in rapporten', 'is_invoiced' => 'Is gefactureerd', - 'change_plan' => 'Beheer Plan', + 'change_plan' => 'Beheer abonnement', 'persist_data' => 'Gegevens behouden', 'customer_count' => 'Klantenteller', 'verify_customers' => 'Klanten verifiëren', 'google_analytics_tracking_id' => 'Google Analytics Tracking ID', - 'decimal_comma' => 'Decimaal komma', - 'use_comma_as_decimal_place' => 'Gebruik een komma als decimaal in formulieren', + 'decimal_comma' => 'Komma als decimaalteken', + 'use_comma_as_decimal_place' => 'Gebruik een komma als decimaalteken in formulieren', 'select_method' => 'Selecteer methode', 'select_platform' => 'Selecteer platform', 'use_web_app_to_connect_gmail' => 'Gebruik de web-app om verbinding te maken met Gmail', @@ -4256,19 +4256,19 @@ Email: :email
    ', 'check_status' => 'Check Status', 'free_trial' => 'Gratis proefversie', 'free_trial_help' => 'Alle accounts krijgen een proefperiode van twee weken van het Pro-abonnement. Zodra de proefperiode is afgelopen, gaat uw account automatisch over naar het gratis abonnement.', - 'free_trial_ends_in_days' => 'De proefperiode van het Pro-plan eindigt over :count dagen, klik om te upgraden.', - 'free_trial_ends_today' => 'Vandaag is de laatste dag van de Pro-proefperiode, klik om te upgraden.', - 'change_email' => 'Wijzig email', - 'client_portal_domain_hint' => 'Optioneel: Configureer een afzonderlijke domein voor de klantenportaal', + 'free_trial_ends_in_days' => 'De proefperiode van het Pro-abonnement eindigt over :count dagen, klik om te upgraden.', + 'free_trial_ends_today' => 'Vandaag is de laatste dag van de proefperiode van het Pro-abonnement, klik om te upgraden.', + 'change_email' => 'Wijzig e-mail', + 'client_portal_domain_hint' => 'Optioneel: configureer een afzonderlijke domein voor de klantenportaal', 'tasks_shown_in_portal' => 'Taken weergegeven in portaal', 'uninvoiced' => 'Gefactureerd', - 'subdomain_guide' => 'De subdomein wordt gebruikt voor het klantenportaal om links aan te passen op jouw merk m.a.w. https://your-brand.invoicing.co', - 'send_time' => 'Verzend uur', - 'import_settings' => 'Importeer settings', - 'json_file_missing' => 'Geef een JSON bestand op', + 'subdomain_guide' => 'De subdomein wordt gebruikt voor het klantenportaal om links aan te passen op uw merk m.a.w. https://your-brand.invoicing.co', + 'send_time' => 'Tijdstip verzending', + 'import_settings' => 'Importeer instellingen', + 'json_file_missing' => 'Geef een JSON-bestand op', 'json_option_missing' => 'Selecteer om instellingen en/of data te importeren', 'json' => 'JSON', - 'no_payment_types_enabled' => 'Geen betalingsmodalititeiten geactiveerd', + 'no_payment_types_enabled' => 'Geen betaalmethoden geactiveerd', 'wait_for_data' => 'Wacht tot de gegevens volledig zijn geladen', 'net_total' => 'Totaal', 'has_taxes' => 'Bevat belastingen', @@ -4276,7 +4276,7 @@ Email: :email
    ', 'imported_customers' => 'Succesvol begonnen met het importeren van klanten', 'login_success' => 'Login succesvol', 'login_failure' => 'Inloggen mislukt', - 'exported_data' => 'Zodra het bestand klaar is, ontvang je een e-mail met een downloadlink', + 'exported_data' => 'Zodra het bestand klaar is, ontvangt u een e-mail met een downloadlink', 'include_deleted_clients' => 'Inclusief verwijderde klanten', 'include_deleted_clients_help' => 'Laad records van verwijderde clients', 'step_1_sign_in' => 'Stap 1: Inloggen', @@ -4294,7 +4294,7 @@ Email: :email
    ', 'count_sessions' => ':count Sessies', 'invoice_created' => 'Factuur aangemaakt', 'quote_created' => 'Offerte aangemaakt', - 'credit_created' => 'Creditnota aangemaakt', + 'credit_created' => 'Creditfactuur aangemaakt', 'enterprise' => 'Onderneming', 'invoice_item' => 'Factuur item', 'quote_item' => 'Offerte item', @@ -4305,12 +4305,12 @@ Email: :email
    ', 'move_up' => 'Verplaats omhoog', 'move_down' => 'Verplaats omlaag', 'move_bottom' => 'Verplaatsknop', - 'body_variable_missing' => 'Fout: de aangepaste email moet een :body variabele bevatten', - 'add_body_variable_message' => 'Zorg ervoor dat je een :body variabele gebruikt', + 'body_variable_missing' => 'Fout: de aangepaste e-mail moet een :body variabele bevatten', + 'add_body_variable_message' => 'Zorg ervoor dat u een :body variabele gebruikt', 'view_date_formats' => 'Bijkijk datumformaten', 'is_viewed' => 'Bekeken', 'letter' => 'Brief', - 'legal' => 'Legaal', + 'legal' => 'Juridisch', 'page_layout' => 'Verticaal', 'portrait' => 'Portrait', 'landscape' => 'Horizontaal', @@ -4333,14 +4333,14 @@ Email: :email
    ', 'trial_enabled' => 'Proefperiode ingeschakeld', 'trial_duration' => 'Proefperiode duratie', 'allow_query_overrides' => 'Sta query overrides toe', - 'allow_plan_changes' => 'Sta planswijzigingen toe', - 'plan_map' => 'Plan map', + 'allow_plan_changes' => 'Sta abonnementswijzigingen toe', + 'plan_map' => 'Overzicht abonnement', 'refund_period' => 'Terugbetalingsperiode', 'webhook_configuration' => 'Webhook Configuratie', 'purchase_page' => 'Aankoop pagina', - 'email_bounced' => 'Email gebounced', + 'email_bounced' => 'E-mail gebounced', 'email_spam_complaint' => 'Spam klacht', - 'email_delivery' => 'Email bezorging', + 'email_delivery' => 'E-mail bezorgd', 'webhook_response' => 'Webhook Response', 'pdf_response' => 'PDF Response', 'authentication_failure' => 'Authenticatie Mislukt', @@ -4352,8 +4352,8 @@ Email: :email
    ', 'status_color_theme' => 'Status Kleurenthema', 'load_color_theme' => 'Kleurthema laden', 'lang_Estonian' => 'Estland', - 'marked_credit_as_paid' => 'Creditnota gemarkeerd als betaald', - 'marked_credits_as_paid' => 'Creditnota\'s gemarkeerd als betaald', + 'marked_credit_as_paid' => 'Creditfactuur gemarkeerd als betaald', + 'marked_credits_as_paid' => 'Creditfacturen gemarkeerd als betaald', 'wait_for_loading' => 'Data is aan het laden - een moment geduld', 'wait_for_saving' => 'Data is aan het opslaan - een moment geduld', 'html_preview_warning' => 'Opmerking: veranderingen die hier worden gemaakt zijn voorvertoningen, ze moeten hierboven worden toegepast', @@ -4368,28 +4368,28 @@ Email: :email
    ', 'to_view_entity_set_password' => 'Om de :entity te bekijken, moet u een wachtwoord instellen.', 'unsubscribe' => 'Afmelden', 'unsubscribed' => 'Afgemeld', - 'unsubscribed_text' => 'Je bent verwijderd uit meldingen voor dit document', - 'client_shipping_state' => 'Verzendstaat klant', - 'client_shipping_city' => 'Opdrachtgever Scheepvaartstad', - 'client_shipping_postal_code' => 'Postcode verzending klant', - 'client_shipping_country' => 'Land van verzending van de klant', + 'unsubscribed_text' => 'U bent verwijderd uit meldingen voor dit document', + 'client_shipping_state' => 'Staat/provincie leveringsadres klant', + 'client_shipping_city' => 'Stad leveringsadres klant', + 'client_shipping_postal_code' => 'Postcode leveringsadres klant', + 'client_shipping_country' => 'Land leveringsadres klant', 'load_pdf' => 'Laad PDF', 'start_free_trial' => 'Start gratis proefperiode', - 'start_free_trial_message' => 'Start your FREE 14 day trial of the Pro Plan', + 'start_free_trial_message' => 'Start uw GRATIS proefperiode van 14 dagen voor het Pro-abonnement', 'due_on_receipt' => 'Verschuldigd bij ontvangst', 'is_paid' => 'Is betaald', 'age_group_paid' => 'Betaald', 'id' => 'ID kaart', 'convert_to' => 'Reken om naar', 'client_currency' => 'Klant valuta', - 'company_currency' => 'Bedrijf valuta', - 'custom_emails_disabled_help' => 'Om spam te voorkomen moet je een betaald account hebben om emails aan te passen', + 'company_currency' => 'Bedrijfsvaluta', + 'custom_emails_disabled_help' => 'Om spam te voorkomen moet u een betaald account hebben om e-mails aan te passen', 'upgrade_to_add_company' => 'Upgrade uw abonnement om meer bedrijven toe te voegen', 'file_saved_in_downloads_folder' => 'Het bestand is opgeslagen in de downloadmap', 'small' => 'Klein', 'quotes_backup_subject' => 'Uw offertes zijn klaar om te downloaden.', - 'credits_backup_subject' => 'Je creditnota\'s zijn klaar om te downloaden', - 'document_download_subject' => 'Je documenten zijn klaar om te downloaden', + 'credits_backup_subject' => 'Uw creditfacturen zijn klaar om te downloaden', + 'document_download_subject' => 'Uw documenten zijn klaar om te downloaden', 'reminder_message' => 'Herinnering voor factuur :number voor :balance', 'gmail_credentials_invalid_subject' => 'Verzenden met GMail ongeldige inloggegevens', 'gmail_credentials_invalid_body' => 'Uw GMail-referenties zijn niet correct. Meld u aan bij de beheerdersportal en navigeer naar Instellingen > Gebruikersgegevens en koppel uw Gmail-account los en maak opnieuw verbinding. We sturen u deze melding dagelijks totdat dit probleem is opgelost', @@ -4417,8 +4417,8 @@ Email: :email
    ', 'signed_in_as' => 'Ingelogd als', 'total_results' => 'Totaal resultaat', 'restore_company_gateway' => 'Poort herstellen', - 'archive_company_gateway' => 'Archief gateway', - 'delete_company_gateway' => 'Gateway verwijderen', + 'archive_company_gateway' => 'Archiveer betaalprovider', + 'delete_company_gateway' => 'Betaalprovider verwijderen', 'exchange_currency' => 'Wisselkoers', 'tax_amount1' => 'Belastingbedrag 1', 'tax_amount2' => 'Belastingbedrag 2', @@ -4451,7 +4451,7 @@ Email: :email
    ', 'export_format' => 'Export Formaat', 'export_type' => 'Export Type', 'stop_on_unpaid' => 'Stop bij onbetaald', - 'stop_on_unpaid_help' => 'Stop met het maken van terugkerende facturen als de laatste factuur onbetaald is.', + 'stop_on_unpaid_help' => 'Stop met het aanmaken van terugkerende facturen wanneer de laatste factuur onbetaald is.', 'use_quote_terms' => 'Gebruik offertevoorwaarden', 'use_quote_terms_help' => 'Bij het omzetten van een offerte naar een factuur', 'add_country' => 'Voeg land toe', @@ -4459,26 +4459,26 @@ Email: :email
    ', 'enable_tooltips_help' => 'Toon tooltips wanneer u met de muis beweegt', 'multiple_client_error' => 'Fout: records behoren tot meer dan één klant', 'login_label' => 'Login met een bestaand account', - 'purchase_order' => 'Aankooporder', + 'purchase_order' => 'Inkooporder', 'purchase_order_number' => 'Aankoop ordernummer', - 'purchase_order_number_short' => 'Aankooporder #', + 'purchase_order_number_short' => 'Inkooporder #', 'inventory_notification_subject' => 'Melding van voorraaddrempel voor product: :product', 'inventory_notification_body' => 'Drempel van :amount is bereikt voor product: :product', - 'activity_130' => ':user heeft aankooporder :purchase_order aangemaakt', - 'activity_131' => ':user heeft aankooporder :purchase_order aangepast', - 'activity_132' => ':user heeft aankooporder :purchase_order gearchiveerd', - 'activity_133' => ':user heeft aankooporder :purchase_order verwijderd', - 'activity_134' => ':user heeft aankooporder :purchase_order hersteld', - 'activity_135' => ': user gebruiker gemailde inkooporder :purchase_order', + 'activity_130' => ':user heeft inkooporder :purchase_order aangemaakt', + 'activity_131' => ':user heeft inkooporder :purchase_order aangepast', + 'activity_132' => ':user heeft inkooporder :purchase_order gearchiveerd', + 'activity_133' => ':user heeft inkooporder :purchase_order verwijderd', + 'activity_134' => ':user heeft inkooporder :purchase_order hersteld', + 'activity_135' => ':user gebruiker gemailde inkooporder :purchase_order', 'activity_136' => ':contact bekeken inkooporder :purchase_order', 'purchase_order_subject' => 'Nieuwe inkooporder :number van :account', 'purchase_order_message' => 'Klik op de onderstaande link om uw bestelling voor :amount te bekijken.', - 'view_purchase_order' => 'Bekijk aankooporder', - 'purchase_orders_backup_subject' => 'Uw inkooporders zijn klaar om te downloaden', - 'notification_purchase_order_viewed_subject' => 'Inkooporder :invoice werd bekeken door :client', + 'view_purchase_order' => 'Bekijk inkooporder', + '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' => 'De volgende leverancier :client heeft inkooporder :invoice voor :amount bekeken.', - 'purchase_order_date' => 'Datum aankooporder', - 'purchase_orders' => 'Aankooporders', + 'purchase_order_date' => 'Datum inkooporder', + 'purchase_orders' => 'Inkooporders', 'purchase_order_number_placeholder' => 'Inkooporder #:purchase_order', 'accepted' => 'Geaccepteerd', 'activity_137' => ':contact geaccepteerde bestelling :purchase_order', @@ -4492,13 +4492,13 @@ Email: :email
    ', 'added_purchase_order_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd', 'added_purchase_orders_to_inventory' => 'Inkooporder met succes aan voorraad toegevoegd', 'client_document_upload' => 'Uploaden klantdocument', - 'vendor_document_upload' => 'Uploaden verkoperdocument', + 'vendor_document_upload' => 'Verkoopdocument uploaden', 'vendor_document_upload_help' => 'Leveranciers in staat stellen documenten te uploaden', - 'are_you_enjoying_the_app' => 'Geniet je van de app?', + 'are_you_enjoying_the_app' => 'Bevalt de app?', 'yes_its_great' => 'Ja, het is geweldig!', 'not_so_much' => 'Niet zo veel', - 'would_you_rate_it' => 'Goed om te horen! Zou je het willen beoordelen?', - 'would_you_tell_us_more' => 'Dat is jammer om te horen! Wil je ons meer vertellen?', + 'would_you_rate_it' => 'Goed om te horen! Zou u het willen beoordelen?', + 'would_you_tell_us_more' => 'Dat is jammer om te horen! Wilt u ons meer vertellen?', 'sure_happy_to' => 'Zeker, graag', 'no_not_now' => 'Nee, nu niet', 'add' => 'Toevoegen', @@ -4506,7 +4506,7 @@ Email: :email
    ', 'enable_flexible_search' => 'Flexibel zoeken inschakelen', 'enable_flexible_search_help' => 'Overeenkomen met niet-aangrenzende tekens, dwz. "ct" komt overeen met "kat"', 'vendor_details' => 'Details verkoper', - 'purchase_order_details' => 'Details aankooporder', + 'purchase_order_details' => 'Details inkooporder', 'qr_iban' => 'QR IBAN', 'besr_id' => 'BESR-ID', 'clone_to_purchase_order' => 'Kloon naar PO', @@ -4519,17 +4519,17 @@ Email: :email
    ', 'cancelled_purchase_order' => 'Inkooporder succesvol geannuleerd', 'cancelled_purchase_orders' => 'Inkooporders succesvol geannuleerd', 'please_select_a_vendor' => 'Gelieve een verkoper te selecteren', - 'purchase_order_total' => 'Inkooporder Totaal', + 'purchase_order_total' => 'Totaal inkooporder', 'email_purchase_order' => 'E-mail inkooporder', 'bulk_email_purchase_order' => 'E-mail inkooporder', 'disconnected_email' => 'E-mail is losgekoppeld', 'connect_email' => 'E-mail koppelen', 'disconnect_email' => 'Koppel e-mail los', 'use_web_app_to_connect_microsoft' => 'Gebruik de web-app om verbinding te maken met Microsoft', - 'email_provider' => 'E-mail provider', - 'connect_microsoft' => 'Verbind Microsoft', + 'email_provider' => 'E-mailprovider', + 'connect_microsoft' => 'Verbind met Microsoft', 'disconnect_microsoft' => 'Koppel Microsoft los', - 'connected_microsoft' => 'Microsoft succesvol verbonden', + 'connected_microsoft' => 'Succesvol verbonden met Microsoft', 'disconnected_microsoft' => 'Losgekoppeld van Microsoft', 'microsoft_sign_in' => 'Inloggen met Microsoft', 'microsoft_sign_up' => 'Meld u aan bij Microsoft', @@ -4544,15 +4544,15 @@ Email: :email
    ', 'new_purchase_order' => 'Nieuwe inkooporder', 'edit_purchase_order' => 'Inkooporder bewerken', 'created_purchase_order' => 'Inkooporder succesvol aangemaakt', - 'updated_purchase_order' => 'Aankooporder succesvol geupdate', - 'archived_purchase_order' => 'Aankooporder succesvol gearchiveerd', - 'deleted_purchase_order' => 'Aankooporder succesvol verwijderd', + 'updated_purchase_order' => 'Inkooporder succesvol geupdate', + 'archived_purchase_order' => 'Inkooporder succesvol gearchiveerd', + 'deleted_purchase_order' => 'Inkooporder succesvol verwijderd', 'removed_purchase_order' => 'Bestelling verwijderd', 'restored_purchase_order' => 'Bestelling hersteld', 'search_purchase_order' => 'Zoek verkoop order', 'search_purchase_orders' => 'Zoek verkoop orders', 'login_url' => 'Inlog-URL', - 'enable_applying_payments' => 'Handmatige teveelbetalingen', + 'enable_applying_payments' => 'Handmatige overbetalingen', 'enable_applying_payments_help' => 'Ondersteuning voor het handmatig toevoegen van een te veel betaald bedrag aan een betaling', 'stock_quantity' => 'Voorraad hoeveelheid', 'notification_threshold' => 'Meldingsdrempel', @@ -4597,12 +4597,12 @@ Email: :email
    ', 'total_logged_expenses' => 'Vastgelegde kosten', 'total_pending_expenses' => 'Lopende kosten', 'total_invoiced_expenses' => 'Gefactureerde kosten', - 'total_invoice_paid_expenses' => 'Factuureer gemaakte kosten', + 'total_invoice_paid_expenses' => 'Factureer gemaakte kosten', 'vendor_portal' => 'Leveranciersportaal', 'send_code' => 'Verstuur code', 'save_to_upload_documents' => 'Sla op om documenten te kunnen uploaden', 'expense_tax_rates' => 'Belastingtarief uitgaven', - 'invoice_item_tax_rates' => 'Belastingtarief factuurregel', + 'invoice_item_tax_rates' => 'Belastingtarief factuurregels', 'verified_phone_number' => 'Telefoonnummer is geverifiëerd', 'code_was_sent' => 'Er is een code via SMS verstuurd', 'resend' => 'Verstuur opnieuw', @@ -4617,13 +4617,13 @@ Email: :email
    ', 'bulk_email_purchase_orders' => 'E-mail inkooporders', 'bulk_email_invoices' => 'E-mail facturen', 'bulk_email_quotes' => 'E-mail offertes', - 'bulk_email_credits' => 'E-mail creditzijde', + 'bulk_email_credits' => 'E-mail creditfacturen', 'archive_purchase_order' => 'Archiveer inkooporder', 'restore_purchase_order' => 'Herstel inkooporder', 'delete_purchase_order' => 'Verwijder inkooporder', 'connect' => 'Koppel', 'mark_paid_payment_email' => 'Betaling betaald gemarkeerd e-mail', - 'convert_to_project' => 'Naar project omzetten', + 'convert_to_project' => 'Omzetten naar project', 'client_email' => 'Klant e-mail', 'invoice_task_project' => 'Factuur taak project', 'invoice_task_project_help' => 'Voeg project toe als factuurregel', @@ -4638,35 +4638,35 @@ Email: :email
    ', 'bank_transaction' => 'Transactie', 'bulk_print' => 'Druk PDF af', 'vendor_postal_code' => 'Postcode leverancier', - 'preview_location' => 'Voorbeeld locatie', + 'preview_location' => 'Voorbeeldlocatie', 'bottom' => 'Onderkant', 'side' => 'Kant', 'pdf_preview' => 'PDF-voorbeeld', 'long_press_to_select' => 'Lang indrukken om te selecteren', 'purchase_order_item' => 'Artikel inkooporder', - 'would_you_rate_the_app' => 'Wil je de app beoordelen?', + 'would_you_rate_the_app' => 'Wilt u de app beoordelen?', 'include_deleted' => 'Inclusief verwijderd', 'include_deleted_help' => 'Neem verwijderde records op in rapporten', 'due_on' => 'Verschuldigd op', 'browser_pdf_viewer' => 'Gebruik Browser PDF-viewer', 'browser_pdf_viewer_help' => 'Waarschuwing: voorkomt interactie met de app via de pdf', - 'converted_transactions' => 'Succesvol geconverteerde transacties', + 'converted_transactions' => 'Transacties succesvol geconverteerd', 'default_category' => 'Standaard categorie', 'connect_accounts' => 'Accounts koppelen', 'manage_rules' => 'Regels beheren', 'search_category' => 'Zoek 1 categorie', 'search_categories' => 'Zoek :count Categorieën', 'min_amount' => 'Min. bedrag', - 'max_amount' => 'Maximaal bedrag', + 'max_amount' => 'Maximumbedrag', 'converted_transaction' => 'Transactie succesvol geconverteerd', 'convert_to_payment' => 'Converteren naar betaling', 'deposit' => 'Borg', 'withdrawal' => 'Opname', 'deposits' => 'stortingen', 'withdrawals' => 'Opnames', - 'matched' => 'Op elkaar afgestemd', - 'unmatched' => 'Ongeëvenaard', - 'create_credit' => 'Maak creditnota', + 'matched' => 'Match', + 'unmatched' => 'Geen match', + 'create_credit' => 'Maak creditfactuur', 'transactions' => 'Transacties', 'new_transaction' => 'Nieuwe transactie', 'edit_transaction' => 'Transactie bewerken', @@ -4677,7 +4677,7 @@ Email: :email
    ', 'removed_transaction' => 'Transactie succesvol verwijderd', 'restored_transaction' => 'Transactie succesvol hersteld', 'search_transaction' => 'Zoek transactie', - 'search_transactions' => 'Zoek :count Transacties', + 'search_transactions' => 'Zoek :count transacties', 'deleted_bank_account' => 'Succesvol verwijderde bankrekening', 'removed_bank_account' => 'Bankrekening succesvol verwijderd', 'restored_bank_account' => 'Bankrekening succesvol hersteld', @@ -4685,21 +4685,21 @@ Email: :email
    ', 'search_bank_accounts' => 'Zoek :count bankrekeningen', 'code_was_sent_to' => 'Er is een code verzonden via sms naar :number', 'verify_phone_number_2fa_help' => 'Verifieer uw telefoonnummer voor 2FA-back-up', - 'enable_applying_payments_later' => 'Schakel Betalingen later toepassen in', - 'line_item_tax_rates' => 'Lijn item BTW-Tarief', - 'show_tasks_in_client_portal' => 'Toon Taken in Klantenportaal', + 'enable_applying_payments_later' => 'Schakel het later toepassen van betalingen in', + 'line_item_tax_rates' => 'Belastingtarief factuurregels', + 'show_tasks_in_client_portal' => 'Toon taken in klantenportaal', 'notification_quote_expired_subject' => 'Offerte :invoice is verlopen voor :client', 'notification_quote_expired' => 'De volgende Offerte :invoice voor klant :client en :amount is nu verlopen.', 'auto_sync' => 'Automatisch synchroniseren', 'refresh_accounts' => 'Ververs accounts', 'upgrade_to_connect_bank_account' => 'Upgrade naar Enterprise om uw bankrekening te koppelen', 'click_here_to_connect_bank_account' => 'Klik hier om uw bankrekening te koppelen', - 'include_tax' => 'BTW inclusief', + 'include_tax' => 'Inclusief BTW', 'email_template_change' => 'De hoofdtekst van het e-mailsjabloon kan worden gewijzigd', 'task_update_authorization_error' => 'Onvoldoende machtigingen of taak is mogelijk vergrendeld', 'cash_vs_accrual' => 'Boekhouding op transactiebasis', 'cash_vs_accrual_help' => 'Inschakelen voor rapportage op transactiebasis, uitschakelen voor rapportage op kasbasis.', - 'expense_paid_report' => 'Onkosten rapportage', + 'expense_paid_report' => 'Onkostenrapportage', 'expense_paid_report_help' => 'Schakel in voor het rapporteren van alle onkosten, schakel uit voor het rapporteren van alleen betaalde onkosten', 'online_payment_email_help' => 'Stuur een e-mail wanneer een online betaling is gedaan', 'manual_payment_email_help' => 'Stuur een e-mail bij het handmatig invoeren van een betaling', @@ -4728,8 +4728,8 @@ Email: :email
    ', 'match_all_rules_help' => 'Alle criteria moeten overeenkomen om de regel toe te passen', 'auto_convert_help' => 'Zet gekoppelde transacties automatisch om in onkosten', 'rules' => 'Reglement', - 'transaction_rule' => 'Transactie Regel', - 'transaction_rules' => 'Transactie regels', + 'transaction_rule' => 'Transactieregel', + 'transaction_rules' => 'Transactieregels', 'new_transaction_rule' => 'Nieuwe transactieregel', 'edit_transaction_rule' => 'Transactieregel bewerken', 'created_transaction_rule' => 'Regel gemaakt', @@ -4764,7 +4764,7 @@ Email: :email
    ', 'purchase_order_sent' => 'Inkooporder verzonden', 'purchase_order_viewed' => 'Inkooporder bekeken', 'purchase_order_accepted' => 'Inkooporder geaccepteerd', - 'credit_payment_error' => 'Het kredietbedrag kan niet groter zijn dan het betalingsbedrag', + 'credit_payment_error' => 'Het kredietbedrag mag niet hoger zijn dan de betaling', 'convert_payment_currency_help' => 'Stel een wisselkoers in bij het invoeren van een handmatige betaling', 'convert_expense_currency_help' => 'Stel een wisselkoers in bij het aanmaken van een uitgave', 'matomo_url' => 'Matomo-URL', @@ -4778,18 +4778,18 @@ Email: :email
    ', 'inventory_threshold' => 'Voorraaddrempel', 'emailed_statement' => 'Verklaring in wachtrij geplaatst om te worden verzonden', 'show_email_footer' => 'Toon e-mailvoettekst', - 'invoice_task_hours' => 'Werkuren factureren', + 'invoice_task_hours' => 'Gewerkte uren factureren', 'invoice_task_hours_help' => 'Voeg de uren toe aan de factuurregelitems', - 'auto_bill_standard_invoices' => 'Auto Bill Standaard Facturen', - 'auto_bill_recurring_invoices' => 'Terugkerende facturen automatisch factureren', + 'auto_bill_standard_invoices' => 'Standaardfacturen automatisch incasseren', + 'auto_bill_recurring_invoices' => 'Terugkerende facturen automatisch incasseren', 'email_alignment' => 'E-mailuitlijning', 'pdf_preview_location' => 'Pdf-voorbeeldlocatie', - 'mailgun' => 'Postpistool', + 'mailgun' => 'Mailgun', 'brevo' => 'Brevo', - 'postmark' => 'Poststempel', + 'postmark' => 'Postmark', 'microsoft' => 'Microsoft', 'click_plus_to_create_record' => 'Klik op + om een record te maken', - 'last365_days' => 'Laatste 365 dagen', + 'last365_days' => 'Afgelopen 365 dagen', 'import_design' => 'Ontwerp importeren', 'imported_design' => 'Ontwerp geïmporteerd', 'invalid_design' => 'Het ontwerp is ongeldig, de :value sectie ontbreekt', @@ -4799,7 +4799,7 @@ Email: :email
    ', 'notify_vendor_when_paid_help' => 'Stuur een e-mail naar de leverancier wanneer de onkosten zijn gemarkeerd als betaald', 'update_payment' => 'Betaling bijwerken', 'markup' => 'Opmaak', - 'unlock_pro' => 'Ontgrendel Pro', + 'unlock_pro' => 'Ontgrendel Pro-abbo', 'upgrade_to_paid_plan_to_schedule' => 'Upgrade naar een betaald abonnement om schema\'s te maken', 'next_run' => 'Volgende run', 'all_clients' => 'Alle klanten', @@ -4807,16 +4807,16 @@ Email: :email
    ', 'show_payments_table' => 'Toon betalingstabel', 'only_clients_with_invoices' => 'Alleen klanten met facturen', 'email_statement' => 'E-mail verklaring', - 'once' => 'Eenmaal', + 'once' => 'Eenmalig', 'schedules' => 'Schema\'s', 'new_schedule' => 'Nieuw schema', 'edit_schedule' => 'Schema bewerken', - 'created_schedule' => 'Planning gemaakt', - 'updated_schedule' => 'Planning bijgewerkt', - 'archived_schedule' => 'Planning is gearchiveerd', - 'deleted_schedule' => 'Planning succesvol verwijderd', - 'removed_schedule' => 'Planning is succesvol verwijderd', - 'restored_schedule' => 'Planning is hersteld', + 'created_schedule' => 'Schema gemaakt', + 'updated_schedule' => 'Schema is bijgewerkt', + 'archived_schedule' => 'Schema is gearchiveerd', + 'deleted_schedule' => 'Schema is succesvol verwijderd', + 'removed_schedule' => 'Schema is succesvol verwijderd', + 'restored_schedule' => 'Schema is hersteld', 'search_schedule' => 'Zoek schema', 'search_schedules' => 'Zoek schema\'s', 'update_product' => 'Product bijwerken', @@ -4826,7 +4826,7 @@ Email: :email
    ', 'sent_quote' => 'Verzonden offerte', 'sent_credit' => 'Verzonden tegoed', 'sent_purchase_order' => 'Inkooporder verzonden', - 'image_url' => 'afbeelding URL', + 'image_url' => 'Afbeeldings-URL', 'max_quantity' => 'Maximale hoeveelheid', 'test_url' => 'Test-URL', 'auto_bill_help_off' => 'Optie wordt niet getoond', @@ -4837,10 +4837,10 @@ Email: :email
    ', 'edit_all' => 'Alles bewerken', 'accept_purchase_order_number' => 'Accepteer inkoopordernummer', 'accept_purchase_order_number_help' => 'Stel klanten in staat om een PO-nummer op te geven bij het goedkeuren van een offerte', - 'from_email' => 'Van email', + 'from_email' => 'Van e-mail', 'show_preview' => 'Toon voorbeeld', 'show_paid_stamp' => 'Betaalde zegel tonen', - 'show_shipping_address' => 'Verzendadres weergeven', + 'show_shipping_address' => 'Leveringsadres weergeven', 'no_documents_to_download' => 'Er zijn geen documenten in de geselecteerde records om te downloaden', 'pixels' => 'Pixels', 'logo_size' => 'Logo-formaat', @@ -4864,7 +4864,7 @@ Email: :email
    ', 'no_assigned_tasks' => 'Geen factureerbare taken voor dit project', 'authorization_failure' => 'Onvoldoende machtigingen om deze actie uit te voeren', 'authorization_sms_failure' => 'Verifieer uw account om e-mails te verzenden.', - 'white_label_body' => 'Bedankt voor het aanschaffen van een white label-licentie.

    Uw licentiesleutel is:

    :license_key

    U kunt uw licentie hier beheren: https://invoiceninja.invoicing.co/client/login', + 'white_label_body' => 'Bedankt voor het aanschaffen van een whitelabel-licentie.

    Uw licentiesleutel is:

    :license_key

    U kunt uw licentie hier beheren: https://invoiceninja.invoicing.co/client/login', 'payment_type_Klarna' => 'Klarna', 'payment_type_Interac E Transfer' => 'Interac E-overdracht', 'xinvoice_payable' => 'Te betalen binnen :payeddue vervaldagen netto tot :paydate', @@ -4889,18 +4889,18 @@ Email: :email
    ', 'optional_one_time_products' => 'Optionele eenmalige producten', 'required' => 'Vereist', 'hidden' => 'Verborgen', - 'payment_links' => 'Betalingslinks', - 'payment_link' => 'Betalingslink', + 'payment_links' => 'Betaallinks', + 'payment_link' => 'Betaallink', 'new_payment_link' => 'Nieuwe betaallink', - 'edit_payment_link' => 'Betalingslink bewerken', + 'edit_payment_link' => 'Betaallink bewerken', 'created_payment_link' => 'Betaallink aangemaakt', 'updated_payment_link' => 'Betaallink succesvol geüpdatet', - 'archived_payment_link' => 'Succesvol gearchiveerde betalingslink', - 'deleted_payment_link' => 'Betalingslink succesvol verwijderd', + 'archived_payment_link' => 'Succesvol gearchiveerde betaallink', + 'deleted_payment_link' => 'Betaallink succesvol verwijderd', 'removed_payment_link' => 'Betaallink succesvol verwijderd', 'restored_payment_link' => 'Betaallink succesvol hersteld', - 'search_payment_link' => 'Zoek 1 Betaallink', - 'search_payment_links' => 'Zoek :count Betalingslinks', + 'search_payment_link' => 'Zoek 1 betaallink', + 'search_payment_links' => 'Zoek :count betaallinks', 'increase_prices' => 'Verhoog de prijzen', 'update_prices' => 'Prijzen bijwerken', 'incresed_prices' => 'Met succes in de wachtrij geplaatste prijzen worden verhoogd', @@ -4922,8 +4922,8 @@ Email: :email
    ', 'client_balance_report' => 'Klant saldo rapport', 'client_sales_report' => 'Klant verkoop rapport', 'user_sales_report' => 'Verkooprapport van de gebruiker', - 'aged_receivable_detailed_report' => 'Gedetailleerd rapport ouderdomsvorderingen', - 'aged_receivable_summary_report' => 'Samenvattend rapport ouderdomsvorderingen', + 'aged_receivable_detailed_report' => 'Gedetailleerd rapport verouderde vorderingen', + 'aged_receivable_summary_report' => 'Samenvattend rapport verouderde vorderingen', 'taxable_amount' => 'Belastbaar bedrag', 'tax_summary' => 'Belastingoverzicht', 'oauth_mail' => 'OAuth/Mail', @@ -4936,7 +4936,7 @@ Email: :email
    ', 'seller_subregion' => 'Verkoper Subregio', 'calculate_taxes' => 'Belastingen berekenen', 'calculate_taxes_help' => 'Bereken automatisch belastingen bij het opslaan van facturen', - 'link_expenses' => 'Link kosten', + 'link_expenses' => 'Kosten koppelen', 'converted_client_balance' => 'Geconverteerd klantensaldo', 'converted_payment_balance' => 'Geconverteerd betalingssaldo', 'total_hours' => 'Totaal aantal uren', @@ -4951,13 +4951,13 @@ Email: :email
    ', 'physical_goods' => 'Fysieke goederen', 'digital_products' => 'Digitale producten', 'services' => 'Diensten', - 'shipping' => 'Verzenden', + 'shipping' => 'Verzending', 'tax_exempt' => 'Vrijgesteld van belasting', 'late_fee_added_locked_invoice' => 'Late vergoeding voor factuur :invoice toegevoegd op :date', 'lang_Khmer' => 'Khmer', 'routing_id' => 'Routerings-ID', - 'enable_e_invoice' => 'E-Factuur activeren', - 'e_invoice_type' => 'E-Factuur type', + 'enable_e_invoice' => 'E-factuur activeren', + 'e_invoice_type' => 'E-factuur type', 'reduced_tax' => 'Verlaagde belasting', 'override_tax' => 'Belasting overschrijven', 'zero_rated' => 'Nul nominaal', @@ -4971,9 +4971,9 @@ Email: :email
    ', 'rename' => 'Hernoem', 'renamed_document' => 'Document succesvol hernoemd', 'e_invoice' => 'E-factuur', - 'light_dark_mode' => 'Licht/Donkere modus', + 'light_dark_mode' => 'Lichte-/donkere modus', 'activities' => 'Activiteiten', - 'recent_transactions' => "Hier zijn het bedrijfs meest recente transacties:", + 'recent_transactions' => "Hier zijn de meest recente transacties van uw bedrijf:", 'country_Palestine' => "Palestina", 'country_Taiwan' => 'Taiwan', 'duties' => 'Taken', @@ -4984,7 +4984,7 @@ Email: :email
    ', 'enable_auto_bill' => 'Schakel automatische facturering in', 'email_count_invoices' => 'E-mail :count -facturen', 'invoice_task_item_description' => 'Factuurtaak Itembeschrijving', - 'invoice_task_item_description_help' => 'Voeg de artikelbeschrijving toe aan de factuurregelitems', + 'invoice_task_item_description_help' => 'Voeg de artikelbeschrijving toe aan de factuurregels', 'next_send_time' => 'Volgende verzendtijd', 'uploaded_certificate' => 'Certificaat succesvol geüpload', 'certificate_set' => 'Certificaat ingesteld', @@ -4996,14 +4996,14 @@ Email: :email
    ', 'valid_vat_number' => 'Geldig BTW-nummer', 'react_notification_link' => 'Reageer op meldingslinks', 'react_notification_link_help' => 'E-mails van beheerders bevatten links naar de reactietoepassing', - 'show_task_billable' => 'Toon taak factureerbaar', + 'show_task_billable' => 'Toon factureerbare taken', 'credit_item' => 'Kredietartikel', 'drop_file_here' => 'Zet het bestand hier neer', 'files' => 'Bestanden', 'camera' => 'Camera', 'gallery' => 'Galerij', 'project_location' => 'Project Locatie', - 'add_gateway_help_message' => 'Voeg een betalingsgateway toe (bijv. Stripe, WePay of PayPal) om online betalingen te accepteren', + 'add_gateway_help_message' => 'Voeg een betaalprovider toe (bijv. Stripe, WePay of PayPal) om online betalingen te accepteren', 'lang_Hungarian' => 'Hongaars', 'use_mobile_to_manage_plan' => 'Gebruik de instellingen van uw telefoonabonnement om uw abonnement te beheren', 'item_tax3' => 'Artikelbelasting3', @@ -5029,7 +5029,7 @@ Email: :email
    ', 'county' => 'District', 'tax_details' => 'Belastinggegevens', 'activity_10_online' => ':contact heeft betaling uitgevoerd :payment voor factuur :invoice voor :client', - 'activity_10_manual' => ':user ingevoerde betaling :payment voor factuur :invoice voor :client', + 'activity_10_manual' => ':user heeft betaling :payment ingevoerd voor factuur :invoice voor :client', 'default_payment_type' => 'Standaard betalingstype', 'number_precision' => 'Cijferprecisie', 'number_precision_help' => 'Bepaalt het aantal decimalen dat in de interface wordt ondersteund', @@ -5044,26 +5044,26 @@ Email: :email
    ', 'reverse_tax_info' => 'Houd er rekening mee dat op deze levering een verleggingsregeling van toepassing is', 'currency_nicaraguan_cordoba' => 'Nicaraguaans Córdoba', 'public' => 'Openbaar', - 'private' => 'Privaat', + 'private' => 'Privé', 'image' => 'Afbeelding', - 'other' => 'Ander', + 'other' => 'Overig', 'linked_to' => 'Gekoppeld aan', 'file_saved_in_path' => 'Het bestand is opgeslagen in :path', - 'unlinked_transactions' => 'Succesvol :count transacties ontkoppeld.', + 'unlinked_transactions' => 'Succesvol :count transacties ontkoppeld', 'unlinked_transaction' => 'Transactie ontkoppeld', 'view_dashboard_permission' => 'Geef de gebruiker toegang tot het dashboard, waarbij de beschikbare rechten bepalen welke gegevens zij kunnen zien', 'marked_sent_credits' => 'Succesvol gemarkeerde verzonden credits', - 'show_document_preview' => 'Toon Documentvoorbeeld', + 'show_document_preview' => 'Toon documentvoorbeeld', 'cash_accounting' => 'Kasboekhouding', 'click_or_drop_files_here' => 'Klik hier of sleep bestanden hierheen', - 'set_public' => 'Openbaar instellen', - 'set_private' => 'Privé instellen', + 'set_public' => 'Openbaar', + 'set_private' => 'Privé', 'individual' => 'Individueel', 'business' => 'Bedrijf', 'partnership' => 'Vennootschap', - 'trust' => 'Vertrouwen', + 'trust' => 'Trustfonds', 'charity' => 'Goed doel', - 'government' => 'Regering', + 'government' => 'Overheid', 'in_stock_quantity' => 'Voorraadhoeveelheid', 'vendor_contact' => 'Contactpersoon leverancier', 'expense_status_4' => 'Onbetaald', @@ -5080,16 +5080,16 @@ Email: :email
    ', 'upcoming' => 'Aankomend', 'client_contact' => 'Klantcontact', 'uncategorized' => 'Niet gecategoriseerd', - 'login_notification' => 'Aanmeldingsmelding', + 'login_notification' => 'Inlogmelding', 'login_notification_help' => 'Stuurt een e-mail met de melding dat er een login heeft plaatsgevonden.', 'payment_refund_receipt' => 'Betalingsrestitutieontvangst # :number', 'payment_receipt' => 'Betalingsbewijs # :number', 'load_template_description' => 'De sjabloon wordt toegepast op het volgende:', - 'run_template' => 'Run Template', - 'statement_design' => 'Verklaring ontwerp', + 'run_template' => 'Sjabloon toepassen', + 'statement_design' => 'Ontwerp van samenvatting', 'delivery_note_design' => 'Ontwerp van leveringsbon', 'payment_receipt_design' => 'Ontwerp van betalingsontvangst', - 'payment_refund_design' => 'Betaling Terugbetaling Ontwerp', + 'payment_refund_design' => 'Ontwerp van terugbetaling', 'task_extension_banner' => 'Voeg de Chrome-extensie toe om uw taken te beheren', 'watch_video' => 'Bekijk video', 'view_extension' => 'Bekijk Extensie', @@ -5117,7 +5117,7 @@ Email: :email
    ', 'charges' => 'Kosten', 'email_report' => 'E-mailrapport', 'payment_type_Pay Later' => 'Betaal later', - 'payment_type_credit' => 'Betalingstype Krediet', + 'payment_type_credit' => 'Betalingstype krediet', 'payment_type_debit' => 'Betalingswijze Debet', 'send_emails_to' => 'Stuur e-mails naar', 'primary_contact' => 'Primaire contactpersoon', @@ -5131,26 +5131,26 @@ Email: :email
    ', 'nordigen_handler_error_heading_account_config_invalid' => 'Ontbrekende inloggegevens', 'nordigen_handler_error_contents_account_config_invalid' => 'Ongeldige of ontbrekende inloggegevens voor Gocardless-bankrekeninggegevens. Neem contact op met de ondersteuning voor hulp als dit probleem zich blijft voordoen.', 'nordigen_handler_error_heading_not_available' => 'Niet beschikbaar', - 'nordigen_handler_error_contents_not_available' => 'Functie niet beschikbaar, alleen Enterprise Plan.', + 'nordigen_handler_error_contents_not_available' => 'Functie niet beschikbaar, alleen binnen het Enterprise-abonnement.', 'nordigen_handler_error_heading_institution_invalid' => 'Ongeldige instelling', 'nordigen_handler_error_contents_institution_invalid' => 'Het opgegeven instellings-ID is ongeldig of niet meer geldig.', 'nordigen_handler_error_heading_ref_invalid' => 'Ongeldige referentie', 'nordigen_handler_error_contents_ref_invalid' => 'GoCardless heeft geen geldige referentie opgegeven. Voer de stroom opnieuw uit en neem contact op met de ondersteuning als dit probleem zich blijft voordoen.', 'nordigen_handler_error_heading_not_found' => 'Ongeldige aanvraag', 'nordigen_handler_error_contents_not_found' => 'GoCardless heeft geen geldige referentie opgegeven. Voer de stroom opnieuw uit en neem contact op met de ondersteuning als dit probleem zich blijft voordoen.', - 'nordigen_handler_error_heading_requisition_invalid_status' => 'Niet klaar', - 'nordigen_handler_error_contents_requisition_invalid_status' => 'Je hebt deze site te vroeg gebeld. Voltooi de autorisatie en vernieuw deze pagina. Neem contact op met de ondersteuning voor hulp als dit probleem zich blijft voordoen.', + 'nordigen_handler_error_heading_requisition_invalid_status' => 'Niet gereed', + 'nordigen_handler_error_contents_requisition_invalid_status' => 'U hebt deze pagina te vroeg bereikt. Voltooi de autorisatie en vernieuw deze pagina. Neem contact op met de klantenservice voor hulp als dit probleem zich blijft voordoen.', 'nordigen_handler_error_heading_requisition_no_accounts' => 'Geen accounts geselecteerd', 'nordigen_handler_error_contents_requisition_no_accounts' => 'De service heeft geen geldige accounts geretourneerd. Overweeg om de stroom opnieuw te starten.', 'nordigen_handler_restart' => 'Start de stroom opnieuw.', 'nordigen_handler_return' => 'Terug naar applicatie.', 'lang_Lao' => 'Laos', 'currency_lao_kip' => 'Laotiaanse kip', - 'yodlee_regions' => 'Regio's: VS, VK, Australië en India', - 'nordigen_regions' => 'Regio's: Europa en VK', + 'yodlee_regions' => 'Regio\'s: VS, VK, Australië en India', + 'nordigen_regions' => 'Regio\'s: Europa en VK', 'select_provider' => 'Selecteer Aanbieder', 'nordigen_requisition_subject' => 'Aanvraag is verlopen. Authenticeer opnieuw.', - 'nordigen_requisition_body' => 'De toegang tot bankrekeningfeeds is verlopen zoals vastgelegd in de Eindgebruikersovereenkomst.

    Meld u aan bij Invoice Ninja en authenticeer opnieuw bij uw banken om transacties te blijven ontvangen.', + 'nordigen_requisition_body' => 'De toegang tot bankrekeningkoppelingen is verlopen zoals vastgelegd in de gebruikersovereenkomst.

    Meld u aan bij Invoice Ninja en log opnieuw in bij uw banken om transacties te blijven ontvangen.', 'participant' => 'Deelnemer', 'participant_name' => 'Naam deelnemer', 'client_unsubscribed' => 'Klant heeft zich afgemeld voor e-mails.', @@ -5169,7 +5169,7 @@ Email: :email
    ', 'my_bank' => 'Mijn bank', 'pay_later' => 'Betaal later', 'local_domain' => 'Lokaal domein', - 'verify_peer' => 'Verifieer peer', + 'verify_peer' => 'Verifieer versleutelde verbinding', 'nordigen_help' => 'Let op: voor het koppelen van een account is een GoCardless/Nordigen API-sleutel vereist', 'ar_detailed' => 'Debiteuren gedetailleerd', 'ar_summary' => 'Overzicht debiteuren', @@ -5182,7 +5182,7 @@ Email: :email
    ', 'step_dependency_order_fail' => 'Component ":step" is afhankelijk van ":dependency". De volgorde van de component(en) is correct.', 'step_authentication_fail' => 'U moet ten minste één van de authenticatiemethoden opnemen.', 'auth.login' => 'Log in', - 'auth.login-or-register' => 'Log in of Registreer', + 'auth.login-or-register' => 'Log in of registreer', 'auth.register' => 'Register', 'cart' => 'Winkelwagen', 'methods' => 'Methoden', @@ -5190,16 +5190,16 @@ Email: :email
    ', 'add_step' => 'Stap toevoegen', 'steps' => 'Stappen', 'steps_order_help' => 'De volgorde van de stappen is belangrijk. De eerste stap mag niet afhankelijk zijn van een andere stap. De tweede stap moet afhankelijk zijn van de eerste stap, enzovoort.', - 'other_steps' => 'Andere stappen', + 'other_steps' => 'Overige stappen', 'use_available_payments' => 'Gebruik beschikbare betalingen', 'test_email_sent' => 'E-mail succesvol verzonden', - 'gateway_type' => 'Gatewaytype', + 'gateway_type' => 'Type betaalprovider', 'save_template_body' => 'Wilt u deze importtoewijzing opslaan als sjabloon voor toekomstig gebruik?', 'save_as_template' => 'Sjabloontoewijzing opslaan', 'checkout_only_for_existing_customers' => 'Afrekenen is alleen mogelijk voor bestaande klanten. Log in met een bestaand account om af te rekenen.', 'checkout_only_for_new_customers' => 'Afrekenen is alleen mogelijk voor nieuwe klanten. Registreer een nieuw account om af te rekenen.', - 'auto_bill_standard_invoices_help' => 'Standaardfacturen automatisch factureren op de vervaldatum', - 'auto_bill_on_help' => 'Automatische factuur op verzenddatum OF vervaldatum (terugkerende facturen)', + 'auto_bill_standard_invoices_help' => 'Standaardfacturen automatisch innen op de vervaldatum', + 'auto_bill_on_help' => 'Automatische betaling op verzenddatum OF vervaldatum (terugkerende facturen)', 'use_available_credits_help' => 'Pas eventuele creditsaldi toe op betalingen voordat u een betaalmethode in rekening brengt', 'use_unapplied_payments' => 'Gebruik niet-verwerkte betalingen', 'use_unapplied_payments_help' => 'Pas eventuele betalingssaldi toe voordat u een betaalmethode in rekening brengt', @@ -5213,11 +5213,11 @@ Email: :email
    ', 'purchase_order_items' => 'Inkooporderartikelen', 'csv_rows_length' => 'Er zijn geen gegevens gevonden in dit CSV-bestand', 'accept_payments_online' => 'Accepteer betalingen online', - 'all_payment_gateways' => 'Bekijk alle betalingsgateways', + 'all_payment_gateways' => 'Bekijk alle betaalproviders', 'product_cost' => 'Productkosten', 'duration_words' => 'Duur in woorden', 'upcoming_recurring_invoices' => 'Aankomende terugkerende facturen', - 'shipping_country_id' => 'Verzendland', + 'shipping_country_id' => 'Land leveringsadres', 'show_table_footer' => 'Tabelvoettekst weergeven', 'show_table_footer_help' => 'Geeft de totalen weer in de voettekst van de tabel', 'total_invoices' => 'Totaal facturen', @@ -5226,81 +5226,90 @@ Email: :email
    ', 'valid_credentials' => 'De legitimatiegegevens zijn geldig', 'e_quote' => 'E-offerte', 'e_credit' => 'E-krediet', - 'e_purchase_order' => 'E-aankooporder', + 'e_purchase_order' => 'E-inkooporder', 'e_quote_type' => 'Type e-offerte', 'unlock_unlimited_clients' => 'Upgrade om een onbeperkt aantal klanten te ontgrendelen!', - 'download_e_purchase_order' => 'E-aankooporder downloaden', + 'download_e_purchase_order' => 'E-inkooporder downloaden', 'flutter_web_warning' => 'Voor de beste prestaties raden we u aan de nieuwe web-app of de desktop-app te gebruiken', - 'rappen_rounding' => 'Rappenafronding', + 'rappen_rounding' => 'Afronden op 5 cent', 'rappen_rounding_help' => 'Rond het bedrag af op 5 cent', 'assign_group' => 'Groep toewijzen', - 'paypal_advanced_cards' => 'Advanced Card Payments', - 'local_domain_help' => 'EHLO domain (optional)', - 'port_help' => 'ie. 25,587,465', - 'host_help' => 'ie. smtp.gmail.com', - 'always_show_required_fields' => 'Allows show required fields form', - 'always_show_required_fields_help' => 'Displays the required fields form always at checkout', - 'advanced_cards' => 'Advanced Cards', - 'activity_140' => 'Statement sent to :client', - 'invoice_net_amount' => 'Invoice Net Amount', - 'round_to_minutes' => 'Round To Minutes', - '1_second' => '1 Second', - '1_minute' => '1 Minute', - '5_minutes' => '5 Minutes', - '15_minutes' => '15 Minutes', - '30_minutes' => '30 Minutes', - '1_hour' => '1 Hour', - '1_day' => '1 Day', - 'round_tasks' => 'Task Rounding Direction', - 'round_tasks_help' => 'Round task times up or down.', - 'direction' => 'Direction', - 'round_up' => 'Round Up', - 'round_down' => 'Round Down', - 'task_round_to_nearest' => 'Round To Nearest', - 'task_round_to_nearest_help' => 'The interval to round the task to.', - 'bulk_updated' => 'Successfully updated data', - 'bulk_update' => 'Bulk Update', - 'calculate' => 'Calculate', - 'sum' => 'Sum', - 'money' => 'Money', - 'web_app' => 'Web App', - 'desktop_app' => 'Desktop App', - 'disconnected' => 'Disconnected', - 'reconnect' => 'Reconnect', - 'e_invoice_settings' => 'E-Invoice Settings', - 'btcpay_refund_subject' => 'Refund of your invoice via BTCPay', - 'btcpay_refund_body' => 'A refund intended for you has been issued. To claim it via BTCPay, please click on this link:', - 'currency_mauritanian_ouguiya' => 'Mauritanian Ouguiya', - 'currency_bhutan_ngultrum' => 'Bhutan Ngultrum', - 'end_of_month' => 'End Of Month', - 'merge_e_invoice_to_pdf' => 'Merge E-Invoice and PDF', - 'task_assigned_subject' => 'New task assignment [Task :task] [ :date ]', - 'task_assigned_body' => 'You have been assigned task :task

    Description: :description

    Client: :client', - 'activity_141' => 'User :user entered note: :notes', - 'quote_reminder_subject' => 'Reminder: Quote :quote from :company', - 'quote_reminder_message' => 'Reminder for quote :number for :amount', - 'quote_reminder1' => 'First Quote Reminder', - 'before_valid_until_date' => 'Before the valid until date', - 'after_valid_until_date' => 'After the valid until date', - 'after_quote_date' => 'After the quote date', - 'remind_quote' => 'Remind Quote', - 'end_of_month' => 'End Of Month', - 'tax_currency_mismatch' => 'Tax currency is different from invoice currency', - 'edocument_import_already_exists' => 'The invoice has already been imported on :date', - 'before_valid_until' => 'Before the valid until', - 'after_valid_until' => 'After the valid until', - 'task_assigned_notification' => 'Task Assigned Notification', - 'task_assigned_notification_help' => 'Send an email when a task is assigned', - 'invoices_locked_end_of_month' => 'Invoices are locked at the end of the month', - 'referral_url' => 'Referral URL', - 'add_comment' => 'Add Comment', - 'added_comment' => 'Successfully saved comment', + 'paypal_advanced_cards' => 'Uitgebreide kaartbetalingen', + 'local_domain_help' => 'EHLO-domein (optioneel)', + 'port_help' => 'bijv. 25,587,465', + 'host_help' => 'bijv. smtp.gmail.com', + 'always_show_required_fields' => 'Altijd het verplichte velden formulier tonen', + 'always_show_required_fields_help' => 'Toon het verplichte velden formulier altijd bij het afrekenen', + 'advanced_cards' => 'Uitgebreide kaarten', + 'activity_140' => 'Overzicht verzonden naar :client', + 'invoice_net_amount' => 'Nettobedrag', + 'round_to_minutes' => 'Afronden op minuten', + '1_second' => '1 seconde', + '1_minute' => '1 minuut', + '5_minutes' => '5 minuten', + '15_minutes' => '15 minuten', + '30_minutes' => '30 minuten', + '1_hour' => '1 uur', + '1_day' => '1 dag', + 'round_tasks' => 'Afrondrichting voor taken', + 'round_tasks_help' => 'Rond tijden naar boven of beneden af', + 'direction' => 'Richting', + 'round_up' => 'Afronden naar boven', + 'round_down' => 'Afronden naar beneden', + 'task_round_to_nearest' => 'Afronden naar dichtstbijzijnde', + 'task_round_to_nearest_help' => 'Afrondinterval voor de taak', + 'bulk_updated' => 'Gegevens succesvol bijgewerkt', + 'bulk_update' => 'In bulk bewerken', + 'calculate' => 'Berekenen', + 'sum' => 'Som', + 'money' => 'Geld', + 'web_app' => 'Web-app', + 'desktop_app' => 'Desktopapplicatie', + 'disconnected' => 'Verbinding verbroken', + 'reconnect' => 'Verbind opnieuw', + 'e_invoice_settings' => 'E-factuurinstellingen', + 'btcpay_refund_subject' => 'Terugbetaling van uw factuur via BTCPay', + 'btcpay_refund_body' => 'Er is een terugbetaling uitgevoerd die voor u is bestemd. Om deze te claimen via BTCPay, kunt u de volgende link gebruiken:', + 'currency_mauritanian_ouguiya' => 'Mauritaanse Ouguiya', + 'currency_bhutan_ngultrum' => 'Bhutaanse Ngultrum', + 'end_of_month' => 'Einde van de maand', + 'merge_e_invoice_to_pdf' => 'E-factuur en PDF samenvoegen', + 'task_assigned_subject' => 'Nieuwe taak toegewezen [Task :task] [ :date ]', + 'task_assigned_body' => 'Taak :task is aan u toegewezen.

    Beschrijving: :description

    Klant: :client', + 'activity_141' => 'Gebruiker :user heeft een notitie toegevoegd: :notes', + 'quote_reminder_subject' => 'Herinnering: offerte :quote van :company', + 'quote_reminder_message' => 'Herinnering voor offerte :number voor een bedrag van :amount', + 'quote_reminder1' => 'Eerste herinnering voor offerte', + 'before_valid_until_date' => 'Voor de geldigheidsdatum', + 'after_valid_until_date' => 'Na de geldigheidsdatum', + 'after_quote_date' => 'Na de vervaldatum', + 'remind_quote' => 'Herinneringen offerte', + 'end_of_month' => 'Einde van de maand', + 'tax_currency_mismatch' => 'De belastingvaluta verschilt van de factuurvaluta', + 'edocument_import_already_exists' => 'De factuur is al geïmporteerd op :date', + 'before_valid_until' => 'Voor de geldigheidsdatum', + 'after_valid_until' => 'Na de geldigheidsdatum', + 'task_assigned_notification' => 'Notificatie voor toegewezen taak', + 'task_assigned_notification_help' => 'Verstuur een e-mail zodra een taak is toegewezen', + 'invoices_locked_end_of_month' => 'Facturen worden vastgezet aan het einde van de maand', + 'referral_url' => 'Referral-URL', + 'add_comment' => 'Commentaar toevoegen', + 'added_comment' => 'Commentaar succesvol opgeslagen', 'tickets' => 'Tickets', - 'assigned_group' => 'Successfully assigned group', - 'merge_to_pdf' => 'Merge to PDF', - '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_help' => 'Automatically expands the notes section within the products table to display more lines.', + 'assigned_group' => 'Groep succesvol toegewezen', + 'merge_to_pdf' => 'Samenvoegen in PDF', + 'latest_requires_php_version' => 'Let op: voor de nieuwste versie is PHP :version vereist', + 'auto_expand_product_table_notes' => 'Automatisch de notities in de producttabel uitklappen', + 'auto_expand_product_table_notes_help' => 'Hiermee worden notities in de producttabel automatisch uitgeklapt om meer regels te kunnen tonen.', + 'institution_number' => 'Banknummer (institution number)', + 'transit_number' => 'Transitnummer', + 'personal' => 'Persoonlijke gegevens', + 'address_information' => 'Adresinformatie', + 'enter_the_information_for_the_bank_account' => 'Voer de rekeninggegevens in', + 'account_holder_information' => 'Rekeninghouderinformatie', + 'enter_information_for_the_account_holder' => 'Voer de gegevens in van de rekeninghouder', + 'customer_type' => 'Klanttype', + 'process_date' => 'Verwerkingsdatum' ); return $lang; From 2a4dd7e5935d842b3cba30a77aba361b8db8bbb1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 5 Aug 2024 18:52:34 +1000 Subject: [PATCH 25/30] Updates for chart queries --- .../ClientPortal/NinjaPlanController.php | 4 +- app/Http/ViewComposers/PortalComposer.php | 6 +- app/Models/Task.php | 63 ++++++++-- app/Services/Chart/ChartCalculations.php | 116 ++++++++++++++++++ app/Services/Chart/ChartService.php | 14 +-- .../portal/ninja2020/plan/trial.blade.php | 46 +++++-- .../ninja2020/plan/trial_confirmed.blade.php | 2 +- 7 files changed, 218 insertions(+), 33 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/NinjaPlanController.php b/app/Http/Controllers/ClientPortal/NinjaPlanController.php index 7d7d3d5ba1b2..3b3c19580488 100644 --- a/app/Http/Controllers/ClientPortal/NinjaPlanController.php +++ b/app/Http/Controllers/ClientPortal/NinjaPlanController.php @@ -80,7 +80,7 @@ class NinjaPlanController extends Controller $data['intent'] = $setupIntent; $data['client'] = Auth::guard('contact')->user()->client; - + return $this->render('plan.trial', $data); } @@ -88,6 +88,8 @@ class NinjaPlanController extends Controller { $trial_started = "Trial Started @ ".now()->format('Y-m-d H:i:s'); + auth()->guard('contact')->user()->fill($request->only(['first_name','last_name']))->save(); + $client = auth()->guard('contact')->user()->client; $client->private_notes = $trial_started; $client->fill($request->all()); diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index 6b0790a0f4ff..9799260c5a17 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -136,11 +136,11 @@ class PortalComposer $data[] = ['title' => ctrans('texts.statement'), 'url' => 'client.statement', 'icon' => 'activity']; - if (Ninja::isHosted() && auth()->guard('contact')->user()->company->id == config('ninja.ninja_default_company_id')) { + // if (Ninja::isHosted() && auth()->guard('contact')->user()->company->id == config('ninja.ninja_default_company_id')) { $data[] = ['title' => ctrans('texts.plan'), 'url' => 'client.plan', 'icon' => 'credit-card']; - } else { + // } else { $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; - } + // } if (auth()->guard('contact')->user()->client->getSetting('client_initiated_payments')) { $data[] = ['title' => ctrans('texts.pre_payment'), 'url' => 'client.pre_payments.index', 'icon' => 'dollar-sign']; diff --git a/app/Models/Task.php b/app/Models/Task.php index 0df362e4d529..89b21ffa81ac 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -16,6 +16,7 @@ use App\Models\CompanyUser; use Illuminate\Support\Carbon; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\SoftDeletes; +use App\Libraries\Currency\Conversion\CurrencyApi; /** * App\Models\Task @@ -159,27 +160,55 @@ class Task extends BaseModel return $this->morphMany(Document::class, 'documentable'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function assigned_user() { return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function user() { return $this->belongsTo(User::class)->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function client() { return $this->belongsTo(Client::class)->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function status() { return $this->belongsTo(TaskStatus::class)->withTrashed(); } - public function stringStatus() + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function invoice() + { + return $this->belongsTo(Invoice::class)->withTrashed(); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function project() + { + return $this->belongsTo(Project::class)->withTrashed(); + } + + public function stringStatus(): string { if($this->invoice_id) { return '
    '.ctrans('texts.invoiced').'
    '; @@ -193,16 +222,6 @@ class Task extends BaseModel } - public function invoice() - { - return $this->belongsTo(Invoice::class)->withTrashed(); - } - - public function project() - { - return $this->belongsTo(Project::class)->withTrashed(); - } - public function calcStartTime() { $parts = json_decode($this->time_log) ?: []; @@ -230,7 +249,7 @@ class Task extends BaseModel public function calcDuration($start_time_cutoff = 0, $end_time_cutoff = 0) { $duration = 0; - $parts = json_decode($this->time_log) ?: []; + $parts = json_decode($this->time_log ?? '{}') ?: []; foreach ($parts as $part) { $start_time = $part[0]; @@ -272,6 +291,26 @@ class Task extends BaseModel return $this->company->settings->default_task_rate ?? 0; } + public function taskCompanyValue(): float + { + $client_currency = $this->client->getSetting('currency_id'); + $company_currency = $this->company->getSetting('currency_id'); + + if($client_currency != $company_currency) + { + $converter = new CurrencyApi(); + return $converter->convert($this->taskValue(), $client_currency, $company_currency); + } + + return $this->taskValue(); + + } + + public function taskValue(): float + { + return round(($this->calcDuration() / 3600) * $this->getRate(),2); + } + public function processLogs() { diff --git a/app/Services/Chart/ChartCalculations.php b/app/Services/Chart/ChartCalculations.php index 92cbbd93c1fc..f8af770d90ff 100644 --- a/app/Services/Chart/ChartCalculations.php +++ b/app/Services/Chart/ChartCalculations.php @@ -14,6 +14,7 @@ namespace App\Services\Chart; use App\Models\Invoice; use App\Models\Payment; use App\Models\Quote; +use App\Models\Task; /** * Class ChartCalculations. @@ -170,4 +171,119 @@ trait ChartCalculations return $result; } + + public function getLoggedTasks($data): int|float + { + //tasks with at least 1 timelog entry. + + $result = 0; + $calculated = collect(); + + $q = Task::query() + ->withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted',0); + + if(in_array($data['period'], ['current,previous'])) { + $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); + } + + if($data['calculation'] != 'count' && $data['format'] == 'money') + { + if($data['currency_id'] != '999') + { + + $q->whereHas('client', function ($query) use ($data){ + $query->where('settings->currency_id', $data['currency_id']); + }); + + } + + $calculated = $this->taskMoneyCalculator($q, $data); + + } + + if($data['calculation'] != 'count' && $data['format'] == 'time') + { + $calculated = $q->get()->map(function ($t){ + return $t->calcDuration(); + }); + } + + match ($data['calculation']) { + 'sum' => $result = $calculated->sum(), + 'avg' => $result = $calculated->avg(), + 'count' => $result = $q->count(), + default => $result = 0, + }; + + return $result; + + } + + private function taskMoneyCalculator($query, $data) + { + + return $query->get() + ->when($data['currency_id'] == '999', function ($collection) { + $collection->map(function ($t) { + return $t->taskCompanyValue(); + }); + }) + ->when($data['currency_id'] != '999', function ($collection) { + + $collection->map(function ($t) { + return $t->taskValue(); + }); + + }); + + } + + public function getInvoicedTasks($data): int|float + { + + $result = 0; + $calculated = collect(); + + $q = Task::query() + ->withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0) + ->whereHas('invoice'); + + if(in_array($data['period'], ['current,previous'])) { + $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); + } + + if($data['calculation'] != 'count' && $data['format'] == 'money') { + + if($data['currency_id'] != '999') { + + $q->whereHas('client', function ($query) use ($data) { + $query->where('settings->currency_id', $data['currency_id']); + }); + + } + + $calculated = $this->taskMoneyCalculator($q, $data); + + } + + if($data['calculation'] != 'count' && $data['format'] == 'time') { + $calculated = $q->get()->map(function ($t) { + return $t->calcDuration(); + }); + } + + match ($data['calculation']) { + 'sum' => $result = $calculated->sum(), + 'avg' => $result = $calculated->avg(), + 'count' => $result = $q->count(), + default => $result = 0, + }; + + return $result; + + } } \ No newline at end of file diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index 4bf080f950e6..f22183f255aa 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -234,13 +234,13 @@ class ChartService match($data['field']){ 'active_invoices' => $results = $this->getActiveInvoices($data), - 'outstanding_invoices' => $results = 0, - 'completed_payments' => $results = 0, - 'refunded_payments' => $results = 0, - 'active_quotes' => $results = 0, - 'unapproved_quotes' => $results = 0, - 'logged_tasks' => $results = 0, - 'invoiced_tasks' => $results = 0, + 'outstanding_invoices' => $results = $this->getOutstandingInvoices($data), + 'completed_payments' => $results = $this->getCompletedPayments($data), + 'refunded_payments' => $results = $this->getRefundedPayments($data), + 'active_quotes' => $results = $this->getActiveQuotes($data), + 'unapproved_quotes' => $results = $this->getUnapprovedQuotes($data), + 'logged_tasks' => $results = $this->getLoggedTasks($data), + 'invoiced_tasks' => $results = $this->getInvoicedTasks($data), 'paid_tasks' => $results = 0, 'logged_expenses' => $results = 0, 'pending_expenses' => $results = 0, diff --git a/resources/views/portal/ninja2020/plan/trial.blade.php b/resources/views/portal/ninja2020/plan/trial.blade.php index 4be765d1bc3a..f905d182ab20 100644 --- a/resources/views/portal/ninja2020/plan/trial.blade.php +++ b/resources/views/portal/ninja2020/plan/trial.blade.php @@ -1451,16 +1451,31 @@ Ensure the default browser behavior of the `hidden` attribute. @csrf -
    +
    + +
    +
    +
    + +
    +
    present()->email() }}', address: { line1: document.querySelector('input[name=address1]').content, diff --git a/resources/views/portal/ninja2020/plan/trial_confirmed.blade.php b/resources/views/portal/ninja2020/plan/trial_confirmed.blade.php index 338db31d485d..b8519f3df7c9 100644 --- a/resources/views/portal/ninja2020/plan/trial_confirmed.blade.php +++ b/resources/views/portal/ninja2020/plan/trial_confirmed.blade.php @@ -1450,7 +1450,7 @@ Ensure the default browser behavior of the `hidden` attribute. type="button" class="mx-[auto] max-w-[212px] bg-primary-blue hover:opacity-80 button button-primary bg-primary rounded-sm text-sm transition duration-300 ease-in md:mx-[0]" > - Account Login + {{ ctrans('texts.return_to_app') }}
    From 7acb3694085d73a75bbbf551d26759251b37583d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 08:22:00 +1000 Subject: [PATCH 26/30] Calculations for cards on dashbaord --- app/Services/Chart/ChartCalculations.php | 186 +++++++++++++++++----- app/Services/Chart/ChartService.php | 12 +- app/Services/Template/TemplateService.php | 2 +- 3 files changed, 150 insertions(+), 50 deletions(-) diff --git a/app/Services/Chart/ChartCalculations.php b/app/Services/Chart/ChartCalculations.php index f8af770d90ff..c3d9487fe3c5 100644 --- a/app/Services/Chart/ChartCalculations.php +++ b/app/Services/Chart/ChartCalculations.php @@ -11,10 +11,12 @@ namespace App\Services\Chart; +use App\Models\Expense; use App\Models\Invoice; use App\Models\Payment; use App\Models\Quote; use App\Models\Task; +use Illuminate\Contracts\Database\Eloquent\Builder; /** * Class ChartCalculations. @@ -174,53 +176,144 @@ trait ChartCalculations public function getLoggedTasks($data): int|float { - //tasks with at least 1 timelog entry. + + $q = $this->taskQuery($data); + + return $this->taskCalculations($q, $data); + + } + + public function getPaidTasks($data): int|float + { + $q = $this->taskQuery($data); + $q->whereHas('invoice', function ($query){ + $query->where('status_id', 4)->where('is_deleted', 0); + }); + + return $this->taskCalculations($q, $data); + + } + + public function getInvoicedTasks($data): int|float + { + + $q = $this->taskQuery($data); + $q->whereHas('invoice'); + + return $this->taskCalculations($q, $data); + + } + + /** + * All Expenses + */ + public function getLoggedExpenses($data): int|float + { + $q = $this->expenseQuery($data); + + return $this->expenseCalculations($q, $data); + } + + + /** + * Expenses that should be invoiced - but are not yet invoiced. + */ + public function getPendingExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->where('should_be_invoiced', true)->whereNull('invoice_id'); + return $this->expenseCalculations($q, $data); + } + + /** + * Invoiced. + */ + public function getInvoicedExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('invoice_id'); + return $this->expenseCalculations($q, $data); + } + + /** + * Paid. + */ + public function getPaidExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('payment_date'); + return $this->expenseCalculations($q, $data); + } + + /** + * Paid. + */ + public function getInvoicedPaidExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('invoice_id')->whereNotNull('payment_date'); + return $this->expenseCalculations($q, $data); + } + + private function expenseCalculations(Builder $query, array $data): int|float + { $result = 0; - $calculated = collect(); - - $q = Task::query() - ->withTrashed() - ->where('company_id', $this->company->id) - ->where('is_deleted',0); - - if(in_array($data['period'], ['current,previous'])) { - $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); - } - - if($data['calculation'] != 'count' && $data['format'] == 'money') - { - if($data['currency_id'] != '999') - { - - $q->whereHas('client', function ($query) use ($data){ - $query->where('settings->currency_id', $data['currency_id']); - }); - - } - - $calculated = $this->taskMoneyCalculator($q, $data); - - } - - if($data['calculation'] != 'count' && $data['format'] == 'time') - { - $calculated = $q->get()->map(function ($t){ - return $t->calcDuration(); - }); - } - + $calculated = $this->expenseCalculator($query, $data); + match ($data['calculation']) { 'sum' => $result = $calculated->sum(), 'avg' => $result = $calculated->avg(), - 'count' => $result = $q->count(), + 'count' => $result = $query->count(), default => $result = 0, }; return $result; + } + private function expenseCalculator(Builder $query, array $data) + { + + return $query->get() + ->when($data['currency_id'] == '999', function ($collection) { + $collection->map(function ($e) { + /** @var \App\Models\Expense $e */ + return $e->amount * $e->exchange_rate; + }); + }) + ->when($data['currency_id'] != '999', function ($collection) { + + $collection->map(function ($e) { + + /** @var \App\Models\Expense $e */ + return $e->amount; + }); + + }); + + } + + private function expenseQuery($data): Builder + { + $query = Expense::query() + ->withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0); + + if(in_array($data['period'], ['current,previous'])) { + $query->whereBetween('date', [$data['start_date'], $data['end_date']]); + } + + return $query; + } + + //////////////////////////////////////////////////////////////// private function taskMoneyCalculator($query, $data) { @@ -240,24 +333,28 @@ trait ChartCalculations } - public function getInvoicedTasks($data): int|float + private function taskQuery($data): Builder { - - $result = 0; - $calculated = collect(); - $q = Task::query() ->withTrashed() ->where('company_id', $this->company->id) - ->where('is_deleted', 0) - ->whereHas('invoice'); - + ->where('is_deleted', 0); + if(in_array($data['period'], ['current,previous'])) { $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); } - if($data['calculation'] != 'count' && $data['format'] == 'money') { + return $q; + } + + private function taskCalculations(Builder $q, array $data): int|float + { + + $result = 0; + $calculated = collect(); + + if($data['calculation'] != 'count' && $data['format'] == 'money') { if($data['currency_id'] != '999') { $q->whereHas('client', function ($query) use ($data) { @@ -286,4 +383,5 @@ trait ChartCalculations return $result; } + } \ No newline at end of file diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index f22183f255aa..792fd87baa08 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -224,6 +224,8 @@ class ChartService * period - current/previous * calculation - sum/count/avg * + * May require currency_id + * * date_range - this_month * or * start_date - end_date @@ -241,11 +243,11 @@ class ChartService 'unapproved_quotes' => $results = $this->getUnapprovedQuotes($data), 'logged_tasks' => $results = $this->getLoggedTasks($data), 'invoiced_tasks' => $results = $this->getInvoicedTasks($data), - 'paid_tasks' => $results = 0, - 'logged_expenses' => $results = 0, - 'pending_expenses' => $results = 0, - 'invoiced_expenses' => $results = 0, - 'invoice_paid_expenses' => $results = 0, + 'paid_tasks' => $results = $this->getPaidTasks($data), + 'logged_expenses' => $results = $this->getLoggedExpenses($data), + 'pending_expenses' => $results = $this->getPendingExpenses($data), + 'invoiced_expenses' => $results = $this->getInvoicedExpenses($data), + 'invoice_paid_expenses' => $results = $this->getInvoicedPaidExpenses($data), default => $results = 0, }; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index c511409993ca..f30302435dc1 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -124,7 +124,7 @@ class TemplateService $this->twig->addFilter($filter); $allowedTags = ['if', 'for', 'set', 'filter']; - $allowedFilters = ['escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format']; + $allowedFilters = ['escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br']; $allowedFunctions = ['range', 'cycle', 'constant', 'date',]; $allowedProperties = ['type_id']; $allowedMethods = ['img','t']; From 7c6732e896c009130fdfc3259d917cca42dcd4ed Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 14:04:03 +1000 Subject: [PATCH 27/30] Minor adjustments for webhooks --- .../Jobs/PaymentIntentProcessingWebhook.php | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php index 3b0c3b30982a..42c4739f7761 100644 --- a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php @@ -59,38 +59,22 @@ class PaymentIntentProcessingWebhook implements ShouldQueue /* Stub processing payment intents with a pending payment */ public function handle() { + nlog($this->stripe_request); + // The first payment will always be a PI payment - subsequent are PY + MultiDB::findAndSetDbByCompanyKey($this->company_key); $company = Company::query()->where('company_key', $this->company_key)->first(); foreach ($this->stripe_request as $transaction) { - $payment = Payment::query() ->where('company_id', $company->id) - ->where(function ($query) use ($transaction) { - - if(isset($transaction['payment_intent'])) { - $query->where('transaction_reference', $transaction['payment_intent']); - } - - if(isset($transaction['payment_intent']) && isset($transaction['id'])) { - $query->orWhere('transaction_reference', $transaction['id']); - } - - if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { - $query->where('transaction_reference', $transaction['id']); - } - - }) + ->where('transaction_reference', $transaction['id']) ->first(); - - if ($payment) { - $payment->status_id = Payment::STATUS_PENDING; - $payment->save(); - + nlog("found payment"); $this->payment_completed = true; } From 36fef6beb35ec9f9db1528b138cd67f1aafdb801 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 18:21:03 +1000 Subject: [PATCH 28/30] Improvements for twig --- app/PaymentDrivers/Stripe/Jobs/ChargeRefunded.php | 5 +++++ app/Services/Template/TemplateService.php | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Stripe/Jobs/ChargeRefunded.php b/app/PaymentDrivers/Stripe/Jobs/ChargeRefunded.php index 405f696742e4..524139527e03 100644 --- a/app/PaymentDrivers/Stripe/Jobs/ChargeRefunded.php +++ b/app/PaymentDrivers/Stripe/Jobs/ChargeRefunded.php @@ -59,6 +59,11 @@ class ChargeRefunded implements ShouldQueue $payment_hash_key = $source['metadata']['payment_hash'] ?? null; + if(is_null($payment_hash_key)){ + nlog("charge.refunded not found"); + return; + } + $payment_hash = PaymentHash::query()->where('hash', $payment_hash_key)->first(); $company_gateway = $payment_hash->payment->company_gateway; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index f30302435dc1..016a91783fd0 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -124,7 +124,7 @@ class TemplateService $this->twig->addFilter($filter); $allowedTags = ['if', 'for', 'set', 'filter']; - $allowedFilters = ['escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br']; + $allowedFilters = ['replace', 'escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br']; $allowedFunctions = ['range', 'cycle', 'constant', 'date',]; $allowedProperties = ['type_id']; $allowedMethods = ['img','t']; @@ -323,6 +323,9 @@ class TemplateService $template = $template->render($this->data); $f = $this->document->createDocumentFragment(); + + $template = htmlspecialchars($template, ENT_XML1, 'UTF-8'); + $f->appendXML(html_entity_decode($template)); $replacements[] = $f; From 2f03a13d34c7e7680cfc991235d4d8ed560ea4ac Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 18:57:19 +1000 Subject: [PATCH 29/30] Fixes for paypal in subscriptions --- app/Livewire/BillingPortalPurchase.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/Livewire/BillingPortalPurchase.php b/app/Livewire/BillingPortalPurchase.php index 079a36325e80..ea37099bb55d 100644 --- a/app/Livewire/BillingPortalPurchase.php +++ b/app/Livewire/BillingPortalPurchase.php @@ -356,15 +356,14 @@ class BillingPortalPurchase extends Component $this->methods = $contact->client->service()->getPaymentMethods($this->price); - foreach($this->methods as $method){ - - if($method['is_paypal'] == '1' && !$this->steps['check_rff']){ - $this->rff(); - break; - } - - } + $method_values = array_column($this->methods, 'is_paypal'); + $is_paypal = in_array('1', $method_values); + if($is_paypal && !$this->steps['check_rff']) + $this->rff(); + elseif(!$is_paypal && !$this->steps['check_rff']) + $this->steps['fetched_payment_methods'] = true; + $this->heading_text = ctrans('texts.payment_methods'); return $this; From 19cfee10a0083dc2bb253adeabce94d65d084212 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 19:21:42 +1000 Subject: [PATCH 30/30] Minor fixes --- VERSION.txt | 2 +- app/Livewire/BillingPortalPurchase.php | 2 +- app/Livewire/BillingPortalPurchasev2.php | 2 +- config/ninja.php | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 21a04bbf2c42..cdaeb5eb133b 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.10.18 \ No newline at end of file +5.10.19 \ No newline at end of file diff --git a/app/Livewire/BillingPortalPurchase.php b/app/Livewire/BillingPortalPurchase.php index ea37099bb55d..2acb2eee917d 100644 --- a/app/Livewire/BillingPortalPurchase.php +++ b/app/Livewire/BillingPortalPurchase.php @@ -361,7 +361,7 @@ class BillingPortalPurchase extends Component if($is_paypal && !$this->steps['check_rff']) $this->rff(); - elseif(!$is_paypal && !$this->steps['check_rff']) + elseif(!$this->steps['check_rff']) $this->steps['fetched_payment_methods'] = true; $this->heading_text = ctrans('texts.payment_methods'); diff --git a/app/Livewire/BillingPortalPurchasev2.php b/app/Livewire/BillingPortalPurchasev2.php index 5ee7191700ca..647613e60f1f 100644 --- a/app/Livewire/BillingPortalPurchasev2.php +++ b/app/Livewire/BillingPortalPurchasev2.php @@ -484,7 +484,7 @@ class BillingPortalPurchasev2 extends Component $this->methods = []; } - if ($this->contact && $this->float_amount_total >= 1) { + if ($this->contact && $this->float_amount_total >= 0) { $this->methods = $this->contact->client->service()->getPaymentMethods($this->float_amount_total); } diff --git a/config/ninja.php b/config/ninja.php index 1881afbb4e3a..601b526f1601 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.10.18'), - 'app_tag' => env('APP_TAG', '5.10.18'), + 'app_version' => env('APP_VERSION', '5.10.19'), + 'app_tag' => env('APP_TAG', '5.10.19'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false),