Merge branch 'fix/elastic-migrations-idempotency' of https://github.com/turbo124/invoiceninja into fix/elastic-migrations-idempotency

This commit is contained in:
David Bomba 2025-11-26 13:34:43 +11:00
commit 019a688047
20 changed files with 322 additions and 205 deletions

View File

@ -1 +1 @@
5.12.34 5.12.35

View File

@ -335,12 +335,11 @@ class RebuildElasticIndexes extends Command
$this->line(" Waiting for our {$expectedJobCount} jobs to complete..."); $this->line(" Waiting for our {$expectedJobCount} jobs to complete...");
$this->line(" (Tracking: pending + processing jobs)", 'comment'); $this->line(" (Tracking: pending + processing jobs)", 'comment');
$maxWaitSeconds = 600;
$startTime = time(); $startTime = time();
$lastReportedDelta = -1; $lastReportedDelta = -1;
$stableCount = 0; $stableCount = 0;
while ((time() - $startTime) < $maxWaitSeconds) { while (true) {
try { try {
$currentJobCount = $this->getTotalActiveJobCount($connection, $queueName); $currentJobCount = $this->getTotalActiveJobCount($connection, $queueName);
$delta = $currentJobCount - $baselineJobCount; $delta = $currentJobCount - $baselineJobCount;
@ -371,13 +370,6 @@ class RebuildElasticIndexes extends Command
return; return;
} }
} }
try {
$finalCount = $this->getTotalActiveJobCount($connection, $queueName);
$this->warn(" ⚠ Timeout after {$maxWaitSeconds}s (active: {$finalCount}, baseline: {$baselineJobCount})");
} catch (\Exception $e) {
$this->warn(" ⚠ Timeout after {$maxWaitSeconds}s - continuing");
}
} }
protected function getTotalActiveJobCount(string $connection, string $queueName): int protected function getTotalActiveJobCount(string $connection, string $queueName): int

View File

@ -135,13 +135,13 @@ class LoginController extends BaseController
if (strlen($request->input('one_time_password')) == 0 || !$google2fa->verifyKey(decrypt($user->google_2fa_secret), $request->input('one_time_password'))) { if (strlen($request->input('one_time_password')) == 0 || !$google2fa->verifyKey(decrypt($user->google_2fa_secret), $request->input('one_time_password'))) {
return response() return response()
->json(['message' => ctrans('texts.invalid_one_time_password')], 401) ->json(['message' => ctrans('texts.invalid_one_time_password')], 422)
->header('X-App-Version', config('ninja.app_version')) ->header('X-App-Version', config('ninja.app_version'))
->header('X-Api-Version', config('ninja.minimum_client_version')); ->header('X-Api-Version', config('ninja.minimum_client_version'));
} }
} elseif (strlen($user->google_2fa_secret ?? '') > 2 && !$request->has('one_time_password')) { } elseif (strlen($user->google_2fa_secret ?? '') > 2 && !$request->has('one_time_password')) {
return response() return response()
->json(['message' => ctrans('texts.invalid_one_time_password')], 401) ->json(['message' => ctrans('texts.invalid_one_time_password')], 422)
->header('X-App-Version', config('ninja.app_version')) ->header('X-App-Version', config('ninja.app_version'))
->header('X-Api-Version', config('ninja.minimum_client_version')); ->header('X-Api-Version', config('ninja.minimum_client_version'));
} }

View File

@ -26,9 +26,16 @@ class EmailPreferencesController extends Controller
{ {
public function index(string $entity, string $invitation_key, Request $request): \Illuminate\View\View public function index(string $entity, string $invitation_key, Request $request): \Illuminate\View\View
{ {
request()->session()->invalidate();
request()->session()->regenerate(true);
request()->session()->regenerateToken();
$class = "\\App\\Models\\".ucfirst(Str::camel($entity)).'Invitation'; $class = "\\App\\Models\\".ucfirst(Str::camel($entity)).'Invitation';
$invitation = $class::where('key', $invitation_key)->firstOrFail(); $invitation = $class::where('key', $invitation_key)->firstOrFail();
auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
$data['receive_emails'] = $invitation->contact->is_locked ? false : true; $data['receive_emails'] = $invitation->contact->is_locked ? false : true;
$data['company'] = $invitation->company; $data['company'] = $invitation->company;

View File

@ -294,6 +294,8 @@ class InvoicePay extends Component
'payable_invoices' => $payable_invoices, 'payable_invoices' => $payable_invoices,
]); ]);
$this->dispatch(self::CONTEXT_READY);
} }
public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View

View File

