#!/usr/bin/perl -Ilibs
package API::CycleCountAdmin;
use strict;
use warnings;
use warnings::register;

use lib $API::Config::Config->{'Website_libs'} || 'libs';

use JSON qw/encode_json decode_json/;
use API::Controller ();
use ECS::Warehouse::CycleCount;
use ECS::Warehouse::CycleCount::User;
use ECS::Warehouse::CycleCount::VarianceDefaults;
use ECS::Warehouse::CycleCount::ABCD;
use ECS::Warehouse::CycleCount::AutomaticThreshold;
use ECS::Warehouse::CycleCount::Discrepancy;
use ECS::DB::Class;

use Moo;
use Try::Tiny;
use Types::Standard qw/-types slurpy/;
use String::Random;

extends 'API::Controller';

my $Config;
BEGIN{
	use API::Config;
	$Config = $API::Config::Config;
}
use lib $Config->{'cycleCountLibs'};
use ECS::CycleCount::User::UserLocation;
use ECS::CycleCount::User::UserLocation::Location;


=pod

=head1 NAME

API::CycleCountAdmin - API for Cycle Count Administration

=head1 SYNOPSIS

	my $api = API::CycleCountAdmin->new();
	$api->cycleCountUsers();

=head1 DESCRIPTION

Provides the back-end functions for the Cycle Count Admin Portal Application

=head1 EXTENDS

=over

=item * L<API::Controller>

=back

=cut

# map frontend change records to ecs-warehouse-cyclecount-methods
my %cyclecount_user_changes = (
	add => 'addUser',
	delete => 'deleteUser',
	update => 'updateUser',
);

my %cyclecount_varianceDefaults_changes = (
	add => 'addVarianceDefault',
	delete => 'deleteVarianceDefault',
	update => 'updateVarianceDefault',
);

my %cyclecount_abcd_changes = (
	update => 'updateABCD',
);
my %cyclecount_usersLocations_changes = (
	list => 'usersLocations',
);

my %cyclecount_manageUserLocations_changes = (
	add => 'addUserLocation',
);

my %cyclecount_getLocation_changes = (
	get => 'getLocationData',
);

my %cyclecount_autumaticThreshold_changes = (
	add => 'addAutomaticThreshold',
	delete => 'deleteAutomaticThreshold',
	update => 'updateAutomaticThreshold',
);

my %cyclecount_discrepancy_changes = (
    list => 'listDiscrepancy',
);

my %cyclecount_discrepancy_actions = (
    NOLOCATION => 'moveThenInventoryAdjustment',
    INVALIDPRODUCT => 'deActivateDiscrepancy',
    INCORRECTLOCATION => 'deActivateDiscrepancy',
    MISSINGPRODUCT => 'deActivateDiscrepancy',
    INCORRECTINVENTORY => 'inventoryAdjustment',
    updateCountedOverrideAndNote => 'updateCountedOverrideAndNote',
);

my $UserChange = Map[ 
	Enum[
		keys %cyclecount_user_changes], 
		Dict[ 
			id => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::User"}{fields}||[] }],
				Tuple[Str|Int, Str|Int],
			]
		]
	];

