Raw Source
smashsports / Boxora

// ==UserScript==
// @name        Boxora
// @include     https://*.brightpearl.com/*p.php?p=print&output=basic&template-type-id=8*&action=template
// @include     https://*.brightpearl.com/*p.php?*report=product-goodsnote*
// @include     https://*.brightpearl.com/*report.php?*report_type=product_list*
// @include     https://*.brightpearl.com/*patt-op.php?scode=product*
// @include     https://*.brightpearl.com/*patt-op.php?scode=invoice*
// @downloadURL http://www.boxora.com/userscripts/Boxora.user.js
// @updateURL   http://www.boxora.com/userscripts/Boxora.user.js
// @version     1.19
// @grant       GM_xmlhttpRequest
// @grant       sandbox
// ==/UserScript==

var BoxoraShipment = new Array();
var BoxoraSettings = new Object();
var totalQtyToShip = 0;
var totalQtyScanned = 0;
var boxoraScriptMode = '';
var screenCode = 'none';
if (undefined != $("#screen-code").html() && $("#screen-code").html()) {
    screenCode = $("#screen-code").html(); // 4.90 format - use the specific span ID
} else if (undefined != $(".screen-code").html()) {
    screenCode = $(".screen-code").html(); // 4.88 format - use the wrapper
    screenCode = screenCode.replace(/\s/g, "");
    screenCode = screenCode.replace(/<strong>/g, "");
    screenCode = screenCode.replace(/<\/strong>/g, "");
}

console.log(screenCode);

