Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Master into Prerelease #658

Merged
merged 7 commits into from
Aug 29, 2023
1 change: 1 addition & 0 deletions api/config_sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@

# Shipping service details
$use_shipping_service = null;
$use_shipping_service_incoming_shipments = null;
$shipping_service_url = null;
$shipping_service_links_in_emails = null;

Expand Down
11 changes: 6 additions & 5 deletions api/src/Database/DatabaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,26 @@ function __construct($databaseConnectionFactory)

public function get($databaseType = null)
{
global $dbtype;

if ( $databaseType == null) {
// Global variable is named $dbtype in config.php.
global $dbtype;
$databaseType = $dbtype;
}

if (!$databaseType) {
error_log('Database type variable, dbtype, is not specified in config.php - defaulting to MySql.');
$database_type = 'MySQL';
$databaseType = 'MySQL';
}

// Determine fully-qualified class name of database class corresponding to $database_type.
if (key_exists(strtolower($databaseType), $this->database_types)) {
$dbType = $this->database_types[strtolower($databaseType)];
$selectedDBConfig = $this->database_types[strtolower($databaseType)];

$full_class_name = 'SynchWeb\\Database\\Type\\' . $dbType["dbClassName"];;
$full_class_name = 'SynchWeb\\Database\\Type\\' . $selectedDBConfig["dbClassName"];

if (class_exists($full_class_name)) {
$conn = $this->databaseConnectionFactory->get($dbType["dataConnectionName"]);
$conn = $this->databaseConnectionFactory->get($selectedDBConfig["dataConnectionName"]);
return new $full_class_name($conn);
}
else {
Expand Down
112 changes: 89 additions & 23 deletions api/src/Page/Shipment.php
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,9 @@ function _dispatch_dewar_in_shipping_service($dispatch_info, $dewar)
"shipper_contact_email" => $facility_email,
"internal_contact_name" => $this->has_arg('LOCALCONTACT') ? $this->args['LOCALCONTACT'] : null,
"shipment_reference" => $dispatch_info['VISIT'],
"external_id" => (int) $dispatch_info['DEWARID']
"external_id" => (int) $dispatch_info['DEWARID'],
"journey_type" => ShippingService::JOURNEY_FROM_FACILITY,
"packages" => array(array("external_id" => (int) $dispatch_info['DEWARID']))
);

# Split up address. Necessary as address is a single field in ispyb
Expand All @@ -968,15 +970,16 @@ function _dispatch_dewar_in_shipping_service($dispatch_info, $dewar)

try {
if ($create === true) {
$shipment_data["proposal"] = $dewar["PROPOSAL"];
$response = $this->shipping_service->create_shipment($shipment_data);
} else {
$this->shipping_service->update_shipment($dispatch_info['DEWARID'], $shipment_data);
$response = $this->shipping_service->get_shipment($dispatch_info['DEWARID']);
$this->shipping_service->update_shipment($dispatch_info['DEWARID'], $shipment_data, ShippingService::JOURNEY_FROM_FACILITY);
$response = $this->shipping_service->get_shipment($dispatch_info['DEWARID'], ShippingService::JOURNEY_FROM_FACILITY);
}
$shipment_id = $response['shipmentId'];
$this->shipping_service->dispatch_shipment($shipment_id);
$this->shipping_service->dispatch_shipment($shipment_id, false);
} catch (Exception $e) {
throw new Exception("Error returned from shipping service: " . $e . "\nShipment data: " . $shipment_data);
throw new Exception("Error returned from shipping service: " . $e . "\nShipment data: " . json_encode($shipment_data));
}

return $shipment_id;
Expand Down Expand Up @@ -1004,7 +1007,7 @@ function _dispatch_dewar()
}

$dew = $this->db->pq(
"SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, s.shippingid
"SELECT d.dewarid, d.barcode, d.storagelocation, d.dewarstatus, s.shippingid, CONCAT(p.proposalcode, p.proposalnumber) as proposal
FROM dewar d
INNER JOIN shipping s ON s.shippingid = d.shippingid
INNER JOIN proposal p ON p.proposalid = s.proposalid
Expand Down Expand Up @@ -2646,9 +2649,66 @@ function _get_default_dewar()
}


function _book_shipment_in_shipping_service($user, $shipment, $dewars, $journey_type) {
$address_lines = explode(PHP_EOL, rtrim($user["address"]));
$contact = array(
"company_name" => $user["company"],
"address_line1" => isset($address_lines[0]) ? $address_lines[0] : null,
"address_line2" => isset($address_lines[1]) ? $address_lines[1] : null,
"address_line3" => isset($address_lines[2]) ? $address_lines[2] : null,
"city" => $user["city"],
"country" => $user["country"],
"post_code" => rtrim($user["postcode"]),
"contact_name" => $user["name"],
"contact_phone_number" => $user["phone"],
"contact_email" => rtrim($user["email"])
);
$shipment_data = array(
"shipment_reference" => $shipment["PROP"],
"external_id" => $shipment['SHIPPINGID'],
"packages" => array_map(
function($dewar) {return array("external_id" => $dewar["DEWARID"]);},
$dewars
)
);

// Create or update shipment in shipping service
try {
$response = $this->shipping_service->get_shipment($shipment['SHIPPINGID'], $journey_type);
$user_shipment_role = $this->has_arg('RETURN') ? "consignee" : "shipper";
$relabelled_contact = array_combine(
array_map(function($key) use ($user_shipment_role) {return $user_shipment_role."_".$key;},
array_keys($contact)),
$contact);
$shipment_update_data = array_merge($response, $shipment_data, $relabelled_contact);
$this->shipping_service->update_shipment($shipment["SHIPPINGID"], $shipment_update_data, ShippingService::JOURNEY_TO_FACILITY);
} catch (\Exception $e) {
$shipment_data["proposal"] = $shipment["PROP"];
$shipment_data["contact"] = $contact;
$response = $this->shipping_service->create_shipment_by_journey_type($shipment_data, $journey_type);
}

// Dispatch shipment in shipping service
$shipmentId = $response["shipmentId"];
$dispatch_details = $this->shipping_service->dispatch_shipment($shipmentId, false);

$awb_pieces = array_map(
function($package, $index) {return array("piecenumber" => $index+1, "licenseplate" => $package["tracking_number"]);},
$dispatch_details["packages"],
array_keys($dispatch_details["packages"])
);

return array(
"awb" => $dispatch_details["tracking_number"],
"label" => $dispatch_details["air_waybill"],
"pieces" => $awb_pieces
);
}


function _create_awb()
{
global $dhl_service, $dhl_service_eu, $dhl_acc, $dhl_acc_import, $facility_courier_countries, $facility_courier_countries_nde;
global $dhl_service, $dhl_service_eu, $dhl_acc, $dhl_acc_import, $facility_courier_countries, $facility_courier_countries_nde, $use_shipping_service_incoming_shipments;

if (!$this->has_arg('prop'))
$this->_error('No proposal specified');
Expand Down Expand Up @@ -2764,22 +2824,28 @@ function _create_awb()
$awb = null;
if (!$ship['DELIVERYAGENT_FLIGHTCODE']) {
try {
$awb = $this->dhl->create_awb(array(
'payee' => $payee,
'accountnumber' => $accno,
'shipperid' => $ship['PROP'],
'service' => $product,
'date' => $ship['DELIVERYAGENT_SHIPPINGDATE'],
'declaredvalue' => $this->arg('DECLAREDVALUE'),
'description' => $this->arg('DESCRIPTION'),

'sender' => $this->has_arg('RETURN') ? $facility : $user,
'receiver' => $this->has_arg('RETURN') ? $user : $facility,

'pieces' => $pieces,
'notification' => implode(';', $emails),
'message' => $facility_company . ': Shipment booked from ISPyB for ' . $ship['PROP'] . ' ' . $ship['SHIPPINGNAME'] . ' containing ' . implode(',', $names)
));
if (Utils::getValueOrDefault($use_shipping_service_incoming_shipments) && $accno === $dhl_acc) {
$journey_type = $this->has_arg('RETURN') ? ShippingService::JOURNEY_FROM_FACILITY : ShippingService::JOURNEY_TO_FACILITY;
$awb = $this->_book_shipment_in_shipping_service($user, $ship, $dewars, $journey_type);
} else {
error_log("Not using shipping service for: {$ship['SHIPPINGID']}");
$awb = $this->dhl->create_awb(array(
'payee' => $payee,
'accountnumber' => $accno,
'shipperid' => $ship['PROP'],
'service' => $product,
'date' => $ship['DELIVERYAGENT_SHIPPINGDATE'],
'declaredvalue' => $this->arg('DECLAREDVALUE'),
'description' => $this->arg('DESCRIPTION'),

'sender' => $this->has_arg('RETURN') ? $facility : $user,
'receiver' => $this->has_arg('RETURN') ? $user : $facility,

'pieces' => $pieces,
'notification' => implode(';', $emails),
'message' => $facility_company . ': Shipment booked from ISPyB for ' . $ship['PROP'] . ' ' . $ship['SHIPPINGNAME'] . ' containing ' . implode(',', $names)
));
}

$this->db->pq("UPDATE shipping
SET deliveryagent_flightcode=:1, deliveryagent_flightcodetimestamp=CURRENT_TIMESTAMP, deliveryagent_label=:2, deliveryagent_productcode=:3, deliveryagent_flightcodepersonid=:4, shippingstatus='awb created', deliveryagent_agentname='DHL'
Expand Down
28 changes: 21 additions & 7 deletions api/src/Shipment/ShippingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class ShippingService
{
private $shipping_api_url;
private $headers;
public const JOURNEY_TO_FACILITY = "TO_FACILITY";
public const JOURNEY_FROM_FACILITY = "FROM_FACILITY";

function __construct()
{
Expand Down Expand Up @@ -77,34 +79,46 @@ function create_shipment($shipment_data)
}


function get_shipment($external_id)
function create_shipment_by_journey_type($shipment_data, $journey_type)
{
return $this->_send_request(
$this->shipping_api_url . '/shipments/external_id/' . $external_id,
$this->shipping_api_url . '/shipments/' . $journey_type,
"POST",
$shipment_data,
201
);
}


function get_shipment($external_id, $journey_type)
{
return $this->_send_request(
$this->shipping_api_url . '/shipments/external_id/' . $external_id . '?journey_type=' . $journey_type,
"GET",
null,
200
);
}


function update_shipment($external_id, $shipment_data)
function update_shipment($external_id, $shipment_data, $journey_type)
{
return $this->_send_request(
$this->shipping_api_url . '/shipments/external_id/' . $external_id,
$this->shipping_api_url . '/shipments/external_id/' . $external_id . '?journey_type=' . $journey_type,
"PUT",
$shipment_data,
204
);
}


function dispatch_shipment($shipment_id)
function dispatch_shipment($shipment_id, $pickup_requested)
{
$pickup_requested_str = ($pickup_requested) ? "true" : "false";
return $this->_send_request(
$this->shipping_api_url . '/shipments/' . $shipment_id . '/dispatch',
$this->shipping_api_url . '/shipments/' . $shipment_id . '/dispatch?pickup_requested=' . $pickup_requested_str,
"POST",
array(),
null,
201
);
}
Expand Down
2 changes: 1 addition & 1 deletion api/tests/Database/DatabaseFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function testErrorIsLoggedForDatabaseTypeClassThatDoesNotExist(): void
{
global $dbtype;
$dbtype = "obscure-db2";
$this->dbFactory->database_types[$dbtype] = $dbtype;
$this->dbFactory->database_types[$dbtype] = ["dbClassName" =>$dbtype, "dataConnectionName" => 'MySQL'];

$log = $this->getFunctionMock(__NAMESPACE__, "error_log");
$log->expects($this->once())->with("Database class 'SynchWeb\Database\Type\obscure-db2' does not exist.");
Expand Down
2 changes: 1 addition & 1 deletion client/src/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@import "partials/_mc.scss";
@import "partials/_imaging.scss";

@import "partials/_summary.scss";



// Third-party
Expand Down
23 changes: 16 additions & 7 deletions client/src/js/modules/shipment/views/createawb.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,19 @@ define(['backbone',
},

checkAvailability: function() {
if (this.shipment.get('DELIVERYAGENT_AGENTNAME').toLowerCase() != 'dhl' && (
!(app.options.get('facility_courier_countries').indexOf(this.lc.get('COUNTRY')) > -1) &&
!(app.options.get('facility_courier_countries_nde').indexOf(this.lc.get('COUNTRY')) > -1)
))
app.message({ title: 'Service Not Available', message: 'This service is only available for shipments from '+app.options.get('facility_courier_countries').concat(app.options.get('facility_courier_countries_nde')).join(',')+', or for user with DHL accounts. Please either update your labcontact or the shipment courier'})
const agent_name = this.shipment.get('DELIVERYAGENT_AGENTNAME')
const facility_courier_countries = app.options.get('facility_courier_countries')
const facility_courier_countries_nde = app.options.get('facility_courier_countries_nde')
if ((agent_name==null || agent_name.toLowerCase() != 'dhl') && (
!(facility_courier_countries.indexOf(this.lc.get('COUNTRY')) > -1) &&
!(facility_courier_countries_nde.indexOf(this.lc.get('COUNTRY')) > -1)
)) {
const valid_countries = facility_courier_countries.concat(facility_courier_countries_nde).join(', ')
app.message({
title: 'Service Not Available',
message: 'This service is only available for shipments from ' + valid_countries +
', or for user with DHL accounts. Please either update your labcontact or the shipment courier'})
}
},

populateLC: function() {
Expand Down Expand Up @@ -435,7 +443,7 @@ define(['backbone',
PRODUCTCODE: prod,
},
success: function(resp) {
app.alert({ message: 'Air Waybill Successfully Created'})
app.message({ message: 'Air Waybill Successfully Created'})
setTimeout(function() {
app.trigger('shipment:show', self.shipment.get('SHIPPINGID'))
}, 1000)
Expand All @@ -452,7 +460,8 @@ define(['backbone',
console.error("Error parsing response: ", err)
}
}
app.alert({ message: json.message })
app.alert({ message: json.message, persist:true })
app.alert({ message: json.message})
self.ui.submit.prop('disabled', false)
self.$el.removeClass('loading')
}
Expand Down
2 changes: 2 additions & 0 deletions client/src/js/modules/shipment/views/dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ define(['marionette', 'views/form',
this.ui.exp.html(this.visits.opts()).val(this.model.get('VISIT'))
this.updateLC()
this.populateCountries()
this.stripPostCode()
this.formatAddress()
},

populateCountries: function() {
Expand Down
11 changes: 6 additions & 5 deletions client/src/js/modules/summary/views/summary.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<h> Filter </h>
</div>
<div class="tw-flex tw-col-span-2 tw-col-start-2 tw-mt-3 tw-ml-3">
<p class="tw-mt-2 tw-text-sm">Select Proposals </p>
<p class="tw-mt-2 tw-text-sm tw-whitespace-no-wrap">Select Proposals </p>
<combo-box v-if="filters[0].inputtype == 'combo-box'"
class="tw-w-7/12 tw-text-sm tw-ml-2 tw-mr-1 tw-mb-2"
:data="filters[0].data"
Expand All @@ -45,12 +45,12 @@
:valueArray="filters[0].selectedArr"
:searchArray="filters[0].selectedArr"
></combo-box>
<button class="sidebar-button tw-mr-1 tw-mb-2" @click="getStarted()">Get Started</button>
<button class="sidebar-button tw-mr-1 tw-mb-3 tw-whitespace-no-wrap" @click="getStarted()">Get Started</button>
</div>
<div class="tw-col-span-1 tw-col-start-6 tw-mt-2 tw-mr-3 ">
<div class="tw-col-span-1 tw-col-start-6 tw-mr-3 ">

<div class="tw-flex tw-mb-2">
<button class="sidebar-button tw-mr-1" @click="toggleSidebar()">Advanced Filter</button>
<div class="tw-flex tw-mb-3 tw-mt-3">
<button class="sidebar-button tw-mr-1 " @click="toggleSidebar()">Advanced Filter</button>
<button class="sidebar-button" @click="searchFilterParams" >
Search
</button>
Expand Down Expand Up @@ -1351,6 +1351,7 @@ export default {
</style>

<style scoped>
@import "../styles/_summary.scss";

.search-icon {
font-size: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@
<extended-validation-provider
:ref="`sample_${sampleIndex}_required_resolution`"
class-names="tw-px-2 tw-w-24"
:rules="sample['PROTEINID'] > -1 ? `required_if:sample ${sampleIndex + 1} screening method,none|positive_decimal:6` : ''"
:rules="sample['PROTEINID'] > -1 && queueForUDC ? `required_if:sample ${sampleIndex + 1} screening method,none,|positive_decimal:6` : ''"
:name="`Sample ${sampleIndex + 1} Required Resolution`"
:vid="`sample ${sampleIndex + 1} required resolution`"
>
Expand Down
2 changes: 1 addition & 1 deletion client/src/js/templates/contact/contactview.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ <h1>View Home Lab Contact</h1>
</li>

<li class="clearfix">
<span class="label">Street Address <br />(excluding post code, city)</span>
<span class="label">Street Address <br />(Max 3 lines, excluding post code, city)</span>
<div class="ADDRESS text editable tw-block"><%-ADDRESS%></div>
</li>

Expand Down
2 changes: 1 addition & 1 deletion client/src/js/templates/shipment/createawb.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ <h2>Laboratory Details</h2>
</li>

<li class="clearfix">
<span class="label">Laboratory Address <br /><span class="small">(excluding post code)</span></span>
<span class="label">Laboratory Address <br /><span class="small">(Max 3 lines, excluding post code, city)</span></span>
<div class="ADDRESS text"></div>
</li>

Expand Down
Loading