8 Commits

16 changed files with 196 additions and 12 deletions

View File

@ -88,4 +88,26 @@
$ref: '#/components/schemas/tenant_with_saldo'
security:
- jwt: ['secret']
/v1/accounts/bydescription/{description}:
get:
tags: [ "account" ]
summary: Return the normalized account with given description
operationId: additional_methods.get_account_by_description
parameters:
- name: description
in: path
required: true
schema:
type: string
responses:
'200':
description: account response
content:
'application/json':
schema:
type: array
items:
$ref: '#/components/schemas/account'
security:
- jwt: ['secret']

View File

@ -36,11 +36,21 @@ def get_account_saldo(user, token_info, accountId=None):
def get_tenant_with_saldo(user, token_info):
return dbGetMany(user, token_info, {
"statement": """
SELECT t.firstname, t.lastname, t.address1, sum(a.amount) AS saldo
FROM tenant_t t, account_entry_t a
WHERE a.account = t.account
GROUP BY t.firstname, t.lastname, t.address1
SELECT t.id, t.firstname, t.lastname, t.address1, sum(a.amount) AS saldo
FROM tenant_t t LEFT OUTER JOIN account_entry_t a ON a.account = t.account
GROUP BY t.id, t.firstname, t.lastname, t.address1
""",
"params": ()
}
)
def get_account_by_description(user, token_info, description=None):
return dbGetOne(user, token_info, {
"statement": """
SELECT a.id ,a.description
FROM account_t a
WHERE a.description = %s""",
"params": (description, )
}
)

View File

@ -1509,6 +1509,28 @@ paths:
$ref: '#/components/schemas/tenant_with_saldo'
security:
- jwt: ['secret']
/v1/accounts/bydescription/{description}:
get:
tags: [ "account" ]
summary: Return the normalized account with given description
operationId: additional_methods.get_account_by_description
parameters:
- name: description
in: path
required: true
schema:
type: string
responses:
'200':
description: account response
content:
'application/json':
schema:
type: array
items:
$ref: '#/components/schemas/account'
security:
- jwt: ['secret']
components:

View File

@ -1,10 +1,13 @@
from db import dbGetMany, dbGetOne
from loguru import logger
from decimal import Decimal
import datetime
def perform(dbh, params):
createdAt = params['created_at']
try:
createdAt = params['created_at']
except KeyError:
createdAt = datetime.datetime.today().strftime("%Y-%m-%d")
tenants = dbGetMany(dbh, { "statement": "SELECT * FROM tenant_t", "params": () })
for tenant in tenants:

View File

@ -38,14 +38,21 @@ parser.add_argument('--verbosity', '-v',
help='Minimal log level for output: DEBUG, INFO, WARNING, ..., default: DEBUG',
required=False,
default="DEBUG")
parser.add_argument('--nocolorize', '-n',
help='disable colored output (for cron)',
required=False,
action='store_true',
default=False)
args = parser.parse_args()
operation = args.operation
params = json.loads(args.params)
logLevel = args.verbosity
noColorize = args.nocolorize
logger.remove()
logger.add(sys.stderr, colorize=True, level=logLevel)
logger.add(sys.stderr, colorize=(not noColorize), level=logLevel)
dbh = None

View File