if ( screenCode == "OPER-PROD-ADPR" ) {
	// Product edit screen (print barcodes)
    boxoraScriptMode = 'barcodeProduct';
	console.log(boxoraScriptMode);
    productID = $("#products_id").val();
    buttonHTML = '<a class="btn small" href="http://www.boxora.com/?p=label&productId='+productID+'">Print label</a>';
    $("#products_barcode").after(buttonHTML);    
    // Copy the product ID into the EAN field
    if ( $("#products_identifier_EAN").val() == "" && $("#products_id").val() > 0 ) {
        $("#products_identifier_EAN").val( $("#products_id").val() );
        $("#products_identifier_EAN").css("backgroundColor","#FFCC00").after('<span style="padding:4px;color:#CC0000;">EAN not yet saved</span>');
    }
} else if ( screenCode == "LIST-PROD-0000" ) {
    $("#moreActions").after(' <a href="#" id="print-labels-list">Print labels via Boxora</a> ');
} else if ( screenCode == "OPER-PURC-ADPO" ) {
    // Order edit (PO) screen (print barcodes)
    boxoraScriptMode = 'barcodeOrder';
	console.log(boxoraScriptMode);
    buttonHTML = '<a class="btn" id="print-labels">Get barcode labels</a>';
    $(".box-actions").before(buttonHTML);    
} else if ( screenCode == "LIST-SALE-NOTE" ) {
	// Goods out note list
    boxoraScriptMode = 'shipmentList';
	console.log(boxoraScriptMode);
	$('#page-controls').after('<form method="POST" id="barcodeScan"><div style="width:200px;"><input style="font-size:20px;width:200px;" type="text" id="goodsOutNoteBarcode" value="" placeholder="Scan barcode"></div></form>');
	$("#goodsOutNoteBarcode").focus();
	$( "#barcodeScan" ).submit(function( event ) {
		// Trim the scanned value
		var barcode = $("#goodsOutNoteBarcode").val().substring(1,10);
		barcode = parseInt(barcode);
		event.preventDefault();
		window.open( _BP.page.baseUrl+"p.php?p=print&output=basic&template-type-id=8&goodsnote-id="+barcode );
		$("#goodsOutNoteBarcode").val();
	});
} else if ( document.location.href.search("p=print") != -1 && document.location.href.search("%2C") == -1 ) {
    // We are on the goods out note screen, with a SINGLE goods out note
	// Hide all the action buttons
    boxoraScriptMode = 'shipmentPack';
	console.log(boxoraScriptMode);
	//$('#template-actions', window.parent.document).hide();

	// Audio handling : preload
	soundScanned    = loadAudio('http://www.boxora.com/sounds/scanned.ogg');
	soundError      = loadAudio('http://www.boxora.com/sounds/error.ogg');
	soundComplete   = loadAudio('http://www.boxora.com/sounds/complete.ogg');
	soundChing      = loadAudio('http://www.boxora.com/sounds/ching.ogg');
	soundBlip       = loadAudio('http://www.boxora.com/sounds/blip.ogg'); // trigger with ok

	filesToLoad = 5;
	filesLoaded = 0;

	// Insert the scanpack form
	$('div.print-template').before('<div id="scanPack" class="noprint" style="padding-left:10px;"><form method="POST" id="barcodeScan"><input type="text" name="scanItem" id="scanItem" value="" placeholder="Scan item barcode" style="font-size:20px"> <input type="text" style="font-size:20px" id="goodsOutNoteBarcode" value="" placeholder="Scan shipment barcode"> <a href="#" id="skipScanning">Skip scanning</a><button type="submit" style="display:inline;">go</button></form></div>');

	// If the goods out note is note yet packed, amend HTML, else packed, so sound the bell
	if ( $("#template-goods-note-actions-pack", window.parent.document).html() == "Pack" ) {
		// This shipment is due to be packed
		$("#scanItem").focus();

        $('#template-goods-note-actions-pack', window.parent.document).hide();
        $('#template-goods-note-actions-ship', window.parent.document).hide();
        
		// Add the scan columns to the end of the table
		$("table.items tr:first").append('<th class="noprint" style="border-bottom:2px solid #aaaaaa;">Scanned</th>');
        
		// Amend the table HTML
		var rowCount = 0;
		$("table.items tr:gt(0)").each( function() {
			
			if ( $(this).find('td.onthisorder').html() != "&nbsp;" ) {
				qty = parseInt($(this).find('td.onthisorder').html());
			} else {
				qty = 0;
			}

			barcode = $(this).find('td:nth-child(3)').html().replace("&nbsp;","");
			
			if ( barcode == "" || qty == 0 ) {
				$(this).append('<td class="noprint" style="text-align:center; border-bottom:1px solid #ccc; font-family:Arial; font-size:20px; font-weight:bold">-</td>');        
			} else {
				$(this).attr("id","row"+rowCount);        
				totalQtyToShip = totalQtyToShip + qty;	// all shippable items on the whole goods note
				
				$(this).append('<td class="noprint" style="text-align:center; border-bottom:1px solid #ccc; font-family:Arial; font-size:20px; font-weight:bold"><button class="manualScanRemove" id="remove'+rowCount+'"> - </button> <span id="scanned'+rowCount+'">0</span>/'+qty+' <button class="manualScanAdd" id="add'+rowCount+'"> + </button></td>');   
				$(this).css("backgroundColor","#FEEFB3");
				
				BoxoraShipment[rowCount] = new Array();
				BoxoraShipment[rowCount]["barcode"] = barcode;
				BoxoraShipment[rowCount]["qtyToShip"] = qty;
				BoxoraShipment[rowCount]["qtyScanned"] = 0;
            }
			
			rowCount++;

		});
        
	} else {
		// Found an unpack button, so we're packed
		soundChing.play();
		// Mark all lines as packed and scanned = to ship
        $("table.items tr:gt(0)").each( function() {
            $(this).css("backgroundColor","#DFF2BF");
            $(this).find("td").css("color","#4F8A10");        
        });
		// Focus on the scan goods note field
		$("#goodsOutNoteBarcode").focus();
	}

	$("#skipScanning").click( function() {
	   readyToPack();
	   return false;
	});

	$(".manualScanAdd").click( function() {
	   var rowId = $(this).attr("id").replace("add","");
	   scanItem(rowId,1,"row");
	   return false;
	});

	$(".manualScanRemove").click( function() {
	   var rowId = $(this).attr("id").replace("remove","");
	   scanItem(rowId,-1,"row");
        if ( BoxoraShipment[rowId]["qtyScanned"] != BoxoraShipment[rowId]["qtyToShip"] ) {
			$("#row"+rowId).css("backgroundColor","#FEEFB3");  
            $("#row"+rowId).find("td").css("color","#000000");     
        } 
	   return false;
	});

	// Handle the scan of the item or goods note
	$( "#barcodeScan" ).submit(function( event ) {

		event.preventDefault();
		
		if ( $("#scanItem").val() != "" ) {
			// Get the scanned barcode
			var itemId = $("#scanItem").val();        
			scanItem(itemId,1,"item");        
		} else {
			// Scanning a goods note
			// Trim the scanned value
			var barcode = $("#goodsOutNoteBarcode").val().substring(1,10);
			barcode = parseInt(barcode);
			event.preventDefault();
			window.top.location.href = _BP.page.baseUrl+"p.php?p=print&output=basic&template-type-id=8&goodsnote-id="+barcode;        
		} 
		
	});
} else {
	console.log("No script mode!");
}