@ -28,42 +28,49 @@ class InvoiceSummary extends Component
public $gateway_fee; public $gateway_fee;
public $isReady = false;
#[On(self::CONTEXT_READY)]
public function onContextReady(): void
{
$this->isReady = true;
$this->loadContextData();
}
public function mount() public function mount()
{ {
$_context = $this->getContext(); $_context = $this->getContext();
$contact = $_context['contact'] ?? auth()->guard('contact')->user(); if (!empty($_context)) {
$this->invoices = $_context['payable_invoices']; $this->isReady = true;
$this->amount = Number::formatMoney($_context['amount'], $contact->client); $this->loadContextData();
$this->gateway_fee = isset($_context['gateway_fee']) ? Number::formatMoney($_context['gateway_fee'], $contact->client) : false; }
}
private function loadContextData(): void
{
$_context = $this->getContext();
if (empty($_context)) {
return;
}
$contact = $_context['contact'] ?? auth()->guard('contact')->user();
$this->invoices = $_context['payable_invoices'] ?? [];
$this->amount = isset($_context['amount']) ? Number::formatMoney($_context['amount'], $contact->client) : '';
$this->gateway_fee = isset($_context['gateway_fee']) ? Number::formatMoney($_context['gateway_fee'], $contact->client) : false;
} }
#[On(self::CONTEXT_UPDATE)] #[On(self::CONTEXT_UPDATE)]
public function onContextUpdate(): void public function onContextUpdate(): void
{ {
$this->loadContextData();
$_context = $this->getContext();
// refactor logic for updating the price for eg if it changes with under/over pay
$contact = $_context['contact'] ?? auth()->guard('contact')->user();
$this->invoices = $_context['payable_invoices'];
$this->amount = Number::formatMoney($_context['amount'], $contact->client);
$this->gateway_fee = isset($_context['gateway_fee']) ? Number::formatMoney($_context['gateway_fee'], $contact->client) : false;
} }
#[On('payment-view-rendered')] #[On('payment-view-rendered')]
public function handlePaymentViewRendered() public function handlePaymentViewRendered(): void
{ {
$this->loadContextData();
$_context = $this->getContext();
$contact = $_context['contact'] ?? auth()->guard('contact')->user();
$this->amount = Number::formatMoney($_context['amount'], $contact->client);
$this->gateway_fee = isset($_context['gateway_fee']) ? Number::formatMoney($_context['gateway_fee'], $contact->client) : false;
} }
public function downloadDocument($invoice_hashed_id) public function downloadDocument($invoice_hashed_id)
@ -91,10 +98,13 @@ class InvoiceSummary extends Component
public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View
{ {
$contact = $this->getContext()['contact'] ?? auth()->guard('contact')->user(); $_context = $this->getContext();
$contact = $_context['contact'] ?? auth()->guard('contact')->user();
return render('flow2.invoices-summary', [ return render('flow2.invoices-summary', [
'client' => $contact->client, 'client' => $contact->client ?? null,
'isReady' => $this->isReady,
]); ]);
} }

View File

