diff --git a/app/Invoice/Actions/HasValidation.php b/app/Invoice/Actions/HasValidation.php
index 652ed662..20a2084f 100644
--- a/app/Invoice/Actions/HasValidation.php
+++ b/app/Invoice/Actions/HasValidation.php
@@ -17,13 +17,13 @@ trait HasValidation
'status' => ['required', 'string', 'max:255', Rule::in(InvoiceStatus::values())],
'via' => ['required', 'string', 'max:255', Rule::in(BillKind::values())],
'usage' => 'required|max:255|string',
- 'mail_email' => 'nullable|string|max:255|email',
'to' => 'array',
'to.address' => 'required|string|max:255',
'to.location' => 'required|string|max:255',
'to.zip' => 'required|string|max:255',
'to.name' => 'required|string|max:255',
- 'greeting' => 'required|string|max:255',
+ 'to.email' => 'nullable|string|max:255|email',
+ 'to.greeting' => 'required|string|max:255',
'positions' => 'array',
'positions.*.description' => 'required|string|max:300',
'positions.*.price' => 'required|integer|min:0',
@@ -42,6 +42,8 @@ trait HasValidation
'to.name' => 'Name',
'to.zip' => 'PLZ',
'to.location' => 'Ort',
+ 'to.greeting' => 'Anrede',
+ 'to.email' => 'E-Mail-Adresse',
'status' => 'Status',
'via' => 'Rechnungsweg',
'usage' => 'Verwendungszweck',
diff --git a/app/Invoice/Actions/InvoiceSendAction.php b/app/Invoice/Actions/InvoiceSendAction.php
index e66d8b5b..f6e504f2 100644
--- a/app/Invoice/Actions/InvoiceSendAction.php
+++ b/app/Invoice/Actions/InvoiceSendAction.php
@@ -37,14 +37,14 @@ class InvoiceSendAction
foreach (Invoice::whereNeedsBill()->where('via', BillKind::EMAIL)->get() as $invoice) {
$document = BillDocument::fromInvoice($invoice);
$path = Storage::disk('temp')->path(Tex::compile($document)->storeIn('', 'temp'));
- Mail::to($invoice->getMailRecipient())->send(new BillMail($invoice, $path));
+ Mail::to($invoice->getRecipient())->send(new BillMail($invoice, $path));
$invoice->sent($document);
}
foreach (Invoice::whereNeedsRemember()->where('via', BillKind::EMAIL)->get() as $invoice) {
$document = RememberDocument::fromInvoice($invoice);
$path = Storage::disk('temp')->path(Tex::compile($document)->storeIn('', 'temp'));
- Mail::to($invoice->getMailRecipient())->send(new RememberMail($invoice, $path));
+ Mail::to($invoice->getRecipient())->send(new RememberMail($invoice, $path));
$invoice->sent($document);
}
diff --git a/app/Invoice/Data/ReceiverData.php b/app/Invoice/Data/ReceiverData.php
new file mode 100644
index 00000000..f360c3bd
--- /dev/null
+++ b/app/Invoice/Data/ReceiverData.php
@@ -0,0 +1,21 @@
+getRecipient();
return static::factory()->withoutMagicalCreation()->from([
- 'toName' => $invoice->to['name'],
- 'toAddress' => $invoice->to['address'],
- 'toZip' => $invoice->to['zip'],
- 'toLocation' => $invoice->to['location'],
- 'greeting' => $invoice->greeting,
+ 'toName' => $recipient->name,
+ 'toAddress' => $recipient->address,
+ 'toZip' => $recipient->zip,
+ 'toLocation' => $recipient->location,
+ 'greeting' => $recipient->greeting,
'positions' => static::renderPositions($invoice),
'usage' => $invoice->usage,
]);
diff --git a/app/Invoice/Models/Invoice.php b/app/Invoice/Models/Invoice.php
index e6bcd490..3fd26ffd 100644
--- a/app/Invoice/Models/Invoice.php
+++ b/app/Invoice/Models/Invoice.php
@@ -4,6 +4,7 @@ namespace App\Invoice\Models;
use App\Invoice\BillDocument;
use App\Invoice\BillKind;
+use App\Invoice\Data\ReceiverData;
use App\Invoice\Enums\InvoiceStatus;
use App\Invoice\InvoiceDocument;
use App\Invoice\InvoiceSettings;
@@ -28,7 +29,7 @@ class Invoice extends Model
public $guarded = [];
public $casts = [
- 'to' => 'json',
+ 'to' => ReceiverData::class,
'status' => InvoiceStatus::class,
'via' => BillKind::class,
'sent_at' => 'datetime',
@@ -54,12 +55,12 @@ class Invoice extends Model
'address' => $member->address,
'zip' => $member->zip,
'location' => $member->location,
+ 'greeting' => 'Liebe Familie ' . $member->lastname,
+ 'email' => $member->email_parents ?: $member->email,
],
- 'greeting' => 'Liebe Familie ' . $member->lastname,
'status' => InvoiceStatus::NEW,
'via' => $member->bill_kind,
'usage' => 'Mitgliedsbeitrag für ' . $member->lastname,
- 'mail_email' => $member->email_parents ?: $member->email,
]);
$positions = collect([]);
@@ -121,12 +122,8 @@ class Invoice extends Model
->where('last_remembered_at', '<=', now()->subWeeks($weeks));
}
- public function getMailRecipient(): stdClass
- {
- return (object) [
- 'email' => $this->mail_email,
- 'name' => $this->to['name']
- ];
+ public function getRecipient(): ReceiverData {
+ return $this->to;
}
public function sent(InvoiceDocument $document): void
@@ -157,8 +154,6 @@ class Invoice extends Model
return [
'to' => implode(', ', $this->to),
'usage' => $this->usage,
- 'greeting' => $this->greeting,
- 'mail_email' => $this->mail_email,
'status' => $this->status->value,
];
}
diff --git a/app/Invoice/Resources/InvoiceResource.php b/app/Invoice/Resources/InvoiceResource.php
index 99ed955d..6ddcc94c 100644
--- a/app/Invoice/Resources/InvoiceResource.php
+++ b/app/Invoice/Resources/InvoiceResource.php
@@ -3,6 +3,7 @@
namespace App\Invoice\Resources;
use App\Invoice\BillKind;
+use App\Invoice\Data\ReceiverData;
use App\Invoice\Enums\InvoiceStatus;
use App\Invoice\Models\Invoice;
use App\Invoice\Scopes\InvoiceFilterScope;
@@ -35,9 +36,7 @@ class InvoiceResource extends JsonResource
'status' => $this->status->value,
'via' => $this->via->value,
'positions' => InvoicePositionResource::collection($this->whenLoaded('positions')),
- 'greeting' => $this->greeting,
'usage' => $this->usage,
- 'mail_email' => $this->mail_email,
'links' => [
'pdf' => route('invoice.pdf', ['invoice' => $this->getModel()]),
'rememberpdf' => route('invoice.rememberpdf', ['invoice' => $this->getModel()]),
@@ -65,18 +64,11 @@ class InvoiceResource extends JsonResource
'subscriptions' => Subscription::forSelect(),
'filter' => InvoiceFilterScope::fromRequest(request()->input('filter', '')),
'default' => [
- 'to' => [
- 'name' => '',
- 'address' => '',
- 'zip' => '',
- 'location' => '',
- ],
+ 'to' => ReceiverData::default(),
'positions' => [],
- 'greeting' => '',
'status' => InvoiceStatus::NEW->value,
'via' => null,
'usage' => '',
- 'mail_email' => '',
],
'default_position' => [
'id' => null,
diff --git a/config/scout.php b/config/scout.php
index 85d135f3..5c81343a 100644
--- a/config/scout.php
+++ b/config/scout.php
@@ -156,10 +156,10 @@ return [
]
],
Invoice::class => [
- 'filterableAttributes' => ['to', 'usage', 'greeting', 'mail_email', 'status', 'id'],
- 'searchableAttributes' => ['to', 'usage', 'greeting', 'mail_email', 'status', 'id'],
+ 'filterableAttributes' => ['to', 'usage', 'status', 'id'],
+ 'searchableAttributes' => ['to', 'usage', 'status', 'id'],
'sortableAttributes' => [],
- 'displayedAttributes' => ['to', 'usage', 'greeting', 'mail_email', 'status', 'id'],
+ 'displayedAttributes' => ['to', 'usage', 'status', 'id'],
'pagination' => [
'maxTotalHits' => 1000000,
]
diff --git a/database/factories/Invoice/Models/InvoiceFactory.php b/database/factories/Invoice/Models/InvoiceFactory.php
index 9001d2a8..dd9eef9f 100644
--- a/database/factories/Invoice/Models/InvoiceFactory.php
+++ b/database/factories/Invoice/Models/InvoiceFactory.php
@@ -24,12 +24,10 @@ class InvoiceFactory extends Factory
public function definition()
{
return [
- 'greeting' => $this->faker->words(4, true),
'to' => ReceiverRequestFactory::new()->create(),
'status' => InvoiceStatus::NEW->value,
'via' => BillKind::POST->value,
'usage' => $this->faker->words(4, true),
- 'mail_email' => $this->faker->safeEmail(),
];
}
diff --git a/database/migrations/2026_06_19_225430_update_invoice_recipient.php b/database/migrations/2026_06_19_225430_update_invoice_recipient.php
new file mode 100644
index 00000000..0f3e0fd7
--- /dev/null
+++ b/database/migrations/2026_06_19_225430_update_invoice_recipient.php
@@ -0,0 +1,32 @@
+count()) {
+ throw new \Exception('Migration not possibue for current bills.');
+ }
+
+ Schema::table('invoices', function (Blueprint $table) {
+ $table->dropColumn('greeting');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('invoices', function (Blueprint $table) {
+ $table->string('greeting');
+ });
+ }
+};
diff --git a/resources/js/views/invoice/Index.vue b/resources/js/views/invoice/Index.vue
index 7882ce2c..8217fae5 100644
--- a/resources/js/views/invoice/Index.vue
+++ b/resources/js/views/invoice/Index.vue
@@ -41,16 +41,16 @@
Speichern
-
-
+
+
-
+
+
-
diff --git a/resources/views/mail/invoice/bill.blade.php b/resources/views/mail/invoice/bill.blade.php
index 35278c7b..7487dd98 100644
--- a/resources/views/mail/invoice/bill.blade.php
+++ b/resources/views/mail/invoice/bill.blade.php
@@ -1,5 +1,4 @@
@component('mail::message')
-# {{ $invoice->greeting }},
Im Anhang findet ihr die aktuelle Rechnung an {{$settings->from}} für das laufende Jahr. Bitte begleicht diese bis zum angegebenen Datum.
diff --git a/resources/views/mail/invoice/remember.blade.php b/resources/views/mail/invoice/remember.blade.php
index 94bba5b5..6c007f13 100644
--- a/resources/views/mail/invoice/remember.blade.php
+++ b/resources/views/mail/invoice/remember.blade.php
@@ -1,5 +1,4 @@
@component('mail::message')
-# {{ $invoice->greeting }},
Hiermit möchten wir euch an die noch ausstehenden Mitgliedsbeiträge an {{$settings->from}} für das laufende Jahr erinnern. Bitte begleicht diese bis zum angegebenen Datum.
diff --git a/tests/Feature/Invoice/InvoiceRequestFactory.php b/tests/Feature/Invoice/InvoiceRequestFactory.php
index b862dbed..61b6cb8c 100644
--- a/tests/Feature/Invoice/InvoiceRequestFactory.php
+++ b/tests/Feature/Invoice/InvoiceRequestFactory.php
@@ -15,7 +15,6 @@ class InvoiceRequestFactory extends RequestFactory
{
return [
'to' => ReceiverRequestFactory::new(),
- 'greeting' => 'Hallo Familie',
'status' => InvoiceStatus::NEW->value,
'via' => BillKind::EMAIL->value,
'positions' => [],
diff --git a/tests/Feature/Invoice/InvoiceSendActionTest.php b/tests/Feature/Invoice/InvoiceSendActionTest.php
index 7a6a48f8..d6d12602 100644
--- a/tests/Feature/Invoice/InvoiceSendActionTest.php
+++ b/tests/Feature/Invoice/InvoiceSendActionTest.php
@@ -29,10 +29,10 @@ class InvoiceSendActionTest extends TestCase
Storage::fake('temp');
$this->withoutExceptionHandling()->login()->loginNami();
$invoice = Invoice::factory()
- ->to(ReceiverRequestFactory::new()->name('Familie Muster'))
+ ->to(ReceiverRequestFactory::new()->name('Familie Muster')->email('max@muster.de'))
->has(InvoicePosition::factory()->withMember(), 'positions')
->via(BillKind::EMAIL)
- ->create(['mail_email' => 'max@muster.de']);
+ ->create();
InvoiceSendAction::run();
@@ -50,11 +50,11 @@ class InvoiceSendActionTest extends TestCase
$this->withoutExceptionHandling()->login()->loginNami();
app(InvoiceSettings::class)->fill(['from_long' => 'Stammname', 'replyTo' => 'reply@mail.com'])->save();
$invoice = Invoice::factory()
- ->to(ReceiverRequestFactory::new()->name('Familie Muster'))
+ ->to(ReceiverRequestFactory::new()->name('Familie Muster')->email('max@muster.de'))
->has(InvoicePosition::factory()->withMember(), 'positions')
->via(BillKind::EMAIL)
->status(InvoiceStatus::SENT)
- ->create(['sent_at' => now()->subMonths(6), 'mail_email' => 'max@muster.de', 'last_remembered_at' => now()->subMonths(6)]);
+ ->create(['sent_at' => now()->subMonths(6), 'last_remembered_at' => now()->subMonths(6)]);
InvoiceSendAction::run();
diff --git a/tests/Feature/Invoice/InvoiceStoreActionTest.php b/tests/Feature/Invoice/InvoiceStoreActionTest.php
index 877b2206..a6bec449 100644
--- a/tests/Feature/Invoice/InvoiceStoreActionTest.php
+++ b/tests/Feature/Invoice/InvoiceStoreActionTest.php
@@ -24,36 +24,32 @@ class InvoiceStoreActionTest extends TestCase
$response = $this->postJson(
route('invoice.store'),
InvoiceRequestFactory::new()
- ->to(ReceiverRequestFactory::new()->name('Familie Blabla')->address('Musterstr 44')->zip('22222')->location('Solingen'))
+ ->to(ReceiverRequestFactory::new()->name('Familie Blabla')->address('Musterstr 44')->zip('22222')->location('Solingen')->greeting('Hallo Familie')->email('a@b.de'))
->status(InvoiceStatus::PAID)
->via(BillKind::POST)
- ->state([
- 'greeting' => 'Hallo Familie',
- ])
->position(InvoicePositionRequestFactory::new()->description('Beitrag Abc')->price(3250)->member($member))
- ->create(['mail_email' => 'a@b.de'])
+ ->create()
);
$response->assertOk();
$this->assertDatabaseHas('invoices', [
- 'greeting' => 'Hallo Familie',
'via' => BillKind::POST->value,
'status' => InvoiceStatus::PAID->value,
- 'mail_email' => 'a@b.de',
]);
- $invoice = Invoice::firstWhere('greeting', 'Hallo Familie');
+ $invoice = Invoice::firstWhere('to->greeting', 'Hallo Familie');
$this->assertDatabaseHas('invoice_positions', [
'invoice_id' => $invoice->id,
'member_id' => $member->id,
'price' => 3250,
'description' => 'Beitrag Abc',
]);
- $this->assertEquals([
- 'name' => 'Familie Blabla',
- 'address' => 'Musterstr 44',
- 'zip' => '22222',
- 'location' => 'Solingen',
- ], $invoice->to);
+
+ $this->assertEquals('Familie Blabla', $invoice->to->name);
+ $this->assertEquals('Musterstr 44', $invoice->to->address);
+ $this->assertEquals('22222', $invoice->to->zip);
+ $this->assertEquals('Solingen', $invoice->to->location);
+ $this->assertEquals('Hallo Familie', $invoice->to->greeting);
+ $this->assertEquals('a@b.de', $invoice->to->email);
}
public static function validationDataProvider(): Generator
diff --git a/tests/Feature/Invoice/InvoiceUpdateActionTest.php b/tests/Feature/Invoice/InvoiceUpdateActionTest.php
index 5350931c..61b1b7c9 100644
--- a/tests/Feature/Invoice/InvoiceUpdateActionTest.php
+++ b/tests/Feature/Invoice/InvoiceUpdateActionTest.php
@@ -25,29 +25,27 @@ class InvoiceUpdateActionTest extends TestCase
$this->patchJson(
route('invoice.update', ['invoice' => $invoice]),
InvoiceRequestFactory::new()
- ->to(ReceiverRequestFactory::new()->name('Familie Blabla')->address('Musterstr 44')->zip('22222')->location('Solingen'))
+ ->to(ReceiverRequestFactory::new()->name('Familie Blabla')->address('Musterstr 44')->zip('22222')->location('Solingen')->greeting('Hallo Familie Blabla'))
->status(InvoiceStatus::PAID)
->via(BillKind::POST)
->state([
- 'greeting' => 'Hallo Familie',
])
->create()
)->assertOk();
$this->assertDatabaseCount('invoices', 1);
$this->assertDatabaseHas('invoices', [
- 'greeting' => 'Hallo Familie',
'via' => BillKind::POST->value,
'status' => InvoiceStatus::PAID->value,
'id' => $invoice->id,
]);
- $invoice = Invoice::firstWhere('greeting', 'Hallo Familie');
- $this->assertEquals([
- 'name' => 'Familie Blabla',
- 'address' => 'Musterstr 44',
- 'zip' => '22222',
- 'location' => 'Solingen',
- ], $invoice->to);
+ $invoice = Invoice::firstWhere('to->greeting', 'Hallo Familie Blabla');
+ $this->assertEquals('Familie Blabla', $invoice->to->name);
+ $this->assertEquals('Musterstr 44', $invoice->to->address);
+ $this->assertEquals('22222', $invoice->to->zip);
+ $this->assertEquals('Solingen', $invoice->to->location);
+ $this->assertEquals('Hallo Familie Blabla', $invoice->to->greeting);
+ $this->assertNull($invoice->to->email);
}
public function testItAddsAPosition(): void
diff --git a/tests/Feature/Invoice/MassStoreActionTest.php b/tests/Feature/Invoice/MassStoreActionTest.php
index 2f51f0b0..9204d22f 100644
--- a/tests/Feature/Invoice/MassStoreActionTest.php
+++ b/tests/Feature/Invoice/MassStoreActionTest.php
@@ -57,14 +57,13 @@ class MassStoreActionTest extends TestCase
$invoice = Invoice::first();
$this->assertNotNull($invoice);
- $this->assertEquals([
- 'name' => 'Familie Muster',
- 'address' => 'Maxstr 4',
- 'zip' => '33445',
- 'location' => 'Solingen',
- ], $invoice->to);
+ $this->assertEquals('Familie Muster', $invoice->to->name);
+ $this->assertEquals('Maxstr 4', $invoice->to->address);
+ $this->assertEquals('33445', $invoice->to->zip);
+ $this->assertEquals('Solingen', $invoice->to->location);
+ $this->assertEquals('Liebe Familie Muster', $invoice->to->greeting);
+ $this->assertEquals('lala@b.de', $invoice->to->email);
$this->assertEquals('Mitgliedsbeitrag für Muster', $invoice->usage);
- $this->assertEquals('lala@b.de', $invoice->mail_email);
$this->assertEquals(BillKind::EMAIL, $invoice->via);
$this->assertDatabaseHas('invoice_positions', [
'invoice_id' => $invoice->id,
diff --git a/tests/Feature/Invoice/MemberNewInvoiceActionTest.php b/tests/Feature/Invoice/MemberNewInvoiceActionTest.php
index 173c8760..bfc86e95 100644
--- a/tests/Feature/Invoice/MemberNewInvoiceActionTest.php
+++ b/tests/Feature/Invoice/MemberNewInvoiceActionTest.php
@@ -32,14 +32,14 @@ class MemberNewInvoiceActionTest extends TestCase
$this->post(route('invoice.new-invoice-attributes'), ['member_id' => $member->id, 'year' => 2019, 'subscription_id' => $subscription->id])
->assertOk()
- ->assertJsonPath('greeting', 'Liebe Familie Muster')
+ ->assertJsonPath('to.greeting', 'Liebe Familie Muster')
->assertJsonPath('to.address', 'Maxstr 4')
->assertJsonPath('to.location', 'Solingen')
->assertJsonPath('to.zip', '33445')
->assertJsonPath('to.name', 'Familie Muster')
+ ->assertJsonPath('to.email', 'lala@b.de')
->assertJsonPath('usage', 'Mitgliedsbeitrag für Muster')
->assertJsonPath('via', 'E-Mail')
- ->assertJsonPath('mail_email', 'lala@b.de')
->assertJsonPath('status', 'Neu')
->assertJsonPath('positions.0.description', 'beitrag Max Muster')
->assertJsonPath('positions.0.member_id', $member->id)
diff --git a/tests/Feature/Invoice/ReceiverRequestFactory.php b/tests/Feature/Invoice/ReceiverRequestFactory.php
index a01dc0e6..ce1bf243 100644
--- a/tests/Feature/Invoice/ReceiverRequestFactory.php
+++ b/tests/Feature/Invoice/ReceiverRequestFactory.php
@@ -13,6 +13,8 @@ class ReceiverRequestFactory extends RequestFactory
'address' => 'Musterstr 44',
'zip' => '22222',
'location' => 'Solingen',
+ 'greeting' => 'Liebe Familie Blabla',
+ 'email' => null,
];
}
@@ -35,4 +37,14 @@ class ReceiverRequestFactory extends RequestFactory
{
return $this->state(['location' => $location]);
}
+
+ public function greeting(string $greeting): self
+ {
+ return $this->state(['greeting' => $greeting]);
+ }
+
+ public function email(string $email): self
+ {
+ return $this->state(['email' => $email]);
+ }
}