Merge pull request #9026 from turbo124/v5-develop

v5.7.58
This commit is contained in:
David Bomba 2023-12-07 14:01:21 +11:00 committed by GitHub
commit 54cdb8c91d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 830 additions and 704 deletions

View File

@ -81,9 +81,9 @@ jobs:
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
php-version: ${{ matrix.php-versions }} php-version: ${{ matrix.php-versions }}
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis, :psr
- uses: actions/checkout@v1 - uses: actions/checkout@v4
with: with:
ref: v5-develop ref: v5-develop
fetch-depth: 1 fetch-depth: 1
@ -96,7 +96,7 @@ jobs:
id: composer-cache id: composer-cache
run: | run: |
echo "::set-output name=dir::$(composer config cache-files-dir)" echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v2 - uses: actions/cache@v3
with: with:
path: ${{ steps.composer-cache.outputs.dir }} path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}

View File

@ -1 +1 @@
5.7.57 5.7.58

View File

@ -127,6 +127,7 @@ class CheckData extends Command
$this->checkCompanyTokens(); $this->checkCompanyTokens();
$this->checkUserState(); $this->checkUserState();
$this->checkContactEmailAndSendEmailStatus(); $this->checkContactEmailAndSendEmailStatus();
$this->checkPaymentCurrency();
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
$this->checkAccountStatuses(); $this->checkAccountStatuses();
@ -325,6 +326,7 @@ class CheckData extends Command
->whereNull('contact_key') ->whereNull('contact_key')
->orderBy('id') ->orderBy('id')
->get(['id']); ->get(['id']);
$this->logMessage($contacts->count().' contacts without a contact_key'); $this->logMessage($contacts->count().' contacts without a contact_key');
if ($contacts->count() > 0) { if ($contacts->count() > 0) {
@ -342,20 +344,8 @@ class CheckData extends Command
} }
} }
// check for missing contacts $vendors = Vendor::withTrashed()->doesntHave('contacts');
$vendors = DB::table('vendors')
->leftJoin('vendor_contacts', function ($join) {
$join->on('vendor_contacts.vendor_id', '=', 'vendors.id')
->whereNull('vendor_contacts.deleted_at');
})
->groupBy('vendors.id', 'vendors.user_id', 'vendors.company_id')
->havingRaw('count(vendor_contacts.id) = 0');
if ($this->option('vendor_id')) {
$vendors->where('vendors.id', '=', $this->option('vendor_id'));
}
$vendors = $vendors->get(['vendors.id', 'vendors.user_id', 'vendors.company_id']);
$this->logMessage($vendors->count().' vendors without any contacts'); $this->logMessage($vendors->count().' vendors without any contacts');
if ($vendors->count() > 0) { if ($vendors->count() > 0) {
@ -377,23 +367,6 @@ class CheckData extends Command
} }
} }
private function checkFailedJobs()
{
if (config('ninja.testvars.travis')) {
return;
}
$queueDB = config('queue.connections.database.connection');
$count = DB::connection($queueDB)->table('failed_jobs')->count();
if ($count > 25) {
$this->isValid = false;
}
$this->logMessage($count.' failed jobs');
}
private function checkInvitations() private function checkInvitations()
{ {
$invoices = DB::table('invoices') $invoices = DB::table('invoices')
@ -683,6 +656,8 @@ class CheckData extends Command
->count(); ->count();
if ($count == 0) { if ($count == 0) {
$this->isValid = false;
//factor in over payments to the client balance //factor in over payments to the client balance
$over_payment = Payment::where('client_id', $client->id) $over_payment = Payment::where('client_id', $client->id)
->where('is_deleted', 0) ->where('is_deleted', 0)
@ -745,6 +720,8 @@ class CheckData extends Command
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first(); $ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
if (number_format($invoice_balance, 4) != number_format($client->balance, 4)) { if (number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
$this->isValid = false;
$this->wrong_balances++; $this->wrong_balances++;
$ledger_balance = $ledger ? $ledger->balance : 0; $ledger_balance = $ledger ? $ledger->balance : 0;
@ -893,6 +870,8 @@ class CheckData extends Command
->exists(); ->exists();
if ($payment) { if ($payment) {
$this->isValid = false;
$this->logMessage("I found a payment for {$account->key}"); $this->logMessage("I found a payment for {$account->key}");
} }
} }
@ -1008,6 +987,7 @@ class CheckData extends Command
BankTransaction::with('payment')->withTrashed()->where('invoice_ids', ',,,,,,,,')->cursor()->each(function ($bt) { BankTransaction::with('payment')->withTrashed()->where('invoice_ids', ',,,,,,,,')->cursor()->each(function ($bt) {
if($bt->payment->exists()) { if($bt->payment->exists()) {
$this->isValid = false;
$bt->invoice_ids = collect($bt->payment->invoices)->pluck('hashed_id')->implode(','); $bt->invoice_ids = collect($bt->payment->invoices)->pluck('hashed_id')->implode(',');
$bt->save(); $bt->save();
@ -1038,4 +1018,30 @@ class CheckData extends Command
}); });
} }
} }
public function checkPaymentCurrency()
{
$p = Payment::with('company','client')
->withTrashed()
->where('currency_id', '')
->orWhereNull('currency_id');
$this->logMessage($p->count() . " Payments with No currency set");
if($p->count() != 0)
$this->isValid = false;
if ($this->option('fix') == 'true') {
$p->cursor()->each(function ($c) {
$c->currency_id = $c->client->settings->currency_id ?? $c->company->settings->currency_id;
$c->saveQuietly();
$this->logMessage("Fixing - {$c->id}");
});
}
}
} }

