Commit 02fe8980 authored by Nicolas Chauvat's avatar Nicolas Chauvat
Browse files

style: get back to black

parent 8da13d641e0d
Pipeline #69242 failed with stages
in 56 seconds
# pylint: disable-msg=W0622
"""cubicweb-fresh application packaging information"""
modname = 'fresh'
distname = 'cubicweb-fresh'
modname = "fresh"
distname = "cubicweb-fresh"
numversion = (1, 1, 0)
version = '.'.join(str(num) for num in numversion)
version = ".".join(str(num) for num in numversion)
license = 'LGPL'
author = 'Logilab'
author_email = 'contact@logilab.fr'
description = 'expense tracking application built on the CubicWeb framework'
web = 'http://www.cubicweb.org/project/%s' % distname
license = "LGPL"
author = "Logilab"
author_email = "contact@logilab.fr"
description = "expense tracking application built on the CubicWeb framework"
web = "http://www.cubicweb.org/project/%s" % distname
classifiers = [
'Environment :: Web Environment',
'Framework :: CubicWeb',
'Programming Language :: Python',
'Programming Language :: JavaScript',
]
"Environment :: Web Environment",
"Framework :: CubicWeb",
"Programming Language :: Python",
"Programming Language :: JavaScript",
]
__depends__ = {
'cubicweb[pyramid]': ">=3.31.0,<3.32.0",
'cubicweb-expense': ">=0.9.0,<0.10.0",
'cubicweb-workcase': ">=0.8.0,<0.9.0",
'cubicweb-searchui': ">=0.4.0,<0.5.0",
'cubicweb-rqlcontroller': ">=0.7.0,<0.8.0",
'cubicweb-signedrequest': ">=1.0.0,<1.1.0",
'cubicweb-sentry': ">=0.5.0,<0.6.0",
'cubicweb-card': ">=1.1.0,<1.2.0",
'cubicweb-oauth2': ">=0.3.0,<0.4.0",
'reportlab': ">=3.5.0,<3.6.0",
'cwclientlib': ">=1.1.0,<1.2.0",
"cubicweb[pyramid]": ">=3.31.0,<3.32.0",
"cubicweb-expense": ">=0.9.0,<0.10.0",
"cubicweb-workcase": ">=0.8.0,<0.9.0",
"cubicweb-searchui": ">=0.4.0,<0.5.0",
"cubicweb-rqlcontroller": ">=0.7.0,<0.8.0",
"cubicweb-signedrequest": ">=1.0.0,<1.1.0",
"cubicweb-sentry": ">=0.5.0,<0.6.0",
"cubicweb-card": ">=1.1.0,<1.2.0",
"cubicweb-oauth2": ">=0.3.0,<0.4.0",
"reportlab": ">=3.5.0,<3.6.0",
"cwclientlib": ">=1.1.0,<1.2.0",
}
......@@ -4,11 +4,10 @@ from cubicweb_expense.entities import ExpenseLine as BaseExpenseLine
class ExpenseLine(BaseExpenseLine):
@property
def workcase(self):
rql = 'Any R WHERE E has_lines EL, EL eid %(el)s, E spent_for W, W ref R'
rset = self._cw.execute(rql, {'el': self.eid})
rql = "Any R WHERE E has_lines EL, EL eid %(el)s, E spent_for W, W ref R"
rset = self._cw.execute(rql, {"el": self.eid})
if rset:
return rset[0][0]
return None
......@@ -6,13 +6,13 @@ from cubicweb.server.sources import storages
class ServerStartupHook(hook.Hook):
__regid__ = 'drh.serverstartup'
events = ('server_startup', 'server_maintenance')
__regid__ = "drh.serverstartup"
events = ("server_startup", "server_maintenance")
def __call__(self):
bfssdir = join(self.repo.config.appdatahome, 'bfss')
bfssdir = join(self.repo.config.appdatahome, "bfss")
if not exists(bfssdir):
makedirs(bfssdir)
print('created', bfssdir)
print("created", bfssdir)
storage = storages.BytesFileSystemStorage(bfssdir)
storages.set_attribute_storage(self.repo, 'File', 'data', storage)
storages.set_attribute_storage(self.repo, "File", "data", storage)
sync_schema_props_perms('spent_for')
sync_schema_props_perms("spent_for")
sync_schema_props_perms('spent_for', syncprops=False)
sync_schema_props_perms("spent_for", syncprops=False)
add_entity_type('Training')
add_entity_type("Training")
if 'Training' not in schema:
add_entity_type('Training')
if "Training" not in schema:
add_entity_type("Training")
# workflows doen't understand yams inheritance
rql('SET WF workflow_of ET, ET default_workflow WF '
'WHERE WF workflow_of WC, WC name "Workcase", ET name "Training"')
rql(
"SET WF workflow_of ET, ET default_workflow WF "
'WHERE WF workflow_of WC, WC name "Workcase", ET name "Training"'
)
commit()
add_cube('oauth2')
drop_cube('trustedauth')
add_cube("oauth2")
drop_cube("trustedauth")
# -*- coding: utf-8 -*-
# postcreate script. You could setup a workflow here for example
for login in (u'alf', u'syt', u'nico', u'jphc', u'ocy', u'auc', u'katia',
u'graz', u'dede', u'juj', u'ludal', u'steph', u'arthur',
u'david', u'joel', u'gaston', u'adim'):
rql('INSERT CWUser E: E login %(login)s, E upassword %(login)s, E in_group G '
'WHERE G name "users"', {'login' : login})
rql('INSERT PaidByAccount P: P label %(label)s, P associated_to U WHERE U login %(login)s',
{'label' : u"refund account - %s" % login, 'login': login})
rql('INSERT PaidForAccount P: P label %(label)s', {'label' : u"charge account - %s" % login})
for login in (
u"alf",
u"syt",
u"nico",
u"jphc",
u"ocy",
u"auc",
u"katia",
u"graz",
u"dede",
u"juj",
u"ludal",
u"steph",
u"arthur",
u"david",
u"joel",
u"gaston",
u"adim",
):
rql(
"INSERT CWUser E: E login %(login)s, E upassword %(login)s, E in_group G "
'WHERE G name "users"',
{"login": login},
)
rql(
"INSERT PaidByAccount P: P label %(label)s, P associated_to U WHERE U login %(login)s",
{"label": u"refund account - %s" % login, "login": login},
)
rql(
"INSERT PaidForAccount P: P label %(label)s",
{"label": u"charge account - %s" % login},
)
for label in (u'Logilab - CB Nicolas', u'Logilab - CB Alexandre', u'Logilab - CB Olivier',
u'Logilab - Espèces'):
rql('INSERT PaidByAccount P: P label %(label)s', {'label' : label})
for label in (
u"Logilab - CB Nicolas",
u"Logilab - CB Alexandre",
u"Logilab - CB Olivier",
u"Logilab - Espèces",
):
rql("INSERT PaidByAccount P: P label %(label)s", {"label": label})
......@@ -9,11 +9,14 @@ class Training(Workcase):
class spent_for(RelationDefinition):
subject = 'Expense'
object = 'Workcase'
cardinality = '?*'
subject = "Expense"
object = "Workcase"
cardinality = "?*"
__permissions__ = {
'read': ('managers', 'users'),
'add': ('managers', RRQLExpression('NOT (S in_state ST, ST name "accepted")')),
'delete': ('managers', RRQLExpression('NOT (S in_state ST, ST name "accepted")')),
}
"read": ("managers", "users"),
"add": ("managers", RRQLExpression('NOT (S in_state ST, ST name "accepted")')),
"delete": (
"managers",
RRQLExpression('NOT (S in_state ST, ST name "accepted")'),
),
}
......@@ -7,12 +7,13 @@ from cubicweb.dataimport import stores, importer
# XXX class copied in crm/fresh, should be kepts sync
class CWClientLibDataFeedParser(datafeed.DataFeedParser):
"""Base class for parsers that search for distant entities using cwclientlib.
"""
"""Base class for parsers that search for distant entities using cwclientlib."""
def process_urls(self, *args, **kwargs):
"""IDataFeedParser main entry point."""
os.environ['CWCLCONF'] = os.path.join(self._cw.vreg.config.apphome, 'cwclientlibrc')
os.environ["CWCLCONF"] = os.path.join(
self._cw.vreg.config.apphome, "cwclientlibrc"
)
self._source_uris = {}
error = super(CWClientLibDataFeedParser, self).process_urls(*args, **kwargs)
if not error:
......@@ -22,44 +23,53 @@ class CWClientLibDataFeedParser(datafeed.DataFeedParser):
def process(self, url, raise_on_error=False):
"""Called once by process_urls (several URL are not expected with this parser)."""
# ensure url ends with a single slash for proper extid generation
url = url.rstrip('/') + '/'
url = url.rstrip("/") + "/"
eeimporter = self.build_importer(raise_on_error)
entities = self.extentities_generator(url)
set_cwuri = importer.use_extid_as_cwuri(eeimporter.extid2eid)
eeimporter.import_entities(set_cwuri(entities))
self.stats['created'] = eeimporter.created
self.stats['updated'] = eeimporter.updated
self.stats["created"] = eeimporter.created
self.stats["updated"] = eeimporter.updated
def build_importer(self, raise_on_error):
"""Instantiate and configure an importer"""
etypes, extid2eid = self.init_extid2eid()
existing_relations = self.init_existing_relations()
store = stores.NoHookRQLObjectStore(self._cw, metagen=stores.MetaGenerator(
self._cw, source=self.source))
return importer.ExtEntitiesImporter(self._cw.vreg.schema, store,
extid2eid=extid2eid,
existing_relations=existing_relations,
etypes_order_hint=etypes,
import_log=self.import_log,
raise_on_error=raise_on_error)
store = stores.NoHookRQLObjectStore(
self._cw, metagen=stores.MetaGenerator(self._cw, source=self.source)
)
return importer.ExtEntitiesImporter(
self._cw.vreg.schema,
store,
extid2eid=extid2eid,
existing_relations=existing_relations,
etypes_order_hint=etypes,
import_log=self.import_log,
raise_on_error=raise_on_error,
)
def handle_deletion(self, *args, **kwargs):
for extid, (eid, etype) in self._source_uris.items():
self._cw.entity_from_eid(eid, etype).cw_delete()
def existing_entities(self, etype):
rset = self._cw.execute('Any XURI, X WHERE X cwuri XURI, X is {0},'
' X cw_source S, S eid %(s)s'.format(etype),
{'s': self.source.eid})
rset = self._cw.execute(
"Any XURI, X WHERE X cwuri XURI, X is {0},"
" X cw_source S, S eid %(s)s".format(etype),
{"s": self.source.eid},
)
for extid, eid in rset:
self._source_uris[extid] = (eid, etype)
yield extid, eid
def states_map(self, etype):
return dict(self._cw.execute(
'Any SN,S WHERE S name SN, S state_of WF, '
'ET default_workflow WF, ET name %(etype)s',
{'etype': etype}))
return dict(
self._cw.execute(
"Any SN,S WHERE S name SN, S state_of WF, "
"ET default_workflow WF, ET name %(etype)s",
{"etype": etype},
)
)
def ext_entity(self, url, etype, eid, values):
extid = url + text_type(eid)
......@@ -69,13 +79,14 @@ class CWClientLibDataFeedParser(datafeed.DataFeedParser):
class DataFeedFreshActivity(CWClientLibDataFeedParser):
"""Parser to import workcases from crm."""
__regid__ = 'fresh.workcases'
__regid__ = "fresh.workcases"
def init_extid2eid(self):
# put state eids in extid2eid as we'll want to link to them
extid2eid = dict(self._cw.execute('Any X,X WHERE X is State'))
extid2eid = dict(self._cw.execute("Any X,X WHERE X is State"))
# map existing orders and workorders from our souce
etypes = ('Workcase',)
etypes = ("Workcase",)
for etype in etypes:
for extid, eid in self.existing_entities(etype):
extid2eid[extid] = eid
......@@ -84,9 +95,10 @@ class DataFeedFreshActivity(CWClientLibDataFeedParser):
def init_existing_relations(self):
existing_relations = {}
rset = self._cw.execute(
'Any O,OS WHERE O in_state OS, O is Workcase, O cw_source S, S eid %(s)s',
{'s': self.source.eid})
existing_relations['in_state'] = set(tuple(x) for x in rset)
"Any O,OS WHERE O in_state OS, O is Workcase, O cw_source S, S eid %(s)s",
{"s": self.source.eid},
)
existing_relations["in_state"] = set(tuple(x) for x in rset)
return existing_relations
def extentities_generator(self, url):
......@@ -94,16 +106,17 @@ class DataFeedFreshActivity(CWClientLibDataFeedParser):
proxy = cwclientlib.cwproxy_for(url)
# XXX check modification_date > last_update
# information necessary to relate order to a state
states_map = self.states_map('Workcase')
states_map = self.states_map("Workcase")
for args in proxy.execute(
'Any W,SN,WR,WS WHERE W is_instance_of Workcase, '
'W ref WR, W subject WS, W in_state S, S name SN'):
"Any W,SN,WR,WS WHERE W is_instance_of Workcase, "
"W ref WR, W subject WS, W in_state S, S name SN"
):
eid = args.pop(0)
state = args.pop(0)
values = values_dict(args, ['ref', 'subject'])
values['in_state'] = set([states_map[state]])
yield self.ext_entity(url, 'Workcase', eid, values)
values = values_dict(args, ["ref", "subject"])
values["in_state"] = set([states_map[state]])
yield self.ext_entity(url, "Workcase", eid, values)
def values_dict(values_list, attributes):
......
......@@ -5,19 +5,28 @@ from cubicweb.web.views.ajaxcontroller import ajaxfunc
_afs = uicfg.autoform_section
_affk = uicfg.autoform_field_kwargs
_afs.tag_subject_of(('Expense', 'spent_for', '*'), 'main', 'attributes')
_afs.tag_subject_of(('Expense', 'spent_for', '*'), 'muledit', 'attributes')
_affk.tag_subject_of(('Expense', 'spent_for', '*'),
{'widget': fw.LazyRestrictedAutoCompletionWidget(
autocomplete_initfunc='get_concerned_by',
autocomplete_settings={'limit': 100, 'delay': 300})})
_afs.tag_subject_of(("Expense", "spent_for", "*"), "main", "attributes")
_afs.tag_subject_of(("Expense", "spent_for", "*"), "muledit", "attributes")
_affk.tag_subject_of(
("Expense", "spent_for", "*"),
{
"widget": fw.LazyRestrictedAutoCompletionWidget(
autocomplete_initfunc="get_concerned_by",
autocomplete_settings={"limit": 100, "delay": 300},
)
},
)
@ajaxfunc(output_type='json')
@ajaxfunc(output_type="json")
def get_concerned_by(self):
term = self._cw.form['q']
limit = self._cw.form.get('limit', 50)
return [{'value': eid, 'label': ref}
for eid, ref in self._cw.execute('DISTINCT Any W,R ORDERBY R LIMIT %s WHERE W ref R,'
'W ref ILIKE %%(term)s' % limit,
{'term': u'%%%s%%' % term})]
term = self._cw.form["q"]
limit = self._cw.form.get("limit", 50)
return [
{"value": eid, "label": ref}
for eid, ref in self._cw.execute(
"DISTINCT Any W,R ORDERBY R LIMIT %s WHERE W ref R,"
"W ref ILIKE %%(term)s" % limit,
{"term": u"%%%s%%" % term},
)
]
......@@ -15,59 +15,64 @@ from cubicweb.view import EntityView
class ExpenseAccountingXmlView(EntityView):
__regid__ = 'accexpense'
__select__ = is_instance('Expense')
__regid__ = "accexpense"
__select__ = is_instance("Expense")
title = _('accounting entry view')
title = _("accounting entry view")
templatable = False
content_type = 'text/xml'
content_type = "text/xml"
def call(self):
"""display a list of entities by calling their <item_vid> view
"""
"""display a list of entities by calling their <item_vid> view"""
self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self._cw.encoding)
self.w(u'<?xml-stylesheet href="%saccounting-entries.xsl" '
u'rel="stylesheet" type="text/xsl"?>\n' % self._cw.datadir_url)
self.w(u'<ecritures>\n')
self.w(
u'<?xml-stylesheet href="%saccounting-entries.xsl" '
u'rel="stylesheet" type="text/xsl"?>\n' % self._cw.datadir_url
)
self.w(u"<ecritures>\n")
for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(u'</ecritures>\n')
self.w(u"</ecritures>\n")
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
rset = entity.related('has_lines')
rset = entity.related("has_lines")
for i in range(len(rset)):
self.wview('accentry', rset, row=i, col=0)
self.wview("accentry", rset, row=i, col=0)
class ExpenseLineAccountingEntryXmlView(EntityView):
__regid__ = 'accentry'
__select__ = is_instance('ExpenseLine',)
__regid__ = "accentry"
__select__ = is_instance(
"ExpenseLine",
)
title = _('accounting entry view')
title = _("accounting entry view")
templatable = False
content_type = 'text/xml'
content_type = "text/xml"
def call(self):
"""display a list of entities by calling their <item_vid> view
"""
"""display a list of entities by calling their <item_vid> view"""
self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self._cw.encoding)
self.w(u'<?xml-stylesheet href="%saccounting-entries.xsl" '
u'rel="stylesheet" type="text/xsl"?>\n' % self._cw.datadir_url)
self.w(u'<ecritures>\n')
self.w(
u'<?xml-stylesheet href="%saccounting-entries.xsl" '
u'rel="stylesheet" type="text/xsl"?>\n' % self._cw.datadir_url
)
self.w(u"<ecritures>\n")
for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(u'</ecritures>\n')
self.w(u"</ecritures>\n")
def cell_call(self, row, col):
entity = self.cw_rset.complete_entity(row, col)
self.w(u' <ecriture date="%s">\n' % entity.diem.strftime('%Y-%m-%d'))
self.w(u' <libelle>%s</libelle>\n' % xml_escape(entity.dc_long_title()))
self.w(u' <ecriture date="%s">\n' % entity.diem.strftime("%Y-%m-%d"))
self.w(u" <libelle>%s</libelle>\n" % xml_escape(entity.dc_long_title()))
amount = round(entity.euro_amount(), 2)
taxes = round(entity.taxes, 2)
account = entity.paid_by[0].account and xml_escape(entity.paid_by[0].account) or u''
self.w(u' <credit compte="%s" montant="%.2f" />\n'
% (account, amount))
account = (
entity.paid_by[0].account and xml_escape(entity.paid_by[0].account) or u""
)
self.w(u' <credit compte="%s" montant="%.2f" />\n' % (account, amount))
if entity.taxes:
# XXX hardcoded account for VAT
self.w(u' <debit compte="44566" montant="%.2f" />\n' % entity.taxes)
......@@ -81,9 +86,8 @@ class ExpenseLineAccountingEntryXmlView(EntityView):
debit_remainder -= 1
else:
debit = debit_quotient / 100.0
account = account.account and xml_escape(account.account) or u''
self.w(u' <debit compte="%s" montant="%.2f" />\n'
% (account, debit))
account = account.account and xml_escape(account.account) or u""
self.w(u' <debit compte="%s" montant="%.2f" />\n' % (account, debit))
if entity.workcase:
self.w(u' <groupe>%s</groupe>\n' % xml_escape(entity.workcase))
self.w(u' </ecriture>\n')
self.w(u" <groupe>%s</groupe>\n" % xml_escape(entity.workcase))
self.w(u" </ecriture>\n")
......@@ -12,10 +12,10 @@ from cubicweb.web.action import Action
class AccountingAction(Action):
__regid__ = 'accaction'
__select__ = is_instance('Expense')
title = _('generate accounting entries')
__regid__ = "accaction"
__select__ = is_instance("Expense")
title = _("generate accounting entries")
def url(self):
entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
return entity.absolute_url(vid='accexpense')
return entity.absolute_url(vid="accexpense")
......@@ -32,34 +32,34 @@ here = dirname(__file__)
# load metadata from the __pkginfo__.py file so there is no risk of conflict
# see https://packaging.python.org/en/latest/single_source_version.html
pkginfo = join(here, 'cubicweb_fresh', '__pkginfo__.py')
pkginfo = join(here, "cubicweb_fresh", "__pkginfo__.py")
__pkginfo__ = {}
with open(pkginfo) as f:
exec(f.read(), __pkginfo__)
# get required metadatas
distname = __pkginfo__['distname']
version = __pkginfo__['version']
license = __pkginfo__['license']
description = __pkginfo__['description']
web = __pkginfo__['web']
author = __pkginfo__['author']
author_email = __pkginfo__['author_email']
classifiers = __pkginfo__['classifiers']
distname = __pkginfo__["distname"]
version = __pkginfo__["version"]
license = __pkginfo__["license"]
description = __pkginfo__["description"]
web = __pkginfo__["web"]
author = __pkginfo__["author"]
author_email = __pkginfo__["author_email"]
classifiers = __pkginfo__["classifiers"]
with open(join(here, 'README.rst')) as f:
with open(join(here, "README.rst")) as f:
long_description = f.read()
# get optional metadatas
data_files = __pkginfo__.get('data_files', None)
dependency_links = __pkginfo__.get('dependency_links', ())
data_files = __pkginfo__.get("data_files", None)
dependency_links = __pkginfo__.get("dependency_links", ())
requires = {}
for entry in ("__depends__",): # "__recommends__"):
requires.update(__pkginfo__.get(entry, {}))
install_requires = ["{0} {1}".format(d, v and v or "").strip()
for d, v in requires.items()]
install_requires = [
"{0} {1}".format(d, v and v or "").strip() for d, v in requires.items()
]
setup(
......@@ -72,12 +72,12 @@ setup(
author_email=author_email,
url=web,
classifiers=classifiers,
packages=find_packages(exclude=['test']),
packages=find_packages(exclude=["test"]),
install_requires=install_requires,
include_package_data=True,
entry_points={
'cubicweb.cubes': [
'fresh=cubicweb_fresh',
"cubicweb.cubes": [
"fresh=cubicweb_fresh",
],
},
zip_safe=False,
......
......@@ -8,11 +8,13 @@ from cubicweb.devtools.testlib import AutomaticWebTest
class AutomaticWebTest(AutomaticWebTest):
vid_validators = AutomaticWebTest.vid_validators.copy()
vid_validators.update({
'accexpense': XMLValidator,
'accentry': XMLValidator,
})