Skip to content

Commit

Permalink
Merge pull request #1471 from bcgov/LCFS-1426-UploadFileAttachements-…
Browse files Browse the repository at this point in the history
…ComplianceReports

LCFS-1426: Upload file attachements compliance reports for Analyst user
  • Loading branch information
areyeslo authored Dec 20, 2024
2 parents 15ff76b + faae96e commit 7314769
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 19 deletions.
27 changes: 26 additions & 1 deletion backend/lcfs/services/s3/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from fastapi import HTTPException
import os
import uuid
from lcfs.db.models.compliance.ComplianceReportStatus import ComplianceReportStatusEnum
from lcfs.db.models.user.Role import RoleEnum
from lcfs.web.api.compliance_report.services import ComplianceReportServices
from fastapi import Depends
from pydantic.v1 import ValidationError
from sqlalchemy import select
Expand All @@ -26,13 +30,34 @@ def __init__(
db: AsyncSession = Depends(get_async_db_session),
clamav_service: ClamAVService = Depends(),
s3_client=Depends(get_s3_client),
compliance_report_service: ComplianceReportServices = Depends(),
):
self.db = db
self.clamav_service = clamav_service
self.s3_client = s3_client
self.compliance_report_service = compliance_report_service

@repo_handler
async def upload_file(self, file, parent_id: str, parent_type="compliance_report"):
async def upload_file(
self, file, parent_id: str, parent_type="compliance_report", user=None
):
compliance_report = (
await self.compliance_report_service.get_compliance_report_by_id(parent_id)
)
if not compliance_report:
raise HTTPException(status_code=404, detail="Compliance report not found")

# Check if the user is a supplier and the compliance report status is different from Draft
if (
RoleEnum.SUPPLIER in user.role_names
and compliance_report.current_status.status
!= ComplianceReportStatusEnum.Draft.value
):
raise HTTPException(
status_code=400,
detail="Suppliers can only upload files when the compliance report status is Draft",
)

file_id = uuid.uuid4()
file_key = f"{settings.s3_docs_path}/{parent_type}/{parent_id}/{file_id}"

Expand Down
9 changes: 7 additions & 2 deletions backend/lcfs/web/api/document/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from http.client import HTTPException
from lcfs.db.models.compliance.ComplianceReportStatus import ComplianceReportStatusEnum
from lcfs.web.api.compliance_report.services import ComplianceReportServices
import structlog
from typing import List

Expand Down Expand Up @@ -40,15 +43,17 @@ async def get_all_documents(
response_model=FileResponseSchema,
status_code=status.HTTP_201_CREATED,
)
@view_handler([RoleEnum.SUPPLIER])
@view_handler([RoleEnum.SUPPLIER, RoleEnum.ANALYST])
async def upload_file(
request: Request,
parent_id: int,
parent_type: str,
file: UploadFile = File(...),
document_service: DocumentService = Depends(),
) -> FileResponseSchema:
document = await document_service.upload_file(file, parent_id, parent_type)
document = await document_service.upload_file(
file, parent_id, parent_type, request.user
)
return FileResponseSchema.model_validate(document)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import BCModal from '@/components/BCModal'
import BCButton from '@/components/BCButton'
import Loading from '@/components/Loading'
import { Role } from '@/components/Role'
import { roles } from '@/constants/roles'
import { Fab, Stack, Tooltip } from '@mui/material'
import BCTypography from '@/components/BCTypography'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
Expand Down Expand Up @@ -80,7 +81,8 @@ export const EditViewComplianceReport = ({ reportData, isError, error }) => {
hasRoles
} = useCurrentUser()
const isGovernmentUser = currentUser?.isGovernmentUser

const isAnalystRole = currentUser?.roles?.some(role => role.name === roles.analyst) || false;

