mivita/tests/Feature/RegenerateCancellationInvoicePdfCommandTest.php
Kevin 1e7ae92d0c Stornorechnung: Fix überdeckte Artikelzeile + Regenerate-Command
Der ACHTUNG-Hinweiskasten hat wegen fixer 15mm-Höhe des Titel-Blocks
den Tabellenkopf und die erste Artikelzeile überdeckt (z.B. Artikel
5010400 auf den Stornos zu Bestellung 56965/56966). Titel-Block wächst
jetzt mit dem Inhalt.

Neuer Command sales:regenerate-cancellation-pdf erzeugt die PDFs
bestehender Stornorechnungen neu (gleiche Nummer/Pfade, keine
Punktebuchung, keine Mails) – per Rechnungs-ID oder mit --order per
Bestell-ID.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:19:28 +00:00

126 lines
4.7 KiB
PHP

<?php
use App\Models\ShoppingOrder;
use App\Models\ShoppingUser;
use App\Models\UserInvoice;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
uses(TestCase::class, RefreshDatabase::class);
beforeEach(fn () => makeShopEnv());
/**
* @return array{0: ShoppingOrder, 1: UserInvoice, 2: UserInvoice} Bestellung, Originalrechnung, Stornorechnung
*/
function makeCancelledOrderWithStornoInvoice(): array
{
$shoppingUser = ShoppingUser::forceCreate([
'auth_user_id' => 0,
'billing_firstname' => 'Max',
'billing_lastname' => 'Mustermann',
'billing_email' => 'storno@example.com',
'billing_country_id' => 1,
'shipping_country_id' => 1,
'wp_order_number' => 0,
'language' => 'de',
]);
$order = ShoppingOrder::create([
'shopping_user_id' => $shoppingUser->id,
'auth_user_id' => 0,
'country_id' => 1,
'user_shop_id' => 0,
'payment_for' => 6,
'shipping' => 0,
'shipping_net' => 0,
'subtotal_ws' => 50,
'subtotal' => 50,
'tax' => 0,
'total_shipping' => 50,
'points' => 0,
'txaction' => 'cancelled',
]);
$product = makeProduct(['12'], 50, 0);
$order->shopping_order_items()->create([
'product_id' => $product->id, 'is_abo_addon' => false, 'qty' => 1,
'price' => 50, 'price_net' => 50, 'tax_rate' => 0, 'tax' => 0, 'price_vk_net' => 50, 'discount' => 0, 'points' => 0,
]);
$original = UserInvoice::create([
'shopping_order_id' => $order->id,
'year' => 2026, 'month' => 7, 'date' => '2026-07-02',
'full_number' => '202600001', 'number' => 1,
'filename' => '202600001-MIVITA-Rechnung.pdf', 'dir' => 'invoice/2026/07/',
'delivery_filename' => '202600001-MIVITA-Lieferschein.pdf', 'delivery_dir' => 'delivery/2026/07/',
'disk' => 'public', 'status' => 1,
]);
$storno = UserInvoice::create([
'shopping_order_id' => $order->id,
'year' => 2026, 'month' => 7, 'date' => '2026-07-13',
'full_number' => '202600002', 'number' => 2,
'filename' => '202600002-MIVITA-Stornorechnung.pdf', 'dir' => 'invoice/2026/07/',
'delivery_filename' => '202600002-MIVITA-Storno-Lieferschein.pdf', 'delivery_dir' => 'delivery/2026/07/',
'disk' => 'public', 'cancellation' => true, 'status' => 11,
]);
$original->update([
'cancellation' => true,
'cancellation_id' => $storno->id,
'cancellation_date' => '2026-07-13',
]);
return [$order, $original, $storno];
}
it('lehnt eine unbekannte Stornorechnung ab', function () {
$this->artisan('sales:regenerate-cancellation-pdf', ['invoices' => [999999], '--force' => true])
->expectsOutputToContain('nicht gefunden')
->assertExitCode(1);
});
it('lehnt eine Originalrechnung ab, die keine Stornorechnung ist', function () {
[, $original] = makeCancelledOrderWithStornoInvoice();
$this->artisan('sales:regenerate-cancellation-pdf', ['invoices' => [$original->id], '--force' => true])
->expectsOutputToContain('keine Stornorechnung')
->assertExitCode(1);
});
it('lehnt eine Bestellung ohne Stornorechnung ab', function () {
[$order, $original, $storno] = makeCancelledOrderWithStornoInvoice();
$original->update(['cancellation' => false, 'cancellation_id' => null]);
$storno->delete();
$this->artisan('sales:regenerate-cancellation-pdf', ['invoices' => [$order->id], '--order' => true, '--force' => true])
->expectsOutputToContain('hat keine Stornorechnung')
->assertExitCode(1);
});
it('erzeugt die Storno-PDFs unter den bestehenden Pfaden neu, ohne neue Rechnungen anzulegen', function () {
Storage::fake('public');
[, , $storno] = makeCancelledOrderWithStornoInvoice();
$this->artisan('sales:regenerate-cancellation-pdf', ['invoices' => [$storno->id], '--force' => true])
->assertExitCode(0);
// Keine neuen Rechnungen, keine Nummern verbraucht.
expect(UserInvoice::count())->toBe(2);
expect($storno->fresh()->full_number)->toBe('202600002');
Storage::disk('public')->assertExists('invoice/2026/07/202600002-MIVITA-Stornorechnung.pdf');
Storage::disk('public')->assertExists('delivery/2026/07/202600002-MIVITA-Storno-Lieferschein.pdf');
});
it('findet die Stornorechnung auch über die Bestell-ID', function () {
Storage::fake('public');
[$order] = makeCancelledOrderWithStornoInvoice();
$this->artisan('sales:regenerate-cancellation-pdf', ['invoices' => [$order->id], '--order' => true, '--force' => true])
->assertExitCode(0);
Storage::disk('public')->assertExists('invoice/2026/07/202600002-MIVITA-Stornorechnung.pdf');
});