View File

@ -30,7 +30,7 @@ class CreditFilters extends QueryFilters
* @param string $value The credit status as seen by the client * @param string $value The credit status as seen by the client
* @return Builder * @return Builder
*/ */
public function credit_status(string $value = ''): Builder public function client_status(string $value = ''): Builder
{ {
if (strlen($value) == 0) { if (strlen($value) == 0) {
return $this->builder; return $this->builder;

View File

@ -147,11 +147,15 @@ class InvoiceFilters extends QueryFilters
public function upcoming(): Builder public function upcoming(): Builder
{ {
return $this->builder->whereIn('status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT]) return $this->builder->whereIn('status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT])
->where(function ($query) { ->whereNull('due_date')
$query->whereNull('due_date') ->orWhere(function ($q) {
->orWhere('due_date', '>', now()); $q->where('due_date', '>=', now()->startOfDay()->subSecond())->where('partial', 0);
}) })
->orderBy('due_date', 'ASC'); ->orWhere(function ($q) {
$q->where('partial_due_date', '>=', now()->startOfDay()->subSecond())->where('partial', '>', 0);
})
->orderByRaw('ISNULL(due_date), due_date '. 'desc')
->orderByRaw('ISNULL(partial_due_date), partial_due_date '. 'desc');
} }
/** /**

View File

@ -55,6 +55,14 @@ class PaymentResponseRequest extends FormRequest
'pay_with_token' => ($this->pay_with_token === 'true' || $this->pay_with_token === true) ? true : false, 'pay_with_token' => ($this->pay_with_token === 'true' || $this->pay_with_token === true) ? true : false,
]); ]);
} }
if($this->has('payment_method_id')) {
$this->merge([
'payment_method_id' => preg_replace('~\D~', '', $this->payment_method_id),
]);
}
} }
public function shouldUseToken(): bool public function shouldUseToken(): bool

View File

@ -60,9 +60,9 @@ class UpdateCreditRequest extends Request
$rules['file'] = $this->file_validation; $rules['file'] = $this->file_validation;
} }
if ($this->number) { $rules['number'] = ['bail', 'sometimes', Rule::unique('credits')->where('company_id', $user->company()->id)->ignore($this->credit->id)];
$rules['number'] = Rule::unique('credits')->where('company_id', $user->company()->id)->ignore($this->credit->id);
} $rules['client_id'] = ['bail', 'sometimes',Rule::in([$this->credit->client_id])];
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';

View File

@ -37,6 +37,7 @@ class ImportRequest extends Request
'column_map' => 'required_with:hash|array', 'column_map' => 'required_with:hash|array',
'skip_header' => 'required_with:hash|boolean', 'skip_header' => 'required_with:hash|boolean',
'files.*' => 'file|mimes:csv,txt', 'files.*' => 'file|mimes:csv,txt',
'bank_integration_id' => 'bail|required_if:column_map,bank_transaction|min:2'
]; ];
} }
} }

View File

@ -22,7 +22,10 @@ class PreImportRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->isAdmin(); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->isAdmin();
} }
public function rules() public function rules()

View File

@ -74,7 +74,7 @@ class StoreInvoiceRequest extends Request
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['exchange_rate'] = 'bail|sometimes|numeric';
$rules['partial'] = 'bail|sometimes|nullable|numeric|gte:0'; $rules['partial'] = 'bail|sometimes|nullable|numeric|gte:0';
$rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date']; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date'];
return $rules; return $rules;
} }
@ -89,6 +89,10 @@ class StoreInvoiceRequest extends Request
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
} }
if(isset($input['partial']) && $input['partial'] == 0 && isset($input['partial_due_date'])) {
$input['partial_due_date'] = '';
}
$input['amount'] = 0; $input['amount'] = 0;
$input['balance'] = 0; $input['balance'] = 0;

View File

@ -59,12 +59,11 @@ class UpdateInvoiceRequest extends Request
$rules['id'] = new LockedInvoiceRule($this->invoice); $rules['id'] = new LockedInvoiceRule($this->invoice);
if ($this->number) { $rules['number'] = ['bail', 'sometimes', Rule::unique('invoices')->where('company_id', $user->company()->id)->ignore($this->invoice->id)];
$rules['number'] = Rule::unique('invoices')->where('company_id', $user->company()->id)->ignore($this->invoice->id);
}
$rules['is_amount_discount'] = ['boolean']; $rules['is_amount_discount'] = ['boolean'];
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])];
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
@ -77,7 +76,7 @@ class UpdateInvoiceRequest extends Request
$rules['status_id'] = 'bail|sometimes|not_in:5'; //do not allow cancelled invoices to be modfified. $rules['status_id'] = 'bail|sometimes|not_in:5'; //do not allow cancelled invoices to be modfified.
$rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['exchange_rate'] = 'bail|sometimes|numeric';
$rules['partial'] = 'bail|sometimes|nullable|numeric'; $rules['partial'] = 'bail|sometimes|nullable|numeric';
$rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date']; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date'];
return $rules; return $rules;
} }
@ -90,6 +89,10 @@ class UpdateInvoiceRequest extends Request
$input['id'] = $this->invoice->id; $input['id'] = $this->invoice->id;
if(isset($input['partial']) && $input['partial'] == 0 && isset($input['partial_due_date'])) {
$input['partial_due_date'] = '';
}
if (isset($input['line_items']) && is_array($input['line_items'])) { if (isset($input['line_items']) && is_array($input['line_items'])) {
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
} }

View File

@ -30,7 +30,10 @@ class UpdatePurchaseOrderRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->can('edit', $this->purchase_order); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('edit', $this->purchase_order);
} }
/** /**
@ -40,11 +43,13 @@ class UpdatePurchaseOrderRequest extends Request
*/ */
public function rules() public function rules()
{ {
/** @var \App\Models\User $user */
$user = auth()->user();
$rules = []; $rules = [];
if ($this->number) { $rules['number'] = ['bail', 'sometimes', Rule::unique('purchase_orders')->where('company_id', $user->company()->id)->ignore($this->purchase_order->id)];
$rules['number'] = Rule::unique('purchase_orders')->where('company_id', auth()->user()->company()->id)->ignore($this->purchase_order->id); $rules['vendor_id'] = ['bail', 'sometimes', Rule::in([$this->purchase_order->vendor_id])];
}
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';

View File

@ -30,11 +30,16 @@ class UpdateQuoteRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->can('edit', $this->quote); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('edit', $this->quote);
} }
public function rules() public function rules()
{ {
/** @var \App\Models\User $user */
$user = auth()->user();
$rules = []; $rules = [];
if ($this->file('documents') && is_array($this->file('documents'))) { if ($this->file('documents') && is_array($this->file('documents'))) {
@ -50,9 +55,9 @@ class UpdateQuoteRequest extends Request
} }
if ($this->number) { $rules['number'] = ['bail', 'sometimes', Rule::unique('quotes')->where('company_id', $user->company()->id)->ignore($this->quote->id)];
$rules['number'] = Rule::unique('quotes')->where('company_id', auth()->user()->company()->id)->ignore($this->quote->id);
} $rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->quote->client_id])];
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';

View File

@ -56,9 +56,10 @@ class UpdateRecurringInvoiceRequest extends Request
$rules['file'] = $this->file_validation; $rules['file'] = $this->file_validation;
} }
if ($this->number) { $rules['number'] = ['bail', 'sometimes', Rule::unique('recurring_invoices')->where('company_id', $user->company()->id)->ignore($this->recurring_invoice->id)];
$rules['number'] = Rule::unique('recurring_invoices')->where('company_id', $user->company()->id)->ignore($this->recurring_invoice->id);
}
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->recurring_invoice->client_id])];
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
$rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate1'] = 'bail|sometimes|numeric';

