Merge pull request #10592 from turbo124/v5-develop

v5.11.32
This commit is contained in:
David Bomba 2025-01-27 13:04:11 +11:00 committed by GitHub
commit c0310f6bae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 120 additions and 76 deletions

View File

@ -1 +1 @@
5.11.31
5.11.32

View File

@ -46,7 +46,7 @@ class PaymentTermFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('payment_terms'))) {
return $this->builder;
}

View File

@ -61,7 +61,7 @@ class ProductFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('products'))) {
return $this->builder;
}

View File

@ -60,7 +60,7 @@ class ProjectFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('projects'))) {
return $this->builder;
}

View File

@ -126,7 +126,7 @@ class PurchaseOrderFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('purchase_orders'))) {
return $this->builder;
}

View File

@ -126,7 +126,7 @@ class RecurringInvoiceFilters extends QueryFilters
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('recurring_invoices'))) {
return $this->builder;
}

View File

@ -46,7 +46,7 @@ class SchedulerFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('schedulers'))) {
return $this->builder;
}

View File

@ -46,7 +46,7 @@ class SubscriptionFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('subscriptions'))) {
return $this->builder;
}

View File

@ -71,7 +71,7 @@ class SystemLogFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('system_logs'))) {
return $this->builder;
}

View File

@ -130,7 +130,7 @@ class TaskFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('tasks'))) {
return $this->builder;
}

View File

@ -46,7 +46,7 @@ class TaskStatusFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('task_statuses'))) {
return $this->builder;
}

View File

@ -46,7 +46,7 @@ class TaxRateFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('tax_rates'))) {
return $this->builder;
}

View File

@ -53,7 +53,7 @@ class TokenFilters extends QueryFilters
$sort_col = explode('|', $sort);
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('users'))) {
if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('company_tokens'))) {
return $this->builder;
}

View File

@ -67,30 +67,28 @@ class EpcQrGenerator
public function encodeMessage()
{
// return rtrim(implode("\n", [
// $this->sepa['serviceTag'],
// sprintf('%03d', $this->sepa['version']),
// $this->sepa['characterSet'],
// $this->sepa['identification'],
// isset($this->company?->custom_fields?->company2) ? $this->company->settings->custom_value2 : '',
// $this->company->present()->name(),
// isset($this->company?->custom_fields?->company1) ? $this->company->settings->custom_value1 : '',
// $this->formatMoney($this->amount),
// $this->sepa['purpose'],
// substr($this->invoice->number, 0, 34),
// '',
// ' '
// ]), "\n");
if (isset($this->company->e_invoice->Invoice->PaymentMeans) && ($pm = $this->company->e_invoice->Invoice->PaymentMeans[0] ?? false) && in_array($pm->PaymentMeansCode->value, ['30', '58'])) {
$iban = $pm->PayeeFinancialAccount->ID->value;
$bic = $pm->PayeeFinancialAccount->FinancialInstitutionBranch->FinancialInstitution->ID->value ?? '';
}
else {
$bic = isset($this->company?->custom_fields?->company2) ? $this->company->settings->custom_value2 : '';
$iban = isset($this->company?->custom_fields?->company1) ? $this->company->settings->custom_value1 : '';
}
$data = [
'BCD',
'002', // Version
'1', // Encoding: 1 = UTF-8
'SCT', // Service Tag: SEPA Credit Transfer
isset($this->company?->custom_fields?->company2) ? $this->company->settings->custom_value2 : '', // BIC
$bic, // BIC
$this->company->present()->name(), // Name of the beneficiary
isset($this->company?->custom_fields?->company1) ? $this->company->settings->custom_value1 : '', // IBAN
$iban, // IBAN
$this->formatMoney($this->amount), // Amount with EUR prefix
'', // Reference
substr(($this->invoice->number ?? ''), 0, 34) // Unstructured remittance information

View File

@ -132,6 +132,10 @@ class BTCPayPaymentDriver extends BaseDriver
}
sleep(1);
$this->init();
$webhookClient = new Webhook($this->btcpay_url, $this->api_key);
if (!$webhookClient->isIncomingWebhookRequestValid($webhook_payload, $sig, $this->webhook_secret)) {
@ -140,11 +144,6 @@ class BTCPayPaymentDriver extends BaseDriver
);
}
sleep(1);
$this->init();
$this->setPaymentMethod(GatewayType::CRYPTO);
$this->payment_hash = PaymentHash::where('hash', $btcpayRep->metadata->InvoiceNinjaPaymentHash)->firstOrFail();

View File

