feat(project): show presign counts as a statistics column
Group presign counts by project and team, include totals and unassigned rows, and reuse count drill-down. Remove the standalone footer while retaining presignTotal compatibility and the four formal business types. Related to issue #13. Independent source review completed; no tests or builds run under user self-test arrangement.
This commit is contained in:
1 parent
ce8babcb7b
commit
79ca01ac0d
5 files changed
+66
-9
No files matched your search
@@ -131,10 +131,11 @@ def records(db, tenant, user, biz_type, page=1, pageSize=20, **filters):
|
||||
def statistics(db, tenant, user, groupBy='project', **filters):
|
||||
if groupBy not in ('project', 'team'):
|
||||
raise HTTPException(400, '分组方式不支持')
|
||||
totals = dict.fromkeys(COUNT_TYPES, 0)
|
||||
unassigned = dict.fromkeys(COUNT_TYPES, 0)
|
||||
statistics_types = ('presign', *COUNT_TYPES)
|
||||
totals = dict.fromkeys(statistics_types, 0)
|
||||
unassigned = dict.fromkeys(statistics_types, 0)
|
||||
counts = {}
|
||||
for kind in COUNT_TYPES:
|
||||
for kind in statistics_types:
|
||||
model = BUSINESS[kind][0]
|
||||
counts[kind] = filtered_query(db, tenant, user, kind, filters).with_entities(
|
||||
model.project_id, func.count(model.id)).group_by(model.project_id).all()
|
||||
@@ -159,10 +160,10 @@ def statistics(db, tenant, user, groupBy='project', **filters):
|
||||
key = team_id if groupBy == 'team' else project_id
|
||||
item = items.setdefault(key, dict(id=key,
|
||||
name=team_name if groupBy == 'team' else (info.project_name if info else None),
|
||||
teamName=team_name, **dict.fromkeys(COUNT_TYPES, 0)))
|
||||
teamName=team_name, **dict.fromkeys(statistics_types, 0)))
|
||||
item[kind] += count
|
||||
return dict(items=list(items.values()), totals=totals, unassignedTotals=unassigned,
|
||||
presignTotal=filtered_query(db, tenant, user, 'presign', filters).count())
|
||||
presignTotal=totals['presign'])
|
||||
|
||||
|
||||
def linked_records(db, tenant, user, kind, row_id, lock=False, current_read=False):
|
||||
|
||||
@@ -70,6 +70,54 @@ class ProjectManagementTest(unittest.TestCase):
|
||||
self.assertEqual(self.db.get(BizPresignOrder, 's').project_id, 'p')
|
||||
self.assertEqual(len(self.svc.assignment_history(self.db, 't', self.user, 'cell_storage', 'a')['list']), 1)
|
||||
|
||||
def test_presign_statistics_column_groups_totals_and_drill_down(self):
|
||||
from datetime import datetime
|
||||
from app.models.models import BizCollectionProtocol, BizPresignOrder
|
||||
self.db.add_all([
|
||||
self.Team(id='g2', tenant_no='t', team_name='Presign only', leader_user_id='u'),
|
||||
self.Project(id='p2', tenant_no='t', project_no='P2', project_name='Presign only',
|
||||
team_id='g2', leader_user_id='u', biz_types='cell_storage', status='active'),
|
||||
BizCollectionProtocol(id='protocol', tenant_no='t', protocol_no='CP', project_id='p',
|
||||
create_time=datetime(2026, 11, 4)),
|
||||
])
|
||||
for row_id, project_id, status, tenant, deleted, day in (
|
||||
('active', 'p', 'active', 't', 0, 4),
|
||||
('converted', 'p', 'converted', 't', 0, 4),
|
||||
('draft', 'p2', 'draft', 't', 0, 4),
|
||||
('void', None, 'void', 't', 0, 4),
|
||||
('foreign', 'p', 'active', 'foreign', 0, 4),
|
||||
('deleted', 'p', 'active', 't', 1, 4),
|
||||
('old', 'p', 'active', 't', 0, 1),
|
||||
):
|
||||
self.db.add(BizPresignOrder(
|
||||
id=row_id, tenant_no=tenant, protocol_no=row_id, project_id=project_id,
|
||||
order_status=status, del_flag=deleted, create_by='u',
|
||||
create_time=datetime(2026, 11, day),
|
||||
converted_protocol_id='protocol' if status == 'converted' else None,
|
||||
))
|
||||
self.db.commit()
|
||||
filters = dict(startDate='2026-11-04', endDate='2026-11-04')
|
||||
for group_by, expected in (('project', {'p': 2, 'p2': 1}), ('team', {'g': 2, 'g2': 1})):
|
||||
with self.subTest(group_by=group_by):
|
||||
result = self.svc.statistics(self.db, 't', self.user, groupBy=group_by, **filters)
|
||||
self.assertEqual(result['totals']['presign'], 4)
|
||||
self.assertEqual(result['presignTotal'], 4)
|
||||
self.assertEqual(result['unassignedTotals']['presign'], 1)
|
||||
self.assertEqual(result['totals']['cell_storage'], 1)
|
||||
self.assertEqual({r['id']: r['presign'] for r in result['items']}, expected)
|
||||
for row in result['items']:
|
||||
drill = {('teamId' if group_by == 'team' else 'projectId'): row['id']}
|
||||
self.assertEqual(self.svc.records(self.db, 't', self.user, 'presign', **drill, **filters)['total'], row['presign'])
|
||||
for selection in (dict(teamId='g'), dict(projectId='p')):
|
||||
result = self.svc.statistics(self.db, 't', self.user, **selection, **filters)
|
||||
self.assertEqual(result['totals']['presign'], 2)
|
||||
self.assertEqual(result['unassignedTotals']['presign'], 0)
|
||||
self.assertEqual(self.svc.records(self.db, 't', self.user, 'presign', unassigned=True, **filters)['total'], 1)
|
||||
denied = self.svc.statistics(self.db, 't', dict(user_id='outsider', role='admin'), **filters)
|
||||
self.assertEqual(denied['totals']['presign'], 0)
|
||||
self.assertEqual(denied['items'], [])
|
||||
self.assertNotIn('presign', self.svc.COUNT_TYPES)
|
||||
|
||||
def test_team_child_ids_survive_edits(self):
|
||||
from app.models.models import SysUser
|
||||
self.db.add(SysUser(id='u', tenant_no='t', user_no='u', nick_name='User'))
|
||||
|
||||
Reference in new issue
Block a user