View File

@ -49,6 +49,7 @@ class StoreSchedulerRequest extends Request
'parameters.entity_id' => ['bail', 'sometimes', 'string'], 'parameters.entity_id' => ['bail', 'sometimes', 'string'],
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,clients,client_contacts,credits,documents,expenses,invoices,invoice_items,quotes,quote_items,recurring_invoices,payments,products,tasks'], 'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,clients,client_contacts,credits,documents,expenses,invoices,invoice_items,quotes,quote_items,recurring_invoices,payments,products,tasks'],
'parameters.date_key' => ['bail','sometimes', 'string'], 'parameters.date_key' => ['bail','sometimes', 'string'],
'parameters.status' => ['bail','sometimes', 'string', 'in:all,draft,paid,unpaid,overdue'],
]; ];
return $rules; return $rules;

View File

@ -353,6 +353,10 @@ class Activity extends StaticModel
return $this->belongsTo(Expense::class)->withTrashed(); return $this->belongsTo(Expense::class)->withTrashed();
} }
public function account(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{
return $this->belongsTo(Account::class);
}
public function recurring_expense(): \Illuminate\Database\Eloquent\Relations\BelongsTo public function recurring_expense(): \Illuminate\Database\Eloquent\Relations\BelongsTo
{ {

View File

@ -139,9 +139,8 @@ class PayPalPPCPPaymentDriver extends BaseDriver
public function init(): self public function init(): self
{ {
// $this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
$this->api_endpoint_url = 'https://api-m.paypal.com'; $this->api_endpoint_url = 'https://api-m.paypal.com';
// $this->api_endpoint_url = 'https://api-m.sandbox.paypal.com';
$secret = config('ninja.paypal.secret'); $secret = config('ninja.paypal.secret');
$client_id = config('ninja.paypal.client_id'); $client_id = config('ninja.paypal.client_id');
@ -238,30 +237,23 @@ class PayPalPPCPPaymentDriver extends BaseDriver
} }
private function getClientToken(): string
{
$r = $this->gatewayRequest('/v1/identity/generate-token', 'post', ['body' => '']);
if($r->successful()) {
return $r->json()['client_token'];
}
throw new PaymentFailed('Unable to gain client token from Paypal. Check your configuration', 401);
}
public function processPaymentResponse($request) public function processPaymentResponse($request)
{ {
$request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']); $request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']);
$response = json_decode($request['gateway_response'], true); $response = json_decode($request['gateway_response'], true);
//capture
$orderID = $response['orderID'];
$r = $this->gatewayRequest("/v2/checkout/orders/{$orderID}/capture", 'post', ['body' => '']);
$response = $r;
if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) { if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) {
$data = [ $data = [
'payment_type' => $this->getPaymentMethod($request->gateway_type_id), 'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'amount' => $response['purchase_units'][0]['amount']['value'], 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => GatewayType::PAYPAL, 'gateway_type_id' => GatewayType::PAYPAL,
]; ];
@ -300,6 +292,21 @@ class PayPalPPCPPaymentDriver extends BaseDriver
} }
} }
private function getClientToken(): string
{
$r = $this->gatewayRequest('/v1/identity/generate-token', 'post', ['body' => '']);
if($r->successful()) {
return $r->json()['client_token'];
}
throw new PaymentFailed('Unable to gain client token from Paypal. Check your configuration', 401);
}
private function paymentSource(): array private function paymentSource(): array
{ {
/** we only need to support paypal as payment source until as we are only using hosted payment buttons */ /** we only need to support paypal as payment source until as we are only using hosted payment buttons */
@ -307,36 +314,6 @@ class PayPalPPCPPaymentDriver extends BaseDriver
} }
/**@deprecated v5.7.54 */
private function injectVenmoPaymentSource(): array
{
return [
"venmo" => [
"email_address" => $this->client->present()->email(),
],
];
}
/**@deprecated v5.7.54 */
private function injectCardPaymentSource(): array
{
return [
"card" => [
"name" => $this->client->present()->name(),
"email_address" => $this->client->present()->email(),
"billing_address" => $this->getBillingAddress(),
"experience_context"=> [
"user_action" => "PAY_NOW"
],
],
];
}
private function injectPayPalPaymentSource(): array private function injectPayPalPaymentSource(): array
{ {
@ -462,10 +439,23 @@ class PayPalPPCPPaymentDriver extends BaseDriver
->withHeaders($this->getHeaders($headers)) ->withHeaders($this->getHeaders($headers))
->{$verb}("{$this->api_endpoint_url}{$uri}", $data); ->{$verb}("{$this->api_endpoint_url}{$uri}", $data);
nlog($r);
nlog($r->json());
if($r->successful()) { if($r->successful()) {
return $r; return $r;
} }
SystemLogger::dispatch(
['response' => $r->body()],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
throw new PaymentFailed("Gateway failure - {$r->body()}", 401); throw new PaymentFailed("Gateway failure - {$r->body()}", 401);
} }

View File

@ -288,7 +288,7 @@ class EmailDefaults
$documents = []; $documents = [];
/* Return early if the user cannot attach documents */ /* Return early if the user cannot attach documents */
if (!$this->email->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if (!$this->email->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT) || $this->email->email_object->email_template_subject == 'email_subject_statement') {
return $this; return $this;
} }

