Skip to content

Commit

Permalink
Tracking pull request to merge release-2.1.0 to master (#1966)
Browse files Browse the repository at this point in the history
* update to 2.1.0

* update to 2.1.0

* -changes text that is displayed after proposing to buy credit, so it now shows price per credit

* fix: refresh token updates

* fix: tfrs-556 - accessing assessment page

* feat: tfrs-514 - inactive suppliers can't accept credit transfers

* fix/feat - adds condition before appending edit and adding  to permissions for comment

* feat - adds supplier status to trade information page

* ZELDA-549 - Schedule D in B persistence issue fix

* ZELDA-558 - Notification page search box issue fix

* fix: tfrs-559 - credit transactions in downloaded spreadsheet

* chore: version bump on certifi

* fix: responsive navbar and banner by adding a media query (and extra div) to navbar items and updating breakpoint for banner

* add valut (#1991)

* fix: tfrs-583 - compliance reporting assessment section

* dockerfile changes

* ZELDA-584- Submit more than 1 exclusion report fix

* update pr number to tracking pr number 1966

* Quick fix - added loading component

* ZELDA-594 update RLCF-017 link

* update for db migration (#2004)

* roll back minio (#2006)

* ZELDA-600-fix Unable to create new fuel suppliers in TFRS

* fix: removed duplicate jquery

* fix: check for null records on scheduleDSheetIndex

* update db upgrading doc (#2027)

* feat: filters updated for pagination

* ZELDA-595 Add Sort & filter to All Tables

* fix: displayname filter fix

Co-authored-by: emi-hi <[email protected]>
Co-authored-by: AlexZorkin <[email protected]>
Co-authored-by: tim738745 <[email protected]>
Co-authored-by: Emily <[email protected]>
Co-authored-by: Alex Zorkin <[email protected]>
Co-authored-by: vibhishan <[email protected]>
Co-authored-by: jig-patel <[email protected]>
  • Loading branch information
8 people authored Jan 25, 2023
1 parent 2c5001b commit 9a09a68
Show file tree
Hide file tree
Showing 72 changed files with 1,646 additions and 710 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build-release.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
## For each release, the value of workflow name, branches and PR_NUMBER need to be adjusted accordingly

name: TFRS release-2.0.0
name: TFRS release-2.1.0

on:
push:
branches: [ release-2.0.0 ]
branches: [ release-2.1.0 ]
workflow_dispatch:
workflow_call:

env:
## The pull request number of the Tracking pull request to merge the release branch to main
## Also remember to update the version in .pipeline/lib/config.js
PR_NUMBER: 1824
RELEASE_NAME: release-2.0.0
PR_NUMBER: 1966
RELEASE_NAME: release-2.1.0

jobs:

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,4 @@ dev/
node_modules/

.sql.gz
*.sql
14 changes: 0 additions & 14 deletions .pipeline/lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,6 @@ module.exports = settings => {
'GIT_REF': oc.git.ref
}
}))

/** to be deleted once 2.0.0 is on prod
//build frontend
objects = objects.concat(oc.processDeploymentTemplate(`${templatesLocalBaseUrl}/templates/frontend/frontend-angular-app-bc.yaml`, {
'param':{
'NAME': phases[phase].name,
'SUFFIX': phases[phase].suffix,
'VERSION': phases[phase].tag,
'GIT_URL': oc.git.http_url,
'GIT_REF': oc.git.ref
}
}))
*/


objects = objects.concat(oc.processDeploymentTemplate(`${templatesLocalBaseUrl}/templates/frontend/frontend-bc-docker.yaml`, {
'param':{
Expand Down
6 changes: 3 additions & 3 deletions .pipeline/lib/config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';
const options= require('@bcgov/pipeline-cli').Util.parseArguments()
const changeId = options.pr //aka pull-request
const version = '2.0.0'
const version = '2.1.0'
const name = 'tfrs'
const ocpName = 'apps.silver.devops'

Expand All @@ -13,7 +13,7 @@ options.git.repository='tfrs'
const phases = {
build: { namespace:'0ab226-tools' , name: `${name}`, phase: 'build' , changeId:changeId, suffix: `-build-${changeId}` ,
instance: `${name}-build-${changeId}` , version:`${version}-${changeId}`, tag:`build-${version}-${changeId}`,
releaseBranch: 'release-2.0.0'
releaseBranch: 'release-2.1.0'
},
dev: {namespace:'0ab226-dev' , name: `${name}`, phase: 'dev' , changeId:changeId, suffix: `-dev` ,
instance: `${name}-dev` , version:`${version}`, tag:`dev-${version}`, dbServiceName: 'tfrs-spilo',
Expand Down Expand Up @@ -45,7 +45,7 @@ const phases = {
schemaSpyAuditCpuRequest: '50m', schemaSpyAuditCpuLimit: '300m', schemaSpyAuditMemoryRequest: '256Mi', schemaSpyAuditMemoryLimit: '512Mi'
},
test: {namespace:'0ab226-test' , name: `${name}`, phase: 'test' , changeId:changeId, suffix: `-test` ,
instance: `${name}-test` , version:`${version}`, tag:`test-${version}`, dbServiceName: 'patroni-master-test',
instance: `${name}-test` , version:`${version}`, tag:`test-${version}`, dbServiceName: 'tfrs-spilo',
frontendCpuRequest: '40m', frontendCpuLimit: '80m', frontendMemoryRequest: '60Mi', frontendMemoryLimit: '120Mi', frontendReplicas: 2,
frontendKeycloakAuthority: 'https://test.loginproxy.gov.bc.ca/auth', frontendKeycloakClientId: 'tfrs-on-gold-4308', frontendKeycloakCallbackUrl: `https://tfrs-test.${ocpName}.gov.bc.ca`,
frontendKeycloakLogoutUrl: `https://tfrs-test.${ocpName}.gov.bc.ca`,
Expand Down
2 changes: 1 addition & 1 deletion backend/Dockerfile-django
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.7-stretch
FROM --platform=linux/amd64 python:3.7-stretch
ENV PYTHONUNBUFFERED 1
RUN mkdir /app
WORKDIR /app
Expand Down
23 changes: 14 additions & 9 deletions backend/api/services/CreditTradeCommentActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
from api.models import CreditTrade, CreditTradeComment
from api.models import CreditTradeComment
from api.models.CreditTrade import CreditTrade

from api.models.CreditTradeHistory import CreditTradeHistory
from api.permissions.CreditTradeComment import CreditTradeCommentPermissions

Expand All @@ -35,22 +37,25 @@ class CreditTradeCommentActions(object):
def available_comment_actions(request, trade: CreditTrade):
available_actions = []

if CreditTradeCommentPermissions.user_can_comment(
request.user, trade, False):
available_actions.append('ADD_COMMENT')
if not trade.is_rescinded and trade.status.status not in ['Declined', 'Cancelled', 'Refused', 'Approved']:

if CreditTradeCommentPermissions.user_can_comment(
request.user, trade, True):
available_actions.append('ADD_PRIVILEGED_COMMENT')
if CreditTradeCommentPermissions.user_can_comment(
request.user, trade, False):
available_actions.append('ADD_COMMENT')

return available_actions
if CreditTradeCommentPermissions.user_can_comment(
request.user, trade, True):
available_actions.append('ADD_PRIVILEGED_COMMENT')

return available_actions

@staticmethod
def available_individual_comment_actions(request, comment: CreditTradeComment):
available_actions = []
trade = CreditTrade.objects.filter(id=comment.credit_trade_id).first()

if CreditTradeCommentPermissions.user_can_edit_comment(
request.user, comment):
request.user, comment) and not trade.is_rescinded and trade.status.status not in ['Declined', 'Cancelled', 'Refused', 'Approved']:
available_actions = ['EDIT_COMMENT']

return available_actions
Expand Down
14 changes: 11 additions & 3 deletions backend/api/services/SpreadSheetBuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,17 @@ def add_credit_transfers(self, credit_trades, user):
credit_trade.fair_market_value_per_credit,
value_format)

worksheet.write(row_index, 7, credit_trade.status.friendly_name)
worksheet.write(row_index, 8, credit_trade.trade_effective_date,
date_format)
if credit_trade.is_rescinded:
worksheet.write(row_index, 7, "Rescinded")
elif (not user.is_government_user) and (credit_trade.status.friendly_name == "Reviewed"):
worksheet.write(row_index, 7, "Signed")
else:
worksheet.write(row_index, 7, credit_trade.status.friendly_name)

if credit_trade.trade_effective_date:
worksheet.write(row_index, 8, credit_trade.trade_effective_date, date_format)
elif credit_trade.type.the_type in ["Credit Reduction", "Credit Validation"] and credit_trade.update_timestamp:
worksheet.write(row_index, 8, credit_trade.update_timestamp.date(), date_format)

comments = credit_trade.unprivileged_comments

Expand Down
154 changes: 115 additions & 39 deletions backend/api/viewsets/ComplianceReport.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.db import transaction
from django.db.models import Count
from django.http import JsonResponse, HttpResponse
from django.http import HttpResponse
from rest_framework import viewsets, mixins, filters, status
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
Expand All @@ -17,15 +17,15 @@
ComplianceReportTypeSerializer, ComplianceReportListSerializer, \
ComplianceReportCreateSerializer, ComplianceReportUpdateSerializer, \
ComplianceReportDeleteSerializer, ComplianceReportDetailSerializer, \
ComplianceReportValidationSerializer, ComplianceReportSnapshotSerializer, \
ComplianceReportDashboardListSerializer
ComplianceReportValidationSerializer, ComplianceReportDashboardListSerializer
from api.serializers.ExclusionReport import \
ExclusionReportDetailSerializer, ExclusionReportUpdateSerializer, ExclusionReportValidationSerializer
from api.services.ComplianceReportService import ComplianceReportService
from api.services.ComplianceReportSpreadSheet import ComplianceReportSpreadsheet
from auditable.views import AuditableMixin
from api.paginations import BasicPagination
from django.db.models import Q
from django.db.models import Q, F, Value
from django.db.models.functions import Concat


class ComplianceReportViewSet(AuditableMixin, mixins.CreateModelMixin,
Expand Down Expand Up @@ -69,10 +69,35 @@ def get_queryset(self):

request = self.request
if self.action == 'list' or self.action == 'paginated':
qs = qs.annotate(Count('supplements')).filter(supplements__count=0)\
.order_by('-compliance_period__effective_date')

qs = qs.annotate(Count('supplements')).filter(supplements__count=0)
if self.action == 'paginated':
sorts = request.data.get('sorts')
if sorts:
sortCondition = sorts[0].get('desc')
sortId = sorts[0].get('id')
key_maps = {'compliance-period':'compliance_period__description', 'organization':'organization__name', 'updateTimestamp':'compliance_period__effective_date'}
if sortId=='displayname':
if sortCondition:
qs = qs.annotate(display_name=Concat(F('type__the_type'), Value(' '), F('compliance_period__description'))).order_by('-display_name')
else:
qs = qs.annotate(display_name=Concat(F('type__the_type'), Value(' '), F('compliance_period__description'))).order_by('display_name')
elif sortId=='status':
if sortCondition:
qs =qs.order_by('-status__director_status__status', '-status__manager_status__status', '-status__analyst_status__status', '-status__fuel_supplier_status__status')
else:
qs = qs.order_by('status__director_status__status', 'status__manager_status__status', 'status__analyst_status__status', 'status__fuel_supplier_status__status')
elif sortId == 'supplemental-status':
# todo;
pass
elif sortId == 'current-status':
# todo;
pass
else:
sortType = "-" if sortCondition else ""
sortString = f"{sortType}{key_maps[sortId]}"
qs = qs.order_by(sortString)
else:
qs=qs.order_by('-compliance_period__effective_date')
filters = request.data.get('filters')
if filters:
for filter in filters:
Expand All @@ -81,29 +106,38 @@ def get_queryset(self):
if id and value:
if id == 'compliance-period':
qs = qs.filter(
compliance_period__description__exact=value)
compliance_period__description__icontains=value)
elif id == 'organization':
qs = qs.filter(
organization__name__icontains=value)
elif id == 'displayname':
qs = qs.filter(Q(nickname__isnull=True) | Q(
nickname__icontains=value))
# possible todo: deal with case where generated nicknames are used
qs = self.filter_displayname(qs, value.lower())
elif id == 'status':
qs = self.filter_compliance_status(
qs, value.lower())
elif id == 'supplemental-status':
# todo; same as the todo above, along with the fact that we'll have to somehow define (annotate)
# a deepest_supplemental_report field (via some sort of aggregation) which we can then filter on
qs = self.filter_supplemental_status(
qs, value.lower())
pass
elif id == 'current-status':
# todo; same as the todo above
qs = self.filter_current_status(
qs, value.lower())
pass
elif id == 'updateTimestamp':
query = self.filter_timestamp(value)
qs = qs.filter(query)
return qs

def filter_displayname(self, qs, value):
if 'exclusion report'.find(value) != -1:
qs = qs.filter(Q(type__the_type='Exclusion Report'))
elif 'compliance report'.find(value) != -1:
qs = qs.filter(Q(type__the_type='Compliance Report'))
else:
qs = qs.annotate(display_name=Concat(F('type__the_type'), Value(' for '), F('compliance_period__description'))).filter(display_name__icontains=value)

return qs

def filter_timestamp(self, date):
date_query = None
date_tuple = date.split('-')
Expand All @@ -130,46 +164,88 @@ def filter_timestamp(self, date):
return date_query

def filter_compliance_status(self, qs, value):
if value in 'recommended':
return qs.filter(
(Q(status__manager_status__status__icontains=value) |
Q(status__analyst_status__status__icontains=value)) &
(~Q(status__director_status__status__icontains='Accepted') &
~Q(status__director_status__status__icontains='Rejected'))
)

if value in 'supplemental requested':
if 'submitted'.find(value) != -1:
return qs.filter(
Q(status__analyst_status__status='Unreviewed') &
Q(status__director_status__status='Unreviewed') &
Q(status__fuel_supplier_status__status='Submitted') &
Q(status__manager_status__status='Unreviewed')
)

if 'accepted'.find(value) != -1:
return qs.filter(
Q(status__manager_status__status__icontains=value) |
Q(status__analyst_status__status__icontains=value)
Q(status__director_status__status='Accepted')
)
if value in 'accepted':

if 'supplemental requested'.find(value) != -1:
return qs.filter(
Q(status__director_status__status__icontains=value)
Q(status__manager_status__status='Requested Supplemental') |
Q(status__analyst_status__status='Requested Supplemental')
)
if value in 'rejected':

if 'rejected'.find(value) != -1:
return qs.filter(
Q(status__director_status__status__icontains=value)
Q(status__director_status__status='Rejected')
)
if value in 'recommended acceptance - manager':

if value == 'recommended acceptance - manager' or 'manager'.find(value) != -1:
return qs.filter(
Q(status__manager_status__status__icontains=value)
Q(status__manager_status__status='Recommended') &
~Q(status__director_status__status='Accepted') &
~Q(status__director_status__status='Rejected') &
~Q(status__analyst_status__status='Requested Supplemental')
)
if value in 'recommended rejection - manager':

if value == 'recommended acceptance - analyst' or 'analyst'.find(value) != -1:
return qs.filter(
Q(status__manager_status__status__icontains=value)
Q(status__analyst_status__status='Recommended') &
Q(status__director_status__status='Unreviewed') &
Q(status__manager_status__status='Unreviewed')
)
if value in 'recommended acceptance - analyst':

if value == 'recommended rejection - manager' or 'rejection'.find(value) != -1:
return qs.filter(
Q(status__analyst_status__status__icontains=value)
Q(status__manager_status__status='Not Recommended')
)
if value in 'recommended rejection - analyst':
if value == 'recommended rejection - analyst' or 'rejection'.find(value) != -1:
return qs.filter(
Q(status__analyst_status__status__icontains=value)
Q(status__analyst_status__status='Not Recommended')
)
return qs.filter(
Q(status__fuel_supplier_status__status__icontains=value)
)

return qs

def filter_supplemental_status(self, qs, value):
try:
latest_supplementals = self.get_latest_supplemental_reports()
ids = [s.id for s in latest_supplementals]
supplemental_reports = ComplianceReport.objects.filter(id__in=ids)
qs = self.filter_compliance_status(supplemental_reports, value)
except Exception as e:
print(e)
return qs

def filter_current_status(self, qs, value):
try:
latest_supplementals = self.get_latest_supplemental_reports()
ids = [s.id for s in latest_supplementals]
supplemental_reports = ComplianceReport.objects.filter(id__in=ids)
original_reports = qs.filter(Q(supplemental_reports=None))
unique_reports = original_reports | supplemental_reports
qs = self.filter_compliance_status(unique_reports, value)
except Exception as e:
print(e)
return qs

def get_latest_supplemental_reports(self):
latest_supplementals = ComplianceReport.objects.raw("""
select distinct on (p.id) c.*
from compliance_report p
left join compliance_report c on p.id = c.supplements_id
where c.status_id is not NULL
order by p.id desc, c.create_timestamp desc
""")
return latest_supplementals

def get_simple_queryset(self):
"""
Expand Down
Loading

0 comments on commit 9a09a68

Please sign in to comment.