#!/usr/bin/perl -Ilibs

package API::InventoryCountAdmin;

use strict;
use warnings;
use namespace::autoclean;

use API::Controller;

# website libs
use ECS::Product;
use ECS::Warehouse::Count;
use ECS::Warehouse::Location;

# scanner libs
use lib qw(/var/www/scanner/libs ../scanner/libs);
use Warehouse::Count::Controller;

use Carp;
use Moose;
use Scalar::Util;
use Try::Tiny;

extends 'API::Controller';

has 'manualCountUserID' => (
    'isa'     => "Int",
    'is'      => "ro",
    'default' => 9001,
);

__PACKAGE__->meta->make_immutable;


###############################################################################

sub inventoryCountIndex {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'templates'} = [ "index.html" ];

    # need some summary data for the bottom
    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbhr,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts( {} );

    # load the product data in bulk
    my %products = map {
        $_->productID => $_->product
    } @{ $countProducts };
    ECS::Product::loadMulti({
        'dbh'      => $self->dbhr,
        'products' => [ values %products ],
    });
    ECS::Product::Vendor::loadProductVendorsMulti({
        'dbh'      => $self->dbhr,
        'products' => \%products,
    });

    my %totals = (
        'expectedLines' => 0,
        'expectedUnits' => 0,
        'expectedCost'  => 0,
        'currentLines'  => 0,
        'currentUnits'  => 0,
        'currentCost'   => 0,
        'productCount'  => 0,
    );
    for my $countProduct ( @{ $countProducts } ) {

        $totals{'expectedLines'} ++;

        my @activeCounts;
        for my $count ( $countProduct->counts ) {
            if ( $count->isActive eq 'YES' ) {
                push(@activeCounts, $count);
            }
        }
        if ( @activeCounts > 0 ) {
            $totals{'currentLines'} ++;
        }

        $totals{'currentUnits'} += $countProduct->finalCount || 0;
        $totals{'currentCost'}  += ($countProduct->finalCount || 0)
                                   * ($countProduct->cost || 0);

        my $units = $countProduct->onHand;
        $totals{'expectedUnits'} += $units;
        $totals{'expectedCost'}  += $units * $countProduct->cost;

        $totals{'productCount'} ++;
    }

    $totals{'netDiff'} = $totals{'currentCost'} - $totals{'expectedCost'};
    $totals{'absDiff'} = abs($totals{'netDiff'});
    if( $totals{'expectedLines'} ) {
        $totals{'pctLines'} = (
            $totals{'currentLines'}
            / $totals{'expectedLines'}
        ) * 100;
    }
    if($totals{'expectedUnits'}) {
        $totals{'pctUnits'} = $totals{'currentUnits'}
            / $totals{'expectedUnits'} * 100;
    }
    if($totals{'expectedCost'}) {
        $totals{'pctCost'} = $totals{'currentCost'}
            / $totals{'expectedCost'} * 100;
    }

    $self->data->{'totals'} = \%totals;

    return $self->result;
}

###############################################################################

sub managementView {
    goto &inventoryCountIndex;
}

###############################################################################

sub setRecount {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts({
        'me.inventoryCountProductID' => $self->input->{'inventoryCountProductID'},
    });

    if(not $countProducts or @{ $countProducts } != 1) {
        $self->data->{'data'}->{'message'} = "Product not found in count";
        return $self->result;
    }

    my $countProduct = $countProducts->[0];

    # mark a product to be recounted
    if($self->input->{'recount'}) {
        # reset the final count
        $countProduct->clearAttempts;
        $countProduct->recount("YES");
        $countProduct->finalCount(undef);
        $countProduct->save;

        # ~~mark all of the counts as inactive~~
        # **mark primary counts as inactive**
        for my $productCount (grep $_->overstock eq 'NO', $countProduct->counts) {
            $productCount->isActive("NO");
            $productCount->save;
        }
    }
    # cancel a recount
    else {
        $countProduct->recount("NO");
		
				#                                   for each location
        # find the most recent non-overstock count ^ and mark it as active
				my %locIDs;
        for my $productCount (grep $_->overstock eq 'NO', reverse $countProduct->counts) {
            if(defined $productCount->count) {
                # bring back the final count
                next if $locIDs{ $productCount->locID };
                $locIDs{ $productCount->locID } = 1;

                # $countProduct->finalCount($productCount->count);
                $productCount->isActive("YES");
                $productCount->save;
                # last;
            }
        }
		$countProduct->setFinalCount();
        $countProduct->save;
    }

    $self->data->{'data'}->{'success'} = 1;
    return $self->result;
}