// Get the settings from Boxora
// eg auto-pack
getBoxoraSettings();

// Print labels from PO
$(".box-buttons").delegate("#print-labels","click", function() {
    var labelUrl = 'http://www.boxora.com/?p=label&id-set=';
    var labelCount = 0;
    $.each( $(".rowCheckbox") , function(index,value) { 
        if ( $(value).prop("checked") == true ) {
        	productID = $(value).closest('tr').find(".products_id").val();
            if ( undefined != $(value).closest('tr').find(".rwQty").val() ) {
                qty = $(value).closest('tr').find(".rwQty").val();
            } else if ( undefined != $(value).closest('tr').find(".colQty input.validMoney").val() ) {
                qty = $(value).closest('tr').find(".colQty input.validMoney").val();
            } else {
             	qty = 1;   
            }
        	labelUrl += productID+':'+qty+',';  
            labelCount++;
        }
    });
    if ( labelCount > 0 ) {
        //alert(labelUrl);
        document.location.href = labelUrl;
    } else {
        alert("Please select at least one row to print labels");
    }
});

// Print labels from product list
$("#print-labels-list").click( function(){
    var labelUrl = 'http://www.boxora.com/?p=label&id-set=';
    var labelCount = 0;
    $.each( $(".rowCheckBox") , function(index,value) { 
        productID = $(value).attr("id").replace("checkBox_","");
        if ( $(value).is(":checked") ) {
        	labelUrl += productID+':1,';
            labelCount++;
        }
    });
    if (labelCount > 0) {
        console.log( labelUrl );
    	document.location.href = labelUrl;        
    }
});

/* -- FUNCTIONS -- */

function loadAudio(uri) {
    var audio = new Audio();
    audio.addEventListener('canplaythrough', isAppLoaded, false);
    audio.src = uri;
    return audio;
}

function isAppLoaded() {
    filesLoaded++;
    if (filesLoaded >= filesToLoad) {
        return true;
    }
}    

