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;