###############################################################################

sub setInventoryReview {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts({
        'me.inventoryCountProductID' => $self->input->{'inventoryCountProductID'},
    });

    if(not $countProducts or @{ $countProducts } != 1) {
        $self->data->{'data'}->{'message'} = "Product not found in count";
        return $self->result;
    }
    my $countProduct = $countProducts->[0];
    my @productCounts = grep( ($_->overstock eq 'NO' && $_->isActive eq 'YES'), $countProduct->counts );

    if($self->input->{'inventoryReview'}) {
        $countProduct->inventoryReview("YES");
        for (@productCounts) {
            $_->review('YES'); 
            $_->save; 
        }
    }
    else {
        $countProduct->inventoryReview("NO");
        for (@productCounts) {
            $_->review('NO'); 
            $_->save; 
        }
    }
    $countProduct->save;

    $self->data->{'data'}->{'success'} = 1;
    return $self->result;
}

###############################################################################

sub setVariance {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts({
        'me.inventoryCountProductID' => $self->input->{'inventoryCountProductID'},
    });

    if(not $countProducts or @{ $countProducts } != 1) {
        $self->data->{'data'}->{'message'} = "Product not found in count";
        return $self->result;
    }
    my $countProduct = $countProducts->[0];
    my @productCounts = grep( ($_->overstock eq 'NO' && $_->isActive eq 'YES'), $countProduct->counts );

    if($self->input->{'variance'}) {
        $countProduct->variance("YES");
    }
    else {
        $countProduct->variance("NO");
    }
    $countProduct->save;

    $self->data->{'data'}->{'success'} = 1;
    return $self->result;
}
###############################################################################

sub setAdjustment {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts({
        'me.inventoryCountProductID' => $self->input->{'inventoryCountProductID'},
    });

    if(not $countProducts or @{ $countProducts } != 1) {
        $self->data->{'data'}->{'message'} = "Product not found in count";
        return $self->result;
    }

    my $countProduct = $countProducts->[0];

    if($self->input->{'adjustment'}) {
        # set an adjustment
        $countProduct->adjustment("Requested");
    }
    else {
        # clear an adjustment
        $countProduct->adjustment(undef);
    }
    $countProduct->save;

    $self->data->{'data'}->{'success'} = 1;
    return $self->result;
}

###############################################################################

sub completeAdjustment {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts = $count->findProducts({
        'me.inventoryCountProductID' => $self->input->{'inventoryCountProductID'},
    });

    if(not $countProducts or @{ $countProducts } != 1) {
        $self->data->{'data'}->{'message'} = "Product not found in count";
        return $self->result;
    }

    my $countProduct = $countProducts->[0];
    $countProduct->adjustment("Completed");
    $countProduct->save;

    $self->data->{'data'}->{'success'} = 1;
    return $self->result;
}

###############################################################################

