+
+
From 4a6b65eaac21e4f5361d72ca64dc6f590f49d1d3 Mon Sep 17 00:00:00 2001
From: sharpeez
Date: Fri, 6 Nov 2020 16:44:09 +0800
Subject: [PATCH 06/23] WildlifeCompliance: FIX application editable when user
is not the assigned officer.
---
.../wildlifecompliance/src/store/modules/renderer.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/renderer.js b/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/renderer.js
index 392a85f74..450d4ed51 100644
--- a/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/renderer.js
+++ b/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/renderer.js
@@ -65,8 +65,12 @@ export const rendererStore = {
return state.form_data[component_name] ? state.form_data[component_name].value : null;
},
isComponentEditableForOfficer: (state, getters, rootState, rootGetters) => {
+ let activity = rootGetters.application.activities.filter(activity => {
+ return activity.licence_activity === rootGetters.selected_activity_tab_id;
+ })[0];
+ let is_assigned = activity.assigned_officer == null ? false : activity.assigned_officer === getters.current_user.id ? false : true
// function to enforce editable rendered components for officer.
- return rootGetters.canAssignOfficerFor(rootGetters.selected_activity_tab_id); // check permissions.
+ return !is_assigned && rootGetters.canAssignOfficerFor(rootGetters.selected_activity_tab_id); // check permissions.
},
allCurrentActivitiesWithAssessor: (state, getters, rootState, rootGetters) => {
// list of activities with assessment sent for the current user.
From ff2c3664f0403a33eb40714b16ec51553bf30d0e Mon Sep 17 00:00:00 2001
From: sharpeez
Date: Tue, 10 Nov 2020 15:06:53 +0800
Subject: [PATCH 07/23] WildlifeCompliance: UPDATE application load to exclude
estimate calc.
---
.../components/applications/models.py | 25 +++++++++++++++++++
.../components/applications/payments.py | 15 ++++++-----
.../components/applications/serializers.py | 25 +++----------------
.../components/applications/services.py | 1 +
.../src/store/modules/application.js | 8 ++++--
5 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/wildlifecompliance/components/applications/models.py b/wildlifecompliance/components/applications/models.py
index d8049a267..8c62b2a58 100644
--- a/wildlifecompliance/components/applications/models.py
+++ b/wildlifecompliance/components/applications/models.py
@@ -809,6 +809,31 @@ def licence_category(self):
except AttributeError:
return ''
+ def set_property_cache_licence_fee(self, licence_fee):
+ '''
+ Setter for licence fee on the property cache.
+
+ NOTE: only used for presentation purposes.
+ '''
+ if self.id:
+ self.property_cache['licence_fee'] = licence_fee
+
+ def get_property_cache_licence_fee(self):
+ '''
+ Getter for licence fee on the property cache.
+
+ NOTE: only used for presentation purposes.
+ '''
+ fee = 0
+ try:
+
+ fee = self.property_cache['licence_fee']
+
+ except KeyError:
+ pass
+
+ return fee
+
def set_activity_processing_status(self, activity_id, processing_status):
if not activity_id:
logger.error("Application: %s cannot update processing status (%s) for an empty activity_id!" %
diff --git a/wildlifecompliance/components/applications/payments.py b/wildlifecompliance/components/applications/payments.py
index 318df290a..d3b8e0fa5 100644
--- a/wildlifecompliance/components/applications/payments.py
+++ b/wildlifecompliance/components/applications/payments.py
@@ -1375,17 +1375,20 @@ def set_application_fee_from_attributes(self, attributes):
paid_lic_tot = 0
paid_app_tot = 0
for p in activity.proposed_purposes.all():
- fees_lic += p.licence_fee if p.is_payable \
- else 0
- fees_app += p.application_fee if p.is_payable \
- else 0
+ # fees_lic += p.licence_fee if p.is_payable \
+ # else 0
+ # fees_app += p.application_fee if p.is_payable \
+ # else 0
paid_lic_tot += p.total_paid_adjusted_licence_fee \
if p.is_payable else 0
paid_app_tot += p.total_paid_adjusted_application_fee \
if p.is_payable else 0
- fees_app_new = fees_app_adj - paid_app_tot
- fees_lic_new = fees_lic_adj - paid_lic_tot
+ fees_app = fees_app_adj - paid_app_tot
+ fees_lic = fees_lic_adj - paid_lic_tot
+
+ fees_app_new += fees_app
+ fees_lic_new += fees_lic
else:
fees_app_new += fees_app_adj
diff --git a/wildlifecompliance/components/applications/serializers.py b/wildlifecompliance/components/applications/serializers.py
index 010a7fe69..5907d3931 100644
--- a/wildlifecompliance/components/applications/serializers.py
+++ b/wildlifecompliance/components/applications/serializers.py
@@ -1195,28 +1195,11 @@ def get_adjusted_paid_amount(self, obj):
"""
Total paid amount adjusted for presentation purposes. Only applicable
for internal officers to enforce refundable payments.
-
- TODO: REDUNDANT
"""
- # adjusted = None
- # # Include previously paid amounts for amendments.
- # adjusted = obj.total_paid_amount + obj.previous_paid_amount
-
- # if obj.processing_status == \
- # Application.PROCESSING_STATUS_UNDER_REVIEW:
- # # when Under Review, fee for amendment is paid and included in
- # # previous paid amount as well as total paid amount. Need to
- # # exclude this previous amount.
- # adjusted = adjusted - obj.previous_paid_amount
-
- # # licence fee is paid with the application fee. Licence fee needs
- # # to be excluded from total paid for application.
- # licence_fee_paid = 0
- # for activity in obj.activities:
- # licence_fee_paid += activity.licence_fee
- # adjusted = adjusted - licence_fee_paid
-
- adjusted = 0
+ adjusted = {
+ 'application_fee': obj.application_fee,
+ 'licence_fee': obj.get_property_cache_licence_fee()
+ }
return adjusted
diff --git a/wildlifecompliance/components/applications/services.py b/wildlifecompliance/components/applications/services.py
index f57daf230..a0693ce88 100644
--- a/wildlifecompliance/components/applications/services.py
+++ b/wildlifecompliance/components/applications/services.py
@@ -1218,6 +1218,7 @@ def do_update_dynamic_attributes(application, fee_exemption=False):
# Update application and licence fees
fees = dynamic_attributes['fees']
application.application_fee = fees['application']
+ application.set_property_cache_licence_fee(fees['licence'])
application.save()
diff --git a/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/application.js b/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/application.js
index d42106787..3ac9b2544 100644
--- a/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/application.js
+++ b/wildlifecompliance/frontend/wildlifecompliance/src/store/modules/application.js
@@ -166,12 +166,16 @@ export const applicationStore = {
commit(UPDATE_PROXY_APPLICANT, {key: 'address', value: state.proxy_address});
};
},
- loadApplication({ dispatch, commit }, { url }) {
+ loadApplication({ dispatch, state, commit }, { url }) {
return new Promise((resolve, reject) => {
Vue.http.get(url).then(res => {
dispatch('setOriginalApplication', res.body);
dispatch('setApplication', res.body);
- dispatch('refreshApplicationFees');
+ dispatch('setApplication', {
+ ...state.application,
+ application_fee: res.body.adjusted_paid_amount.application_fee,
+ licence_fee: res.body.adjusted_paid_amount.licence_fee
+ });
for(let form_data_record of res.body.data) {
dispatch('setFormValue', {
key: form_data_record.field_name,
From e2025e598c2a1c061f94323e56f9f08f0bce0235 Mon Sep 17 00:00:00 2001
From: sharpeez
Date: Wed, 11 Nov 2020 09:48:21 +0800
Subject: [PATCH 08/23] WildlifeCompliance: FIX external application estimate
fee calculation.
---
wildlifecompliance/components/applications/models.py | 3 ++-
.../wildlifecompliance/src/components/external/application.vue | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/wildlifecompliance/components/applications/models.py b/wildlifecompliance/components/applications/models.py
index 8c62b2a58..e0ceadc3c 100644
--- a/wildlifecompliance/components/applications/models.py
+++ b/wildlifecompliance/components/applications/models.py
@@ -816,7 +816,8 @@ def set_property_cache_licence_fee(self, licence_fee):
NOTE: only used for presentation purposes.
'''
if self.id:
- self.property_cache['licence_fee'] = licence_fee
+ data = str(licence_fee)
+ self.property_cache['licence_fee'] = data
def get_property_cache_licence_fee(self):
'''
diff --git a/wildlifecompliance/frontend/wildlifecompliance/src/components/external/application.vue b/wildlifecompliance/frontend/wildlifecompliance/src/components/external/application.vue
index 6460753a9..862651058 100644
--- a/wildlifecompliance/frontend/wildlifecompliance/src/components/external/application.vue
+++ b/wildlifecompliance/frontend/wildlifecompliance/src/components/external/application.vue
@@ -136,6 +136,7 @@ export default {
'setApplication',
'setActivityTab',
'saveFormData',
+ 'refreshApplicationFees',
]),
eventListeners: function(){
if(!this.tabSelected) {
@@ -438,6 +439,7 @@ export default {
beforeRouteEnter: function(to, from, next) {
next(vm => {
vm.reloadApplication(to.params.application_id);
+ vm.refreshApplicationFees();
});
},
updated: function(){
From 4c405164d393c71442231a038a29e824e758b68e Mon Sep 17 00:00:00 2001
From: sharpeez
Date: Thu, 12 Nov 2020 11:17:13 +0800
Subject: [PATCH 09/23] WildlifeCompliance: ADD components for system
maintenance.
---
cron | 1 +
wildlifecompliance/components/main/models.py | 25 +++++++++
.../commands/system_maintenance_check.py | 37 ++++++++++++
.../migrations/0524_systemmaintenance.py | 28 ++++++++++
wildlifecompliance/settings.py | 6 +-
.../templates/wildlifecompliance/base.html | 8 +++
wildlifecompliance/templatetags/users.py | 56 +++++++++++++++++++
7 files changed, 159 insertions(+), 2 deletions(-)
create mode 100644 wildlifecompliance/management/commands/system_maintenance_check.py
create mode 100644 wildlifecompliance/migrations/0524_systemmaintenance.py
diff --git a/cron b/cron
index dce593eba..697656474 100644
--- a/cron
+++ b/cron
@@ -1,2 +1,3 @@
+* * * * * root eval $(grep -v '^#' /etc/.cronenv | xargs -d "\n" -I {} echo export \"{}\" ) && cd /app && python manage_wc.py system_maintenance_check > /dev/null 2>&1
0 2 * * * root eval $(grep -v '^#' /etc/.cronenv | xargs -d "\n" -I {} echo export \"{}\" ) && cd /app && python manage_wc.py cron_tasks > logs/cron_tasks.log 2>&1
10 2 * * * root eval $(grep -v '^#' /etc/.cronenv | xargs -d "\n" -I {} echo export \"{}\" ) && cd /app && python manage_wc.py runcrons > logs/runcrons.log 2>&1
diff --git a/wildlifecompliance/components/main/models.py b/wildlifecompliance/components/main/models.py
index 8fbfdb8d2..1f40253fb 100644
--- a/wildlifecompliance/components/main/models.py
+++ b/wildlifecompliance/components/main/models.py
@@ -10,6 +10,31 @@
logger = logging.getLogger(__name__)
+@python_2_unicode_compatible
+class SystemMaintenance(models.Model):
+ name = models.CharField(max_length=100)
+ description = models.TextField()
+ start_date = models.DateTimeField()
+ end_date = models.DateTimeField()
+
+ def duration(self):
+ """ Duration of system maintenance (in mins) """
+ return int(
+ (self.end_date - self.start_date).total_seconds()/60.
+ ) if self.end_date and self.start_date else ''
+
+ duration.short_description = 'Duration (mins)'
+
+ class Meta:
+ app_label = 'wildlifecompliance'
+ verbose_name_plural = "System maintenance"
+
+ def __str__(self):
+ return 'System Maintenance: {} ({}) - starting {}, ending {}'.format(
+ self.name, self.description, self.start_date, self.end_date
+ )
+
+
@python_2_unicode_compatible
class Sequence(models.Model):
diff --git a/wildlifecompliance/management/commands/system_maintenance_check.py b/wildlifecompliance/management/commands/system_maintenance_check.py
new file mode 100644
index 000000000..eed1fc08d
--- /dev/null
+++ b/wildlifecompliance/management/commands/system_maintenance_check.py
@@ -0,0 +1,37 @@
+from django.core.management.base import BaseCommand
+from django.conf import settings
+import subprocess
+import os
+from wildlifecompliance.templatetags.users import system_maintenance_can_start
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class Command(BaseCommand):
+ """
+ Excecuted from cron, eg:
+ SHELL=/bin/bash
+ # Execute every minute. Polls the Disturbance Admin table
+ # SystemMaintenance, and checks if the application can be taken down at
+ # the time indicated in the Admin table.
+
+ * * * * * root cd /var/www/disturbance-dev2
+ && source venv/bin/activate
+ && python manage_ds.py system_maintenance_check >/dev/null 2>&1
+ CMD's eg:
+ SUPERVISOR_STOP_CMD="supervisorctl stop disturbance-dev"
+ SUPERVISOR_STOP_CMD="pkill -f 8499"
+ """
+ help = 'Check Maintenance is due, and terminate uwsgi/supervisor process'
+ log_file = os.getcwd() + '/logs/sys_maintenance.log'
+
+ def handle(self, *args, **options):
+ if system_maintenance_can_start():
+ logger.info('Running command {}'.format(__name__))
+ subprocess.Popen(
+ 'date 2>&1 | tee -a {}'.format(self.log_file), shell=True)
+ subprocess.Popen(
+ settings.SUPERVISOR_STOP_CMD + ' 2>&1 | tee -a {}'.format(
+ self.log_file), shell=True
+ )
diff --git a/wildlifecompliance/migrations/0524_systemmaintenance.py b/wildlifecompliance/migrations/0524_systemmaintenance.py
new file mode 100644
index 000000000..80bbcaac0
--- /dev/null
+++ b/wildlifecompliance/migrations/0524_systemmaintenance.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2020-11-12 03:11
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wildlifecompliance', '0523_auto_20201016_1342'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SystemMaintenance',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('description', models.TextField()),
+ ('start_date', models.DateTimeField()),
+ ('end_date', models.DateTimeField()),
+ ],
+ options={
+ 'verbose_name_plural': 'System maintenance',
+ },
+ ),
+ ]
diff --git a/wildlifecompliance/settings.py b/wildlifecompliance/settings.py
index 94fc58a1b..756a9005a 100644
--- a/wildlifecompliance/settings.py
+++ b/wildlifecompliance/settings.py
@@ -1,10 +1,11 @@
+from django.core.exceptions import ImproperlyConfigured
+from ledger.settings_base import *
+
import os
import confy
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
confy.read_environment_file(BASE_DIR+"/.env")
os.environ.setdefault("BASE_DIR", BASE_DIR)
-from django.core.exceptions import ImproperlyConfigured
-from ledger.settings_base import *
os.environ['LEDGER_PRODUCT_CUSTOM_FIELDS'] = "('ledger_description','quantity','price_incl_tax','price_excl_tax','oracle_code')"
os.environ['LEDGER_REFUND_TRANSACTION_CALLBACK_MODULE'] = 'wildlifecompliance:wildlifecompliance.components.applications.api.application_refund_callback'
@@ -12,6 +13,7 @@
ROOT_URLCONF = 'wildlifecompliance.urls'
SITE_ID = 1
+SYSTEM_MAINTENANCE_WARNING = env('SYSTEM_MAINTENANCE_WARNING', 24) # hours
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles_wc')
SHOW_DEBUG_TOOLBAR = env('SHOW_DEBUG_TOOLBAR', False)
diff --git a/wildlifecompliance/templates/wildlifecompliance/base.html b/wildlifecompliance/templates/wildlifecompliance/base.html
index fd1fb807c..d67f4378f 100644
--- a/wildlifecompliance/templates/wildlifecompliance/base.html
+++ b/wildlifecompliance/templates/wildlifecompliance/base.html
@@ -11,6 +11,7 @@
{% is_compliance_internal_user as is_compliance_internal_login %}
{% prefer_compliance_management as prefer_compliance_management %}
{% is_compliance_management_readonly_user as is_compliance_management_readonly_user %}
+{% system_maintenance_due as system_maintenance_due %}
@@ -182,6 +183,13 @@
+ {% endif %}
+
{% block content %}
{% endblock %}
{% block modals %}
diff --git a/wildlifecompliance/templatetags/users.py b/wildlifecompliance/templatetags/users.py
index 737beff01..d621c7c01 100644
--- a/wildlifecompliance/templatetags/users.py
+++ b/wildlifecompliance/templatetags/users.py
@@ -1,5 +1,9 @@
from django.template import Library
+from django.utils import timezone
+from datetime import timedelta
+
from wildlifecompliance import helpers as wildlifecompliance_helpers
+from wildlifecompliance.components.main.models import SystemMaintenance
register = Library()
@@ -49,3 +53,55 @@ def is_compliance_management_readonly_user(context):
request = context['request']
return wildlifecompliance_helpers.is_compliance_management_readonly_user(request)
+
+@register.simple_tag()
+def system_maintenance_due():
+ '''
+ Returns True (actually a time str), if within