View File

@ -715,10 +715,8 @@ class SubscriptionService
nlog($response); nlog($response);
if ($credit) { if ($credit) {
// return $this->handleRedirect('/client/credits/'.$credit->hashed_id);
return '/client/credits/'.$credit->hashed_id; return '/client/credits/'.$credit->hashed_id;
} else { } else {
// return $this->handleRedirect('/client/credits');
return '/client/credits'; return '/client/credits';
} }
} }
@ -1494,10 +1492,10 @@ class SubscriptionService
private function handleRedirect($default_redirect) private function handleRedirect($default_redirect)
{ {
if (array_key_exists('return_url', $this->subscription->webhook_configuration) && strlen($this->subscription->webhook_configuration['return_url']) >=1) { if (array_key_exists('return_url', $this->subscription->webhook_configuration) && strlen($this->subscription->webhook_configuration['return_url']) >=1) {
return redirect($this->subscription->webhook_configuration['return_url']); return redirect($this->subscription->webhook_configuration['return_url'])->send();
} }
return redirect($default_redirect); return redirect($default_redirect)->send();
} }
/** /**

View File

@ -85,7 +85,7 @@
"setasign/fpdf": "^1.8", "setasign/fpdf": "^1.8",
"setasign/fpdi": "^2.3", "setasign/fpdi": "^2.3",
"shopify/shopify-api": "^4.3", "shopify/shopify-api": "^4.3",
"socialiteproviders/apple": "^5.2", "socialiteproviders/apple": "dev-master",
"socialiteproviders/microsoft": "^4.1", "socialiteproviders/microsoft": "^4.1",
"spatie/laravel-data": "^3.5", "spatie/laravel-data": "^3.5",
"sprain/swiss-qr-bill": "^4.3", "sprain/swiss-qr-bill": "^4.3",
@ -113,7 +113,7 @@
"laracasts/cypress": "^3.0", "laracasts/cypress": "^3.0",
"mockery/mockery": "^1.4.4", "mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0", "nunomaduro/collision": "^7.0",
"nunomaduro/larastan": "^2.0", "larastan/larastan": "^2",
"phpstan/phpstan": "^1.9", "phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^10.0", "phpunit/phpunit": "^10.0",
"spatie/laravel-ignition": "^2.0", "spatie/laravel-ignition": "^2.0",
@ -171,6 +171,12 @@
"php-http/discovery": true "php-http/discovery": true
} }
}, },
"repositories": [
{
"type": "vcs",
"url": "https://github.com/turbo124/apple"
}
],
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true "prefer-stable": true
} }

1202
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION', '5.7.57'), 'app_version' => env('APP_VERSION', '5.7.58'),
'app_tag' => env('APP_TAG', '5.7.57'), 'app_tag' => env('APP_TAG', '5.7.58'),
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false), 'api_secret' => env('API_SECRET', false),

View File

@ -3372,7 +3372,7 @@ $lang = array(
'credit_number_counter' => 'Credit Number Counter', 'credit_number_counter' => 'Credit Number Counter',
'reset_counter_date' => 'Reset Counter Date', 'reset_counter_date' => 'Reset Counter Date',
'counter_padding' => 'Counter Padding', 'counter_padding' => 'Counter Padding',
'shared_invoice_quote_counter' => 'Share Invoice Quote Counter', 'shared_invoice_quote_counter' => 'Share Invoice/Quote Counter',
'default_tax_name_1' => 'Default Tax Name 1', 'default_tax_name_1' => 'Default Tax Name 1',
'default_tax_rate_1' => 'Default Tax Rate 1', 'default_tax_rate_1' => 'Default Tax Rate 1',
'default_tax_name_2' => 'Default Tax Name 2', 'default_tax_name_2' => 'Default Tax Name 2',

View File

@ -1,9 +0,0 @@
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/class t{constructor(){this.button=document.querySelector("#pay-button")}init(){this.frames=Frames.init(document.querySelector("meta[name=public-key]").content)}handle(){this.init(),Frames.addEventHandler(Frames.Events.CARD_VALIDATION_CHANGED,e=>{this.button.disabled=!Frames.isCardValid()}),Frames.addEventHandler(Frames.Events.CARD_TOKENIZED,e=>{document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e),document.getElementById("server_response").submit()}),document.querySelector("#authorization-form").addEventListener("submit",e=>{this.button.disabled=!0,e.preventDefault(),Frames.submitCard()})}}new t().handle();

View File

@ -1,9 +0,0 @@
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/class o{constructor(){this.tokens=[]}mountFrames(){console.log("Mount checkout frames..")}handlePaymentUsingToken(t){document.getElementById("checkout--container").classList.add("hidden"),document.getElementById("pay-now-with-token--container").classList.remove("hidden"),document.getElementById("save-card--container").style.display="none",document.querySelector("input[name=token]").value=t.target.dataset.token}handlePaymentUsingCreditCard(t){document.getElementById("checkout--container").classList.remove("hidden"),document.getElementById("pay-now-with-token--container").classList.add("hidden"),document.getElementById("save-card--container").style.display="grid",document.querySelector("input[name=token]").value="";const e=document.getElementById("pay-button"),a=document.querySelector('meta[name="public-key"]').content??"",d=document.getElementById("payment-form");Frames.init(a),Frames.addEventHandler(Frames.Events.CARD_VALIDATION_CHANGED,function(n){e.disabled=!Frames.isCardValid()}),Frames.addEventHandler(Frames.Events.CARD_TOKENIZATION_FAILED,function(n){pay.button.disabled=!1}),Frames.addEventHandler(Frames.Events.CARD_TOKENIZED,function(n){e.disabled=!0,document.querySelector('input[name="gateway_response"]').value=JSON.stringify(n),document.querySelector('input[name="store_card"]').value=document.querySelector("input[name=token-billing-checkbox]:checked").value,document.getElementById("server-response").submit()}),d.addEventListener("submit",function(n){n.preventDefault(),Frames.submitCard()})}completePaymentUsingToken(t){let e=document.getElementById("pay-now-with-token");e.disabled=!0,e.querySelector("svg").classList.remove("hidden"),e.querySelector("span").classList.add("hidden"),document.getElementById("server-response").submit()}handle(){this.handlePaymentUsingCreditCard(),Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(t=>t.addEventListener("click",this.handlePaymentUsingToken)),document.getElementById("toggle-payment-with-credit-card").addEventListener("click",this.handlePaymentUsingCreditCard),document.getElementById("pay-now-with-token").addEventListener("click",this.completePaymentUsingToken)}}new o().handle();

View File

@ -41,7 +41,7 @@
"src": "resources/js/clients/payment_methods/authorize-authorize-card.js" "src": "resources/js/clients/payment_methods/authorize-authorize-card.js"
}, },
"resources/js/clients/payment_methods/authorize-checkout-card.js": { "resources/js/clients/payment_methods/authorize-checkout-card.js": {
"file": "assets/authorize-checkout-card-9d660182.js", "file": "assets/authorize-checkout-card-d561d355.js",
"isEntry": true, "isEntry": true,
"src": "resources/js/clients/payment_methods/authorize-checkout-card.js" "src": "resources/js/clients/payment_methods/authorize-checkout-card.js"
}, },
@ -71,7 +71,7 @@
"src": "resources/js/clients/payments/braintree-paypal.js" "src": "resources/js/clients/payments/braintree-paypal.js"
}, },
"resources/js/clients/payments/checkout-credit-card.js": { "resources/js/clients/payments/checkout-credit-card.js": {
"file": "assets/checkout-credit-card-906a30cd.js", "file": "assets/checkout-credit-card-8a04938c.js",
"isEntry": true, "isEntry": true,
"src": "resources/js/clients/payments/checkout-credit-card.js" "src": "resources/js/clients/payments/checkout-credit-card.js"
}, },

View File

@ -10,7 +10,9 @@
class CheckoutCreditCardAuthorization { class CheckoutCreditCardAuthorization {
constructor() { constructor() {
this.button = document.querySelector('#pay-button'); // this.button = document.querySelector('#pay-button');
this.button = document.getElementById('pay-button');
} }
init() { init() {

View File

@ -37,6 +37,7 @@ class CheckoutCreditCard {
.value = ''; .value = '';
const payButton = document.getElementById('pay-button'); const payButton = document.getElementById('pay-button');
const publicKey = document.querySelector('meta[name="public-key"]').content ?? ''; const publicKey = document.querySelector('meta[name="public-key"]').content ?? '';
const form = document.getElementById('payment-form'); const form = document.getElementById('payment-form');
@ -47,7 +48,7 @@ class CheckoutCreditCard {
}); });
Frames.addEventHandler(Frames.Events.CARD_TOKENIZATION_FAILED, function (event) { Frames.addEventHandler(Frames.Events.CARD_TOKENIZATION_FAILED, function (event) {
pay.button.disabled = false; payButton.disabled = false;
}); });
Frames.addEventHandler(Frames.Events.CARD_TOKENIZED, function (event) { Frames.addEventHandler(Frames.Events.CARD_TOKENIZED, function (event) {
@ -68,6 +69,7 @@ class CheckoutCreditCard {
form.addEventListener('submit', function (event) { form.addEventListener('submit', function (event) {
event.preventDefault(); event.preventDefault();
payButton.disabled = true;
Frames.submitCard(); Frames.submitCard();
}); });
} }

View File

@ -53,10 +53,11 @@
return actions.restart(); return actions.restart();
} }
return actions.order.capture().then(function(details) { // return actions.order.capture().then(function(details) {
document.getElementById("gateway_response").value =JSON.stringify( details ); document.getElementById("gateway_response").value =JSON.stringify( data );
// document.getElementById("gateway_response").value =JSON.stringify( details );
document.getElementById("server_response").submit(); document.getElementById("server_response").submit();
}); // });
}, },
onCancel: function() { onCancel: function() {
window.location.href = "/client/invoices/"; window.location.href = "/client/invoices/";

View File

@ -19,8 +19,18 @@ use Tests\TestCase;
*/ */
class EvaluateStringTest extends TestCase class EvaluateStringTest extends TestCase
{ {
public function testNumericCleanup()
{
$string = '13/favicon.ico';
$number = preg_replace('~\D~', '', $string);
$this->assertEquals(13, $number);
}
public function testClassNameResolution() public function testClassNameResolution()
{ {
$this->assertEquals(class_basename(Client::class), 'Client'); $this->assertEquals(class_basename(Client::class), 'Client');
} }
} }