sub viewEmployeeAisles {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'templates'} = [ "index.html" ];

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my %assignedAisles = ();
    for my $employee ($count->employees) {
        $assignedAisles{ $employee->userID } = $employee->assignedAisle
            if $employee->assignedAisle;
    }

    my $allEmployees = ECS::Warehouse::Count::Employee::getEmployeesById({
        'dbh' => $self->dbh,
    });
    for my $userID (keys %{ $allEmployees }) {
        my $employee = $allEmployees->{$userID};
        if($assignedAisles{$userID}) {
            $employee->{'aisle'} = $assignedAisles{$userID};
        }
    }
    $self->data->{'employees'} = $allEmployees;
    for my $employee ($count->employees) {
        if (my $e = $allEmployees->{ $employee->userID }){
            $e->{inventoryReview} = $employee->inventoryReview;
            $e->{fetchDirection} = $employee->fetchDirection;
            $e->{middleStart} = $employee->middleStart;
        }
    }

    my $countProducts;
    try {
        $countProducts = $count->findProducts({
            'product.locID' => { '<>' => undef },
            'me.finalCount' => undef,
        },
        {
            '+select'  => [ "product.locID" ],
            'join'     => "product",
            'prefetch' => "counts",
        });
        1;
    }
    catch {
        carp $_;
        $self->error("Failed to load products: $_");
        0;
    }
    or return $self->result;

    # figure out which aisles have remaining work
    my %remainingAisles = ();
    for my $countProduct (@{ $countProducts }) {
        $countProduct->locID($countProduct->_row->product->locID);
        #if($countProduct->counts) {
        #    my %locIDs;
        #    for my $productCount (reverse $countProduct->counts) {
        #        next if $productCount->overstock eq 'YES';
        #        next if $locIDs{ $productCount->locID };
        #        $locIDs{ $productCount->locID } = 1;
        #        next if $productCount->isActive eq 'YES';
        #        my ($loc) = grep { $_->{locID} == $productCount->locID } $countProduct->locations;
        #        
        #        if ($loc) {
        #            my $aisle = $loc->{'isle'};
        #            $remainingAisles{$aisle} ++;
        #        }
        #    }
        #}
        if ($countProduct->locations) {
            my %loc = map( ($_->{locID} => $_), $countProduct->locations);
            if ($countProduct->counts) {
                my @countLoc = map( $_->locID, grep( $_->isActive eq 'YES', $countProduct->counts ));
                delete @loc{ @countLoc };
            }
            for my $loc (values %loc) {
                my $aisle = $loc->{'isle'};
                $remainingAisles{$aisle} ++;
            }
        }
    }
    $self->data->{'aisles'} = \%remainingAisles;

    return $self->result;
}

###############################################################################

sub setEmployeeAisles {
    my $self = (shift)->new({'input' => shift || {}});

    my %employeeAisles = ();
    my %inventoryReview = ();
    my %middleStart = ();
    my %fetchDirection;
    for my $key (keys %{ $self->input }) {
        if($key =~ m/^employeeAisle_(\d+)$/) {
            $employeeAisles{$1} = uc $self->input->{$key};
            $employeeAisles{$1} =~ s/[^A-Z]//g;
        } elsif($key =~ m/^inventoryReview_(\d+)$/) {
            $inventoryReview{$1} = 1;
        } elsif($key =~ m/^employeeFetchDirection_(\d+)$/) {
            $fetchDirection{$1} = $self->input->{ $key } || 'ASC';
        } elsif($key =~ m/^employeeMiddleStart_(\d+)$/) {
            $middleStart{$1} = 1;
        }
    }

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    # for the employees already in the count, set the current aisle
    for my $employee ($count->employees) {
        $employee->assignedAisle($employeeAisles{ $employee->userID } || undef);
        $employee->fetchDirection( $fetchDirection{ $employee->userID } || 'ASC' );
        if ($inventoryReview{ $employee->userID }) {
            $employee->inventoryReview( 'YES' );
        } else {
            $employee->inventoryReview( 'NO' );
        }
        if ($middleStart{ $employee->userID }) {
            $employee->middleStart( 'YES' );
        } else {
            $employee->middleStart( 'NO' );
        }
        $employee->save;
        delete $employeeAisles{ $employee->userID };
        delete $inventoryReview{ $employee->userID };
    }

    # for the remaining employees, add them to the audit
    # only if we are assigning them an aisle
    for my $userID (keys %employeeAisles) {
        next unless ($employeeAisles{$userID} || $inventoryReview{$userID});

        my $review = defined $inventoryReview{$userID} ? 'YES' : 'NO';
        my $middle = defined $middleStart{$userID} ? 'YES' : 'NO';
        my $employee = ECS::Warehouse::Count::Employee->new({
            'dbh'              => $self->dbh,
            'inventoryCountID' => $count->inventoryCountID,
            'userID'           => $userID,
            'assignedAisle'    => $employeeAisles{$userID} || '',
            'fetchDirection'   => $fetchDirection{$userID} || 'ASC',
            'isActive'         => "NO",
            'inventoryReview'  => $review,
            'middleStart'      => $middle,
            'warehouseID'      => 1,
        });
        $employee->save;
    }

    $self->data->{'redirect'} = "?action=viewEmployeeAisles";

    return $self->result;
}