my $VarianceDefaultsChange = Map[ 
	Enum[
		keys %cyclecount_varianceDefaults_changes], 
		Dict[ 
			cycleCountVarianceDefaultsID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::VarianceDefaults"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];

my $ABCDChange = Map[ 
	Enum[
		keys %cyclecount_abcd_changes], 
		Dict[ 
			cycleCountABCDID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::ABCD"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];

my $UsersLocations = Map[ 
	Enum[
		keys %cyclecount_usersLocations_changes], 
		Dict[ 
			cycleCountUserLocationID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::User::UserLocation"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];
my $ThresholdChange = Map[
	Enum[
		keys %cyclecount_autumaticThreshold_changes],
		Dict[
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::AutomaticThreshold"}{fields}||[] }[1]],
				Int
			]
		]
	];

my $DiscrepancyChange = Map[ 
	Enum[
		keys %cyclecount_discrepancy_changes], 
		Dict[ 
			cycleCountDiscrepancyID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::Warehouse::CycleCount::Discrepancy"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];

my $ManageUserLocations = Map[ 
	Enum[
		keys %cyclecount_manageUserLocations_changes], 
		Dict[ 
			cycleCountUserLocationID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::CycleCount::User::UserLocation"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];

my $getLocation = Map[ 
	Enum[
		keys %cyclecount_getLocation_changes], 
		Dict[ 
			cycleCountUserLocationID => Int, 
			slurpy Map[
				Enum[@{ $ECS::DB::Class::models->{"ECS::CycleCount::User::UserLocation"}{fields}||[] }],
				Tuple[Undef|Str|Int, Undef|Str|Int],
			]
		]
	];

has _cyclecount => (
	is	=> 'ro',
	isa	=> (Undef|HasMethods[qw/scannerUsers users/, values %cyclecount_user_changes]),
	lazy => 1,
	builder => '_build_cyclecount',
);

has _cyclecountVarianceDefaults => (
	is	=> 'ro',
	isa	=> (Undef|HasMethods[qw/varianceDefaults warehouseNames locFunctionNames locTypes locSizes/, values %cyclecount_varianceDefaults_changes]),
	lazy => 1,
	builder => '_build_cyclecountVarianceDefaults',
);

has _cyclecountABCD => (
	is	=> 'ro',
	isa	=> (Undef|HasMethods[qw/abcd/, values %cyclecount_abcd_changes]),
	lazy => 1,
	builder => '_build_cyclecountABCD',
);

has _cyclecountDiscrepancy => (
	is	=> 'ro',
	isa	=> (Undef|HasMethods[qw/listDiscrepancy deActivateDiscrepancy inventoryAdjustment moveThenInventoryAdjustment/, values %cyclecount_discrepancy_changes]),
	lazy => 1,
	builder => '_build_cyclecountDiscrepancy',
);

has _cyclecountUsersLocations => (
	is	=> 'ro',
	isa	=> (Undef|HasMethods[qw/usersLocations/, values %cyclecount_usersLocations_changes]),
	lazy => 1,
	builder => '_build_cyclecount',
);

sub _build_cyclecount {
	my $self = shift;
	ECS::Warehouse::CycleCount->new({
		dbh => $self->dbh,
		dbhr => $self->dbhr,
		employeeID => $self->input->{employeeID}
	});
}

sub _build_cyclecountVarianceDefaults {
	my $self = shift;
	ECS::Warehouse::CycleCount->new({
		dbh => $self->dbh,
		dbhr => $self->dbh,
		employeeID => $self->input->{employeeID}
	});
}

sub _build_cyclecountABCD {
	my $self = shift;
	ECS::Warehouse::CycleCount->new({
		dbh => $self->dbh,
		employeeID => $self->input->{employeeID}
	});
}

sub _build_cyclecountDiscrepancy {
	my $self = shift;
    
	ECS::Warehouse::CycleCount->new({
		dbh => $self->dbh,
		employeeID => $self->input->{employeeID},
	});
}

sub _cyclecount_users {
	my $self = shift;
	my @cyclecount_users;
	push @cyclecount_users, +{ %$_ } for @{ $self->_cyclecount->users };
	delete $_->{DBH} for @cyclecount_users;
	delete $_->{DBHr} for @cyclecount_users;
	return \@cyclecount_users;
}

sub _scanner_users {
	my $self = shift;
	my @scanner_users;
	push @scanner_users, +{ %$_ } for @{ $self->_cyclecount->scannerUsers };
	delete $_->{DBH} for @scanner_users;
	delete $_->{DBHr} for @scanner_users;
	return \@scanner_users;
}

sub _warehouses {
	my $self = shift;
	my @warehouses;
	push @warehouses, +{ %$_ } for @{ $self->_cyclecount->warehouses };
	delete $_->{DBH} for @warehouses;
	delete $_->{DBHr} for @warehouses;
	return \@warehouses;
}

sub _cyclecount_varianceDefaults {
	my $self = shift;
	my @cyclecount_varianceDefaults;
	push @cyclecount_varianceDefaults, +{ %$_ } for @{ $self->_cyclecountVarianceDefaults->varianceDefaults };
	delete $_->{DBH} for @cyclecount_varianceDefaults;
	delete $_->{DBHr} for @cyclecount_varianceDefaults;
	return \@cyclecount_varianceDefaults;
}

sub _warehouse_names {
	my $self = shift;
	my @warehouse_names;
	push @warehouse_names, +{ %$_ } for @{ $self->_cyclecountVarianceDefaults->warehouseNames };
	delete $_->{DBH} for @warehouse_names;
	delete $_->{DBHr} for @warehouse_names;
	return \@warehouse_names;
}

sub _locFunction_names {
	my $self = shift;
	my @locFunction_names;
	push @locFunction_names, +{ %$_ } for @{ $self->_cyclecountVarianceDefaults->locFunctionNames };
	delete $_->{DBH} for @locFunction_names;
	delete $_->{DBHr} for @locFunction_names;
	return \@locFunction_names;
}

sub _locTypes {
	my $self = shift;
	my @locTypes;

    push @locTypes, undef;
    foreach my $locType (keys (%{$self->_cyclecountVarianceDefaults->locTypes})) {
        push @locTypes, $locType;
    }
	return \@locTypes;
}

sub _locSizes {
	my $self = shift;
	my @locSizes;

    push @locSizes, undef;
    foreach my $locSize (sort keys (%{$self->_cyclecountVarianceDefaults->locSizes})) {
        push @locSizes, $locSize;
    }
	return \@locSizes;
}

sub _cyclecount_abcd {
	my $self = shift;
	my @cyclecount_abcd;
	push @cyclecount_abcd, +{ %$_ } for @{ $self->_cyclecountABCD->abcd };
	delete $_->{DBH} for @cyclecount_abcd;
	delete $_->{DBHr} for @cyclecount_abcd;
	return \@cyclecount_abcd;
}

sub _cyclecount_discrepancy_list {
	my $self = shift;
	my @cyclecount_discrepancy;
	push @cyclecount_discrepancy, +{ %$_ } for @{ $self->_cyclecountDiscrepancy->listDiscrepancy };
	delete $_->{DBH} for @cyclecount_discrepancy;
	delete $_->{DBHr} for @cyclecount_discrepancy;
	return \@cyclecount_discrepancy;
}

sub _cyclecount_usersLocations {
	my $self = shift;
	my @cyclecount_usersLocations;
	push @cyclecount_usersLocations, +{ %$_ } for @{ $self->_cyclecountUsersLocations->usersLocations };
	delete $_->{DBH} for @cyclecount_usersLocations;
	delete $_->{DBHr} for @cyclecount_usersLocations;
	return \@cyclecount_usersLocations;
}

=pod

=head1 API METHODS

=head2 index

Returns the template and data needed for the Cycle Count Admin Index page

=cut

sub index {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

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

=pod

=head2 cycleCountUsers

Returns the template and data needed for the Cycle Count Admin Users page

=cut

sub cycleCountUsers {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

	my $result = try {
		my $cyclecount_users = $self->_cyclecount->users;
		$self->data->{scanner_users} = $self->_scanner_users;
		$self->data->{warehouses} = $self->_warehouses;
		$self->data->{cyclecount_users} = $self->_cyclecount_users;
		# assign name from scanner_users
		for my $cyclecount_user ( @{ $self->data->{cyclecount_users} } ) {
			next if $cyclecount_user->{name};
			my ($scanner_user) = List::Util::first {
				$cyclecount_user->{scannerUserID} == $_->{userID}
			} @{ $self->_scanner_users };
			$cyclecount_user->{name} = $scanner_user->{name} if $scanner_user;
		}
		$self->data->{templates} = ['users.html'];
		$self->data->{partial} = 1;
		$self->result;
	} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;
}

=pod

=head2 setCycleCountUsers

I<Write Method>

Updates the Cycle Count User Data with the changes passed in as JSON

=cut

sub setCycleCountUsers {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";
	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };


	VALIDATE: { 
		unless ($self->input->{changes}) {
			$error = 'No changes';
			last;
		}
		$changes = try {
			decode_json( $self->input->{changes} )
		} catch {
			undef;
		};
		unless (defined $changes) {
			$error = 'Invalid changes';
			last;
		}
		unless ((ArrayRef)->check( $changes )) {
			$error = 'Invalid changes';
			last;
		}
		unless ( (ArrayRef[ $UserChange ])->check( $changes) ) {
			$error = 'Invalid changes';
			last;
		} 
		unless ( scalar @$changes ) {
			$error = 'No changes';
			last;
		}
		CHANGES: for my $change (@$changes) {
			my ($type, $value) = %$change;
			my $method = $cyclecount_user_changes{ $type };
			my $result = try {
				$self->_cyclecount->$method( $value );
			} catch {
				# uncoverable subroutine
				$error = $_;  # uncoverable statement
				0;  # uncoverable statement
			};
			# uncoverable branch true
			unless ($result) {
				last CHANGES;  # uncoverable statement
			} else {
				next;	
			}
		}
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
}

=pod

=head2 cycleCountVarianceDefaults

Returns the template and data needed for the Cycle Count Admin Variance Defaults page

=cut
sub cycleCountVarianceDefaults {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

	my $result = try {
		my $cyclecount_varianceDefaults = $self->_cyclecountVarianceDefaults->varianceDefaults;

		$self->data->{templates} = ['varianceDefaults.html'];
        $self->data->{partial} = 1;
		$self->data->{cyclecount_varianceDefaults} = $self->_cyclecount_varianceDefaults;
   		$self->data->{warehouse_names} = $self->_warehouse_names;
   		$self->data->{locFunction_names} = $self->_locFunction_names;
   		$self->data->{locTypes} = $self->_locTypes;
   		$self->data->{locSizes} = $self->_locSizes;
		$self->result;

	} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;
    
}
=pod

=head2 setCycleCountVarianceDefaults

I<Write Method>

Updates the Cycle Count Variance Defaults Data with the changes passed in as JSON

=cut

sub setCycleCountVarianceDefaults {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };


	VALIDATE: { 
		unless ($self->input->{changes}) {
			$error = 'No changes';
			last;
		}
		$changes = try {
			decode_json( $self->input->{changes} )
		} catch {
			undef;
		};
		my ($mainType) = keys( %{@$changes[0]} );

		unless (defined $changes) {
			$error = 'Invalid changes';
			last;
		}
		unless ((ArrayRef)->check( $changes )) {
			$error = 'Invalid changes';
			last;
		}
		unless ( scalar @$changes ) {
			$error = 'No changes';
			last;
		}
        CHANGES: for my $change (@$changes) {
            
            my ($type, $value) = %$change;
            
            my $method = $cyclecount_varianceDefaults_changes{ $type };
            my $result = try {
                $self->_cyclecount->$method( $value );
            } catch {
                # uncoverable subroutine
                $error = $_;  # uncoverable statement
                0;  # uncoverable statement
            };
            # uncoverable branch true
            unless ($result) {
                last CHANGES;  # uncoverable statement
            } else {
                next;	
            }
        }
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
   
}

=pod

=head2 cycleCountABCD

Returns the template and data needed for the Cycle Count Admin ABCD page

=cut
sub cycleCountABCD {

	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

	my $result = try {
		my $cyclecount_abcd = $self->_cyclecountABCD->abcd;

		$self->data->{templates} = ['abcd.html'];
        $self->data->{partial} = 1;
		$self->data->{cyclecount_abcd} = $self->_cyclecount_abcd;
		$self->result;
		} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;
}
=head2 automaticThreshold

Returns the template and data needed for the Cycle Count Automatic Approval Threshold page

=cut

sub automaticThreshold {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

	my $result = try {
		$self->data->{dollarAmount} = $self->_cyclecount->automaticThreshold->dollarAmount;
		$self->data->{templates} = ['automaticThreshold.html'];
		$self->data->{partial} = 1;
		$self->result;

	} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;    
}
=pod

=head2 setCycleCountABCD

I<Write Method>

Updates the Cycle Count ABCD Data with the changes passed in as JSON

=cut

sub setCycleCountABCD {
my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };


	VALIDATE: { 
		unless ($self->input->{changes}) {
			$error = 'No changes';
			last;
		}
		$changes = try {
			decode_json( $self->input->{changes} )
		} catch {
			undef;
		};
		my ($mainType) = keys( %{@$changes[0]} );

		unless (defined $changes) {
			$error = 'Invalid changes';
			last;
		}
		unless ((ArrayRef)->check( $changes )) {
			$error = 'Invalid changes';
			last;
		}
		unless ( scalar @$changes ) {
			$error = 'No changes';
			last;
		}
        CHANGES: for my $change (@$changes) {
            
            my ($type, $value) = %$change;
            my $method = $cyclecount_abcd_changes{ $type };
            my $result = try {
                $self->_cyclecount->$method( $value );
            } catch {
                # uncoverable subroutine
                $error = $_;  # uncoverable statement
                0;  # uncoverable statement
            };
            # uncoverable branch true
            unless ($result) {
                last CHANGES;  # uncoverable statement
            } else {
                next;	
            }
        }
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
   
}

sub setAutomaticThreshold {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };

	VALIDATE: { 
		unless ($self->input->{changes}) {
			$error = 'No changes';
			last;
		}
		$changes = try {
			decode_json( $self->input->{changes} )
		} catch {
			undef;
		};
		unless (defined $changes) {
			$error = 'Invalid changes';
			last;
		}
		unless ((ArrayRef)->check( $changes )) {
			$error = 'Invalid changes';
			last;
		}
		unless ( scalar @$changes ) {
			$error = 'No changes';
			last;
		}
		CHANGES: for my $change (@$changes) {
			my ($type, $value) = %$change;
			my $method = $cyclecount_autumaticThreshold_changes{ $type };
			my $result = try {
				$self->_cyclecount->$method( $value );
			} catch {
				# uncoverable subroutine
				$error = $_;  # uncoverable statement
				0;  # uncoverable statement
			};
			# uncoverable branch true
			unless ($result) {
				last CHANGES;  # uncoverable statement
			} else {
				next;	
			}
		}
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
   
}
=pod

=head2 cycleCountManageUserLocations

Returns the template and data needed for the Cycle Count Admin User Locations page

=cut
sub cycleCountManageUserLocations {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
    my @locationsAndStatus;
	my $result = try {
        foreach (@{$self->_cyclecount->usersLocations}) {
            my $listItem->{status} = $_->status; 
            $listItem->{scannerUserID} = $_->scannerUserID;
           	my $location = ECS::CycleCount::User::UserLocation::Location->loadMulti({ 
                DBH => $self->dbhr,
                _return => 'HASHREF',
                locID => $_->locID,
                active => 'Y',
            });
            if ($location) {
                $listItem->{name} = $location->{$_->locID}->prettyLocation; 
                push @locationsAndStatus, $listItem;
            }
        }
        my @sorted =  sort { $a->{name} cmp $b->{name} } @locationsAndStatus;

		$self->data->{cyclecount_users} = $self->_cyclecount_users;
   		$self->data->{usersLocations} = \@sorted;
		$self->data->{templates} = ['manageUserLocations.html'];
        $self->data->{partial} = 1;
		$self->result;

	} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;
    
}
=pod

=head2 getLocation

I<Read Method>

Returns location data 

=cut

sub getLocation {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };

	VALIDATE: { 
		unless ($self->input->{location}) {
			$error = 'Location Required';
			last;
		}
        my $value = $self->input->{location};
        my $method = 'getLocationData';
        $result = try {
            $self->_cyclecount->$method( $value );
        } catch {
            # uncoverable subroutine
            $error = $_;  # uncoverable statement
            0;  # uncoverable statement
        };
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => $result->{message},
					success => 1,
                    typeAndSize => $result->{typeAndSize},
                    locID => $result->{locID},
                    status => $result->{status},
                    scannerUserID => $result->{scannerUserID},
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
}
=pod

=head2 assignUserLocation

I<Write Method>

Updates the Cycle Count User Location Table

=cut

sub assignUserLocation {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };

	VALIDATE: { 
		unless ($self->input->{employeeID}) {
			$error = 'Employee ID Required';
			last;
		}
		unless ($self->input->{locID}) {
			$error = 'LocID Required';
			last;
		}
		unless ($self->input->{scannerUserID}) {
			$error = 'Scanner User ID Required';
			last;
		}
           
        my $value = ({
                'scannerUserID' => $self->input->{scannerUserID},
                'locID'         => $self->input->{locID},
                'status'         => $self->input->{status},
        });
        my $method = 'addUserLocation';
        my $result = try {
            $self->_cyclecount->$method( $value );
        } catch {
            # uncoverable subroutine
            $error = $_;  # uncoverable statement
            0;  # uncoverable statement
        };
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
}

=pod

=head2 assignUserLocationIsle

I<Write Method>

Updates the Cycle Count User Location Table
Adds all active locations in an Isle to a cycle count user as long as they
are assigned the same warehouse.

=cut

sub assignUserLocationIsle {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
	$self->data->{'dataType'} = "json";

	my $error;
	my $changes; 
    my $result = {
        'success'   => 1,
        'error'     => undef,
        'message'   => undef,
		'data'		=> {},
        'update_DB' => $Config->{update_DB}
    };

	VALIDATE: { 
		unless ($self->input->{employeeID}) {
			$error = 'Employee ID Required';
			last;
		}
		unless ($self->input->{isle}) {
			$error = 'Isle Required';
			last;
		}
		unless ($self->input->{scannerUserName}) {
			$error = 'Scanner User Required';
			last;
		}
           
        my $value = ({
                'scannerUserName' => $self->input->{scannerUserName},
                'isle'         => $self->input->{isle},
                'status'         => $self->input->{status},
        });
        my $method = 'addUserLocationIsle';
        my $result = try {
            $self->_cyclecount->$method( $value );
        } catch {
            # uncoverable subroutine
            $error = $_;  # uncoverable statement
            0;  # uncoverable statement
        };
	}

	if ($error) {
		$result = {
			data => {
				data => {
					message => $error,
					success => 0,
				},
				dataType => 'json',
			},
			error => $error,
			success => 0,
			update_DB => $Config->{update_DB},
		};

	} else {
		$result = {
			data => {
				data => {
					message => "",
					success => 1,
				},
				dataType => 'json',
			},
			error => "",
			success => 1,
			update_DB => $Config->{update_DB},
		};
	}
	return $result;
}
=pod

=head2 cycleCountDiscrepancy

Returns the template and data needed for the Cycle Count Admin Manage Discrepancy page

=cut
sub cycleCountDiscrepancy {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});

	my $result = try {
		my $cyclecount_discrepancy = $self->_cyclecount_discrepancy_list;
		$self->data->{templates} = ['discrepancy.html'];
        $self->data->{partial} = 1;
		$self->data->{cyclecount_discrepancy} = $cyclecount_discrepancy;
        $self->data->{automaticThreshold} = $self->_cyclecount->automaticThreshold->dollarAmount;
		$self->result;

	} catch {
		{
			data => {
				data => {
					message => $_,
					success => 0,
				},
				dataType => 'json',
			},
			error => $_,
			success => 0,
			update_DB => $Config->{update_DB},
		};
	};
	return $result;
    
}

=pod

=head2 approveCycleCountDiscrepancy

=cut
sub approveCycleCountDiscrepancy {
	my ($class, $params) = @_;
	$params ||= {};
	my $self = ($class)->new({'input' => $params});
    my $error;
	my $changes = try {
			decode_json( $self->input->{changes} )
		} catch {
			undef;
		};
    # default response if no changes.
    my $result = {
                data => {
                    data => {
                        message => "Nothing to Apply",
                        success => 0,
                    },
                    dataType => 'json',
                },
                error => "",
                success => 1,
                update_DB => $Config->{update_DB},
            };
    foreach (@$changes) {
        if ($_->{update}{approve} eq 'Y') {
            my $method = $cyclecount_discrepancy_actions{ $_->{update}{discrepancyType} };
            my $adjResult = $self->_cyclecountDiscrepancy->$method( $_->{update} );
            if (!$adjResult->{success}) {
                $result = {
                    data => {
                        data => {
                            message => $adjResult->{message},
                            success => 0,
                        },
                        dataType => 'json',
                    },
                    error => $adjResult->{message},
                    success => 0,
                    update_DB => $Config->{update_DB},
                };
                last;
            } else {
                $result = {
                    data => {
                        data => {
                            message => "",
                            success => 1,
                        },
                        dataType => 'json',
                    },
                    error => "",
                    success => 1,
                    update_DB => $Config->{update_DB},
                };
            }
        } else {
            my $method = $cyclecount_discrepancy_actions{ 'updateCountedOverrideAndNote' };
            my $adjResult = $self->_cyclecountDiscrepancy->$method( $_->{update} );
            $result = {
                data => {
                    data => {
                        message => "",
                        success => 1,
                    },
                    dataType => 'json',
                },
                error => "",
                success => 1,
                update_DB => $Config->{update_DB},
            };
        }
    }
    return $result;
}


no Types::Standard;
no Moo;
no JSON;
1;

