From 89d82b6f019b8c98be407e8766fb65524c4ecbb4 Mon Sep 17 00:00:00 2001 From: NKatti2011 <108797920+NKatti2011@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:16:41 +0100 Subject: [PATCH] Merge Pre-release/2023-R3.4 into Master (#656) * LIMS_817: Update shipping service requests * LIMS-817: Add param to dispatch function * LIMS-832: Book incoming shipments with the shipping service * LIMS-832: Fix array string conversion error * LIMS-832: Label address input with 'max 3 lines' * Format address & post code in dispatch form * LIMS-832: Trim post code & email for shipping service * [LIMS-116] Fix: Summary page revamp, make css local (#639) * updating .gitignore * adding frontend files and building backend * adding front end files and router files * create sidebar, filter options added, routes added * add routing to page,search bar and column selector * adding pagination continutation * adding csv, all columns, rest of filters * added descending and ascending * sidebar dropdown&changed data structure&hide row * cleaning up fixing jump bug * refactored backend mapped data * added expanding row * refactored favourites * refactored orderby filter * cleaned up code, added comments * added all params to watcher * added summary db connection * add routes to summary * add backend changes summarypage * changes to expandable sidebar, cleaning up fronte * clean up, add functions to get data * front end changes, group concat backend * remove summarypage code * fix pagination, timeout * delete old summary file * changed pagination in summary.php * changed backend to not include tot * fix refined cell c column * added ifsets to avoid undefined offset error * delete offset for output * change order of operands * change filters, fix operands * fix csv button * changed prop to propid * format beamlinename * change al,be,gamma * add selected columns summary * additional changes for selected columns * add multiple selections change expandable sidebar * redo routing, keep alive summary * fixes, change routing, results display, orderby * fixes to selected columns * format page to allow for customisation * area for potential formatting and fix to querypara * changes to regex, combobox multiple, and fomat * column select fix, resize pill fix, format inputs * Update api/src/Database/DatabaseConnectionFactory.php Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/sp/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/saxs/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/pow/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/mx/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/em/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/app/components/combo-box.vue Co-authored-by: Guilherme Francisco * Update api/src/Database/DatabaseFactory.php Co-authored-by: John Holt <7570055+John-Holt-Tessella@users.noreply.github.com> * Update api/src/TemplateParser.php Co-authored-by: Guilherme Francisco * Code review changes: database conns, code tidy * add get started button * Change styling to be local rather than global --------- Co-authored-by: Guilherme Francisco Co-authored-by: John Holt <7570055+John-Holt-Tessella@users.noreply.github.com> * [LIMS-116] Fix: Summary page revamp, delete css global (#640) * updating .gitignore * adding frontend files and building backend * adding front end files and router files * create sidebar, filter options added, routes added * add routing to page,search bar and column selector * adding pagination continutation * adding csv, all columns, rest of filters * added descending and ascending * sidebar dropdown&changed data structure&hide row * cleaning up fixing jump bug * refactored backend mapped data * added expanding row * refactored favourites * refactored orderby filter * cleaned up code, added comments * added all params to watcher * added summary db connection * add routes to summary * add backend changes summarypage * changes to expandable sidebar, cleaning up fronte * clean up, add functions to get data * front end changes, group concat backend * remove summarypage code * fix pagination, timeout * delete old summary file * changed pagination in summary.php * changed backend to not include tot * fix refined cell c column * added ifsets to avoid undefined offset error * delete offset for output * change order of operands * change filters, fix operands * fix csv button * changed prop to propid * format beamlinename * change al,be,gamma * add selected columns summary * additional changes for selected columns * add multiple selections change expandable sidebar * redo routing, keep alive summary * fixes, change routing, results display, orderby * fixes to selected columns * format page to allow for customisation * area for potential formatting and fix to querypara * changes to regex, combobox multiple, and fomat * column select fix, resize pill fix, format inputs * Update api/src/Database/DatabaseConnectionFactory.php Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/sp/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/saxs/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/pow/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/mx/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/modules/types/em/menu.js Co-authored-by: Guilherme Francisco * Update client/src/js/app/components/combo-box.vue Co-authored-by: Guilherme Francisco * Update api/src/Database/DatabaseFactory.php Co-authored-by: John Holt <7570055+John-Holt-Tessella@users.noreply.github.com> * Update api/src/TemplateParser.php Co-authored-by: Guilherme Francisco * Code review changes: database conns, code tidy * add get started button * Change styling to be local rather than global * delete summary css globals --------- Co-authored-by: Guilherme Francisco Co-authored-by: John Holt <7570055+John-Holt-Tessella@users.noreply.github.com> * Update api/src/Page/Shipment.php * Update to use fns in 7.3 and improve errors * Use constants * Fix failing tests * LIMS-892: Dont allow UDC samples with no screening method and no reqd resolution (#629) Co-authored-by: Mark Williams * User shipping service if using facility account number * LIMS-932: Send proposal when creating shipments in shipping service (#646) * LIMS-932: Send proposal when creating shipments in shipping service * Use proposal from db query rather than args --------- Co-authored-by: John Holt --------- Co-authored-by: Matthew Pritchard Co-authored-by: Guilherme Francisco Co-authored-by: John Holt <7570055+John-Holt-Tessella@users.noreply.github.com> Co-authored-by: John Holt Co-authored-by: Mark W <24956497+ndg63276@users.noreply.github.com> Co-authored-by: Mark Williams Co-authored-by: Matthew Pritchard <46708056+MattPrit@users.noreply.github.com> --- api/config_sample.php | 1 + api/src/Database/DatabaseFactory.php | 11 +- api/src/Page/Shipment.php | 112 ++++++++++++++---- api/src/Shipment/ShippingService.php | 28 +++-- api/tests/Database/DatabaseFactoryTest.php | 2 +- .../js/modules/shipment/views/createawb.js | 23 ++-- .../src/js/modules/shipment/views/dispatch.js | 2 + .../types/mx/samples/tabbed-columns-view.vue | 2 +- .../src/js/templates/contact/contactview.html | 2 +- .../src/js/templates/shipment/createawb.html | 2 +- 10 files changed, 139 insertions(+), 46 deletions(-) diff --git a/api/config_sample.php b/api/config_sample.php index 1727e9025..9aefd1996 100644 --- a/api/config_sample.php +++ b/api/config_sample.php @@ -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; diff --git a/api/src/Database/DatabaseFactory.php b/api/src/Database/DatabaseFactory.php index 8edcb1b23..61ba33c04 100644 --- a/api/src/Database/DatabaseFactory.php +++ b/api/src/Database/DatabaseFactory.php @@ -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 { diff --git a/api/src/Page/Shipment.php b/api/src/Page/Shipment.php index ebc31ec33..376360c89 100644 --- a/api/src/Page/Shipment.php +++ b/api/src/Page/Shipment.php @@ -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 @@ -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; @@ -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 @@ -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'); @@ -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' diff --git a/api/src/Shipment/ShippingService.php b/api/src/Shipment/ShippingService.php index 34477788a..6b9fddee9 100644 --- a/api/src/Shipment/ShippingService.php +++ b/api/src/Shipment/ShippingService.php @@ -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() { @@ -77,10 +79,21 @@ 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 @@ -88,10 +101,10 @@ function get_shipment($external_id) } - 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 @@ -99,12 +112,13 @@ function update_shipment($external_id, $shipment_data) } - 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 ); } diff --git a/api/tests/Database/DatabaseFactoryTest.php b/api/tests/Database/DatabaseFactoryTest.php index 9dc78dc23..8d2ae6720 100644 --- a/api/tests/Database/DatabaseFactoryTest.php +++ b/api/tests/Database/DatabaseFactoryTest.php @@ -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."); diff --git a/client/src/js/modules/shipment/views/createawb.js b/client/src/js/modules/shipment/views/createawb.js index 53a953ba2..c33c28bfb 100644 --- a/client/src/js/modules/shipment/views/createawb.js +++ b/client/src/js/modules/shipment/views/createawb.js @@ -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() { @@ -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) @@ -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') } diff --git a/client/src/js/modules/shipment/views/dispatch.js b/client/src/js/modules/shipment/views/dispatch.js index 858d390c4..c9ac364cc 100644 --- a/client/src/js/modules/shipment/views/dispatch.js +++ b/client/src/js/modules/shipment/views/dispatch.js @@ -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() { diff --git a/client/src/js/modules/types/mx/samples/tabbed-columns-view.vue b/client/src/js/modules/types/mx/samples/tabbed-columns-view.vue index 639568a98..8ad5cd882 100644 --- a/client/src/js/modules/types/mx/samples/tabbed-columns-view.vue +++ b/client/src/js/modules/types/mx/samples/tabbed-columns-view.vue @@ -388,7 +388,7 @@ diff --git a/client/src/js/templates/contact/contactview.html b/client/src/js/templates/contact/contactview.html index 071812fa9..0e041cde2 100644 --- a/client/src/js/templates/contact/contactview.html +++ b/client/src/js/templates/contact/contactview.html @@ -42,7 +42,7 @@

View Home Lab Contact

  • - Street Address
    (excluding post code, city)
    + Street Address
    (Max 3 lines, excluding post code, city)
    <%-ADDRESS%>
  • diff --git a/client/src/js/templates/shipment/createawb.html b/client/src/js/templates/shipment/createawb.html index bad90054b..b2286c54f 100644 --- a/client/src/js/templates/shipment/createawb.html +++ b/client/src/js/templates/shipment/createawb.html @@ -64,7 +64,7 @@

    Laboratory Details

  • - Laboratory Address
    (excluding post code)
    + Laboratory Address
    (Max 3 lines, excluding post code, city)