###############################################################################

sub viewoverstockLocationsCount{
    my $self = shift->new({'input' => shift || {}});
    $self->data->{'templates'} = [ "index.html" ];

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts;
    try {
        $countProducts = $count->findProducts({
            'location.warehouseID' => 1,
			'location.locFunctionID' => 2,
        },
        {
            'join' => {
                'product' => {
                    'productAltLocation' => "location",
                },
            },
        });
        1;
    }
	
    catch {
        carp $_;
        $self->error("Failed to find products: $_");
        0;
    }
    or return $self->result;

    # load the product data in bulk
    my %products = map { $_->productID => $_->product } @{ $countProducts };
    ECS::Product::loadMulti({
        'dbh'      => $self->dbh,
        'products' => [ values %products ],
    });

    my @packedProducts = ();
    for my $countProduct (@{ $countProducts }) {
        # check for multiple active count objects per productID:locID
        my $multipleActiveCounts;
        # set to update final/overstock counts
        my $set_counts = 0;
        foreach my $count (@{ $countProduct->_counts }) {
            next if ($count->isActive eq 'NO');
            if (!$multipleActiveCounts->{$count->locID}) {
                # save the first active count found
                $multipleActiveCounts->{$count->locID} = $count;
            } else {
                # already have an active count so check if this active count is later, if so use it.
                if ($count->inventoryCountProductCountID > $multipleActiveCounts->{$count->locID}->inventoryCountProductCountID) {
                    $set_counts = 1;
                    # deactivate older count
                    $multipleActiveCounts->{$count->locID}->isActive("NO");
                    $multipleActiveCounts->{$count->locID}->save;
                    # save newer count in hash 
                    $multipleActiveCounts->{$count->locID} = $count;
                }
            }
        }
        if ($set_counts) {
           $countProduct->setFinalCount;
           $countProduct->setOverstockCount;
           $countProduct->save;
        }
        my $packedProduct = $countProduct->pack;
        $packedProduct->{partnumber} = $countProduct->product->partnumber;
		$packedProduct->{description} = $countProduct->product->description;

        push @packedProducts, $packedProduct;
    }
    $self->data->{'products'} = \@packedProducts;

    return $self->result;
}

###############################################################################

