From 6fcd785be05130e63f87d0e5120acca158e76f41 Mon Sep 17 00:00:00 2001 From: Wolfgang Ludger Hottgenroth Date: Thu, 9 Sep 2021 18:00:24 +0200 Subject: [PATCH] locale stuff --- api/additional_endpoints.yaml | 24 ++++ api/additional_methods.py | 7 + api/methods.py | 2 + api/openapi.yaml | 24 ++++ schema.json | 2 +- ui/hv2-ui/package-lock.json | 135 ++++++++++++++++++ ui/hv2-ui/package.json | 1 + .../src/app/account/account.component.css | 4 + .../src/app/account/account.component.html | 5 +- .../src/app/account/account.component.ts | 9 +- ui/hv2-ui/src/app/app.module.ts | 7 +- ui/hv2-ui/src/app/data-objects.ts | 36 ++--- ui/hv2-ui/src/app/data-objects.ts.tmpl | 2 +- ui/hv2-ui/src/app/ext-data-object-service.ts | 6 + ui/hv2-ui/src/app/ext-data-objects.ts | 5 + ui/hv2-ui/src/polyfills.ts | 4 + 16 files changed, 250 insertions(+), 23 deletions(-) create mode 100644 ui/hv2-ui/src/app/ext-data-objects.ts diff --git a/api/additional_endpoints.yaml b/api/additional_endpoints.yaml index 205f16a..d1c3735 100644 --- a/api/additional_endpoints.yaml +++ b/api/additional_endpoints.yaml @@ -49,3 +49,27 @@ $ref: '#/components/schemas/fee' security: - 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'] + diff --git a/api/additional_methods.py b/api/additional_methods.py index b53149f..0f8cf33 100644 --- a/api/additional_methods.py +++ b/api/additional_methods.py @@ -25,3 +25,10 @@ SELECT o.id, o.description, o.amount, o.fee_type, o.startdate, o.enddate "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, ) + } + ) \ No newline at end of file diff --git a/api/methods.py b/api/methods.py index 756b10d..7a2c91f 100644 --- a/api/methods.py +++ b/api/methods.py @@ -1244,6 +1244,8 @@ SELECT ,created_at ,amount FROM account_entry_t + ORDER BY + amount """, "params": () } diff --git a/api/openapi.yaml b/api/openapi.yaml index 99f929f..8e9190c 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1308,6 +1308,30 @@ paths: $ref: '#/components/schemas/fee' security: - 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: securitySchemes: diff --git a/schema.json b/schema.json index e76fc6d..1dedf98 100644 --- a/schema.json +++ b/schema.json @@ -115,7 +115,7 @@ { "name": "description", "sqltype": "varchar(128)", "notnull": true }, { "name": "account", "sqltype": "integer", "notnull": true, "foreignkey": true }, { "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 } ] } ] diff --git a/ui/hv2-ui/package-lock.json b/ui/hv2-ui/package-lock.json index 9eb7b46..1eb00b9 100644 --- a/ui/hv2-ui/package-lock.json +++ b/ui/hv2-ui/package-lock.json @@ -460,6 +460,141 @@ "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": { "version": "11.2.13", "resolved": "https://registry.npmjs.org/@angular/material/-/material-11.2.13.tgz", diff --git a/ui/hv2-ui/package.json b/ui/hv2-ui/package.json index 58153b2..2153046 100644 --- a/ui/hv2-ui/package.json +++ b/ui/hv2-ui/package.json @@ -31,6 +31,7 @@ "@angular-devkit/build-angular": "~0.1100.6", "@angular/cli": "~11.0.6", "@angular/compiler-cli": "~11.0.6", + "@angular/localize": "^11.0.9", "@types/jasmine": "~3.6.0", "@types/node": "^12.11.1", "codelyzer": "^6.0.0", diff --git a/ui/hv2-ui/src/app/account/account.component.css b/ui/hv2-ui/src/app/account/account.component.css index 98f3784..a36a8fc 100644 --- a/ui/hv2-ui/src/app/account/account.component.css +++ b/ui/hv2-ui/src/app/account/account.component.css @@ -24,4 +24,8 @@ table { .rightaligned { justify-self: right; +} + +.large { + font-size: large; } \ No newline at end of file diff --git a/ui/hv2-ui/src/app/account/account.component.html b/ui/hv2-ui/src/app/account/account.component.html index d0a7516..ec5db5d 100644 --- a/ui/hv2-ui/src/app/account/account.component.html +++ b/ui/hv2-ui/src/app/account/account.component.html @@ -10,7 +10,7 @@ (closed)="collapse = false"> - Kontoübersicht + Kontoübersicht, Saldo: {{saldo?.saldo | number:'1.2-2'}} € @@ -34,6 +34,9 @@ +
+ Saldo: {{saldo?.saldo | number:'1.2-2'}} € +
diff --git a/ui/hv2-ui/src/app/account/account.component.ts b/ui/hv2-ui/src/app/account/account.component.ts index e9db08e..a62a3f6 100644 --- a/ui/hv2-ui/src/app/account/account.component.ts +++ b/ui/hv2-ui/src/app/account/account.component.ts @@ -3,6 +3,8 @@ import { MatButton } from '@angular/material/button'; import { MatTableDataSource } from '@angular/material/table'; import { AccountEntryService, AccountService } from '../data-object-service'; 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'; @Component({ @@ -21,6 +23,8 @@ export class AccountComponent implements OnInit { accountEntries: AccountEntry[] accountEntriesDataSource: MatTableDataSource accountEntriesDisplayedColumns: string[] = [ "description", "amount", "createdAt" ] + saldo: Saldo + newAccountEntry: AccountEntry = NULL_AccountEntry @@ -28,6 +32,7 @@ export class AccountComponent implements OnInit { constructor( private accountService: AccountService, private accountEntryService: AccountEntryService, + private extApiService: ExtApiService, private messageService: MessageService ) { } @@ -47,8 +52,10 @@ export class AccountComponent implements OnInit { async getAccountEntries(): Promise { try { this.accountEntries = await this.accountEntryService.getAccountEntrysByAccount(this.selectedAccountId) + this.accountEntries.reverse() this.messageService.add(`AccountEntries: ${JSON.stringify(this.accountEntries, undefined, 4)}`) this.accountEntriesDataSource = new MatTableDataSource(this.accountEntries) + this.saldo = await this.extApiService.getAccountSaldo(this.selectedAccountId) } catch (err) { 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.newAccountEntry = await this.accountEntryService.postAccountEntry(this.newAccountEntry) 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() } catch (err) { this.messageService.add(`Error in addAccountEntry: ${JSON.stringify(err, undefined, 4)}`) diff --git a/ui/hv2-ui/src/app/app.module.ts b/ui/hv2-ui/src/app/app.module.ts index a64ed18..382d574 100644 --- a/ui/hv2-ui/src/app/app.module.ts +++ b/ui/hv2-ui/src/app/app.module.ts @@ -1,5 +1,7 @@ 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 { 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 { AccountComponent } from './account/account.component' +registerLocaleData(localeDe) + @NgModule({ declarations: [ AppComponent, @@ -92,6 +96,7 @@ import { AccountComponent } from './account/account.component' providers: [ { provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: AuthHandlerInterceptor, multi: true }, + { provide: LOCALE_ID, useValue: 'de' }, MatNativeDateModule ], bootstrap: [AppComponent] diff --git a/ui/hv2-ui/src/app/data-objects.ts b/ui/hv2-ui/src/app/data-objects.ts index 7eafd46..abbd75d 100644 --- a/ui/hv2-ui/src/app/data-objects.ts +++ b/ui/hv2-ui/src/app/data-objects.ts @@ -43,7 +43,7 @@ export const NULL_Tenant: Tenant = { ,phone1: '' ,phone2: '' ,iban: '' - ,account: 0 + ,account: undefined } export interface Premise { @@ -71,9 +71,9 @@ export interface Flat { export const NULL_Flat: Flat = { id: 0 ,description: '' - ,premise: 0 - ,area: 0 - ,flat_no: 0 + ,premise: undefined + ,area: undefined + ,flat_no: undefined } export interface OverheadAdvance { @@ -86,7 +86,7 @@ export interface OverheadAdvance { export const NULL_OverheadAdvance: OverheadAdvance = { id: 0 ,description: '' - ,amount: 0 + ,amount: undefined ,startdate: '' ,enddate: '' } @@ -98,8 +98,8 @@ export interface OverheadAdvanceFlatMapping { } export const NULL_OverheadAdvanceFlatMapping: OverheadAdvanceFlatMapping = { id: 0 - ,overhead_advance: 0 - ,flat: 0 + ,overhead_advance: undefined + ,flat: undefined } export interface Parking { @@ -110,7 +110,7 @@ export interface Parking { export const NULL_Parking: Parking = { id: 0 ,description: '' - ,premise: 0 + ,premise: undefined } export interface CommercialPremise { @@ -121,7 +121,7 @@ export interface CommercialPremise { export const NULL_CommercialPremise: CommercialPremise = { id: 0 ,description: '' - ,premise: 0 + ,premise: undefined } export interface Tenancy { @@ -137,10 +137,10 @@ export interface Tenancy { export const NULL_Tenancy: Tenancy = { id: 0 ,description: '' - ,tenant: 0 - ,flat: 0 - ,parking: 0 - ,commercial_premise: 0 + ,tenant: undefined + ,flat: undefined + ,parking: undefined + ,commercial_premise: undefined ,startdate: '' ,enddate: '' } @@ -156,7 +156,7 @@ export interface Fee { export const NULL_Fee: Fee = { id: 0 ,description: '' - ,amount: 0 + ,amount: undefined ,fee_type: '' ,startdate: '' ,enddate: '' @@ -169,8 +169,8 @@ export interface TenancyFeeMapping { } export const NULL_TenancyFeeMapping: TenancyFeeMapping = { id: 0 - ,tenancy: 0 - ,fee: 0 + ,tenancy: undefined + ,fee: undefined } export interface AccountEntry { @@ -183,9 +183,9 @@ export interface AccountEntry { export const NULL_AccountEntry: AccountEntry = { id: 0 ,description: '' - ,account: 0 + ,account: undefined ,created_at: '' - ,amount: 0 + ,amount: undefined } diff --git a/ui/hv2-ui/src/app/data-objects.ts.tmpl b/ui/hv2-ui/src/app/data-objects.ts.tmpl index 425cd80..1fce557 100644 --- a/ui/hv2-ui/src/app/data-objects.ts.tmpl +++ b/ui/hv2-ui/src/app/data-objects.ts.tmpl @@ -16,7 +16,7 @@ export const NULL_$JsNameConverter($table.name): $JsNameConverter($table.name) = #if $column.jstype == "string" '' #else if $column.jstype == "number" - 0 + undefined #end if #end for } 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 1d8dce3..05549b9 100644 --- a/ui/hv2-ui/src/app/ext-data-object-service.ts +++ b/ui/hv2-ui/src/app/ext-data-object-service.ts @@ -7,6 +7,7 @@ import { serviceBaseUrl } from './config'; import { Fee, OverheadAdvance } from './data-objects'; +import { Saldo } from './ext-data-objects'; @Injectable({ providedIn: 'root' }) @@ -22,4 +23,9 @@ export class ExtApiService { this.messageService.add(`ExtApiService: get fees by flat ${id}`); return this.http.get(`${serviceBaseUrl}/v1/fees/tenancy/${id}`).toPromise() } + + async getAccountSaldo(id: number): Promise { + this.messageService.add(`ExtApiService: get saldo for account ${id}`); + return this.http.get(`${serviceBaseUrl}/v1/account/saldo/${id}`).toPromise() + } } diff --git a/ui/hv2-ui/src/app/ext-data-objects.ts b/ui/hv2-ui/src/app/ext-data-objects.ts new file mode 100644 index 0000000..69d4160 --- /dev/null +++ b/ui/hv2-ui/src/app/ext-data-objects.ts @@ -0,0 +1,5 @@ + +export interface Saldo { + saldo: number +} + \ No newline at end of file diff --git a/ui/hv2-ui/src/polyfills.ts b/ui/hv2-ui/src/polyfills.ts index 9b8f300..bb3a246 100644 --- a/ui/hv2-ui/src/polyfills.ts +++ b/ui/hv2-ui/src/polyfills.ts @@ -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. * You can add your own extra polyfills to this file.