API updadte

This commit is contained in:
2025-11-08 22:51:35 +01:00
parent 0fb028d19a
commit c0c346a9ed
10 changed files with 526 additions and 108 deletions

134
README.md
View File

@@ -98,6 +98,8 @@ Die vollständige API-Dokumentation mit allen Endpunkten, Beispielen und interak
Wichtigste Endpunkte: Wichtigste Endpunkte:
- **Immobilien**: `/api/immobilies` (GET, POST, PATCH, DELETE) - **Immobilien**: `/api/immobilies` (GET, POST, PATCH, DELETE)
- **Benutzer**: `/api/users` (GET, POST, PUT, DELETE) - **Benutzer**: `/api/users` (GET, POST, PUT, DELETE)
- **Bundesländer**: `/api/bundeslands` (GET, POST, PUT, DELETE)
- **Heizungstypen**: `/api/heizungstyps` (GET, POST, PUT, DELETE)
## Datenbank-Schema ## Datenbank-Schema
@@ -111,6 +113,30 @@ Wichtigste Endpunkte:
| role | ENUM | Benutzerrolle (user, admin, moderator) | | role | ENUM | Benutzerrolle (user, admin, moderator) |
| created_at | DATETIME | Erstellungsdatum | | created_at | DATETIME | Erstellungsdatum |
### Bundesland-Tabelle
| Feld | Typ | Beschreibung |
|------|-----|--------------|
| id | INT | Primärschlüssel (Auto-Increment) |
| name | VARCHAR(100) | Name des Bundeslandes (Unique) |
| grunderwerbsteuer | DECIMAL(4,2) | Grunderwerbsteuer in Prozent |
**Grunderwerbsteuer-Sätze (Stand 2025):**
- Baden-Württemberg, Bremen, Niedersachsen, Rheinland-Pfalz, Sachsen-Anhalt, Thüringen: 5,0%
- Bayern: 3,5%
- Hamburg, Sachsen: 5,5%
- Berlin, Hessen, Mecklenburg-Vorpommern: 6,0%
- Brandenburg, Nordrhein-Westfalen, Saarland, Schleswig-Holstein: 6,5%
### Heizungstyp-Tabelle
| Feld | Typ | Beschreibung |
|------|-----|--------------|
| id | INT | Primärschlüssel (Auto-Increment) |
| name | VARCHAR(100) | Name des Heizungstyps (Unique) |
**Beispiele:** Gasheizung, Wärmepumpe, Ölheizung, Fernwärme, etc.
### Immobilien-Tabelle ### Immobilien-Tabelle
| Feld | Typ | Beschreibung | | Feld | Typ | Beschreibung |
@@ -118,25 +144,27 @@ Wichtigste Endpunkte:
| id | INT | Primärschlüssel (Auto-Increment) | | id | INT | Primärschlüssel (Auto-Increment) |
| verwalter_id | INT | Foreign Key zu User (Verwalter der Immobilie) | | verwalter_id | INT | Foreign Key zu User (Verwalter der Immobilie) |
| adresse | VARCHAR(255) | Vollständige Adresse (5-255 Zeichen) | | adresse | VARCHAR(255) | Vollständige Adresse (5-255 Zeichen) |
| preis | DECIMAL | Kaufpreis oder Miete | | wohnflaeche | INT | Wohnfläche in m² (ganze Zahl) |
| flaeche | DECIMAL | Wohnfläche in m² | | nutzflaeche | INT | Nutzfläche in m² (ganze Zahl) |
| garage | BOOLEAN | Hat Garage? (Standard: false) | | garage | BOOLEAN | Hat Garage? (Standard: false) |
| zimmer | INT | Anzahl Zimmer (> 0) | | zimmer | INT | Anzahl Zimmer (> 0) |
| baujahr | INT | Baujahr (1800-2100, optional) | | baujahr | INT | Baujahr (1800-2100, optional) |
| typ | ENUM | Immobilientyp (wohnung, haus, grundstueck, gewerbe, buero) | | typ | ENUM | Immobilientyp (wohnung, haus, grundstueck, gewerbe, buero) |
| beschreibung | TEXT | Freitextbeschreibung (optional) | | beschreibung | TEXT | Freitextbeschreibung (optional) |
| verfuegbar | BOOLEAN | Verfügbarkeit (Standard: true) | | etage | INT | Stockwerk (0-10, optional) |
| balkon_flaeche | INT | Balkonfläche in m² (optional) | | heizungstyp_id | INT | Foreign Key zu Heizungstyp (optional) |
| keller_flaeche | INT | Kellerfläche in m² (optional) | | abschreibungszeit | INT | Abschreibungszeit in Jahren (0-100, optional) |
| etage | INT | Stockwerk (optional) | | bundesland_id | INT | Foreign Key zu Bundesland (optional) |
| heizungstyp | VARCHAR(255) | Art der Heizung (optional) | | kaufpreis | INT | Kaufpreis in Euro (ganze Zahl, optional) |
| nebenkosten | DECIMAL | Monatliche Nebenkosten (optional) |
| created_at | DATETIME | Erstellungsdatum | | created_at | DATETIME | Erstellungsdatum |
| updated_at | DATETIME | Letzte Aktualisierung | | updated_at | DATETIME | Letzte Aktualisierung |
**Berechnete Felder (nicht in DB gespeichert):** **Berechnete Felder (nicht in DB gespeichert):**
- `preis_pro_qm`: Preis / Fläche - `gesamtflaeche`: Wohnfläche + Nutzfläche
- `gesamtflaeche`: Fläche + Balkon + Keller - `kaufnebenkosten`: Objekt mit Notar, Grundbuch, Grunderwerbsteuer und Gesamtsumme
- Notarkosten: ca. 1,5% des Kaufpreises
- Grundbuchkosten: ca. 0,5% des Kaufpreises
- Grunderwerbsteuer: abhängig vom Bundesland (3,5% - 6,5%)
## Entwicklung ## Entwicklung
@@ -444,8 +472,49 @@ curl -H "Accept: application/ld+json" http://localhost:8080/api/users
| PUT | `/api/users/{id}` | User vollständig ersetzen | | PUT | `/api/users/{id}` | User vollständig ersetzen |
| DELETE | `/api/users/{id}` | User löschen | | DELETE | `/api/users/{id}` | User löschen |
#### Bundesland-Endpunkte
| Methode | Endpoint | Beschreibung |
|---------|----------|--------------|
| GET | `/api/bundeslands` | Alle Bundesländer abrufen (mit Pagination) |
| GET | `/api/bundeslands/{id}` | Einzelnes Bundesland abrufen |
| POST | `/api/bundeslands` | Neues Bundesland erstellen |
| PUT | `/api/bundeslands/{id}` | Bundesland vollständig ersetzen |
| DELETE | `/api/bundeslands/{id}` | Bundesland löschen |
#### Heizungstyp-Endpunkte
| Methode | Endpoint | Beschreibung |
|---------|----------|--------------|
| GET | `/api/heizungstyps` | Alle Heizungstypen abrufen (mit Pagination) |
| GET | `/api/heizungstyps/{id}` | Einzelnen Heizungstyp abrufen |
| POST | `/api/heizungstyps` | Neuen Heizungstyp erstellen |
| PUT | `/api/heizungstyps/{id}` | Heizungstyp vollständig ersetzen |
| DELETE | `/api/heizungstyps/{id}` | Heizungstyp löschen |
### Beispiele ### Beispiele
#### Bundesland erstellen
```bash
curl -X POST http://localhost:8080/api/bundeslands \
-H "Content-Type: application/json" \
-d '{
"name": "Bayern",
"grunderwerbsteuer": 3.5
}'
```
#### Heizungstyp erstellen
```bash
curl -X POST http://localhost:8080/api/heizungstyps \
-H "Content-Type: application/json" \
-d '{
"name": "Wärmepumpe"
}'
```
#### Immobilie erstellen #### Immobilie erstellen
```bash ```bash
@@ -454,13 +523,17 @@ curl -X POST http://localhost:8080/api/immobilies \
-d '{ -d '{
"verwalter": "/api/users/1", "verwalter": "/api/users/1",
"adresse": "Hauptstraße 123, 12345 Musterstadt", "adresse": "Hauptstraße 123, 12345 Musterstadt",
"preis": "250000", "wohnflaeche": 85,
"flaeche": "85.5", "nutzflaeche": 15,
"zimmer": 3, "zimmer": 3,
"typ": "wohnung", "typ": "wohnung",
"garage": true, "garage": true,
"balkonFlaeche": 8, "baujahr": 2020,
"baujahr": 2020 "heizungstyp": "/api/heizungstyps/1",
"bundesland": "/api/bundeslands/1",
"kaufpreis": 350000,
"abschreibungszeit": 50,
"etage": 3
}' }'
``` ```
@@ -492,8 +565,9 @@ curl http://localhost:8080/api/immobilies?page=2
curl -X PATCH http://localhost:8080/api/immobilies/1 \ curl -X PATCH http://localhost:8080/api/immobilies/1 \
-H "Content-Type: application/merge-patch+json" \ -H "Content-Type: application/merge-patch+json" \
-d '{ -d '{
"preis": "260000", "wohnflaeche": 90,
"verfuegbar": false "kaufpreis": 360000,
"heizungstyp": "/api/heizungstyps/2"
}' }'
``` ```
@@ -501,11 +575,35 @@ curl -X PATCH http://localhost:8080/api/immobilies/1 \
Die Immobilien-Entity bietet automatisch berechnete Felder: Die Immobilien-Entity bietet automatisch berechnete Felder:
- **preisProQm**: Berechnet automatisch den Preis pro Quadratmeter - **gesamtflaeche**: Berechnet die Gesamtfläche (Wohnfläche + Nutzfläche)
- **gesamtflaeche**: Summiert Wohnfläche + Balkonfläche + Kellerfläche - **kaufnebenkosten**: Berechnet die Kaufnebenkosten basierend auf Kaufpreis und Bundesland
- Enthält: Notarkosten (1,5%), Grundbuchkosten (0,5%), Grunderwerbsteuer (abhängig vom Bundesland) und Gesamtsumme
Diese Felder sind schreibgeschützt (read-only) und werden automatisch bei jeder Abfrage berechnet. Diese Felder sind schreibgeschützt (read-only) und werden automatisch bei jeder Abfrage berechnet.
### Enums
Die API verwendet folgende Enums:
**ImmobilienTyp:**
- `wohnung` - Wohnung
- `haus` - Haus
- `grundstueck` - Grundstück
- `gewerbe` - Gewerbe
- `buero` - Büro
**UserRole:**
- `user` - Benutzer
- `admin` - Administrator
- `moderator` - Moderator
### Relationen
**Bundesland und Heizungstyp** sind eigene Entities, die über Foreign Keys mit Immobilien verknüpft sind:
- Bei der Erstellung einer Immobilie muss eine IRI verwendet werden (z.B. `/api/bundeslands/1`)
- Diese Entities können über ihre eigenen Endpunkte verwaltet werden
- Bundesländer enthalten die Grunderwerbsteuer-Sätze für die Kaufnebenkosten-Berechnung
### Hydra-Unterstützung ### Hydra-Unterstützung
Bei Verwendung des JSON-LD Formats (Standard) bietet die API Hydra-Unterstützung: Bei Verwendung des JSON-LD Formats (Standard) bietet die API Hydra-Unterstützung:

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251108213222 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE immobilien ADD abschreibungszeit INT DEFAULT NULL, ADD bundesland VARCHAR(255) DEFAULT NULL, ADD kaufpreis INT DEFAULT NULL, DROP balkon_flaeche, DROP keller_flaeche, CHANGE preis preis INT NOT NULL, CHANGE heizungstyp heizungstyp VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE immobilien ADD balkon_flaeche INT DEFAULT NULL, ADD keller_flaeche INT DEFAULT NULL, DROP abschreibungszeit, DROP bundesland, DROP kaufpreis, CHANGE preis preis NUMERIC(10, 2) NOT NULL, CHANGE heizungstyp heizungstyp VARCHAR(100) DEFAULT NULL');
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251108214500 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE bundeslaender (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(100) NOT NULL, grunderwerbsteuer NUMERIC(4, 2) NOT NULL, UNIQUE INDEX UNIQ_DF7DFAB25E237E06 (name), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('CREATE TABLE heizungstypen (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(100) NOT NULL, UNIQUE INDEX UNIQ_6161C2A65E237E06 (name), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
$this->addSql('ALTER TABLE immobilien ADD nutzflaeche INT NOT NULL, ADD heizungstyp_id INT DEFAULT NULL, ADD bundesland_id INT DEFAULT NULL, DROP flaeche, DROP verfuegbar, DROP heizungstyp, DROP nebenkosten, DROP bundesland, CHANGE preis wohnflaeche INT NOT NULL');
$this->addSql('ALTER TABLE immobilien ADD CONSTRAINT FK_2C789DC1B4DB52 FOREIGN KEY (heizungstyp_id) REFERENCES heizungstypen (id)');
$this->addSql('ALTER TABLE immobilien ADD CONSTRAINT FK_2C789DB74FDBEB FOREIGN KEY (bundesland_id) REFERENCES bundeslaender (id)');
$this->addSql('CREATE INDEX IDX_2C789DC1B4DB52 ON immobilien (heizungstyp_id)');
$this->addSql('CREATE INDEX IDX_2C789DB74FDBEB ON immobilien (bundesland_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE bundeslaender');
$this->addSql('DROP TABLE heizungstypen');
$this->addSql('ALTER TABLE immobilien DROP FOREIGN KEY FK_2C789DC1B4DB52');
$this->addSql('ALTER TABLE immobilien DROP FOREIGN KEY FK_2C789DB74FDBEB');
$this->addSql('DROP INDEX IDX_2C789DC1B4DB52 ON immobilien');
$this->addSql('DROP INDEX IDX_2C789DB74FDBEB ON immobilien');
$this->addSql('ALTER TABLE immobilien ADD preis INT NOT NULL, ADD flaeche NUMERIC(8, 2) NOT NULL, ADD verfuegbar TINYINT(1) NOT NULL, ADD heizungstyp VARCHAR(255) DEFAULT NULL, ADD nebenkosten NUMERIC(6, 2) DEFAULT NULL, ADD bundesland VARCHAR(255) DEFAULT NULL, DROP wohnflaeche, DROP nutzflaeche, DROP heizungstyp_id, DROP bundesland_id');
}
}

