Compare commits
2 Commits
e7bf2f887a
...
6b06028771
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b06028771 | |||
| 0aa423e90e |
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Domains\Sale\Controllers\AdminApp;
|
namespace App\Domains\Sale\Controllers\AdminApp;
|
||||||
|
|
||||||
use App\Domains\Sale\Requests\AdminAppSaleIndexRequest;
|
use App\Domains\Sale\Requests\AdminAppSaleIndexRequest;
|
||||||
|
use App\Domains\Sale\Requests\AdminAppSaleModificationPdfRequest;
|
||||||
|
use App\Domains\Sale\Requests\AdminAppSalePdfRequest;
|
||||||
use App\Domains\Sale\Resources\AdminApp\SaleDetailResource;
|
use App\Domains\Sale\Resources\AdminApp\SaleDetailResource;
|
||||||
use App\Domains\Sale\Resources\AdminApp\SaleModificationResource;
|
use App\Domains\Sale\Resources\AdminApp\SaleModificationResource;
|
||||||
use App\Domains\Sale\Resources\AdminApp\SaleResource;
|
use App\Domains\Sale\Resources\AdminApp\SaleResource;
|
||||||
@@ -71,23 +73,25 @@ class SaleController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function downloadPdf(AdminAppSaleIndexRequest $request): Response
|
public function downloadPdf(AdminAppSalePdfRequest $request): Response
|
||||||
{
|
{
|
||||||
$tenant = $request->user()->tenant()->firstOrFail();
|
$tenant = $request->user()->tenant()->firstOrFail();
|
||||||
|
|
||||||
return $this->salePdfService->downloadSales(
|
return $this->salePdfService->downloadSales(
|
||||||
$tenant,
|
$tenant,
|
||||||
$this->saleService->salesForExport($tenant, $request->validated()),
|
$this->saleService->salesForExport($tenant, $request->validated()),
|
||||||
|
$request->validated('timezone'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function downloadModificationsPdf(Request $request): Response
|
public function downloadModificationsPdf(AdminAppSaleModificationPdfRequest $request): Response
|
||||||
{
|
{
|
||||||
$tenant = $request->user()->tenant()->firstOrFail();
|
$tenant = $request->user()->tenant()->firstOrFail();
|
||||||
|
|
||||||
return $this->salePdfService->downloadModifications(
|
return $this->salePdfService->downloadModifications(
|
||||||
$tenant,
|
$tenant,
|
||||||
$this->saleService->modificationsForExport($tenant),
|
$this->saleService->modificationsForExport($tenant),
|
||||||
|
$request->validated('timezone'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Sale\Requests;
|
||||||
|
|
||||||
|
use App\Domains\Shared\Rules\ValidTimezone;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class AdminAppSaleModificationPdfRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<string, list<string>> */
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'timezone' => ['required', 'string', new ValidTimezone],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Domains/Sale/Requests/AdminAppSalePdfRequest.php
Normal file
17
app/Domains/Sale/Requests/AdminAppSalePdfRequest.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Sale\Requests;
|
||||||
|
|
||||||
|
use App\Domains\Shared\Rules\ValidTimezone;
|
||||||
|
|
||||||
|
class AdminAppSalePdfRequest extends AdminAppSaleIndexRequest
|
||||||
|
{
|
||||||
|
/** @return array<string, list<string>> */
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
...parent::rules(),
|
||||||
|
'timezone' => ['required', 'string', new ValidTimezone],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,14 @@ use Illuminate\Support\Collection;
|
|||||||
class AdminAppSalePdfService
|
class AdminAppSalePdfService
|
||||||
{
|
{
|
||||||
/** @param Collection<int, Purchase> $sales */
|
/** @param Collection<int, Purchase> $sales */
|
||||||
public function downloadSales(Tenant $tenant, Collection $sales): Response
|
public function downloadSales(Tenant $tenant, Collection $sales, string $timeZone): Response
|
||||||
{
|
{
|
||||||
|
$generatedAt = now();
|
||||||
$pdf = Pdf::loadView('pdf.adminapp.sales', [
|
$pdf = Pdf::loadView('pdf.adminapp.sales', [
|
||||||
'tenant' => $tenant,
|
'tenant' => $tenant,
|
||||||
'sales' => $sales,
|
'sales' => $sales,
|
||||||
'generatedAt' => now(),
|
'generatedAt' => $generatedAt,
|
||||||
|
'timeZone' => $timeZone,
|
||||||
'confirmedSalesTotal' => number_format(
|
'confirmedSalesTotal' => number_format(
|
||||||
(float) $sales->where('status', Purchase::STATUS_PAID)->sum('total'),
|
(float) $sales->where('status', Purchase::STATUS_PAID)->sum('total'),
|
||||||
2,
|
2,
|
||||||
@@ -30,23 +32,30 @@ class AdminAppSalePdfService
|
|||||||
$this->addPageNumbers($pdf);
|
$this->addPageNumbers($pdf);
|
||||||
|
|
||||||
return $pdf->download(
|
return $pdf->download(
|
||||||
'ventas_'.$tenant->codigo.'_'.now()->format('Ymd_His').'.pdf'
|
'ventas_'.$tenant->codigo.'_'
|
||||||
|
.$generatedAt->copy()->timezone($timeZone)->format('Ymd_His').'.pdf'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param Collection<int, ValueChange> $modifications */
|
/** @param Collection<int, ValueChange> $modifications */
|
||||||
public function downloadModifications(Tenant $tenant, Collection $modifications): Response
|
public function downloadModifications(
|
||||||
{
|
Tenant $tenant,
|
||||||
|
Collection $modifications,
|
||||||
|
string $timeZone,
|
||||||
|
): Response {
|
||||||
|
$generatedAt = now();
|
||||||
$pdf = Pdf::loadView('pdf.adminapp.sale-modifications', [
|
$pdf = Pdf::loadView('pdf.adminapp.sale-modifications', [
|
||||||
'tenant' => $tenant,
|
'tenant' => $tenant,
|
||||||
'modifications' => $modifications,
|
'modifications' => $modifications,
|
||||||
'generatedAt' => now(),
|
'generatedAt' => $generatedAt,
|
||||||
|
'timeZone' => $timeZone,
|
||||||
])->setPaper('a4', 'landscape');
|
])->setPaper('a4', 'landscape');
|
||||||
|
|
||||||
$this->addPageNumbers($pdf);
|
$this->addPageNumbers($pdf);
|
||||||
|
|
||||||
return $pdf->download(
|
return $pdf->download(
|
||||||
'historial_modificaciones_'.$tenant->codigo.'_'.now()->format('Ymd_His').'.pdf'
|
'historial_modificaciones_'.$tenant->codigo.'_'
|
||||||
|
.$generatedAt->copy()->timezone($timeZone)->format('Ymd_His').'.pdf'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
app/Domains/Shared/Rules/ValidTimezone.php
Normal file
24
app/Domains/Shared/Rules/ValidTimezone.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Shared\Rules;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use DateTimeZone;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
|
class ValidTimezone implements ValidationRule
|
||||||
|
{
|
||||||
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
|
{
|
||||||
|
if (! is_string($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new DateTimeZone($value);
|
||||||
|
} catch (Exception) {
|
||||||
|
$fail(__('validation.timezone'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ return [
|
|||||||
'required_with' => 'The :attribute field is required when :values is present.',
|
'required_with' => 'The :attribute field is required when :values is present.',
|
||||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||||
'string' => 'The :attribute must be a string.',
|
'string' => 'The :attribute must be a string.',
|
||||||
|
'timezone' => 'The timezone sent by the browser is invalid.',
|
||||||
'unique' => 'The :attribute has already been taken.',
|
'unique' => 'The :attribute has already been taken.',
|
||||||
'url' => 'The :attribute must be a valid URL.',
|
'url' => 'The :attribute must be a valid URL.',
|
||||||
'uuid' => 'The :attribute must be a valid UUID.',
|
'uuid' => 'The :attribute must be a valid UUID.',
|
||||||
@@ -52,6 +53,7 @@ return [
|
|||||||
'password_confirmation' => 'password confirmation',
|
'password_confirmation' => 'password confirmation',
|
||||||
'telefono' => 'phone number',
|
'telefono' => 'phone number',
|
||||||
'tenant_codigo' => 'tenant',
|
'tenant_codigo' => 'tenant',
|
||||||
|
'timezone' => 'timezone',
|
||||||
'variant_id' => 'variant',
|
'variant_id' => 'variant',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ return [
|
|||||||
'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.',
|
'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.',
|
||||||
'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.',
|
'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.',
|
||||||
'string' => ':Attribute debe ser texto.',
|
'string' => ':Attribute debe ser texto.',
|
||||||
|
'timezone' => 'La zona horaria enviada por el navegador no es válida.',
|
||||||
'unique' => 'El :attribute ya está en uso.',
|
'unique' => 'El :attribute ya está en uso.',
|
||||||
'url' => ':Attribute debe ser una URL válida.',
|
'url' => ':Attribute debe ser una URL válida.',
|
||||||
'uuid' => ':Attribute debe ser un UUID válido.',
|
'uuid' => ':Attribute debe ser un UUID válido.',
|
||||||
@@ -52,6 +53,7 @@ return [
|
|||||||
'password_confirmation' => 'confirmación de contraseña',
|
'password_confirmation' => 'confirmación de contraseña',
|
||||||
'telefono' => 'teléfono',
|
'telefono' => 'teléfono',
|
||||||
'tenant_codigo' => 'tenant',
|
'tenant_codigo' => 'tenant',
|
||||||
|
'timezone' => 'zona horaria',
|
||||||
'variant_id' => 'variante',
|
'variant_id' => 'variante',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Historial de modificaciones de ventas</h1>
|
<h1>Historial de modificaciones de ventas</h1>
|
||||||
<p class="subtitle">{{ $tenant->nombre }} · Generado el {{ $generatedAt->format('d/m/Y H:i') }}</p>
|
<p class="subtitle">{{ $tenant->nombre }} · Generado el {{ $generatedAt->copy()->timezone($timeZone)->format('d/m/Y H:i') }}</p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
@forelse ($modifications as $modification)
|
@forelse ($modifications as $modification)
|
||||||
@php($sale = $modification->trackable)
|
@php($sale = $modification->trackable)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $modification->changed_at->format('d/m/Y') }}</td>
|
<td>{{ $modification->changed_at->copy()->timezone($timeZone)->format('d/m/Y') }}</td>
|
||||||
<td>{{ $modification->changed_at->format('H:i:s') }}</td>
|
<td>{{ $modification->changed_at->copy()->timezone($timeZone)->format('H:i:s') }}</td>
|
||||||
<td>#{{ $modification->trackable_id }}</td>
|
<td>#{{ $modification->trackable_id }}</td>
|
||||||
<td>{{ $sale?->nombre_apellido ?: 'Sin nombre' }}</td>
|
<td>{{ $sale?->nombre_apellido ?: 'Sin nombre' }}</td>
|
||||||
<td>{{ $modification->attribute }}</td>
|
<td>{{ $modification->attribute }}</td>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Historial de ventas</h1>
|
<h1>Historial de ventas</h1>
|
||||||
<p class="subtitle">{{ $tenant->nombre }} · Generado el {{ $generatedAt->format('d/m/Y H:i') }}</p>
|
<p class="subtitle">{{ $tenant->nombre }} · Generado el {{ $generatedAt->copy()->timezone($timeZone)->format('d/m/Y H:i') }}</p>
|
||||||
|
|
||||||
<div class="summary">
|
<div class="summary">
|
||||||
Total de ventas confirmadas en este reporte: <strong>${{ number_format((float) $confirmedSalesTotal, 2, ',', '.') }}</strong>
|
Total de ventas confirmadas en este reporte: <strong>${{ number_format((float) $confirmedSalesTotal, 2, ',', '.') }}</strong>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
@forelse ($sales as $sale)
|
@forelse ($sales as $sale)
|
||||||
<tr>
|
<tr>
|
||||||
<td>#{{ $sale->id }}</td>
|
<td>#{{ $sale->id }}</td>
|
||||||
<td>{{ $sale->created_at?->format('d/m/Y H:i') ?? '-' }}</td>
|
<td>{{ $sale->created_at?->copy()->timezone($timeZone)->format('d/m/Y H:i') ?? '-' }}</td>
|
||||||
<td>{{ $sale->nombre_apellido ?: 'Sin nombre' }}</td>
|
<td>{{ $sale->nombre_apellido ?: 'Sin nombre' }}</td>
|
||||||
<td class="center">{{ (int) ($sale->quantity ?? 0) }}</td>
|
<td class="center">{{ (int) ($sale->quantity ?? 0) }}</td>
|
||||||
<td>{{ match ($sale->status) {
|
<td>{{ match ($sale->status) {
|
||||||
|
|||||||
55
tests/Unit/Sale/AdminAppSalePdfRequestTest.php
Normal file
55
tests/Unit/Sale/AdminAppSalePdfRequestTest.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Sale;
|
||||||
|
|
||||||
|
use App\Domains\Sale\Requests\AdminAppSaleModificationPdfRequest;
|
||||||
|
use App\Domains\Sale\Requests\AdminAppSalePdfRequest;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AdminAppSalePdfRequestTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_pdf_requests_accept_php_timezone_identifiers_including_browser_aliases(): void
|
||||||
|
{
|
||||||
|
$requests = [
|
||||||
|
new AdminAppSalePdfRequest,
|
||||||
|
new AdminAppSaleModificationPdfRequest,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
$this->assertTrue(Validator::make([
|
||||||
|
'timezone' => 'America/Argentina/Buenos_Aires',
|
||||||
|
], $request->rules())->passes());
|
||||||
|
|
||||||
|
$this->assertTrue(Validator::make([
|
||||||
|
'timezone' => 'America/Buenos_Aires',
|
||||||
|
], $request->rules())->passes());
|
||||||
|
|
||||||
|
$this->assertFalse(Validator::make([
|
||||||
|
'timezone' => 'Invalid/Timezone',
|
||||||
|
], $request->rules())->passes());
|
||||||
|
|
||||||
|
$this->assertFalse(Validator::make([], $request->rules())->passes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_invalid_timezone_message_uses_the_application_locale(): void
|
||||||
|
{
|
||||||
|
$request = new AdminAppSalePdfRequest;
|
||||||
|
|
||||||
|
App::setLocale('es');
|
||||||
|
$spanishValidator = Validator::make(['timezone' => 'Invalid/Timezone'], $request->rules());
|
||||||
|
$this->assertSame(
|
||||||
|
'La zona horaria enviada por el navegador no es válida.',
|
||||||
|
$spanishValidator->errors()->first('timezone'),
|
||||||
|
);
|
||||||
|
|
||||||
|
App::setLocale('en');
|
||||||
|
$englishValidator = Validator::make(['timezone' => 'Invalid/Timezone'], $request->rules());
|
||||||
|
$this->assertSame(
|
||||||
|
'The timezone sent by the browser is invalid.',
|
||||||
|
$englishValidator->errors()->first('timezone'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ use App\Domains\Purchase\Models\Purchase;
|
|||||||
use App\Domains\Sale\Services\AdminAppSalePdfService;
|
use App\Domains\Sale\Services\AdminAppSalePdfService;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Barryvdh\DomPDF\ServiceProvider;
|
use Barryvdh\DomPDF\ServiceProvider;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
class AdminAppSalePdfServiceTest extends TestCase
|
class AdminAppSalePdfServiceTest extends TestCase
|
||||||
@@ -17,6 +18,14 @@ class AdminAppSalePdfServiceTest extends TestCase
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->app->register(ServiceProvider::class);
|
$this->app->register(ServiceProvider::class);
|
||||||
|
Carbon::setTestNow(Carbon::parse('2026-08-24 17:53:00', 'UTC'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
Carbon::setTestNow();
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_downloads_the_sales_report_as_a_pdf(): void
|
public function test_it_downloads_the_sales_report_as_a_pdf(): void
|
||||||
@@ -24,11 +33,12 @@ class AdminAppSalePdfServiceTest extends TestCase
|
|||||||
$response = app(AdminAppSalePdfService::class)->downloadSales(
|
$response = app(AdminAppSalePdfService::class)->downloadSales(
|
||||||
$this->tenant(),
|
$this->tenant(),
|
||||||
collect([$this->sale()]),
|
collect([$this->sale()]),
|
||||||
|
'America/La_Paz',
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertSame('application/pdf', $response->headers->get('content-type'));
|
$this->assertSame('application/pdf', $response->headers->get('content-type'));
|
||||||
$this->assertStringContainsString(
|
$this->assertStringContainsString(
|
||||||
'attachment; filename=ventas_acme_',
|
'attachment; filename=ventas_acme_20260824_135300.pdf',
|
||||||
(string) $response->headers->get('content-disposition'),
|
(string) $response->headers->get('content-disposition'),
|
||||||
);
|
);
|
||||||
$this->assertStringStartsWith('%PDF', $response->getContent());
|
$this->assertStringStartsWith('%PDF', $response->getContent());
|
||||||
@@ -57,16 +67,52 @@ class AdminAppSalePdfServiceTest extends TestCase
|
|||||||
$response = app(AdminAppSalePdfService::class)->downloadModifications(
|
$response = app(AdminAppSalePdfService::class)->downloadModifications(
|
||||||
$this->tenant(),
|
$this->tenant(),
|
||||||
collect([$modification]),
|
collect([$modification]),
|
||||||
|
'America/La_Paz',
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertSame('application/pdf', $response->headers->get('content-type'));
|
$this->assertSame('application/pdf', $response->headers->get('content-type'));
|
||||||
$this->assertStringContainsString(
|
$this->assertStringContainsString(
|
||||||
'attachment; filename=historial_modificaciones_acme_',
|
'attachment; filename=historial_modificaciones_acme_20260824_135300.pdf',
|
||||||
(string) $response->headers->get('content-disposition'),
|
(string) $response->headers->get('content-disposition'),
|
||||||
);
|
);
|
||||||
$this->assertStringStartsWith('%PDF', $response->getContent());
|
$this->assertStringStartsWith('%PDF', $response->getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_it_renders_pdf_dates_in_the_requested_timezone(): void
|
||||||
|
{
|
||||||
|
$sale = $this->sale();
|
||||||
|
$modification = (new ValueChange)->forceFill([
|
||||||
|
'id' => 1,
|
||||||
|
'trackable_id' => $sale->id,
|
||||||
|
'attribute' => 'status',
|
||||||
|
'old_value' => Purchase::STATUS_PENDING_PAYMENT,
|
||||||
|
'new_value' => Purchase::STATUS_PAID,
|
||||||
|
'changed_at' => now(),
|
||||||
|
'actor_type' => 'system',
|
||||||
|
]);
|
||||||
|
$modification->setRelation('trackable', $sale);
|
||||||
|
$modification->setRelation('user', null);
|
||||||
|
|
||||||
|
$salesHtml = view('pdf.adminapp.sales', [
|
||||||
|
'tenant' => $this->tenant(),
|
||||||
|
'sales' => collect([$sale]),
|
||||||
|
'generatedAt' => now(),
|
||||||
|
'timeZone' => 'America/La_Paz',
|
||||||
|
'confirmedSalesTotal' => '25000.00',
|
||||||
|
])->render();
|
||||||
|
$modificationsHtml = view('pdf.adminapp.sale-modifications', [
|
||||||
|
'tenant' => $this->tenant(),
|
||||||
|
'modifications' => collect([$modification]),
|
||||||
|
'generatedAt' => now(),
|
||||||
|
'timeZone' => 'America/La_Paz',
|
||||||
|
])->render();
|
||||||
|
|
||||||
|
$this->assertStringContainsString('Generado el 24/08/2026 13:53', $salesHtml);
|
||||||
|
$this->assertStringContainsString('24/08/2026 13:53', $salesHtml);
|
||||||
|
$this->assertStringContainsString('Generado el 24/08/2026 13:53', $modificationsHtml);
|
||||||
|
$this->assertStringContainsString('13:53:00', $modificationsHtml);
|
||||||
|
}
|
||||||
|
|
||||||
private function tenant(): Tenant
|
private function tenant(): Tenant
|
||||||
{
|
{
|
||||||
return (new Tenant)->forceFill([
|
return (new Tenant)->forceFill([
|
||||||
|
|||||||
Reference in New Issue
Block a user