function scanItem(itemId, qty, idType) {
    
    // See if there is a row ID given (manual scan) else find a row with this item
    var rowId = -1;
    if ( idType == "row" ) {
        // Access the row directly
        rowId = itemId;
        qtyScanned = BoxoraShipment[itemId]["qtyScanned"];
        qtyToShip = BoxoraShipment[itemId]["qtyToShip"];
    } else {
        // We're scanning an item code, find a row with it
        for (var i=0;i<BoxoraShipment.length;i++) {
            if ( undefined != BoxoraShipment[i] && BoxoraShipment[i]["barcode"] == itemId ) {
                //alert(itemId+" found on row "+i);
        		qtyScanned = BoxoraShipment[i]["qtyScanned"];
        		qtyToShip = BoxoraShipment[i]["qtyToShip"]; 
                
                // If all of this item have been scanned keep looking
                // We will only be adding items by scanning codes (manual uses row ID)
                if ( qtyScanned == qtyToShip ) {
                    // continue, but set row ID to -2 to mark as found
                    rowId = -2;
                } else {
                	rowId = i;
                	break;                    
                }
            }
        }
    	if ( rowId == -1 ) {
            soundError.play();       
    	    alert(itemId+" was not found on this shipment");
    	    $("#scanItem").val("");
    	    return false;
        } else if ( rowId == -2 ) {
        	alert("You've already scanned all of this item");   
            return false;
        }
    }
    
    // Prevent user setting less than zero
    if ( qtyScanned == 0 && qty < 0 ) {
        return false;
    }
    
    // Prevent user setting more than due to ship
    if ( qtyScanned == qtyToShip && qty > 0 && parseInt(qtyToShip) > 0 ) {
        alert("You've already scanned all of this item");
        return false;
    }    
    
    qty = parseInt(qty);
    if ( qtyToShip == qtyScanned && parseInt(qtyToShip) > 0 && qty > 0 ) {
        alert("You've already scanned and packed all "+qtyToShip+" of this item");
        $("#scanItem").val("");
        return false;
    } else if ( qtyToShip > 0 ) {
        // Still some left to scan
        qtyScanned = parseInt(qtyScanned) + qty;
        totalQtyScanned = parseInt(totalQtyScanned) + qty;
        $("#scanned"+rowId).html( qtyScanned );
        if ( qtyToShip == qtyScanned ) {
            $("#row"+rowId).css("backgroundColor","#DFF2BF");
            $("#row"+rowId).find("td").css("color","#4F8A10");
        }
    } else if ( undefined == qtyToShip ) {
        soundError.play();        
        //alert("Could not find an item on this goods note with barcode "+itemId);
        $("#scanItem").val("").focus();
        return false;
    }
        
    // Set the data
    BoxoraShipment[rowId]["qtyScanned"] = qtyScanned;
    BoxoraShipment[rowId]["qtyToShip"] = qtyToShip;
    
    if ( totalQtyToShip == totalQtyScanned ) {
        soundComplete.play();
        readyToPack();
    } else {
    	$("#scanItem").val("");        
        soundScanned.play(); 
    }    
}

function readyToPack() {
    $('#template-goods-note-actions-pack', window.parent.document).show();
    $('#template-goods-note-actions-ship', window.parent.document).show();    
    $("#scanPack").hide();
    // Open the pack modal
    $("#template-goods-note-actions-pack", window.parent.document).click().delay(1000);
	if ( BoxoraSettings.extensionAutoPack == 1 ) {
		// Set as packed
		window.setTimeout( scanPackSetAsPacked, 3000 );
	}
}

function scanPackSetAsPacked() {
	var obj = window.parent.frames['popupiframe'].contentWindow.document.getElementById('submit');
    $(obj).click();
}

function getBoxoraSettings() {
	// Get the user settings from Boxora
    accountCode = $(".account-id").children(".white").html();
    console.log( "account code : "+accountCode );
    
    // Try the template
	if ( (undefined == accountCode || accountCode.length == 0) ) {
		// No settings can be got
		return false;
	}
    
    GM_xmlhttpRequest({
		method: "GET",
		url: "http://www.boxora.com/?p=log&account="+accountCode+"&v=1.19&op=getSettings&x="+boxoraScriptMode,
		onload: function(response) {
			BoxoraSettings = JSON.parse(response.responseText);
            if ( BoxoraSettings.account_id > 0 ) {
				console.log("Settings loaded OK from Boxora for "+accountCode);
			} else {
				alert("We could not load settings from Boxora for "+accountCode+" ... please ensure you have set up a Boxora account, and have added the HTML code to your packing note template.");
			}
            console.log(BoxoraSettings);
		}
	});
}