sub viewManualCount {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'templates'} = [ "index.html" ];

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts;
    try {
        $countProducts = $count->findProducts({
            'location.warehouseID' => 2,
        },
        {
            'join' => {
                'product' => {
                    'productAltLocation' => "location",
                },
            },
        });
        1;
    }
    catch {
        carp $_;
        $self->error("Failed to find products: $_");
        0;
    }
    or return $self->result;

    # load the product data in bulk
    my %products = map { $_->productID => $_->product } @{ $countProducts };
    return $self->result unless %products;
    ECS::Product::loadMulti({
        'dbh'      => $self->dbh,
        'products' => [ values %products ],
    });
    ECS::Product::Vendor::loadProductVendorsMulti({
        'dbh'      => $self->dbh,
        'products' => \%products,
    });

    my @packedProducts = ();
    for my $countProduct (@{ $countProducts }) {
        my $packedProduct = $countProduct->pack;

        $packedProduct->{$_} = $countProduct->product->$_ for qw(
            partnumber
            description
        );

        push @packedProducts, $packedProduct;
    }
    $self->data->{'products'} = \@packedProducts;

    return $self->result;
}

###############################################################################

sub setManualCount { 
    my $self = shift->new({'input' => shift || {}});

    # look through the form data and find the counts
    my %newCounts = ();
    my %expectedCounts = ();
    my $overstock = ($self->input->{'caller'} eq "OverstockCount") ? "YES" : "NO"; 
    for my $field (keys %{ $self->input }) {
        my $count = $self->input->{$field};
        undef $count if $count !~ m/^\d+$/;

        if($field =~ m/^count_(\d+)_(\d+)$/) {
            my $productID = $1;
            my $locID     = $2;

            $newCounts{ $productID }->{ $locID } = $count;
        }
        elsif($field =~ m/^expected_(\d+)_(\d+)$/) {
            my $productID = $1;
            my $locID     = $2;

            $expectedCounts{ $productID }->{ $locID } = $count;
        }
    }
    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    my $countProducts;
    try {
        $countProducts = $count->findProducts({
            'productID' => [ keys %newCounts ],
        });
        1;
    }
    catch {
        carp $_;
        $self->error("Failed to find products: $_");
        0;
    }
    or return $self->result;
    # apply this data to the products
    for my $countProduct (@{ $countProducts }) { 
        my $productCounts = $newCounts{ $countProduct->productID };
        my $productExpected = $expectedCounts{ $countProduct->productID };
        
        for my $count ($countProduct->counts) {
            # skip inactive or unrelated counts
            if($count->isActive eq "NO"
                or not defined $productCounts->{ $count->locID }
                ) {
                next;
            }

            my $newCount = delete $productCounts->{ $count->locID };

            # if they match, nothing to do
            if(defined $newCount
                and $count->count == $newCount
                ) {
                next 
            }

            # invalidate the previous count
            $count->isActive("NO");
            $count->save;

            # don't add a new count if the value was cleared out
            next unless defined $newCount;

            $countProduct->addCount({
                'userID'    => 0,
                'locID'     => $count->locID,
                'cost'      => $countProduct->cost,
                'onShelf'   => $productExpected->{ $count->locID },
                'count'     => $newCount,
                'overstock' => $overstock,
            });
        }

        # any remaining counts are added as entirely new entries
        for my $locID (keys %{ $productCounts }) {
            my $count = $productCounts->{ $locID };
            next unless defined $count;

            $countProduct->addCount({
                'userID'    => 0,
                'locID'     => $locID,
                'cost'      => $countProduct->cost,
                'onShelf'   => $productExpected->{ $locID },
                'count'     => $count,
                'overstock' => $overstock,
            });
        }

        # reload from the DB
		$countProduct->_resultset->clear_cache();

        $countProduct->setFinalCount;
        $countProduct->save;
    }

    ($self->input->{'caller'} eq "OverstockCount") 
        ? ($self->data->{'redirect'} = "?action=viewoverstockLocationsCount") 
        : ($self->data->{'redirect'} = "?action=viewManualCount");
    
    return $self->result;
}

###############################################################################

sub getCountData {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my @countProducts = $self->_doSearch;
    return $self->result if $self->data->{'data'}->{'error'};

    my @packedProducts = ();
    for my $countProduct (@countProducts) {
        my $packedProduct = $countProduct->pack;

        $packedProduct->{$_} = $countProduct->product->$_ for qw(
            partnumber
            description
        );

        push @packedProducts, $packedProduct;
    }

    $self->data->{'data'}->{'products'} = \@packedProducts;
    $self->data->{'data'}->{'success'} = 1;

    return $self->result;
}