69
src/Entity/Bundesland.php Normal file
View File

@@ -0,0 +1,69 @@
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use App\Repository\BundeslandRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: BundeslandRepository::class)]
#[ORM\Table(name: 'bundeslaender')]
#[ApiResource(
operations: [
new Get(),
new GetCollection(),
new Post(),
new Put(),
new Delete()
]
)]
class Bundesland
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 100, unique: true)]
#[Assert\NotBlank]
#[Assert\Length(min: 2, max: 100)]
private string $name;
#[ORM\Column(type: 'decimal', precision: 4, scale: 2)]
#[Assert\NotBlank]
#[Assert\Range(min: 0, max: 100)]
private float $grunderwerbsteuer;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getGrunderwerbsteuer(): float
{
return $this->grunderwerbsteuer;
}
public function setGrunderwerbsteuer(float $grunderwerbsteuer): self
{
$this->grunderwerbsteuer = $grunderwerbsteuer;
return $this;
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use App\Repository\HeizungstypRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: HeizungstypRepository::class)]
#[ORM\Table(name: 'heizungstypen')]
#[ApiResource(
operations: [
new Get(),
new GetCollection(),
new Post(),
new Put(),
new Delete()
]
)]
class Heizungstyp
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 100, unique: true)]
#[Assert\NotBlank]
#[Assert\Length(min: 2, max: 100)]
private string $name;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}

