From 11faa5f329cb26a457a45c8e4890ab7f6cb94f98 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Fri, 6 Jun 2025 12:44:57 +0100 Subject: [PATCH 1/5] LIMS-1739: Add button to say shipment is ready for scheduling --- api/src/Page/Shipment.php | 15 ++- .../src/js/modules/shipment/views/dewars.js | 7 ++ .../src/js/modules/shipment/views/shipment.js | 101 ++++++++++++------ .../src/js/templates/shipment/shipment.html | 24 +---- client/src/js/utils/editable.js | 9 +- 5 files changed, 103 insertions(+), 53 deletions(-) diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php index d3f7dbc31..b7512c5ac 100644 --- a/api/src/Page/Shipment.php +++ b/api/src/Page/Shipment.php @@ -1726,7 +1726,8 @@ function _get_dewars() d.code, d.barcode, d.storagelocation, d.dewarstatus, d.dewarid, d.trackingnumbertosynchrotron, d.trackingnumberfromsynchrotron, d.externalShippingIdFromSynchrotron, s.deliveryagent_agentname, d.weight, d.deliveryagent_barcode, GROUP_CONCAT(c.code SEPARATOR ', ') as containers, - s.sendinglabcontactid, s.returnlabcontactid, pe.givenname, pe.familyname, s.safetylevel as shippingsafetylevel + s.sendinglabcontactid, s.returnlabcontactid, pe.givenname, pe.familyname, s.safetylevel as shippingsafetylevel, + s.extra FROM dewar d LEFT OUTER JOIN container c ON c.dewarid = d.dewarid INNER JOIN shipping s ON d.shippingid = s.shippingid @@ -1740,6 +1741,18 @@ function _get_dewars() GROUP BY CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number), r.labcontactid, se.beamlineoperator, TO_CHAR(se.startdate, 'HH24:MI DD-MM-YYYY'), (case when se.visit_number > 0 then (CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number)) else '' end),s.shippingid, s.shippingname, d.code, d.barcode, d.storagelocation, d.dewarstatus, d.dewarid, d.trackingnumbertosynchrotron, d.trackingnumberfromsynchrotron, d.facilitycode, d.firstexperimentid ORDER BY $order", $args); + foreach ($dewars as &$s) { + $extra_json = json_decode($s['EXTRA'], true); + if (is_null($extra_json)) { + $extra_json = array(); + foreach ($this->extra_arg_list as $arg) { + $extra_json[$arg] = ""; + } + } + $s = array_merge($s, $extra_json); + } + + if ($this->has_arg('did')) { if (sizeof($dewars)) $this->_output($dewars[0]); diff --git a/client/src/js/modules/shipment/views/dewars.js b/client/src/js/modules/shipment/views/dewars.js index c853b3a4e..70a7726eb 100644 --- a/client/src/js/modules/shipment/views/dewars.js +++ b/client/src/js/modules/shipment/views/dewars.js @@ -41,6 +41,7 @@ define(['marionette', 'backbone', dispatch: '.dispatch', transfer: '.transfer', ssd: '.ssdispatch', + addcont: '.add-container-small', }, className: function() { @@ -126,6 +127,7 @@ define(['marionette', 'backbone', this.ui.fc.html(this.getOption('regdewars').opts({ empty: true })) this.showHideButtons() + this.listenTo(this.model, 'change', this.showHideButtons) }, showHideButtons: function() { @@ -148,6 +150,11 @@ define(['marionette', 'backbone', } else { this.ui.ssd.hide() } + if (this.model.get('DYNAMIC') === 'Ready') { + this.ui.addcont.hide() + } else { + this.ui.addcont.show() + } }, modelEvents: { diff --git a/client/src/js/modules/shipment/views/shipment.js b/client/src/js/modules/shipment/views/shipment.js index 2e634d38d..07ffe51b8 100644 --- a/client/src/js/modules/shipment/views/shipment.js +++ b/client/src/js/modules/shipment/views/shipment.js @@ -54,11 +54,14 @@ define(['marionette', 'click a.send': 'sendShipment', 'click a.pdf': utils.signHandler, 'click a.cancel_pickup': 'cancelPickup', + 'click a.ready': 'markAsReady', }, ui: { add_dewar: '#add_dewar', longwavelength: '.longwavelength', + ready: '.ready', + dynamic: '.DYNAMIC', }, @@ -173,10 +176,33 @@ define(['marionette', this.fetchDewars(true) }, + markAsReady: function(e) { + e.preventDefault() + utils.confirm({ + title: 'Ready for Scheduling', + content: 'Are you sure you want to mark the shipment as ready for scheduling?