@ -27,10 +27,6 @@ class ClientGatewayTokenRepository extends BaseRepository
$client_gateway_token->company_gateway_id = $data['company_gateway_id']; $client_gateway_token->company_gateway_id = $data['company_gateway_id'];
} }
if (isset($data['is_default']) && !boolval($data['is_default'])) {
$client_gateway_token->is_default = false;
}
$client_gateway_token->save(); $client_gateway_token->save();
if (isset($data['is_default']) && boolval($data['is_default'])) { if (isset($data['is_default']) && boolval($data['is_default'])) {
@ -45,6 +41,7 @@ class ClientGatewayTokenRepository extends BaseRepository
ClientGatewayToken::withTrashed() ClientGatewayToken::withTrashed()
->where('company_id', $client_gateway_token->company_id) ->where('company_id', $client_gateway_token->company_id)
->where('client_id', $client_gateway_token->client_id) ->where('client_id', $client_gateway_token->client_id)
->where('id', '!=', $client_gateway_token->id)
->update(['is_default' => false]); ->update(['is_default' => false]);
$client_gateway_token->is_default = true; $client_gateway_token->is_default = true;

View File

@ -14,10 +14,11 @@ namespace App\Services\EDocument\Standards\Verifactu;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use App\Services\EDocument\Standards\Verifactu\ResponseProcessor; use App\Services\EDocument\Standards\Verifactu\ResponseProcessor;
use App\Services\EDocument\Standards\Verifactu\Signing\SigningService;
class AeatClient class AeatClient
{ {
private string $base_url = 'https://www1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP'; private string $base_url = 'https://www1.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP';
private string $sandbox_url = 'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP'; private string $sandbox_url = 'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP';
@ -61,8 +62,34 @@ class AeatClient
return $this; return $this;
} }
/**
* Sign SOAP envelope with XML Digital Signature
*
* @param string $xml - Unsigned SOAP envelope
* @return string - Signed SOAP envelope
*/
private function signSoapEnvelope(string $xml): string
{
try {
$signingService = new SigningService(
$xml,
file_get_contents($this->ssl_key),
file_get_contents($this->certificate)
);
return $signingService->sign();
} catch (\Exception $e) {
nlog("Error signing SOAP envelope: " . $e->getMessage());
throw $e;
}
}
public function send($xml): array public function send($xml): array
{ {
// Sign the SOAP envelope before sending
$signed_xml = $this->signSoapEnvelope($xml);
nlog("AEAT Request URL: " . $this->base_url);
nlog("Signed SOAP envelope size: " . strlen($signed_xml) . " bytes");
$response = Http::withHeaders([ $response = Http::withHeaders([
'Content-Type' => 'text/xml; charset=utf-8', 'Content-Type' => 'text/xml; charset=utf-8',
@ -74,11 +101,13 @@ class AeatClient
'verify' => false, 'verify' => false,
'timeout' => 30, 'timeout' => 30,
]) ])
->withBody($xml, 'text/xml') ->withBody($signed_xml, 'text/xml')
->post($this->base_url); ->post($this->base_url);
$success = $response->successful(); $success = $response->successful();
nlog("AEAT Response HTTP Code: " . $response->status());
$responseProcessor = new ResponseProcessor(); $responseProcessor = new ResponseProcessor();
$parsedResponse = $responseProcessor->processResponse($response->body()); $parsedResponse = $responseProcessor->processResponse($response->body());

View File

@ -957,6 +957,7 @@ class PdfMock
'$contact.first_name' => 'Geo', '$contact.first_name' => 'Geo',
'$company.vat_number' => 'vat number', '$company.vat_number' => 'vat number',
'$contact.signature' => '', '$contact.signature' => '',
'$verifactu_qr_code' => '',
'$product.tax_name1' => '', '$product.tax_name1' => '',
'$product.tax_name2' => '', '$product.tax_name2' => '',
'$product.tax_name3' => '', '$product.tax_name3' => '',

View File

@ -168,7 +168,7 @@ class TaxProvider
private function taxShippingAddress(): bool private function taxShippingAddress(): bool
{ {
if ($this->client->shipping_country_id == "840" && strlen($this->client->shipping_postal_code) > 3) { if ($this->client->shipping_country_id == "840" && strlen($this->client->shipping_postal_code ?? '') > 3) {
return true; return true;
} }

View File

@ -49,24 +49,24 @@ class ClientGatewayTokenTransformer extends EntityTransformer
{ {
$casted = new stdClass(); $casted = new stdClass();
if (property_exists($meta, 'exp_month')) { if ($exp_month = data_get($meta, 'exp_month')) {
$casted->exp_month = (string) $meta->exp_month; $casted->exp_month = (string) $exp_month;
} }
if (property_exists($meta, 'exp_year')) { if ($exp_year = data_get($meta, 'exp_year')) {
$casted->exp_year = (string) $meta->exp_year; $casted->exp_year = (string) $exp_year;
} }
if (property_exists($meta, 'brand')) { if ($brand = data_get($meta, 'brand')) {
$casted->brand = (string) $meta->brand; $casted->brand = (string) $brand;
} }
if (property_exists($meta, 'last4')) { if ($last4 = data_get($meta, 'last4')) {
$casted->last4 = (string) $meta->last4; $casted->last4 = (string) $last4;
} }
if (property_exists($meta, 'type')) { if ($type = data_get($meta, 'type')) {
$casted->type = (int) $meta->type; $casted->type = (int) $type;
} }
return $casted; return $casted;

View File

@ -17,6 +17,7 @@ use Illuminate\Support\Str;
trait WithSecureContext trait WithSecureContext
{ {
public const CONTEXT_UPDATE = 'secureContext.updated'; public const CONTEXT_UPDATE = 'secureContext.updated';
public const CONTEXT_READY = 'flow2.context.ready';
/** /**
* @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\ContainerExceptionInterface
@ -24,19 +25,9 @@ trait WithSecureContext
*/ */
public function getContext(): mixed public function getContext(): mixed
{ {
$context = \Illuminate\Support\Facades\Cache::get(session()->getId()) ?? [];
$context = \Illuminate\Support\Facades\Cache::get(session()->getId()) ?? false;
if (!$context) {
usleep(300000); //@monitor - inject delay to catch delays in cache updating
$context = \Illuminate\Support\Facades\Cache::get(session()->getId()) ?? [];
}
return $context; return $context;
} }
public function setContext(string $property, $value): array public function setContext(string $property, $value): array

View File

@ -220,14 +220,9 @@
"url": "https://github.com/beganovich/php-ansible" "url": "https://github.com/beganovich/php-ansible"
}, },
{ {
"type": "vcs", "type": "path",
"url": "https://github.com/turbo124/snappdf" "url": "../admin-api"
},
{
"type": "vcs",
"url": "https://github.com/invoiceninja/admin-api"
} }
], ],
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true "prefer-stable": true

240
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b2d1e12e4e351e18abb37f43b9da125f", "content-hash": "9a8f043b7584acdd2884d1ede7909e33",
"packages": [ "packages": [
{ {
"name": "afosto/yaac", "name": "afosto/yaac",
@ -61,16 +61,16 @@
}, },
{ {
"name": "apimatic/core", "name": "apimatic/core",
"version": "0.3.14", "version": "0.3.16",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/apimatic/core-lib-php.git", "url": "https://github.com/apimatic/core-lib-php.git",
"reference": "c3eaad6cf0c00b793ce6d9bee8b87176247da582" "reference": "ae4ab4ca26a41be41718f33c703d67b7a767c07b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/apimatic/core-lib-php/zipball/c3eaad6cf0c00b793ce6d9bee8b87176247da582", "url": "https://api.github.com/repos/apimatic/core-lib-php/zipball/ae4ab4ca26a41be41718f33c703d67b7a767c07b",
"reference": "c3eaad6cf0c00b793ce6d9bee8b87176247da582", "reference": "ae4ab4ca26a41be41718f33c703d67b7a767c07b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -82,7 +82,8 @@
"ext-libxml": "*", "ext-libxml": "*",
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"php-jsonpointer/php-jsonpointer": "^3.0.2", "php-jsonpointer/php-jsonpointer": "^3.0.2",
"psr/log": "^1.1.4 || ^2.0.0 || ^3.0.0" "psr/log": "^1.1.4 || ^2.0.0 || ^3.0.0",
"symfony/http-foundation": "^5.4 || ^6.0 || ^7.0 || ^8.0"
}, },
"require-dev": { "require-dev": {
"phan/phan": "5.4.5", "phan/phan": "5.4.5",
@ -109,9 +110,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/apimatic/core-lib-php/issues", "issues": "https://github.com/apimatic/core-lib-php/issues",
"source": "https://github.com/apimatic/core-lib-php/tree/0.3.14" "source": "https://github.com/apimatic/core-lib-php/tree/0.3.16"
}, },
"time": "2025-02-27T06:03:30+00:00" "time": "2025-11-25T04:42:27+00:00"
}, },
{ {
"name": "apimatic/core-interfaces", "name": "apimatic/core-interfaces",
@ -496,16 +497,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.363.0", "version": "3.363.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "b2f78a0787a73801957eb329048d52b4181e9660" "reference": "f8b5f125248daa8942144b4771c041a63ec41900"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b2f78a0787a73801957eb329048d52b4181e9660", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f8b5f125248daa8942144b4771c041a63ec41900",
"reference": "b2f78a0787a73801957eb329048d52b4181e9660", "reference": "f8b5f125248daa8942144b4771c041a63ec41900",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -587,9 +588,9 @@
"support": { "support": {
"forum": "https://github.com/aws/aws-sdk-php/discussions", "forum": "https://github.com/aws/aws-sdk-php/discussions",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.363.0" "source": "https://github.com/aws/aws-sdk-php/tree/3.363.2"
}, },
"time": "2025-11-21T19:41:10+00:00" "time": "2025-11-25T19:04:55+00:00"
}, },
{ {
"name": "babenkoivan/elastic-adapter", "name": "babenkoivan/elastic-adapter",
@ -1011,13 +1012,13 @@
"version": "dev-master", "version": "dev-master",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/turbo124/snappdf.git", "url": "https://github.com/beganovich/snappdf.git",
"reference": "73997afb327fb9cd99686368769d2f0562cb3a9f" "reference": "340e877e63ef98db82766a8d8a853d7759cf79fa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/turbo124/snappdf/zipball/73997afb327fb9cd99686368769d2f0562cb3a9f", "url": "https://api.github.com/repos/beganovich/snappdf/zipball/340e877e63ef98db82766a8d8a853d7759cf79fa",
"reference": "73997afb327fb9cd99686368769d2f0562cb3a9f", "reference": "340e877e63ef98db82766a8d8a853d7759cf79fa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1042,16 +1043,7 @@
"Beganovich\\Snappdf\\": "src/" "Beganovich\\Snappdf\\": "src/"
} }
}, },
"autoload-dev": { "notification-url": "https://packagist.org/downloads/",
"psr-4": {
"Test\\Snappdf\\": "tests/"
}
},
"scripts": {
"tests": [
"@php vendor/bin/phpunit --testdox"
]
},
"license": [ "license": [
"MIT" "MIT"
], ],
@ -1063,9 +1055,10 @@
], ],
"description": "Convert webpages or HTML into the PDF file using Chromium or Google Chrome.", "description": "Convert webpages or HTML into the PDF file using Chromium or Google Chrome.",
"support": { "support": {
"source": "https://github.com/turbo124/snappdf/tree/master" "issues": "https://github.com/beganovich/snappdf/issues",
"source": "https://github.com/beganovich/snappdf/tree/v5.0.1"
}, },
"time": "2025-01-04T00:35:22+00:00" "time": "2024-11-20T17:31:20+00:00"
}, },
{ {
"name": "braintree/braintree_php", "name": "braintree/braintree_php",
@ -1118,16 +1111,16 @@
}, },
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.14.0", "version": "0.14.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/brick/math.git", "url": "https://github.com/brick/math.git",
"reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2" "reference": "f05858549e5f9d7bb45875a75583240a38a281d0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0",
"reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", "reference": "f05858549e5f9d7bb45875a75583240a38a281d0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1166,7 +1159,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/brick/math/issues", "issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.0" "source": "https://github.com/brick/math/tree/0.14.1"
}, },
"funding": [ "funding": [
{ {
@ -1174,7 +1167,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-08-29T12:40:03+00:00" "time": "2025-11-24T14:40:29+00:00"
}, },
{ {
"name": "btcpayserver/btcpayserver-greenfield-php", "name": "btcpayserver/btcpayserver-greenfield-php",
@ -3035,16 +3028,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.420.1", "version": "v0.421.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "f1200dbf48d02dcfa36c5771f4dbc0433655a7ab" "reference": "d84e7301a52405677807564dab6b1a112dfd03bd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/f1200dbf48d02dcfa36c5771f4dbc0433655a7ab", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/d84e7301a52405677807564dab6b1a112dfd03bd",
"reference": "f1200dbf48d02dcfa36c5771f4dbc0433655a7ab", "reference": "d84e7301a52405677807564dab6b1a112dfd03bd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3073,9 +3066,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.420.1" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.421.0"
}, },
"time": "2025-11-17T01:06:15+00:00" "time": "2025-11-23T01:06:22+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -4835,16 +4828,16 @@
}, },
{ {
"name": "josemmo/facturae-php", "name": "josemmo/facturae-php",
"version": "v1.8.3", "version": "v1.8.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/josemmo/Facturae-PHP.git", "url": "https://github.com/josemmo/Facturae-PHP.git",
"reference": "f4099c9479fb770bd03f9c559c054c0fea86fa44" "reference": "21283e460d2a24d58c06454596fcaecc63c8f123"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/josemmo/Facturae-PHP/zipball/f4099c9479fb770bd03f9c559c054c0fea86fa44", "url": "https://api.github.com/repos/josemmo/Facturae-PHP/zipball/21283e460d2a24d58c06454596fcaecc63c8f123",
"reference": "f4099c9479fb770bd03f9c559c054c0fea86fa44", "reference": "21283e460d2a24d58c06454596fcaecc63c8f123",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4886,9 +4879,15 @@
], ],
"support": { "support": {
"issues": "https://github.com/josemmo/Facturae-PHP/issues", "issues": "https://github.com/josemmo/Facturae-PHP/issues",
"source": "https://github.com/josemmo/Facturae-PHP/tree/v1.8.3" "source": "https://github.com/josemmo/Facturae-PHP/tree/v1.8.4"
}, },
"time": "2025-06-22T08:30:43+00:00" "funding": [
{
"url": "https://github.com/josemmo",
"type": "github"
}
],
"time": "2025-11-24T14:05:18+00:00"
}, },
{ {
"name": "kmukku/php-iso11649", "name": "kmukku/php-iso11649",
@ -5079,16 +5078,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v11.46.1", "version": "v11.46.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "5fd457f807570a962a53b403b1346efe4cc80bb8" "reference": "d6b16e72a98c2ad3257ec6b3f1f00532c3b1c2fc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/5fd457f807570a962a53b403b1346efe4cc80bb8", "url": "https://api.github.com/repos/laravel/framework/zipball/d6b16e72a98c2ad3257ec6b3f1f00532c3b1c2fc",
"reference": "5fd457f807570a962a53b403b1346efe4cc80bb8", "reference": "d6b16e72a98c2ad3257ec6b3f1f00532c3b1c2fc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5290,7 +5289,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-09-30T14:51:32+00:00" "time": "2025-11-25T19:02:06+00:00"
}, },
{ {
"name": "laravel/octane", "name": "laravel/octane",
@ -5384,16 +5383,16 @@
}, },
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
"version": "v0.3.7", "version": "v0.3.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/prompts.git", "url": "https://github.com/laravel/prompts.git",
"reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc" "reference": "096748cdfb81988f60090bbb839ce3205ace0d35"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/a1891d362714bc40c8d23b0b1d7090f022ea27cc", "url": "https://api.github.com/repos/laravel/prompts/zipball/096748cdfb81988f60090bbb839ce3205ace0d35",
"reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc", "reference": "096748cdfb81988f60090bbb839ce3205ace0d35",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5409,7 +5408,7 @@
"require-dev": { "require-dev": {
"illuminate/collections": "^10.0|^11.0|^12.0", "illuminate/collections": "^10.0|^11.0|^12.0",
"mockery/mockery": "^1.5", "mockery/mockery": "^1.5",
"pestphp/pest": "^2.3|^3.4", "pestphp/pest": "^2.3|^3.4|^4.0",
"phpstan/phpstan": "^1.12.28", "phpstan/phpstan": "^1.12.28",
"phpstan/phpstan-mockery": "^1.1.3" "phpstan/phpstan-mockery": "^1.1.3"
}, },
@ -5437,22 +5436,22 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.", "description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": { "support": {
"issues": "https://github.com/laravel/prompts/issues", "issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.7" "source": "https://github.com/laravel/prompts/tree/v0.3.8"
}, },
"time": "2025-09-19T13:47:56+00:00" "time": "2025-11-21T20:52:52+00:00"
}, },
{ {
"name": "laravel/scout", "name": "laravel/scout",
"version": "v10.22.0", "version": "v10.22.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/scout.git", "url": "https://github.com/laravel/scout.git",
"reference": "5f629471eed80c97a1fa2f12a2fb213c7e09f729" "reference": "13ed8e0eeaddd894bf360b85cb873980de19dbaf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/scout/zipball/5f629471eed80c97a1fa2f12a2fb213c7e09f729", "url": "https://api.github.com/repos/laravel/scout/zipball/13ed8e0eeaddd894bf360b85cb873980de19dbaf",
"reference": "5f629471eed80c97a1fa2f12a2fb213c7e09f729", "reference": "13ed8e0eeaddd894bf360b85cb873980de19dbaf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5473,10 +5472,9 @@
"algolia/algoliasearch-client-php": "^3.2|^4.0", "algolia/algoliasearch-client-php": "^3.2|^4.0",
"meilisearch/meilisearch-php": "^1.0", "meilisearch/meilisearch-php": "^1.0",
"mockery/mockery": "^1.0", "mockery/mockery": "^1.0",
"orchestra/testbench": "^7.31|^8.11|^9.0|^10.0", "orchestra/testbench": "^7.31|^8.36|^9.15|^10.8",
"php-http/guzzle7-adapter": "^1.0", "php-http/guzzle7-adapter": "^1.0",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.3|^10.4|^11.5",
"typesense/typesense-php": "^4.9.3" "typesense/typesense-php": "^4.9.3"
}, },
"suggest": { "suggest": {
@ -5520,20 +5518,20 @@
"issues": "https://github.com/laravel/scout/issues", "issues": "https://github.com/laravel/scout/issues",
"source": "https://github.com/laravel/scout" "source": "https://github.com/laravel/scout"
}, },
"time": "2025-11-12T17:00:55+00:00" "time": "2025-11-25T15:19:35+00:00"
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v2.0.6", "version": "v2.0.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "038ce42edee619599a1debb7e81d7b3759492819" "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
"reference": "038ce42edee619599a1debb7e81d7b3759492819", "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5542,7 +5540,7 @@
"require-dev": { "require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0", "illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0", "nesbot/carbon": "^2.67|^3.0",
"pestphp/pest": "^2.36|^3.0", "pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0", "phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0" "symfony/var-dumper": "^6.2.0|^7.0.0"
}, },
@ -5581,20 +5579,20 @@
"issues": "https://github.com/laravel/serializable-closure/issues", "issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure" "source": "https://github.com/laravel/serializable-closure"
}, },
"time": "2025-10-09T13:42:30+00:00" "time": "2025-11-21T20:52:36+00:00"
}, },
{ {
"name": "laravel/slack-notification-channel", "name": "laravel/slack-notification-channel",
"version": "v3.6.0", "version": "v3.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/slack-notification-channel.git", "url": "https://github.com/laravel/slack-notification-channel.git",
"reference": "642677a57490eebccb7e9fb666f5a5379c6e3459" "reference": "414aec57b487bfbac7f90fc30f50a2f0a2df4caa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/642677a57490eebccb7e9fb666f5a5379c6e3459", "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/414aec57b487bfbac7f90fc30f50a2f0a2df4caa",
"reference": "642677a57490eebccb7e9fb666f5a5379c6e3459", "reference": "414aec57b487bfbac7f90fc30f50a2f0a2df4caa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5644,22 +5642,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/laravel/slack-notification-channel/issues", "issues": "https://github.com/laravel/slack-notification-channel/issues",
"source": "https://github.com/laravel/slack-notification-channel/tree/v3.6.0" "source": "https://github.com/laravel/slack-notification-channel/tree/v3.7.0"
}, },
"time": "2025-06-26T16:51:38+00:00" "time": "2025-11-20T17:26:07+00:00"
}, },
{ {
"name": "laravel/socialite", "name": "laravel/socialite",
"version": "v5.23.1", "version": "v5.23.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/socialite.git", "url": "https://github.com/laravel/socialite.git",
"reference": "83d7523c97c1101d288126948947891319eef800" "reference": "41e65d53762d33d617bf0253330d672cb95e624b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/83d7523c97c1101d288126948947891319eef800", "url": "https://api.github.com/repos/laravel/socialite/zipball/41e65d53762d33d617bf0253330d672cb95e624b",
"reference": "83d7523c97c1101d288126948947891319eef800", "reference": "41e65d53762d33d617bf0253330d672cb95e624b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5675,9 +5673,9 @@
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^1.0", "mockery/mockery": "^1.0",
"orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", "orchestra/testbench": "^4.18|^5.20|^6.47|^7.55|^8.36|^9.15|^10.8",
"phpstan/phpstan": "^1.12.23", "phpstan/phpstan": "^1.12.23",
"phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5" "phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5|^12.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -5718,20 +5716,20 @@
"issues": "https://github.com/laravel/socialite/issues", "issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite" "source": "https://github.com/laravel/socialite"
}, },
"time": "2025-10-27T15:36:41+00:00" "time": "2025-11-21T14:00:38+00:00"
}, },
{ {
"name": "laravel/tinker", "name": "laravel/tinker",
"version": "v2.10.1", "version": "v2.10.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/tinker.git", "url": "https://github.com/laravel/tinker.git",
"reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" "reference": "3bcb5f62d6f837e0f093a601e26badafb127bd4c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", "url": "https://api.github.com/repos/laravel/tinker/zipball/3bcb5f62d6f837e0f093a601e26badafb127bd4c",
"reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", "reference": "3bcb5f62d6f837e0f093a601e26badafb127bd4c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5782,9 +5780,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/laravel/tinker/issues", "issues": "https://github.com/laravel/tinker/issues",
"source": "https://github.com/laravel/tinker/tree/v2.10.1" "source": "https://github.com/laravel/tinker/tree/v2.10.2"
}, },
"time": "2025-01-27T14:24:01+00:00" "time": "2025-11-20T16:29:12+00:00"
}, },
{ {
"name": "laravel/ui", "name": "laravel/ui",
@ -8528,16 +8526,16 @@
}, },
{ {
"name": "open-telemetry/api", "name": "open-telemetry/api",
"version": "1.7.0", "version": "1.7.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/opentelemetry-php/api.git", "url": "https://github.com/opentelemetry-php/api.git",
"reference": "610b79ad9d6d97e8368bcb6c4d42394fbb87b522" "reference": "45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/opentelemetry-php/api/zipball/610b79ad9d6d97e8368bcb6c4d42394fbb87b522", "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4",
"reference": "610b79ad9d6d97e8368bcb6c4d42394fbb87b522", "reference": "45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -8557,7 +8555,7 @@
] ]
}, },
"branch-alias": { "branch-alias": {
"dev-main": "1.7.x-dev" "dev-main": "1.8.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -8590,11 +8588,11 @@
], ],
"support": { "support": {
"chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V", "chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V",
"docs": "https://opentelemetry.io/docs/php", "docs": "https://opentelemetry.io/docs/languages/php",
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php" "source": "https://github.com/open-telemetry/opentelemetry-php"
}, },
"time": "2025-10-02T23:44:28+00:00" "time": "2025-10-19T10:49:48+00:00"
}, },
{ {
"name": "open-telemetry/context", "name": "open-telemetry/context",
@ -9480,16 +9478,16 @@
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
"version": "1.11.1", "version": "1.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git", "url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "f626740b38009078de0dc8b2b9dc4e7f749c6eba" "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/f626740b38009078de0dc8b2b9dc4e7f749c6eba", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195",
"reference": "f626740b38009078de0dc8b2b9dc4e7f749c6eba", "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9532,22 +9530,22 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues", "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.11.1" "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0"
}, },
"time": "2025-11-21T11:31:57+00:00" "time": "2025-11-21T15:09:14+00:00"
}, },
{ {
"name": "phpoffice/phpspreadsheet", "name": "phpoffice/phpspreadsheet",
"version": "2.4.1", "version": "2.4.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "096ae6faf94b49b2cf53e92a0073133c941e1f57" "reference": "931ad61fb2c229063fc4e7e665fb52b87249cc56"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/096ae6faf94b49b2cf53e92a0073133c941e1f57", "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/931ad61fb2c229063fc4e7e665fb52b87249cc56",
"reference": "096ae6faf94b49b2cf53e92a0073133c941e1f57", "reference": "931ad61fb2c229063fc4e7e665fb52b87249cc56",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9568,7 +9566,7 @@
"maennchen/zipstream-php": "^2.1 || ^3.0", "maennchen/zipstream-php": "^2.1 || ^3.0",
"markbaker/complex": "^3.0", "markbaker/complex": "^3.0",
"markbaker/matrix": "^3.0", "markbaker/matrix": "^3.0",
"php": "^8.1", "php": ">=8.1.0 <8.6.0",
"psr/http-client": "^1.0", "psr/http-client": "^1.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0" "psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
@ -9577,7 +9575,7 @@
"dealerdirect/phpcodesniffer-composer-installer": "dev-main", "dealerdirect/phpcodesniffer-composer-installer": "dev-main",
"dompdf/dompdf": "^2.0 || ^3.0", "dompdf/dompdf": "^2.0 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.2", "friendsofphp/php-cs-fixer": "^3.2",
"mitoteam/jpgraph": "^10.3", "mitoteam/jpgraph": "^10.5",
"mpdf/mpdf": "^8.1.1", "mpdf/mpdf": "^8.1.1",
"phpcompatibility/php-compatibility": "^9.3", "phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^1.1", "phpstan/phpstan": "^1.1",
@ -9588,7 +9586,7 @@
}, },
"suggest": { "suggest": {
"dompdf/dompdf": "Option for rendering PDF with PDF Writer", "dompdf/dompdf": "Option for rendering PDF with PDF Writer",
"ext-intl": "PHP Internationalization Functions", "ext-intl": "PHP Internationalization Functions, required for NumberFormatter Wizard",
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
"mpdf/mpdf": "Option for rendering PDF with PDF Writer", "mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
@ -9637,9 +9635,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.4.1" "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.4.2"
}, },
"time": "2025-09-01T18:41:37+00:00" "time": "2025-11-24T15:59:19+00:00"
}, },
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
@ -11532,16 +11530,16 @@
}, },
{ {
"name": "smalot/pdfparser", "name": "smalot/pdfparser",
"version": "v2.12.1", "version": "v2.12.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/smalot/pdfparser.git", "url": "https://github.com/smalot/pdfparser.git",
"reference": "98d31ba34ef5b5a98897ef4b6c3925d502ea53b1" "reference": "370b7e983fafecb787a9bcfd73baab8038212ad1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/smalot/pdfparser/zipball/98d31ba34ef5b5a98897ef4b6c3925d502ea53b1", "url": "https://api.github.com/repos/smalot/pdfparser/zipball/370b7e983fafecb787a9bcfd73baab8038212ad1",
"reference": "98d31ba34ef5b5a98897ef4b6c3925d502ea53b1", "reference": "370b7e983fafecb787a9bcfd73baab8038212ad1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11577,9 +11575,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/smalot/pdfparser/issues", "issues": "https://github.com/smalot/pdfparser/issues",
"source": "https://github.com/smalot/pdfparser/tree/v2.12.1" "source": "https://github.com/smalot/pdfparser/tree/v2.12.2"
}, },
"time": "2025-07-31T06:19:56+00:00" "time": "2025-09-04T08:49:09+00:00"
}, },
{ {
"name": "socialiteproviders/apple", "name": "socialiteproviders/apple",
@ -18353,7 +18351,7 @@
}, },
{ {
"name": "illuminate/json-schema", "name": "illuminate/json-schema",
"version": "v12.39.0", "version": "v12.40.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/json-schema.git", "url": "https://github.com/illuminate/json-schema.git",

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.12.34'), 'app_version' => env('APP_VERSION', '5.12.35'),
'app_tag' => env('APP_TAG', '5.12.34'), 'app_tag' => env('APP_TAG', '5.12.35'),
'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),

File diff suppressed because one or more lines are too long

View File

@ -385,7 +385,7 @@
"src": "resources/js/setup/setup.js" "src": "resources/js/setup/setup.js"
}, },
"resources/sass/app.scss": { "resources/sass/app.scss": {
"file": "assets/app-9454bf28.css", "file": "assets/app-55cdafc9.css",
"isEntry": true, "isEntry": true,
"src": "resources/sass/app.scss" "src": "resources/sass/app.scss"
} }

