reports: Add BaseODS.meta_links_cell() method.

This commit is contained in:
Brett Smith 2020-06-12 17:10:25 -04:00
parent 17c5468a7d
commit aff1fc537d
4 changed files with 75 additions and 24 deletions

View file

@ -71,7 +71,6 @@ import datetime
import enum
import logging
import sys
import urllib.parse as urlparse
from pathlib import Path
@ -293,8 +292,7 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]):
date: datetime.date,
logger: logging.Logger,
) -> None:
super().__init__()
self.rt_wrapper = rt_wrapper
super().__init__(rt_wrapper)
self.date = date
self.logger = logger
@ -388,20 +386,6 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]):
self.balance_cell(total_balance),
)
def _link_seq(self, row: AccrualPostings, key: MetaKey) -> Iterator[Tuple[str, str]]:
for href in row.all_meta_links(key):
rt_ids = self.rt_wrapper.parse(href)
rt_href = rt_ids and self.rt_wrapper.url(*rt_ids)
if rt_ids is None or rt_href is None:
# '..' pops the ODS filename off the link path. In other words,
# make the link relative to the directory the ODS is in.
href_path = Path('..', urlparse.urlparse(href).path)
href = str(href_path)
text = urlparse.unquote(href_path.name)
else:
text = self.rt_wrapper.unparse(*rt_ids)
yield (href, text)
def write_row(self, row: AccrualPostings) -> None:
age = (self.date - row[0].meta.date).days
if row.end_balance.ge_zero():
@ -426,11 +410,11 @@ class AgingODS(core.BaseODS[AccrualPostings, Optional[data.Account]]):
amount_cell,
self.balance_cell(row.end_balance),
self.multiline_cell(sorted(projects)),
self.multilink_cell(self._link_seq(row, 'rt-id')),
self.multilink_cell(self._link_seq(row, 'invoice')),
self.multilink_cell(self._link_seq(row, 'approval')),
self.multilink_cell(self._link_seq(row, 'contract')),
self.multilink_cell(self._link_seq(row, 'purchase-order')),
self.meta_links_cell(row.all_meta_links('rt-id')),
self.meta_links_cell(row.all_meta_links('invoice')),
self.meta_links_cell(row.all_meta_links('approval')),
self.meta_links_cell(row.all_meta_links('contract')),
self.meta_links_cell(row.all_meta_links('purchase-order')),
)

View file

@ -20,6 +20,7 @@ import datetime
import itertools
import operator
import re
import urllib.parse as urlparse
import babel.core # type:ignore[import]
import babel.numbers # type:ignore[import]
@ -39,6 +40,7 @@ from beancount.core import amount as bc_amount
from .. import data
from .. import filters
from .. import rtutil
from typing import (
cast,
@ -457,7 +459,8 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
See also the BaseSpreadsheet base class for additional documentation about
methods you must and can define, the definition of RT and ST, etc.
"""
def __init__(self) -> None:
def __init__(self, rt_wrapper: Optional[rtutil.RT]=None) -> None:
self.rt_wrapper = rt_wrapper
self.locale = babel.core.Locale.default('LC_MONETARY')
self.currency_fmt_key = 'accounting'
self._name_counter = itertools.count(1)
@ -912,6 +915,34 @@ class BaseODS(BaseSpreadsheet[RT, ST], metaclass=abc.ABCMeta):
cell.addElement(odf.text.P(text=str(value)))
return cell
def _meta_link_pairs(self, links: Iterable[Optional[str]]) -> Iterator[Tuple[str, str]]:
for href in links:
if href is None:
continue
elif self.rt_wrapper is not None:
rt_ids = self.rt_wrapper.parse(href)
rt_href = rt_ids and self.rt_wrapper.url(*rt_ids)
else:
rt_ids = None
rt_href = None
if rt_ids is None or rt_href is None:
# '..' pops the ODS filename off the link path. In other words,
# make the link relative to the directory the ODS is in.
href_path = Path('..', href)
href = str(href_path)
text = href_path.name
else:
rt_path = urlparse.urlparse(rt_href).path
if rt_path.endswith('/Ticket/Display.html'):
text = rtutil.RT.unparse(*rt_ids)
else:
text = urlparse.unquote(Path(rt_path).name)
href = rt_href
yield (href, text)
def meta_links_cell(self, links: Iterable[Optional[str]], **attrs: Any) -> odf.table.TableCell:
return self.multilink_cell(self._meta_link_pairs(links), **attrs)
def multiline_cell(self, lines: Iterable[Any], **attrs: Any) -> odf.table.TableCell:
cell = odf.table.TableCell(valuetype='string', **attrs)
for line in lines:

View file

@ -5,7 +5,7 @@ from setuptools import setup
setup(
name='conservancy_beancount',
description="Plugin, library, and reports for reading Conservancy's books",
version='1.1.12',
version='1.1.13',
author='Software Freedom Conservancy',
author_email='info@sfconservancy.org',
license='GNU AGPLv3+',

View file

@ -32,6 +32,7 @@ from decimal import Decimal
from . import testutil
from conservancy_beancount import rtutil
from conservancy_beancount.reports import core
EN_US = babel.core.Locale('en', 'US')
@ -493,6 +494,41 @@ def test_ods_writer_float_cell(ods_writer, cell_source, style_name):
assert cell.getAttribute('value') == expected
assert get_text(cell) == expected
def test_ods_writer_meta_links_cell(ods_writer):
rt_client = testutil.RTClient()
ods_writer.rt_wrapper = rtutil.RT(rt_client)
rt_url = rt_client.DEFAULT_URL[:-10]
meta_links = [
'rt://ticket/1',
'rt://ticket/2/attachments/9',
'rt:1/5',
'Invoices/0123.pdf',
]
cell = ods_writer.meta_links_cell(meta_links, stylename='meta1')
assert cell.getAttribute('valuetype') == 'string'
assert cell.getAttribute('stylename') == 'meta1'
children = iter(get_children(cell, odf.text.A))
child = next(children)
assert child.getAttribute('type') == 'simple'
expect_url = f'{rt_url}/Ticket/Display.html?id=1'
assert child.getAttribute('href') == expect_url
assert get_text(child) == 'rt:1'
child = next(children)
assert child.getAttribute('type') == 'simple'
expect_url = f'{rt_url}/Ticket/Display.html?id=2#txn-7'
assert child.getAttribute('href') == expect_url
assert get_text(child) == 'rt:2/9'
child = next(children)
assert child.getAttribute('type') == 'simple'
expect_url = f'{rt_url}/Ticket/Attachment/1/5/photo.jpg'
assert child.getAttribute('href') == expect_url
assert get_text(child) == 'photo.jpg'
child = next(children)
assert child.getAttribute('type') == 'simple'
expect_url = f'../{meta_links[3]}'
assert child.getAttribute('href') == expect_url
assert get_text(child) == '0123.pdf'
def test_ods_writer_multiline_cell(ods_writer):
cell = ods_writer.multiline_cell(iter(STRING_CELL_DATA))
assert cell.getAttribute('valuetype') == 'string'