reports: Add BaseODS.meta_links_cell() method.
This commit is contained in:
parent
17c5468a7d
commit
aff1fc537d
4 changed files with 75 additions and 24 deletions
|
@ -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')),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
2
setup.py
2
setup.py
|
@ -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+',
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in a new issue