Untitled

 avatar
unknown
plain_text
2 years ago
88 kB
4
Indexable
'use strict';

angular.module('a-sis/wms-preparation-ui-quality-check')

    .controller('qualityCheckCtrl', ['$scope', '$uibModal', 'focus', '$filter', 'qualityCheckService', 'notification', 'urlManager', 'enums', '$timeout', 'utilGs1Service',
     'utilWmsPreparationUnitService', 'utilRefProductService', 'utilCommonService',
        function ($scope, $uibModal, focus, $filter, qualityCheckService, notification, urlManager, enums, $timeout, utilGs1Service, utilWmsPreparationUnitService,
          utilRefProductService, utilCommonService) {

        $scope.workspace.setActiveScreenLabel($filter('translate')('Quality Check', $scope.translateNamespace));

        // init variable
        $scope.parentobj = {};
        $scope.parentobj.stepNumber = '0';
        $scope.parentobj.activeInput = 'quantity';
        $scope.parentobj.itemQuantity = 1;
        $scope.parentobj.productCode = undefined;
        $scope.parentobj.productName = undefined;
        $scope.parentobj.productBatch = undefined;
        $scope.parentobj.productManufacturingDate = undefined;
        $scope.parentobj.productSellByDate = undefined;
        $scope.parentobj.productUseByDate = undefined;
        $scope.parentobj.productBestBeforeDate = undefined;
        $scope.parentobj.productFeatureString1 = undefined;
        $scope.parentobj.productFeatureString2 = undefined;
        $scope.parentobj.productFeatureDate1 = undefined;
        $scope.parentobj.productCountryOfOrigin = undefined;
        $scope.parentobj.productSerial = undefined;
        $scope.parentobj.activedRow = {};
        $scope.parentobj.percent = 0;
        $scope.parentobj.packageNumber = undefined;
        $scope.parentobj.barcodeScanned = undefined;
        $scope.packageItems = [];
        $scope.puIsPresent = false;
        $scope.parentobj.currentRowInScanMode = undefined;
        $scope.countriesOfOrigin = [];

        //This is as subset of PreparationUnitLines. It carries the code & quantity of the LU.
        $scope.parentobj.selectedLogisticUnit = {};
        $scope.logisticUnits = [];

        // Init variable for unexpected items
        $scope.unexpectedItems = [];
        // Init variable for progress bar
        var allQuantityPastChecked = 0;

        $scope.wmsPreparationUnitNeedStatuses = enums.WmsPreparationUnitNeed$Status;
        $scope.VASCount = 0;
        $scope.VASAllTerminated = false;

        // printer: no initial printer defined, but printer selected in modal will be kept for next use
        $scope.printer = {};
        $scope.printer.reportExchange = {};

        $scope.wmsQualityCheckHistoryId = undefined;

        $timeout(function () {
            focus('packageNumber');
        }, 100);

        // Store Preparation unit code in scope
        $scope.memPUCode = urlManager.getPathParameter('code');
        if($scope.memPUCode != null) {
            $scope.puIsPresent = true;
            validateBox($scope.memPUCode);
        }

        // Share picking type enum in the scope
        $scope.enumPickingType = enums.WmsEnumPickingType;

        function convertPreparationUnitLineToPackageItem(item, index) {
            return {
                selected: false,
                quantityPastChecked: 0,
                quantityToChecked: item.quantity,
                quantity: item.quantity,
                logisticUnitQuantity: item.refLogisticUnitQuantity,
                name: item.refProductDescription,
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                logisticUnitCode: item.refLogisticUnitCode,
                logisticUnitBarcodes: item.refLogisticUnitBarcodes,
                picture: item.pictureUrl,
                refLocationCodes: item.refLocationCodes,
                batch: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.batch == null) ? undefined : item.wmsFeature.batch,
                manufacturingDate: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.manufacturingDate == null) ? undefined : moment(item.wmsFeature.manufacturingDate),
                sellByDate: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.sellByDate == null) ? undefined : moment(item.wmsFeature.sellByDate),
                useByDate: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.useByDate == null) ? undefined : moment(item.wmsFeature.useByDate),
                bestBeforeDate: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.bestBeforeDate == null) ? undefined : moment(item.wmsFeature.bestBeforeDate),
                featureString1: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.featureString1 == null) ? undefined : item.wmsFeature.featureString1,
                featureString2: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.featureString2 == null) ? undefined : item.wmsFeature.featureString2,
                featureDate1: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.featureDate1 == null) ? undefined : moment(item.wmsFeature.featureDate1),
                countryOfOrigin: (angular.isUndefined(item.wmsFeature) || item.wmsFeature == null || item.wmsFeature.countryOfOrigin == null) ? undefined : item.wmsFeature.countryOfOrigin,
                serialNumber: item.serialNumber,
                productCode: item.refProductCode,
                pickingType: $scope.enumPickingType[item.wmsEnumPickingType.id]
            }
        }

        function convertPackageItemToLogisticUnit(item, index) {
            return {
                logisticUnitQuantity: item.logisticUnitQuantity,
                name: item.name,
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                logisticUnitCode: item.logisticUnitCode,
                logisticUnitBarcodes: item.logisticUnitBarcodes,
                productCode: item.productCode
            }
        }

        function uniqueArray( ar ) {
          var j = {};
          ar.forEach( function(v) {
            j[v+ '::' + typeof v] = v;
          });
          return Object.keys(j).map(function(v){
            return j[v];
          });
        }

        // Valid box and select the type of checking
        $scope.validBox = function(barcode){
            validateBox(barcode);
        }

        function validateBox(barcode){
            qualityCheckService.findPreparationUnitToCheck(barcode)
                .then(function(preparationUnitToCheck) {
                    if (preparationUnitToCheck != null) {
                        $scope.stockOwnerCode = preparationUnitToCheck.wmsPreparationOrder.refStockOwner.code;
                        $scope.preparationOrderSiteCode = preparationUnitToCheck.wmsPreparationOrder.refSite.code;
                        var declarationQualityCheckHistoryStart = {
                                  wmsPreparationUnitId: preparationUnitToCheck.id,
                                  wmsEnumPreparationMode: enums.WmsEnumPreparationMode.DESKTOP.value}
                            qualityCheckService.qualityCheckHistoryStart(declarationQualityCheckHistoryStart)
                            .then(function(newQualityCheckHistoryId) {
                                // every entrance in the quality check must trigger a new quality check history
                                $scope.wmsQualityCheckHistoryId = newQualityCheckHistoryId;

                                // Get lines
                                $scope.parentobj.wmsPreparationUnitId = preparationUnitToCheck.id;
                                qualityCheckService.findPreparationUnitLinesToCheck(preparationUnitToCheck.id)
                                    .then(function(preparationUnitLinesToCheck) {
                                        if (preparationUnitLinesToCheck != null && preparationUnitLinesToCheck.length > 0){
                                            // full (scanned) checking by default
                                            $scope.parentobj.stepNumber = '2';
                                            $timeout(function () {
                                                focus('code');
                                            }, 100);
                                            $scope.parentobj.packageNumber = preparationUnitToCheck.code;
                                            $scope.parentobj.status = preparationUnitToCheck.status;
                                            $scope.packageItems = preparationUnitLinesToCheck.map(convertPreparationUnitLineToPackageItem);
                                            $scope.packageItems = _.chain($scope.packageItems)
                                                                        .sortBy('logisticUnitQuantity')
                                                                        .sortBy('productCode').reverse()
                                                                        .value();
                                        } else if($scope.puIsPresent) {
                                            $scope.workspace.back();
                                        } else {
                                            var message = $filter('translate')('Unable to check box {{barcode}} because no preparation unit line to check', $scope.translateNamespace, {barcode : barcode});
                                            notification.error(message);
                                        }

                                        refreshVAS();
                                });
                            });
                    } else if($scope.puIsPresent) {
                        $scope.workspace.back();
                    }
                });
        };

        $scope.switchMode = function(){
            if ($scope.parentobj.stepNumber === '1'){
                $scope.parentobj.stepNumber = '2';
            } else if ($scope.parentobj.stepNumber === '2'){
                $scope.parentobj.stepNumber = '1';
            }
            $scope.resetInputAndSelectionLine();
        };

        $scope.focusProductCode = function($event) {
            $scope.parentobj.activeInput = 'code';
            // On focus, selected input text
            $event.target.select();
        };

        $scope.onChangeProductCode = function() {
            $scope.parentobj.currentRowInScanMode = undefined;
            $scope.parentobj.barcodeScanned = undefined;
            $scope.resetFeaturesInput();
        };

        // user can change the auto-recognized LU.
        // This can be usefull to switch (without rescaning product) to another LU of the same product if more than one LU of the same product are to check for this package
        $scope.onChangeSelectedLogisticUnit = function() {
            $scope.parentobj.currentRowInScanMode.selectedLogisticUnit = $scope.parentobj.selectedLogisticUnit;
        };

        $scope.onChangeFeatureOrSerial = function() {
            endHighlightRow();
            $scope.searchRowInScanMode();
        };

        // Calculate progress bar length
        // Sum of all items quantity in the packageItems table
        var allQuantity = 0;
        angular.forEach($scope.packageItems, function (item) {
            allQuantity = allQuantity + item.quantity;

        });

        // Keypad methods
        $scope.sentNumber = function (nbr) {
            if ($scope.parentobj.activeInput === 'packageNumber') {
                if ($scope.parentobj.packageNumber != undefined) {
                    $scope.parentobj.packageNumber = String($scope.parentobj.packageNumber) + nbr;
                } else {
                    $scope.parentobj.packageNumber = String(nbr);
                }
            } else {
                // remove "0" before appending number (to avoid 0 at first place)
                if ($scope.parentobj.itemQuantity == 0) {
                    $scope.parentobj.itemQuantity = "";
                }
                $scope.parentobj.itemQuantity = String($scope.parentobj.itemQuantity) + nbr;
            }
            $timeout(function () {
                focus('code');
            }, 100);
        };
        $scope.removeNumber = function () {
            if ($scope.parentobj.activeInput === 'packageNumber') {
                $scope.parentobj.packageNumber = $scope.parentobj.packageNumber.slice(0, -1);
            } else {
                $scope.parentobj.itemQuantity = String($scope.parentobj.itemQuantity);
                $scope.parentobj.itemQuantity = $scope.parentobj.itemQuantity.slice(0, -1);
            }
            $timeout(function () {
                focus('code');
            }, 100);
        };

        $scope.minusCount = function() {
            $scope.parentobj.itemQuantity = Number($scope.parentobj.itemQuantity);
            $scope.parentobj.itemQuantity = $scope.parentobj.itemQuantity - 1;
            $timeout(function () {
                focus('code');
            }, 100);
        };

        $scope.plusCount = function() {
            $scope.parentobj.itemQuantity = Number($scope.parentobj.itemQuantity);
            $scope.parentobj.itemQuantity = $scope.parentobj.itemQuantity + 1;
            $timeout(function () {
                focus('code');
            }, 100);
        };

        // Selected a row in the table
        $scope.activeRow = function (row) {
            // Active row
            $scope.parentobj.activedRow = row;

            //Send row information to input
            if (!row.quantityChecked) {
                $scope.parentobj.itemQuantity = row.quantityToChecked / row.logisticUnitQuantity;
                row.quantityChecked = row.quantityToChecked;
            } else {
                $scope.parentobj.itemQuantity = row.quantityChecked / row.logisticUnitQuantity;
            }
            $scope.parentobj.productCode = row.productCode;
            $scope.parentobj.productBatch = row.batch != null ? row.batch : undefined;
            $scope.parentobj.productSerial = row.serialNumber != null ? row.serialNumber : undefined;
            $scope.parentobj.productManufacturingDate = utilCommonService.isDefinedAndNotNull(row.manufacturingDate) ? row.manufacturingDate._i : undefined;
            $scope.parentobj.productSellByDate = utilCommonService.isDefinedAndNotNull(row.sellByDate) ? row.sellByDate._i : undefined;
            $scope.parentobj.productUseByDate = utilCommonService.isDefinedAndNotNull(row.useByDate) ? row.useByDate._i : undefined;
            $scope.parentobj.productBestBeforeDate = utilCommonService.isDefinedAndNotNull(row.bestBeforeDate) ? row.bestBeforeDate._i : undefined;
            $scope.parentobj.productFeatureString1 = row.featureString1 != null ? row.featureString1 : undefined;
            $scope.parentobj.productFeatureString2 = row.featureString2 != null ? row.featureString2 : undefined;
            $scope.parentobj.productFeatureDate1 = utilCommonService.isDefinedAndNotNull(row.featureDate1) ? row.featureDate1._i : undefined;
            $scope.parentobj.productCountryOfOrigin = row.countryOfOrigin != null ? row.countryOfOrigin : undefined;
            highlightRow([row]);

            $scope.updateLogisticUnitChoices();
            $timeout(function () {
                focus('code');
            }, 100);
        };

        // Link item quantity to input quantity & logisticUnit selection
        $scope.$watch('parentobj.itemQuantity', function(){
            updateItemQuantity();
        });
        $scope.$watch('parentobj.selectedLogisticUnit', function() {
            updateItemQuantity();
        });


        // Activate/deactivate the checkbox
        $scope.fillCheck = function (row, $event) {
            $event.stopPropagation();
            $event.preventDefault();
            if (row.selected === false) {
                $scope.activeRow(row);
            }
            else {
                row.selected = false;
                $scope.activeRow([]);
                row.quantityChecked = undefined;
            }
        };

        $scope.resetInputAndSelectionLine = function () {
            // reset all inputs
            $scope.parentobj.productCode = undefined;
            $scope.parentobj.barcodeScanned = undefined;
            $scope.resetFeaturesInput();

            // reset currentRowInScanMode
            $scope.resetSelectionLine();

            // clear highlights on right panel (PU lines)
            endHighlightRow();
        };

        $scope.resetFeaturesInput = function () {
            $scope.parentobj.productBatch = undefined;
            $scope.parentobj.productManufacturingDate = undefined;
            $scope.parentobj.productSellByDate = undefined;
            $scope.parentobj.productUseByDate = undefined;
            $scope.parentobj.productBestBeforeDate = undefined;
            $scope.parentobj.productFeatureString1 = undefined;
            $scope.parentobj.productFeatureString2 = undefined;
            $scope.parentobj.productFeatureDate1 = undefined;
            $scope.parentobj.productCountryOfOrigin = undefined;
            $scope.parentobj.productSerial = undefined;
        };

        $scope.resetSelectionLine = function () {

            if($scope.parentobj.stepNumber == '1'){
                $scope.parentobj.itemQuantity = undefined;
            }
            else{
                $scope.parentobj.itemQuantity = 1;
            }
            $scope.parentobj.activedRow = {};
            $scope.parentobj.logisticUnits = [];
            $scope.parentobj.selectedLogisticUnit = {};
            // reset current row (for scan mode)
            $scope.parentobj.currentRowInScanMode = undefined;
        };

        $scope.isCorrectQuantity = function () {
            return $scope.parentobj.selectedLogisticUnit !== undefined &&
                $scope.parentobj.selectedLogisticUnit !== {} &&
                !isNaN($scope.parentobj.selectedLogisticUnit.logisticUnitQuantity * $scope.parentobj.itemQuantity);
        };

        var updateItemQuantity = function() {
            if ($scope.parentobj.itemQuantity < 0) $scope.parentobj.itemQuantity = 0;
            if($scope.parentobj.selectedLogisticUnit == null) return;
            $scope.parentobj.activedRow.quantityChecked = $scope.parentobj.itemQuantity * $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
        };

        $scope.updateLogisticUnitChoices = function() {
            if($scope.parentobj.stepNumber == '2') { // full check mode. User scans things
                var code = $scope.parentobj.productCode;
                var rows = $scope.packageItems;

                // filter package items with remainging quantity to check (usefull when multiple LUs of the same product in the package to check)
                rows = rows.filter(rows => rows.quantityToChecked > 0);

                // get all LUs from package items
                var lus = rows.map(convertPackageItemToLogisticUnit);

                // filter matching LUs (based on scanned productCode)
                var matches = _.filter(lus, {'productCode' : code});
                // product code filter fail -> filter by logistic Unit Code
                if(matches.length == 0) {
                    // filter by product logisticUnit barcode if possible
                    matches = _.filter(lus, function(item) {
                        for(var i in item.logisticUnitBarcodes)
                            if(item.logisticUnitBarcodes[i] == code)
                                return true;
                        return false;
                    });
                }

                // due to features and serial (one WmsPreparationUnitLineDetail for each), same LUs may be present in the matches list -> select distinct
                $scope.logisticUnits = uniqueArray(matches);

                if($scope.logisticUnits.length > 0) {
                    // Sort the smallest logisticUnits first
                    $scope.logisticUnits = _.sortBy($scope.logisticUnits, 'logisticUnitQuantity');
                    $scope.parentobj.selectedLogisticUnit = $scope.logisticUnits[0]; // always at least 1 match. Preselect the first one.
                } else {
                    $scope.parentobj.selectedLogisticUnit = {}; // no matches. WTF ?
                }
            } else {
                $scope.logisticUnits = [ $scope.parentobj.activedRow ];
                $scope.parentobj.selectedLogisticUnit = $scope.logisticUnits[0];
            }
        };

        // search the item in $scope.packageItems
        $scope.searchRowInSelectionMode = function () {
            $scope.parentobj.barcodeScanned = $scope.parentobj.productCode;

            if (angular.isUndefined($scope.parentobj.barcodeScanned)) {
                findError();
                return;
            }

            var rows= $scope.packageItems;
            //kill selected lines
            endHighlightRow();
            // find object which matches with the information enter in the input
            // rows contain the objetcs
            if($scope.parentobj.productCode != undefined && $scope.parentobj.productBatch == undefined &&
            $scope.parentobj.productSerial == undefined && $scope.parentobj.productManufacturingDate == undefined &&
            $scope.parentobj.productSellByDate == undefined && $scope.parentobj.productUseByDate == undefined &&
            $scope.parentobj.productBestBeforeDate == undefined && $scope.parentobj.productFeatureString1 == undefined &&
            $scope.parentobj.productFeatureString2 == undefined && $scope.parentobj.productFeatureDate1 == undefined &&
            $scope.parentobj.productCountryOfOrigin == undefined) {
                //Filter by product code
                rows = _.filter(rows, {'productCode' : $scope.parentobj.productCode});

                //Discriminate duplicates (products / LU barcodes) with the selected logistic unit code
                if(rows.length > 1)
                    rows = _.filter(rows, {'logisticUnitCode' : $scope.parentobj.selectedLogisticUnit.logisticUnitCode});

                // product code filter fail -> filter by logistic Unit Code
                if(rows.length == 0)
                    rows = _.filter(rows, function(item) {
                        for(var i in item.logisticUnitBarcodes) {
                            if(item.logisticUnitBarcodes[i] == $scope.parentobj.productCode)
                                return true;
                        }
                        return false;
                    });

            } else {
                if (angular.isDefined($scope.parentobj.productCode)) {
                    // filter rows with the right product
                    rows = _.filter(rows, {'productCode' : $scope.parentobj.productCode});
                    // filter rows with remaining quantity to check
                    rows = rows.filter(rows => rows.quantityToChecked > 0);
                }
                rows = filterRowsByFeaturesAndSerial(rows);
            }

            rows = checkSingleItemNotMissingIdentified(rows);
            var activeTraceability = checkActivatedTraceability(rows);
            // If there is missing traceability info, return the error
            if (activeTraceability && !checkTraceability(rows)) {
                findError();
                return;
            }

            // Find what to do with the rows
            if (rows && rows.length == 1) {
                checkAndUpdateQuantity(rows[0]);
                $scope.resetInputAndSelectionLine();
            } else if (rows.length > 1) {
                if (!activeTraceability) {
                    var quantityToVentilate = ventilateQuantity(rows);
                    if (quantityToVentilate > 0){
                        // Try to ventilate the overflow on the first row to display alert message
                        $scope.parentobj.itemQuantity = quantityToVentilate / $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
                        checkAndUpdateQuantity(rows[0]);
                    }
                    $scope.resetInputAndSelectionLine();
                }
            } else {
                findError();
            }
        };

         // TO BE USED with mode scan (=step2) : search the item in $scope.packageItems, display logistic unit and quantity and add of quantity after scan of item
        $scope.searchRowInScanMode = function () {
            $scope.isUnknownScan = false;
            $scope.isUnexpectedScan = false;
            var rows = $scope.packageItems;
            var gs1BarcodeResult;
            var isNewBarcode = angular.isUndefined($scope.parentobj.barcodeScanned);

            if (isNewBarcode) {
                $scope.parentobj.barcodeScanned = $scope.parentobj.productCode;
                // Parse barcode if needed (save parsed barcode to have potential traceability datas)
                utilGs1Service.parse($scope.parentobj.barcodeScanned)
                    .then(gs1BarcodeResult => {
                            initParentObjWithGS1BarcodeResult(gs1BarcodeResult)
                            // find object which matches with the information enter in the input
                            if (angular.isDefined($scope.parentobj.productCode) && angular.isDefined($scope.stockOwnerCode) && angular.isDefined($scope.preparationOrderSiteCode)) {
                                utilRefProductService.findProductByProductCodeOrLUBarcodeOrGtin($scope.preparationOrderSiteCode, $scope.stockOwnerCode, $scope.parentobj.productCode)
                                    .then(foundProduct => {
                                        if (utilCommonService.isUndefinedOrNull(foundProduct)) {
                                            $scope.isUnknownScan = true;
                                            findError();
                                        } else {
                                            $scope.resetSelectionLine();
                                            $scope.updateLogisticUnitChoices();
                                            $scope.isCorrectQuantity();
                                            endHighlightRow();

                                            // Retrieve list of countries of origin.
                                            utilRefProductService.getCountryOfOriginList($scope.stockOwnerCode, foundProduct.code)
                                                .then(function(countryOfOriginList) {
                                                    $scope.countriesOfOrigin = countryOfOriginList;
                                                });

                                            rows = getRowsByCodeProductOrLU(rows, foundProduct.code);
                                            // filter rows with remaining quantity to check
                                            rows = rows.filter(rows => rows.quantityToChecked > 0);
                                             // discriminate duplicates (products / LU barcodes) with the selected logistic unit code (first selected LU by default is the smallest one)
                                             if (rows.length > 1) {
                                                 rows = _.filter(rows, { 'logisticUnitCode': $scope.parentobj.selectedLogisticUnit.logisticUnitCode });
                                             }
                                             rows = filterRowsByFeaturesAndSerialProduct(rows);
                                             if (rows.length == 0 && !$scope.isUnknownScan) {
                                                 $scope.isUnexpectedScan = true;
                                             }
                                             //-First- Select the not missing preparation unit line detail if exists
                                             var tmpRows = _.filter(rows, function (item) {
                                                 if ($scope.enumPickingType.PICKED.eq(item.pickingType) && (item.quantity - item.quantityPastChecked > 0))
                                                     return item;
                                             });
                                             if (tmpRows.length > 0) {
                                                 rows = tmpRows;
                                             }
                                             highlightRow(rows);
                                             var activeTraceability = checkActivatedTraceabilityProduct(rows, foundProduct);
                                             // If there is missing traceability info, return the error
                                             if (activeTraceability && !checkTraceabilityProduct(rows, foundProduct)) {
                                                 findError();
                                                 return;
                                             }
                                             // Find what to do with the rows
                                             if (rows && rows.length == 1) {
                                                 $scope.parentobj.currentRowInScanMode = rows[0];
                                                 // highlight row to show line with remaining quantity to check for the current product (when present)
                                                  if(rows[0].pickingType.value.id == "MISSING") {
                                                     $scope.parentobj.currentRowInScanMode.batch = $scope.parentobj.productBatch;
                                                     $scope.parentobj.currentRowInScanMode.serialNumber = $scope.parentobj.productSerial;
                                                     $scope.parentobj.currentRowInScanMode.manufacturingDate = $scope.parentobj.productManufacturingDate;
                                                     $scope.parentobj.currentRowInScanMode.sellByDate = $scope.parentobj.productSellByDate;
                                                     $scope.parentobj.currentRowInScanMode.useByDate = $scope.parentobj.productUseByDate;
                                                     $scope.parentobj.currentRowInScanMode.bestBeforeDate = $scope.parentobj.productBestBeforeDate;
                                                     $scope.parentobj.currentRowInScanMode.featureString1 = $scope.parentobj.productFeatureString1;
                                                     $scope.parentobj.currentRowInScanMode.featureString2 = $scope.parentobj.productFeatureString2;
                                                     $scope.parentobj.currentRowInScanMode.featureDate1 = $scope.parentobj.featureDate1;
                                                     $scope.parentobj.currentRowInScanMode.countryOfOrigin = $scope.parentobj.productCountryOfOrigin;
                                                 }
                                                 showItem($scope.parentobj.currentRowInScanMode);
                                                 $scope.parentobj.currentRowInScanMode = rows[0];
                                             } else if (rows.length > 1) {
                                                 if ((!activeTraceability) || (activeTraceability && rows[0].pickingType.value.id == "MISSING")) {
                                                     var quantityToVentilate = ventilateQuantity(rows);
                                                     if (quantityToVentilate > 0) {
                                                         // Try to ventilate the overflow on the first row to display alert message
                                                         $scope.parentobj.itemQuantity = quantityToVentilate / $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
                                                         $scope.parentobj.currentRowInScanMode = rows[0];
                                                         checkAndUpdateQuantity($scope.parentobj.currentRowInScanMode);
                                                     }
                                                     // set focus on code for next scan to be done immediately if no modification of quantity
                                                     $scope.parentobj.activeInput = 'code';
                                                     if(activeTraceability && rows[0].pickingType.value.id == "MISSING") {
                                                         $scope.parentobj.currentRowInScanMode = rows[0];
                                                         $scope.parentobj.currentRowInScanMode.batch = $scope.parentobj.productBatch;
                                                         $scope.parentobj.currentRowInScanMode.serialNumber = $scope.parentobj.productSerial;
                                                         $scope.parentobj.currentRowInScanMode.manufacturingDate = $scope.parentobj.productManufacturingDate;
                                                         $scope.parentobj.currentRowInScanMode.sellByDate = $scope.parentobj.productSellByDate;
                                                         $scope.parentobj.currentRowInScanMode.useByDate = $scope.parentobj.productUseByDate;
                                                         $scope.parentobj.currentRowInScanMode.bestBeforeDate = $scope.parentobj.productBestBeforeDate;
                                                         $scope.parentobj.currentRowInScanMode.featureString1 = $scope.parentobj.productFeatureString1;
                                                         $scope.parentobj.currentRowInScanMode.featureString2 = $scope.parentobj.productFeatureString2;
                                                         $scope.parentobj.currentRowInScanMode.featureDate1 = $scope.parentobj.featureDate1;
                                                         $scope.parentobj.currentRowInScanMode.countryOfOrigin = $scope.parentobj.productCountryOfOrigin;
                                                     }
                                                     // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                                                     focus('quantity');
                                                     $timeout(function () {
                                                         focus('code');
                                                     }, 100);
                                                     $scope.resetInputAndSelectionLine();
                                                 }
                                            } else {
                                                findError();
                                            }
                                        }
                                    });
                            } else {
                                findError();
                                return;
                            }
                   });
            }

        };

        function initParentObjWithGS1BarcodeResult(gs1BarcodeResult) {
            // If barcode was correctly parsed, gtin will always be defined
            if (angular.isDefined(gs1BarcodeResult) && angular.isDefined(gs1BarcodeResult.gtin)) {
                $scope.parentobj.productCode = gs1BarcodeResult.gtin;
                $scope.parentobj.productBatch = gs1BarcodeResult.batchOrLotNumber;
                $scope.parentobj.productSerial = gs1BarcodeResult.serialNumber;
                // kis-input can only handle Date type
                if (gs1BarcodeResult.productionDate) {
                    $scope.parentobj.productManufacturingDate = new Date(gs1BarcodeResult.productionDate);
                }
                if (gs1BarcodeResult.sellByDate) {
                    $scope.parentobj.productSellByDate =  new Date(gs1BarcodeResult.sellByDate);
                }
                if (gs1BarcodeResult.expirationDate) {
                    $scope.parentobj.productUseByDate =  new Date(gs1BarcodeResult.expirationDate);
                }
                if (gs1BarcodeResult.bestBeforeDate) {
                    $scope.parentobj.productBestBeforeDate =  new Date(gs1BarcodeResult.bestBeforeDate);
                }
            }
        }

        function featureIsPresent() {
            parentobj.currentRowInScanMode.batch != undefined
            parentobj.currentRowInScanMode.manufacturingDate != undefined
            parentobj.currentRowInScanMode.sellByDate != undefined
            parentobj.currentRowInScanMode.useByDate != undefined
            parentobj.currentRowInScanMode.bestBeforeDate != undefined
            parentobj.currentRowInScanMode.featureString1 != undefined
            parentobj.currentRowInScanMode.featureString2 != undefined
            parentobj.currentRowInScanMode.featureDate1 != undefined
            parentobj.currentRowInScanMode.countryOfOrigin != undefined
            parentobj.currentRowInScanMode.serialNumber != undefined

        }

        function filterRowsByFeaturesAndSerial(rows) {
            if ($scope.parentobj.productBatch) {
                rows = _.filter(rows, {'batch' : $scope.parentobj.productBatch});
            }
            if ($scope.parentobj.productSerial) {
                rows = _.filter(rows, {'serialNumber' : $scope.parentobj.productSerial});
            }
            if ($scope.parentobj.productManufacturingDate) {
                rows = rows.filter(row => sameDayAs(row.manufacturingDate, $scope.parentobj.productManufacturingDate));
            }
            if ($scope.parentobj.productSellByDate) {
                rows = rows.filter(row => sameDayAs(row.sellByDate, $scope.parentobj.productSellByDate));
            }
            if ($scope.parentobj.productUseByDate) {
                rows = rows.filter(row => sameDayAs(row.useByDate, $scope.parentobj.productUseByDate));
            }
            if ($scope.parentobj.productBestBeforeDate) {
                rows = rows.filter(row => sameDayAs(row.bestBeforeDate, $scope.parentobj.productBestBeforeDate));
            }
            if ($scope.parentobj.productFeatureString1) {
                rows = _.filter(rows, {'featureString1' : $scope.parentobj.productFeatureString1});
            }
            if ($scope.parentobj.productFeatureString2) {
                rows = _.filter(rows, {'featureString2' : $scope.parentobj.productFeatureString2});
            }
            if ($scope.parentobj.productFeatureDate1) {
                rows = rows.filter(row => sameDayAs(row.featureDate1, $scope.parentobj.productFeatureDate1));
            }
            if ($scope.parentobj.productCountryOfOrigin) {
                rows = _.filter(rows, {'countryOfOrigin' : $scope.parentobj.productCountryOfOrigin});
            }
            return rows;
        }

        function filterRowsByFeaturesAndSerialProduct(rows) {
            var rowsfilter = rows;
            var rowMissing = [];
            rowMissing = rowsfilter.filter(rows => rows.pickingType.value.id != "MISSING");
            if(rowMissing.length === 0) return rows;

            if ($scope.parentobj.productBatch && $scope.parentobj.status.value.id != "MISSING") {
                rows = _.filter(rows, {'batch' : $scope.parentobj.productBatch});
            }
            if ($scope.parentobj.productSerial && $scope.parentobj.status.value.id != "MISSING") {
                rows = _.filter(rows, {'serialNumber' : $scope.parentobj.productSerial});
            }
            if ($scope.parentobj.productManufacturingDate && $scope.parentobj.status.value.id != "MISSING") {
                rows = rows.filter(row => sameDayAs(row.manufacturingDate, $scope.parentobj.productManufacturingDate));
            }
            if ($scope.parentobj.productSellByDate && $scope.parentobj.status.value.id != "MISSING") {
                rows = rows.filter(row => sameDayAs(row.sellByDate, $scope.parentobj.productSellByDate));
            }
            if ($scope.parentobj.productUseByDate && $scope.parentobj.status.value.id != "MISSING") {
                rows = rows.filter(row => sameDayAs(row.useByDate, $scope.parentobj.productUseByDate));
            }
            if ($scope.parentobj.productBestBeforeDate && $scope.parentobj.status.value.id != "MISSING") {
                rows = rows.filter(row => sameDayAs(row.bestBeforeDate, $scope.parentobj.productBestBeforeDate));
            }
            if ($scope.parentobj.productFeatureString1 && $scope.parentobj.status.value.id != "MISSING") {
                rows = _.filter(rows, {'featureString1' : $scope.parentobj.productFeatureString1});
            }
            if ($scope.parentobj.productFeatureString2 && $scope.parentobj.status.value.id != "MISSING") {
                rows = _.filter(rows, {'featureString2' : $scope.parentobj.productFeatureString2});
            }
            if ($scope.parentobj.productFeatureDate1 && $scope.parentobj.status.value.id != "MISSING") {
                rows = rows.filter(row => sameDayAs(row.featureDate1, $scope.parentobj.productFeatureDate1));
            }
            if ($scope.parentobj.productCountryOfOrigin && $scope.parentobj.status.value.id != "MISSING") {
                rows = _.filter(rows, {'countryOfOrigin' : $scope.parentobj.productCountryOfOrigin});
            }
            return rows;
        }

        function sameDayAs(value, momentToFilter) {
            // value might not be defined if user scans a date feature that is not managed by the product
            return angular.isDefined(value) && value.isSame(momentToFilter, 'day');
        }

        function showItem(item) {
            checkAndUpdateQuantity(item);
            // set item quantity to 0 (to avoid need to remove "1" from field if quantity not starting with "1")
            $scope.parentobj.itemQuantity = 0;
            // set focus on code for next scan to be done immediately if no modification of quantity
            $scope.parentobj.activeInput = 'code';
            // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
            focus('quantity');
            $timeout(function () {
                focus('code');
            }, 100);
            if(item.serialNumber != null) {
                $scope.resetInputAndSelectionLine();
            }
        }

        $scope.displayFeature = function (item) {
            if($scope.enumPickingType.MISSING.eq(item.pickingType)){
                return(false);
            } else return(true);
        }

        function getRowsByCodeProductOrLU(rows, codeProductOrLU) {
            // Filter by product code
            rows = _.filter(rows, {'productCode' : codeProductOrLU});

            // filter by product code has fail. Try recognition by GTIN LU barcode ...
            if(rows.length == 0) {
                rows = _.filter($scope.packageItems, function(item) {
                    for(var i in item.logisticUnitBarcodes) {
                        if(item.logisticUnitBarcodes[i] == codeProductOrLU)
                            return true;
                    }
                    return false;
                });
            }
            return rows;
        }

        function checkSingleItemNotMissingIdentified(rows) {
            //-First- Select the not missing preparation unit line detail if exists
            var tmpRows = _.filter(rows, function(item){
                    if($scope.enumPickingType.PICKED.eq(item.pickingType) && (item.quantity - item.quantityPastChecked > 0))
                        return item;
                });
            if (tmpRows.length == 1) {
                rows = tmpRows;
            }
            return rows;
        }


        function checkActivatedTraceability(rows) {
            var activateCarac = false;
            if (angular.isUndefined(rows) || rows.length == 0) {
                return activateCarac;
            }

            if(rows[0].batch && !$scope.parentobj.activedRow.batch) {
                $scope.parentobj.activedRow.batch = true;
                activateCarac = true;
            }
            if(rows[0].serialNumber && !$scope.parentobj.activedRow.serialNumber) {
                $scope.parentobj.activedRow.serialNumber = true;
                activateCarac = true;
            }
            if(rows[0].manufacturingDate && !$scope.parentobj.activedRow.manufacturingDate) {
                $scope.parentobj.activedRow.manufacturingDate = true;
                activateCarac = true;
            }
            if(rows[0].sellByDate && !$scope.parentobj.activedRow.sellByDate) {
                $scope.parentobj.activedRow.sellByDate = true;
                activateCarac = true;
            }
            if(rows[0].useByDate && !$scope.parentobj.activedRow.useByDate) {
                $scope.parentobj.activedRow.useByDate = true;
                activateCarac = true;
            }
            if(rows[0].bestBeforeDate && !$scope.parentobj.activedRow.bestBeforeDate) {
                $scope.parentobj.activedRow.bestBeforeDate = true;
                activateCarac = true;
            }
            if(rows[0].featureString1 && !$scope.parentobj.activedRow.featureString1) {
                $scope.parentobj.activedRow.featureString1 = true;
                activateCarac = true;
            }
            if(rows[0].featureString2 && !$scope.parentobj.activedRow.featureString2) {
                $scope.parentobj.activedRow.featureString2 = true;
                activateCarac = true;
            }
            if(rows[0].featureDate1 && !$scope.parentobj.activedRow.featureDate1) {
                $scope.parentobj.activedRow.featureDate1 = true;
                activateCarac = true;
            }
            if(rows[0].countryOfOrigin && !$scope.parentobj.activedRow.countryOfOrigin) {
                $scope.parentobj.activedRow.countryOfOrigin = true;
                activateCarac = true;
            }

            return activateCarac;
        }

        function checkActivatedTraceabilityProduct(rows, product) {
            var activateCarac = false;
            if (angular.isUndefined(rows) || rows.length == 0) {
                return activateCarac;
            }

            if((rows[0].batch || product.traceabilityBatch.id != "NO") && !$scope.parentobj.activedRow.batch) {
                $scope.parentobj.activedRow.batch = true;
                activateCarac = true;
            }
            if((rows[0].serialNumber || product.traceabilitySerialNumber.id != "NO") && !$scope.parentobj.activedRow.serialNumber) {
                $scope.parentobj.activedRow.serialNumber = true;
                activateCarac = true;
            }
            if((rows[0].manufacturingDate || product.traceabilityManufacturingDate.id != "NO")  && !$scope.parentobj.activedRow.manufacturingDate) {
                $scope.parentobj.activedRow.manufacturingDate = true;
                activateCarac = true;
            }
            if((rows[0].sellByDate || product.traceabilitySellByDate.id != "NO") && !$scope.parentobj.activedRow.sellByDate) {
                $scope.parentobj.activedRow.sellByDate = true;
                activateCarac = true;
            }
            if((rows[0].useByDate || product.traceabilitySellByDate.id != "NO") && !$scope.parentobj.activedRow.useByDate) {
                $scope.parentobj.activedRow.useByDate = true;
                activateCarac = true;
            }
            if((rows[0].bestBeforeDate || product.traceabilityBestBeforeDate.id != "NO") && !$scope.parentobj.activedRow.bestBeforeDate) {
                $scope.parentobj.activedRow.bestBeforeDate = true;
                activateCarac = true;
            }
            if((rows[0].featureString1 || product.traceabilityFeatureString1.id != "NO") && !$scope.parentobj.activedRow.featureString1) {
                $scope.parentobj.activedRow.featureString1 = true;
                activateCarac = true;
            }
            if((rows[0].featureString2 || product.traceabilityFeatureString2.id != "NO") && !$scope.parentobj.activedRow.featureString2) {
                $scope.parentobj.activedRow.featureString2 = true;
                activateCarac = true;
            }
            if((rows[0].featureDate1  || product.traceabilityFeatureDate1.id != "NO") && !$scope.parentobj.activedRow.featureDate1) {
                $scope.parentobj.activedRow.featureDate1 = true;
                activateCarac = true;
            }
            if((rows[0].countryOfOrigin || product.traceabilityCountryOfOrigin.id != "NO") && !$scope.parentobj.activedRow.countryOfOrigin) {
                $scope.parentobj.activedRow.countryOfOrigin = true;
                activateCarac = true;
            }

            return activateCarac;
        }

        function checkTraceability(rows) {
            var batchTraceNotNecessaryOrFilled = !rows[0].batch || angular.isDefined($scope.parentobj.productBatch);
            var serialNumberTraceNotNecessaryOrFilled = !rows[0].serialNumber || angular.isDefined($scope.parentobj.productSerial);
            var manufacturingDateTraceNotNecessaryOrFilled = !rows[0].manufacturingDate || angular.isDefined($scope.parentobj.productManufacturingDate);
            var sellByDateTraceNotNecessaryOrFilled = !rows[0].sellByDate || angular.isDefined($scope.parentobj.productSellByDate);
            var useByDateTraceNotNecessaryOrFilled = !rows[0].useByDate || angular.isDefined($scope.parentobj.productUseByDate);
            var bestBeforeDateTraceNotNecessaryOrFilled = !rows[0].bestBeforeDate || angular.isDefined($scope.parentobj.productBestBeforeDate);
            var featureString1TraceNotNecessaryOrFilled = !rows[0].featureString1 || angular.isDefined($scope.parentobj.productFeatureString1);
            var featureString2TraceNotNecessaryOrFilled = !rows[0].featureString2 || angular.isDefined($scope.parentobj.productFeatureString2);
            var featureDate1TraceNotNecessaryOrFilled = !rows[0].featureDate1 || angular.isDefined($scope.parentobj.productFeatureDate1);
            var countryOfOriginTraceNotNecessaryOrFilled = !rows[0].countryOfOrigin || angular.isDefined($scope.parentobj.productCountryOfOrigin);

            return batchTraceNotNecessaryOrFilled &&
                    serialNumberTraceNotNecessaryOrFilled &&
                    manufacturingDateTraceNotNecessaryOrFilled &&
                    sellByDateTraceNotNecessaryOrFilled &&
                    useByDateTraceNotNecessaryOrFilled &&
                    bestBeforeDateTraceNotNecessaryOrFilled &&
                    featureString1TraceNotNecessaryOrFilled &&
                    featureString2TraceNotNecessaryOrFilled &&
                    featureDate1TraceNotNecessaryOrFilled &&
                    countryOfOriginTraceNotNecessaryOrFilled;
        }

        function checkTraceabilityProduct(rows, product) {
            var batchTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].batch) && product.traceabilityBatch.id != 'NO') ||
            (product.traceabilityBatch.id != 'NO' && angular.isDefined($scope.parentobj.productBatch)) ||
            (!angular.isDefined(rows[0].batch) && product.traceabilityBatch.id == 'NO' && !angular.isDefined($scope.parentobj.productBatch));

            var serialNumberTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].serialNumber) && product.traceabilitySerialNumber.id != 'NO') ||
            (product.traceabilitySerialNumber.id != 'NO' && angular.isDefined($scope.parentobj.productSerial)) ||
            ((!angular.isDefined(rows[0].serialNumber) || rows[0].serialNumber == null) && product.traceabilitySerialNumber.id == 'NO' && !angular.isDefined($scope.parentobj.productSerial)) ;

            var manufacturingDateTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].manufacturingDate) && product.traceabilityManufacturingDate.id != 'NO') ||
            (product.traceabilityManufacturingDate.id != 'NO' && angular.isDefined($scope.parentobj.productManufacturingDate)) ||
            (!angular.isDefined(rows[0].manufacturingDate) && product.traceabilityManufacturingDate.id == 'NO' && !angular.isDefined($scope.parentobj.productManufacturingDate));

            var sellByDateTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].sellByDate) && product.traceabilitySellByDate.id != 'NO') ||
            (product.traceabilitySellByDate.id != 'NO' && angular.isDefined($scope.parentobj.productSellByDate)) ||
            (!angular.isDefined(rows[0].sellByDate) && product.traceabilitySellByDate.id == 'NO' && !angular.isDefined($scope.parentobj.productSellByDate));

            var useByDateTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].useByDate) && product.traceabilityUseByDate.id != 'NO') ||
            (product.traceabilityUseByDate.id != 'NO' && angular.isDefined($scope.parentobj.productUseByDate)) ||
            (!angular.isDefined(rows[0].useByDate) && product.traceabilityUseByDate.id == 'NO' && !angular.isDefined($scope.parentobj.productUseByDate));

            var bestBeforeDateTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].bestBeforeDate) && product.traceabilityBestBeforeDate.id != 'NO') ||
            (product.traceabilityBestBeforeDate.id != 'NO' && angular.isDefined($scope.parentobj.productBestBeforeDate)) ||
            (!angular.isDefined(rows[0].bestBeforeDate) && product.traceabilityBestBeforeDate.id == 'NO' && !angular.isDefined($scope.parentobj.productBestBeforeDate));

            var featureString1TraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].featureString1) && product.traceabilityFeatureString1.id != 'NO') ||
            (product.traceabilityFeatureString1.id != 'NO' && angular.isDefined($scope.parentobj.productFeatureString1)) ||
            (!angular.isDefined(rows[0].featureString1) && product.traceabilityFeatureString1.id == 'NO' && !angular.isDefined($scope.parentobj.productFeatureString1));

            var featureString2TraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].featureString2) && product.traceabilityFeatureString2.id != 'NO') ||
            (product.traceabilityFeatureString2.id != 'NO' && angular.isDefined($scope.parentobj.productFeatureString2)) ||
            (!angular.isDefined(rows[0].featureString2) && product.traceabilityFeatureString2.id == 'NO' && !angular.isDefined($scope.parentobj.productFeatureString2));

            var featureDate1TraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].featureDate1) && product.traceabilityFeatureDate1.id != 'NO') ||
            (product.traceabilityFeatureDate1.id != 'NO' && angular.isDefined($scope.parentobj.productFeatureDate1)) ||
            (!angular.isDefined(rows[0].featureDate1) && product.traceabilityFeatureDate1.id == 'NO' && !angular.isDefined($scope.parentobj.productFeatureDate1));

            var countryOfOriginTraceNotNecessaryOrFilled = (!angular.isDefined(rows[0].countryOfOrigin) && product.traceabilityCountryOfOrigin.id != 'NO' && angular.isDefined($scope.parentobj.productCountryOfOrigin)) ||
            (product.traceabilityCountryOfOrigin.id != 'NO' && angular.isDefined($scope.parentobj.productCountryOfOrigin)) ||
            (!angular.isDefined(rows[0].countryOfOrigin) && product.traceabilityCountryOfOrigin.id == 'NO' && !angular.isDefined($scope.parentobj.productCountryOfOrigin));

            return batchTraceNotNecessaryOrFilled &&
                    serialNumberTraceNotNecessaryOrFilled &&
                    manufacturingDateTraceNotNecessaryOrFilled &&
                    sellByDateTraceNotNecessaryOrFilled &&
                    useByDateTraceNotNecessaryOrFilled &&
                    bestBeforeDateTraceNotNecessaryOrFilled &&
                    featureString1TraceNotNecessaryOrFilled &&
                    featureString2TraceNotNecessaryOrFilled &&
                    featureDate1TraceNotNecessaryOrFilled &&
                    countryOfOriginTraceNotNecessaryOrFilled;
        }

        function ventilateQuantity(rows) {
            var quantityToVentilate = Number($scope.parentobj.itemQuantity) * $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
            angular.forEach(rows, function(row) {
                if (quantityToVentilate > 0 && row.quantityToChecked > 0){
                    if (quantityToVentilate >= row.quantityToChecked){
                        $scope.parentobj.itemQuantity = row.quantityToChecked / $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
                    }else {
                        $scope.parentobj.itemQuantity = quantityToVentilate / $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
                    }
                    checkAndUpdateQuantity(row);
                    quantityToVentilate = quantityToVentilate - $scope.parentobj.itemQuantity * $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
                }
            });
            return quantityToVentilate;
        }

        $scope.addCheckedQuantityInScanMode = function() {
            // warning : 1 logistic unit has already been count by scan. The current quantity will be added
            checkAndUpdateQuantity($scope.parentobj.currentRowInScanMode, $scope.parentobj.productCode);
            $scope.resetInputAndSelectionLine();
            $timeout(function () {
                focus('code');
            }, 100);
        };

        // Highlight serial/batch lines
        var highlightRows = [];
        var highlightRow = function(rows) {
            highlightRows = rows;
            angular.forEach(rows, function (item) {
                item.selected = true;
            })
        };

        var endHighlightRow = function() {
            if(highlightRows.length > 0) {
                angular.forEach(highlightRows, function (item) {
                    item.selected = false;
                })
            }
        };

        // Update quantity if one object from $scope.packageItems matches with the input informations
        var checkAndUpdateQuantity = function(o) {
            o.quantityChecked = Number($scope.parentobj.itemQuantity) * $scope.parentobj.selectedLogisticUnit.logisticUnitQuantity;
            o.unexpectedQuantity = undefined;

            if (o.quantityChecked > o.quantityToChecked) {
                o.unexpectedQuantity = o.quantityChecked - o.quantityToChecked;
                o.quantityPastChecked = o.quantity;
                $scope.unexpectedItems.push(o);
                $scope.openAlertUnexpected($scope.unexpectedItems);
                qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanExpected(o));
                qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanUnexpected(o));
            } else {
                o.quantityPastChecked = o.quantityChecked + o.quantityPastChecked;
                qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanExpected(o));
            }
            o.quantityChecked = undefined;
            o.quantityToChecked = o.quantity - o.quantityPastChecked;

            // Update progress bar
            allQuantityPastChecked = allQuantityPastChecked + o.quantityPastChecked;
            $scope.parentobj.percent = allQuantityPastChecked / allQuantity * 100 + '%';
        };

        function commitUnknownItemToHistory() {
            qualityCheckService.qualityCheckHistoryScanUnknownOrUnexpected($scope.isUnknownScan,
                $scope.isUnexpectedScan,
                prepareDeclarationQualityCheckHistoryScanUnknownFromSelection());
        }

        // Find the errors and open the correct modal for each problem
        var findError = function() {
            if($scope.parentobj.activedRow.batch && $scope.parentobj.productBatch == undefined){
                // Need to enter a batch
                $scope.alertMessageContent = $filter('translate')('You need to enter a batch', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.serialNumber && $scope.parentobj.productSerial == undefined) {
                // Need to enter a serial number
                $scope.alertMessageContent = $filter('translate')('You need to enter a serial number', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.manufacturingDate && $scope.parentobj.productManufacturingDate == undefined){
                // Need to enter a manufacturing date
                $scope.alertMessageContent = $filter('translate')('You need to enter a manufacturing date', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.sellByDate && $scope.parentobj.productSellByDate == undefined){
                // Need to enter a sale date
                $scope.alertMessageContent = $filter('translate')('You need to enter a Sell By Date', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.useByDate && $scope.parentobj.productUseByDate == undefined){
                // Need to enter a use by date
                $scope.alertMessageContent = $filter('translate')('You need to enter a Use By Date', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.bestBeforeDate && $scope.parentobj.productBestBeforeDate == undefined){
                // Need to enter a best before date
                $scope.alertMessageContent = $filter('translate')('You need to enter a Best Before Date', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.featureString1 && $scope.parentobj.productFeatureString1 == undefined){
                // Need to enter feature string 1
                $scope.alertMessageContent = $filter('translate')('You need to enter feature string 1', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.featureString2 && $scope.parentobj.productFeatureString2 == undefined){
                // Need to enter feature string 2
                $scope.alertMessageContent = $filter('translate')('You need to enter feature string 2', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.featureDate1 && $scope.parentobj.productFeatureDate1 == undefined){
                // Need to enter feature date 1
                $scope.alertMessageContent = $filter('translate')('You need to enter feature date 1', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.countryOfOrigin && $scope.parentobj.productCountryOfOrigin == undefined){
                // Need to enter the country of origin
                $scope.alertMessageContent = $filter('translate')('You need to enter the country of origin', $scope.translateNamespace);
                openInfo();
            } else if($scope.parentobj.activedRow.batch && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'batch' : $scope.parentobj.productBatch}).length == 0) {
                // Batch false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The batch you have entered, didn\'t match any batch of the product from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.serialNumber && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'serialNumber' : $scope.parentobj.productSerial}).length == 0) {
                // Serial Number false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The serial number you have entered, didn\'t match any of the product serial number from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.manufacturingDate && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'manufacturingDate' : $scope.parentobj.productManufacturingDate}).length == 0) {
                // Manufacturing date false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The manufacturing date you have entered, didn\'t match any of the manufacturing dates from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.sellByDate && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'sellByDate' : $scope.parentobj.productSellByDate}).length == 0){
                // Sell by date false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The Sell By Date you have entered, didn\'t match any of the Sell By Dates from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.bestBeforeDate && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'bestBeforeDate' : $scope.parentobj.productBestBeforeDate}).length == 0) {
                // Best before date false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The Best Before Date you have entered, didn\'t match any of the Best Before Dates from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.useByDate && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'useByDate' : $scope.parentobj.productUseByDate}).length == 0) {
                // Use by date false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The Use By Date you have entered, didn\'t match any of the Use By Dates from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.featureString1 && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'featureString1' : $scope.parentobj.productFeatureString1}).length == 0) {
                // Feature string 1 false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The feature string 1 you have entered, didn\'t match any of the feature string 1 from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.featureString2 && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'featureString2' : $scope.parentobj.productFeatureString2}).length == 0) {
                // Feature string 2 false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The feature string 2 you have entered, didn\'t match any of the feature string 2 from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.featureDate1 && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'featureDate1' : $scope.parentobj.productFeatureDate1}).length == 0) {
                // Feature date 1 false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The feature date 1 you have entered, didn\'t match any of the feature date 1 from your package', $scope.translateNamespace);
                openAlert();
            } else if($scope.parentobj.activedRow.countryOfOrigin && _.filter($scope.packageItems, {'productCode' : $scope.parentobj.productCode, 'countryOfOrigin' : $scope.parentobj.productCountryOfOrigin}).length == 0) {
                // Feature string 2 false
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The country of origin you have entered, didn\'t match any of the country of origin from your package', $scope.translateNamespace);
                openAlert();
            } else {
                commitUnknownItemToHistory();
                $scope.alertMessageContent = $filter('translate')('The product you scanned, didn\'t match any expected product for your package', $scope.translateNamespace);
                openAlert();
            }
        };

        // Validate item selected in visual mode
        $scope.globalcheckAndUpdateQuantity = function (items) {

            angular.forEach(items, function (item) {
                item.quantityChecked = Number(item.quantityChecked);
                if (item.selected) {
                    item.unexpectedQuantity = undefined;
                    if (item.quantityChecked > item.quantityToChecked) {
                        item.unexpectedQuantity = item.quantityChecked - item.quantityToChecked;
                        item.quantityPastChecked = item.quantity;
                        $scope.unexpectedItems.push(item);
                        qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanExpected(item));
                        qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanUnexpected(item));
                    } else {
                        qualityCheckService.qualityCheckHistoryScan(prepareDeclarationQualityCheckHistoryScanExpected(item));
                        item.quantityPastChecked = item.quantityChecked + item.quantityPastChecked;
                    }
                    item.quantityChecked = undefined;
                    item.quantityToChecked = item.quantity - item.quantityPastChecked;
                    item.selected = false;

                    // Update progress bar
                    allQuantityPastChecked = allQuantityPastChecked + item.quantityPastChecked;
                    $scope.parentobj.percent = allQuantityPastChecked / allQuantity * 100 + '%';
                }
            });

            if ($scope.unexpectedItems.length > 0) {
                $scope.openAlertUnexpected($scope.unexpectedItems);
            }

            $scope.parentobj.activedRow = {};
            $scope.resetInputAndSelectionLine();
        };

        $scope.finishPackageChecking = function () {
            var nbLinesChecked = 0;
            var nbMissingLines = 0;
            var nbMissingLinesChecked = 0;
            var nbUncheckedLines = 0;
            $scope.selected = {motiveInfo: undefined};
            angular.forEach($scope.packageItems, function (item) {
                if ($scope.enumPickingType.MISSING.eq(item.pickingType)) {
                    nbMissingLines = nbMissingLines + 1;
                }
                if (item.quantityChecked + item.quantityPastChecked == item.quantity || item.quantityPastChecked == item.quantity) {
                    nbLinesChecked = nbLinesChecked + 1;
                } else if (!$scope.enumPickingType.MISSING.eq(item.pickingType)) {
                    nbUncheckedLines = nbUncheckedLines + 1;
                }
                if ($scope.enumPickingType.MISSING.eq(item.pickingType)) {
                    if (item.quantityChecked > 0 || item.quantityPastChecked > 0) {
                        nbMissingLinesChecked = nbMissingLinesChecked + 1;
                    }
                }
            });
            if (nbLinesChecked == $scope.packageItems.length - nbMissingLines &&
                nbMissingLinesChecked == 0 &&
                nbUncheckedLines == 0) {
                // All prepared item have been checked
                qualityCheckService.validateQualityCheck($scope.wmsQualityCheckHistoryId, $scope.packageItems.map(convertPackageItemsToValidation))
                    .then(function(preparationUnitLinesToCheck) {
                        if (preparationUnitLinesToCheck != null){
                            endAndNotifySuccess();
                        }
                    });
            } else {
                openAlertEnd(nbUncheckedLines > 0, nbMissingLinesChecked > 0);
            }
            $scope.resetInputAndSelectionLine();
            $scope.parentobj.itemQuantity = 1;
            $timeout(function () {
                focus('packageNumber');
            }, 100);
        };

        $scope.cancelPackageChecking = function() {
            cancelQualityCheckHistory();
            if($scope.puIsPresent) {
                $scope.workspace.back();
            } else {
                $scope.parentobj.stepNumber = '0';
                $scope.parentobj.packageNumber = undefined;
                $scope.resetInputAndSelectionLine();
                $timeout(function () {
                    focus('packageNumber');
                }, 100);
            }
        };

        $scope.openHistory = function () {
            var modalInstance = $uibModal.open({
                templateUrl: 'historyModalTemplate',
                backdrop: 'static',
                size: 'lg',
                scope: $scope
            });
            $scope.removeSelectedItem = function (item) {
                // Update progress bar
                allQuantityPastChecked = allQuantityPastChecked - item.quantityPastChecked;
                $scope.parentobj.percent = allQuantityPastChecked / allQuantity * 100 + '%';
                // Update item
                item.quantityChecked = item.quantityPastChecked;
                item.quantityPastChecked = 0;
                item.quantityToChecked = item.quantity;
                qualityCheckService.qualityCheckHistoryScanCancel($scope.wmsQualityCheckHistoryId, convertPackageItemsToValidation(item));
                item.quantityChecked = 0;
                // reset current input as soon as a controlled line is removed (otherwise may be very confusing)
                $scope.resetInputAndSelectionLine();
            };
            $scope.closeModal = function () {
                modalInstance.close();
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);

            };
        };

        $scope.openAlertUnexpected = function () {
            var modalInstance = $uibModal.open({
                templateUrl: 'alertUnexpectedModalTemplate',
                backdrop: 'static',
                size: 'md',
                scope: $scope
            });

            $scope.closeModal = function () {
                // Reset unexpected list
                $scope.unexpectedItems = [];
                modalInstance.close();
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);

            };
        };

        var openAlertEnd = function (withUnchecked, withMissingChecked) {
            var templateUrl = 'alertModalTemplate';
            if (withMissingChecked === true && withUnchecked === false) {
                templateUrl = 'alertMissingModalTemplate'
            }
            if (withMissingChecked === true && withUnchecked === true) {
                templateUrl = 'alertUncheckedMissingModalTemplate'
            }

            var modalInstance = $uibModal.open({
                templateUrl: templateUrl,
                backdrop: 'static',
                size: 'md',
                scope: $scope
            });

            $scope.closeModal = function () {
                modalInstance.close();
                $scope.motiveNeeded = false;
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);
            };

            $scope.continue = function () {
                qualityCheckService.validateQualityCheck($scope.wmsQualityCheckHistoryId, $scope.packageItems.map(convertPackageItemsToValidation))
                    .then(function(preparationUnitLinesToCheck) {
                        if (preparationUnitLinesToCheck != null){
                            checkDeliveryNotePrinting();
                        }
                        modalInstance.close();
                    });
            };
        };

        function convertPackageItemsToValidation(item, index) {
            var quantityChecked = 0;
            if (!angular.isUndefined(item.quantityChecked) && !isNaN(item.quantityChecked)){
                quantityChecked += item.quantityChecked;
            }
            if (!angular.isUndefined(item.quantityPastChecked) && !isNaN(item.quantityPastChecked)){
                quantityChecked += item.quantityPastChecked;
            }
            var refOperationMotiveId = undefined;
            if (angular.isDefined($scope.selected) && angular.isDefined($scope.selected.motiveInfo)){
                refOperationMotiveId = $scope.selected.motiveInfo.id;
            }
            return {
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                quantityExpected: item.quantity,
                quantityChecked: quantityChecked,
                wmsEnumPickingType: item.pickingType.value,
                wmsFeature: getWmsFeatureFromItem(item),
                serialNumber: item.serialNumber,
                refOperationMotiveId: refOperationMotiveId
            }
        };

        function getWmsFeatureFromItem(item) {
            var wmsFeature = undefined;
            if (!angular.isUndefined(item.batch) || !angular.isUndefined(item.manufacturingDate) ||
            !angular.isUndefined(item.sellByDate) || !angular.isUndefined(item.useByDate) ||
            !angular.isUndefined(item.bestBeforeDate) || !angular.isUndefined(item.featureString1) ||
            !angular.isUndefined(item.featureString2) || !angular.isUndefined(item.featureDate1) ||
            !angular.isUndefined(item.countryOfOrigin))
            {
                wmsFeature = {
                    batch : item.batch,
                    manufacturingDate : item.manufacturingDate,
                    sellByDate : item.sellByDate,
                    useByDate : item.useByDate,
                    bestBeforeDate : item.bestBeforeDate,
                    featureString1 : item.featureString1,
                    featureString2 : item.featureString2,
                    featureDate1 : item.featureDate1,
                    countryOfOrigin : item.countryOfOrigin
                }
            }
            return wmsFeature;
        }

        function prepareDeclarationQualityCheckHistoryScanUnknownFromSelection() {
            return {
                wmsQualityCheckHistoryId: $scope.wmsQualityCheckHistoryId,
                barcode: $scope.parentobj.barcodeScanned,
                quantity: Number($scope.parentobj.itemQuantity),
                wmsFeature: getWmsFeatureFromSelection(),
                serialNumber: $scope.parentobj.productSerial
            }
        }

        function getWmsFeatureFromSelection() {
            let wmsFeature = {
                batch : $scope.parentobj.productBatch,
                manufacturingDate : $scope.parentobj.productManufacturingDate,
                sellByDate : $scope.parentobj.productSellByDate,
                useByDate : $scope.parentobj.productUseByDate,
                bestBeforeDate : $scope.parentobj.productBestBeforeDate,
                featureString1 : $scope.parentobj.productFeatureString1,
                featureString2 : $scope.parentobj.productFeatureString2,
                featureDate1 : $scope.parentobj.productFeatureDate1,
                countryOfOrigin : $scope.parentobj.productCountryOfOrigin
            };
            if (Object.values(wmsFeature).every(field => field === undefined)) {
                return undefined;
            }
            return wmsFeature;
        }

        function prepareDeclarationQualityCheckHistoryScanExpected(item) {
            var quantityCheckedAndExpected = item.quantityChecked;
            if (angular.isDefined(item.unexpectedQuantity)) {
                quantityCheckedAndExpected = item.quantityChecked - item.unexpectedQuantity;
            }
            return {
                wmsQualityCheckHistoryId: $scope.wmsQualityCheckHistoryId,
                barcode: $scope.parentobj.barcodeScanned,
                quantity: quantityCheckedAndExpected,
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                wmsFeature: getWmsFeatureFromItem(item),
                serialNumber: item.serialNumber,
                expected: true
            }
        }

        function prepareDeclarationQualityCheckHistoryScanUnexpected(item) {
            return {
                wmsQualityCheckHistoryId: $scope.wmsQualityCheckHistoryId,
                barcode: $scope.parentobj.barcodeScanned,
                quantity: item.unexpectedQuantity,
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                wmsFeature: getWmsFeatureFromItem(item),
                serialNumber: item.serialNumber,
                expected: false
            }
        }

        function prepareDeclarationQualityCheckHistoryScanCancel(item) {
            return {
                refLogisticUnitSiteId: item.refLogisticUnitSiteId,
                quantityExpected: item.quantity,
                quantityChecked: item.quantityToChecked,
                wmsEnumPickingType: item.pickingType.value,
                wmsFeature: getWmsFeatureFromItem(item),
                serialNumber: item.serialNumber,
                refOperationMotiveId: undefined
            }
        }


        function cancelQualityCheckHistory() {
            if (!angular.isUndefined($scope.wmsQualityCheckHistoryId) && $scope.wmsQualityCheckHistoryId != null) {
                qualityCheckService.qualityCheckHistoryCancel($scope.wmsQualityCheckHistoryId);
            }
        }

        var checkDeliveryNotePrinting = function () {
            utilWmsPreparationUnitService.isDeliveryNoteNeeded($scope.parentobj.wmsPreparationUnitId)
            .then(function(isPrintNeeded) {
                if (isPrintNeeded === true){
                    // open modal to choose/confirm printer
                     var modalInstance = $uibModal.open({
                         templateUrl: 'printDeliveryNote',
                         controller:  'printDeliveryNoteController',
                         backdrop: 'static',
                         size: 'lg',
                         scope: $scope.$new()
                     });
                     modalInstance.result.then(function (result) {
                        if (result.confirm) {
                            utilWmsPreparationUnitService.printDeliveryNote($scope.parentobj.wmsPreparationUnitId, $scope.printer.reportExchange.id);
                        }
                        endAndNotifySuccess()
                    });                   
                } else {
                    endAndNotifySuccess()
                }
            });
        }

        var endAndNotifySuccess = function () {
            notification.success($filter('translate')('Box {{boxCode}} checked !', $scope.translateNamespace, {boxCode:$scope.parentobj.packageNumber}));
            if($scope.puIsPresent) {
                $scope.workspace.back();
            } else {
                $scope.parentobj.stepNumber = '0';
                $scope.parentobj.packageNumber = undefined;
                $timeout(function () {
                    focus('packageNumber');
                }, 100);
            }
        };

        function refreshVAS() {
            utilWmsPreparationUnitService.getPreparationUnitNeedsTypedVAS($scope.parentobj.packageNumber)
                .then(function(preparationUnitNeedsTypedVAS) {
                    $scope.VASCount = 0;
                    $scope.VASAllTerminated = true;

                    angular.forEach(preparationUnitNeedsTypedVAS, function(vasPuNeed) {
                        $scope.VASCount++;
                        $scope.VASAllTerminated = $scope.VASAllTerminated && isVASTerminated(vasPuNeed);
                    });
                });
        }

        function isVASTerminated(vasPuNeed) {
            return vasPuNeed.status.id != $scope.wmsPreparationUnitNeedStatuses.TO_DO.value.id;
        }

        var openAlert = function () {
            var modalInstance = $uibModal.open({
                templateUrl: 'alertNeededTemplate',
                backdrop: 'static',
                size: 'md',
                scope: $scope
            });
            $scope.removeItem = function () {
                $scope.resetInputAndSelectionLine();
                modalInstance.close();
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);
            };
        };

        var openInfo = function () {
            var modalInstance = $uibModal.open({
                templateUrl: 'infoNeededTemplate',
                backdrop: 'static',
                size: 'sm',
                scope: $scope
            });

            $scope.tryAgain = function () {
                modalInstance.close();
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);
            };
            $scope.removeItem = function () {
                $scope.resetInputAndSelectionLine();
                modalInstance.close();
                // Warning : focusing on another field is necessary to force ng-focus execution on 'code'
                focus('quantity');
                $timeout(function () {
                    focus('code');
                }, 100);
            };
        };
        $scope.openVASChecking = function() {
            $scope.activeVASChecking = true;

            var modalInstance = $uibModal.open({
                templateUrl: 'vasModalTemplate',
                controller: 'vasModalCtrl',
                backdrop: 'static',
                size: 'xl',
                scope: $scope
            });

            modalInstance.result.then(function() {
                $scope.activeVASChecking = false;
                refreshVAS();
            });
        };
        $scope.activeVASChecking = false;
    }])
;
Editor is loading...