###############################################################################

# non-API method for searching products
sub _doSearch {
    my $self = shift;

    my $search;
    try {
        my $json = JSON->new;
        $search = $json->decode($self->input->{'search'});
        1;
    }
    catch {
        carp $_;
        $self->data->{'data'}->{'error'} = "Invalid search parameters: $_";
        0;
    }
    or return;

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });

    $search->[ 1 ]->{'getStats'} = 1;

    my @countProducts;
    try {
        $search->[1]->{'pager'} = 1 if $search->[1]->{'page'};
        @countProducts = @{ $count->findProducts(@{ $search }) };
        my $pager = $search->[1]->{'pager'};
        $self->data->{'data'}->{'count'} = $pager->total_entries if $pager;
        $self->data->{'data'}->{'stats'} = $search->[ 1 ]->{'stats'};
        1;
    }
    catch {
        carp $_;
        $self->data->{'data'}->{'error'} = "Failed to search: $_";
        0;
    }
    or return;

    return @countProducts;
}

###############################################################################

sub viewEmployeeLocations {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'templates'} = [ "employeeLocations.html" ];

    my $count = ECS::Warehouse::Count->new({
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    });
    $self->data->{'templates'} = [ "employeeLocations.html" ];
		$self->data->{noHeader} = 1;
		
		if (my $userID = $self->input->{userID}) {{
			my $employeeLocations = [];
			my $locations = { isles => [], lines => [], rows => [], positions => [] };
			my ($employee) = @{ $count->findEmployees({ userID => $userID }) };
			my $warehouseID;
			unless ($employee) {
        # add a new employee on the count
        $employee = ECS::Warehouse::Count::Employee->new({
            'dbh'              => $self->dbh,
            'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
            'userID'           => $userID,
            'warehouseID'      => ($warehouseID||1),
        });
				$employee->save;
			}
			last unless $employee;
			my $scanner_employee = ECS::Warehouse::Count::Employee::getEmployeesById({
						 dbh => $self->dbh,
					})->{ $employee->userID };
			last unless $scanner_employee;
			$self->data->{ employee } = $scanner_employee;
			for my $loc ( $employee->_locations ) {
				my %employeeLocation;
				$employeeLocation{ $_ } = $loc->$_ 
					for qw/fromIsle toIsle fromLine toLine fromRow toRow fromPosition toPosition inventoryCountEmployeeLocationID/;
				if ( $self->input->{delete} && $self->input->{delete} == $employeeLocation{ inventoryCountEmployeeLocationID }) {
					$loc->delete;
				} else {
					push @$employeeLocations, \%employeeLocation;
				}
			}
			if ($self->input->{new}) {{
				my %employeeLocation;
				next unless $self->input->{fromIsle};
				my $newLoc = $employee->newLocation;
				for (	qw/fromIsle toIsle fromLine toLine fromRow toRow fromPosition toPosition/ ) {
					$newLoc->$_( $self->input->{ $_ } )
				}
				$newLoc->save;
				$employeeLocation{ $_ } = $newLoc->$_ 
					for qw/fromIsle toIsle fromLine toLine fromRow toRow fromPosition toPosition inventoryCountEmployeeLocationID/;
				push @$employeeLocations, \%employeeLocation;
			}}
			$self->data->{employeeLocations} = $employeeLocations;
			my $warehouseLocs = ECS::Warehouse::Location::getAllLocations({
            'dbh'             => $self->dbh,
            'warehouseID'   => $employee->warehouseID,
      });
			my (%isles, %lines, %rows, %positions);
			my @parts = \( %isles, %lines, %rows, %positions );
			for my $whloc (values %$warehouseLocs) {
				# this split is useful, given PD14AA25 returns ('PD',14','AA', '25', '')
				# my @locParts = split /([0-9]+)/ => $whloc->{locStr}, 3;
				my @locParts = @{ $whloc }{ qw/isle line row position/ };
				for (0..$#locParts) {
					last unless $locParts[ $_ ];
					$locParts[ $_ ] = uc $locParts[ $_ ];
					$parts[ $_ ]->{ $locParts[ $_ ] } = 1;
				}
			}
			my @locationsParts = @{ $locations }{ qw/isles lines rows positions/ };
			@{ $locationsParts[ $_ ] } = $_ % 2 ? sort { $a <=> $b } keys %{ $parts[ $_ ] } : sort keys %{ $parts[ $_ ] }
				for (0..$#parts);
			$self->data->{locations} = $locations;
			
			
			
		}} 

		
		
    return $self->result;
}

