package LIMS::Controller::Roles::Storage;
use POSIX;
use Moose::Role;
use Data::Printer alias => 'p';
has base_location => ( is => 'rw', isa => 'Str' );
# calculates location of rack and tray according to location specification
# re-allocates any empty spaces:
sub get_auto_location {
my ($self, $base_location) = @_;
return $base_location unless # will be free-text box for other services:
$self->cfg('settings')->{'_centre'} eq 'leeds';
# set base location for _get_plate_location() method:
$self->base_location($base_location);
# get list of all locations for $base_location:
my $o = do {
my $q = [ storage_location => { like => $base_location . '%' } ];
$self->model('Base')->get_objects('StorageRack', { query => $q });
};
my @locations = map $_->storage_location, @$o; # p \@locations;
# total no. of plates for this base location:
my $total = scalar @locations; # p $total; exit;
my $storage_location; # to be determined:
# first try to (re)allocate any missing spaces in existing trays:
PLATE: # for each tray in this rack, check we have 4 plates:
for my $i ( 0 .. $total - 1 ) { # for each of $total plates:
next PLATE if $i % 4; # only need to check 1st of 4 identical positions
# get predicted tray location for plate $i:
my $tray_location = $self->_get_plate_location($i); # p $tray_location;
# how many plates do we already have for this tray (4 is full):
my $n = grep $_ eq $tray_location, @locations; # p $n;
# allocate this location if tray not full, either because of missing
# plate in earlier tray, or newest tray and it's not full:
$storage_location = $tray_location and last PLATE if $n < 4;
} # p $storage_location;
# get a new location if not already provided:
$storage_location ||= $self->_get_plate_location($total); # p $storage_location;
return $storage_location;
}
sub _get_plate_location {
my ($self, $n) = @_;
my $rack = floor($n / 36) + 1; # p $rack;
my $tray = floor($n % 36 / 4) + 1; # p $tray;
my $base_location = $self->base_location;
if ( $base_location eq 'Archive' ) { # replace rack number with letter:
my $letter = 'A'; # start at A and auto-increment, a ..z, aa, ab, etc
$letter++ while --$rack; # p $letter;
$rack = $letter;
}
return join '/', $base_location, $rack, $tray;
}
#===============================================================================
sub _rack_dimensions_map { # dimensions A1-D6, A1-H8, etc
return {
24 => { alpha_max => 'D', numbr_max => 6 },
48 => { alpha_max => 'F', numbr_max => 8 },
96 => { alpha_max => 'H', numbr_max => 12 },
};
}
#===============================================================================
sub _dummy_data { # dummy data to spare plate reader ...
my $self = shift;
=begin # to clear request_storage & storage_racks tables:
UPDATE request_storage SET rack_id = NULL;
UPDATE request_storage SET vial_location = NULL;
UPDATE request_storage SET signed_out = NULL;
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE storage_racks;
SET FOREIGN_KEY_CHECKS=1;
=cut
#=begin # uncomment to get 24, 48 or 96 vials from request_storage db table:
{
my $number_of_vials = 96; # 24, 48 or 96
my $rack_dimensions = _rack_dimensions_map(); # dimensions A1-D6, A1-H8, etc
my $q = [ # uncomment one:
# vial_location => undef # not assigned to a rack
vial_location => { ne => undef } # is assigned to a rack
];
my $data = do {
my %args = ( query => $q, limit => $number_of_vials );
$self->model('Base')->get_objects('RequestStorage', \%args );
}; # p $_->as_tree for @$data;
# 24/48/96-well data (24-well = A1-D6, 48-well = A1-F8, 96-well = A1-H12):
my $alpha_max = $rack_dimensions->{$number_of_vials}{alpha_max};
my $numbr_max = sprintf '%02d', $rack_dimensions->{$number_of_vials}{numbr_max};
my @cells = map { $_ . '01' .. $_ . $numbr_max } ( 'A' .. $alpha_max ); # p @cells;
my %h; @h{@cells} = map $_->vialId, @$data; # p %h;
my $plateId = DateTime->now->epoch;
# uncomment to get plateId from storage_racks:
# $plateId = $self->model('Storage')->get_objects('StorageRack',
# { query => [ is_active => 'yes' ], limit => 1 } )->[0]->plateId; # p $plateId;
return { # same format as xtr-96 output:
plate_data => \%h,
well_max => $rack_dimensions->{$number_of_vials},
plateId => $plateId,
};
}
#=cut
=begin to get more data from db:
select vialId, vial_location
from request_storage
where vial_location is not null and signed_out is null
group by vial_location
order by vial_location
select vial_location, vialId
from request_storage rs
join storage_racks sr on rs.rack_id = sr.id
where sr.plateId = 'SA00084423'
order by vial_location
=cut
my $plateId = 'SA00084427'; # SA00098711
my %data = %{ _plate_data() }; # warn Dumper \%data;
my %h = ( plateId => $plateId );
# uncomment to return 48-well data (replace 96 with 48):
# ---------------------------------------------------------------------------
# %data = map { $_ => $data{$_} } grep $_ =~ /[A-F]0[1-8]/, keys %data; # p %data;
# ---------------------------------------------------------------------------
$h{plate_data} = \%data;
{ # get number of wells from $data for tt to draw table of correct size:
my $dimensions_map = _rack_dimensions_map(); # dimensions A1-D6, A1-H8, etc
my $number_of_wells = keys %data; # warn $number_of_wells;
$h{well_max} = $dimensions_map->{$number_of_wells};
} # p %h;
return \%h; # same format as xtr-96 output
}
sub _test_data {
my $data = _plate_data(); # returns hash
return {
plate_data => $data,
well_max => 96,
plateId => 'SA01234567',
}
}
sub _plate_data {
my $i = 1000000001; # 10 digit number
my @cells = map { $_ . '01' .. $_ . '12' } ( 'A' .. 'H' ); # p @cells;
my %h = map { $_ => $i++ } @cells; # p %h;
return \%h;
=begin
return (
'A01' => '1020850304',
'A02' => '1020850312',
'A03' => '1020850320',
'A04' => '1020850328',
'A05' => '1020850336',
'A06' => '1020850344',
'A07' => '1020850352',
'A08' => '1020850360',
'A09' => '1020850368',
'A10' => '1020850321',
'A11' => '1020850384',
'A12' => '1020850392',
'B01' => '1020850305',
'B02' => '1020850313',
'B03' => '1020850348',
'B04' => '1020850383',
'B05' => '1020850391',
'B06' => '1020850345',
'B07' => '1020850353',
'B08' => '1020850361',
'B09' => '1020850369',
'B10' => '1020850367',
'B11' => '1020850385',
'B12' => '1020850393',
'C01' => '1020850306',
'C02' => '1020850314',
'C03' => '1020850322',
'C04' => '1020850359',
'C05' => '1020850338',
'C06' => '1020850346',
'C07' => '1020850354',
'C08' => '1020850362',
'C09' => '1020850370',
'C10' => '1020850378',
'C11' => '1020850386',
'C12' => '1020850394',
'D01' => '1020850319',
'D02' => '1020850315',
'D03' => '1020850323',
'D04' => '1020850331',
'D05' => '1020850355',
'D06' => '1020850347',
'D07' => '1020850397',
'D08' => '1020850398',
'D09' => '1020850371',
'D10' => '1020850379',
'D11' => '1020850387',
'D12' => '1020850395',
'E01' => '1020850308',
'E02' => '1020850316',
'E03' => '1020850324',
'E04' => '1020850332',
'E05' => '1020850340',
'E06' => '1020850311',
'E07' => '1020850356',
'E08' => '1020850364',
'E09' => '1020850372',
'E10' => '1020850380',
'E11' => '1020850388',
'E12' => '1020850382',
'F01' => '1020850390',
'F02' => '1020850317',
'F03' => '1020850325',
'F04' => '1020850358',
'F05' => '1020850333',
'F06' => '1020850357',
'F07' => '1020850374',
'F08' => '1020850365',
'F09' => '1020850373',
'F10' => '1020850381',
'F11' => '1020850406',
'F12' => '1020850414',
'G01' => '1020850422',
'G02' => '1020850405',
'G03' => '1020850413',
'G04' => '1020850421',
'G05' => '1020850429',
'G06' => '1020850437',
'G07' => '1020850445',
'G08' => '1020850453',
'G09' => '1020850461',
'G10' => '1020850469',
'G11' => '1020850477',
'G12' => '1020850485',
'H01' => '1020850493',
'H02' => '1020850404',
'H03' => '1020850412',
'H04' => '1020850420',
'H05' => '1020850428',
'H06' => '1020850436',
'H07' => '1020850444',
'H08' => '1020850452',
'H09' => '1020850460',
'H10' => '1020850468',
'H11' => '1020850476',
'H12' => '1020850484',
)
=cut
}
1;