View File

@ -1,4 +1,22 @@
<div class="w-full"> <div class="w-full">
@if(!$isReady)
<div class="rounded-lg border bg-card bg-white text-card-foreground shadow-sm overflow-hidden">
<div class="pt-6 px-6 flex flex-row items-start bg-muted/50">
<div class="grid gap-0.5">
<h3 class="font-semibold tracking-tight text-lg">{{ ctrans('texts.invoices') }}</h3>
</div>
</div>
<div class="p-6 flex items-center justify-center min-h-32">
<div class="flex flex-col items-center gap-2">
<svg class="animate-spin h-8 w-8 text-blue" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<p class="text-sm text-muted-foreground">{{ ctrans('texts.loading') }}</p>
</div>
</div>
</div>
@else
<div class="rounded-lg border bg-card bg-white text-card-foreground shadow-sm overflow-hidden" x-chunk="An order details card with order details, shipping information, customer information and payment information."> <div class="rounded-lg border bg-card bg-white text-card-foreground shadow-sm overflow-hidden" x-chunk="An order details card with order details, shipping information, customer information and payment information.">
<div class="pt-6 px-6 flex flex-row items-start bg-muted/50"> <div class="pt-6 px-6 flex flex-row items-start bg-muted/50">
<div class="grid gap-0.5"> <div class="grid gap-0.5">
@ -105,4 +123,5 @@
</div> </div>
</div> </div>
</div> </div>
@endif
</div> </div>

