from db import dbGetMany, dbGetOne import datetime from loguru import logger from decimal import * from utils import getParam from Cheetah.Template import Template EPSILON = Decimal('0.000000001') def perform(dbh, params): year = getParam(params, 'year', datetime.datetime.today().year) startDate = datetime.datetime(year, 1, 1, 0, 0, 0) endDate = datetime.datetime(year, 12, 31, 23, 59, 59) premises = (1, 2) houses = {} for premise in premises: # get overhead sums by object, category and timespan overheadItems = dbGetMany( dbh, { "statement": """ select sum(ae.amount) as sum, aec.description as category, aec.considerminusarea as considerminusarea from account_t a, premise_t p, account_entry_t ae, account_entry_category_t aec where p.account = a.id and ae.account = a.id and aec.overhead_relevant = 't' and ae.account_entry_category = aec.id and ae.fiscal_year = %(year)s and p.id = %(premise)s group by category, considerminusarea union select 0 as sum, aec.description as category, aec.considerminusarea as considerminusarea from account_t a, premise_t p, account_entry_t ae, account_entry_category_t aec where p.account = a.id and ae.account = a.id and aec.overhead_relevant = 't' and aec.id not in (select distinct account_entry_category from account_entry_t) and ae.fiscal_year = %(year)s and p.id = %(premise)s group by category, considerminusarea union select 120 as sum, 'Waschmaschine' as category, false as considerminusarea from premise_t where id = %(premise)s order by category """, "params": { "year": year, "premise": premise } } ) # get areas and factors totalArea = {} flatArea = dbGetOne( dbh, { "statement": """ select sum(f.area) as flat_area from premise_t p, flat_t f where f.premise = p.id and p.id = %(premise)s """, "params": { "premise": premise } } ) totalArea['flat_area'] = flatArea['flat_area'] commercialArea = dbGetOne( dbh, { "statement": """ select coalesce(sum(c.area), 0) as commercial_area from premise_t p full outer join commercial_premise_t c on c.premise = p.id where p.id = %(premise)s """, "params": { "premise": premise } } ) totalArea['commercial_area'] = commercialArea['commercial_area'] minusAreaAndDetails = dbGetOne( dbh, { "statement": """ select p.minus_area as minus_area, p.id as house_id, p.description as house from premise_t p where p.id = %(premise)s """, "params": { "premise": premise } } ) totalArea['minus_area'] = minusAreaAndDetails['minus_area'] details = { 'id': minusAreaAndDetails['house_id'], 'description': minusAreaAndDetails['house'] } totalArea['other_area'] = totalArea['commercial_area'] + totalArea['minus_area'] totalArea['total_area'] = totalArea['flat_area'] + totalArea['other_area'] totalArea['flat_factor'] = totalArea['flat_area'] / totalArea['total_area'] totalArea['other_factor'] = totalArea['other_area'] / totalArea['total_area'] totalArea['factor_check'] = totalArea['flat_factor'] + totalArea['other_factor'] totalSum = Decimal('0') flatSum = Decimal('0') otherSum = Decimal('0') for overheadItem in overheadItems: totalSum += overheadItem['sum'] overheadItem['flat_part'] = overheadItem['sum'] * totalArea['flat_factor'] if overheadItem['considerminusarea'] else overheadItem['sum'] flatSum += overheadItem['flat_part'] overheadItem['other_part'] = overheadItem['sum'] * totalArea['other_factor'] if overheadItem['considerminusarea'] else Decimal('0') otherSum += overheadItem['other_part'] verifyDifference = totalSum - flatSum - otherSum logger.debug(f"{totalSum=}, {verifyDifference=}") if abs(verifyDifference) > EPSILON: raise Exception(f"Verify Difference is too large: {premise=}, {verifyDifference=}") umlageAusfallWagnis = flatSum * Decimal('0.02') flatSum2 = flatSum + umlageAusfallWagnis partByMonthArea = flatSum2 / Decimal('12') / totalArea['flat_area'] houses[details['id']] = { 'details': details, 'areas': totalArea, 'overhead_items': overheadItems, 'flat_sum': flatSum, 'flat_sum_2': flatSum2, 'other_sum': otherSum, 'total_sum': totalSum, 'umlage_ausfall_wagnis': umlageAusfallWagnis, 'part_by_montharea': partByMonthArea, 'year': year } logger.info(f"{houses=}") printOverviews = getParam(params, 'printOverviews', True) if printOverviews: overviewTemplate = getParam(params, 'overviewTemplate', 'betriebskostenuebersicht.tmpl') overviewPrefix = getParam(params, 'overviewPrefix', 'overview') overviewSuffix = getParam(params, 'overviewSuffix', 'tex') for house in houses.values(): logger.debug(f"Processing item: {house}") outputFile = f"{overviewPrefix}-{house['details']['id']}.{overviewSuffix}" tmpl = Template(file=overviewTemplate, searchList=[ house ]) logger.debug(tmpl) with open(outputFile, 'w') as f: f.write(str(tmpl)) # get flat tenants by object and timespan with paid overhead and due overhead tenants = dbGetMany( dbh, { "statement": """ select t.id as tenant_id, t.salutation as tenant_salutation, t.firstname as tenant_firstname, t.lastname as tenant_lastname, t.address1 as tenant_address1, t.address2 as tenant_address2, t.address3 as tenant_address3, t.zip as tenant_zip, t.city as tenant_city, f.id as flat_id, f.description as flat, f.area as flat_area, p.id as house_id, p.description as house, ty.startdate as startdate, ty.enddate as enddate, t.account as tenant_account from tenant_t t, premise_t p, flat_t f, tenancy_t ty where ty.tenant = t.id and ty.flat = f.id and ty.startdate <= %(startDate)s and (ty.enddate >= %(endDate)s or ty.enddate is null) and f.premise = p.id and p.id in %(premises)s order by house_id, tenant_id """, "params": { "startDate": startDate, "endDate": endDate, "premises": premises } } ) letters = [] for tenant in tenants: letter = {} paidTotal = dbGetOne( dbh, { "statement": """ SELECT sum(amount) AS sum, count(id) AS cnt FROM account_entry_t WHERE account = %(account)s AND account_entry_category = 2 AND fiscal_year = %(year)s """, "params": { "account": tenant['tenant_account'], "year": year } } ) tenant['paid_total'] = paidTotal['sum'] receivableFee = dbGetOne( dbh, { "statement": """ SELECT sum(amount) * -1 AS sum , count(id) AS cnt FROM account_entry_t WHERE account = %(account)s AND account_entry_category = 3 AND fiscal_year = %(year)s """, "params": { "account": tenant['tenant_account'], "year": year } } ) tenant['receivable_fee'] = receivableFee['sum'] tenant['rent_time'] = receivableFee['cnt'] tenant['paid_overhead'] = paidTotal['sum'] - receivableFee['sum'] letter['tenant'] = tenant letter['year'] = year letter['flat_area'] = tenant['flat_area'] letter['receivable_overhead'] = tenant['flat_area'] * houses[tenant['house_id']]['part_by_montharea'] * tenant['rent_time'] letter['unbalanced_overhead'] = tenant['paid_overhead'] - letter['receivable_overhead'] letter['unbalanced_overhead_unsigned'] = abs(letter['unbalanced_overhead']) letter['total_overhead'] = houses[tenant['house_id']]['flat_sum_2'] letters.append(letter) logger.info(f"{letter=}") printLetters = getParam(params, 'printLetters', True) if printLetters: letterTemplate = getParam(params, 'letterTemplate', 'jahresabrechnung.tmpl') letterPrefix = getParam(params, 'letterPrefix', 'letter') letterSuffix = getParam(params, 'letterSuffix', 'tex') for letter in letters: logger.debug(f"Processing item: {letter}") outputFile = f"{letterPrefix}-{letter['tenant']['tenant_id']}.{letterSuffix}" tmpl = Template(file=letterTemplate, searchList=[ letter ]) logger.debug(tmpl) with open(outputFile, 'w') as f: f.write(str(tmpl))