View File

@@ -7,7 +7,6 @@ use App\Enum\ImmobilienTyp;
use App\Repository\ImmobilieRepository; use App\Repository\ImmobilieRepository;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
#[ORM\Entity(repositoryClass: ImmobilieRepository::class)] #[ORM\Entity(repositoryClass: ImmobilieRepository::class)]
#[ORM\Table(name: 'immobilien')] #[ORM\Table(name: 'immobilien')]
@@ -30,15 +29,15 @@ class Immobilie
#[Assert\Length(min: 5, max: 255)] #[Assert\Length(min: 5, max: 255)]
private string $adresse; private string $adresse;
#[ORM\Column(type: 'decimal', precision: 10, scale: 2)] #[ORM\Column(type: 'integer')]
#[Assert\NotBlank] #[Assert\NotBlank]
#[Assert\Positive] #[Assert\Positive]
private float $preis; private int $wohnflaeche;
#[ORM\Column(type: 'decimal', precision: 8, scale: 2)] #[ORM\Column(type: 'integer')]
#[Assert\NotBlank] #[Assert\NotBlank]
#[Assert\Positive] #[Assert\PositiveOrZero]
private float $flaeche; private int $nutzflaeche;
#[ORM\Column(type: 'boolean')] #[ORM\Column(type: 'boolean')]
private bool $garage = false; private bool $garage = false;
@@ -58,28 +57,26 @@ class Immobilie
#[ORM\Column(type: 'text', nullable: true)] #[ORM\Column(type: 'text', nullable: true)]
private ?string $beschreibung = null; private ?string $beschreibung = null;
#[ORM\Column(type: 'boolean')]
private bool $verfuegbar = true;
#[ORM\Column(type: 'integer', nullable: true)]
#[Assert\PositiveOrZero]
private ?int $balkonFlaeche = null;
#[ORM\Column(type: 'integer', nullable: true)]
#[Assert\PositiveOrZero]
private ?int $kellerFlaeche = null;
#[ORM\Column(type: 'integer', nullable: true)] #[ORM\Column(type: 'integer', nullable: true)]
#[Assert\Min(0)] #[Assert\Min(0)]
#[Assert\Max(10)] #[Assert\Max(10)]
private ?int $etage = null; private ?int $etage = null;
#[ORM\Column(type: 'string', length: 100, nullable: true)] #[ORM\ManyToOne(targetEntity: Heizungstyp::class, inversedBy: 'immobilien')]
private ?string $heizungstyp = null; #[ORM\JoinColumn(nullable: true)]
private ?Heizungstyp $heizungstyp = null;
#[ORM\Column(type: 'decimal', precision: 6, scale: 2, nullable: true)] #[ORM\Column(type: 'integer', nullable: true)]
#[Assert\Range(min: 0, max: 100)]
private ?int $abschreibungszeit = null;
#[ORM\ManyToOne(targetEntity: Bundesland::class, inversedBy: 'immobilien')]
#[ORM\JoinColumn(nullable: true)]
private ?Bundesland $bundesland = null;
#[ORM\Column(type: 'integer', nullable: true)]
#[Assert\PositiveOrZero] #[Assert\PositiveOrZero]
private ?float $nebenkosten = null; private ?int $kaufpreis = null;
#[ORM\Column(type: 'datetime')] #[ORM\Column(type: 'datetime')]
private \DateTimeInterface $createdAt; private \DateTimeInterface $createdAt;
@@ -92,6 +89,7 @@ class Immobilie
$this->createdAt = new \DateTime(); $this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime(); $this->updatedAt = new \DateTime();
$this->typ = ImmobilienTyp::WOHNUNG; $this->typ = ImmobilienTyp::WOHNUNG;
$this->nutzflaeche = 0;
} }
#[ORM\PreUpdate] #[ORM\PreUpdate]
@@ -116,25 +114,25 @@ class Immobilie
return $this; return $this;
} }
public function getPreis(): float public function getWohnflaeche(): int
{ {
return $this->preis; return $this->wohnflaeche;
} }
public function setPreis(float $preis): self public function setWohnflaeche(int $wohnflaeche): self
{ {
$this->preis = $preis; $this->wohnflaeche = $wohnflaeche;
return $this; return $this;
} }
public function getFlaeche(): float public function getNutzflaeche(): int
{ {
return $this->flaeche; return $this->nutzflaeche;
} }
public function setFlaeche(float $flaeche): self public function setNutzflaeche(int $nutzflaeche): self
{ {
$this->flaeche = $flaeche; $this->nutzflaeche = $nutzflaeche;
return $this; return $this;
} }
@@ -198,39 +196,6 @@ class Immobilie
return $this; return $this;
} }
public function isVerfuegbar(): bool
{
return $this->verfuegbar;
}
public function setVerfuegbar(bool $verfuegbar): self
{
$this->verfuegbar = $verfuegbar;
return $this;
}
public function getBalkonFlaeche(): ?int
{
return $this->balkonFlaeche;
}
public function setBalkonFlaeche(?int $balkonFlaeche): self
{
$this->balkonFlaeche = $balkonFlaeche;
return $this;
}
public function getKellerFlaeche(): ?int
{
return $this->kellerFlaeche;
}
public function setKellerFlaeche(?int $kellerFlaeche): self
{
$this->kellerFlaeche = $kellerFlaeche;
return $this;
}
public function getEtage(): ?int public function getEtage(): ?int
{ {
return $this->etage; return $this->etage;
@@ -242,28 +207,17 @@ class Immobilie
return $this; return $this;
} }
public function getHeizungstyp(): ?string public function getHeizungstyp(): ?Heizungstyp
{ {
return $this->heizungstyp; return $this->heizungstyp;
} }
public function setHeizungstyp(?string $heizungstyp): self public function setHeizungstyp(?Heizungstyp $heizungstyp): self
{ {
$this->heizungstyp = $heizungstyp; $this->heizungstyp = $heizungstyp;
return $this; return $this;
} }
public function getNebenkosten(): ?float
{
return $this->nebenkosten;
}
public function setNebenkosten(?float $nebenkosten): self
{
$this->nebenkosten = $nebenkosten;
return $this;
}
public function getCreatedAt(): \DateTimeInterface public function getCreatedAt(): \DateTimeInterface
{ {
return $this->createdAt; return $this->createdAt;
@@ -286,6 +240,39 @@ class Immobilie
return $this; return $this;
} }
public function getAbschreibungszeit(): ?int
{
return $this->abschreibungszeit;
}
public function setAbschreibungszeit(?int $abschreibungszeit): self
{
$this->abschreibungszeit = $abschreibungszeit;
return $this;
}
public function getBundesland(): ?Bundesland
{
return $this->bundesland;
}
public function setBundesland(?Bundesland $bundesland): self
{
$this->bundesland = $bundesland;
return $this;
}
public function getKaufpreis(): ?int
{
return $this->kaufpreis;
}
public function setKaufpreis(?int $kaufpreis): self
{
$this->kaufpreis = $kaufpreis;
return $this;
}
public function getVerwalter(): User public function getVerwalter(): User
{ {
return $this->verwalter; return $this->verwalter;
@@ -298,28 +285,45 @@ class Immobilie
} }
/** /**
* Berechnet den Preis pro Quadratmeter * Berechnet die Gesamtfläche (Wohnfläche + Nutzfläche)
*/ */
public function getPreisProQm(): float public function getGesamtflaeche(): int
{ {
if ($this->flaeche > 0) { return $this->wohnflaeche + $this->nutzflaeche;
return round($this->preis / $this->flaeche, 2);
}
return 0;
} }
/** /**
* Berechnet die Gesamtfläche inkl. Balkon und Keller * Berechnet die Kaufnebenkosten basierend auf dem Bundesland
* Rückgabe: Array mit Notar, Grundbuch, Grunderwerbsteuer und Gesamt
*/ */
public function getGesamtflaeche(): float public function getKaufnebenkosten(): array
{ {
$gesamt = $this->flaeche; if (!$this->kaufpreis || !$this->bundesland) {
if ($this->balkonFlaeche) { return [
$gesamt += $this->balkonFlaeche; 'notar' => 0,
'grundbuch' => 0,
'grunderwerbsteuer' => 0,
'gesamt' => 0
];
} }
if ($this->kellerFlaeche) {
$gesamt += $this->kellerFlaeche; // Notarkosten: ca. 1,5% des Kaufpreises
} $notar = (int) round($this->kaufpreis * 0.015);
return $gesamt;
// Grundbuchkosten: ca. 0,5% des Kaufpreises
$grundbuch = (int) round($this->kaufpreis * 0.005);
// Grunderwerbsteuer: abhängig vom Bundesland
$grunderwerbsteuerSatz = $this->bundesland->getGrunderwerbsteuer() / 100;
$grunderwerbsteuer = (int) round($this->kaufpreis * $grunderwerbsteuerSatz);
$gesamt = $notar + $grundbuch + $grunderwerbsteuer;
return [
'notar' => $notar,
'grundbuch' => $grundbuch,
'grunderwerbsteuer' => $grunderwerbsteuer,
'gesamt' => $gesamt
];
} }
} }

