locale stuff

This commit is contained in:
Wolfgang Hottgenroth 2021-09-09 18:00:24 +02:00
parent 8276e39a7e
commit 6fcd785be0
Signed by: wn
GPG Key ID: 6C1E5E531E0D5D7F
16 changed files with 250 additions and 23 deletions

View File

@ -49,3 +49,27 @@
$ref: '#/components/schemas/fee' $ref: '#/components/schemas/fee'
security: security:
- jwt: ['secret'] - jwt: ['secret']
/v1/account/saldo/{accountId}:
get:
tags: [ "account" ]
summary: Return saldo of the account
operationId: additional_methods.get_account_saldo
parameters:
- name: accountId
in: path
required: true
schema:
type: integer
responses:
'200':
description: get_account_saldo
content:
'application/json':
schema:
type: object
properties:
saldo:
type: number
security:
- jwt: ['secret']

View File

@ -25,3 +25,10 @@ SELECT o.id, o.description, o.amount, o.fee_type, o.startdate, o.enddate
"params": (tenancyId, ) "params": (tenancyId, )
} }
) )
def get_account_saldo(user, token_info, accountId=None):
return dbGetOne(user, token_info, {
"statement": "SELECT sum(amount) as saldo FROM account_entry_t WHERE account=%s",
"params": (accountId, )
}
)

View File

@ -1244,6 +1244,8 @@ SELECT
,created_at ,created_at
,amount ,amount
FROM account_entry_t FROM account_entry_t
ORDER BY
amount
""", """,
"params": () "params": ()
} }

View File

@ -1308,6 +1308,30 @@ paths:
$ref: '#/components/schemas/fee' $ref: '#/components/schemas/fee'
security: security:
- jwt: ['secret'] - jwt: ['secret']
/v1/account/saldo/{accountId}:
get:
tags: [ "account" ]
summary: Return saldo of the account
operationId: additional_methods.get_account_saldo
parameters:
- name: accountId
in: path
required: true
schema:
type: integer
responses:
'200':
description: get_account_saldo
content:
'application/json':
schema:
type: object
properties:
saldo:
type: number
security:
- jwt: ['secret']
components: components:
securitySchemes: securitySchemes:

View File

@ -115,7 +115,7 @@
{ "name": "description", "sqltype": "varchar(128)", "notnull": true }, { "name": "description", "sqltype": "varchar(128)", "notnull": true },
{ "name": "account", "sqltype": "integer", "notnull": true, "foreignkey": true }, { "name": "account", "sqltype": "integer", "notnull": true, "foreignkey": true },
{ "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" }, { "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" },
{ "name": "amount", "sqltype": "numeric(10,2)", "notnull": true } { "name": "amount", "sqltype": "numeric(10,2)", "notnull": true, "selector": 0 }
] ]
} }
] ]

View File

