Quick solution
😎
SELECT
RoleName = max(pr.name )
,RoleType = max(pr.type_desc )
,perms = max( X.PERMS )
,ObjectName = max(s.name + '.' + o.name )
,ObjectType = max(o.type_desc )
,Created = max(o.create_date )
,Altered = max(o.modify_date )
FROM sys.database_principals AS pr
JOIN sys.database_permissions pe ON pe.grantee_principal_id=pr.principal_id
RIGHT JOIN sys.objects o ON pe.major_id=o.object_id
JOIN sys.schemas s ON o.schema_id=s.schema_id
CROSS APPLY
(SELECT STUFF ( (SELECT NCHAR(44) + spe.permission_name
FROM sys.database_permissions spe
WHERE pe.grantee_principal_id = spe.grantee_principal_id
FOR XML PATH(''),TYPE).value('.[1]','NVARCHAR(512)')
,1,1,'')) AS X(PERMS)
WHERE is_ms_shipped=0
AND o.TYPE IN ('FN','P','U','V','TF')
AND pr.name IS NOT NULL
GROUP BY pr.name
,pr.type_desc
,s.name + '.' + o.name
,pe.grantee_principal_id
,o.type
,o.name
,X.PERMS
ORDER BY CASE WHEN pr.name IS NULL THEN 0 ELSE 1 END
,o.type
,o.name
,pr.name;