View File

@ -1,6 +1,6 @@
@extends('portal.ninja2020.layout.clean') @section('meta_title', @extends('portal.ninja2020.layout.clean') @section('meta_title',
ctrans('texts.preferences')) @section('body') ctrans('texts.preferences')) @section('body')
<div class="flex h-screen"> <div class="flex h-screen" x-data="{ modalOpen: false, actionType: '' }">
<div class="m-auto md:w-1/3 lg:w-1/5"> <div class="m-auto md:w-1/3 lg:w-1/5">
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<img <img
@ -12,15 +12,16 @@ ctrans('texts.preferences')) @section('body')
{{ ctrans('texts.email_preferences') }} {{ ctrans('texts.email_preferences') }}
</h1> </h1>
<form class="my-4 flex flex-col items-center text-center" method="post"> <form id="preferencesForm" class="my-4 flex flex-col items-center text-center" method="post">
@csrf @method('put') @csrf @method('put')
<input type="hidden" name="action" id="actionInput">
@if($receive_emails) @if($receive_emails)
<p>{{ ctrans('texts.subscribe_help') }}</p> <p>{{ ctrans('texts.subscribe_help') }}</p>
<button <button
name="action" type="button"
value="unsubscribe" @click="modalOpen = true; actionType = 'unsubscribe'"
class="button button-secondary mt-4" class="button button-secondary mt-4"
> >
{{ ctrans('texts.unsubscribe') }} {{ ctrans('texts.unsubscribe') }}
@ -29,8 +30,8 @@ ctrans('texts.preferences')) @section('body')
<p>{{ ctrans('texts.unsubscribe_help') }}</p> <p>{{ ctrans('texts.unsubscribe_help') }}</p>
<button <button
name="action" type="button"
value="subscribe" @click="modalOpen = true; actionType = 'subscribe'"
class="button button-secondary mt-4" class="button button-secondary mt-4"
> >
{{ ctrans('texts.subscribe') }} {{ ctrans('texts.subscribe') }}
@ -39,5 +40,54 @@ ctrans('texts.preferences')) @section('body')
</form> </form>
</div> </div>
</div> </div>
<!-- Confirmation Modal -->
<div x-show="modalOpen" class="fixed bottom-0 inset-x-0 px-4 pb-4 sm:inset-0 sm:flex sm:items-center sm:justify-center"
style="display:none;">
<div x-show="modalOpen" x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
class="fixed inset-0 transition-opacity" style="display:none;">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<div x-show="modalOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="bg-white rounded-lg px-4 pt-5 pb-4 overflow-hidden shadow-xl transform transition-all sm:max-w-lg sm:w-full sm:p-6">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
<svg class="h-6 w-6 text-blue-600" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
<span x-show="actionType === 'unsubscribe'">{{ ctrans('texts.confirm') }}</span>
<span x-show="actionType === 'subscribe'">{{ ctrans('texts.confirm') }}</span>
</h3>
<div class="mt-2">
<p class="text-sm leading-5 text-gray-500">
<span>{{ ctrans('texts.are_you_sure') }}</span>
</p>
</div>
</div>
</div>
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button @click="document.getElementById('actionInput').value = actionType; document.getElementById('preferencesForm').submit();"
type="button" class="button button-danger sm:ml-3 sm:w-auto">
<span x-show="actionType === 'unsubscribe'">{{ ctrans('texts.unsubscribe') }}</span>
<span x-show="actionType === 'subscribe'">{{ ctrans('texts.subscribe') }}</span>
</button>
<button @click="modalOpen = false" type="button" class="button button-secondary button-block sm:mt-0 sm:w-auto sm:ml-3">
{{ ctrans('texts.cancel') }}
</button>
</div>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -98,6 +98,32 @@ class ClientGatewayTokenApiTest extends TestCase
} }
public function testCompanyGatewaySettableOnTokenAndDefaultIsTrue()
{
$data = [
'client_id' => $this->client->hashed_id,
'company_gateway_id' => $this->cg->hashed_id,
'gateway_type_id' => GatewayType::CREDIT_CARD,
'token' => 'tokey',
'gateway_customer_reference' => 'reffy',
'meta' => '{}',
'is_default' => true,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/client_gateway_tokens', $data);
$response->assertStatus(200);
$arr = $response->json();
$t1 = $arr['data']['id'];
$this->assertTrue($arr['data']['is_default']);
}
public function testCompanyGatewaySettableOnToken() public function testCompanyGatewaySettableOnToken()
{ {