diff --git a/api/methods.py b/api/methods.py index 7a2c91f..d100d08 100644 --- a/api/methods.py +++ b/api/methods.py @@ -1320,3 +1320,80 @@ SELECT } ) +def get_notes(user, token_info): + return dbGetMany(user, token_info, { + "statement": """ +SELECT + id + ,created_at + ,tenant + ,note + FROM note_t + """, + "params": () + } + ) + +def insert_note(user, token_info, **args): + try: + body = args["body"] + v_created_at = body["created_at"] + v_tenant = body["tenant"] + v_note = body["note"] + return dbInsert(user, token_info, { + "statement": """ +INSERT INTO note_t + ( + created_at + ,tenant + ,note + ) VALUES ( + %s + ,%s + ,%s + ) + RETURNING * +""", + "params": [ + v_created_at + ,v_tenant + ,v_note + ] + }) + except KeyError as e: + logger.warning("insert_note: parameter missing: {}".format(e)) + raise werkzeug.exceptions.UnprocessableEntity("parameter missing: {}".format(e)) + + +def get_note(user, token_info, noteId=None): + return dbGetOne(user, token_info, { + "statement": """ +SELECT + id + ,created_at + ,tenant + ,note + FROM note_t + WHERE id = %s + """, + "params": (noteId, ) + } + ) + + + +def get_note_by_tenant(user, token_info, tenantId=None): + return dbGetMany(user, token_info, { + "statement": """ +SELECT + id + ,created_at + ,tenant + ,note + FROM note_t + WHERE tenant = %s + """, + "params": (tenantId, ) + } + ) + diff --git a/api/openapi.yaml b/api/openapi.yaml index 8e9190c..2c6f785 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1256,6 +1256,87 @@ paths: $ref: '#/components/schemas/account_entry' security: - jwt: ['secret'] + /v1/notes: + get: + tags: [ "note" ] + summary: Return all normalized notes + operationId: methods.get_notes + responses: + '200': + description: notes response + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/note' + security: + - jwt: ['secret'] + post: + tags: [ "note" ] + summary: Insert a note + operationId: methods.insert_note + requestBody: + description: note + content: + application/json: + schema: + $ref: '#/components/schemas/note' + responses: + '200': + description: note successfully inserted + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/note' + security: + - jwt: ['secret'] + /v1/notes/{noteId}: + get: + tags: [ "note" ] + summary: Return the normalized note with given id + operationId: methods.get_note + parameters: + - name: noteId + in: path + required: true + schema: + type: integer + responses: + '200': + description: note response + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/note' + security: + - jwt: ['secret'] + /v1/notes/tenant/{tenantId}: + get: + tags: [ "note", "tenant" ] + summary: Return note by $tenant + operationId: methods.get_note_by_tenant + parameters: + - name: tenantId + in: path + required: true + schema: + type: integer + responses: + '200': + description: note response + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/note' + security: + - jwt: ['secret'] # ------------------------------------------------------------------- # ATTENTION: This file will not be parsed by Cheetah @@ -1511,3 +1592,15 @@ components: type: string amount: type: number + note: + description: note + type: object + properties: + id: + type: integer + created_at: + type: string + tenant: + type: integer + note: + type: string diff --git a/schema.json b/schema.json index 1dedf98..b18d675 100644 --- a/schema.json +++ b/schema.json @@ -117,6 +117,15 @@ { "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" }, { "name": "amount", "sqltype": "numeric(10,2)", "notnull": true, "selector": 0 } ] + }, + { + "name": "note", + "immutable": true, + "columns": [ + { "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" }, + { "name": "tenant", "sqltype": "integer", "notnull": true, "foreignkey": true }, + { "name": "note", "sqltype": "varchar(4096)", "notnull": true } + ] } ] } diff --git a/schema/create.sql b/schema/create.sql index 74722b7..d3e4066 100644 --- a/schema/create.sql +++ b/schema/create.sql @@ -104,5 +104,12 @@ CREATE TABLE account_entry_t ( ,amount numeric(10,2) not null ); +CREATE TABLE note_t ( + id serial not null primary key + ,created_at timestamp not null default now() + ,tenant integer not null references tenant_t (id) + ,note varchar(4096) not null +); + diff --git a/ui/hv2-ui/src/app/account/account.component.ts b/ui/hv2-ui/src/app/account/account.component.ts index a62a3f6..5d290d9 100644 --- a/ui/hv2-ui/src/app/account/account.component.ts +++ b/ui/hv2-ui/src/app/account/account.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnInit, OnChanges, ViewChild } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatTableDataSource } from '@angular/material/table'; import { AccountEntryService, AccountService } from '../data-object-service'; @@ -82,4 +82,9 @@ export class AccountComponent implements OnInit { this.getAccount() } + ngOnChanges(): void { + this.messageService.add(`AccountComponent.ngOnChanges, account: ${this.selectedAccountId}`) + this.getAccount() + } + } diff --git a/ui/hv2-ui/src/app/app.module.ts b/ui/hv2-ui/src/app/app.module.ts index 382d574..a98333e 100644 --- a/ui/hv2-ui/src/app/app.module.ts +++ b/ui/hv2-ui/src/app/app.module.ts @@ -43,7 +43,8 @@ import { MatNativeDateModule } from '@angular/material/core'; import { FeeListComponent } from './fee-list/fee-list.component'; import { FeeDetailsComponent } from './fee-details/fee-details.component'; import { MatExpansionModule } from '@angular/material/expansion'; -import { AccountComponent } from './account/account.component' +import { AccountComponent } from './account/account.component'; +import { NoteComponent } from './note/note.component' registerLocaleData(localeDe) @@ -69,7 +70,8 @@ registerLocaleData(localeDe) OverheadAdvanceDetailsComponent, FeeListComponent, FeeDetailsComponent, - AccountComponent + AccountComponent, + NoteComponent ], imports: [ BrowserModule, diff --git a/ui/hv2-ui/src/app/data-object-service.ts b/ui/hv2-ui/src/app/data-object-service.ts index c240148..b70902c 100644 --- a/ui/hv2-ui/src/app/data-object-service.ts +++ b/ui/hv2-ui/src/app/data-object-service.ts @@ -25,6 +25,7 @@ import { Tenancy } from './data-objects'; import { Fee } from './data-objects'; import { TenancyFeeMapping } from './data-objects'; import { AccountEntry } from './data-objects'; +import { Note } from './data-objects'; @@ -452,4 +453,34 @@ export class AccountEntryService { } +@Injectable({ providedIn: 'root' }) +export class NoteService { + constructor(private messageService: MessageService, private http: HttpClient) { } + + async getNotes(): Promise { + this.messageService.add(`NoteService: get data`); + return this.http.get(`${serviceBaseUrl}/v1/notes`).toPromise() + } + + async getNote(id: number): Promise { + this.messageService.add(`NoteService: get data for ${id}`); + return this.http.get(`${serviceBaseUrl}/v1/notes/${id}`).toPromise() + } + + async postNote(item: Note): Promise { + let itemStr: string = JSON.stringify(item, undefined, 4) + this.messageService.add(`NoteService: post data for ${itemStr}`); + return this.http.post(`${serviceBaseUrl}/v1/notes`, item).toPromise() + } + + + + async getNotesByTenant(id: number): Promise { + this.messageService.add(`NoteService: get data by Tenant ${id}`); + return this.http.get(`${serviceBaseUrl}/v1/notes/tenant/${id}`).toPromise() + } + + +} + diff --git a/ui/hv2-ui/src/app/data-objects.ts b/ui/hv2-ui/src/app/data-objects.ts index abbd75d..db5ed57 100644 --- a/ui/hv2-ui/src/app/data-objects.ts +++ b/ui/hv2-ui/src/app/data-objects.ts @@ -188,4 +188,17 @@ export const NULL_AccountEntry: AccountEntry = { ,amount: undefined } +export interface Note { + id: number + created_at: string + tenant: number + note: string +} +export const NULL_Note: Note = { + id: 0 + ,created_at: '' + ,tenant: undefined + ,note: '' +} + diff --git a/ui/hv2-ui/src/app/note/note.component.css b/ui/hv2-ui/src/app/note/note.component.css new file mode 100644 index 0000000..c047311 --- /dev/null +++ b/ui/hv2-ui/src/app/note/note.component.css @@ -0,0 +1,40 @@ +table { + width: 75%; +} + +.spacer { + flex: 1 1 auto; +} + +#addEntryfield { + margin-right: 15px; +} + +#divider { + margin-top: 20px; +} + +#firstblock { + margin-bottom: 20px; +} + +#secondblock { + margin-top: 20px; +} + +.rightaligned { + justify-self: right; +} + +.large { + font-size: large; +} + +.notearea { + width: 75%; +} + +.topalign { + vertical-align: top; + padding-right: 10px; +} \ No newline at end of file diff --git a/ui/hv2-ui/src/app/note/note.component.html b/ui/hv2-ui/src/app/note/note.component.html new file mode 100644 index 0000000..ca485b6 --- /dev/null +++ b/ui/hv2-ui/src/app/note/note.component.html @@ -0,0 +1,53 @@ + + + + Notizen + + + + + + + + Übersicht + + + + +
+
+
+ + Text + + +
+ +
+
+
+
+ + + + + + + + + + + +
Datum{{element.created_at | date}}Notiz{{element.note}}
+
+
+
+ +
+
diff --git a/ui/hv2-ui/src/app/note/note.component.spec.ts b/ui/hv2-ui/src/app/note/note.component.spec.ts new file mode 100644 index 0000000..3595cba --- /dev/null +++ b/ui/hv2-ui/src/app/note/note.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NoteComponent } from './note.component'; + +describe('NoteComponent', () => { + let component: NoteComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NoteComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NoteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ui/hv2-ui/src/app/note/note.component.ts b/ui/hv2-ui/src/app/note/note.component.ts new file mode 100644 index 0000000..a23e54d --- /dev/null +++ b/ui/hv2-ui/src/app/note/note.component.ts @@ -0,0 +1,77 @@ +import { Component, Input, OnInit, OnChanges, ViewChild } from '@angular/core'; +import { MatButton } from '@angular/material/button'; +import { MatTableDataSource } from '@angular/material/table'; +import { NoteService } from '../data-object-service'; +import { Note, NULL_Note } from '../data-objects'; +import { MessageService } from '../message.service'; + +@Component({ + selector: 'app-note', + templateUrl: './note.component.html', + styleUrls: ['./note.component.css'] +}) +export class NoteComponent implements OnInit { + + @Input() selectedTenantId: number + @ViewChild('addNoteButton') addNoteButton: MatButton + + collapse: boolean = false + + notes: Note[] + notesDataSource: MatTableDataSource + notesDisplayedColumns: string[] = [ "createdAt", "note" ] + + newNote : Note = NULL_Note + + constructor( + private noteService: NoteService, + private messageService: MessageService + ) { } + + + async getNotes(): Promise { + try { + if (this.selectedTenantId) { + this.messageService.add(`Trying to load note for ${this.selectedTenantId}`) + this.notes = await this.noteService.getNotesByTenant(this.selectedTenantId) + this.notes.reverse() + this.messageService.add(`Notes: ${JSON.stringify(this.notes, undefined, 4)}`) + this.notesDataSource = new MatTableDataSource(this.notes) + } + } catch (err) { + this.messageService.add(`Error in getNotes: ${JSON.stringify(err, undefined, 4)}`) + } + } + + + async addNote(): Promise { + try { + this.addNoteButton.disabled = true + this.newNote.tenant = this.selectedTenantId + this.newNote.created_at = new Date().toDateString() + this.messageService.add(`addNote: ${ JSON.stringify(this.newNote, undefined, 4) }`) + this.newNote = await this.noteService.postNote(this.newNote) + this.messageService.add(`New addNote created: ${this.newNote.id}`) + this.newNote = { 'tenant': this.selectedTenantId, 'note': '', 'created_at': '', 'id': 0 } + this.getNotes() + } catch (err) { + this.messageService.add(`Error in addNote: ${JSON.stringify(err, undefined, 4)}`) + } finally { + this.addNoteButton.disabled = false + } + } + + + ngOnInit(): void { + this.messageService.add(`NoteComponent.ngOnInit, account: ${this.selectedTenantId}`) + this.getNotes() + + } + + ngOnChanges(): void { + this.messageService.add(`NoteComponent.ngOnChanges, account: ${this.selectedTenantId}`) + this.getNotes() + + } + +} 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 f7e4bf9..8898f2a 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 @@ -203,6 +203,8 @@ - + + +