Merge branch 'v5-develop' into v5-develop

This commit is contained in:
David Bomba 2020-12-09 07:25:16 +11:00 committed by GitHub
commit 6a03bcc546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 103542 additions and 104989 deletions

View File

@ -4,6 +4,7 @@ $finder = Symfony\Component\Finder\Finder::create()
->notPath('vendor')
->notPath('bootstrap')
->notPath('storage')
->notPath('node_modules')
->in(__DIR__)
->name('*.php')
->notName('*.blade.php');

View File

@ -74,8 +74,26 @@ To improve chances of PRs being merged please include tests to ensure your code
API documentation is hosted using Swagger and can be found [HERE](https://app.swaggerhub.com/apis/invoiceninja/invoiceninja)
## Credits
* [Hillel Coren](https://hillelcoren.com/)
* [David Bomba](https://github.com/turbo124)
* [All contributors](https://github.com/invoiceninja/invoiceninja/graphs/contributors)
**Special thanks to:**
* [Holger Lösken](https://github.com/codedge) - [codedge](http://codedge.de)
* [Samuel Laulhau](https://github.com/lalop) - [Lalop](http://lalop.co/)
* [Alexander Vanderveen](https://blog.technicallycomputers.ca/) - [Technically Computers](https://www.technicallycomputers.ca/)
* [Efthymios Sarmpanis](https://github.com/esarbanis)
* [Gianfranco Gasbarri](https://github.com/gincos)
* [Clemens Mol](https://github.com/clemensmol)
* [Benjamin Beganović](https://github.com/beganovich)
## Current work in progress
Invoice Ninja is currently being written in a combination of Laravel for the API and Client Portal and Flutter for the front end management console. This will allow an immersive and consistent experience across any device: mobile, tablet or desktop.
To manage our workflow we will be creating separate branches for the client (Flutter) and server (Laravel API / Client Portal) and merge these into a release branch for deployments.
## License
Invoice Ninja is released under the Attribution Assurance License.
See [LICENSE](LICENSE) for details.

View File

@ -635,7 +635,7 @@ class CompanySettings extends BaseSettings
'$product.line_total',
],
'task_columns' =>[
'$task.product_key',
'$task.service',
'$task.description',
'$task.rate',
'$task.hours',

View File

@ -13,9 +13,16 @@ class PaymentFailed extends Exception
public function render($request)
{
if (auth()->user()) {
return render('gateways.unsuccessful', [
'message' => $this->getMessage(),
'code' => $this->getCode(),
]);
}
return response([
'message' => $this->getMessage(),
'code' => $this->getCode(),
]);
}
}

View File

@ -843,8 +843,13 @@ class InvoiceController extends BaseController
{
$file_path = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
try {
$file = public_path("storage/{$file_path}");
return response()->download($file, basename($file));
} catch (\Exception $e) {
return response(['message' => 'Oops, something went wrong. Make sure you have symlink to storage/ in public/ directory.'], 500);
}
}
}

View File

@ -13,8 +13,6 @@
namespace App\Http\Controllers;
use App\Http\Requests\Payments\PaymentWebhookRequest;
use App\Models\Payment;
use Illuminate\Support\Arr;
class PaymentWebhookController extends Controller
{
@ -23,36 +21,10 @@ class PaymentWebhookController extends Controller
$this->middleware('guest');
}
public function __invoke(PaymentWebhookRequest $request, string $company_key = null, string $gateway_key = null)
public function __invoke(PaymentWebhookRequest $request, string $gateway_key, string $company_key)
{
$transaction_reference = $this->getTransactionReference($request->all(), $request);
$payment = Payment::where('transaction_reference', $transaction_reference)->first();
if (is_null($payment)) {
return response([
'message' => 'Sorry, we couldn\'t find requested payment.',
'status_code' => 404,
], 404); /* Record event, throw an exception.. */
}
return $request
->companyGateway()
->driver($payment->client)
->setPaymentMethod($payment->gateway_type_id)
->processWebhookRequest($request->all(), $request->company(), $request->companyGateway(), $payment);
}
public function getTransactionReference(array $data, PaymentWebhookRequest $request)
{
$flatten = Arr::dot($data);
if (isset($flatten['data.object.id'])) {
return $flatten['data.object.id']; // stripe.com
}
if ($request->has('cko-session-id')) {
// checkout.com
}
return $request->getCompanyGateway()
->driver($request->getClient())
->processWebhookRequest($request, $request->getPayment());
}
}

View File

@ -67,11 +67,33 @@ class SetupController extends Controller
return response('Oops, something went wrong. Check your logs.'); /* We should never reach this block, but just in case. */
}
$mail_driver = $request->input('mail_driver');
try {
$db = SystemHealth::dbCheck($request);
if (!$this->failsafeMailCheck($request)) {
$mail_driver = 'log';
if ($db['success'] == false) {
throw new \Exception($db['message']);
}
} catch (\Exception $e) {
return response([
'message' => 'Oops, connection to database was not successful.',
'error' => $e->getMessage(),
]);
}
try {
$smtp = SystemHealth::testMailServer($request);
if ($smtp['success'] == false) {
throw new \Exception($smtp['message']);
}
} catch (\Exception $e) {
return response([
'message' => 'Oops, connection to mail server was not successful.',
'error' => $e->getMessage(),
]);
}
$mail_driver = $request->input('mail_driver');
$url = $request->input('url');
@ -84,8 +106,8 @@ class SetupController extends Controller
'REQUIRE_HTTPS' => $request->input('https') ? 'true' : 'false',
'APP_DEBUG' => $request->input('debug') ? 'true' : 'false',
'DB_HOST1' => $request->input('host'),
'DB_DATABASE1' => $request->input('database'),
'DB_HOST1' => $request->input('db_host'),
'DB_DATABASE1' => $request->input('db_database'),
'DB_USERNAME1' => $request->input('db_username'),
'DB_PASSWORD1' => $request->input('db_password'),
@ -171,12 +193,12 @@ class SetupController extends Controller
public function checkMail(CheckMailRequest $request)
{
try {
$response_array = SystemHealth::testMailServer($request);
$response = SystemHealth::testMailServer($request);
if (count($response_array) == 0) {
if ($response['success']) {
return response([], 200);
} else {
return response()->json(['message' => $response_array[0]], 400);
return response()->json(['message' => $response['message']], 400);
}
} catch (Exception $e) {
info(['message' => $e->getMessage(), 'action' => 'SetupController::checkMail()']);
@ -187,10 +209,10 @@ class SetupController extends Controller
private function failsafeMailCheck($request)
{
$response_array = SystemHealth::testMailServer($request);
$response = SystemHealth::testMailServer($request);
if ($response_array instanceof Response) {
return true;
if ($response['success']) {
true;
}
return false;

View File

@ -1,5 +1,15 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Livewire;
use App\Models\Credit;

View File

@ -1,5 +1,15 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Livewire;
use App\Models\Invoice;
@ -8,9 +18,6 @@ use Carbon\Carbon;
use Livewire\Component;
use Livewire\WithPagination;
/**
* @todo: Integrate InvoiceFilters
*/
class InvoicesTable extends Component
{
use WithPagination, WithSorting;

View File

@ -1,5 +1,8 @@
<?php
namespace App\Http\Livewire;
use App\Models\ClientGatewayToken;

View File

@ -1,5 +1,15 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Livewire;
use App\Models\Payment;

View File

@ -1,5 +1,15 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Livewire;
use App\Models\Quote;

View File

@ -1,5 +1,15 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Livewire;
use App\Models\RecurringInvoice;

View File

@ -1,4 +1,5 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
@ -9,12 +10,14 @@
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\Requests\Payments;
use App\Http\Requests\Request;
use App\Models\Client;
use App\Models\Company;
use App\Models\CompanyGateway;
use App\Models\Payment;
use App\Models\PaymentHash;
class PaymentWebhookRequest extends Request
{
@ -30,28 +33,61 @@ class PaymentWebhookRequest extends Request
];
}
public function company()
/**
* Resolve company gateway.
*
* @param mixed $id
* @return null|\App\Models\CompanyGateway
*/
public function getCompanyGateway(): ?CompanyGateway
{
if (! $this->company_key) {
return false;
return CompanyGateway::where('gateway_key', $this->gateway_key)->firstOrFail();
}
return Company::query()
->where('company_key', $this->company_key)
->firstOrFail();
}
public function companyGateway()
/**
* Resolve payment hash.
*
* @param string $hash
* @return null|\App\Http\Requests\Payments\PaymentHash
*/
public function getPaymentHash(): ?PaymentHash
{
if (! $this->gateway_key || ! $this->company_key) {
return false;
if ($this->query('hash')) {
return PaymentHash::where('hash', $this->query('hash'))->firstOrFail();
}
}
$company = $this->company();
/**
* Resolve possible payment in the request.
*
* @return null|\App\Models\Payment
*/
public function getPayment(): ?Payment
{
$hash = $this->getPaymentHash();
return CompanyGateway::query()
->where('gateway_key', $this->gateway_key)
->where('company_id', $company->id)
->firstOrFail();
return $hash->payment;
}
/**
* Resolve client from payment hash.
*
* @return null|\App\Models\Client
*/
public function getClient(): ?Client
{
$hash = $this->getPaymentHash();
return Client::find($hash->data->client_id)->firstOrFail();
}
/**
* Resolve company from company_key parameter.
*
* @return null|\App\Models\Company
*/
public function getCompany(): ?Company
{
return Company::where('company_key', $this->company_key)->firstOrFail();
}
}

View File

@ -34,9 +34,9 @@ class CheckDatabaseRequest extends Request
public function rules()
{
return [
'host' => ['required'],
'database' => ['required'],
'username' => ['required'],
'db_host' => ['required'],
'db_database' => ['required'],
'db_username' => ['required'],
];
}
}

View File

@ -36,14 +36,13 @@ class CheckMailRequest extends Request
info($this->driver);
return [
'driver' => ['required', 'in:smtp,mail,sendmail,log'],
'from_name' => ['required_unless:driver,log'],
'from_address' => ['required_unless:driver,log'],
'username' => ['required_unless:driver,log'],
'host' => ['required_unless:driver,log'],
'port' => ['required_unless:driver,log'],
'encryption' => ['required_unless:driver,log'],
'password' => ['required_unless:driver,log'],
'mail_driver' => 'required',
'encryption' => 'required_unless:mail_driver,log',
'mail_host' => 'required_unless:mail_driver,log',
'mail_username' => 'required_unless:mail_driver,log',
'mail_name' => 'required_unless:mail_driver,log',
'mail_address' => 'required_unless:mail_driver,log',
'mail_password' => 'required_unless:mail_driver,log',
];
}
}

View File

@ -31,8 +31,8 @@ class StoreSetupRequest extends Request
/*System*/
'url' => 'required',
/*Database*/
'host' => 'required',
'database' => 'required',
'db_host' => 'required',
'db_database' => 'required',
'db_username' => 'required',
'db_password' => '',
/*Mail driver*/

View File

@ -30,7 +30,6 @@ class DownloadInvoices extends Mailable
*/
public function build()
{
return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_files'))

View File

@ -27,7 +27,6 @@ class ExistingMigration extends Mailable
*/
public function build()
{
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.existing');

View File

@ -31,7 +31,6 @@ class MigrationFailed extends Mailable
*/
public function build()
{
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.failed');

View File

@ -82,6 +82,7 @@ class CreditCard
'currency' => $request->currency,
'payment_hash' => $request->payment_hash,
'reference' => $request->payment_hash,
'client_id' => $this->checkout->client->id,
];
$state = array_merge($state, $request->all());
@ -121,8 +122,17 @@ class CreditCard
$payment->amount = $this->checkout->payment_hash->data->value;
$payment->reference = $this->checkout->payment_hash->data->reference;
$this->checkout->payment_hash->data = array_merge((array) $this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]);
$this->checkout->payment_hash->save();
if ($this->checkout->client->currency()->code === 'EUR') {
$payment->{'3ds'} = ['enabled' => true];
$payment->{'success_url'} = route('payment_webhook', [
'gateway_key' => $this->checkout->company_gateway->gateway_key,
'company_key' => $this->checkout->client->company->company_key,
'hash' => $this->checkout->payment_hash->hash,
]);
}
try {

View File

@ -29,6 +29,11 @@ trait Utilities
return $this->company_gateway->getConfigField('publicApiKey');
}
public function getParent()
{
return static::class == 'App\PaymentDrivers\CheckoutComPaymentDriver' ? $this : $this->checkout;
}
public function convertToCheckoutAmount($amount, $currency)
{
$cases = [
@ -52,42 +57,42 @@ trait Utilities
private function processSuccessfulPayment(Payment $_payment)
{
if ($this->checkout->payment_hash->data->store_card) {
if ($this->getParent()->payment_hash->data->store_card) {
$this->storePaymentMethod($_payment);
}
$data = [
'payment_method' => $_payment->source['id'],
'payment_type' => PaymentType::parseCardType(strtolower($_payment->source['scheme'])),
'amount' => $this->checkout->payment_hash->data->raw_value,
'amount' => $this->getParent()->payment_hash->data->raw_value,
'transaction_reference' => $_payment->id,
];
$payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
$payment = $this->getParent()->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $_payment, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_CHECKOUT,
$this->checkout->client
$this->getParent()->client
);
return redirect()->route('client.payments.show', ['payment' => $this->checkout->encodePrimaryKey($payment->id)]);
return redirect()->route('client.payments.show', ['payment' => $this->getParent()->encodePrimaryKey($payment->id)]);
}
public function processUnsuccessfulPayment(Payment $_payment)
{
PaymentFailureMailer::dispatch(
$this->checkout->client,
$this->getParent()->client,
$_payment,
$this->checkout->client->company,
$this->checkout->payment_hash->data->value
$this->getParent()->client->company,
$this->getParent()->payment_hash->data->value
);
$message = [
'server_response' => $_payment,
'data' => $this->checkout->payment_hash->data,
'data' => $this->getParent()->payment_hash->data,
];
SystemLogger::dispatch(
@ -95,7 +100,7 @@ trait Utilities
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_CHECKOUT,
$this->checkout->client
$this->getParent()->client
);
throw new PaymentFailed($_payment->status, $_payment->http_code);
@ -103,27 +108,10 @@ trait Utilities
private function processPendingPayment(Payment $_payment)
{
$data = [
'payment_method' => $_payment->source->id,
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
'amount' => $this->checkout->payment_hash->data->value,
'transaction_reference' => $_payment->id,
];
$payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $_payment, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_CHECKOUT,
$this->checkout->client
);
try {
return redirect($_payment->_links['redirect']['href']);
} catch (Exception $e) {
return $this->processInternallyFailedPayment($this->checkout, $e);
return $this->processInternallyFailedPayment($this->getParent(), $e);
}
}
@ -140,10 +128,10 @@ trait Utilities
$data = [
'payment_meta' => $payment_meta,
'token' => $response->source['id'],
'payment_method_id' => $this->checkout->payment_hash->data->payment_method_id,
'payment_method_id' => $this->getParent()->payment_hash->data->payment_method_id,
];
return $this->checkout->storePaymentMethod($data);
return $this->getParent()->storePaymentMethod($data);
} catch (Exception $e) {
session()->flash('message', ctrans('texts.payment_method_saving_failed'));
}

View File

@ -12,7 +12,9 @@
namespace App\PaymentDrivers;
use App\Http\Requests\Payments\PaymentWebhookRequest;
use App\Models\ClientGatewayToken;
use App\Models\Company;
use App\Models\GatewayType;
use App\Models\Payment;
use App\Models\PaymentHash;
@ -23,6 +25,7 @@ use App\Utils\Traits\SystemLogTrait;
use Checkout\CheckoutApi;
use Checkout\Library\Exceptions\CheckoutHttpException;
use Checkout\Models\Payments\Refund;
use Exception;
class CheckoutComPaymentDriver extends BaseDriver
{
@ -209,5 +212,24 @@ class CheckoutComPaymentDriver extends BaseDriver
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
{
// ..
}
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
{
$this->init();
$this->setPaymentHash($request->getPaymentHash());
try {
$payment = $this->gateway->payments()->details($request->query('cko-session-id'));
if ($payment->approved) {
return $this->processSuccessfulPayment($payment);
} else {
return $this->processUnsuccessfulPayment($payment);
}
} catch (CheckoutHttpException | Exception $e) {
return $this->processInternallyFailedPayment($this, $e);
}
}
}

View File

@ -87,7 +87,6 @@ class InvoiceRepository extends BaseRepository
{
//if we have just archived, only perform a soft restore
if (!$invoice->is_deleted) {
parent::restore($invoice);
return $invoice;

View File

@ -13,11 +13,9 @@ namespace App\Services\Invoice;
use App\Models\Invoice;
use App\Services\AbstractService;
use Illuminate\Support\Facades\DB;
class HandleRestore extends AbstractService
{
private $invoice;
private $payment_total = 0;
@ -29,14 +27,13 @@ class HandleRestore extends AbstractService
public function run()
{
if(!$this->invoice->is_deleted)
if (!$this->invoice->is_deleted) {
return $this->invoice;
}
//determine whether we need to un-delete payments OR just modify the payment amount /applied balances.
foreach($this->invoice->payments as $payment)
{
foreach ($this->invoice->payments as $payment) {
//restore the payment record
$payment->restore();
@ -59,14 +56,11 @@ class HandleRestore extends AbstractService
info($payment->amount . " == " . $payment_amount);
if ($payment->amount == $payment_amount) {
$payment->is_deleted = false;
$payment->save();
$this->payment_total += $payment_amount;
}
else {
} else {
$payment->is_deleted = false;
$payment->amount += ($payment_amount - $pre_restore_amount);
$payment->applied += ($payment_amount - $pre_restore_amount);
@ -74,7 +68,6 @@ class HandleRestore extends AbstractService
$this->payment_total += ($payment_amount - $pre_restore_amount);
}
}
//adjust ledger balance
@ -95,7 +88,6 @@ class HandleRestore extends AbstractService
private function windBackInvoiceNumber()
{
$findme = '_' . ctrans('texts.deleted');
$pos = strpos($this->invoice->number, $findme);
@ -105,11 +97,8 @@ class HandleRestore extends AbstractService
try {
$this->invoice->number = $new_invoice_number;
$this->invoice->save();
}
catch(\Exception $e){
} catch (\Exception $e) {
info("I could not wind back the invoice number");
}
}
}

View File

@ -33,8 +33,9 @@ class MarkInvoiceDeleted extends AbstractService
public function run()
{
if($this->invoice->is_deleted)
if ($this->invoice->is_deleted) {
return $this->invoice;
}
// if(in_array($this->invoice->status_id, ['currencies', 'industries', 'languages', 'countries', 'banks']))
// return $this->
@ -76,15 +77,11 @@ class MarkInvoiceDeleted extends AbstractService
//if total payments = adjustment amount - that means we need to delete the payments as well.
if ($this->adjustment_amount == $this->total_payments) {
$this->invoice->payments()->update(['payments.deleted_at' => now(), 'payments.is_deleted' => true]);
}
else {
} else {
//adjust payments down by the amount applied to the invoice payment.
$this->invoice->payments->each(function ($payment) {
$payment_adjustment = $payment->paymentables
->where('paymentable_type', '=', 'invoices')
->where('paymentable_id', $this->invoice->id)
@ -93,7 +90,6 @@ class MarkInvoiceDeleted extends AbstractService
$payment->amount -= $payment_adjustment;
$payment->applied -= $payment_adjustment;
$payment->save();
});
}
@ -102,7 +98,6 @@ class MarkInvoiceDeleted extends AbstractService
private function setAdjustmentAmount()
{
foreach ($this->invoice->payments as $payment) {
$this->adjustment_amount += $payment->paymentables
->where('paymentable_type', '=', 'invoices')
@ -118,7 +113,6 @@ class MarkInvoiceDeleted extends AbstractService
private function cleanup()
{
$check = false;
$x=0;
@ -136,7 +130,6 @@ class MarkInvoiceDeleted extends AbstractService
$this->invoice->expenses()->update(['invoice_id' => null]);
return $this;
}
private function calcNumber($x)
@ -153,7 +146,6 @@ class MarkInvoiceDeleted extends AbstractService
private function deletePaymentables()
{
$this->invoice->payments->each(function ($payment) {
$payment->paymentables()
->where('paymentable_type', '=', 'invoices')

View File

@ -192,6 +192,13 @@ class Design extends BaseDesign
$elements = [];
// We don't want to show account balance or invoice total on PDF.. or any amount with currency.
if ($this->type == 'delivery_note') {
$variables = array_filter($variables, function ($m) {
return !in_array($m, ['$invoice.balance_due', '$invoice.total']);
});
}
foreach ($variables as $variable) {
$_variable = explode('.', $variable)[1];
$_customs = ['custom1', 'custom2', 'custom3', 'custom4'];
@ -293,9 +300,7 @@ class Design extends BaseDesign
$elements = [];
// Some of column can be aliased. This is simple workaround for these.
$aliases = [
'$task.product_key' => '$task.service',
];
$aliases = [];
foreach ($this->context['pdf_variables']["{$type}_columns"] as $column) {
if (array_key_exists($column, $aliases)) {

View File

@ -156,10 +156,10 @@ class HtmlEngine
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.balance_due')];
}
$data['$quote.balance_due'] = &$data['$balance_due'];
$data['$invoice.balance_due'] = &$data['$balance_due'];
$data['$balance_due'] = &$data['$balance_due'];
$data['$outstanding'] = &$data['$balance_due'];
$data['$quote.balance_due'] = $data['$balance_due'];
$data['$invoice.balance_due'] = $data['$balance_due'];
$data['$balance_due'] = $data['$balance_due'];
$data['$outstanding'] = $data['$balance_due'];
$data['$partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.partial_due')];
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.total')];
$data['$amount'] = &$data['$total'];
@ -307,7 +307,7 @@ class HtmlEngine
$data['$task.date'] = ['value' => '', 'label' => ctrans('texts.date')];
$data['$task.discount'] = ['value' => '', 'label' => ctrans('texts.discount')];
$data['$task.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')];
$data['$task.service'] = ['value' => '', 'label' => ctrans('texts.service')];
$data['$task.description'] = ['value' => '', 'label' => ctrans('texts.description')];
$data['$task.rate'] = ['value' => '', 'label' => ctrans('texts.rate')];
$data['$task.hours'] = ['value' => '', 'label' => ctrans('texts.hours')];
@ -343,6 +343,8 @@ class HtmlEngine
$data['$item'] = ['value' => '', 'label' => ctrans('texts.item')];
$data['$description'] = ['value' => '', 'label' => ctrans('texts.description')];
$data['$entity_footer'] = ['value' => $this->client->getSetting("{$this->entity_string}_footer"), 'label' => ''];
// $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')];
// $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')];
// $data['custom_label3'] = ['value' => '', 'label' => ctrans('texts.')];

View File

@ -11,8 +11,6 @@
namespace App\Utils;
use App\Http\Requests\Setup\CheckDatabaseRequest;
use App\Http\Requests\Setup\CheckMailRequest;
use App\Libraries\MultiDB;
use App\Mail\TestMailServer;
use Exception;
@ -160,11 +158,11 @@ class SystemHealth
{
$result = ['success' => false];
if ($request && $request instanceof CheckDatabaseRequest) {
config(['database.connections.db-ninja-01.host'=> $request->input('host')]);
config(['database.connections.db-ninja-01.database'=> $request->input('database')]);
config(['database.connections.db-ninja-01.username'=> $request->input('username')]);
config(['database.connections.db-ninja-01.password'=> $request->input('password')]);
if ($request) {
config(['database.connections.db-ninja-01.host'=> $request->input('db_host')]);
config(['database.connections.db-ninja-01.database'=> $request->input('db_database')]);
config(['database.connections.db-ninja-01.username'=> $request->input('db_username')]);
config(['database.connections.db-ninja-01.password'=> $request->input('db_password')]);
config(['database.default' => 'db-ninja-01']);
DB::purge('db-ninja-01');
@ -191,6 +189,7 @@ class SystemHealth
} catch (Exception $e) {
$result[] = [config('database.connections.'.config('database.default').'.database') => false];
$result['success'] = false;
$result['message'] = $e->getMessage();
}
}
}
@ -209,35 +208,24 @@ class SystemHealth
return [];
}
if ($request && $request instanceof CheckMailRequest) {
config(['mail.driver' => $request->input('driver')]);
config(['mail.host' => $request->input('host')]);
config(['mail.port' => $request->input('port')]);
config(['mail.from.address' => $request->input('from_address')]);
config(['mail.from.name' => $request->input('from_name')]);
if ($request) {
config(['mail.driver' => $request->input('mail_driver')]);
config(['mail.host' => $request->input('mail_host')]);
config(['mail.port' => $request->input('mail_port')]);
config(['mail.from.address' => $request->input('mail_address')]);
config(['mail.from.name' => $request->input('mail_name')]);
config(['mail.encryption' => $request->input('encryption')]);
config(['mail.username' => $request->input('username')]);
config(['mail.password' => $request->input('password')]);
config(['mail.username' => $request->input('mail_username')]);
config(['mail.password' => $request->input('mail_password')]);
}
try {
Mail::to(config('mail.from.address'))->send(new TestMailServer('Email Server Works!', config('mail.from.address')));
} catch (Exception $e) {
return [$e->getMessage()];
return ['success' => false, 'message' => $e->getMessage()];
}
/*
* 'message' => 'count(): Parameter must be an array or an object that implements Countable',
* 'action' => 'SetupController::checkMail()',
*
* count(Mail::failures())
*/
if (Mail::failures() > 0) {
return Mail::failures();
}
return response()->json(['message' => 'Success'], 200);
return ['success' => true];
}
private static function checkEnvWritable()

View File

@ -617,6 +617,7 @@ trait MakesInvoiceValues
}
$data[$key][$table_type.'.product_key'] = $item->product_key;
$data[$key][$table_type.'.service'] = is_null(optional($item)->service) ? $item->product_key : $item->service;
$data[$key][$table_type.'.notes'] = $item->notes;
$data[$key][$table_type.'.description'] = $item->notes;
$data[$key][$table_type.'.custom_value1'] = $item->custom_value1;

View File

@ -191,7 +191,7 @@ trait MakesTemplateData
$data['$product.line_total'] = ['value' => '$20.00', 'label' => ctrans('texts.line_total')];
$data['$task.date'] = ['value' => '2010-02-03', 'label' => ctrans('texts.date')];
$data['$task.discount'] = ['value' => '5%', 'label' => ctrans('texts.discount')];
$data['$task.product_key'] = ['value' => 'key', 'label' => ctrans('texts.product_key')];
$data['$task.service'] = ['value' => 'key', 'label' => ctrans('texts.service')];
$data['$task.notes'] = ['value' => 'Note for Tasks', 'label' => ctrans('texts.notes')];
$data['$task.rate'] = ['value' => '$100.00', 'label' => ctrans('texts.rate')];
$data['$task.hours'] = ['value' => '1', 'label' => ctrans('texts.hours')];

View File

@ -51,7 +51,7 @@
"league/flysystem-cached-adapter": "^1.1",
"league/fractal": "^0.17.0",
"league/omnipay": "^3.0",
"livewire/livewire": "^1.3",
"livewire/livewire": "^2.0",
"maennchen/zipstream-php": "^1.2",
"nwidart/laravel-modules": "^8.0",
"omnipay/paypal": "^3.0",

35
composer.lock generated
View File

@ -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": "ef60a891b86ee73c6f31b73f0e778e09",
"content-hash": "a96274475177046a99ed701ae4148a3d",
"packages": [
{
"name": "asgrim/ofxparser",
@ -3712,30 +3712,32 @@
},
{
"name": "livewire/livewire",
"version": "v1.3.5",
"version": "v2.3.5",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
"reference": "b1673ff9fc78a3296ca4a3b0d1ca26da0a5cdf82"
"reference": "781a1250dc8eab9121fd856ff0b6efca8c32756f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/b1673ff9fc78a3296ca4a3b0d1ca26da0a5cdf82",
"reference": "b1673ff9fc78a3296ca4a3b0d1ca26da0a5cdf82",
"url": "https://api.github.com/repos/livewire/livewire/zipball/781a1250dc8eab9121fd856ff0b6efca8c32756f",
"reference": "781a1250dc8eab9121fd856ff0b6efca8c32756f",
"shasum": ""
},
"require": {
"illuminate/database": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0|^8.0",
"illuminate/support": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0|^8.0",
"illuminate/validation": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0|^8.0",
"php": "^7.1.3",
"symfony/http-kernel": "^4.0|^5.0"
"illuminate/database": "^7.0|^8.0",
"illuminate/support": "^7.0|^8.0",
"illuminate/validation": "^7.0|^8.0",
"php": "^7.2.5|^8.0",
"symfony/http-kernel": "^5.0"
},
"require-dev": {
"laravel/framework": "~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0",
"calebporzio/sushi": "^2.1",
"laravel/framework": "^7.0|^8.0",
"mockery/mockery": "^1.3.1",
"orchestra/testbench": "~3.6.0|~3.7.0|~3.8.0|^4.0|^5.0",
"phpunit/phpunit": "^7.5.15|^8.4|^9.0",
"orchestra/testbench": "^5.0|^6.0",
"orchestra/testbench-dusk": "^5.2|^6.0",
"phpunit/phpunit": "^8.4|^9.0",
"psy/psysh": "@stable"
},
"type": "library",
@ -3750,6 +3752,9 @@
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Livewire\\": "src/"
}
@ -3767,7 +3772,7 @@
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v1.3.5"
"source": "https://github.com/livewire/livewire/tree/v2.3.5"
},
"funding": [
{
@ -3775,7 +3780,7 @@
"type": "github"
}
],
"time": "2020-09-17T04:38:16+00:00"
"time": "2020-12-01T20:51:29+00:00"
},
{
"name": "maennchen/zipstream-php",

81
package-lock.json generated
View File

@ -1508,64 +1508,22 @@
"integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w="
},
"adjust-sourcemap-loader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz",
"integrity": "sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz",
"integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==",
"requires": {
"assert": "1.4.1",
"camelcase": "5.0.0",
"loader-utils": "1.2.3",
"object-path": "0.11.4",
"regex-parser": "2.2.10"
"loader-utils": "^2.0.0",
"regex-parser": "^2.2.11"
},
"dependencies": {
"assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
"integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
"requires": {
"util": "0.10.3"
}
},
"camelcase": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA=="
},
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
},
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
"integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^2.0.0",
"json5": "^1.0.1"
}
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"requires": {
"inherits": "2.0.1"
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
}
}
@ -6698,11 +6656,6 @@
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4="
},
"object-path": {
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz",
"integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk="
},
"object-visit": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
@ -8192,9 +8145,9 @@
}
},
"regex-parser": {
"version": "2.2.10",
"resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.10.tgz",
"integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA=="
"version": "2.2.11",
"resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
"integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q=="
},
"regexp.prototype.flags": {
"version": "1.3.0",
@ -8355,11 +8308,11 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
"resolve-url-loader": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz",
"integrity": "sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz",
"integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==",
"requires": {
"adjust-sourcemap-loader": "2.0.0",
"adjust-sourcemap-loader": "3.0.0",
"camelcase": "5.3.1",
"compose-function": "3.0.3",
"convert-source-map": "1.7.0",

View File

@ -28,7 +28,7 @@
"jsignature": "^2.1.3",
"laravel-mix": "^5.0.7",
"lodash": "^4.17.20",
"resolve-url-loader": "^3.1.0",
"resolve-url-loader": "^3.1.2",
"sass": "^1.26.10",
"sass-loader": "^8.0.0",
"tailwindcss": "^1.6.2"

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

View File

@ -3,36 +3,36 @@ const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
"version.json": "32afcc2282ccf7746c00708ef0601017",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"main.dart.js": "b3c0b8b130688ccb988a28e1ec1f4a26",
"/": "23224b5e03519aaa87594403d54412cf",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"assets/AssetManifest.json": "659dcf9d1baf3aed3ab1b9c42112bf8f",
"assets/fonts/MaterialIcons-Regular.otf": "1288c9e28052e028aba623321f7826ac",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "c1242726c7eac4eb5e843d826f78fb1b",
"version.json": "aeea8a1fbb79cee45facc28ba9a6baf7",
"assets/assets/images/logo.png": "090f69e23311a4b6d851b3880ae52541",
"assets/assets/images/google-icon.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/fonts/MaterialIcons-Regular.otf": "1288c9e28052e028aba623321f7826ac",
"assets/AssetManifest.json": "659dcf9d1baf3aed3ab1b9c42112bf8f",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
"assets/NOTICES": "7d8f2aa600c3ae24c9efdad38c9f53b4",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "c1242726c7eac4eb5e843d826f78fb1b",
"main.dart.js": "d361e1c5411cf7fe77a39c60139a0073",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"/": "23224b5e03519aaa87594403d54412cf",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"manifest.json": "77215c1737c7639764e64a192be2f7b8",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35"
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed"
};
// The application shell files that are downloaded before a service worker can

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

205993
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"/js/app.js": "/js/app.js?id=a33a5a58bfc6e2174841",
"/css/app.css": "/css/app.css?id=2fee89354bd20f89bf73",
"/css/app.css": "/css/app.css?id=fb5c591f4280af2b670a",
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=cddcd46c630c71737bda",
@ -15,6 +15,6 @@
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=85bcae0a646882e56b12",
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=5c35d28cf0a3286e7c45",
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=fa54bb4229aba6b0817c",
"/js/setup/setup.js": "/js/setup/setup.js?id=34b53878aeaca14a2b33",
"/js/setup/setup.js": "/js/setup/setup.js?id=725362f2ed393909fc8b",
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ad"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"/livewire.js":"/livewire.js?id=d7d975b5d122717a1ee0"}
{"/livewire.js":"/livewire.js?id=eb510e851dceb24afd36"}

View File

@ -1 +1 @@
{"app_name":"invoiceninja_flutter","version":"5.0.27","build_number":"27"}
{"app_name":"invoiceninja_flutter","version":"5.0.28","build_number":"28"}

View File

@ -24,10 +24,10 @@ class Setup {
handleDatabaseCheck() {
let data = {
host: document.querySelector('input[name="host"]').value,
database: document.querySelector('input[name="database"]').value,
username: document.querySelector('input[name="db_username"]').value,
password: document.querySelector('input[name="db_password"]').value,
db_host: document.querySelector('input[name="db_host"]').value,
db_database: document.querySelector('input[name="db_database"]').value,
db_username: document.querySelector('input[name="db_username"]').value,
db_password: document.querySelector('input[name="db_password"]').value,
};
Axios.post('/setup/check_db', data)
@ -39,17 +39,17 @@ class Setup {
handleSmtpCheck() {
let data = {
driver: document.querySelector('select[name="mail_driver"]').value,
from_name: document.querySelector('input[name="mail_name"]').value,
from_address: document.querySelector('input[name="mail_address"]')
mail_driver: document.querySelector('select[name="mail_driver"]').value,
mail_name: document.querySelector('input[name="mail_name"]').value,
mail_address: document.querySelector('input[name="mail_address"]')
.value,
username: document.querySelector('input[name="mail_username"]')
mail_username: document.querySelector('input[name="mail_username"]')
.value,
host: document.querySelector('input[name="mail_host"]').value,
port: document.querySelector('input[name="mail_port"]').value,
mail_host: document.querySelector('input[name="mail_host"]').value,
mail_port: document.querySelector('input[name="mail_port"]').value,
encryption: document.querySelector('select[name="encryption"]')
.value,
password: document.querySelector('input[name="mail_password"]')
mail_password: document.querySelector('input[name="mail_password"]')
.value,
};

View File

@ -3233,7 +3233,7 @@ return [
'test_pdf' => 'Test PDF',
'status_cancelled' => 'Cancelled',
'checkout_authorize_label' => 'Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Save card" during payment process.',
'checkout_authorize_label' => 'Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Store credit card details" during payment process.',
'node_status' => 'Node status',
'npm_status' => 'NPM status',

View File

@ -206,4 +206,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -248,4 +248,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -189,4 +189,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -213,4 +213,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -217,5 +217,5 @@
<p class="thanks-label">$thanks_label!</p>
<hr class="double-border"/>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -243,4 +243,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -217,7 +217,7 @@
<div style="margin-top: 195px"></div>
<div class="footer-wrapper" id="footer">
<div class="footer-content">
<div></div>
<div>$entity_footer</div>
<div id="company-details"></div>
<div id="company-address"></div>
</div>

View File

@ -162,4 +162,4 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -231,5 +231,5 @@
<table id="delivery-note-table" cellspacing="0"></table>
</div>
<div id="footer"></div>
<div id="footer">$entity_footer</div>

View File

@ -76,6 +76,6 @@
{{ ctrans('texts.showing_x_of', ['first' => $credits->firstItem(), 'last' => $credits->lastItem(), 'total' => $credits->total()]) }}
</span>
@endif
{{ $credits->links() }}
{{ $credits->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -104,6 +104,6 @@
{{ ctrans('texts.showing_x_of', ['first' => $documents->firstItem(), 'last' => $documents->lastItem(), 'total' => $documents->total()]) }}
</span>
@endif
{{ $documents->links() }}
{{ $documents->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -122,11 +122,11 @@
</div>
<div class="flex justify-center mt-6 mb-6 md:justify-between">
@if($invoices->total() > 0)
<span class="hidden text-sm text-gray-700 md:block">
<span class="hidden text-sm text-gray-700 md:block mr-2">
{{ ctrans('texts.showing_x_of', ['first' => $invoices->firstItem(), 'last' => $invoices->lastItem(), 'total' => $invoices->total()]) }}
</span>
@endif
{{ $invoices->links() }}
{{ $invoices->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -116,6 +116,6 @@
</span>
@endif
{{ $payment_methods->links() }}
{{ $payment_methods->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -82,6 +82,6 @@
{{ ctrans('texts.showing_x_of', ['first' => $payments->firstItem(), 'last' => $payments->lastItem(), 'total' => $payments->total()]) }}
</span>
@endif
{{ $payments->links() }}
{{ $payments->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -112,7 +112,7 @@
{{ ctrans('texts.showing_x_of', ['first' => $quotes->firstItem(), 'last' => $quotes->lastItem(), 'total' => $quotes->total()]) }}
</span>
@endif
{{ $quotes->links() }}
{{ $quotes->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -84,6 +84,6 @@
{{ ctrans('texts.showing_x_of', ['first' => $invoices->firstItem(), 'last' => $invoices->lastItem(), 'total' => $invoices->total()]) }}
</span>
@endif
{{ $invoices->links() }}
{{ $invoices->links('portal/ninja2020/vendor/pagination') }}
</div>
</div>

View File

@ -49,7 +49,7 @@
<!-- Scripts -->
<script src="{{ mix('js/app.js') }}" defer></script>
<script src="{{ asset('js/vendor/alpinejs/alpine.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.7.x/dist/alpine.min.js" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="https://fonts.gstatic.com">

View File

@ -48,7 +48,7 @@
<!-- Scripts -->
<script src="{{ mix('js/app.js') }}" defer></script>
<script src="{{ asset('js/vendor/alpinejs/alpine.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.7.x/dist/alpine.min.js" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="https://fonts.gstatic.com">

View File

@ -1,67 +1,56 @@
<div class="border-t border-gray-200 px-4 flex items-center justify-between sm:px-0">
<div class="w-0 flex-1 flex">
<a href="{{ $paginator->previousPageUrl() }}"
class="-mt-px border-t-2 border-transparent pt-4 pr-1 inline-flex items-center text-sm leading-5 font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-400 transition ease-in-out duration-150">
<svg class="mr-3 h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M7.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l2.293 2.293a1 1 0 010 1.414z"
clip-rule="evenodd"/>
</svg>
@lang('texts.previous')
</a>
</div>
<div class="hidden md:flex">
@foreach ($elements as $element)
@if (is_string($element))
<span
class="-mt-px border-t-2 border-transparent pt-4 px-4 inline-flex items-center text-sm leading-5 font-medium text-gray-500">
...
@if ($paginator->hasPages())
<ul class="pagination" role="navigation">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.previous')">
<span class="page-link" aria-hidden="true">
<span class="d-none d-md-block">&lsaquo;</span>
<span class="d-block d-md-none">@lang('pagination.previous')</span>
</span>
</li>
@else
<li class="page-item">
<button type="button" class="page-link" wire:click="previousPage" rel="prev" aria-label="@lang('pagination.previous')">
<span class="d-none d-md-block">&lsaquo;</span>
<span class="d-block d-md-none">@lang('pagination.previous')</span>
</button>
</li>
@endif
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- "Three Dots" Separator --}}
@if (is_string($element))
<li class="page-item disabled d-none d-md-block" aria-disabled="true"><span class="page-link">{{ $element }}</span></li>
@endif
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page == $paginator->currentPage())
<a href="#" disabled
class="-mt-px border-t-2 border-blue-600 pt-4 px-4 inline-flex items-center text-sm leading-5 font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-400 transition ease-in-out duration-150"
aria-current="page">
{{ $page }}
</a>
<li class="page-item active d-none d-md-block" aria-current="page"><span class="page-link">{{ $page }}</span></li>
@else
<a href="{{ $url }}"
class="-mt-px border-t-2 border-transparent pt-4 px-4 inline-flex items-center text-sm leading-5 font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-400 transition ease-in-out duration-150">
{{ $page }}
</a>
<li class="page-item d-none d-md-block"><button type="button" class="page-link" wire:click="gotoPage({{ $page }})">{{ $page }}</button></li>
@endif
@endforeach
@endif
@endforeach
</div>
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<div class="w-0 flex-1 flex justify-end">
<a href="{{ $paginator->nextPageUrl() }}"
class="-mt-px border-t-2 border-transparent pt-4 pl-1 inline-flex items-center text-sm leading-5 font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-400 transition ease-in-out duration-150">
@lang('texts.next')
<svg class="ml-3 h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
clip-rule="evenodd"/>
</svg>
</a>
</div>
<li class="page-item">
<button type="button" class="page-link" wire:click="nextPage" rel="next" aria-label="@lang('pagination.next')">
<span class="d-block d-md-none">@lang('pagination.next')</span>
<span class="d-none d-md-block">&rsaquo;</span>
</button>
</li>
@else
<div class="w-0 flex-1 flex justify-end">
<a href="#"
class="-mt-px border-t-2 border-transparent pt-4 pl-1 inline-flex items-center text-sm leading-5 font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-400 transition ease-in-out duration-150">
@lang('texts.next')
<svg class="ml-3 h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
clip-rule="evenodd"/>
</svg>
</a>
</div>
<li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.next')">
<span class="page-link" aria-hidden="true">
<span class="d-block d-md-none">@lang('pagination.next')</span>
<span class="d-none d-md-block">&rsaquo;</span>
</span>
</li>
@endif
</ul>
@endif
</div>

View File

@ -38,7 +38,7 @@ FLUSH PRIVILEGES;
{{ ctrans('texts.host') }}*
</dt>
<dd class="text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<input type="text" class="input w-full" name="host" required value="{{ old('host') ?: 'localhost'}}">
<input type="text" class="input w-full" name="db_host" required value="{{ old('host') ?: 'localhost'}}">
</dd>
</div>
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:flex sm:items-center">
@ -46,7 +46,7 @@ FLUSH PRIVILEGES;
{{ ctrans('texts.database') }}*
</dt>
<dd class="text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<input type="text" class="input w-full" name="database" required value="{{ old('database') ?: 'db-ninja-01'}}">
<input type="text" class="input w-full" name="db_database" required value="{{ old('database') ?: 'db-ninja-01'}}">
</dd>
</div>
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:flex sm:items-center">

View File

@ -3,7 +3,7 @@
@push('head')
<meta name="pdf-url" content="{{ asset($entity->pdf_file_path()) }}">
<script src="{{ asset('js/vendor/pdf.js/pdf.min.js') }}"></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.7.x/dist/alpine.min.js" defer></script>
@endpush
@section('body')

View File

@ -180,6 +180,6 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::post('support/messages/send', 'Support\Messages\SendingController');
});
Route::match(['get', 'post'], 'payment_webhook/{company_key?}/{gateway_key?}', 'PaymentWebhookController');
Route::match(['get', 'post'], 'payment_webhook/{gateway_key}/{company_key}', 'PaymentWebhookController')->name('payment_webhook');
Route::fallback('BaseController@notFound');

View File

@ -45,7 +45,6 @@ class DeleteInvoiceTest extends TestCase
*/
public function testInvoiceDeletion()
{
$data = [
'name' => 'A Nice Client',
];
@ -148,7 +147,6 @@ class DeleteInvoiceTest extends TestCase
$this->assertFalse((bool)$invoice->is_deleted);
$this->assertNull($invoice->deleted_at);
$this->assertEquals(20, $invoice->client->fresh()->balance);
}
/**