###############################################################################

sub viewManualEntry {
    my $self = (shift)->new({'input' => shift || {}});
    $self->data->{'templates'} = [ "index.html" ];
    return $self->result;
}

###############################################################################

sub setManualEntry {
    my $self = (shift)->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";

    my $location  = $self->input->{ 'location' };
    my $productID = $self->input->{ 'productID' };
    my $qty       = $self->input->{ 'qty' };

    my %location = ();
    $location =~ m/^([a-z]+)(\d*)([a-z]*)(\d*)$/i;
    $location{ 'isle'     } = $1 || "";
    $location{ 'line'     } = $2 || "";
    $location{ 'row'      } = $3 || "";
    $location{ 'position' } = $4 || "";
    $location{ 'active'   } = 'Y';

    my $locations = ECS::Warehouse::Location::search( {
        'dbh'   => $self->dbh,
        'search' => [
            \%location,
        ],
    } );
    my $locID;
    if ( $locations
        and @{ $locations }
        ) {
        $locID = $locations->[ 0 ]->locID;
    }
    else {
        $self->data->{ 'data' }->{ 'error' } = "Invalid location";
        return $self->result;
    }

    my $count = ECS::Warehouse::Count->new( {
        'dbh'              => $self->dbh,
        'inventoryCountID' => $Warehouse::Count::Controller::COUNT_ID,
    } );

    my $countProduct;
    try {
        my $countProducts = $count->findProducts( {
            'productID' => [ $productID ],
        } );
        ( $countProduct ) = @{ $countProducts };
        die "Invalid product" unless $countProduct;
        1;
    }
    catch {
        carp $_;
        $self->data->{ 'data' }->{ 'error' } = "Invalid ES#";
        0;
    }
    or return $self->result;

    my ( $locObj ) = grep { $_->{ 'locID' } == $locID } $countProduct->locations;
    my $onShelf = $countProduct->product->onShelf;
    my $overstock = "NO";
    if ( $locObj->{ 'locOS' } ) {
        $onShelf = $locObj->{ 'locQty' };
        $overstock = "YES";
    }
    elsif ( $locObj->{ 'locPL' } ) {
        $onShelf = $locObj->{ 'locSub' };
    }

    for my $count ( $countProduct->counts ) {
        # skip inactive or unrelated counts
        if ( $count->isActive eq "NO"
            or $locID != $count->locID
            ) {
            next;
        }

        # invalidate the previous count
        $count->isActive("NO");
        $count->save;
    }

    $countProduct->addCount( {
        'userID'    => $self->manualCountUserID,
        'locID'     => $locID,
        'cost'      => $countProduct->cost,
        'count'     => $qty,
        'onShelf'   => $onShelf,
        'overstock' => $overstock,
    } );
    # reload from the DB
    $countProduct->_resultset->clear_cache();

    $countProduct->setFinalCount;
    $countProduct->save;

    $self->data->{'data'}->{'success'} = 1;

    return $self->result;
}

###############################################################################

1;

