feat(project): show business fields in statistics details
Reuse assignment business columns and keyword searches in the four statistics drill-down lists. Add a statistics-permission read endpoint sharing tenant-scoped detail queries without granting assignment access. Related to issue #13. Independent static review completed. User self-test arrangement: regression cases authored, no tests or builds executed.
This commit is contained in:
1 parent
f04e24186f
commit
fa5efa9629
7 files changed
+106
-8
No files matched your search
@@ -59,6 +59,65 @@ class ProjectAssignmentRecordsTest(unittest.TestCase):
|
||||
self.db.commit()
|
||||
self.assertEqual([r['id'] for r in self.records()['list']], ['own'])
|
||||
|
||||
def test_statistics_detail_permission_is_separate_from_assignment(self):
|
||||
self.user['role'] = 'admin'
|
||||
self.grant('project:statistics:list')
|
||||
self.db.add_all([
|
||||
BizCollectionProtocol(id='own', tenant_no='t', protocol_no='OWN', create_by='u'),
|
||||
BizCollectionProtocol(id='other', tenant_no='t', protocol_no='OTHER', create_by='other'),
|
||||
BizCollectionProtocol(id='foreign', tenant_no='foreign', protocol_no='FOREIGN', create_by='u'),
|
||||
BizCollectionProtocol(id='deleted', tenant_no='t', protocol_no='DELETED', create_by='u', del_flag=1),
|
||||
BizProtocolPartyCustomer(id='p', tenant_no='t', collection_protocol_id='own', mother_name='Mother', mother_phone='13800000000'),
|
||||
BizProtocolSample(id='s', tenant_no='t', collection_protocol_id='own', sample_code='SAMPLE'),
|
||||
])
|
||||
self.db.commit()
|
||||
result = svc.statistics_records(self.db, 't', self.user, 'cell_storage', keyword='SAMPLE')
|
||||
self.assertEqual(result['total'], 1)
|
||||
self.assertEqual(result['list'][0]['motherName'], 'Mother')
|
||||
self.assertEqual(result['list'][0]['motherPhone'], '13800000000')
|
||||
self.assertEqual(result['list'][0]['sampleCodes'], 'SAMPLE')
|
||||
self.assertEqual(svc.statistics_records(self.db, 't', self.user, 'cell_storage')['total'], 1)
|
||||
with self.assertRaises(HTTPException) as denied:
|
||||
self.records()
|
||||
self.assertEqual(denied.exception.status_code, 403)
|
||||
self.db.get(SysRole, 'project:statistics:list').status = '0'
|
||||
self.db.commit()
|
||||
self.grant('project:assignment:edit')
|
||||
self.assertEqual(self.records()['total'], 1)
|
||||
with self.assertRaises(HTTPException) as denied:
|
||||
svc.statistics_records(self.db, 't', self.user, 'cell_storage')
|
||||
self.assertEqual(denied.exception.status_code, 403)
|
||||
|
||||
def test_four_statistics_details_share_fields_and_match_summary_counts(self):
|
||||
cases = (
|
||||
('cell_storage', BizCollectionProtocol, dict(protocol_no='C'), 'sampleCodes'),
|
||||
('research_donation', BizResearchDonation, dict(donation_no='D'), 'motherName'),
|
||||
('pilot_service', BizPilotApplication, dict(application_no='P', channel_service_order_id='', biz_type='pilot_service', application_name='Pilot'), 'applicationName'),
|
||||
('basic_experiment', BizPilotApplication, dict(application_no='B', channel_service_order_id='', biz_type='basic_experiment', project_title='Study'), 'projectTitle'),
|
||||
)
|
||||
for kind, model, fields, detail_key in cases:
|
||||
self.db.add_all([
|
||||
model(id=kind + '-assigned', tenant_no='t', project_id='project', create_time=datetime(2026, 11, 4), **fields),
|
||||
model(id=kind + '-empty', tenant_no='t', create_time=datetime(2026, 11, 4), **fields),
|
||||
model(id=kind + '-old', tenant_no='t', create_time=datetime(2026, 11, 1), **fields),
|
||||
])
|
||||
self.db.commit()
|
||||
filters = dict(startDate='2026-11-04', endDate='2026-11-04')
|
||||
summary = project_management.statistics(self.db, 't', self.user, **filters)
|
||||
for kind, _, _, detail_key in cases:
|
||||
with self.subTest(kind=kind):
|
||||
details = svc.statistics_records(self.db, 't', self.user, kind, **filters)
|
||||
self.assertEqual(details, self.records(kind, **filters))
|
||||
self.assertEqual(details['total'], summary['totals'][kind])
|
||||
self.assertEqual(details['total'], 2)
|
||||
self.assertIn(detail_key, details['list'][0])
|
||||
unassigned = svc.statistics_records(self.db, 't', self.user, kind, unassigned=True, **filters)
|
||||
self.assertEqual(unassigned['total'], summary['unassignedTotals'][kind])
|
||||
self.assertEqual(unassigned['list'][0]['id'], kind + '-empty')
|
||||
assigned = svc.statistics_records(self.db, 't', self.user, kind, projectId='project', **filters)
|
||||
self.assertEqual(assigned['total'], 1)
|
||||
self.assertEqual(assigned['list'][0]['id'], kind + '-assigned')
|
||||
|
||||
def test_children_do_not_duplicate_counts_or_leak_foreign_deleted_data(self):
|
||||
self.db.add_all([
|
||||
BizCollectionProtocol(id='a', tenant_no='t', protocol_no='A', protocol_status='sxz'),
|
||||
|
||||
Reference in new issue
Block a user