您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Корректирует закупки на склад при условии что поставщиков у каждого товара может быть несколько. Учитывает доступные остатки/ограничения_количества и пропорционально увеличивает/уменьшает закупку.
// ==UserScript== // @name Virtonomica: управление закупками на склад // @version 1.11 // @namespace Virtonomica // @description Корректирует закупки на склад при условии что поставщиков у каждого товара может быть несколько. Учитывает доступные остатки/ограничения_количества и пропорционально увеличивает/уменьшает закупку. // @include http*://*virtonomic*.*/*/main/unit/view/*/supply // ==/UserScript== var run = function() { //ждем заполнения .bg-image скриптом $( document ).ready(function() { var win = (typeof(unsafeWindow) != 'undefined' ? unsafeWindow : top.window); $ = win.$; var src = $('.bg-image').attr('class'); //если это не склад, выходим if(src.indexOf("warehouse") <= 0){ return; } function toFloat(spNum){ //console.log('toFloat = ' + spNum); if(spNum == null || spNum == '') { return 0; } return parseFloat(spNum.replace('$','').replace('"','').replace(/\s+/g,''),10); } function priceToFloat(spNum){ //console.log('priceToFloat = ' + spNum); if(spNum == null || spNum == '') { return 0; } var nvSlashPos = spNum.indexOf("/"); if(nvSlashPos > -1){ return toFloat(spNum.substr(nvSlashPos + 1)); } else { return toFloat(spNum); } } function remainToFloat(spNum){ //console.log('remainToFloat = ' + spNum); if(spNum == null || spNum == '') { return 0; } var nvSpanCloseTagPos = spNum.indexOf(">"); var nvBrPos = spNum.indexOf("<br>"); if(nvBrPos > -1){ var svNum = spNum.substr(nvSpanCloseTagPos+1, nvBrPos-nvSpanCloseTagPos-1); var nvInPos = svNum.indexOf("из"); if(nvInPos > -1){ return Math.min(toFloat(svNum.substr(0, nvInPos)), toFloat(svNum.substr(nvInPos+3))); } else { return toFloat(svNum); } } else { return toFloat(spNum); } } var data = []; function addProduct(spProductTitle, npQtyNeed, npQtyOrdered, opAddContras){ //console.log('addProduct "'+spProductTitle+'"'); data[spProductTitle] = { aContras : [] ,nQtyNeed : npQtyNeed ,nQtyOrdered : npQtyOrdered ,oAddContras : opAddContras }; } function addContras(spProductTitle, opInputOrderQty, npOrderedQty, npPrice, npQuality, npRemain){ //console.log('addContras "'+spProductTitle+'"'); data[spProductTitle].aContras.push({ oInputOrderQty : opInputOrderQty ,nOrderedQty : npOrderedQty ,nPrice : npPrice ,nQuality : npQuality ,nRemain : npRemain }); } function collectData(){ var svProductTitle = ''; data = []; $("table.list > tbody > tr[class]").each( function() { var row = $(this); if(row.attr('class') == 'p_title'){ //Отгрузки по контрактам // > td.p_title_l > div:nth-child(2) > table > tbody > tr > td:nth-child(2) > strong var nvQtyNeed = toFloat($('> td.p_title_l > div:nth-child(2) > table > tbody > tr:nth-child(3) > td:nth-child(2) > strong', row).first().text()); console.log('nvQtyNeed = ' + nvQtyNeed); var nvQtyOrdered = toFloat($('> td:nth-child(2) > nobr > strong', row).first().text()); console.log('nvQtyOrdered = ' + nvQtyOrdered); var ovProductImg = $('> td.p_title_l > div:nth-child(1) > div:nth-child(1) > div > img', row); var ovAddContras = $('> td.p_title_l > div:nth-child(1) > div:nth-child(2) > a:nth-child(2)', row); svProductTitle = ovProductImg.attr('title'); //console.log('svProductTitle = ' + svProductTitle); addProduct(svProductTitle, nvQtyNeed, nvQtyOrdered, ovAddContras); } else if (row.attr('class') == 'odd' || row.attr('class') == 'even'){ var ovInputOrderQty = $('> td:nth-child(2) > input[type="text"]:nth-child(1)', row); ovInputOrderQty.attr('old_val', ovInputOrderQty.val()); var nvOrderedQty = toFloat($('> td:nth-child(3)', row).first().text()); var nvPrice = priceToFloat($('> td:nth-child(4)', row).first().text()); var nvQuality = toFloat($('> td:nth-child(6)', row).first().text()); var nvRemain = remainToFloat($('> td:nth-child(9)', row).first().html()); if ($(' > td:nth-child(1) > div:nth-child(3) > img[src="/img/unit_types/seaport.gif"]', row).length > 0){ nvRemain = Number.POSITIVE_INFINITY; } addContras(svProductTitle, ovInputOrderQty, nvOrderedQty, nvPrice, nvQuality, nvRemain); } }); } function sortTable(){ var filtered = true; for(var producTitle in data){ //console.log(producTitle); var avContras = data[producTitle].aContras; var iterCnt = 0; do { filtered = true; for(var i = 0; i < avContras.length; i++) { if(i > 0 && avContras[i].nPrice / avContras[i].nQuality < avContras[i-1].nPrice / avContras[i-1].nQuality){ var tbody = avContras[i].oInputOrderQty.closest('tbody'); var prev = avContras[i-1].oInputOrderQty.closest('tr'); var prevClass = prev.attr('class'); var curr = avContras[i].oInputOrderQty.closest('tr'); var currClass = curr.attr('class'); prev.attr('class', currClass); curr.attr('class', prevClass); //console.log('move '+ (avContras[i].nPrice / avContras[i].nQuality) +' before '+(avContras[i-1].nPrice / avContras[i-1].nQuality)); prev.before(curr); var tmp = avContras[i-1]; avContras[i-1] = avContras[i]; avContras[i] = tmp; //tbody.insertBefore(curr, prev); filtered = false; } } iterCnt++; if (iterCnt > 10000){ console.log('зацикливание при сортировке или слишком много заказов продукта "'+producTitle+'"'); break; } } while (!filtered); } } function changeOrderQty(opInput, npQty){ var svOld = opInput.attr('old_val'); var svNew = npQty; if(opInput.prev().prop("tagName") == 'B'){ opInput.prev().remove(); } opInput.before('<b>'+svOld+'->'+svNew+'</b>'); opInput.val(npQty); } function scrollTo(element){ element.focus(); //var offset = element.offset().top; //$('html, body').animate({ scrollTop: offset }, 500); } function clearLog(){ $('#autoCorrectMessages').html(''); } function addToLog(opMsg){ $('#autoCorrectMessages').append('<br>').append(opMsg); } function oneToOne(){ clearLog(); for(var producTitle in data){ var avContras = data[producTitle].aContras; var nvQtyNeed = data[producTitle].nQtyNeed; var nvQtyOrdered = data[producTitle].nQtyOrdered; if(avContras.length == 0 && nvQtyNeed > 0){ scrollTo(data[producTitle].oAddContras); addToLog('Нужно добавить поставщика товара "'+producTitle+'"'); alert('Нужно добавить поставщика товара "'+producTitle+'"'); return; } else if(avContras.length == 1){ var nvOrderQty = toFloat(avContras[0].oInputOrderQty.val()); console.log('nvQtyNeed = '+nvQtyNeed); console.log('nvOrderQty = '+nvOrderQty); console.log('avContras[0].nRemain = '+avContras[0].nRemain); if(nvQtyNeed > avContras[0].nRemain){ scrollTo(data[producTitle].oAddContras); addToLog('Нужно добавить поставщика товара "'+producTitle+'"'); alert('Нужно добавить поставщика товара "'+producTitle+'"'); return; } else if (nvQtyNeed < avContras[0].nRemain && nvOrderQty != nvQtyNeed) { changeOrderQty(avContras[0].oInputOrderQty, nvQtyNeed); } } else { for(var i = 0; i < avContras.length; i++) { var nvOrderQty = toFloat(avContras[i].oInputOrderQty.val()); if(nvOrderQty > 0){ if(nvQtyNeed == 0){ changeOrderQty(avContras[i].oInputOrderQty, 0); } else { //console.log('nvOrderQty = '+nvOrderQty); //console.log('nRemain = '+avContras[i].nRemain); if(avContras[i].nRemain == 0){ changeOrderQty(avContras[i].oInputOrderQty, 0); nvQtyOrdered = nvQtyOrdered - nvOrderQty; } else if(avContras[i].nRemain < nvOrderQty){ changeOrderQty(avContras[i].oInputOrderQty, avContras[i].nRemain); nvQtyOrdered = nvQtyOrdered - (nvOrderQty - avContras[i].nRemain); } } } } if(nvQtyNeed < nvQtyOrdered){ var nvMissing = nvQtyNeed; for(var i = 0; i < avContras.length; i++) { var nvOrderQty = toFloat(avContras[i].oInputOrderQty.val()); if(nvOrderQty > 0){ var part = nvQtyOrdered / nvOrderQty; //console.log('nvQtyOrdered = '+nvQtyOrdered); //console.log('nvOrderQty = '+nvOrderQty); //console.log('part = '+part); var nvNew = Math.max(Math.round(nvQtyNeed / part), 0); //console.log('nvNew = '+nvNew); changeOrderQty(avContras[i].oInputOrderQty, nvNew); nvMissing = nvMissing - nvNew; } } if(nvMissing > 0){ console.log('nvMissing = '+nvMissing); for(var i = avContras.length - 1; i >= 0; i--) { var nvOrderQty = toFloat(avContras[i].oInputOrderQty.val()); if(nvOrderQty > 0){ var nvNew = Math.max(nvOrderQty - nvMissing, 0); changeOrderQty(avContras[i].oInputOrderQty, nvNew); nvMissing = nvMissing - nvNew; if(nvMissing <= 0){ break; } } } if(nvMissing > 0){ console.log('nvMissing = '+nvMissing); scrollTo(data[producTitle].oAddContras); addToLog('Нужно уменьшить поставки товара "'+producTitle+'"'); alert('Нужно уменьшить поставки товара "'+producTitle+'"'); return; } } } else if(nvQtyNeed > nvQtyOrdered){ var nvMissing = 0; for(var i = 0; i < avContras.length; i++) { var nvOrderQty = toFloat(avContras[i].oInputOrderQty.val()); if(nvOrderQty > 0){ var part = nvQtyOrdered / nvOrderQty; var nvNew = Math.min(Math.round(nvQtyNeed / part), avContras[i].nRemain); changeOrderQty(avContras[i].oInputOrderQty, nvNew); nvMissing = nvMissing + nvNew; } } if(nvMissing < nvQtyNeed){ console.log('nvMissing = '+nvMissing); for(var i = 0; i < avContras.length; i++) { var nvOrderQty = toFloat(avContras[i].oInputOrderQty.val()); if(nvOrderQty > 0){ var nvNew = Math.min(nvOrderQty + nvMissing, avContras[i].nRemain); changeOrderQty(avContras[i].oInputOrderQty, nvNew); nvMissing = nvMissing + nvNew; if(nvMissing >= nvQtyNeed){ break; } } } if(nvMissing < nvQtyNeed){ console.log('nvMissing = '+nvMissing); scrollTo(data[producTitle].oAddContras); addToLog('Нужно добавить поставщика товара "'+producTitle+'"'); alert('Нужно добавить поставщика товара "'+producTitle+'"'); return; } } } } } } function maxAvailable(){ clearLog(); for(var producTitle in data){ var avContras = data[producTitle].aContras; var nvQtyOrdered = data[producTitle].nQtyOrdered; for(var i = 0; i < avContras.length; i++) { changeOrderQty(avContras[i].oInputOrderQty, avContras[i].nRemain); } } } // кнопки var oneToOneBtn = $('<button>1:1</button>').click(function() { oneToOne(); }); var maxAvailableBtn = $('<button>max</button>').click(function() { maxAvailable(); }); $('#mainContent form').first().before(oneToOneBtn).before(maxAvailableBtn).before('<div id="autoCorrectMessages"></div>'); // collectData(); sortTable(); }); } // Хак, что бы получить полноценный доступ к DOM >:] var script = document.createElement("script"); script.textContent = '(' + run.toString() + ')();'; document.documentElement.appendChild(script);