@ -145,7 +145,7 @@ GRANT SELECT, UPDATE ON account_entry_category_t_id_seq TO hv2;
CREATE TABLE account_entry_t (
id serial not null primary key
,description varchar(128) not null
,description varchar(1024) not null
,account integer not null references account_t (id)
,created_at timestamp not null default now()
,amount numeric(10,2) not null

View File

@ -8,7 +8,7 @@
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Kategorie</mat-label>
<mat-select [(ngModel)]="newAccountEntry.account_entry_category" name="category" disabled="shallBeRentPayment">
<mat-select [(ngModel)]="newAccountEntry.account_entry_category" name="category" [disabled]="shallBeRentPayment">
<mat-option *ngFor="let p of accountEntryCategories" [value]="p.id">{{p.description}}</mat-option>
</mat-select>
</mat-form-field>

View File

@ -19,6 +19,7 @@ import { FeeListComponent } from './fee-list/fee-list.component';
import { FeeDetailsComponent } from './fee-details/fee-details.component';
import { EnterPaymentComponent } from './enter-payment/enter-payment.component';
import { HomeComponent } from './home/home.component';
import { LedgerComponent } from './ledger/ledger.component';
const routes: Routes = [
@ -44,6 +45,7 @@ const routes: Routes = [
{ path: 'fee/:id', component: FeeDetailsComponent, canActivate: [ AuthGuardService ] },
{ path: 'fee', component: FeeDetailsComponent, canActivate: [ AuthGuardService ] },
{ path: 'enterPayment', component: EnterPaymentComponent, canActivate: [ AuthGuardService ] },
{ path: 'ledger', component: LedgerComponent, canActivate: [ AuthGuardService ] },
{ path: 'home', component: HomeComponent },
{ path: 'logout', component: LogoutComponent },
{ path: 'login', component: LoginComponent },

View File

@ -47,7 +47,8 @@ import { AccountComponent } from './account/account.component';
import { NoteComponent } from './note/note.component'
import { MatMomentDateModule, MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
import { EnterPaymentComponent } from './enter-payment/enter-payment.component';
import { HomeComponent } from './home/home.component'
import { HomeComponent } from './home/home.component';
import { LedgerComponent } from './ledger/ledger.component'
registerLocaleData(localeDe)
@ -76,7 +77,8 @@ registerLocaleData(localeDe)
AccountComponent,
NoteComponent,
EnterPaymentComponent,
HomeComponent
HomeComponent,
LedgerComponent
],
imports: [
BrowserModule,

View File

@ -6,7 +6,7 @@ import { MessageService } from './message.service';
import { serviceBaseUrl } from './config';
import { Fee, OverheadAdvance } from './data-objects';
import { Account, Fee, OverheadAdvance } from './data-objects';
import { Saldo, Tenant_with_Saldo } from './ext-data-objects';
@ -19,6 +19,11 @@ export class ExtApiService {
return this.http.get<OverheadAdvance[]>(`${serviceBaseUrl}/v1/overhead_advances/flat/${id}`).toPromise()
}
async getAccountByDescription(description: string): Promise<Account> {
this.messageService.add(`ExtApiService: get account by description ${description}`);
return this.http.get<Account>(`${serviceBaseUrl}/v1/accounts/bydescription/${description}`).toPromise()
}
async getFeeByTenancies(id: number): Promise<Fee[]> {
this.messageService.add(`ExtApiService: get fees by flat ${id}`);
return this.http.get<Fee[]>(`${serviceBaseUrl}/v1/fees/tenancy/${id}`).toPromise()

View File

@ -0,0 +1,33 @@
<mat-card class="defaultCard">
<mat-card-header>
<mat-card-title>
Buchführung
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-accordion>
<mat-expansion-panel (opened)="collapseIncomeDetails = true"
(closed)="collapseIncomeDetails = false">
<mat-expansion-panel-header>
<mat-panel-title>
Einnahmen
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
<app-account [selectedAccountId]="incomeAccountId" [shallBeRentPayment]="false"></app-account>
</mat-expansion-panel>
<mat-expansion-panel (opened)="collapseExpenseDetails = true"
(closed)="collapseExpenseDetails = false">
<mat-expansion-panel-header>
<mat-panel-title>
Ausgaben
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
<app-account [selectedAccountId]="expenseAccountId" [shallBeRentPayment]="false"></app-account>
</mat-expansion-panel>
</mat-accordion>
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LedgerComponent } from './ledger.component';
describe('LedgerComponent', () => {
let component: LedgerComponent;
let fixture: ComponentFixture<LedgerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LedgerComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LedgerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,44 @@
import { Component, OnInit } from '@angular/core';
import { Account } from '../data-objects';
import { ExtApiService } from '../ext-data-object-service';
import { MessageService } from '../message.service';
@Component({
selector: 'app-ledger',
templateUrl: './ledger.component.html',
styleUrls: ['./ledger.component.css']
})
export class LedgerComponent implements OnInit {
incomeAccount: Account
incomeAccountId: number
expenseAccount: Account
expenseAccountId: number
collapseIncomeDetails: boolean = false
collapseExpenseDetails: boolean = false
constructor(
private extApiService: ExtApiService,
private messageService: MessageService
) { }
async getAccount(): Promise<void> {
try {
this.messageService.add("Trying to load ledger account")
this.incomeAccount = await this.extApiService.getAccountByDescription('LedgerIncome')
this.expenseAccount = await this.extApiService.getAccountByDescription('LedgerExpense')
this.messageService.add("Account loaded")
} catch (err) {
this.messageService.add(JSON.stringify(err, undefined, 4))
}
}
async ngOnInit(): Promise<void> {
await this.getAccount()
this.incomeAccountId = this.incomeAccount.id
this.expenseAccountId = this.expenseAccount.id
}
}

View File

@ -9,6 +9,8 @@
</mat-nav-list>
<mat-nav-list *ngIf="authenticated">
<a mat-list-item href="/enterPayment">Mietzahlung eintragen</a>
</mat-nav-list><mat-divider *ngIf="authenticated"></mat-divider><mat-nav-list *ngIf="authenticated">
<a mat-list-item href="/ledger">Buchführung</a>
</mat-nav-list><mat-divider *ngIf="authenticated"></mat-divider><mat-nav-list *ngIf="authenticated">
<a mat-list-item href="/tenants">Meine Mieter/innen</a>
</mat-nav-list><mat-divider *ngIf="authenticated"></mat-divider><mat-nav-list *ngIf="authenticated">

View File

@ -90,11 +90,18 @@ export class TenantDetailsComponent implements OnInit {
async getTenant(): Promise<void> {
try {
const id = +this.route.snapshot.paramMap.get('id')
this.messageService.add(`getTenant, id=${id}`)
if (id != 0) {
this.messageService.add("getTenant, not-0-branch")
this.tenantId = id
this.tenant = await this.tenantService.getTenant(id)
this.account = await this.accountService.getAccount(this.tenant.account)
this.getTenancies()
} else {
this.messageService.add("getTenant, 0-branch")
this.tenant = NULL_Tenant
this.account = NULL_Account
this.tenancies = []
}
} catch (err) {
this.messageService.add(JSON.stringify(err, undefined, 4))