const currentStatus = reportData?.report.currentStatus?.status
const { data: orgData, isLoading } = useOrganization(
reportData?.report.organizationId
Expand Down Expand Up @@ -209,7 +211,7 @@ export const EditViewComplianceReport = ({ reportData, isError, error }) => {
</Stack>
{!location.state?.newReport && (
<>
<ReportDetails currentStatus={currentStatus} />
<ReportDetails currentStatus={currentStatus} isAnalystRole={isAnalystRole}/>
<ComplianceReportSummary
reportID={complianceReportId}
currentStatus={currentStatus}
Expand Down
50 changes: 36 additions & 14 deletions frontend/src/views/ComplianceReports/components/ReportDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ import { FuelExportSummary } from '@/views/FuelExports/FuelExportSummary'
import { SupportingDocumentSummary } from '@/views/SupportingDocuments/SupportingDocumentSummary'
import DocumentUploadDialog from '@/components/Documents/DocumentUploadDialog'
import { useComplianceReportDocuments } from '@/hooks/useComplianceReports'
import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses'

const ReportDetails = ({ currentStatus = 'Draft' }) => {
const ReportDetails = ({ currentStatus = 'Draft', isAnalystRole }) => {
const { t } = useTranslation()
const { compliancePeriod, complianceReportId } = useParams()
const navigate = useNavigate()

const [isFileDialogOpen, setFileDialogOpen] = useState(false)
const editSupportingDocs = useMemo(() => {
return isAnalystRole && (
currentStatus === COMPLIANCE_REPORT_STATUSES.SUBMITTED ||
currentStatus === COMPLIANCE_REPORT_STATUSES.ASSESSED
) || currentStatus === COMPLIANCE_REPORT_STATUSES.DRAFT;
}, [isAnalystRole, currentStatus]);

const isArrayEmpty = useCallback((data) => {
if (Array.isArray(data)) {
Expand All @@ -64,11 +71,22 @@ const ReportDetails = ({ currentStatus = 'Draft' }) => {
},
useFetch: useComplianceReportDocuments,
component: (data) => (
<SupportingDocumentSummary
data={data}
reportID={complianceReportId}
/>
)
<>
<SupportingDocumentSummary
data={data}
reportID={complianceReportId}
/>
<DocumentUploadDialog
parentID={complianceReportId}
parentType="compliance_report"
open={isFileDialogOpen}
close={() => {
setFileDialogOpen(false)
}}
/>
</>
),
condition: true
},
{
name: t('report:activityLists.supplyOfFuel'),
Expand Down Expand Up @@ -171,9 +189,13 @@ const ReportDetails = ({ currentStatus = 'Draft' }) => {
]
)

const [expanded, setExpanded] = useState(() =>
activityList.map((_, index) => `panel${index}`)
)
const [expanded, setExpanded] = useState(activityList.map((activity, index) => {
if (activity.name === t('report:supportingDocs')) {
return isArrayEmpty(activity.useFetch(complianceReportId).data) ? '' : `panel${index}`
}
return `panel${index}`
}).filter(Boolean)) // Initialize with panels that should be open by default

const [allExpanded, setAllExpanded] = useState(true)

const handleChange = (panel) => (event, isExpanded) => {
Expand Down Expand Up @@ -217,11 +239,10 @@ const ReportDetails = ({ currentStatus = 'Draft' }) => {
{activityList.map((activity, index) => {
const { data, error, isLoading } = activity.useFetch(complianceReportId)
return (
data &&
!isArrayEmpty(data) && (
(data && !isArrayEmpty(data) || activity.name === t('report:supportingDocs')) && (
<Accordion
key={index}
expanded={expanded.includes(`panel${index}`)}
expanded={activity.name === t('report:supportingDocs') ? expanded.includes(`panel${index}`) && !isArrayEmpty(data) : expanded.includes(`panel${index}`)}
onChange={handleChange(`panel${index}`)}
>
<AccordionSummary
Expand All @@ -239,13 +260,14 @@ const ReportDetails = ({ currentStatus = 'Draft' }) => {
component="div"
>
{activity.name}&nbsp;&nbsp;
{currentStatus === 'Draft' && (
{editSupportingDocs && (
<>
<Role
roles={[
roles.supplier,
roles.compliance_reporting,
roles.compliance_reporting
roles.compliance_reporting,
roles.analyst
]}
>
<IconButton
Expand Down

0 comments on commit 7314769

Please sign in to comment.