diff --git a/api/additional_endpoints.yaml b/api/additional_endpoints.yaml index 1872050..205f16a 100644 --- a/api/additional_endpoints.yaml +++ b/api/additional_endpoints.yaml @@ -8,7 +8,7 @@ /v1/overhead_advances/flat/{flatId}: get: tags: [ "overhead_advance", "flat" ] - summary: Return overhead_advances by $flat + summary: Return overhead_advances by flat operationId: additional_methods.get_overhead_advances_by_flat parameters: - name: flatId @@ -27,3 +27,25 @@ $ref: '#/components/schemas/overhead_advance' security: - jwt: ['secret'] + /v1/fees/tenancy/{tenancyId}: + get: + tags: [ "fee", "tenancy" ] + summary: Return fees by tenancy + operationId: additional_methods.get_fees_by_tenancy + parameters: + - name: tenancyId + in: path + required: true + schema: + type: integer + responses: + '200': + description: get_fees_by_tenancy response + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/fee' + security: + - jwt: ['secret'] diff --git a/api/additional_methods.py b/api/additional_methods.py index 4fb590d..b53149f 100644 --- a/api/additional_methods.py +++ b/api/additional_methods.py @@ -15,3 +15,13 @@ SELECT o.id ,o.description ,o.amount ,o.startdate ,o.enddate "params": (flatId, ) } ) + +def get_fees_by_tenancy(user, token_info, tenancyId=None): + return dbGetMany(user, token_info, { + "statement": """ +SELECT o.id, o.description, o.amount, o.fee_type, o.startdate, o.enddate + FROM fee_t o, tenancy_fee_mapping_t m + WHERE o.id = m.fee and m.tenancy = %s""", + "params": (tenancyId, ) + } + ) diff --git a/api/openapi.yaml b/api/openapi.yaml index be04a68..99f929f 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1267,7 +1267,7 @@ paths: /v1/overhead_advances/flat/{flatId}: get: tags: [ "overhead_advance", "flat" ] - summary: Return overhead_advances by $flat + summary: Return overhead_advances by flat operationId: additional_methods.get_overhead_advances_by_flat parameters: - name: flatId @@ -1286,6 +1286,28 @@ paths: $ref: '#/components/schemas/overhead_advance' security: - jwt: ['secret'] + /v1/fees/tenancy/{tenancyId}: + get: + tags: [ "fee", "tenancy" ] + summary: Return fees by tenancy + operationId: additional_methods.get_fees_by_tenancy + parameters: + - name: tenancyId + in: path + required: true + schema: + type: integer + responses: + '200': + description: get_fees_by_tenancy response + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/fee' + security: + - jwt: ['secret'] components: securitySchemes: diff --git a/ui/hv2-ui/src/app/ext-data-object-service.ts b/ui/hv2-ui/src/app/ext-data-object-service.ts index 61d7c72..1d8dce3 100644 --- a/ui/hv2-ui/src/app/ext-data-object-service.ts +++ b/ui/hv2-ui/src/app/ext-data-object-service.ts @@ -6,15 +6,20 @@ import { MessageService } from './message.service'; import { serviceBaseUrl } from './config'; -import { OverheadAdvance } from './data-objects'; +import { Fee, OverheadAdvance } from './data-objects'; @Injectable({ providedIn: 'root' }) -export class ExtOverheadAdvanceService { +export class ExtApiService { constructor(private messageService: MessageService, private http: HttpClient) { } - async getOverheadAdvancesByFlat(flatId: number): Promise { - this.messageService.add(`OverheadAdvanceService: get data by flat ${flatId}`); - return this.http.get(`${serviceBaseUrl}/v1/overhead_advances/flat/${flatId}`).toPromise() + async getOverheadAdvancesByFlat(id: number): Promise { + this.messageService.add(`ExtApiService: get overheadadvances by flat ${id}`); + return this.http.get(`${serviceBaseUrl}/v1/overhead_advances/flat/${id}`).toPromise() + } + + async getFeeByTenancies(id: number): Promise { + this.messageService.add(`ExtApiService: get fees by flat ${id}`); + return this.http.get(`${serviceBaseUrl}/v1/fees/tenancy/${id}`).toPromise() } } diff --git a/ui/hv2-ui/src/app/flat-details/flat-details.component.ts b/ui/hv2-ui/src/app/flat-details/flat-details.component.ts index 6fd0bd7..f7e7ac2 100644 --- a/ui/hv2-ui/src/app/flat-details/flat-details.component.ts +++ b/ui/hv2-ui/src/app/flat-details/flat-details.component.ts @@ -5,7 +5,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { FlatService, OverheadAdvanceFlatMappingService, OverheadAdvanceService, PremiseService } from '../data-object-service'; import { Flat, OverheadAdvance, OverheadAdvanceFlatMapping, Premise } from '../data-objects'; -import { ExtOverheadAdvanceService } from '../ext-data-object-service'; +import { ExtApiService } from '../ext-data-object-service'; import { MessageService } from '../message.service'; @Component({ @@ -45,7 +45,7 @@ export class FlatDetailsComponent implements OnInit { constructor( private flatService: FlatService, private premiseService: PremiseService, - private extOverheadAdvanceService: ExtOverheadAdvanceService, + private extApiService: ExtApiService, private overheadAdvanceService: OverheadAdvanceService, private overheadAdvanceFlatMappingService: OverheadAdvanceFlatMappingService, private messageService: MessageService, @@ -59,7 +59,7 @@ export class FlatDetailsComponent implements OnInit { if (id != 0) { this.flat = await this.flatService.getFlat(id) this.premise = await this.premiseService.getPremise(this.flat.premise) - this.mappedOverheadAdvances = await this.extOverheadAdvanceService.getOverheadAdvancesByFlat(this.flat.id) + this.mappedOverheadAdvances = await this.extApiService.getOverheadAdvancesByFlat(this.flat.id) this.dataSource = new MatTableDataSource(this.mappedOverheadAdvances) } } catch (err) { diff --git a/ui/hv2-ui/src/app/navigation/navigation.component.html b/ui/hv2-ui/src/app/navigation/navigation.component.html index c23c030..fe5168a 100644 --- a/ui/hv2-ui/src/app/navigation/navigation.component.html +++ b/ui/hv2-ui/src/app/navigation/navigation.component.html @@ -6,14 +6,14 @@ Menu Meine Mieter/innen -
+ Meine Wohnungen Meine Garagen Meine Büros -
+ Betriebskostensätze Mietsätze -
+ Meine Häuser diff --git a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.css b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.css index bbe34f1..ece0220 100644 --- a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.css +++ b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.css @@ -6,6 +6,10 @@ table { flex: 1 1 auto; } -#addoverheadfield { +#setenddatefield { + margin-right: 15px; +} + +#addfeefield { margin-right: 15px; } diff --git a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.html b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.html index c53257f..8d3ab4e 100644 --- a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.html +++ b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.html @@ -6,82 +6,82 @@ - - - - - Details - - + + + + + Details + + - -
-
+
- - Anrede - - - - Vorname - - - - Nachname - - -
- - Adresse 1 (Straße) - - - - Adresse 2 - - - - Adresse 3 - - -
- - PLZ - - - - Ort - - -
- - Telefon 1 - - - - Telefon 2 - - -
- - IBAN - - -
- - Account ID - - - - Account Description - - + +
+ + Anrede + + + + Vorname + + + + Nachname + + +
+ + Adresse 1 (Straße) + + + + Adresse 2 + + + + Adresse 3 + + +
+ + PLZ + + + + Ort + + +
+ + Telefon 1 + + + + Telefon 2 + + +
+ + IBAN + + +
+ + Account ID + + + + Account Description + + +
+ +
- - -
-
-
+
+
@@ -95,46 +95,112 @@ - - - Übersicht - - - - -
- + + + Übersicht + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Beschreibung{{element.rawTenancy.description}}Wohnung{{element.flat}}Garage{{element.parking}}Büro{{element.commercial_premise}}Beginn{{element.rawTenancy.startdate}}Ende{{element.rawTenancy.enddate}}
+
+
+
+ + + + + + + {{selectedTenancy.description}} + + + + + Mietdetails: {{selectedTenancy.description}} + +
+
+ + Ende + + + + + +
+
+ +
+ - + - - - + + + - - - - - - - + + + - + - + - - + +
Beschreibung{{element.rawTenancy.description}}{{element.description}} Wohnung{{element.flat}}Betrag{{element.amount}} € Garage{{element.parking}}Büro{{element.commercial_premise}}Typ{{element.fee_type}} € Beginn{{element.rawTenancy.startdate}}{{element.startdate}} Ende{{element.rawTenancy.enddate}}{{element.enddate}}
- - -
+
+
+ + Mietsatz + + {{p.description}} {{p.amount}} {{p.startdate}} + + + +
+ +
+ +
diff --git a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.ts b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.ts index 30a4d14..dd48160 100644 --- a/ui/hv2-ui/src/app/tenant-details/tenant-details.component.ts +++ b/ui/hv2-ui/src/app/tenant-details/tenant-details.component.ts @@ -1,10 +1,11 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { AccountService, CommercialPremiseService, FlatService, ParkingService, PremiseService, TenancyService, TenantService } from '../data-object-service'; -import { Account, CommercialPremise, Flat, NULL_Account, NULL_CommercialPremise, NULL_Flat, NULL_Parking, NULL_Tenant, Parking, Premise, Tenancy, Tenant } from '../data-objects'; +import { AccountService, CommercialPremiseService, FeeService, FlatService, ParkingService, PremiseService, TenancyFeeMappingService, TenancyService, TenantService } from '../data-object-service'; +import { Account, CommercialPremise, Fee, Flat, NULL_Account, NULL_CommercialPremise, NULL_Flat, NULL_Parking, NULL_Tenancy, NULL_Tenant, Parking, Premise, Tenancy, TenancyFeeMapping, Tenant } from '../data-objects'; import { MessageService } from '../message.service'; import { MatButton } from '@angular/material/button'; import { MatTableDataSource } from '@angular/material/table'; +import { ExtApiService } from '../ext-data-object-service'; interface DN_Tenancy { @@ -25,14 +26,23 @@ export class TenantDetailsComponent implements OnInit { account: Account = NULL_Account - tenancies: DN_Tenancy[] = [] + tenancies: DN_Tenancy[] tenancyDataSource: MatTableDataSource tenancyDisplayColumns: string[] = [ "description", "flat", "parking", "commercial_premise", "startdate", "enddate" ] collapseTenantDetails: boolean = false collapseTenancies: boolean = false + selectedTenancy: Tenancy = undefined + mappedFees: Fee[] + mappedFeesDataSource: MatTableDataSource + mappedFeesDisplayedColumns: string[] = [ "description", "amount", "fee_type", "startdate", "enddate" ] + allFees: Fee[] + selectedFee: number + + @ViewChild('submitButton') submitButton: MatButton + @ViewChild('mapFeeButton') mapFeeButton: MatButton constructor( private tenantService: TenantService, @@ -41,6 +51,9 @@ export class TenantDetailsComponent implements OnInit { private flatService: FlatService, private parkingService: ParkingService, private commercialPremiseService: CommercialPremiseService, + private tenancyFeeMappingService: TenancyFeeMappingService, + private feeService: FeeService, + private extApiService: ExtApiService, private premiseService: PremiseService, private messageService: MessageService, private route: ActivatedRoute, @@ -53,31 +66,39 @@ export class TenantDetailsComponent implements OnInit { if (id != 0) { this.tenant = await this.tenantService.getTenant(id) this.account = await this.accountService.getAccount(this.tenant.account) - - const premises: Premise[] = await this.premiseService.getPremises() - const premisesDict = new Map() - for (let p of premises) { - premisesDict.set(p.id, p) - } - for (let t of await this.tenancyService.getTenancysByTenant(this.tenant.id)) { - const flat: Flat = (t.flat) ? await this.flatService.getFlat(t.flat) : NULL_Flat - const parking: Parking = (t.parking) ? await this.parkingService.getParking(t.parking) : NULL_Parking - const commercialPremise: CommercialPremise = (t.commercial_premise) ? await this.commercialPremiseService.getCommercialPremise(t.commercial_premise) : NULL_CommercialPremise - this.tenancies.push({ - rawTenancy: t, - flat: (flat != NULL_Flat) ? `${flat.description} (${premisesDict.get(flat.premise).description})` : '', - parking: (parking != NULL_Parking) ? `${parking.description} (${premisesDict.get(parking.premise).description})` : '', - commercialPremise: (commercialPremise != NULL_CommercialPremise) ? `${commercialPremise.description} (${premisesDict.get(commercialPremise.premise).description})` : '' - }) - } - this.tenancyDataSource = new MatTableDataSource(this.tenancies) + this.getTenancies() } } catch (err) { this.messageService.add(JSON.stringify(err, undefined, 4)) } } - async saveTenant() { + async getTenancies(): Promise { + try { + this.tenancies = [] + const premises: Premise[] = await this.premiseService.getPremises() + const premisesDict = new Map() + for (let p of premises) { + premisesDict.set(p.id, p) + } + for (let t of await this.tenancyService.getTenancysByTenant(this.tenant.id)) { + const flat: Flat = (t.flat) ? await this.flatService.getFlat(t.flat) : NULL_Flat + const parking: Parking = (t.parking) ? await this.parkingService.getParking(t.parking) : NULL_Parking + const commercialPremise: CommercialPremise = (t.commercial_premise) ? await this.commercialPremiseService.getCommercialPremise(t.commercial_premise) : NULL_CommercialPremise + this.tenancies.push({ + rawTenancy: t, + flat: (flat != NULL_Flat) ? `${flat.description} (${premisesDict.get(flat.premise).description})` : '', + parking: (parking != NULL_Parking) ? `${parking.description} (${premisesDict.get(parking.premise).description})` : '', + commercialPremise: (commercialPremise != NULL_CommercialPremise) ? `${commercialPremise.description} (${premisesDict.get(commercialPremise.premise).description})` : '' + }) + } + this.tenancyDataSource = new MatTableDataSource(this.tenancies) + } catch (err) { + this.messageService.add(JSON.stringify(err, undefined, 4)) + } + } + + async saveTenant(): Promise { try { this.submitButton.disabled = true this.messageService.add("saveTenant") @@ -103,8 +124,54 @@ export class TenantDetailsComponent implements OnInit { } } + async setSelectedTenancy(selectedTenancy: Tenancy): Promise { + this.selectedTenancy = selectedTenancy + this.getMappedFees() + } + + async getMappedFees(): Promise { + this.mappedFees = await this.extApiService.getFeeByTenancies(this.selectedTenancy.id) + this.messageService.add(`setSelectedTenancy: mappedFees: ${JSON.stringify(this.mappedFees, undefined, 4)}`) + this.mappedFeesDataSource = new MatTableDataSource(this.mappedFees) + this.messageService.add("mappedFeesDataSource set") + } + + clearSelectedTenancy(): void { + this.selectedTenancy = undefined + } + + + async getFees(): Promise { + try { + this.messageService.add("Trying to load fees") + this.allFees = await this.feeService.getFees() + this.messageService.add("fees loaded") + } catch (err) { + this.messageService.add(JSON.stringify(err, undefined, 4)) + } + } + + async addFee() { + try { + this.mapFeeButton.disabled = true + this.messageService.add(`fee: ${ JSON.stringify(this.selectedFee, undefined, 4) }`) + let newMapping: TenancyFeeMapping = { + 'tenancy': this.selectedTenancy.id, + 'fee': this.selectedFee, + 'id': 0 + } + newMapping = await this.tenancyFeeMappingService.postTenancyFeeMapping(newMapping) + this.messageService.add(`New fee tenancy mapping created: ${newMapping.id}`) + this.selectedFee = undefined + this.getMappedFees() + } finally { + this.mapFeeButton.disabled = false + } + } + ngOnInit(): void { this.getTenant() + this.getFees() } }