Greasy Fork is available in English.

Virtonomica: Quick Price Set

Быстрая установка цены товаров в торговом зале.

Устаревшая версия на 16.03.2017. Перейти к последней версии.

// ==UserScript==
// @namespace      virtonomica
// @name           Virtonomica: Quick Price Set
// @description:en Quick installation prices of goods in the trading hall.
// @description:ru Быстрая установка цены товаров в торговом зале.
// @include        https://virtonomica*.*/*/main/unit/view/*/trading_hall
// @include        https://virtonomica.ru/*/main/unit/view/*/trading_hall
// @version        97
// @grant          AntiStream
// @description Quick installation prices of goods in the trading hall.
// ==/UserScript==

(function(window) {
	let run = function() {
		const VER = 97;

		//
		// Localization
		//

		let en_EN = {
			"minPriceCost": "% Minimum Price of Cost (if there is)",
			"targetPrice": "% Price of city price",
			"storeList": "Store List:",
			"addStoreToList": "Add Store To List",
			"removeStoreFromList": "Remove Store From List",
			"calcStorePrice": "Сalc Prices",
			"itsMagicFrame": "IT'S MAGIC IFRAME, RUN! (Сalculate the price for all stores from the list!)",
			"saveStoreConfig": "Save Config",
			"wait": "Wait...",
			"calcGroupPrice": "Сalc Group Price",
			"minPriceOff": "MinPrice(0=off)",
			"itemMul": "ItemPriceMul",
			"calcItemPrice": "Сalc Price",
			"rulesOfPricing": "Rules of pricing:",
			"rule1Dis": "IF market share less X%, THAT price is multiplied by Y",
			"rule2Dis": "IF market share greater X%, THAT price is multiplied by Y",
			"rule3Dis": "The adjustment of prices depending on quality of item and city: P * ((IQ / CQ) ^ (1 / X))",
			"rule4Dis": "The adjustment of prices depending on brand of item and city: P * (((1+IB) / (1+CB)) ^ (1 / X))",
			"addRule": "Add rule: ",
			"deleteRule": "Delete rule",
		};

		let ru_RU = {
			"minPriceCost": "% минимальной цены от себестоимости (если есть)",
			"targetPrice": "% цены от цены города",
			"storeList": "Список магазинов:",
			"addStoreToList": "Добавить магазин в список",
			"removeStoreFromList": "Удалить магазин из списка",
			"calcStorePrice": "Вычислить цену всего",
			"itsMagicFrame": "IT'S MAGIC IFRAME, RUN! (Вычислить цену для всего во всех магазинах из списка)",
			"saveStoreConfig": "Сохранить параметры",
			"wait": "Жди...",
			"calcGroupPrice": "Вычислить цены группы",
			"minPriceOff": "МинЦена(0=выкл)",
			"itemMul": "МножетельЦены",
			"calcItemPrice": "Вычислить цену",
			"rulesOfPricing": "Правила формирования цены:",
			"rule1Dis": "Если доля рынка меньше X%, то цена умножается на Y",
			"rule2Dis": "Если доля рынка больше X%, то цена умножается на Y",
			"rule3Dis": "Корректировка цены в зависимости от качества предмета и города: P * ((IQ / CQ) ^ (1 / X))",
			"rule4Dis": "Корректировка цены в зависимости от бренда предмета и города: P * (((1+IB) / (1+CB)) ^ (1 / X))",
			"addRule": "Добавить правило: ",
			"deleteRule": "Удалить правило",
		};

		let loc = (navigator.language || navigator.languages[0]) == "ru" ? ru_RU : en_EN;

		//
		// qps_mainCont
		//

		let $tbody = $("table.grid:eq(0) > tbody:eq(0)");
		$tbody.parent().before(`
			<div class="qps_mainCont">
				<h1>
					<a href="https://greasyfork.org/ru/scripts/8095-virtonomica-quick-price-set">Virtonomica: Quick Price Set</a> ${VER}
				</h1>
			</div>
		`);
		let $qps_mainCont = $(".qps_mainCont");
		const thisStoreUrl = window.location.toString();

		//
		// PRICE
		//

		$qps_mainCont.append(`
			<div>
				<div>
					${loc["rulesOfPricing"]}
				</div>

				<div>
					<input id='qps_minCostPrise' type='text' value='200'>${loc["minPriceCost"]}
				</div>

				<div style="margin-top: 2px;">
					<input id='qps_targetPrice' type='text' value='110'>${loc["targetPrice"]}
				</div>

				<div style="margin-top: 2px; background-color: #DADADA;">
					<div id="qps_rulesList">

					</div>

					<div style="margin-top: 2px;">
						<input id='qps_addRule' class='qps_button' type='button' value='${loc["addRule"]}'><select id="qps_ruleType">
							<option value="rule1">${loc["rule1Dis"]}</option>
							<option value="rule2">${loc["rule2Dis"]}</option>
							<option value="rule3">${loc["rule3Dis"]}</option>
							<option value="rule4">${loc["rule4Dis"]}</option>
						</select>
					</div>
				</div>
			</div>
		`);

		let $qps_minCostPrise = $("#qps_minCostPrise");
		let $qps_targetPrice = $("#qps_targetPrice");
		let $qps_rulesList = $("#qps_rulesList");

		let addRule = function(obj) {
			let ruleType = obj.type;
			if (["rule1", "rule2"].indexOf(ruleType) > -1) {
				$qps_rulesList.append(`
					<div rule_type="${ruleType}" style="margin-left: 2px;">
						<div>
							${
								loc[ruleType+"Dis"].
								replace("X", `<input class="qpsDol" type="text" size=4 value="${obj.dol}">`).
								replace("Y", `<input class="qpsMul" type="text" size=4 value="${obj.mul}">`)
							}
							<input type="button" value="${loc["deleteRule"]}" onclick="$(this).parent().parent().remove()">
						</div>
					</div>
				`);
			} else if (["rule3", "rule4"].indexOf(ruleType) > -1) {
				$qps_rulesList.append(`
					<div rule_type="${ruleType}" style="margin-left: 2px;">
						<div>
							${loc[ruleType+"Dis"].replace("X", `<input class="qpsX" type="text" size=4 value="${obj.x}">`)}
							<input type="button" value="${loc["deleteRule"]}" onclick="$(this).parent().parent().remove()">
						</div>
					</div>
				`);
			}
		};

		$("#qps_addRule").click(function() {
			let ruleType = $("#qps_ruleType").val();
			if (["rule1", "rule2"].indexOf(ruleType) > -1) {
				thisStoreData.rulesList.push({
					type: ruleType,
					dol: "100",
					mul: "1.0"
				});
				addRule({
					type: ruleType,
					dol: "100",
					mul: "1.0"
				});
			} else if (["rule3", "rule4"].indexOf(ruleType) > -1) {
				thisStoreData.rulesList.push({
					type: ruleType,
					x: "5",
				});
				addRule({
					type: ruleType,
					x: "5",
				});
			}
		});

		/* killer feature, unbalance! =)

		//
		// STORE LIST
		//

		$qps_mainCont.append(`
			<div style="margin-top: 10px;">
				<div>
					${loc["storeList"]}
				</div>
				<div id='qps_storeList' style="margin-left: 4px; margin-top: 4px;">

				</div>
				<div style="margin-top: 4px;">
					<input id='qps_addStoreToList' class='qps_button' type='button' value='${loc["addStoreToList"]}'>
				</div>
				<div>
					<input id='qps_removeStoreFromList' class='qps_button' type='button' value='${loc["removeStoreFromList"]}'>
				</div>
			</div>
		`);

		let storeList = JSON.parse(localStorage.getItem("storeList") || `{}`);
		let $qps_storeList = $("#qps_storeList");
		let $qps_addStoreToList = $("#qps_addStoreToList");
		let $qps_removeStoreFromList = $("#qps_removeStoreFromList");

		let drawStoreList = function() {
			$qps_storeList.empty();

			for (let store in storeList) {
				$qps_storeList.append(`
					<div store="${store}">
						${store}
					</div>
				`);
			}
		};
		drawStoreList();

		$qps_addStoreToList.click(function() {
			storeList[thisStoreUrl] = thisStoreUrl;
			localStorage.setItem("storeList", JSON.stringify(storeList));
			drawStoreList();
		});

		$qps_removeStoreFromList.click(function() {
			delete storeList[thisStoreUrl];
			localStorage.setItem("storeList", JSON.stringify(storeList));
			drawStoreList();
		});

		//
		// MAGIC IFRAME
		//

		$qps_mainCont.append(`
			<div style="margin-top: 10px;">
				<iframe id='qps_iframe' style="width:0;height:0;border:0;border:none;"></iframe>
				<input id='qps_iframeMagic' class='qps_button' type='button' value="${loc["itsMagicFrame"]}">
			</div>
		`);

		let $qps_iframe = $("#qps_iframe");
		let $qps_iframeMagic = $("#qps_iframeMagic");

		$qps_iframeMagic.click(function() {
			let $this = $(this);
			$this.attr("disabled", "disabled");
			$this.val(loc["wait"]);

			let $MIF = $qps_iframe;
			let stores = [];
			for (let store in storeList) {
				stores.push(store);
			}
			let index = -1;

			let endMagic = function() {
				window.location = window.location;
			};

			let nextStore = function() {
				index++;
				let firstLoad = true;
				let store = stores[index];

				$MIF.load(function() {
					if (firstLoad) {
						firstLoad = false;

						$qps_storeList.find(`div[store="${store}"]`).css("background-color", "yellow");

						$MIF.contents().find("#qps_calcStoreButton").click();
						setTimeout(function() {
							$MIF.contents().find("input[name='setprice']").click();
						}, 300);
					} else {
						setTimeout(function() {
							$qps_storeList.find(`div[store="${store}"]`).css("background-color", "green");
							nextStore();
						}, 3000);
					}
				});

				if (stores[index]) {
					$MIF.attr("src", stores[index]);
				} else {
					endMagic();
				}
			};
			nextStore();
		});

		*/

		//
		// SET STORE PRICE
		//

		$qps_mainCont.append(`
			<div style="margin-top: 2px;" class="qps_footer">
				<input id='qps_calcStoreButton' class='qps_button' type='button' value='${loc["calcStorePrice"]}'>
			</div>
		`);
		let $qps_footer = $qps_mainCont.children(".qps_footer:eq(0)");

		$("#qps_calcStoreButton").click(function() {
			setPrice(-1, -1);
		});

		//
		//	Store Config and Set Price
		//

		$qps_footer.append(`
				<input id='qps_saveStoreConfig' class='qps_button' type='button' value='${loc["saveStoreConfig"]}'>
				<input id="qps_savePrices" class='qps_button' type='button' value='${$("input[name='setprice']").val()}'>
		`);

		let thisStoreData = JSON.parse(localStorage.getItem(thisStoreUrl) || `{}`);
		thisStoreData.itemsMinPrice = thisStoreData.itemsMinPrice || {};
		thisStoreData.itemsPriceMult = thisStoreData.itemsPriceMult || {};
		thisStoreData.rulesList = thisStoreData.rulesList || [];

		if (thisStoreData.targetPriceType) {
			delete thisStoreData.targetPriceType;
		}

		$("#qps_savePrices").click(function() {
			$("input[name='setprice']").click();
		});

		if (thisStoreData.minPrice) {
			$qps_minCostPrise.val(thisStoreData.minPrice);
		}

		if (thisStoreData.targetPrice) {
			$qps_targetPrice.val(thisStoreData.targetPrice);
		}

		if (thisStoreData.rulesList.length > 0) {
			for (let rule of thisStoreData.rulesList) {
				addRule(rule);
			}
		} else {
			addRule({type: "rule2",dol: "90",mul: "1.05"});
			addRule({type: "rule1",dol: "30",mul: "0.95"});
		}

		$("#qps_saveStoreConfig").click(function() {
			thisStoreData = {};
			thisStoreData.minPrice = $qps_minCostPrise.val();
			thisStoreData.targetPrice = $qps_targetPrice.val();
			thisStoreData.itemsMinPrice = {};
			thisStoreData.itemsPriceMult = {};

			$tbody.children("tr").each(function() {
				let $tr = $(this);
				if ($tr.children("td").length > 1) {
					let itemType = $tr.children("td:eq(2)").attr("title").replace(/^(.*) \(.*$/, "$1");
					thisStoreData.itemsMinPrice[itemType] = $tr.children("td:eq(9)").find(".qps_minPrice:eq(0)").val();
					thisStoreData.itemsPriceMult[itemType] = $tr.children("td:eq(9)").find(".qps_priceMult:eq(0)").val().replace(",", ".");
				}
			});

			let tmpRls = [];
			$qps_rulesList.children().each(function() {
				$this = $(this);
				let ruleType = $this.attr("rule_type");

				if (["rule1", "rule2"].indexOf(ruleType) > -1) {
					tmpRls.push({
						type: ruleType,
						dol: $this.find(".qpsDol").val(),
						mul: $this.find(".qpsMul").val().replace(",", ".")
					});
				} else if (["rule3", "rule4"].indexOf(ruleType) > -1) {
					tmpRls.push({
						type: ruleType,
						x: $this.find(".qpsX").val().replace(",", "."),
					});
				}
			});
			thisStoreData.rulesList = tmpRls;

			thisStoreData.ver = VER;
			localStorage.setItem(thisStoreUrl, JSON.stringify(thisStoreData));
		});

		//
		// SET PRICE
		//

		let setPrice = function(group, item) {
			if (!Number.isFinite($qps_minCostPrise.val() - 0)) {
				$qps_minCostPrise.val($qps_minCostPrise.val() + "ERR!");
				return;
			}
			if (!Number.isFinite($qps_targetPrice.val() - 0)) {
				$qps_targetPrice.val($qps_targetPrice.val() + "ERR!");
				return;
			}

			let minPriceMultiplier = $qps_minCostPrise.val() * 0.01;
			let targetPriceMultiplier = $qps_targetPrice.val() * 0.01;

			let groupId = 0;
			let itemId = 0;

			$tbody.children("tr").each(function() {
				let $tr = $(this);

				if ($tr.children("td").length === 1) {
					groupId++;
				} else if ($tr.children("td").length > 1) {
					itemId++;
					if ((group === -1 || group === groupId) && (item === -1 || item === itemId)) {
						let $td10 = $tr.children("td:eq(9)"); // price input
						let $priceInput = $td10.children("input:eq(0)");

						const itemType = $tr.children("td:eq(2)").attr("title").replace(/^(.*) \(.*$/, "$1").trim();;
						let itemQuality = $tr.children("td:eq(6)").text().trim() - 0;
						let itemBrand = $tr.children("td:eq(7)").text().trim() - 0;
						let itemCost = $tr.children("td:eq(8)").text().trim().replace(" ", "").replace("$", "") - 0;

						const cityPrice = $tr.children("td:eq(11)").text().trim().replace(" ", "").replace("$", "") - 0;
						const cityQuality = $tr.children("td:eq(12)").text().trim() - 0;
						const cityBrand = $tr.children("td:eq(13)").text().trim() - 0;
						const marketShare = $tr.children("td:eq(10)").text().trim().replace(" ", "").replace("%", "") - 0;

						let currentPrice = $td10.children("input:eq(0)").val().trim().replace(" ", "") - 0;

						let targetPrice = 0;
						let minPrice = 0;
						let maxPrice = Number.POSITIVE_INFINITY;

						if (itemCost.toString() !== "NaN") {
							minPrice = itemCost * minPriceMultiplier;
						} else {
							itemCost = cityPrice;
							itemQuality = cityQuality;
						}

						let itemMinPrice = $td10.find("input.qps_minPrice").val();
						itemMinPrice = Number.isFinite(itemMinPrice - 0) ? (itemMinPrice - 0) : 0;
						if (itemMinPrice > 0) {
							minPrice = itemMinPrice;
						}

						targetPrice = cityPrice * targetPriceMultiplier;

						let itemPriceMult = $td10.find("input.qps_priceMult").val().replace(",", ".")-0;
						if (Number.isFinite(itemPriceMult)) {
							targetPrice *= itemPriceMult;
						}

						// Rules

						$qps_rulesList.children().each(function() {
							$this = $(this);
							let ruleType = $this.attr("rule_type");

							if (["rule1", "rule2"].indexOf(ruleType) > -1) {
								let rDol = $this.find(".qpsDol").val().replace(",", ".") - 0;
								let rMul = $this.find(".qpsMul").val().replace(",", ".") - 0;

								if (Number.isFinite(rDol) && Number.isFinite(rMul)) {
									if (
										(ruleType == "rule1" && marketShare < rDol) ||
										(ruleType == "rule2" && marketShare > rDol)
									) {
										targetPrice *= rMul;
									}
								}
							} else if (["rule3", "rule4"].indexOf(ruleType) > -1) {
								let rX = $this.find(".qpsX").val().replace(",", ".") - 0;

								if (Number.isFinite(rX)) {
									if (ruleType == "rule3") {
										targetPrice *= Math.pow(itemQuality / cityQuality, 1 / rX);
									} else if (ruleType == "rule4") {
										targetPrice *= Math.pow((1+itemBrand) / (1+cityBrand), 1 / rX);
									}
								}
							}
						});

						if (targetPrice < minPrice) {
							targetPrice = minPrice;
						}

						if (targetPrice > maxPrice) {
							targetPrice = maxPrice;
						}

						$td10.children("input:eq(0)").val(targetPrice.toFixed(2));
					}
				}
			});
		};

		let groupId = 0;
		let itemId = 0;
		$tbody.children("tr").each(function() {
			let $tr = $(this);

			if ($tr.children("td").length === 1) {
				(function(groupId) {
					$tr.append(`
						<div class="qps_cont">
							<input class='qps_button' type='button' value='${loc["calcGroupPrice"]}'>
						</div>
					`);
					$tr.find("input[class='qps_button']").click(function() {
						setPrice(groupId, -1);
					});
				})(++groupId);
			} else if ($tr.children("td").length > 1) {
				let $td10 = $tr.children("td:eq(9)");
				(function(groupId, itemId) {
					$td10.append(`
						<div class="qps_cont">
							<div>
								<div>
									Min<input class="qps_minPrice" size=11 placeholder="${loc["minPriceOff"]}" title="${loc["minPriceOff"]}" type="text" value="0">
								</div>
								<div>
									Mul<input class="qps_priceMult" size=11 placeholder="${loc["itemMul"]}" title="${loc["itemMul"]}" type="text" value="1.0">
								</div>
							</div>
							<div>
								<input class='qps_button' type='button' value='${loc["calcItemPrice"]}'>
							</div>
						</div>
					`);
					$td10.find("input[class='qps_button']").click(function() {
						setPrice(groupId, itemId);
					});
					let itemType = $tr.children("td:eq(2)").attr("title").replace(/^(.*) \(.*$/, "$1");
					if (thisStoreData.itemsMinPrice[itemType]) {
						$td10.find(".qps_minPrice:eq(0)").val(thisStoreData.itemsMinPrice[itemType] || "0");
						$td10.find(".qps_priceMult:eq(0)").val(thisStoreData.itemsPriceMult[itemType] || "1.0");
					}
				})(groupId, ++itemId);
			}
		});
	};

	$("head").append(
`<style>
.qps_button {
	background-color: green;
	color: white;
}
.qps_mainCont {
	background-color: #81cfef;
}
.qps_cont {
	background-color: #81cfef;
}
</style>`);

	let script = document.createElement("script");
	script.textContent = '(' + run.toString() + ')();';
	document.documentElement.appendChild(script);
})(window);