diff --git a/api/assets/emails/html/dewar-dispatch-lite.html b/api/assets/emails/html/dewar-dispatch-lite.html
new file mode 100644
index 000000000..ad3b16b2b
--- /dev/null
+++ b/api/assets/emails/html/dewar-dispatch-lite.html
@@ -0,0 +1,30 @@
+
Dewar ready to leave diamond
+
+
+ Goods Handling, please arrange dispatch of the following Dewar.
+
+
+
+
+
+ Proposal |
+ |
+
+
+ Air Waybill |
+ |
+
+
+ Dewar Facility Code |
+ |
+
+
+ Dewar Barcode |
+ |
+
+
+ Current Location |
+ |
+
+
+
diff --git a/api/config_sample.php b/api/config_sample.php
index 1267f8fe3..69bf049d7 100644
--- a/api/config_sample.php
+++ b/api/config_sample.php
@@ -264,6 +264,7 @@
# Shipping service details
$use_shipping_service = null;
$use_shipping_service_incoming_shipments = null;
+ $use_shipping_service_redirect = null;
$shipping_service_api_url = null;
$shipping_service_api_user = null;
$shipping_service_api_password = null;
diff --git a/api/index.php b/api/index.php
index 2095ba7cc..a067449d5 100644
--- a/api/index.php
+++ b/api/index.php
@@ -70,7 +70,7 @@ function setupApplication($mode): Slim
global $motd, $authentication_type, $cas_url, $cas_sso, $sso_url, $package_description,
$facility_courier_countries, $facility_courier_countries_nde,
$dhl_enable, $dhl_link, $scale_grid, $scale_grid_end_date, $preset_proposal, $timezone,
- $valid_components, $enabled_container_types, $ifsummary, $synchweb_version;
+ $valid_components, $enabled_container_types, $ifsummary, $synchweb_version, $shipping_service_app_url, $use_shipping_service_redirect;
$app->contentType('application/json');
$options = $app->container['options'];
$app->response()->body(json_encode(array(
@@ -91,7 +91,8 @@ function setupApplication($mode): Slim
'valid_components' => $valid_components,
'enabled_container_types' => $enabled_container_types,
'ifsummary' => $ifsummary,
- 'synchweb_version' => $synchweb_version
+ 'synchweb_version' => $synchweb_version,
+ 'shipping_service_app_url' => $use_shipping_service_redirect ? $shipping_service_app_url : null,
)));
});
return $app;
diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php
index ca95ef552..459e4bdc6 100644
--- a/api/src/Page/Shipment.php
+++ b/api/src/Page/Shipment.php
@@ -924,6 +924,60 @@ function _transfer_dewar()
$this->_output(1);
}
+ function _dispatch_dewar_shipment_request($dewar)
+ {
+ if (!is_null($dewar['EXTERNALSHIPPINGIDFROMSYNCHROTRON'])) {
+ return $dewar['EXTERNALSHIPPINGIDFROMSYNCHROTRON'];
+ }
+ $server_port = ($_SERVER['SERVER_PORT']==='443') ? '' : ":{$_SERVER['SERVER_PORT']}";
+ $shipment_request_info = array(
+ "proposal" => $dewar['PROPOSAL'],
+ "external_id" => (int) $dewar['DEWARID'],
+ "origin_url" => "https://{$_SERVER['SERVER_NAME']}{$server_port}/shipments/sid/{$dewar['SHIPPINGID']}",
+ "packages" => [
+ [
+ "external_id" => (int) $dewar['DEWARID'],
+ "shippable_item_type" => "CRYOGENIC_DRY_SHIPPER_CASE",
+ "line_items" => [
+ [
+ "shippable_item_type" => "CRYOGENIC_DRY_SHIPPER",
+ "quantity" => 1
+ ],
+ [
+ "shippable_item_type" => "SHELVED_UNI_PUCK_SHIPPING_CANE",
+ "quantity" => 1
+ ],
+ ]
+ ]
+ ]
+ );
+ if ((int) $dewar['NUM_PUCKS'] > 0) {
+ array_push(
+ $shipment_request_info["packages"][0]["line_items"],
+ [
+ "shippable_item_type"=> "UNI_PUCK",
+ "quantity" => (int) $dewar['NUM_PUCKS']
+ ]
+ );
+ }
+ if ((int) $dewar['NUM_SAMPLES'] > 0) {
+ array_push(
+ $shipment_request_info["packages"][0]["line_items"],
+ [
+ "shippable_item_type"=> "SPINE_SAMPLE_HOLDER",
+ "quantity" => (int) $dewar['NUM_SAMPLES']
+ ]
+ );
+ }
+ $response = $this->shipping_service->create_shipment_request($shipment_request_info);
+ $external_shipping_id = $response['shipmentRequestId'];
+ $this->db->pq(
+ "UPDATE dewar SET externalShippingIdFromSynchrotron=:1 WHERE dewarid=:2",
+ array($external_shipping_id, $dewar['DEWARID'])
+ );
+ return $external_shipping_id;
+ }
+
function _dispatch_dewar_in_shipping_service($dispatch_info, $dewar)
{
global $facility_company;
@@ -1000,6 +1054,8 @@ function _dispatch_dewar()
global $dispatch_email_intl;
global $use_shipping_service;
global $shipping_service_links_in_emails;
+ global $use_shipping_service_redirect;
+ global $shipping_service_app_url;
// Variable to store where the dewar is (Synchrotron or eBIC building)
// Could map this to dewar storage locations in ISPyB to make more generic...?
$dispatch_from_location = 'Synchrotron';
@@ -1014,10 +1070,12 @@ function _dispatch_dewar()
}
$dew = $this->db->pq(
- "SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, s.shippingid, CONCAT(p.proposalcode, p.proposalnumber) as proposal
+ "SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, d.externalShippingIdFromSynchrotron, s.shippingid, CONCAT(p.proposalcode, p.proposalnumber) as proposal, count(distinct c.containerId) as num_pucks, count(b.blsampleId) as num_samples
FROM dewar d
INNER JOIN shipping s ON s.shippingid = d.shippingid
INNER JOIN proposal p ON p.proposalid = s.proposalid
+ LEFT JOIN container c on c.dewarid = d.dewarid
+ LEFT JOIN BLSample b on b.containerId = c.containerId
WHERE d.dewarid=:1 and p.proposalid=:2",
array($this->arg('DEWARID'), $this->proposalid)
);
@@ -1032,7 +1090,7 @@ function _dispatch_dewar()
// If no location specified (i.e. deleted), then read from dewar transport history.
// If no dewar transport history fall back to dewar location
// We still update history based on provided location to record action from user
- $dewar_location = $this->has_arg('LOCATION)') ? $this->arg('LOCATION') : "";
+ $dewar_location = $this->has_arg('LOCATION') ? $this->arg('LOCATION') : "";
if (empty($dewar_location)) {
// What was the last history entry for this dewar?
@@ -1080,21 +1138,42 @@ function _dispatch_dewar()
if (Utils::getValueOrDefault($use_shipping_service) && in_array($country, $facility_courier_countries)) {
if ($terms_accepted) {
- try {
- $shipment_id = $this->_dispatch_dewar_in_shipping_service($data, $dew);
+ if (Utils::getValueOrDefault($use_shipping_service_redirect)) {
+ try {
+ $shipment_id = $this->_dispatch_dewar_shipment_request($dew);
+ } catch (Exception $e) {
+ error_log("Error returned from shipping service: " . $e . "\nDewar data: " . json_encode($dew));
+ $error_response = json_decode($e->getMessage());
+ $this->_error($error_response->content->detail, $error_response->status);
+ }
+ if (Utils::getValueOrDefault($shipping_service_links_in_emails)) {
+ $data['AWBURL'] = "{$shipping_service_app_url}/shipment-requests/{$shipment_id}/outgoing";
+ }
+ } else {
+ try {
+ $shipment_id = $this->_dispatch_dewar_in_shipping_service($data, $dew);
+ } catch (Exception $e) {
+ error_log($e);
+ $data['AWBURL'] = "";
+ }
if (Utils::getValueOrDefault($shipping_service_links_in_emails)) {
$data['AWBURL'] = $this->shipping_service->get_awb_pdf_url($shipment_id);
}
- } catch (Exception $e) {
- error_log($e);
- $data['AWBURL'] = "";
}
}
}
# Prepare e-mail response for dispatch request
- $subject_line = '*** Dispatch requested for Dewar ' . $dew['BARCODE'] . ' from ' . $dispatch_from_location . ' - Pickup Date: ' . $this->args['DELIVERYAGENT_SHIPPINGDATE'] . ' ***';
- $email = new Email('dewar-dispatch', $subject_line);
+ $use_dispatch_lite_template = (
+ Utils::getValueOrDefault($use_shipping_service)
+ && in_array($country, $facility_courier_countries)
+ && $terms_accepted
+ && Utils::getValueOrDefault($use_shipping_service_redirect)
+ );
+ $subject_pickup_date = $use_dispatch_lite_template ? '' : ' - Pickup Date: ' . $this->args['DELIVERYAGENT_SHIPPINGDATE'];
+ $subject_line = '*** Dispatch requested for Dewar ' . $dew['BARCODE'] . ' from ' . $dispatch_from_location . $subject_pickup_date . ' ***';
+ $email_template = $use_dispatch_lite_template ? 'dewar-dispatch-lite' : 'dewar-dispatch';
+ $email = new Email($email_template, $subject_line);
// If a local contact is given, try to find their email address
// First try LDAP, if unsuccessful look at the ISPyB person record for a matching staff user
@@ -1120,6 +1199,7 @@ function _dispatch_dewar()
$data['LOCALCONTACT'] = $local_contact;
if (!array_key_exists('LCEMAIL', $data))
$data['LCEMAIL'] = '';
+ $data['BARCODE'] = $dew['BARCODE'];
$email->data = $data;
if ($country != $facility_country && !is_null($dispatch_email_intl)) {
@@ -1343,7 +1423,7 @@ function _get_dewars()
$order = $cols[$this->arg('sort_by')] . ' ' . $dir;
}
- $dewars = $this->db->paginate("SELECT CONCAT(p.proposalcode, p.proposalnumber) as prop, CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number) as firstexperiment, r.labcontactid, se.beamlineoperator as localcontact, se.beamlinename, TO_CHAR(se.startdate, 'HH24:MI DD-MM-YYYY') as firstexperimentst, d.firstexperimentid, s.shippingid, s.shippingname, d.facilitycode, count(c.containerid) as ccount, (case when se.visit_number > 0 then (CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number)) else '' end) as exp, d.code, d.barcode, d.storagelocation, d.dewarstatus, d.dewarid, d.trackingnumbertosynchrotron, d.trackingnumberfromsynchrotron, s.deliveryagent_agentname, d.weight, d.deliveryagent_barcode, GROUP_CONCAT(c.code SEPARATOR ', ') as containers, s.sendinglabcontactid, s.returnlabcontactid, pe.givenname, pe.familyname
+ $dewars = $this->db->paginate("SELECT CONCAT(p.proposalcode, p.proposalnumber) as prop, CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number) as firstexperiment, r.labcontactid, se.beamlineoperator as localcontact, se.beamlinename, TO_CHAR(se.startdate, 'HH24:MI DD-MM-YYYY') as firstexperimentst, d.firstexperimentid, s.shippingid, s.shippingname, d.facilitycode, count(c.containerid) as ccount, (case when se.visit_number > 0 then (CONCAT(p.proposalcode, p.proposalnumber, '-', se.visit_number)) else '' end) as exp, 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
FROM dewar d
LEFT OUTER JOIN container c ON c.dewarid = d.dewarid
INNER JOIN shipping s ON d.shippingid = s.shippingid
diff --git a/api/src/Shipment/ShippingService.php b/api/src/Shipment/ShippingService.php
index 647fba717..a43e90363 100644
--- a/api/src/Shipment/ShippingService.php
+++ b/api/src/Shipment/ShippingService.php
@@ -151,4 +151,14 @@ function get_awb_pdf_url($shipment_id)
{
return $this->shipping_app_url . '/shipments/' . $shipment_id . '/awb';
}
+
+ function create_shipment_request($shipment_request_data)
+ {
+ return $this->_send_request(
+ $this->shipping_api_url . '/shipment_requests/',
+ "POST",
+ $shipment_request_data,
+ 201
+ );
+ }
}
diff --git a/client/src/js/modules/shipment/models/dispatch.js b/client/src/js/modules/shipment/models/dispatch.js
index bd4652cc0..36baa84dc 100644
--- a/client/src/js/modules/shipment/models/dispatch.js
+++ b/client/src/js/modules/shipment/models/dispatch.js
@@ -16,7 +16,9 @@ define(['backbone'], function(Backbone) {
},
VISIT: {
- required: true,
+ required: function() {
+ return this.visitRequired
+ },
pattern: 'visit',
},
@@ -108,6 +110,7 @@ define(['backbone'], function(Backbone) {
courierDetailsRequired: false, // We want to set this default to false unless 'DELIVERYAGENT_AGENTCODE' has a value in the shipment model
postCodeRequired: false,
+ visitRequired: true,
})
})
diff --git a/client/src/js/modules/shipment/views/dispatch.js b/client/src/js/modules/shipment/views/dispatch.js
index cf74fb433..977a5f746 100644
--- a/client/src/js/modules/shipment/views/dispatch.js
+++ b/client/src/js/modules/shipment/views/dispatch.js
@@ -60,7 +60,8 @@ define(['marionette', 'views/form',
'click @ui.facc': 'showTerms',
'blur @ui.postCode': 'stripPostCode',
'blur @ui.addr': 'formatAddress',
- 'change @ui.country': 'checkPostCodeRequired'
+ 'change @ui.country': 'checkPostCodeRequired',
+ 'change @ui.dispatchCountry': 'showDispatchForm'
},
ui: {
@@ -80,17 +81,24 @@ define(['marionette', 'views/form',
ph: 'input[name=PHONENUMBER]',
lab: 'input[name=LABNAME]',
+ submit: 'button[name=submit]',
+
facc: 'a.facc',
accountNumber: 'input[NAME=DELIVERYAGENT_AGENTCODE]',
courier: 'input[name=DELIVERYAGENT_AGENTNAME]',
courierDetails: '.courierDetails',
+ dispatchDetails: '.dispatchDetails',
facilityCourier: '.facilityCourier',
awbNumber: 'input[name=AWBNUMBER]',
useAnotherCourierAccount: 'input[name=USE_ANOTHER_COURIER_ACCOUNT]',
- dispatchState: '.dispatch-state'
+ dispatchState: '.dispatch-state',
+
+ dispatchCountry: 'select[name=DISPATCHCOUNTRY]',
+ courierSection: '.courierSection'
},
labContactCountry : null,
+ dispatchCountry: null,
templateHelpers: function() {
return {
@@ -112,6 +120,18 @@ define(['marionette', 'views/form',
success: function() {
app.trigger('shipment:show', this.getOption('dewar').get('SHIPPINGID'))
+ if (
+ app.options.get("shipping_service_app_url")
+ && (Number(this.terms.get('ACCEPTED')) === 1) // terms.ACCPETED could be undefined, 1, or "1"
+ && app.options.get("facility_courier_countries").includes(this.dispatchCountry)
+ ) {
+ this.getOption('dewar').fetch().done((dewar) => {
+ const external_id = dewar.EXTERNALSHIPPINGIDFROMSYNCHROTRON;
+ window.location.assign(
+ `${app.options.get("shipping_service_app_url")}/shipment-requests/${external_id}/outgoing`
+ )
+ })
+ }
},
failure: function() {
@@ -120,6 +140,7 @@ define(['marionette', 'views/form',
onRender: function() {
this.date('input[name=DELIVERYAGENT_SHIPPINGDATE]')
+ this.$el.hide()
var d = new Date()
var today = (d.getDate() < 10 ? '0'+d.getDate() : d.getDate()) + '-' + (d.getMonth() < 9 ? '0'+(d.getMonth()+1) : d.getMonth()+1) + '-' + d.getFullYear()
@@ -147,9 +168,20 @@ define(['marionette', 'views/form',
doOnRender: function() {
this.ui.exp.html(this.visits.opts()).val(this.model.get('VISIT'))
this.updateLC()
+ this.populateDispatchCountries()
this.populateCountries()
this.stripPostCode()
this.formatAddress()
+ this.$el.show()
+ this.hideDispatchForm();
+ },
+
+ populateDispatchCountries: function () {
+ const dispatchCountryOptions = [...app.options.get("facility_courier_countries"), 'Other']
+ .map((country) => ``)
+ .join("");
+ this.ui.dispatchCountry.html(dispatchCountryOptions);
+ this.ui.dispatchCountry.val('');
},
populateCountries: function() {
@@ -240,6 +272,28 @@ define(['marionette', 'views/form',
}
},
+ hideDispatchForm: function () {
+ this.ui.courierSection.hide();
+ this.ui.dispatchDetails.hide();
+ this.ui.submit.hide();
+ },
+
+ showDispatchForm: function() {
+ this.dispatchCountry = this.ui.dispatchCountry.val()
+ this.ui.courierSection.show();
+ this.ui.dispatchDetails.show();
+ this.ui.submit.show();
+ if (
+ this.terms.get("ACCEPTED")
+ && app.options.get("shipping_service_app_url")
+ && app.options.get("facility_courier_countries").includes(this.dispatchCountry)
+ ){
+ this.model.visitRequired = false
+ this.ui.dispatchDetails.hide()
+ this.ui.submit.text("Proceed")
+ }
+ },
+
showTerms: function() {
var terms = new TCDialog({ model: this.terms })
this.listenTo(terms, 'terms:accepted', this.termsAccepted, this)
@@ -266,6 +320,14 @@ define(['marionette', 'views/form',
this.ui.courierDetails.hide()
this.ui.facilityCourier.show()
this.model.courierDetailsRequired = false
+ if (
+ app.options.get("shipping_service_app_url")
+ && app.options.get("facility_courier_countries").includes(this.ui.dispatchCountry.val())
+ ){
+ this.model.visitRequired = false
+ this.ui.dispatchDetails.hide()
+ this.ui.submit.text("Proceed")
+ }
},
checkPostCodeRequired: function() {
diff --git a/client/src/js/templates/shipment/dewarlistrow.html b/client/src/js/templates/shipment/dewarlistrow.html
index 47f737029..1be50e6e2 100644
--- a/client/src/js/templates/shipment/dewarlistrow.html
+++ b/client/src/js/templates/shipment/dewarlistrow.html
@@ -15,7 +15,12 @@
Add Container
<% if (STORAGELOCATION != 'stores-out') { %>
- Dispatch Dewar
+ <% if (app.options.get("shipping_service_app_url") && EXTERNALSHIPPINGIDFROMSYNCHROTRON) { %>
+ <% const link = `${app.options.get("shipping_service_app_url")}/shipment-requests/${EXTERNALSHIPPINGIDFROMSYNCHROTRON}/outgoing` %>
+ Dispatch Dewar
+ <% } else { %>
+ Dispatch Dewar
+ <% } %>
Transfer Dewar
<% } %>
diff --git a/client/src/js/templates/shipment/dispatch.html b/client/src/js/templates/shipment/dispatch.html
index b21cc8eec..d8e4cd634 100644
--- a/client/src/js/templates/shipment/dispatch.html
+++ b/client/src/js/templates/shipment/dispatch.html
@@ -23,6 +23,69 @@ Request Dewar Dispatch
<%-DEWAR.FACILITYCODE%>
<% } %>
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-