We ask users to define all samples prior to shipping any dewar to us. We can schedule dewars before they arrive, once we have confirmation that the dewar is ready to be loaded onto a beamline.

Once you confirm that the shipment is finalised, you will not be able to add dewars or pucks.', + callback: this.doMarkAsReady.bind(this) + }) + }, + + doMarkAsReady: function() { + this.model.save({ DYNAMIC: 'Ready' }, { patch: true }) + if (!app.staff) this.edit.remove('DYNAMIC') + }, + updateDynamic: function(){ dynamic = this.model.get('DYNAMIC') dynamicSelectedValues = [true, 'Yes', 'yes', 'Y', 'y'] - if (!dynamicSelectedValues.includes(dynamic)) { + this.ui.ready.hide() + if (dynamic === 'Ready') { + this.ui.dynamic.html('I would like a session to be scheduled - my shipment is ready for scheduling') + } else if (dynamicSelectedValues.includes(dynamic)) { + this.ui.dynamic.html(this.dynamicOptions['Yes']) + this.ui.ready.show() + } else { + this.ui.dynamic.html(this.dynamicOptions[dynamic]) + } + if (!dynamicSelectedValues.includes(dynamic) && dynamic != 'Ready') { this.$el.find(".remoteormailin").hide() this.$el.find(".remoteform").hide() this.ui.longwavelength.hide() @@ -193,10 +219,22 @@ define(['marionette', this.$el.find(".remoteform").show() } } + if (dynamic === 'Ready' || (app.proposal && app.proposal.get('ACTIVE') != '1')) { + this.ui.add_dewar.hide() + } else { + this.ui.add_dewar.show() + } + + if (this.dewars) { + this.dewars.each(function(dewar) { + if (dewar.get('DYNAMIC') !== dynamic) { + dewar.set('DYNAMIC', dynamic) + } + }) + } }, onRender: function() { - if (app.proposal && app.proposal.get('ACTIVE') != '1') this.ui.add_dewar.hide() this.table.show(new DewarsView({ collection: this.dewars })) this.cont.show(new DewarContentView({ collection: this.dewarcontent })) @@ -205,46 +243,49 @@ define(['marionette', this.listenTo(this.cont.currentView, 'refresh:dewars', this.refreshDewar, this) - var edit = new Editable({ model: this.model, el: this.$el }) - edit.create('SHIPPINGNAME', 'textlong') - edit.create('SAFETYLEVEL', 'select', { data: {'Green': 'Green', 'Yellow':'Yellow', 'Red': 'Red'}, alert: true, revert: true }) - edit.create('COMMENTS', 'textarea') - edit.create('DELIVERYAGENT_AGENTNAME', 'text') - edit.create('DELIVERYAGENT_AGENTCODE', 'text') - edit.create('DELIVERYAGENT_SHIPPINGDATE', 'date') - edit.create('DELIVERYAGENT_DELIVERYDATE', 'date') - edit.create('DELIVERYAGENT_FLIGHTCODE', 'text') - edit.create('PHYSICALLOCATION', 'text') - edit.create('READYBYTIME', 'time') - edit.create('CLOSETIME', 'time') + this.edit = new Editable({ model: this.model, el: this.$el }) + this.edit.create('SHIPPINGNAME', 'textlong') + this.edit.create('SAFETYLEVEL', 'select', { data: {'Green': 'Green', 'Yellow':'Yellow', 'Red': 'Red'}, alert: true, revert: true }) + this.edit.create('COMMENTS', 'textarea') + this.edit.create('DELIVERYAGENT_AGENTNAME', 'text') + this.edit.create('DELIVERYAGENT_AGENTCODE', 'text') + this.edit.create('DELIVERYAGENT_SHIPPINGDATE', 'date') + this.edit.create('DELIVERYAGENT_DELIVERYDATE', 'date') + this.edit.create('DELIVERYAGENT_FLIGHTCODE', 'text') + this.edit.create('PHYSICALLOCATION', 'text') + this.edit.create('READYBYTIME', 'time') + this.edit.create('CLOSETIME', 'time') - edit.create("ENCLOSEDHARDDRIVE", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) - edit.create("ENCLOSEDTOOLS", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) - edit.create("DYNAMIC", 'select', { data: { + this.edit.create("ENCLOSEDHARDDRIVE", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.edit.create("ENCLOSEDTOOLS", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.dynamicOptions = { 'No': 'I have a session already scheduled', 'UDC': 'I am sending pucks for Unattended Data Collection', 'Imaging': 'I am sending plates for imaging', 'Yes': 'I would like a session to be scheduled', 'Other': 'Something else', - }}) + } + if (app.staff || this.model.get('DYNAMIC') != 'Ready') { + this.edit.create('DYNAMIC', 'select', { data: this.dynamicOptions}) + } industrial_codes = ['in', 'sw'] industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) if (!industrial_visit) { this.$el.find(".remoteormailin").hide() } else { - edit.create("REMOTEORMAILIN", 'select', { data: {'Remote': 'Remote', 'Mail-in': 'Mail-in', 'Other': 'Other'}}) + this.edit.create("REMOTEORMAILIN", 'select', { data: {'Remote': 'Remote', 'Mail-in': 'Mail-in', 'Other': 'Other'}}) } - edit.create("LONGWAVELENGTH", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) - edit.create("SESSIONLENGTH", 'text') - edit.create("ENERGY", 'text') - edit.create("MICROFOCUSBEAM", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) - edit.create("SCHEDULINGRESTRICTIONS", 'text') - edit.create("LASTMINUTEBEAMTIME", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) - edit.create("DEWARGROUPING", 'select', { data: {'Yes': 'Yes', 'No': 'No', 'Don\'t mind': 'Don\'t mind'}}) - edit.create("EXTRASUPPORTREQUIREMENT", 'text'); - edit.create("MULTIAXISGONIOMETRY", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.edit.create("LONGWAVELENGTH", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.edit.create("SESSIONLENGTH", 'text') + this.edit.create("ENERGY", 'text') + this.edit.create("MICROFOCUSBEAM", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.edit.create("SCHEDULINGRESTRICTIONS", 'text') + this.edit.create("LASTMINUTEBEAMTIME", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) + this.edit.create("DEWARGROUPING", 'select', { data: {'Yes': 'Yes', 'No': 'No', 'Don\'t mind': 'Don\'t mind'}}) + this.edit.create("EXTRASUPPORTREQUIREMENT", 'text'); + this.edit.create("MULTIAXISGONIOMETRY", 'select', { data: {'Yes': 'Yes', 'No': 'No'}}) this.updateDynamic() this.listenTo(this.model, "change", this.updateDynamic) @@ -253,8 +294,8 @@ define(['marionette', this.contacts = new LabContacts(null, { state: { pageSize: 9999 } }) this.contacts.fetch().done(function() { console.log(self.contacts, self.contacts.kv()) - edit.create('SENDINGLABCONTACTID', 'select', { data: self.contacts.kv() }) - edit.create('RETURNLABCONTACTID', 'select', { data: self.contacts.kv() }) + self.edit.create('SENDINGLABCONTACTID', 'select', { data: self.contacts.kv() }) + self.edit.create('RETURNLABCONTACTID', 'select', { data: self.contacts.kv() }) }) }, diff --git a/client/src/js/templates/shipment/shipment.html b/client/src/js/templates/shipment/shipment.html index c87a39481..5414a239c 100644 --- a/client/src/js/templates/shipment/shipment.html +++ b/client/src/js/templates/shipment/shipment.html @@ -129,26 +129,6 @@

Shipment: <%-SHIPPI <% } %> <% - switch(DYNAMIC) { - case 'No': - DYNAMIC = 'I have a session already scheduled'; - break; - case 'UDC': - DYNAMIC = 'I am sending pucks for Unattended Data Collection'; - break; - case 'Imaging': - DYNAMIC = 'I am sending plates for imaging'; - break; - case 'Yes': - DYNAMIC = 'I would like a session to be scheduled'; - break; - case 'Other': - DYNAMIC = 'Something else'; - break; - default: - DYNAMIC = ''; - break; - }; REMOTEORMAILIN=(typeof REMOTEORMAILIN !== 'undefined')? REMOTEORMAILIN : null; SESSIONLENGTH=(typeof SESSIONLENGTH !== 'undefined')? SESSIONLENGTH : null; ENERGY=(typeof ENERGY !== 'undefined')? ENERGY : null; @@ -174,7 +154,8 @@

Shipment: <%-SHIPPI
  • Scheduling - <%-DYNAMIC %> + + Shipment is ready for scheduling
  • @@ -195,6 +176,7 @@

    Shipment: <%-SHIPPI
  • Energy/wavelength requirements <%-ENERGY %> +
  • diff --git a/client/src/js/utils/editable.js b/client/src/js/utils/editable.js index a33d32027..654fb7ef8 100644 --- a/client/src/js/utils/editable.js +++ b/client/src/js/utils/editable.js @@ -208,7 +208,14 @@ define(['marionette', } this.el.find('.'+attr).editable(submit.bind(this), $.extend({}, defaults, types[type], options, { onsubmit: onsubmit.bind(this), attr: attr, model: this.model })).addClass('editable') - } + }, + + remove: function(attr) { + // Find the element and destroy its editable instance + this.el.find('.' + attr).editable('destroy'); + // Also remove the 'editable' class to fix the CSS + this.el.find('.' + attr).removeClass('editable'); + }, }) From f906398a70988081424b5d67904f951c289da2c0 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Fri, 6 Jun 2025 13:28:21 +0100 Subject: [PATCH 2/5] LIMS-1739: Add button to say shipment is ready for scheduling --- client/src/js/templates/shipment/shipment.html | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/js/templates/shipment/shipment.html b/client/src/js/templates/shipment/shipment.html index 5414a239c..3289db27c 100644 --- a/client/src/js/templates/shipment/shipment.html +++ b/client/src/js/templates/shipment/shipment.html @@ -176,7 +176,6 @@

    Shipment: <%-SHIPPI
  • Energy/wavelength requirements <%-ENERGY %> -
  • From c9c5c5bc843a7f443e6e1ef58597719e50f3a4be Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Fri, 6 Jun 2025 15:37:18 +0100 Subject: [PATCH 3/5] LIMS-1739: Add contact instruction --- client/src/js/modules/shipment/views/shipment.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/js/modules/shipment/views/shipment.js b/client/src/js/modules/shipment/views/shipment.js index 07ffe51b8..9e6c4de3d 100644 --- a/client/src/js/modules/shipment/views/shipment.js +++ b/client/src/js/modules/shipment/views/shipment.js @@ -180,7 +180,10 @@ define(['marionette', e.preventDefault() utils.confirm({ title: 'Ready for Scheduling', - content: 'Are you sure you want to mark the shipment as ready for scheduling?

    We ask users to define all samples prior to shipping any dewar to us. We can schedule dewars before they arrive, once we have confirmation that the dewar is ready to be loaded onto a beamline.

    Once you confirm that the shipment is finalised, you will not be able to add dewars or pucks.', + content: 'Are you sure you want to mark the shipment as ready for scheduling?

    '+ + 'We ask users to define all samples prior to shipping any dewar to us. We can schedule dewars before they arrive, once we have confirmation that the dewar is ready to be loaded onto a beamline.

    '+ + 'Once you confirm that the shipment is finalised, you will not be able to add dewars or pucks.

    '+ + 'If you have any questions, please email your local contact.', callback: this.doMarkAsReady.bind(this) }) }, From 6e3513eac7165a7b27dc5029ddba4a59a49b6163 Mon Sep 17 00:00:00 2001 From: Mark Williams Date: Wed, 18 Jun 2025 15:39:29 +0100 Subject: [PATCH 4/5] LIMS-1739: Dont show 'ready' button for industrial proposals --- api/config_sample.php | 3 +++ api/index.php | 5 +++-- client/src/js/modules/shipment/views/dispatch.js | 12 ++++++------ client/src/js/modules/shipment/views/shipment.js | 14 +++++++------- .../src/js/modules/shipment/views/shipmentadd.js | 2 +- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/api/config_sample.php b/api/config_sample.php index 6aa9db02b..df6b156ef 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -308,6 +308,9 @@ # - If these are not defined for a proposal type, the api then uses bl_types below $prop_types = array('mx'); + # Industrial proposals are not allowed to use the facility shipping account + $industrial_prop_codes = array('sw', 'in', 'ic'); + # This maps beamlinename in blsession to a proposal type # - Internal maps a beamline to an api "type", there are currently: # mx, gen, em diff --git a/api/index.php b/api/index.php index ee9c612a3..dcfd3519c 100644 --- a/api/index.php +++ b/api/index.php @@ -73,7 +73,7 @@ function setupApplication($mode): Slim $valid_components, $enabled_container_types, $synchweb_version, $redirects, $shipping_service_app_url, $use_shipping_service_redirect, $use_shipping_service_redirect_incoming_shipments, $dials_rest_url_rings, $closed_proposal_link, $ccp4_cloud_upload_url, - $only_staff_can_assign; + $only_staff_can_assign, $industrial_prop_codes; $app->contentType('application/json'); $options = $app->container['options']; $app->response()->body(json_encode(array( @@ -102,7 +102,8 @@ function setupApplication($mode): Slim 'dials_rest_url_rings' => $dials_rest_url_rings, 'ccp4_cloud_upload_url' => $ccp4_cloud_upload_url, 'redirects' => $redirects, - 'only_staff_can_assign' => $only_staff_can_assign + 'only_staff_can_assign' => $only_staff_can_assign, + 'industrial_prop_codes' => $industrial_prop_codes ))); }); return $app; diff --git a/client/src/js/modules/shipment/views/dispatch.js b/client/src/js/modules/shipment/views/dispatch.js index dafa0c578..3304e00b6 100644 --- a/client/src/js/modules/shipment/views/dispatch.js +++ b/client/src/js/modules/shipment/views/dispatch.js @@ -156,12 +156,6 @@ define(['marionette', 'views/form', this.$el.find('input[name=DELIVERYAGENT_SHIPPINGDATE]').val(today) this.$el.find('.facilityCourier').hide() - industrial_codes = ['in', 'sw'] - industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) - if (industrial_visit) { - this.ui.facc.hide() - } - if (this.shipping.get('TERMSACCEPTED') == 0) { this.ui.courier.val(this.shipping.get('DELIVERYAGENT_AGENTNAME')) this.ui.accountNumber.val(this.shipping.get('DELIVERYAGENT_AGENTCODE')) @@ -280,7 +274,12 @@ define(['marionette', 'views/form', this.ui.dispatchDetails.show(); this.enableValidation() this.ui.submit.show(); + + industrial_codes = app.options.get('industrial_prop_codes') + industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) + if ( + industrial_visit || this.terms.get("ACCEPTED") || (!app.options.get("facility_courier_countries").includes(this.dispatchCountry) && !app.options.get("facility_courier_countries_nde").includes(this.dispatchCountry)) @@ -289,6 +288,7 @@ define(['marionette', 'views/form', } else { this.ui.facc.show() } + if ( this.terms.get("ACCEPTED") && app.options.get("shipping_service_app_url") diff --git a/client/src/js/modules/shipment/views/shipment.js b/client/src/js/modules/shipment/views/shipment.js index 9e6c4de3d..062c52cc8 100644 --- a/client/src/js/modules/shipment/views/shipment.js +++ b/client/src/js/modules/shipment/views/shipment.js @@ -201,7 +201,9 @@ define(['marionette', this.ui.dynamic.html('I would like a session to be scheduled - my shipment is ready for scheduling') } else if (dynamicSelectedValues.includes(dynamic)) { this.ui.dynamic.html(this.dynamicOptions['Yes']) - this.ui.ready.show() + if (!this.industrial_visit) { + this.ui.ready.show() + } } else { this.ui.dynamic.html(this.dynamicOptions[dynamic]) } @@ -210,9 +212,7 @@ define(['marionette', this.$el.find(".remoteform").hide() this.ui.longwavelength.hide() } else { - industrial_codes = ['in', 'sw'] - industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) - if (industrial_visit) { + if (this.industrial_visit) { this.$el.find(".remoteormailin").show() } this.ui.longwavelength.show() @@ -272,9 +272,9 @@ define(['marionette', if (app.staff || this.model.get('DYNAMIC') != 'Ready') { this.edit.create('DYNAMIC', 'select', { data: this.dynamicOptions}) } - industrial_codes = ['in', 'sw'] - industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) - if (!industrial_visit) { + industrial_codes = app.options.get('industrial_prop_codes') + this.industrial_visit = industrial_codes.includes(app.prop.slice(0,2)) + if (!this.industrial_visit) { this.$el.find(".remoteormailin").hide() } else { this.edit.create("REMOTEORMAILIN", 'select', { data: {'Remote': 'Remote', 'Mail-in': 'Mail-in', 'Other': 'Other'}}) diff --git a/client/src/js/modules/shipment/views/shipmentadd.js b/client/src/js/modules/shipment/views/shipmentadd.js index da90f4e66..bb9185922 100644 --- a/client/src/js/modules/shipment/views/shipmentadd.js +++ b/client/src/js/modules/shipment/views/shipmentadd.js @@ -162,7 +162,7 @@ define(['marionette', 'views/form', }, isIndustrialProposal: function() { - industrial_codes = ['in', 'sw'] + industrial_codes = app.options.get('industrial_prop_codes') return industrial_codes.includes(app.prop.slice(0,2)) }, From 233584f0d6ffd53f4aa64f26c46750f0a4f1ef70 Mon Sep 17 00:00:00 2001 From: Mark W <24956497+ndg63276@users.noreply.github.com> Date: Tue, 8 Jul 2025 11:37:01 +0100 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Guilherme Francisco --- client/src/js/modules/shipment/views/shipment.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/js/modules/shipment/views/shipment.js b/client/src/js/modules/shipment/views/shipment.js index c956719ed..ad561dd87 100644 --- a/client/src/js/modules/shipment/views/shipment.js +++ b/client/src/js/modules/shipment/views/shipment.js @@ -293,7 +293,7 @@ define(['marionette', } else { this.ui.dynamic.html(this.dynamicOptions[dynamic]) } - if (!dynamicSelectedValues.includes(dynamic) && dynamic != 'Ready') { + if (!dynamicSelectedValues.includes(dynamic) && dynamic !== 'Ready') { this.$el.find(".remoteormailin").hide() this.$el.find(".remoteform").hide() this.ui.longwavelength.hide() @@ -355,7 +355,7 @@ define(['marionette', 'Yes': 'I would like a session to be scheduled', 'Other': 'Something else', } - if (app.staff || this.model.get('DYNAMIC') != 'Ready') { + if (app.staff || this.model.get('DYNAMIC') !== 'Ready') { this.edit.create('DYNAMIC', 'select', { data: this.dynamicOptions}) } industrial_codes = app.options.get('industrial_prop_codes')