Verbesserte EÜR-Abrechnung
This commit is contained in:
@@ -202,11 +202,95 @@ class EventIncomeSurplusStatementTest extends TestCase
|
||||
// Kein Geldfluss, also keine Ausgabe:
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 999.0, InvoiceStatus::INVOICE_STATUS_DENIED);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 888.0, InvoiceStatus::INVOICE_STATUS_DELETED);
|
||||
|
||||
// Eine Spende ist Ausgabe ihres Typs (und zugleich Einnahme unter den Förderungen):
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 777.0, InvoiceStatus::INVOICE_STATUS_NEW, donation: true);
|
||||
|
||||
$this->assertEqualsWithDelta(150.0, $this->group('Programmkosten')['sum']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(927.0, $this->group('Programmkosten')['sum']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(30.0, $this->group('Verpflegungskosten')['sum']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(180.0, $this->statement()->expenses['total']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(957.0, $this->statement()->expenses['total']->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Spenden
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function test_without_donations_the_donation_line_is_zero(): void
|
||||
{
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 100.0, InvoiceStatus::INVOICE_STATUS_NEW);
|
||||
|
||||
$this->assertEqualsWithDelta(0.0, $this->entry('Spenden')->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(0.0, $this->statement()->donations['total']->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
public function test_a_donation_is_an_expense_of_its_type_and_funding_income(): void
|
||||
{
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 100.0, InvoiceStatus::INVOICE_STATUS_NEW);
|
||||
$resultWithoutDonation = $this->statement()->result->getAmount();
|
||||
|
||||
$donated = $this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 40.0, InvoiceStatus::INVOICE_STATUS_APPROVED, donation: true);
|
||||
|
||||
$statement = $this->statement();
|
||||
$program = $this->group('Programmkosten');
|
||||
|
||||
$this->assertEqualsWithDelta(140.0, $program['sum']->getAmount(), 0.001);
|
||||
$this->assertContains($donated->invoice_number, array_column($program['rows'], 'number'));
|
||||
|
||||
// Gegenbuchung unter den Förderungen (ohne Anmeldung keine Fördermittel, also nur die Spende).
|
||||
$this->assertSame('Förderungen', $statement->income['categories'][1]['name']);
|
||||
$this->assertEqualsWithDelta(40.0, $this->entry('Spenden')->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(40.0, $statement->income['categories'][1]['total']->getAmount(), 0.001);
|
||||
|
||||
// Ausgabe und Einnahme heben sich auf.
|
||||
$this->assertEqualsWithDelta($resultWithoutDonation, $statement->result->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
public function test_donations_are_grouped_like_expenses(): void
|
||||
{
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 100.0, InvoiceStatus::INVOICE_STATUS_NEW);
|
||||
$programDonation = $this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 25.0, InvoiceStatus::INVOICE_STATUS_NEW, donation: true);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 15.0, InvoiceStatus::INVOICE_STATUS_EXPORTED, donation: true);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_CATERING, 60.0, InvoiceStatus::INVOICE_STATUS_APPROVED, donation: true);
|
||||
|
||||
$donations = $this->statement()->donations;
|
||||
|
||||
// Dieselbe Gliederung wie die Ausgaben, auch Typen ohne Spende stehen darin.
|
||||
$this->assertSame(
|
||||
array_column($this->statement()->expenses['groups'], 'name'),
|
||||
array_column($donations['groups'], 'name')
|
||||
);
|
||||
|
||||
$this->assertEqualsWithDelta(40.0, $this->donationGroup('Programmkosten')['sum']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(60.0, $this->donationGroup('Verpflegungskosten')['sum']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(100.0, $donations['total']->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(100.0, $this->entry('Spenden')->getAmount(), 0.001);
|
||||
|
||||
// Derselbe Beleg steht als Ausgabe und als Spende.
|
||||
$this->assertContains($programDonation->invoice_number, array_column($this->group('Programmkosten')['rows'], 'number'));
|
||||
$this->assertContains($programDonation->invoice_number, array_column($this->donationGroup('Programmkosten')['rows'], 'number'));
|
||||
|
||||
// Nicht gespendete Belege stehen nicht in der Spenden-Anlage.
|
||||
$this->assertCount(2, $this->donationGroup('Programmkosten')['rows']);
|
||||
}
|
||||
|
||||
public function test_donations_list_only_booked_donations(): void
|
||||
{
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 20.0, InvoiceStatus::INVOICE_STATUS_NEW, donation: true);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 999.0, InvoiceStatus::INVOICE_STATUS_DENIED, donation: true);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 888.0, InvoiceStatus::INVOICE_STATUS_DELETED, donation: true);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PARTICIPATION_REFUND, 220.0, InvoiceStatus::INVOICE_STATUS_EXPORTED, donation: true);
|
||||
|
||||
$donations = $this->statement()->donations;
|
||||
|
||||
$this->assertEqualsWithDelta(20.0, $donations['total']->getAmount(), 0.001);
|
||||
$this->assertCount(1, $this->donationGroup('Programmkosten')['rows']);
|
||||
$this->assertNotContains('Beitragserstattung', array_column($donations['groups'], 'name'));
|
||||
}
|
||||
|
||||
public function test_a_refund_is_no_expense(): void
|
||||
@@ -311,12 +395,34 @@ class EventIncomeSurplusStatementTest extends TestCase
|
||||
public function test_the_comment_is_no_longer_part_of_the_purpose(): void
|
||||
{
|
||||
// Die Anmerkung trägt, was die Kassenwart*in beim Korrigieren notiert hat -- sie steht auf dem
|
||||
// Beleg-PDF und hat im Zweck nichts zu suchen. Bestandsbelege ohne erfassten Zahlungsgrund haben
|
||||
// hier deshalb eine leere Zelle; nachtragen lässt er sich beim Korrigieren.
|
||||
// Beleg-PDF und hat im Zweck nichts zu suchen.
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 100.0, InvoiceStatus::INVOICE_STATUS_NEW);
|
||||
|
||||
$this->assertSame('', $this->group('Programmkosten')['rows'][0]['purpose']);
|
||||
$this->assertStringNotContainsString('Materialkauf', $this->group('Programmkosten')['rows'][0]['purpose']);
|
||||
}
|
||||
|
||||
public function test_an_empty_purpose_falls_back_to_the_refund_of_the_contact(): void
|
||||
{
|
||||
// Ältere Abrechnungen ohne jede Zweckangabe: ersatzweise, wem erstattet wurde -- als Ausgabe wie als Spende.
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 100.0, InvoiceStatus::INVOICE_STATUS_NEW);
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 30.0, InvoiceStatus::INVOICE_STATUS_NEW, donation: true);
|
||||
$this->makeInvoice(
|
||||
InvoiceType::INVOICE_TYPE_PROGRAM,
|
||||
50.0,
|
||||
InvoiceStatus::INVOICE_STATUS_NEW,
|
||||
purpose: 'Material für den Bastelnachmittag'
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
['Auslagenerstattung Mika Muster', 'Auslagenerstattung Mika Muster', 'Material für den Bastelnachmittag'],
|
||||
array_column($this->group('Programmkosten')['rows'], 'purpose')
|
||||
);
|
||||
$this->assertSame(
|
||||
['Auslagenerstattung Mika Muster'],
|
||||
array_column($this->donationGroup('Programmkosten')['rows'], 'purpose')
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -388,6 +494,20 @@ class EventIncomeSurplusStatementTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function test_a_donation_still_does_not_count_in_the_expense_overview(): void
|
||||
{
|
||||
// Die Bildschirm-Übersicht kennt keine Spenden-Einnahme -- dort bleibt die Spende außen vor.
|
||||
$this->makeEvent();
|
||||
$this->makeInvoice(InvoiceType::INVOICE_TYPE_PROGRAM, 777.0, InvoiceStatus::INVOICE_STATUS_NEW, donation: true);
|
||||
|
||||
$amount = new CostUnitRepository()->sumupByInvoiceType(
|
||||
$this->costUnit->fresh(),
|
||||
InvoiceType::where('slug', InvoiceType::INVOICE_TYPE_PROGRAM)->first()
|
||||
);
|
||||
|
||||
$this->assertEqualsWithDelta(0.0, $amount->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Helfer
|
||||
@@ -435,6 +555,18 @@ class EventIncomeSurplusStatementTest extends TestCase
|
||||
$this->fail('Ausgaben-Gruppe "' . $name . '" fehlt.');
|
||||
}
|
||||
|
||||
/** @return array{name: string, sum: Amount, rows: array<int, array<string, mixed>>} */
|
||||
private function donationGroup(string $name): array
|
||||
{
|
||||
foreach ($this->statement()->donations['groups'] as $group) {
|
||||
if ($group['name'] === $name) {
|
||||
return $group;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fail('Spenden-Gruppe "' . $name . '" fehlt.');
|
||||
}
|
||||
|
||||
private function makeEvent(): Event
|
||||
{
|
||||
$fee = EventParticipationFee::create([
|
||||
|
||||
Reference in New Issue
Block a user