API updadte
This commit is contained in:
134
README.md
134
README.md
@@ -98,6 +98,8 @@ Die vollständige API-Dokumentation mit allen Endpunkten, Beispielen und interak
|
||||
Wichtigste Endpunkte:
|
||||
- **Immobilien**: `/api/immobilies` (GET, POST, PATCH, 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
|
||||
|
||||
@@ -111,6 +113,30 @@ Wichtigste Endpunkte:
|
||||
| role | ENUM | Benutzerrolle (user, admin, moderator) |
|
||||
| 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
|
||||
|
||||
| Feld | Typ | Beschreibung |
|
||||
@@ -118,25 +144,27 @@ Wichtigste Endpunkte:
|
||||
| id | INT | Primärschlüssel (Auto-Increment) |
|
||||
| verwalter_id | INT | Foreign Key zu User (Verwalter der Immobilie) |
|
||||
| adresse | VARCHAR(255) | Vollständige Adresse (5-255 Zeichen) |
|
||||
| preis | DECIMAL | Kaufpreis oder Miete |
|
||||
| flaeche | DECIMAL | Wohnfläche in m² |
|
||||
| wohnflaeche | INT | Wohnfläche in m² (ganze Zahl) |
|
||||
| nutzflaeche | INT | Nutzfläche in m² (ganze Zahl) |
|
||||
| garage | BOOLEAN | Hat Garage? (Standard: false) |
|
||||
| zimmer | INT | Anzahl Zimmer (> 0) |
|
||||
| baujahr | INT | Baujahr (1800-2100, optional) |
|
||||
| typ | ENUM | Immobilientyp (wohnung, haus, grundstueck, gewerbe, buero) |
|
||||
| beschreibung | TEXT | Freitextbeschreibung (optional) |
|
||||
| verfuegbar | BOOLEAN | Verfügbarkeit (Standard: true) |
|
||||
| balkon_flaeche | INT | Balkonfläche in m² (optional) |
|
||||
| keller_flaeche | INT | Kellerfläche in m² (optional) |
|
||||
| etage | INT | Stockwerk (optional) |
|
||||
| heizungstyp | VARCHAR(255) | Art der Heizung (optional) |
|
||||
| nebenkosten | DECIMAL | Monatliche Nebenkosten (optional) |
|
||||
| etage | INT | Stockwerk (0-10, optional) |
|
||||
| heizungstyp_id | INT | Foreign Key zu Heizungstyp (optional) |
|
||||
| abschreibungszeit | INT | Abschreibungszeit in Jahren (0-100, optional) |
|
||||
| bundesland_id | INT | Foreign Key zu Bundesland (optional) |
|
||||
| kaufpreis | INT | Kaufpreis in Euro (ganze Zahl, optional) |
|
||||
| created_at | DATETIME | Erstellungsdatum |
|
||||
| updated_at | DATETIME | Letzte Aktualisierung |
|
||||
|
||||
**Berechnete Felder (nicht in DB gespeichert):**
|
||||
- `preis_pro_qm`: Preis / Fläche
|
||||
- `gesamtflaeche`: Fläche + Balkon + Keller
|
||||
- `gesamtflaeche`: Wohnfläche + Nutzfläche
|
||||
- `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
|
||||
|
||||
@@ -444,8 +472,49 @@ curl -H "Accept: application/ld+json" http://localhost:8080/api/users
|
||||
| PUT | `/api/users/{id}` | User vollständig ersetzen |
|
||||
| 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
|
||||
|
||||
#### 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
|
||||
|
||||
```bash
|
||||
@@ -454,13 +523,17 @@ curl -X POST http://localhost:8080/api/immobilies \
|
||||
-d '{
|
||||
"verwalter": "/api/users/1",
|
||||
"adresse": "Hauptstraße 123, 12345 Musterstadt",
|
||||
"preis": "250000",
|
||||
"flaeche": "85.5",
|
||||
"wohnflaeche": 85,
|
||||
"nutzflaeche": 15,
|
||||
"zimmer": 3,
|
||||
"typ": "wohnung",
|
||||
"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 \
|
||||
-H "Content-Type: application/merge-patch+json" \
|
||||
-d '{
|
||||
"preis": "260000",
|
||||
"verfuegbar": false
|
||||
"wohnflaeche": 90,
|
||||
"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:
|
||||
|
||||
- **preisProQm**: Berechnet automatisch den Preis pro Quadratmeter
|
||||
- **gesamtflaeche**: Summiert Wohnfläche + Balkonfläche + Kellerfläche
|
||||
- **gesamtflaeche**: Berechnet die Gesamtfläche (Wohnfläche + Nutzflä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.
|
||||
|
||||
### 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
|
||||
|
||||
Bei Verwendung des JSON-LD Formats (Standard) bietet die API Hydra-Unterstützung:
|
||||
|
||||
31
migrations/Version20251108213222.php
Normal file
31
migrations/Version20251108213222.php
Normal 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');
|
||||
}
|
||||
}
|
||||
43
migrations/Version20251108214500.php
Normal file
43
migrations/Version20251108214500.php
Normal 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
69
src/Entity/Bundesland.php
Normal 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;
|
||||
}
|
||||
}
|
||||
53
src/Entity/Heizungstyp.php
Normal file
53
src/Entity/Heizungstyp.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ use App\Enum\ImmobilienTyp;
|
||||
use App\Repository\ImmobilieRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ImmobilieRepository::class)]
|
||||
#[ORM\Table(name: 'immobilien')]
|
||||
@@ -30,15 +29,15 @@ class Immobilie
|
||||
#[Assert\Length(min: 5, max: 255)]
|
||||
private string $adresse;
|
||||
|
||||
#[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Positive]
|
||||
private float $preis;
|
||||
private int $wohnflaeche;
|
||||
|
||||
#[ORM\Column(type: 'decimal', precision: 8, scale: 2)]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Positive]
|
||||
private float $flaeche;
|
||||
#[Assert\PositiveOrZero]
|
||||
private int $nutzflaeche;
|
||||
|
||||
#[ORM\Column(type: 'boolean')]
|
||||
private bool $garage = false;
|
||||
@@ -58,28 +57,26 @@ class Immobilie
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
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)]
|
||||
#[Assert\Min(0)]
|
||||
#[Assert\Max(10)]
|
||||
private ?int $etage = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 100, nullable: true)]
|
||||
private ?string $heizungstyp = null;
|
||||
#[ORM\ManyToOne(targetEntity: Heizungstyp::class, inversedBy: 'immobilien')]
|
||||
#[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]
|
||||
private ?float $nebenkosten = null;
|
||||
private ?int $kaufpreis = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
private \DateTimeInterface $createdAt;
|
||||
@@ -92,6 +89,7 @@ class Immobilie
|
||||
$this->createdAt = new \DateTime();
|
||||
$this->updatedAt = new \DateTime();
|
||||
$this->typ = ImmobilienTyp::WOHNUNG;
|
||||
$this->nutzflaeche = 0;
|
||||
}
|
||||
|
||||
#[ORM\PreUpdate]
|
||||
@@ -116,25 +114,25 @@ class Immobilie
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -198,39 +196,6 @@ class Immobilie
|
||||
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
|
||||
{
|
||||
return $this->etage;
|
||||
@@ -242,28 +207,17 @@ class Immobilie
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeizungstyp(): ?string
|
||||
public function getHeizungstyp(): ?Heizungstyp
|
||||
{
|
||||
return $this->heizungstyp;
|
||||
}
|
||||
|
||||
public function setHeizungstyp(?string $heizungstyp): self
|
||||
public function setHeizungstyp(?Heizungstyp $heizungstyp): self
|
||||
{
|
||||
$this->heizungstyp = $heizungstyp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNebenkosten(): ?float
|
||||
{
|
||||
return $this->nebenkosten;
|
||||
}
|
||||
|
||||
public function setNebenkosten(?float $nebenkosten): self
|
||||
{
|
||||
$this->nebenkosten = $nebenkosten;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeInterface
|
||||
{
|
||||
return $this->createdAt;
|
||||
@@ -286,6 +240,39 @@ class Immobilie
|
||||
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
|
||||
{
|
||||
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 round($this->preis / $this->flaeche, 2);
|
||||
}
|
||||
return 0;
|
||||
return $this->wohnflaeche + $this->nutzflaeche;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->balkonFlaeche) {
|
||||
$gesamt += $this->balkonFlaeche;
|
||||
if (!$this->kaufpreis || !$this->bundesland) {
|
||||
return [
|
||||
'notar' => 0,
|
||||
'grundbuch' => 0,
|
||||
'grunderwerbsteuer' => 0,
|
||||
'gesamt' => 0
|
||||
];
|
||||
}
|
||||
if ($this->kellerFlaeche) {
|
||||
$gesamt += $this->kellerFlaeche;
|
||||
}
|
||||
return $gesamt;
|
||||
|
||||
// Notarkosten: ca. 1,5% des Kaufpreises
|
||||
$notar = (int) round($this->kaufpreis * 0.015);
|
||||
|
||||
// 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
71
src/Enum/Bundesland.php
Normal 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
19
src/Enum/Heizungstyp.php
Normal 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',
|
||||
};
|
||||
}
|
||||
}
|
||||
15
src/Repository/BundeslandRepository.php
Normal file
15
src/Repository/BundeslandRepository.php
Normal 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);
|
||||
}
|
||||
}
|
||||
15
src/Repository/HeizungstypRepository.php
Normal file
15
src/Repository/HeizungstypRepository.php
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user