@ -142,7 +142,7 @@ class PaymentMethod implements MethodInterface, LivewireMethodInterface
{
$data = $this->paymentData($data);
if ($data['authorize_then_redirect']) {
if ($data['authorize_then_redirect'] ?? false) {
return $this->authorizeView($data);
}
@ -194,27 +194,7 @@ class PaymentMethod implements MethodInterface, LivewireMethodInterface
}
}
public function processPendingPayment($payment_id, float $amount, int $gateway_type_id, $payment_method)
{
$data = [
'payment_method' => $payment_method,
'payment_type' => $gateway_type_id,
'amount' => $amount,
'transaction_reference' => $payment_id,
'gateway_type_id' => $gateway_type_id,
];
$payment = $this->rotessa->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
[ 'data' => $data ],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_ROTESSA,
$this->rotessa->client,
$this->rotessa->client->company,
);
return redirect()->route('client.payments.show', [ 'payment' => $payment->hashed_id ]);
}
/**
* Handle unsuccessful payment for Rotessa.
@ -288,4 +268,76 @@ class PaymentMethod implements MethodInterface, LivewireMethodInterface
return $data;
}
public function tokenBilling(\App\Models\ClientGatewayToken $customer, \App\Models\PaymentHash $payment_hash)
{
try {
$transaction = array_merge($this->transaction, [
'amount' => $payment_hash->data->amount_with_fee,
'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();
$data = [
'payment_method' => $customer->token,
'payment_type' => PaymentType::ACSS,
'amount' => $response['amount'],
'transaction_reference' => $response['id'],
'gateway_type_id' => PaymentType::ACSS,
];
SystemLogger::dispatch(
[ 'data' => $data ],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_ROTESSA,
$this->rotessa->client,
$this->rotessa->client->company,
);
$payment = $this->rotessa->createPayment($data, Payment::STATUS_PENDING);
return $payment;
} catch (\Throwable $e) {
$this->processUnsuccessfulPayment(new \Exception($e->getMessage(), (int) $e->getCode()));
}
}
public function processPendingPayment($payment_id, float $amount, int $gateway_type_id, $payment_method)
{
$data = [
'payment_method' => $payment_method,
'payment_type' => $gateway_type_id,
'amount' => $amount,
'transaction_reference' => $payment_id,
'gateway_type_id' => $gateway_type_id,
];
$payment = $this->rotessa->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
[ 'data' => $data ],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_ROTESSA,
$this->rotessa->client,
$this->rotessa->client->company,
);
return redirect()->route('client.payments.show', [ 'payment' => $payment->hashed_id ]);
}
}

View File

@ -276,6 +276,15 @@ class RotessaPaymentDriver extends BaseDriver
return $r;
}
public function tokenBilling(\App\Models\ClientGatewayToken $cgt, \App\Models\PaymentHash $payment_hash)
{
$this->setPaymentMethod($cgt->gateway_type_id);
return $this->payment_method->tokenBilling($cgt, $payment_hash);
}
private function getUrl(): string
{
return $this->company_gateway->getConfigField('testMode') ? 'https://sandbox-api.rotessa.com/v1/' : 'https://api.rotessa.com/v1/';

View File

@ -241,7 +241,7 @@ class TaskRepository extends BaseRepository
{
//do no allow an task to be restarted if it has been invoiced
if ($task->invoice_id) {
return;
return $task;
}
if (strlen($task->time_log) < 5) {

View File

@ -2012,14 +2012,7 @@ class PdfBuilder
$first_char = substr($trimmed, 0, 1);
if (
$first_char === '#' || // Headers
$first_char === '>' || // Blockquotes
$first_char === '-' || // Lists
$first_char === '*' || // Lists/Bold
$first_char === '_' || // Italic
$first_char === '`' || // Code
$first_char === '[' || // Links
if (in_array($first_char, ['#', '>', '-', '+', '*', '_', '`', '[']) || // Markdown characters
str_contains($trimmed, '**') // Bold (special case)
) {
$contains_markdown = true;

View File

@ -106,13 +106,7 @@ trait PdfMakerUtilities
$first_char = substr($trimmed, 0, 1);
if (
$first_char === '#' || // Headers
$first_char === '>' || // Blockquotes
$first_char === '-' || // Lists
$first_char === '*' || // Lists/Bold
$first_char === '_' || // Italic
$first_char === '`' || // Code
$first_char === '[' || // Links
in_array($first_char, ['#', '>', '-', '+', '*', '_', '`', '[']) || // Markdown characters
str_contains($trimmed, '**') // Bold (special case)
) {
$contains_markdown = true;

View File

@ -69,7 +69,7 @@ class TemplateService
private ?Vendor $vendor = null;
private Invoice | Quote | Credit | PurchaseOrder | RecurringInvoice | Task | Project | Payment $entity;
private Invoice | Quote | Credit | PurchaseOrder | RecurringInvoice | Task | Project | Payment | Client $entity;
private Payment $payment;
@ -108,7 +108,6 @@ class TemplateService
$this->twig->addExtension(new \Twig\Extension\DebugExtension());
$this->twig->addExtension(new MarkdownExtension());
$this->twig->addRuntimeLoader(new class () implements RuntimeLoaderInterface {
public function load($class)
{

View File

@ -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.11.31'),
'app_tag' => env('APP_TAG', '5.11.31'),
'app_version' => env('APP_VERSION', '5.11.32'),
'app_tag' => env('APP_TAG', '5.11.32'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false),