diff --git a/app/assets/stylesheets/legacy/chemical-tab.scss b/app/assets/stylesheets/legacy/chemical-tab.scss
index e07e537ab9..a215a85bfe 100644
--- a/app/assets/stylesheets/legacy/chemical-tab.scss
+++ b/app/assets/stylesheets/legacy/chemical-tab.scss
@@ -130,11 +130,11 @@ table.table-borderless {
}
.inventory-information-status {
- width: 22%;
+ width: 28%;
}
.inventory-text-input {
- width: 19%;
+ width: 30%;
}
.text-input-group {
@@ -144,20 +144,24 @@ table.table-borderless {
}
.text-input-price {
- width: 22%;
+ width: 10%;
}
.text-input-person {
- width: 22%;
+ width: 15%;
+ }
+
+ .text-input-storage-temperature {
+ width: 39%;
}
.text-input-date {
- margin-top: -17px;
- width: 35%;
+ margin-top: -17px;
+ width: 65%;
}
.text-input-required-by {
- width: 22%;
+ width: 18%;
}
}
diff --git a/app/packs/src/apps/mydb/elements/details/NumericInputUnit.js b/app/packs/src/apps/mydb/elements/details/NumericInputUnit.js
index 1c8ce81308..5578e54ee4 100644
--- a/app/packs/src/apps/mydb/elements/details/NumericInputUnit.js
+++ b/app/packs/src/apps/mydb/elements/details/NumericInputUnit.js
@@ -62,8 +62,10 @@ export default function NumericInputUnit(props) {
convertedValue = parseFloat(value);
break;
}
- onInputChange(convertedValue, convertedUnit);
- setUnit(convertedUnit);
+ if (!Number.isNaN(convertedValue)) {
+ onInputChange(convertedValue, convertedUnit);
+ setUnit(convertedUnit);
+ }
};
const handleInputValueChange = (event) => {
diff --git a/app/packs/src/components/ChemicalTab.js b/app/packs/src/components/ChemicalTab.js
index 8aa50321e2..e2241d32ad 100644
--- a/app/packs/src/components/ChemicalTab.js
+++ b/app/packs/src/components/ChemicalTab.js
@@ -395,7 +395,8 @@ export default class ChemicalTab extends React.Component {
}
textInput(data, label, parameter) {
- const componentClass = parameter !== 'important_notes' && parameter !== 'disposal_info' && parameter !== 'sensitivity_storage'
+ const componentClass = parameter !== 'important_notes'
+ && parameter !== 'disposal_info' && parameter !== 'sensitivity_storage'
&& parameter !== 'solubility' ? 'input' : 'textarea';
let value = '';
if (parameter !== 'cas') {
@@ -403,18 +404,23 @@ export default class ChemicalTab extends React.Component {
} else {
value = data || '';
}
- let conditionalOverlay;
- if (parameter === 'date') {
- conditionalOverlay = 'please enter the name of the person who orders/ordered the substance';
+ let conditionalOverlay = null;
+ if (parameter === 'person') {
+ conditionalOverlay = 'please enter the name of the person who ordered the substance';
} else if (parameter === 'required_by') {
conditionalOverlay = 'please enter the name of the person who requires the substance';
- } else {
- conditionalOverlay = null;
+ } else if (parameter === 'expiration_date') {
+ conditionalOverlay = 'please enter the expiration date of the substance';
}
const checkLabel = label !== 'Date' &&
{label};
+ const dateArray = ['person', 'required_by', 'expiration_date'];
return (
- {conditionalOverlay} : }>
+ {conditionalOverlay} : }
+ >
{checkLabel}
{this.textInput(data, 'Order number', 'order_number')}
-
- {this.numInputWithoutTable(data, 'Amount', 'amount')}
-
-
- {this.numInputWithoutTable(data, '', 'volume')}
-
-
-
{this.textInput(data, 'Price', 'price')}
-
+
+
+
{this.textInput(data, 'Person', 'person')}
-
+
this.setState({ switchRequiredOrderedDate: 'required' })}
@@ -922,15 +925,33 @@ export default class ChemicalTab extends React.Component {
>
Ordered date
+ this.setState({ switchRequiredOrderedDate: 'expiration' })}
+ active={switchRequiredOrderedDate === 'expiration'}
+ size="xxsm"
+ >
+ Expiration date
+
- {switchRequiredOrderedDate === 'required'
- ? this.textInput(data, 'Date', 'required_date')
- : this.textInput(data, 'Date', 'ordered_date')}
+ {switchRequiredOrderedDate === 'required' && this.textInput(data, 'Date', 'required_date')}
+ {switchRequiredOrderedDate === 'ordered' && this.textInput(data, 'Date', 'ordered_date')}
+ {switchRequiredOrderedDate === 'expiration' && this.textInput(data, 'Date', 'expiration_date')}
{this.textInput(data, 'Required by', 'required_by')}
+
+
+ {this.numInputWithoutTable(data, 'Amount', 'amount')}
+
+
+ {this.numInputWithoutTable(data, '', 'volume')}
+
+
+ {this.numInputWithoutTable(data, 'Storage Temperature', 'storage_temperature')}
+
+
>
);
}
diff --git a/app/packs/src/components/contextActions/ModalExport.js b/app/packs/src/components/contextActions/ModalExport.js
index 8f48c83f7a..b08189ef38 100644
--- a/app/packs/src/components/contextActions/ModalExport.js
+++ b/app/packs/src/components/contextActions/ModalExport.js
@@ -108,11 +108,16 @@ export default class ModalExport extends React.Component {
{ value: 'person', text: 'person', checked: false },
{ value: 'required_date', text: 'required date', checked: false },
{ value: 'ordered_date', text: 'ordered date', checked: false },
+ { value: 'expiration_date', text: 'expiration date', checked: false },
+ { value: 'storage_temperature', text: 'storage temperature', checked: false },
{ value: 'required_by', text: 'required by', checked: false },
{
- value: ['safety_sheet_link_merck', 'safety_sheet_link_thermofischer'],
+ value: [
+ 'safety_sheet_link_merck',
+ 'safety_sheet_link_thermofischer'
+ ],
text: 'safety sheet link',
- checked: false
+ checked: false,
},
{ value: ['product_link_merck', 'product_link_thermofischer'], text: 'product link', checked: false },
{ value: 'pictograms', text: 'pictograms', checked: false },
diff --git a/app/packs/src/components/searchModal/forms/SampleInventoryFieldData.js b/app/packs/src/components/searchModal/forms/SampleInventoryFieldData.js
index 250332c89a..118526d3e6 100644
--- a/app/packs/src/components/searchModal/forms/SampleInventoryFieldData.js
+++ b/app/packs/src/components/searchModal/forms/SampleInventoryFieldData.js
@@ -65,6 +65,13 @@ export default {
table: 'chemicals',
type: 'text',
},
+ {
+ column: 'expiration_date',
+ label: 'Expiration date',
+ key: 'information',
+ table: 'chemicals',
+ type: 'text',
+ },
{
column: 'required_by',
label: 'Required by',
diff --git a/lib/export/export_chemicals.rb b/lib/export/export_chemicals.rb
index e854b40bec..fc4e742b7c 100644
--- a/lib/export/export_chemicals.rb
+++ b/lib/export/export_chemicals.rb
@@ -3,11 +3,11 @@
module Export
class ExportChemicals
CHEMICAL_FIELDS = %w[
- chemical_sample_id cas status vendor order_number amount price person required_date
- ordered_date required_by pictograms h_statements p_statements safety_sheet_link_merck
- safety_sheet_link_thermofischer product_link_merck product_link_thermofischer
- host_building host_room host_cabinet host_group owner borrowed_by current_building
- current_room current_cabinet current_group disposal_info important_notes
+ chemical_sample_id cas status vendor order_number amount price person required_date owner
+ ordered_date expiration_date storage_temperature required_by pictograms h_statements
+ p_statements safety_sheet_link_merck safety_sheet_link_thermofischer product_link_merck
+ product_link_thermofischer host_building host_room host_cabinet host_group important_notes
+ borrowed_by current_building current_room current_cabinet current_group disposal_info
].freeze
MERCK_SDS_LINK = 'c."chemical_data"->0->\'merckProductInfo\'->\'sdsLink\''
ALFA_SDS_LINK = 'c."chemical_data"->0->\'alfaProductInfo\'->\'sdsLink\''
@@ -22,6 +22,8 @@ class ExportChemicals
amount: ['c."chemical_data"->0->\'amount\'', '"amount"', nil],
order_number: ['c."chemical_data"->0->\'order_number\'', '"order_number"', nil],
required_date: ['c."chemical_data"->0->\'required_date\'', '"required_date"', nil],
+ expiration_date: ['c."chemical_data"->0->\'expiration_date\'', '"expiration_date"', nil],
+ storage_temperature: ['c."chemical_data"->0->\'storage_temperature\'', '"storage_temperature"', nil],
required_by: ['c."chemical_data"->0->\'required_by\'', '"required_by"', nil],
safety_sheet_link_merck: [MERCK_SDS_LINK, '"safety_sheet_link_merck"', nil],
safety_sheet_link_thermofischer: [ALFA_SDS_LINK, '"safety_sheet_link_thermofischer"', nil],
@@ -67,8 +69,9 @@ def self.format_chemical_results(result)
end
def self.construct_column_name(column_name, index, columns_index)
- format_chemical_column = ['p statements', 'h statements', 'amount', 'safety sheet link thermofischer',
- 'safety sheet link merck', 'product link thermofischer', 'product link merck'].freeze
+ format_chemical_column = ['p statements', 'h statements', 'amount', 'storage temperature',
+ 'safety sheet link thermofischer', 'safety sheet link merck',
+ 'product link thermofischer', 'product link merck'].freeze
if column_name.is_a?(String) && CHEMICAL_FIELDS.include?(column_name)
column_name = column_name.tr('_', ' ')
construct_column_name_hash(columns_index, column_name, index) if format_chemical_column.include?(column_name)
@@ -86,6 +89,8 @@ def self.construct_column_name_hash(columns_index, column_name, index)
columns_index['h_statements'] = index
when 'amount'
columns_index['amount'] = index
+ when 'storage temperature'
+ columns_index['storage_temperature'] = index
when 'safety sheet link merck', 'safety sheet link thermofischer'
columns_index['safety_sheet_link'].push(index)
when 'product link merck', 'product link thermofischer'
@@ -110,8 +115,8 @@ def self.format_row(row, columns_index, indexes_to_delete)
case index
when columns_index['p_statements'], columns_index['h_statements']
value = format_p_and_h_statements(value)
- when columns_index['amount']
- value = format_chemical_amount(value)
+ when columns_index['amount'], columns_index['storage_temperature']
+ value = format_chemical_fields_with_unit(value)
when columns_index['safety_sheet_link'][0]
value = format_link(value, row, columns_index['safety_sheet_link'][1], indexes_to_delete)
when columns_index['product_link'][0]
@@ -126,9 +131,9 @@ def self.format_p_and_h_statements(value)
keys.join('-')
end
- def self.format_chemical_amount(value)
- amount_value_unit = JSON.parse(value).values
- sorted = amount_value_unit.sort_by { |element| [element.is_a?(Integer) || element.is_a?(Float) ? 0 : 1, element] }
+ def self.format_chemical_fields_with_unit(value)
+ field_values = JSON.parse(value).values
+ sorted = field_values.sort_by { |element| [element.is_a?(Integer) || element.is_a?(Float) ? 0 : 1, element] }
sorted.join
end
diff --git a/lib/import/import_chemicals.rb b/lib/import/import_chemicals.rb
index ed88f15754..ad3c240553 100644
--- a/lib/import/import_chemicals.rb
+++ b/lib/import/import_chemicals.rb
@@ -4,6 +4,8 @@ module Import
class ImportChemicals
SAFETY_PHRASES = %w[pictograms h_statements p_statements].freeze
AMOUNT = %w[amount].freeze
+ AMOUNT = %w[amount].freeze
+ STORAGE_TEMPERATURE = %w[storage_temperature].freeze
SAFETY_SHEET = %w[safety_sheet_link_merck product_link_merck].freeze
KEYS_TO_EXCLUDE = SAFETY_SHEET + %w[cas].freeze
SIGMA_ALDRICH_PATTERN = /(sigmaaldrich|merck)/.freeze
@@ -17,7 +19,7 @@ class ImportChemicals
'cas', 'status', 'vendor', 'order number', 'amount', 'price', 'person', 'required date', 'ordered date',
'required by', 'pictograms', 'h statements', 'p statements', 'safety sheet link', 'product link', 'host building',
'host room', 'host cabinet', 'host group', 'owner', 'borrowed by', 'current building', 'current room',
- 'current cabinet', 'current group', 'disposal info', 'important notes'
+ 'current cabinet', 'current group', 'disposal info', 'important notes', 'expiration date'
].freeze
GHS_VALUES = %w[GHS01 GHS02 GHS03 GHS04 GHS05 GHS06 GHS07 GHS08 GHS09].freeze
AMOUNT_UNITS = %w[g mg μg].freeze
@@ -50,14 +52,25 @@ def self.process_column(chemical, column_header, value)
map_column = CHEMICAL_FIELDS.find { |e| e == column_header.downcase.rstrip }
key = to_snake_case(column_header)
format_value = value.strip
- if map_column.present? && should_process_key(key)
- chemical['chemical_data'][0][key] = format_value
- elsif SAFETY_SHEET.include?(key)
+
+ return process_chemical_data(chemical, key, format_value) if map_column.present? && should_process_key(key)
+
+ process_special_fields(chemical, key, format_value)
+ end
+
+ def self.process_chemical_data(chemical, key, format_value)
+ chemical['chemical_data'][0][key] = format_value
+ end
+
+ def self.process_special_fields(chemical, key, format_value)
+ if SAFETY_SHEET.include?(key)
set_safety_sheet(chemical, key, format_value)
elsif SAFETY_PHRASES.include?(key)
set_safety_phrases(chemical, key, format_value)
elsif AMOUNT.include?(key)
set_amount(chemical, format_value)
+ elsif STORAGE_TEMPERATURE.include?(key)
+ set_storage_temperature(chemical, format_value)
end
end
@@ -168,5 +181,16 @@ def self.set_amount(chemical, value)
chemical['chemical_data'][0]['amount']['value'] = quantity
chemical['chemical_data'][0]['amount']['unit'] = unit
end
+
+ def self.set_storage_temperature(chemical, value)
+ unit_is_celsius = value.gsub(/\d+(\.\d+)?/, '') == '°C'
+ return chemical unless unit_is_celsius
+
+ if chemical['chemical_data'][0]['storage_temperature'].nil?
+ chemical['chemical_data'][0]['storage_temperature'] = {}
+ end
+ chemical['chemical_data'][0]['storage_temperature']['value'] = value.to_f
+ chemical['chemical_data'][0]['storage_temperature']['unit'] = '°C'
+ end
end
end
diff --git a/spec/lib/export/export_chemicals_spec.rb b/spec/lib/export/export_chemicals_spec.rb
index 4d8c102eff..391be7b4bb 100644
--- a/spec/lib/export/export_chemicals_spec.rb
+++ b/spec/lib/export/export_chemicals_spec.rb
@@ -5,12 +5,18 @@
# rubocop: disable Style/OpenStructUse
describe Export::ExportChemicals do
- describe '.format_chemical_amount' do
+ describe '.format_chemical_fields_with_unit' do
it 'formats chemical amount correctly' do
input_value = '{"value": 50, "unit": "mg"}'
- formatted_amount = described_class.format_chemical_amount(input_value)
+ formatted_amount = described_class.format_chemical_fields_with_unit(input_value)
expect(formatted_amount).to eq('50mg')
end
+
+ it 'formats chemical storage temperature correctly' do
+ input_value = '{"value": 30, "unit": "°C"}'
+ formatted_amount = described_class.format_chemical_fields_with_unit(input_value)
+ expect(formatted_amount).to eq('30°C')
+ end
end
describe '.format_columns_name' do