71
src/Enum/Bundesland.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
namespace App\Enum;
enum Bundesland: string
{
case BADEN_WUERTTEMBERG = 'baden_wuerttemberg';
case BAYERN = 'bayern';
case BERLIN = 'berlin';
case BRANDENBURG = 'brandenburg';
case BREMEN = 'bremen';
case HAMBURG = 'hamburg';
case HESSEN = 'hessen';
case MECKLENBURG_VORPOMMERN = 'mecklenburg_vorpommern';
case NIEDERSACHSEN = 'niedersachsen';
case NORDRHEIN_WESTFALEN = 'nordrhein_westfalen';
case RHEINLAND_PFALZ = 'rheinland_pfalz';
case SAARLAND = 'saarland';
case SACHSEN = 'sachsen';
case SACHSEN_ANHALT = 'sachsen_anhalt';
case SCHLESWIG_HOLSTEIN = 'schleswig_holstein';
case THUERINGEN = 'thueringen';
public function getLabel(): string
{
return match($this) {
self::BADEN_WUERTTEMBERG => 'Baden-Württemberg',
self::BAYERN => 'Bayern',
self::BERLIN => 'Berlin',
self::BRANDENBURG => 'Brandenburg',
self::BREMEN => 'Bremen',
self::HAMBURG => 'Hamburg',
self::HESSEN => 'Hessen',
self::MECKLENBURG_VORPOMMERN => 'Mecklenburg-Vorpommern',
self::NIEDERSACHSEN => 'Niedersachsen',
self::NORDRHEIN_WESTFALEN => 'Nordrhein-Westfalen',
self::RHEINLAND_PFALZ => 'Rheinland-Pfalz',
self::SAARLAND => 'Saarland',
self::SACHSEN => 'Sachsen',
self::SACHSEN_ANHALT => 'Sachsen-Anhalt',
self::SCHLESWIG_HOLSTEIN => 'Schleswig-Holstein',
self::THUERINGEN => 'Thüringen',
};
}
/**
* Gibt die Grunderwerbsteuer in Prozent für das Bundesland zurück
* Stand: 2025
*/
public function getGrunderwerbsteuer(): float
{
return match($this) {
self::BADEN_WUERTTEMBERG => 5.0,
self::BAYERN => 3.5,
self::BERLIN => 6.0,
self::BRANDENBURG => 6.5,
self::BREMEN => 5.0,
self::HAMBURG => 5.5,
self::HESSEN => 6.0,
self::MECKLENBURG_VORPOMMERN => 6.0,
self::NIEDERSACHSEN => 5.0,
self::NORDRHEIN_WESTFALEN => 6.5,
self::RHEINLAND_PFALZ => 5.0,
self::SAARLAND => 6.5,
self::SACHSEN => 5.5,
self::SACHSEN_ANHALT => 5.0,
self::SCHLESWIG_HOLSTEIN => 6.5,
self::THUERINGEN => 5.0,
};
}
}

19
src/Enum/Heizungstyp.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Enum;
enum Heizungstyp: string
{
case GASHEIZUNG = 'gasheizung';
case WAERMEPUMPE = 'waermepumpe';
case OELHEIZUNG = 'oelheizung';
public function getLabel(): string
{
return match($this) {
self::GASHEIZUNG => 'Gasheizung',
self::WAERMEPUMPE => 'Wärmepumpe',
self::OELHEIZUNG => 'Ölheizung',
};
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Repository;
use App\Entity\Bundesland;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class BundeslandRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Bundesland::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Repository;
use App\Entity\Heizungstyp;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class HeizungstypRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Heizungstyp::class);
}
}