@ -460,6 +460,141 @@
"tslib": "^2.0.0" "tslib": "^2.0.0"
} }
}, },
"@angular/localize": {
"version": "11.0.9",
"resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.0.9.tgz",
"integrity": "sha512-5NtyqCcBN8G6muXpyrHuVHTdD9slpyUAl6vF6NbyejgVeuV35wPXwIa+3qauPiVlFGEBQpn/uKAU57mVGm8WUg==",
"dev": true,
"requires": {
"@babel/core": "7.8.3",
"glob": "7.1.2",
"yargs": "^16.1.1"
},
"dependencies": {
"@babel/core": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
"integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@babel/generator": "^7.8.3",
"@babel/helpers": "^7.8.3",
"@babel/parser": "^7.8.3",
"@babel/template": "^7.8.3",
"@babel/traverse": "^7.8.3",
"@babel/types": "^7.8.3",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.1",
"json5": "^2.1.0",
"lodash": "^4.17.13",
"resolve": "^1.3.2",
"semver": "^5.4.1",
"source-map": "^0.5.0"
}
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true
}
}
},
"@angular/material": { "@angular/material": {
"version": "11.2.13", "version": "11.2.13",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-11.2.13.tgz", "resolved": "https://registry.npmjs.org/@angular/material/-/material-11.2.13.tgz",

View File

@ -31,6 +31,7 @@
"@angular-devkit/build-angular": "~0.1100.6", "@angular-devkit/build-angular": "~0.1100.6",
"@angular/cli": "~11.0.6", "@angular/cli": "~11.0.6",
"@angular/compiler-cli": "~11.0.6", "@angular/compiler-cli": "~11.0.6",
"@angular/localize": "^11.0.9",
"@types/jasmine": "~3.6.0", "@types/jasmine": "~3.6.0",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
"codelyzer": "^6.0.0", "codelyzer": "^6.0.0",

View File

@ -24,4 +24,8 @@ table {
.rightaligned { .rightaligned {
justify-self: right; justify-self: right;
}
.large {
font-size: large;
} }

View File

@ -10,7 +10,7 @@
(closed)="collapse = false"> (closed)="collapse = false">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title *ngIf="!collapse"> <mat-panel-title *ngIf="!collapse">
Kontoübersicht Kontoübersicht, Saldo: {{saldo?.saldo | number:'1.2-2'}} €
</mat-panel-title> </mat-panel-title>
<mat-panel-description> <mat-panel-description>
</mat-panel-description> </mat-panel-description>
@ -34,6 +34,9 @@
<button #addAccountEntryButton type="submit" mat-raised-button color="primary">Buchung speichern</button> <button #addAccountEntryButton type="submit" mat-raised-button color="primary">Buchung speichern</button>
</form> </form>
</div> </div>
<div class="large">
Saldo: {{saldo?.saldo | number:'1.2-2'}} €
</div>
<div id="secondBlock"> <div id="secondBlock">
<table mat-table [dataSource]="accountEntriesDataSource" #zftable> <table mat-table [dataSource]="accountEntriesDataSource" #zftable>
<ng-container matColumnDef="description"> <ng-container matColumnDef="description">

View File

@ -3,6 +3,8 @@ import { MatButton } from '@angular/material/button';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { AccountEntryService, AccountService } from '../data-object-service'; import { AccountEntryService, AccountService } from '../data-object-service';
import { Account, AccountEntry, NULL_AccountEntry } from '../data-objects'; import { Account, AccountEntry, NULL_AccountEntry } from '../data-objects';
import { ExtApiService } from '../ext-data-object-service';
import { Saldo } from '../ext-data-objects';
import { MessageService } from '../message.service'; import { MessageService } from '../message.service';
@Component({ @Component({
@ -21,6 +23,8 @@ export class AccountComponent implements OnInit {
accountEntries: AccountEntry[] accountEntries: AccountEntry[]
accountEntriesDataSource: MatTableDataSource<AccountEntry> accountEntriesDataSource: MatTableDataSource<AccountEntry>
accountEntriesDisplayedColumns: string[] = [ "description", "amount", "createdAt" ] accountEntriesDisplayedColumns: string[] = [ "description", "amount", "createdAt" ]
saldo: Saldo
newAccountEntry: AccountEntry = NULL_AccountEntry newAccountEntry: AccountEntry = NULL_AccountEntry
@ -28,6 +32,7 @@ export class AccountComponent implements OnInit {
constructor( constructor(
private accountService: AccountService, private accountService: AccountService,
private accountEntryService: AccountEntryService, private accountEntryService: AccountEntryService,
private extApiService: ExtApiService,
private messageService: MessageService private messageService: MessageService
) { } ) { }
@ -47,8 +52,10 @@ export class AccountComponent implements OnInit {
async getAccountEntries(): Promise<void> { async getAccountEntries(): Promise<void> {
try { try {
this.accountEntries = await this.accountEntryService.getAccountEntrysByAccount(this.selectedAccountId) this.accountEntries = await this.accountEntryService.getAccountEntrysByAccount(this.selectedAccountId)
this.accountEntries.reverse()
this.messageService.add(`AccountEntries: ${JSON.stringify(this.accountEntries, undefined, 4)}`) this.messageService.add(`AccountEntries: ${JSON.stringify(this.accountEntries, undefined, 4)}`)
this.accountEntriesDataSource = new MatTableDataSource<AccountEntry>(this.accountEntries) this.accountEntriesDataSource = new MatTableDataSource<AccountEntry>(this.accountEntries)
this.saldo = await this.extApiService.getAccountSaldo(this.selectedAccountId)
} catch (err) { } catch (err) {
this.messageService.add(`Error in getAccountEntries: ${JSON.stringify(err, undefined, 4)}`) this.messageService.add(`Error in getAccountEntries: ${JSON.stringify(err, undefined, 4)}`)
} }
@ -61,7 +68,7 @@ export class AccountComponent implements OnInit {
this.messageService.add(`addAccountEntry: ${ JSON.stringify(this.newAccountEntry, undefined, 4) }`) this.messageService.add(`addAccountEntry: ${ JSON.stringify(this.newAccountEntry, undefined, 4) }`)
this.newAccountEntry = await this.accountEntryService.postAccountEntry(this.newAccountEntry) this.newAccountEntry = await this.accountEntryService.postAccountEntry(this.newAccountEntry)
this.messageService.add(`New accountEntry created: ${this.newAccountEntry.id}`) this.messageService.add(`New accountEntry created: ${this.newAccountEntry.id}`)
this.newAccountEntry = { 'account': this.account.id, 'amount': 0, 'created_at': '', 'description': '', 'id': 0 } this.newAccountEntry = { 'account': this.account.id, 'amount': undefined, 'created_at': '', 'description': '', 'id': 0 }
this.getAccountEntries() this.getAccountEntries()
} catch (err) { } catch (err) {
this.messageService.add(`Error in addAccountEntry: ${JSON.stringify(err, undefined, 4)}`) this.messageService.add(`Error in addAccountEntry: ${JSON.stringify(err, undefined, 4)}`)

View File

@ -1,5 +1,7 @@
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { LOCALE_ID, NgModule } from '@angular/core';
import localeDe from '@angular/common/locales/de';
import { registerLocaleData } from '@angular/common';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -43,6 +45,8 @@ import { FeeDetailsComponent } from './fee-details/fee-details.component';
import { MatExpansionModule } from '@angular/material/expansion'; import { MatExpansionModule } from '@angular/material/expansion';
import { AccountComponent } from './account/account.component' import { AccountComponent } from './account/account.component'
registerLocaleData(localeDe)
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
@ -92,6 +96,7 @@ import { AccountComponent } from './account/account.component'
providers: [ providers: [
{ provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: AuthHandlerInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: AuthHandlerInterceptor, multi: true },
{ provide: LOCALE_ID, useValue: 'de' },
MatNativeDateModule MatNativeDateModule
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -43,7 +43,7 @@ export const NULL_Tenant: Tenant = {
,phone1: '' ,phone1: ''
,phone2: '' ,phone2: ''
,iban: '' ,iban: ''
,account: 0 ,account: undefined
} }
export interface Premise { export interface Premise {
@ -71,9 +71,9 @@ export interface Flat {
export const NULL_Flat: Flat = { export const NULL_Flat: Flat = {
id: 0 id: 0
,description: '' ,description: ''
,premise: 0 ,premise: undefined
,area: 0 ,area: undefined
,flat_no: 0 ,flat_no: undefined
} }
export interface OverheadAdvance { export interface OverheadAdvance {
@ -86,7 +86,7 @@ export interface OverheadAdvance {
export const NULL_OverheadAdvance: OverheadAdvance = { export const NULL_OverheadAdvance: OverheadAdvance = {
id: 0 id: 0
,description: '' ,description: ''
,amount: 0 ,amount: undefined
,startdate: '' ,startdate: ''
,enddate: '' ,enddate: ''
} }
@ -98,8 +98,8 @@ export interface OverheadAdvanceFlatMapping {
} }
export const NULL_OverheadAdvanceFlatMapping: OverheadAdvanceFlatMapping = { export const NULL_OverheadAdvanceFlatMapping: OverheadAdvanceFlatMapping = {
id: 0 id: 0
,overhead_advance: 0 ,overhead_advance: undefined
,flat: 0 ,flat: undefined
} }
export interface Parking { export interface Parking {
@ -110,7 +110,7 @@ export interface Parking {
export const NULL_Parking: Parking = { export const NULL_Parking: Parking = {
id: 0 id: 0
,description: '' ,description: ''
,premise: 0 ,premise: undefined
} }
export interface CommercialPremise { export interface CommercialPremise {
@ -121,7 +121,7 @@ export interface CommercialPremise {
export const NULL_CommercialPremise: CommercialPremise = { export const NULL_CommercialPremise: CommercialPremise = {
id: 0 id: 0
,description: '' ,description: ''
,premise: 0 ,premise: undefined
} }
export interface Tenancy { export interface Tenancy {
@ -137,10 +137,10 @@ export interface Tenancy {
export const NULL_Tenancy: Tenancy = { export const NULL_Tenancy: Tenancy = {
id: 0 id: 0
,description: '' ,description: ''
,tenant: 0 ,tenant: undefined
,flat: 0 ,flat: undefined
,parking: 0 ,parking: undefined
,commercial_premise: 0 ,commercial_premise: undefined
,startdate: '' ,startdate: ''
,enddate: '' ,enddate: ''
} }
@ -156,7 +156,7 @@ export interface Fee {
export const NULL_Fee: Fee = { export const NULL_Fee: Fee = {
id: 0 id: 0
,description: '' ,description: ''
,amount: 0 ,amount: undefined
,fee_type: '' ,fee_type: ''
,startdate: '' ,startdate: ''
,enddate: '' ,enddate: ''
@ -169,8 +169,8 @@ export interface TenancyFeeMapping {
} }
export const NULL_TenancyFeeMapping: TenancyFeeMapping = { export const NULL_TenancyFeeMapping: TenancyFeeMapping = {
id: 0 id: 0
,tenancy: 0 ,tenancy: undefined
,fee: 0 ,fee: undefined
} }
export interface AccountEntry { export interface AccountEntry {
@ -183,9 +183,9 @@ export interface AccountEntry {
export const NULL_AccountEntry: AccountEntry = { export const NULL_AccountEntry: AccountEntry = {
id: 0 id: 0
,description: '' ,description: ''
,account: 0 ,account: undefined
,created_at: '' ,created_at: ''
,amount: 0 ,amount: undefined
} }

View File

@ -16,7 +16,7 @@ export const NULL_$JsNameConverter($table.name): $JsNameConverter($table.name) =
#if $column.jstype == "string" #if $column.jstype == "string"
'' ''
#else if $column.jstype == "number" #else if $column.jstype == "number"
0 undefined
#end if #end if
#end for #end for
} }

View File

@ -7,6 +7,7 @@ import { serviceBaseUrl } from './config';
import { Fee, OverheadAdvance } from './data-objects'; import { Fee, OverheadAdvance } from './data-objects';
import { Saldo } from './ext-data-objects';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
@ -22,4 +23,9 @@ export class ExtApiService {
this.messageService.add(`ExtApiService: get fees by flat ${id}`); this.messageService.add(`ExtApiService: get fees by flat ${id}`);
return this.http.get<Fee[]>(`${serviceBaseUrl}/v1/fees/tenancy/${id}`).toPromise() return this.http.get<Fee[]>(`${serviceBaseUrl}/v1/fees/tenancy/${id}`).toPromise()
} }
async getAccountSaldo(id: number): Promise<Saldo> {
this.messageService.add(`ExtApiService: get saldo for account ${id}`);
return this.http.get<Saldo>(`${serviceBaseUrl}/v1/account/saldo/${id}`).toPromise()
}
} }

View File

@ -0,0 +1,5 @@
export interface Saldo {
saldo: number
}

View File

@ -1,3 +1,7 @@
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
/** /**
* This file includes polyfills needed by Angular and is loaded before the app. * This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file. * You can add your own extra polyfills to this file.