Analyzes MP Stats data and suggests optimal pricing using Bayesian methods to maximize profit
Size
107.2 KB
Version
2.1.19
Created
Dec 10, 2025
Updated
4 days ago
1// ==UserScript==
2// @name OZON Price Optimizer with Bayesian Analysis
3// @description Analyzes MP Stats data and suggests optimal pricing using Bayesian methods to maximize profit
4// @version 2.1.19
5// @match https://*.ozon.ru/*
6// @icon https://st.ozone.ru/assets/favicon.ico
7// @grant GM.getValue
8// @grant GM.setValue
9// @grant GM.xmlhttpRequest
10// @require https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js
11// ==/UserScript==
12(function() {
13 'use strict';
14
15 console.log('🚀🚀🚀 OZON PRICE OPTIMIZER VERSION 2.0.1 LOADED 🚀🚀🚀');
16
17 // Product data mapping (артикул -> себестоимость, комиссия, доставка)
18 const PRODUCT_DATA = {
19'1740824669': { cost: 146.4, commission: 0.39, delivery: 105 },
20 '1157786755': { cost: 159.6, commission: 0.39, delivery: 105 },
21 '1126896590': { cost: 111.6, commission: 0.39, delivery: 105 },
22 '1643994739': { cost: 242.4, commission: 0.39, delivery: 105 },
23 '1672597444': { cost: 130.8, commission: 0.39, delivery: 105 },
24 '1220422423': { cost: 115.2, commission: 0.39, delivery: 105 },
25 '1791969680': { cost: 258, commission: 0.39, delivery: 105 },
26 '1134301258': { cost: 117.6, commission: 0.39, delivery: 105 },
27 '881812095': { cost: 219.6, commission: 0.39, delivery: 105 },
28 '476573272': { cost: 198, commission: 0.39, delivery: 105 },
29 '1091687376': { cost: 133.2, commission: 0.39, delivery: 105 },
30 '1865971423': { cost: 213.6, commission: 0.39, delivery: 105 },
31 '1091884893': { cost: 115.2, commission: 0.39, delivery: 105 },
32 '1509173668': { cost: 146.4, commission: 0.39, delivery: 105 },
33 '1643957952': { cost: 154.8, commission: 0.39, delivery: 105 },
34 '1615018099': { cost: 216, commission: 0.39, delivery: 105 },
35 '1149665681': { cost: 92.4, commission: 0.39, delivery: 105 },
36 '1042512806': { cost: 118.8, commission: 0.39, delivery: 105 },
37 '1586302587': { cost: 200.4, commission: 0.39, delivery: 105 },
38 '1915136286': { cost: 199.2, commission: 0.39, delivery: 105 },
39 '1061692407': { cost: 188.4, commission: 0.39, delivery: 105 },
40 '907545404': { cost: 199.2, commission: 0.39, delivery: 105 },
41 '701748607': { cost: 124.8, commission: 0.39, delivery: 105 },
42 '1464498458': { cost: 147.6, commission: 0.39, delivery: 105 },
43 '1423324644': { cost: 117.6, commission: 0.39, delivery: 105 },
44 '847234813': { cost: 146.4, commission: 0.39, delivery: 105 },
45 '1644305207': { cost: 236.4, commission: 0.39, delivery: 105 },
46 '1220412279': { cost: 110.4, commission: 0.39, delivery: 105 },
47 '1440280204': { cost: 172.8, commission: 0.39, delivery: 105 },
48 '881841274': { cost: 182.4, commission: 0.39, delivery: 105 },
49 '881911476': { cost: 162, commission: 0.39, delivery: 105 },
50 '1558183265': { cost: 151.2, commission: 0.39, delivery: 105 },
51 '442408015': { cost: 213.6, commission: 0.39, delivery: 105 },
52 '1323322968': { cost: 175.2, commission: 0.39, delivery: 105 },
53 '524540150': { cost: 138, commission: 0.39, delivery: 105 },
54 '1648863445': { cost: 172.8, commission: 0.39, delivery: 105 },
55 '1646939718': { cost: 157.2, commission: 0.39, delivery: 105 },
56 '1205194839': { cost: 153.6, commission: 0.39, delivery: 105 },
57 '645226241': { cost: 158.4, commission: 0.39, delivery: 105 },
58 '2007243137': { cost: 291.6, commission: 0.39, delivery: 105 },
59 '1421135622': { cost: 91.2, commission: 0.39, delivery: 105 },
60 '701884874': { cost: 116.4, commission: 0.39, delivery: 105 },
61 '1421119246': { cost: 158.4, commission: 0.39, delivery: 105 },
62 '2007259608': { cost: 307.2, commission: 0.39, delivery: 105 },
63 '359062751': { cost: 122.4, commission: 0.39, delivery: 105 },
64 '1005718040': { cost: 158.4, commission: 0.39, delivery: 105 },
65 '906225589': { cost: 96, commission: 0.39, delivery: 105 },
66 '1556242664': { cost: 680.4, commission: 0.39, delivery: 105 },
67 '1064594212': { cost: 148.8, commission: 0.39, delivery: 105 },
68 '799768912': { cost: 122.4, commission: 0.39, delivery: 105 },
69 '1739604132': { cost: 217.2, commission: 0.39, delivery: 105 },
70 '1062956956': { cost: 136.8, commission: 0.39, delivery: 105 },
71 '645221613': { cost: 144, commission: 0.39, delivery: 105 },
72 '259307672': { cost: 154.8, commission: 0.39, delivery: 105 },
73 '1739610762': { cost: 214.8, commission: 0.39, delivery: 105 },
74 '261137335': { cost: 130.8, commission: 0.39, delivery: 105 },
75 '1134258903': { cost: 120, commission: 0.39, delivery: 105 },
76 '1354364340': { cost: 140.4, commission: 0.39, delivery: 105 },
77 '583903282': { cost: 105.6, commission: 0.39, delivery: 105 },
78 '1210396815': { cost: 152.4, commission: 0.39, delivery: 105 },
79 '840692395': { cost: 140.4, commission: 0.39, delivery: 105 },
80 '1428754652': { cost: 117.6, commission: 0.39, delivery: 105 },
81 '830793833': { cost: 141.6, commission: 0.39, delivery: 105 },
82 '645231878': { cost: 122.4, commission: 0.39, delivery: 105 },
83 '1638790412': { cost: 147.6, commission: 0.39, delivery: 105 },
84 '1594351493': { cost: 148.8, commission: 0.39, delivery: 105 },
85 '1556059491': { cost: 472.8, commission: 0.39, delivery: 105 },
86 '1652932872': { cost: 166.8, commission: 0.39, delivery: 105 },
87 '1220450238': { cost: 141.6, commission: 0.39, delivery: 105 },
88 '601543246': { cost: 133.2, commission: 0.39, delivery: 105 },
89 '907613435': { cost: 156, commission: 0.39, delivery: 105 },
90 '528451380': { cost: 109.2, commission: 0.39, delivery: 105 },
91 '645231366': { cost: 111.6, commission: 0.39, delivery: 105 },
92 '1583090470': { cost: 211.2, commission: 0.39, delivery: 105 },
93 '645344262': { cost: 217.2, commission: 0.39, delivery: 105 },
94 '1427430872': { cost: 135.6, commission: 0.39, delivery: 105 },
95 '308474502': { cost: 135.6, commission: 0.39, delivery: 105 },
96 '1034686951': { cost: 110.4, commission: 0.39, delivery: 105 },
97 '1635265452': { cost: 164.4, commission: 0.39, delivery: 105 },
98 '1181294718': { cost: 136.8, commission: 0.39, delivery: 105 },
99 '907477992': { cost: 111.6, commission: 0.39, delivery: 105 },
100 '275785773': { cost: 105.6, commission: 0.39, delivery: 105 },
101 '415116965': { cost: 129.6, commission: 0.39, delivery: 105 },
102 '885661840': { cost: 132, commission: 0.39, delivery: 105 },
103 '1138405158': { cost: 123.6, commission: 0.39, delivery: 105 },
104 '1474598641': { cost: 153.6, commission: 0.39, delivery: 105 },
105 '1749441319': { cost: 156, commission: 0.39, delivery: 105 },
106 '983496770': { cost: 180, commission: 0.39, delivery: 105 },
107 '259307514': { cost: 121.2, commission: 0.39, delivery: 105 },
108 '1412471842': { cost: 147.6, commission: 0.39, delivery: 105 },
109 '2007285388': { cost: 260.4, commission: 0.39, delivery: 105 },
110 '753545450': { cost: 105.6, commission: 0.39, delivery: 105 },
111 '414662752': { cost: 145.2, commission: 0.39, delivery: 105 },
112 '906537851': { cost: 120, commission: 0.39, delivery: 105 },
113 '745134928': { cost: 120, commission: 0.39, delivery: 105 },
114 '1450813313': { cost: 171.6, commission: 0.39, delivery: 105 },
115 '815579726': { cost: 108, commission: 0.39, delivery: 105 },
116 '1554889144': { cost: 172.8, commission: 0.39, delivery: 105 },
117 '1317529509': { cost: 108, commission: 0.39, delivery: 105 },
118 '1412482622': { cost: 201.6, commission: 0.39, delivery: 105 },
119 '711457941': { cost: 116.4, commission: 0.39, delivery: 105 },
120 '746323388': { cost: 166.8, commission: 0.39, delivery: 105 },
121 '1678615312': { cost: 144, commission: 0.39, delivery: 105 },
122 '1261461822': { cost: 93.6, commission: 0.39, delivery: 105 },
123 '601551066': { cost: 144, commission: 0.39, delivery: 105 },
124 '1440304060': { cost: 218.4, commission: 0.39, delivery: 105 },
125 '1363004944': { cost: 132, commission: 0.39, delivery: 105 },
126 '583586841': { cost: 162, commission: 0.39, delivery: 105 },
127 '701743635': { cost: 112.8, commission: 0.39, delivery: 105 },
128 '483752519': { cost: 114, commission: 0.39, delivery: 105 },
129 '254240996': { cost: 110.4, commission: 0.39, delivery: 105 },
130 '711403910': { cost: 105.6, commission: 0.39, delivery: 105 },
131 '701745855': { cost: 111.6, commission: 0.39, delivery: 105 },
132 '483722993': { cost: 123.6, commission: 0.39, delivery: 105 },
133 '265381213': { cost: 109.2, commission: 0.39, delivery: 105 },
134 '1865968664': { cost: 189.6, commission: 0.39, delivery: 105 },
135 '1361974814': { cost: 127.2, commission: 0.39, delivery: 105 },
136 '1711210766': { cost: 154.8, commission: 0.39, delivery: 105 },
137 '1430070632': { cost: 117.6, commission: 0.39, delivery: 105 },
138 '645347197': { cost: 111.6, commission: 0.39, delivery: 105 },
139 '601547006': { cost: 111.6, commission: 0.39, delivery: 105 },
140 '1554898780': { cost: 159.6, commission: 0.39, delivery: 105 },
141 '576759419': { cost: 146.4, commission: 0.39, delivery: 105 },
142 '361963040': { cost: 145.2, commission: 0.39, delivery: 105 },
143 '1588873517': { cost: 144, commission: 0.39, delivery: 105 },
144 '701743610': { cost: 94.8, commission: 0.39, delivery: 105 },
145 '362561005': { cost: 126, commission: 0.39, delivery: 105 },
146 '1638838932': { cost: 142.8, commission: 0.39, delivery: 105 },
147 '1586310017': { cost: 175.2, commission: 0.39, delivery: 105 },
148 '265381147': { cost: 112.8, commission: 0.39, delivery: 105 },
149 '799722971': { cost: 138, commission: 0.39, delivery: 105 },
150 '701746001': { cost: 133.2, commission: 0.39, delivery: 105 },
151 '885718701': { cost: 129.6, commission: 0.39, delivery: 105 },
152 '627707226': { cost: 135.6, commission: 0.39, delivery: 105 },
153 '907359259': { cost: 157.2, commission: 0.39, delivery: 105 },
154 '1422546406': { cost: 127.2, commission: 0.39, delivery: 105 },
155 '711392959': { cost: 123.6, commission: 0.39, delivery: 105 },
156 '701739222': { cost: 109.2, commission: 0.39, delivery: 105 },
157 '799782895': { cost: 120, commission: 0.39, delivery: 105 },
158 '905741712': { cost: 145.2, commission: 0.39, delivery: 105 },
159 '627696549': { cost: 153.6, commission: 0.39, delivery: 105 },
160 '627691916': { cost: 126, commission: 0.39, delivery: 105 },
161 '1525587675': { cost: 94.8, commission: 0.39, delivery: 105 },
162 '518696433': { cost: 118.8, commission: 0.39, delivery: 105 },
163 '1915145626': { cost: 94.8, commission: 0.39, delivery: 105 },
164 '1915134983': { cost: 92.4, commission: 0.39, delivery: 105 },
165 '1617625622': { cost: 669.6, commission: 0.39, delivery: 105 },
166 '2151674296': { cost: 294, commission: 0.39, delivery: 105 },
167 '1688371971': { cost: 213.6, commission: 0.39, delivery: 105 },
168 '2007269923': { cost: 348, commission: 0.39, delivery: 105 },
169 '1619711279': { cost: 535.2, commission: 0.39, delivery: 105 },
170 '1556227793': { cost: 598.8, commission: 0.39, delivery: 105 },
171 '1556213113': { cost: 624, commission: 0.39, delivery: 105 },
172 '1556033933': { cost: 805.2, commission: 0.39, delivery: 105 },
173 '1614280315': { cost: 711.6, commission: 0.39, delivery: 105 },
174 '1623554699': { cost: 613.2, commission: 0.39, delivery: 105 },
175 '1614312529': { cost: 598.8, commission: 0.39, delivery: 105 },
176 '1556157230': { cost: 568.8, commission: 0.39, delivery: 105 },
177 '1621230498': { cost: 567.6, commission: 0.39, delivery: 105 },
178 '1556203577': { cost: 487.2, commission: 0.39, delivery: 105 },
179 '1619457861': { cost: 476.4, commission: 0.39, delivery: 105 },
180 '1691210828': { cost: 118.8, commission: 0.39, delivery: 105 },
181 '1643979499': { cost: 309.6, commission: 0.39, delivery: 105 },
182 '1467776379': { cost: 175.2, commission: 0.39, delivery: 105 },
183 '881795381': { cost: 204, commission: 0.39, delivery: 105 },
184 '815257353': { cost: 126, commission: 0.39, delivery: 105 },
185 '2196230178': { cost: 96.168, commission: 0.39, delivery: 105 },
186 '2196231035': { cost: 97.332, commission: 0.39, delivery: 105 },
187 '2524038158': { cost: 97.392, commission: 0.39, delivery: 105 },
188 '2196231426': { cost: 97.596, commission: 0.39, delivery: 105 },
189 '2196232023': { cost: 119.916, commission: 0.39, delivery: 105 },
190 '2196243941': { cost: 129.12, commission: 0.39, delivery: 105 },
191 '2196234143': { cost: 134.58, commission: 0.39, delivery: 105 },
192 '320244429': { cost: 158.4, commission: 0.3, delivery: 90 },
193 '240637697': { cost: 108, commission: 0.3, delivery: 90 },
194 '608450235': { cost: 126, commission: 0.3, delivery: 90 },
195 '946421600': { cost: 103.2, commission: 0.3, delivery: 90 },
196 '496076761': { cost: 166.8, commission: 0.3, delivery: 90 },
197 '1413311039': { cost: 135.6, commission: 0.3, delivery: 90 },
198 '440778548': { cost: 708, commission: 0.3, delivery: 90 },
199 '523217298': { cost: 219.6, commission: 0.3, delivery: 90 },
200 '384090220': { cost: 103.2, commission: 0.3, delivery: 90 },
201 '496052718': { cost: 163.2, commission: 0.3, delivery: 90 },
202 '608424787': { cost: 116.4, commission: 0.3, delivery: 90 },
203 '710687654': { cost: 110.4, commission: 0.3, delivery: 90 },
204 '302313862': { cost: 146.4, commission: 0.3, delivery: 90 },
205 '275431854': { cost: 90, commission: 0.3, delivery: 90 },
206 '629089591': { cost: 111.6, commission: 0.3, delivery: 90 },
207 '445990016': { cost: 104.4, commission: 0.3, delivery: 90 },
208 '269055046': { cost: 177.6, commission: 0.3, delivery: 90 },
209 '1006091512': { cost: 100.8, commission: 0.3, delivery: 90 },
210 '541317459': { cost: 163.2, commission: 0.3, delivery: 90 },
211 '643867409': { cost: 170.4, commission: 0.3, delivery: 90 },
212 '1742879159': { cost: 172.8, commission: 0.3, delivery: 90 },
213 '723677583': { cost: 115.2, commission: 0.3, delivery: 90 },
214 '1162597065': { cost: 96, commission: 0.3, delivery: 90 },
215 '240618618': { cost: 117.6, commission: 0.3, delivery: 90 },
216 '308612909': { cost: 286.8, commission: 0.3, delivery: 90 },
217 '641019479': { cost: 90, commission: 0.3, delivery: 90 },
218 '415367670': { cost: 87.6, commission: 0.3, delivery: 90 },
219 '1755740945': { cost: 135.6, commission: 0.3, delivery: 90 },
220 '605720925': { cost: 121.2, commission: 0.3, delivery: 90 },
221 '1787685452': { cost: 124.8, commission: 0.3, delivery: 90 },
222 '930467608': { cost: 312, commission: 0.3, delivery: 90 },
223 '1675833489': { cost: 138, commission: 0.3, delivery: 90 },
224 '523205834': { cost: 120, commission: 0.3, delivery: 90 },
225 '955365874': { cost: 126, commission: 0.3, delivery: 90 },
226 '765946072': { cost: 174, commission: 0.3, delivery: 90 },
227 '302313862': { cost: 146.4, commission: 0.3, delivery: 90 },
228 '275431854': { cost: 90, commission: 0.3, delivery: 90 },
229 '629089591': { cost: 111.6, commission: 0.3, delivery: 90 },
230 '445990016': { cost: 104.4, commission: 0.3, delivery: 90 },
231 '269055046': { cost: 177.6, commission: 0.3, delivery: 90 },
232 '1006091512': { cost: 100.8, commission: 0.3, delivery: 90 },
233 '541317459': { cost: 163.2, commission: 0.3, delivery: 90 },
234 '643867409': { cost: 170.4, commission: 0.3, delivery: 90 },
235 '1742879159': { cost: 172.8, commission: 0.3, delivery: 90 },
236 '723677583': { cost: 115.2, commission: 0.3, delivery: 90 },
237 '1162597065': { cost: 96, commission: 0.3, delivery: 90 },
238 '240618618': { cost: 117.6, commission: 0.3, delivery: 90 },
239 '308612909': { cost: 286.8, commission: 0.3, delivery: 90 },
240 '641019479': { cost: 90, commission: 0.3, delivery: 90 },
241 '415367670': { cost: 87.6, commission: 0.3, delivery: 90 },
242 '1755740945': { cost: 135.6, commission: 0.3, delivery: 90 },
243 '605720925': { cost: 121.2, commission: 0.3, delivery: 90 },
244 '1787685452': { cost: 124.8, commission: 0.3, delivery: 90 },
245 '930467608': { cost: 312, commission: 0.3, delivery: 90 },
246 '1675833489': { cost: 138, commission: 0.3, delivery: 90 },
247 '523205834': { cost: 120, commission: 0.3, delivery: 90 },
248 '955365874': { cost: 126, commission: 0.3, delivery: 90 },
249 '765946072': { cost: 174, commission: 0.3, delivery: 90 },
250 '302474910': { cost: 155.376, commission: 0.3, delivery: 90 },
251 '496313974': { cost: 112.8, commission: 0.3, delivery: 90 },
252 '235921201': { cost: 96, commission: 0.3, delivery: 90 },
253 '257759548': { cost: 129.6, commission: 0.3, delivery: 90 },
254 '1423368794': { cost: 96, commission: 0.3, delivery: 90 },
255 '496162051': { cost: 100.8, commission: 0.3, delivery: 90 },
256 '256464706': { cost: 91.2, commission: 0.3, delivery: 90 },
257 '256403990': { cost: 100.8, commission: 0.3, delivery: 90 },
258 '496078352': { cost: 150, commission: 0.3, delivery: 90 },
259 '439787475': { cost: 128.4, commission: 0.3, delivery: 90 },
260 '2246237790': { cost: 352.8, commission: 0.3, delivery: 90 },
261 '1162432442': { cost: 162, commission: 0.3, delivery: 90 },
262 '496385269': { cost: 117.6, commission: 0.3, delivery: 90 },
263 '235747007': { cost: 123.6, commission: 0.3, delivery: 90 },
264 '240596679': { cost: 82.8, commission: 0.3, delivery: 90 },
265 '946386913': { cost: 67.416, commission: 0.3, delivery: 90 },
266 '1077386569': { cost: 264, commission: 0.3, delivery: 90 },
267 '342033120': { cost: 186, commission: 0.3, delivery: 90 },
268 '327212556': { cost: 88.8, commission: 0.3, delivery: 90 },
269 '257870717': { cost: 133.476, commission: 0.3, delivery: 90 },
270 '523338483': { cost: 165.6, commission: 0.3, delivery: 90 },
271 '955212015': { cost: 175.2, commission: 0.3, delivery: 90 },
272 '2937015180': { cost: 229.2, commission: 0.3, delivery: 90 },
273 '322211321': { cost: 123.6, commission: 0.3, delivery: 90 },
274 '821056923': { cost: 127.2, commission: 0.3, delivery: 90 },
275 '607930809': { cost: 218.4, commission: 0.3, delivery: 90 },
276 '605645338': { cost: 144, commission: 0.3, delivery: 90 },
277 '309603422': { cost: 194.4, commission: 0.3, delivery: 90 },
278 '496192068': { cost: 118.8, commission: 0.3, delivery: 90 },
279 '1225837045': { cost: 192, commission: 0.3, delivery: 90 },
280 '2975092428': { cost: 0, commission: 0.3, delivery: 90 },
281 '2925851542': { cost: 0, commission: 0.3, delivery: 90 },
282 '256499007': { cost: 124.8, commission: 0.3, delivery: 90 },
283 '631642752': { cost: 97.2, commission: 0.3, delivery: 90 },
284 '772649191': { cost: 80.4, commission: 0.3, delivery: 90 },
285 '1609663001': { cost: 217.2, commission: 0.3, delivery: 90 },
286 '530615077': { cost: 108, commission: 0.3, delivery: 90 },
287 '879257026': { cost: 160.8, commission: 0.3, delivery: 90 },
288 '1074695072': { cost: 176.4, commission: 0.3, delivery: 90 },
289 '697745723': { cost: 121.2, commission: 0.3, delivery: 90 },
290 '736971656': { cost: 111.6, commission: 0.3, delivery: 90 },
291 '951571515': { cost: 145.2, commission: 0.3, delivery: 90 },
292 '1773186071': { cost: 220.8, commission: 0.3, delivery: 90 },
293 '203461072': { cost: 204, commission: 0.3, delivery: 90 },
294 '496104827': { cost: 114, commission: 0.3, delivery: 90 },
295 '292190882': { cost: 102, commission: 0.3, delivery: 90 },
296 '1653722295': { cost: 218.4, commission: 0.3, delivery: 90 },
297 '1122871855': { cost: 216, commission: 0.3, delivery: 90 },
298 '1931646505': { cost: 136.8, commission: 0.3, delivery: 90 },
299 '439682438': { cost: 69.6, commission: 0.3, delivery: 90 },
300 '496210001': { cost: 72, commission: 0.3, delivery: 90 },
301 '1620775285': { cost: 112.8, commission: 0.3, delivery: 90 },
302 '1617839244': { cost: 114, commission: 0.3, delivery: 90 },
303 '1787676082': { cost: 243.6, commission: 0.3, delivery: 90 },
304 '631658690': { cost: 91.2, commission: 0.3, delivery: 90 },
305 '257885915': { cost: 133.488, commission: 0.3, delivery: 90 },
306 '1805680376': { cost: 58.8, commission: 0.3, delivery: 90 },
307 '540355209': { cost: 159.6, commission: 0.3, delivery: 90 },
308 '1742877411': { cost: 208.8, commission: 0.3, delivery: 90 },
309 '1418275068': { cost: 158.4, commission: 0.3, delivery: 90 },
310 '2899612149': { cost: 145.2, commission: 0.3, delivery: 90 },
311 '2963203543': { cost: 129.948, commission: 0.3, delivery: 90 },
312 '607968165': { cost: 103.2, commission: 0.3, delivery: 90 },
313 '1162462310': { cost: 180, commission: 0.3, delivery: 90 },
314 '1507555262': { cost: 114, commission: 0.3, delivery: 90 },
315 '2925821091': { cost: 0, commission: 0.3, delivery: 90 },
316 '608298877': { cost: 136.8, commission: 0.3, delivery: 90 },
317 '1239708831': { cost: 169.2, commission: 0.3, delivery: 90 },
318 '1724749801': { cost: 180, commission: 0.3, delivery: 90 },
319 '439673824': { cost: 140.4, commission: 0.3, delivery: 90 },
320 '496542249': { cost: 81.6, commission: 0.3, delivery: 90 },
321 '1417508954': { cost: 122.4, commission: 0.3, delivery: 90 },
322 '372062053': { cost: 140.4, commission: 0.3, delivery: 90 },
323 '235824492': { cost: 105.6, commission: 0.3, delivery: 90 },
324 '912117351': { cost: 153.6, commission: 0.3, delivery: 90 },
325 '1162577837': { cost: 117.6, commission: 0.3, delivery: 90 },
326 '838273559': { cost: 163.2, commission: 0.3, delivery: 90 },
327 '953470782': { cost: 134.4, commission: 0.3, delivery: 90 },
328 '1591125774': { cost: 328.8, commission: 0.3, delivery: 90 },
329 '1239742307': { cost: 139.2, commission: 0.3, delivery: 90 },
330 '422559168': { cost: 159.6, commission: 0.3, delivery: 90 },
331 '1581558117': { cost: 117.6, commission: 0.3, delivery: 90 },
332 '697870104': { cost: 92.4, commission: 0.3, delivery: 90 },
333 '561033759': { cost: 112.8, commission: 0.3, delivery: 90 },
334 '1696256652': { cost: 115.2, commission: 0.3, delivery: 90 },
335 '2925806092': { cost: 0, commission: 0.3, delivery: 90 },
336 '1911238277': { cost: 103.2, commission: 0.3, delivery: 90 },
337 '282398558': { cost: 123.6, commission: 0.3, delivery: 90 },
338 '1880336894': { cost: 340.8, commission: 0.3, delivery: 90 },
339 '1394598690': { cost: 127.2, commission: 0.3, delivery: 90 },
340 '1161957584': { cost: 141.6, commission: 0.3, delivery: 90 },
341 '697830627': { cost: 182.4, commission: 0.3, delivery: 90 },
342 '307964008': { cost: 94.8, commission: 0.3, delivery: 90 },
343 '254895676': { cost: 112.8, commission: 0.3, delivery: 90 },
344 '1417478667': { cost: 124.8, commission: 0.3, delivery: 90 },
345 '1609652145': { cost: 144, commission: 0.3, delivery: 90 },
346 '1010086939': { cost: 141.6, commission: 0.3, delivery: 90 },
347 '952853707': { cost: 128.4, commission: 0.3, delivery: 90 },
348 '1665302366': { cost: 224.4, commission: 0.3, delivery: 90 },
349 '302361373': { cost: 104.4, commission: 0.3, delivery: 90 },
350 '952754284': { cost: 144.54, commission: 0.3, delivery: 90 },
351 '273926369': { cost: 88.8, commission: 0.3, delivery: 90 },
352 '838115048': { cost: 164.4, commission: 0.3, delivery: 90 },
353 '838251281': { cost: 103.788, commission: 0.3, delivery: 90 },
354 '732238010': { cost: 148.8, commission: 0.3, delivery: 90 },
355 '445989855': { cost: 85.2, commission: 0.3, delivery: 90 },
356 '269076077': { cost: 301.452, commission: 0.3, delivery: 90 },
357 '257568474': { cost: 73.2, commission: 0.3, delivery: 90 },
358 '954664346': { cost: 129.6, commission: 0.3, delivery: 90 },
359 '254600991': { cost: 132, commission: 0.3, delivery: 90 },
360 '772640606': { cost: 106.8, commission: 0.3, delivery: 90 },
361 '955283837': { cost: 182.4, commission: 0.3, delivery: 90 },
362 '254686077': { cost: 174, commission: 0.3, delivery: 90 },
363 '1394711785': { cost: 144, commission: 0.3, delivery: 90 },
364 '257884238': { cost: 130.8, commission: 0.3, delivery: 90 },
365 '1620776878': { cost: 157.2, commission: 0.3, delivery: 90 },
366 '951783485': { cost: 132, commission: 0.3, delivery: 90 },
367 '356177679': { cost: 69.6, commission: 0.3, delivery: 90 },
368 '1394612090': { cost: 159.6, commission: 0.3, delivery: 90 },
369 '2897675749': { cost: 0, commission: 0.3, delivery: 90 },
370 '1162445078': { cost: 186, commission: 0.3, delivery: 90 },
371 '1932949948': { cost: 235.2, commission: 0.3, delivery: 90 },
372 '879083250': { cost: 186, commission: 0.3, delivery: 90 },
373 '256466996': { cost: 200.4, commission: 0.3, delivery: 90 },
374 '3006918397': { cost: 313.2, commission: 0.3, delivery: 90 },
375 '1418277399': { cost: 346.8, commission: 0.3, delivery: 90 },
376 '496419419': { cost: 258, commission: 0.3, delivery: 90 },
377 '1007822873': { cost: 134.4, commission: 0.3, delivery: 90 },
378 '608351238': { cost: 120, commission: 0.3, delivery: 90 },
379 '1413857256': { cost: 159.6, commission: 0.3, delivery: 90 },
380 '1787673702': { cost: 150, commission: 0.3, delivery: 90 },
381 '1162216260': { cost: 145.2, commission: 0.3, delivery: 90 },
382 '1413837107': { cost: 87.6, commission: 0.3, delivery: 90 },
383 '768941637': { cost: 171.6, commission: 0.3, delivery: 90 },
384 '1507653510': { cost: 96, commission: 0.3, delivery: 90 },
385 '1007787669': { cost: 132, commission: 0.3, delivery: 90 },
386 '2352209417': { cost: 283.752, commission: 0.3, delivery: 90 },
387 '1397098991': { cost: 331.2, commission: 0.3, delivery: 90 },
388 '1507630430': { cost: 99.6, commission: 0.3, delivery: 90 },
389 '1189589105': { cost: 130.8, commission: 0.3, delivery: 90 },
390 '1506037461': { cost: 470.4, commission: 0.3, delivery: 90 },
391 '1162348932': { cost: 194.4, commission: 0.3, delivery: 90 },
392 '2975103256': { cost: 163.056, commission: 0.3, delivery: 90 },
393 '1506047716': { cost: 171.6, commission: 0.3, delivery: 90 },
394 '911292485': { cost: 112.8, commission: 0.3, delivery: 90 },
395 '1880333546': { cost: 364.8, commission: 0.3, delivery: 90 },
396 '1608793966': { cost: 132, commission: 0.3, delivery: 90 },
397 '1880315436': { cost: 344.4, commission: 0.3, delivery: 90 },
398 '2352282340': { cost: 283.752, commission: 0.3, delivery: 90 },
399 '709600226': { cost: 129.6, commission: 0.3, delivery: 90 },
400 '3016287234': { cost: 274.8, commission: 0.3, delivery: 90 },
401 '3016266763': { cost: 240, commission: 0.3, delivery: 90 },
402 '3026343193': { cost: 283.2, commission: 0.3, delivery: 90 },
403 '3011261105': { cost: 208.8, commission: 0.3, delivery: 90 },
404 '3026384906': { cost: 309.6, commission: 0.3, delivery: 90 },
405 '1303951724': { cost: 67.2, commission: 0.3, delivery: 90 },
406 '3026360459': { cost: 310.8, commission: 0.3, delivery: 90 },
407 '951614842': { cost: 116.4, commission: 0.3, delivery: 90 },
408 '1758263220': { cost: 776.4, commission: 0.3, delivery: 90 },
409 '1162674702': { cost: 152.4, commission: 0.3, delivery: 90 },
410 '236327983': { cost: 120, commission: 0.3, delivery: 90 },
411 '256416463': { cost: 104.4, commission: 0.3, delivery: 90 },
412 '1790465865': { cost: 62.4, commission: 0.3, delivery: 90 },
413 '2975215156': { cost: 163.056, commission: 0.3, delivery: 90 },
414 '1005952104': { cost: 94.8, commission: 0.3, delivery: 90 },
415 '399215466': { cost: 102, commission: 0.3, delivery: 90 },
416 '1162300125': { cost: 116.4, commission: 0.3, delivery: 90 },
417 '1005952110': { cost: 93.6, commission: 0.3, delivery: 90 },
418 '496044796': { cost: 116.4, commission: 0.3, delivery: 90 },
419 '203389028': { cost: 166.8, commission: 0.3, delivery: 90 },
420 '1005550551': { cost: 96, commission: 0.3, delivery: 90 },
421 '203480472': { cost: 94.8, commission: 0.3, delivery: 90 },
422 '203473290': { cost: 121.2, commission: 0.3, delivery: 90 },
423 '1620772534': { cost: 321.6, commission: 0.3, delivery: 90 },
424 '282469378': { cost: 100.8, commission: 0.3, delivery: 90 },
425 '1805671797': { cost: 58.8, commission: 0.3, delivery: 90 },
426 '203350791': { cost: 134.4, commission: 0.3, delivery: 90 },
427 '1394625221': { cost: 129.6, commission: 0.3, delivery: 90 },
428 '301908659': { cost: 111.6, commission: 0.3, delivery: 90 },
429 '1507673120': { cost: 253.2, commission: 0.36, delivery: 200 },
430 '1239609957': { cost: 123.6, commission: 0.36, delivery: 200 },
431 '1006163518': { cost: 188.4, commission: 0.36, delivery: 200 },
432 '1422925703': { cost: 252, commission: 0.36, delivery: 200 },
433 '1572975136': { cost: 547.2, commission: 0.36, delivery: 200 },
434 '2394561998': { cost: 106.8, commission: 0.36, delivery: 200 },
435 '838220448': { cost: 136.8, commission: 0.36, delivery: 200 },
436 '543848911': { cost: 228, commission: 0.36, delivery: 200 },
437 '1020579419': { cost: 88.8, commission: 0.36, delivery: 200 },
438 '557726786': { cost: 217.2, commission: 0.36, delivery: 200 },
439 '1608785751': { cost: 176.4, commission: 0.36, delivery: 200 },
440 '1020578939': { cost: 92.4, commission: 0.36, delivery: 200 },
441 '519816761': { cost: 231.6, commission: 0.36, delivery: 200 },
442 '1673659402': { cost: 1267, commission: 0.36, delivery: 200 },
443 '501441185': { cost: 216, commission: 0.36, delivery: 200 },
444 '860254877': { cost: 223.2, commission: 0.36, delivery: 200 },
445 '774068400': { cost: 358.8, commission: 0.36, delivery: 200 },
446 '519740742': { cost: 216, commission: 0.36, delivery: 200 },
447 '1673650914': { cost: 1537, commission: 0.36, delivery: 200 },
448 '519734762': { cost: 234, commission: 0.36, delivery: 200 },
449 '1558177759': { cost: 366, commission: 0.36, delivery: 200 },
450 '1558176776': { cost: 421.2, commission: 0.36, delivery: 200 },
451 '643844171': { cost: 112.8, commission: 0.36, delivery: 200 },
452 '519732586': { cost: 98.4, commission: 0.36, delivery: 200 },
453 '1019659629': { cost: 91.2, commission: 0.36, delivery: 200 },
454 '1673649384': { cost: 1517, commission: 0.36, delivery: 200 },
455 '860261495': { cost: 240, commission: 0.36, delivery: 200 },
456 '1880450237': { cost: 271.2, commission: 0.36, delivery: 200 },
457 '1558174139': { cost: 372, commission: 0.36, delivery: 200 },
458 '1845802065': { cost: 768, commission: 0.36, delivery: 200 },
459 '1673647587': { cost: 1497, commission: 0.36, delivery: 200 },
460 '557670932': { cost: 392.4, commission: 0.36, delivery: 200 },
461 '1979738121': { cost: 637.2, commission: 0.36, delivery: 200 },
462 '1020579926': { cost: 88.8, commission: 0.36, delivery: 200 },
463 '1880440770': { cost: 273.6, commission: 0.36, delivery: 200 },
464 '1979755177': { cost: 662.4, commission: 0.36, delivery: 200 },
465 '2898154255': { cost: 124.8, commission: 0.36, delivery: 200 },
466 '2899553513': { cost: 145.2, commission: 0.36, delivery: 200 },
467 '1846354292': { cost: 768, commission: 0.36, delivery: 200 },
468 '1880410608': { cost: 285.6, commission: 0.36, delivery: 200 },
469 '2898115411': { cost: 136.8, commission: 0.36, delivery: 200 },
470 '1880442651': { cost: 270, commission: 0.36, delivery: 200 },
471 '501438861': { cost: 220.8, commission: 0.36, delivery: 200 },
472 '1397099331': { cost: 372, commission: 0.36, delivery: 200 },
473 '1846363096': { cost: 768, commission: 0.36, delivery: 200 },
474 '2631471568': { cost: 685.2, commission: 0.36, delivery: 200 },
475 '1911710527': { cost: 276, commission: 0.36, delivery: 200 },
476 '1911695310': { cost: 267.6, commission: 0.36, delivery: 200 },
477 '1911704413': { cost: 264, commission: 0.36, delivery: 200 },
478 '1020579746': { cost: 90, commission: 0.36, delivery: 200 },
479 '335431876': { cost: 51.6, commission: 0.36, delivery: 200 },
480 '439685200': { cost: 55.2, commission: 0.36, delivery: 200 },
481 '1019698970': { cost: 88.8, commission: 0.36, delivery: 200 },
482 '439692165': { cost: 55.2, commission: 0.36, delivery: 200 },
483 '335431975': { cost: 54, commission: 0.36, delivery: 200 },
484 '335446268': { cost: 52.8, commission: 0.36, delivery: 200 },
485 '1846315219': { cost: 768, commission: 0.36, delivery: 200 },
486 '335440088': { cost: 61.2, commission: 0.36, delivery: 200 },
487 '838167533': { cost: 106.8, commission: 0.3, delivery: 90 },
488 '878312141': { cost: 265.2, commission: 0.36, delivery: 200 },
489 '1572991087': { cost: 290.4, commission: 0.36, delivery: 200 },
490 '1521855158': { cost: 104.4, commission: 0.3, delivery: 90 },
491 '646434083': { cost: 252, commission: 0.3, delivery: 90 },
492 '646441179': { cost: 273.6, commission: 0.3, delivery: 90 },
493 '2352128160': { cost: 340.8, commission: 0.36, delivery: 200 },
494 '446010027': { cost: 344.4, commission: 0.3, delivery: 90 },
495 '1773177807': { cost: 192, commission: 0.36, delivery: 200 },
496 '1980328072': { cost: 338.4, commission: 0.36, delivery: 200 },
497 '646441673': { cost: 258, commission: 0.3, delivery: 90 },
498 '772524320': { cost: 131.64, commission: 0.3, delivery: 90 },
499 '302573933': { cost: 258, commission: 0.3, delivery: 90 },
500 '824213857': { cost: 172.8, commission: 0.3, delivery: 90 },
501 '1609643510': { cost: 175.2, commission: 0.3, delivery: 90 },
502 '439749049': { cost: 357.6, commission: 0.3, delivery: 90 },
503 '496064096': { cost: 230.052, commission: 0.3, delivery: 90 },
504 '732341657': { cost: 205.2, commission: 0.36, delivery: 200 },
505 '955327749': { cost: 146.4, commission: 0.3, delivery: 90 },
506 '1787680920': { cost: 230.4, commission: 0.3, delivery: 90 },
507 '2352063264': { cost: 285.6, commission: 0.36, delivery: 200 },
508 '2352107373': { cost: 321.6, commission: 0.36, delivery: 200 },
509 '1521854115': { cost: 177.6, commission: 0.3, delivery: 90 },
510 '240602548': { cost: 128.4, commission: 0.3, delivery: 90 },
511 '1239644265': { cost: 207.6, commission: 0.3, delivery: 90 },
512 '203465007': { cost: 124.8, commission: 0.36, delivery: 200 },
513 '1937534346': { cost: 144, commission: 0.3, delivery: 90 },
514 '1979698296': { cost: 324, commission: 0.36, delivery: 200 },
515 '256430704': { cost: 99.6, commission: 0.3, delivery: 90 },
516 '1505980019': { cost: 183.6, commission: 0.3, delivery: 90 }
517 };
518
519 // Extract product ID from URL
520 function getProductId() {
521 const match = window.location.href.match(/product\/[^\/]+-(\d+)/);
522 return match ? match[1] : null;
523 }
524
525 // Get short SKU from full product ID (last 5 digits)
526 function getShortSku(fullProductId) {
527 if (PRODUCT_DATA[fullProductId]) {
528 return fullProductId;
529 }
530
531 const last5 = fullProductId.slice(-5);
532 if (PRODUCT_DATA[last5]) {
533 return last5;
534 }
535
536 const last6 = fullProductId.slice(-6);
537 if (PRODUCT_DATA[last6]) {
538 return last6;
539 }
540
541 return null;
542 }
543
544 // Extract daily price and sales data from MP Stats chart
545 async function extractDailyDataFromChart(widget) {
546 console.log('>>> extractDailyDataFromChart CALLED (v2.0.1) <<<');
547
548 try {
549 const dailyData = [];
550 const svgs = widget.querySelectorAll('svg.apexcharts-svg');
551 console.log('Found ApexCharts SVG elements:', svgs.length);
552
553 if (svgs.length === 0) {
554 console.log('No SVG charts found');
555 return dailyData;
556 }
557
558 const salesSvg = svgs[0];
559 console.log('Analyzing sales chart (SVG 0)...');
560
561 const bars = salesSvg.querySelectorAll('path.apexcharts-bar-area');
562 console.log(`Found ${bars.length} bar elements`);
563
564 if (bars.length === 0) {
565 console.log('No bars found in sales chart');
566 return dailyData;
567 }
568
569 console.log('Starting tooltip extraction...');
570
571 const indices = [];
572 for (let i = 1; i < bars.length; i++) {
573 indices.push(i);
574 }
575 indices.push(0);
576
577 for (const index of indices) {
578 const bar = bars[index];
579 const rect = bar.getBoundingClientRect();
580 const centerX = rect.left + rect.width / 2;
581 const centerY = rect.top + rect.height / 2;
582
583 console.log(`Day ${index + 1}: rect:`, { left: rect.left, top: rect.top, width: rect.width, height: rect.height });
584
585 bar.dispatchEvent(new MouseEvent('mousemove', {
586 bubbles: true,
587 cancelable: true,
588 view: window,
589 clientX: centerX,
590 clientY: centerY
591 }));
592
593 const waitTime = index <= 2 ? 800 : 200;
594 await new Promise(resolve => setTimeout(resolve, waitTime));
595
596 let tooltip = document.querySelector('.chart-custom-tooltip');
597 let retries = 0;
598 const maxRetries = index === 0 ? 8 : 5;
599
600 while (!tooltip && retries < maxRetries) {
601 console.log(`Day ${index + 1}: Tooltip not found, retry ${retries + 1}/${maxRetries}`);
602
603 bar.dispatchEvent(new MouseEvent('mousemove', {
604 bubbles: true,
605 cancelable: true,
606 view: window,
607 clientX: centerX,
608 clientY: centerY
609 }));
610
611 await new Promise(resolve => setTimeout(resolve, 400));
612 tooltip = document.querySelector('.chart-custom-tooltip');
613 retries++;
614 }
615
616 if (!tooltip) {
617 console.log(`Day ${index + 1}: Tooltip not found after ${maxRetries} retries, skipping`);
618 continue;
619 }
620
621 const tooltipText = tooltip.textContent;
622 console.log(`Day ${index + 1}: Tooltip text:`, tooltipText);
623
624 const salesMatch = tooltipText.match(/Продажи:\s*(\d+)\s*шт/);
625 const sales = salesMatch ? parseInt(salesMatch[1]) : null;
626
627 const priceMatch = tooltipText.match(/Цена:\s*(\d+)\s*₽/);
628 const price = priceMatch ? parseInt(priceMatch[1]) : null;
629
630 if (sales !== null && price !== null && sales > 0 && price > 0) {
631 dailyData.push({
632 day: index + 1,
633 sales: sales,
634 price: price
635 });
636 } else {
637 console.log(`Day ${index + 1}: Invalid data - sales: ${sales}, price: ${price}`);
638 }
639 }
640
641 console.log(`Total extracted daily data points: ${dailyData.length}`);
642 console.log('Sample data - First 5 days:', dailyData.slice(0, 5));
643 console.log('Sample data - Last 5 days:', dailyData.slice(-5));
644 return dailyData;
645
646 } catch (error) {
647 console.error('Error extracting daily data:', error);
648 return [];
649 }
650 }
651
652 // Extract stock data from MP Stats stock chart
653 async function extractStockData(widget) {
654 console.log('Extracting stock data from MP Stats...');
655
656 if (!widget) {
657 console.error('Widget not provided to extractStockData');
658 return null;
659 }
660
661 const svgs = widget.querySelectorAll('svg.apexcharts-svg');
662 console.log(`Found ${svgs.length} SVG charts for stock data`);
663
664 if (!svgs || svgs.length < 4) {
665 console.error(`Stock chart SVG not found - only ${svgs ? svgs.length : 0} charts available, need at least 4`);
666 return null;
667 }
668
669 const stockSvg = svgs[3];
670 console.log('Analyzing stock chart (SVG 3)...');
671
672 const stockBars = stockSvg.querySelectorAll('path.apexcharts-bar-area');
673 console.log(`Found ${stockBars.length} stock bars in fourth chart`);
674
675 if (!stockBars || stockBars.length === 0) {
676 console.error('No stock bars found in fourth chart');
677 return null;
678 }
679
680 const stockPoints = [];
681 console.log('Starting stock tooltip extraction...');
682
683 const indices = [];
684 for (let i = 1; i < stockBars.length; i++) {
685 indices.push(i);
686 }
687 indices.push(0);
688
689 for (const index of indices) {
690 const bar = stockBars[index];
691 const rect = bar.getBoundingClientRect();
692 const centerX = rect.left + rect.width / 2;
693 const centerY = rect.top + rect.height / 2;
694
695 console.log(`Stock Day ${index + 1}: rect:`, { left: rect.left, top: rect.top, width: rect.width, height: rect.height });
696
697 bar.dispatchEvent(new MouseEvent('mousemove', {
698 bubbles: true,
699 cancelable: true,
700 view: window,
701 clientX: centerX,
702 clientY: centerY
703 }));
704
705 const waitTime = index <= 2 ? 800 : 200;
706 await new Promise(resolve => setTimeout(resolve, waitTime));
707
708 let tooltip = document.querySelector('.chart-custom-tooltip');
709 let retries = 0;
710 const maxRetries = index === 0 ? 8 : 5;
711
712 while (!tooltip && retries < maxRetries) {
713 console.log(`Stock Day ${index + 1}: Tooltip not found, retry ${retries + 1}/${maxRetries}`);
714
715 bar.dispatchEvent(new MouseEvent('mousemove', {
716 bubbles: true,
717 cancelable: true,
718 view: window,
719 clientX: centerX,
720 clientY: centerY
721 }));
722
723 await new Promise(resolve => setTimeout(resolve, 400));
724 tooltip = document.querySelector('.chart-custom-tooltip');
725 retries++;
726 }
727
728 if (!tooltip) {
729 console.log(`Stock Day ${index + 1}: Tooltip not found after ${maxRetries} retries, skipping`);
730 continue;
731 }
732
733 const tooltipText = tooltip.textContent;
734 console.log(`Stock Day ${index + 1}: Tooltip text:`, tooltipText);
735
736 const stockMatch = tooltipText.match(/Остаток:\s*(\d+)\s*шт/) || tooltipText.match(/(\d+)\s*шт/);
737 const stock = stockMatch ? parseInt(stockMatch[1]) : null;
738
739 if (stock !== null && stock >= 0) {
740 stockPoints.push({
741 day: index + 1,
742 stock: stock
743 });
744 console.log(`Stock Day ${index + 1}: Extracted stock: ${stock}`);
745 } else {
746 console.log(`Stock Day ${index + 1}: Invalid stock data - stock: ${stock}`);
747 }
748 }
749
750 console.log(`Extracted ${stockPoints.length} days of stock data from chart`);
751 console.log('Stock data sample - First 5 days:', stockPoints.slice(0, 5));
752 console.log('Stock data sample - Last 5 days:', stockPoints.slice(-5));
753 return stockPoints;
754 }
755
756 // Extract competitor data from product page
757 async function extractCompetitorData() {
758 console.log('=== START extractCompetitorData ===');
759 try {
760 console.log('Extracting competitor data...');
761
762 const productNameElement = document.querySelector('[data-widget="webProductHeading"] h1');
763 console.log('Product name element found:', !!productNameElement);
764
765 if (!productNameElement) {
766 console.error('Product name not found');
767 return null;
768 }
769
770 const productName = productNameElement.textContent.trim();
771 console.log('Product name:', productName);
772
773 const words = productName.split(' ');
774 const firstWord = words[0].toLowerCase();
775 const secondWord = words[1] ? words[1].toLowerCase() : '';
776 console.log('Searching for competitors with first word:', firstWord, 'and second word:', secondWord);
777
778 const competitors = [];
779 const productNameDivs = document.querySelectorAll('div[class*="bq03"]');
780 console.log(`Found ${productNameDivs.length} product name divs on page`);
781
782 const processedSkus = new Set();
783 const currentProductId = getProductId();
784
785 productNameDivs.forEach((nameDiv, index) => {
786 try {
787 const nameSpan = nameDiv.querySelector('span.tsBody500Medium');
788 if (!nameSpan) {
789 return;
790 }
791
792 const competitorName = nameSpan.textContent.trim();
793 const competitorWords = competitorName.split(' ');
794 const competitorFirstWord = competitorWords[0].toLowerCase();
795 const competitorSecondWord = competitorWords[1] ? competitorWords[1].toLowerCase() : '';
796
797 if (competitorFirstWord !== firstWord || competitorSecondWord !== secondWord) {
798 return;
799 }
800
801 const container = nameDiv.closest('div[class*="tile"]') || nameDiv.closest('div');
802 if (!container) {
803 return;
804 }
805
806 const productLink = container.querySelector('a[href*="/product/"]');
807 if (!productLink) {
808 return;
809 }
810
811 const match = productLink.href.match(/product\/[^\/]+-(\d+)/);
812 if (!match) {
813 return;
814 }
815
816 const sku = match[1];
817
818 if (sku === currentProductId || processedSkus.has(sku)) {
819 return;
820 }
821 processedSkus.add(sku);
822
823 const priceSpans = container.querySelectorAll('span');
824 let price = null;
825
826 for (const span of priceSpans) {
827 const text = span.textContent.trim();
828 if (text.match(/^\d[\d\s]*₽?$/)) {
829 const priceText = text.replace(/[^\d]/g, '');
830 const parsedPrice = parseInt(priceText);
831 if (!isNaN(parsedPrice) && parsedPrice > 100 && parsedPrice < 10000) {
832 price = parsedPrice;
833 break;
834 }
835 }
836 }
837
838 if (!price) {
839 return;
840 }
841
842 let sales30days = null;
843 let revenue30days = null;
844
845 const mpstatsContainer = container.querySelector('[class*="container_ihu0b"], .mpstats-loader');
846 if (mpstatsContainer) {
847 const text = mpstatsContainer.textContent;
848 const salesMatch = text.match(/(\d+)\s*шт/);
849 if (salesMatch) {
850 sales30days = parseInt(salesMatch[1]);
851 revenue30days = price * sales30days;
852 }
853 }
854
855 competitors.push({
856 name: competitorName,
857 price: price,
858 sales30days: sales30days,
859 revenue30days: revenue30days,
860 sku: sku
861 });
862
863 console.log(`Competitor ${index}: ${competitorName}, Price: ${price}, Sales: ${sales30days}, SKU: ${sku}`);
864 } catch (error) {
865 console.error(`Competitor ${index}: Error:`, error);
866 }
867 });
868
869 console.log(`Found ${competitors.length} competitors on product page`);
870
871 if (competitors.length > 0) {
872 competitors.sort((a, b) => {
873 const revenueA = a.revenue30days || 0;
874 const revenueB = b.revenue30days || 0;
875 return revenueB - revenueA;
876 });
877
878 return competitors;
879 }
880
881 console.log('No competitors found on page');
882 return null;
883
884 } catch (error) {
885 console.error('Error in extractCompetitorData:', error);
886 return null;
887 }
888 }
889
890 // Extract summary data from MP Stats widget
891 async function extractMPStatsData() {
892 console.log('Extracting MP Stats summary data...');
893
894 const widget = document.querySelector('.mps-sidebar');
895 if (!widget) {
896 console.error('MP Stats widget not found');
897 return null;
898 }
899
900 const revenueText = widget.textContent.match(/Выручка за 30 суток\s*([\d\s]+)/);
901 const salesText = widget.textContent.match(/Продаж за 30 суток\s*([\d\s]+)/);
902 const currentStockText = widget.textContent.match(/Текущий остаток\s*([\d\s]+)/);
903
904 if (revenueText && salesText) {
905 const revenue = parseInt(revenueText[1].replace(/\s/g, ''));
906 const sales = parseInt(salesText[1].replace(/\s/g, ''));
907
908 let avgPrice = revenue / sales;
909 const webPriceWidget = document.querySelector('[data-widget="webPrice"]');
910 if (webPriceWidget) {
911 const priceSpans = webPriceWidget.querySelectorAll('span');
912 const prices = [];
913 priceSpans.forEach(span => {
914 const text = span.textContent.trim();
915 const match = text.match(/^(\d[\d\s]*)\s*₽$/);
916 if (match) {
917 const priceText = match[1].replace(/\s/g, '');
918 const parsedPrice = parseInt(priceText);
919 if (!isNaN(parsedPrice) && parsedPrice > 100 && parsedPrice < 100000) {
920 prices.push(parsedPrice);
921 }
922 }
923 });
924 if (prices.length > 0) {
925 avgPrice = Math.min(...prices);
926 console.log('Found prices in webPrice:', prices, 'Using minimum:', avgPrice);
927 }
928 }
929
930 const currentStock = currentStockText ? parseInt(currentStockText[1].replace(/\s/g, '')) : 0;
931
932 const dataPoints = await extractDailyDataFromChart(widget);
933
934 if (!dataPoints || dataPoints.length === 0) {
935 console.error('Failed to extract chart data');
936 return null;
937 }
938
939 const stockPoints = await extractStockData(widget);
940 console.log('Stock points extracted:', stockPoints);
941
942 const totalSales = dataPoints.reduce((sum, d) => sum + d.sales, 0);
943 const avgDailySales = totalSales / dataPoints.length;
944
945 let matchedStockPoints = null;
946 if (stockPoints && stockPoints.length > 0) {
947 console.log('Matching stock data with sales data...');
948 matchedStockPoints = dataPoints.map(salesDay => {
949 const stockDay = stockPoints.find(s => s.day === salesDay.day);
950 return {
951 day: salesDay.day,
952 sales: salesDay.sales,
953 price: salesDay.price,
954 stock: stockDay ? stockDay.stock : null
955 };
956 });
957 console.log('Matched stock data - First 5 days:', matchedStockPoints.slice(0, 5));
958 console.log('Matched stock data - Last 5 days:', matchedStockPoints.slice(-5));
959 } else {
960 console.log('No stock data to match');
961 }
962
963 console.log('Extracted summary data:', {
964 revenue,
965 sales,
966 avgPrice,
967 currentStock,
968 avgDailySales,
969 daysOfData: dataPoints.length,
970 stockDataPoints: stockPoints ? stockPoints.length : 0,
971 matchedDataPoints: matchedStockPoints ? matchedStockPoints.length : 0
972 });
973
974 return {
975 revenue,
976 sales,
977 avgPrice,
978 currentStock,
979 avgDailySales,
980 dataPoints,
981 stockPoints,
982 matchedStockPoints
983 };
984 }
985
986 return null;
987 }
988
989 // Calculate demand elasticity from historical data
990 function calculateDemandElasticity(dataPoints, matchedStockPoints) {
991 console.log('=== CALCULATING DEMAND ELASTICITY (v2.0.1) ===');
992 console.log('dataPoints:', dataPoints);
993 console.log('matchedStockPoints:', matchedStockPoints);
994
995 // Filter out days with zero stock and the day before zero stock
996 let validPoints = dataPoints;
997 if (matchedStockPoints && matchedStockPoints.length > 0) {
998 const zeroStockDays = new Set();
999 matchedStockPoints.forEach((d, index) => {
1000 if (d.stock === 0) {
1001 zeroStockDays.add(d.day);
1002 // Also exclude the day before zero stock
1003 if (index > 0) {
1004 zeroStockDays.add(matchedStockPoints[index - 1].day);
1005 }
1006 }
1007 });
1008 validPoints = matchedStockPoints.filter(d => !zeroStockDays.has(d.day));
1009 console.log(`Excluded ${zeroStockDays.size} days (zero stock and day before)`);
1010 }
1011
1012 console.log(`Using ${validPoints.length} days for elasticity calculation`);
1013 console.log('Valid points sample:', validPoints.slice(0, 5));
1014
1015 if (validPoints.length < 5) {
1016 console.log('Not enough data points for elasticity calculation, using default -1.5');
1017 return { elasticity: -1.5, reliability: 'bad', r2: 0, uniquePrices: 0, daysUsed: validPoints.length };
1018 }
1019
1020 const avgPrice = validPoints.reduce((sum, d) => sum + d.price, 0) / validPoints.length;
1021 const avgSales = validPoints.reduce((sum, d) => sum + d.sales, 0) / validPoints.length;
1022
1023 console.log(`Average price: ${avgPrice.toFixed(2)}₽, Average sales: ${avgSales.toFixed(1)} шт/день`);
1024
1025 let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0, sumY2 = 0;
1026 const n = validPoints.length;
1027
1028 validPoints.forEach(d => {
1029 sumX += d.price;
1030 sumY += d.sales;
1031 sumXY += d.price * d.sales;
1032 sumX2 += d.price * d.price;
1033 sumY2 += d.sales * d.sales;
1034 });
1035
1036 console.log(`Regression sums: n=${n}, sumX=${sumX}, sumY=${sumY}, sumXY=${sumXY}, sumX2=${sumX2}, sumY2=${sumY2}`);
1037
1038 const numerator = n * sumXY - sumX * sumY;
1039 const denominator = n * sumX2 - sumX * sumX;
1040 const slope = numerator / denominator;
1041
1042 // Calculate R² (coefficient of determination)
1043 const ssTotal = sumY2 - (sumY * sumY) / n;
1044 const ssResidual = sumY2 - slope * sumXY - (avgSales - slope * avgPrice) * sumY;
1045 const r2 = 1 - (ssResidual / ssTotal);
1046
1047 console.log(`Slope: numerator=${numerator}, denominator=${denominator}, slope=${slope}`);
1048 console.log(`R²: ssTotal=${ssTotal}, ssResidual=${ssResidual}, R²=${r2.toFixed(4)}`);
1049
1050 const elasticity = slope * (avgPrice / avgSales);
1051
1052 console.log(`Elasticity: slope=${slope.toFixed(4)} * (${avgPrice.toFixed(2)} / ${avgSales.toFixed(1)}) = ${elasticity.toFixed(4)}`);
1053
1054 if (elasticity > 0) {
1055 console.log('⚠️ WARNING: Positive elasticity! Using default -1.5');
1056 return { elasticity: -1.5, reliability: 'bad', r2: r2, uniquePrices: [...new Set(validPoints.map(d => d.price))].length, daysUsed: n };
1057 }
1058
1059 const clampedElasticity = Math.max(-3.0, Math.min(-0.3, elasticity));
1060
1061 if (clampedElasticity !== elasticity) {
1062 console.log(`Elasticity ${elasticity.toFixed(4)} clamped to ${clampedElasticity.toFixed(4)}`);
1063 }
1064
1065 // Determine reliability based on R², number of unique prices, and days
1066 const uniquePrices = [...new Set(validPoints.map(d => d.price))].length;
1067 let reliability = 'bad';
1068
1069 if (r2 >= 0.7 && uniquePrices >= 10 && n >= 20) {
1070 reliability = 'good';
1071 } else if (r2 >= 0.5 && uniquePrices >= 5 && n >= 10) {
1072 reliability = 'satisfactory';
1073 } else {
1074 reliability = 'bad';
1075 }
1076
1077 console.log(`=== FINAL ELASTICITY: ${clampedElasticity.toFixed(4)}, R²=${r2.toFixed(4)}, Reliability=${reliability} ===`);
1078 return { elasticity: clampedElasticity, reliability: reliability, r2: r2, uniquePrices: uniquePrices, daysUsed: n };
1079 }
1080
1081 // AI-powered Bayesian price optimization
1082 async function bayesianPriceOptimizationWithAI(historicalData, productData, competitorData, coinvest, drr) {
1083 console.log('=== ENTERED bayesianPriceOptimizationWithAI (v2.0.1) ===');
1084 console.log('Historical data:', historicalData);
1085 console.log('Product data:', productData);
1086 console.log('Competitor data:', competitorData);
1087 console.log('Coinvest:', coinvest, '%, DRR:', drr, '%');
1088
1089 try {
1090 console.log('>>> ABOUT TO CALL calculateDemandElasticity <<<');
1091 console.log('>>> dataPoints:', historicalData.dataPoints);
1092 console.log('>>> matchedStockPoints:', historicalData.matchedStockPoints);
1093
1094 const elasticityResult = calculateDemandElasticity(historicalData.dataPoints, historicalData.matchedStockPoints);
1095 const realElasticity = elasticityResult.elasticity;
1096
1097 console.log(`>>> AFTER calculateDemandElasticity, realElasticity = ${realElasticity} <<<`);
1098 console.log(`Real demand elasticity calculated: ${realElasticity.toFixed(4)}, R²=${elasticityResult.r2.toFixed(4)}, Reliability=${elasticityResult.reliability}`);
1099
1100 // Prepare historical data summary
1101 const dailySalesInfo = historicalData.dataPoints
1102 .map(d => `День ${d.day}: ${d.sales} шт × ${d.price}₽`)
1103 .join(', ');
1104
1105 const uniquePrices = [...new Set(historicalData.dataPoints.map(d => d.price))];
1106
1107 console.log(`Historical data: ${historicalData.dataPoints.length} days, ${uniquePrices.length} unique prices:`, uniquePrices);
1108
1109 // Prepare stock correlation data
1110 let stockAnalysis = '';
1111 if (historicalData.matchedStockPoints && historicalData.matchedStockPoints.length > 0) {
1112 const validPoints = historicalData.matchedStockPoints.filter(d => d.stock !== null && d.stock > 0);
1113 if (validPoints.length > 5) {
1114 const lowStockDays = validPoints.filter(d => d.stock < 50);
1115 const normalStockDays = validPoints.filter(d => d.stock >= 50);
1116
1117 if (lowStockDays.length > 0 && normalStockDays.length > 0) {
1118 const avgSalesLowStock = lowStockDays.reduce((sum, d) => sum + d.sales, 0) / lowStockDays.length;
1119 const avgSalesNormalStock = normalStockDays.reduce((sum, d) => sum + d.sales, 0) / normalStockDays.length;
1120
1121 stockAnalysis = `\nКОРРЕЛЯЦИЯ ОСТАТКОВ И ПРОДАЖ: При остатке <50 шт средние продажи ${avgSalesLowStock.toFixed(1)} шт/день, при остатке ≥50 шт — ${avgSalesNormalStock.toFixed(1)} шт/день. Текущий остаток: ${historicalData.currentStock} шт.`;
1122 }
1123 }
1124 }
1125
1126 // Prepare competitor analysis
1127 let competitorAnalysis = '';
1128 if (competitorData && competitorData.length > 0) {
1129 const prices = competitorData.map(c => c.price);
1130 const minCompPrice = Math.min(...prices);
1131 const maxCompPrice = Math.max(...prices);
1132 const avgCompPrice = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length);
1133
1134 const topCompetitors = competitorData.slice(0, 3).map(c =>
1135 `${c.price}₽ (${c.sales30days ? (c.sales30days / 30).toFixed(1) + ' шт/день' : 'н/д'})`
1136 ).join(', ');
1137
1138 competitorAnalysis = `\nКОНКУРЕНТЫ (${competitorData.length} шт): цены ${minCompPrice}-${maxCompPrice}₽, средняя ${avgCompPrice}₽. Топ-3 по выручке: ${topCompetitors}.`;
1139 }
1140
1141 const commissionPercent = Math.round(productData.commission * 100);
1142
1143 // Calculate actual price from current display price using user's coinvest value
1144 const displayPriceMultiplier = (100 - coinvest) / 100;
1145 const actualPrice = historicalData.avgPrice / displayPriceMultiplier;
1146 const minBreakevenActualPrice = (productData.cost + productData.delivery) / (1 - productData.commission - drr / 100);
1147 const minBreakevenDisplayPrice = Math.ceil(minBreakevenActualPrice * displayPriceMultiplier);
1148
1149 const aiPrompt = `Ты - эксперт по ценообразованию на маркетплейсах. Твоя задача - найти цену, которая МАКСИМИЗИРУЕТ ДНЕВНУЮ ПРИБЫЛЬ.
1150
1151КРИТИЧЕСКИ ВАЖНО:
1152- Текущая цена ${Math.round(historicalData.avgPrice)}₽ - это цена РЕАЛИЗАЦИИ (после скидки ${coinvest}% от OZON)
1153- Фактическая цена = Цена реализации ÷ ${displayPriceMultiplier.toFixed(2)} = ${Math.round(actualPrice)}₽
1154- ВСЕ расходы (комиссия, реклама) считаются от ФАКТИЧЕСКОЙ цены
1155- Прибыль = (Фактическая цена - Себестоимость - Комиссия - Доставка - Реклама) × Продажи
1156
1157ТЕКУЩАЯ СИТУАЦИЯ:
1158• Цена реализации: ${Math.round(historicalData.avgPrice)}₽
1159• Фактическая цена: ${Math.round(actualPrice)}₽
1160• Продажи: ${historicalData.avgDailySales.toFixed(1)} шт/день
1161• Остаток: ${historicalData.currentStock} шт
1162
1163СТРУКТУРА РАСХОДОВ (на единицу товара):
1164• Себестоимость: ${productData.cost}₽
1165• Комиссия OZON: ${commissionPercent}% от фактической цены
1166• Доставка: ${productData.delivery}₽
1167• ДРР (реклама): ${drr}% от фактической цены
1168• Минимальная цена безубыточности: ${minBreakevenDisplayPrice}₽ (реализация)
1169
1170ЭЛАСТИЧНОСТЬ СПРОСА (из ${historicalData.dataPoints.length} дней, ${uniquePrices.length} уникальных цен):
1171• Коэффициент эластичности: ${realElasticity.toFixed(4)}
1172• Формула: Продажи(новая_цена) = ${historicalData.avgDailySales.toFixed(1)} × (1 + ${realElasticity.toFixed(4)} × ((новая_цена ÷ ${Math.round(historicalData.avgPrice)}) - 1))
1173• Это означает: при изменении цены на 1%, продажи изменятся на ${(realElasticity * 100).toFixed(1)}%
1174
1175ИСТОРИЧЕСКИЕ ДАННЫЕ ПО ДНЯМ: ${dailySalesInfo}${stockAnalysis}${competitorAnalysis}
1176
1177ТВОЯ ЗАДАЧА:
11781. Рассчитай прибыль/день для КАЖДОЙ цены от ${minBreakevenDisplayPrice}₽ до ${Math.round(historicalData.avgPrice * 1.5)}₽ с шагом 10₽
11792. Для КАЖДОЙ цены реализации используй формулу:
1180 • Фактическая цена = Цена реализации ÷ ${displayPriceMultiplier.toFixed(2)}
1181 • Прогноз продаж = ${historicalData.avgDailySales.toFixed(1)} × (1 + ${realElasticity.toFixed(4)} × ((Цена реализации ÷ ${Math.round(historicalData.avgPrice)}) - 1))
1182 • Комиссия = Фактическая цена × ${productData.commission}
1183 • Реклама = Фактическая цена × ${drr / 100}
1184 • Прибыль/день = (Фактическая цена - ${productData.cost} - Комиссия - ${productData.delivery} - Реклама) × Прогноз продаж
11853. ВЫБЕРИ цену с МАКСИМАЛЬНОЙ прибылью/день
11864. Учитывай: низкий остаток (<50 шт) может ограничить продажи
11875. Учитывай: конкуренты влияют на спрос
1188
1189ВАЖНО: Не бойся рекомендовать изменение цены! Если расчеты показывают, что другая цена даст больше прибыли - рекомендуй её!
1190
1191Верни JSON с оптимальной ценой РЕАЛИЗАЦИИ (той, что дает максимальную прибыль/день).`;
1192
1193 console.log('>>> CALLING RM.aiCall <<<');
1194 const aiResponse = await RM.aiCall(aiPrompt, {
1195 type: 'json_schema',
1196 json_schema: {
1197 name: 'price_optimization',
1198 schema: {
1199 type: 'object',
1200 properties: {
1201 optimalPrice: { type: 'number' },
1202 minPrice: { type: 'number' },
1203 maxPrice: { type: 'number' },
1204 confidence: { type: 'number' },
1205 reasoning: { type: 'string' },
1206 explorationPrices: {
1207 type: 'array',
1208 items: { type: 'number' },
1209 minItems: 3,
1210 maxItems: 3
1211 }
1212 },
1213 required: ['optimalPrice', 'minPrice', 'maxPrice', 'confidence', 'reasoning', 'explorationPrices']
1214 }
1215 }
1216 });
1217
1218 console.log('>>> AI RESPONSE RECEIVED <<<');
1219 console.log('AI response:', aiResponse);
1220 console.log('AI optimalPrice:', aiResponse.optimalPrice);
1221 console.log('AI reasoning:', aiResponse.reasoning);
1222 console.log('AI confidence:', aiResponse.confidence);
1223 console.log('AI explorationPrices:', aiResponse.explorationPrices);
1224
1225 // Calculate all possible prices and find the one with maximum profit
1226 const priceRange = [];
1227 const step = (aiResponse.maxPrice - aiResponse.minPrice) / 20;
1228
1229 for (let price = aiResponse.minPrice; price <= aiResponse.maxPrice; price += step) {
1230 priceRange.push(Math.round(price));
1231 }
1232
1233 aiResponse.explorationPrices.forEach(p => {
1234 if (!priceRange.includes(Math.round(p))) {
1235 priceRange.push(Math.round(p));
1236 }
1237 });
1238
1239 priceRange.sort((a, b) => a - b);
1240
1241 const results = priceRange.map(displayPrice => {
1242 const priceChangePercent = (displayPrice / historicalData.avgPrice) - 1;
1243 const salesChangePercent = realElasticity * priceChangePercent;
1244 const estimatedSales = historicalData.avgDailySales * (1 + salesChangePercent);
1245
1246 // Calculate actual price from display price using user's coinvest
1247 const actualPrice = displayPrice / displayPriceMultiplier;
1248 const commission = actualPrice * productData.commission;
1249 const advertisingCost = actualPrice * (drr / 100);
1250 const delivery = productData.delivery;
1251 const profit = (actualPrice - productData.cost - commission - delivery - advertisingCost) * estimatedSales;
1252 const margin = ((actualPrice - productData.cost - commission - delivery - advertisingCost) / actualPrice) * 100;
1253
1254 return {
1255 price: Math.round(displayPrice * 10) / 10,
1256 actualPrice: Math.round(actualPrice * 10) / 10,
1257 estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1258 estimatedDailyProfit: Math.round(profit * 10) / 10,
1259 profitMargin: Math.round(margin * 10) / 10,
1260 confidence: aiResponse.confidence,
1261 commission: Math.round(commission * 10) / 10,
1262 advertisingCost: Math.round(advertisingCost * 10) / 10,
1263 delivery: delivery
1264 };
1265 });
1266
1267 // Find the price with maximum profit from our calculations
1268 const maxProfitResult = results.reduce((max, current) =>
1269 current.estimatedDailyProfit > max.estimatedDailyProfit ? current : max
1270 );
1271
1272 console.log('>>> CALCULATED OPTIMAL PRICE <<<');
1273 console.log('AI suggested:', aiResponse.optimalPrice, 'with profit:', results.find(r => r.price === aiResponse.optimalPrice)?.estimatedDailyProfit);
1274 console.log('Math optimal:', maxProfitResult.price, 'with profit:', maxProfitResult.estimatedDailyProfit);
1275
1276 // Use the mathematically optimal price instead of AI suggestion
1277 let optimalResult = maxProfitResult;
1278
1279 // Update AI reasoning to reflect the correction
1280 if (Math.abs(maxProfitResult.price - aiResponse.optimalPrice) > 5) {
1281 aiResponse.reasoning = `Математический расчет показал, что оптимальная цена ${maxProfitResult.price}₽ (прибыль ${maxProfitResult.estimatedDailyProfit}₽/день) лучше, чем первоначально предложенная ${aiResponse.optimalPrice}₽. ${aiResponse.reasoning}`;
1282 console.log('>>> CORRECTED AI SUGGESTION <<<');
1283 }
1284
1285 const alternatives = [];
1286 aiResponse.explorationPrices.forEach(explorePrice => {
1287 if (explorePrice !== aiResponse.optimalPrice) {
1288 let altResult = results.find(r => r.price === explorePrice);
1289
1290 if (!altResult) {
1291 const priceChangePercent = (explorePrice / historicalData.avgPrice) - 1;
1292 const salesChangePercent = realElasticity * priceChangePercent;
1293 const estimatedSales = historicalData.avgDailySales * (1 + salesChangePercent);
1294
1295 const actualPrice = explorePrice / displayPriceMultiplier;
1296 const commission = actualPrice * productData.commission;
1297 const advertisingCost = actualPrice * (drr / 100);
1298 const delivery = productData.delivery;
1299 const profit = (actualPrice - productData.cost - commission - delivery - advertisingCost) * estimatedSales;
1300 const margin = ((actualPrice - productData.cost - commission - delivery - advertisingCost) / actualPrice) * 100;
1301
1302 altResult = {
1303 price: Math.round(explorePrice * 10) / 10,
1304 actualPrice: Math.round(actualPrice * 10) / 10,
1305 estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1306 estimatedDailyProfit: Math.round(profit * 10) / 10,
1307 profitMargin: Math.round(margin * 10) / 10,
1308 confidence: aiResponse.confidence,
1309 commission: Math.round(commission * 10) / 10,
1310 advertisingCost: Math.round(advertisingCost * 10) / 10,
1311 delivery: delivery
1312 };
1313 }
1314
1315 alternatives.push(altResult);
1316 }
1317 });
1318
1319 console.log('>>> RETURNING OPTIMIZATION RESULTS <<<');
1320 return {
1321 optimal: optimalResult,
1322 alternatives: alternatives,
1323 currentPrice: Math.round(historicalData.avgPrice),
1324 productData: productData,
1325 allResults: results,
1326 aiReasoning: aiResponse.reasoning,
1327 aiConfidence: aiResponse.confidence,
1328 aiDemandElasticity: realElasticity,
1329 elasticityReliability: elasticityResult.reliability,
1330 elasticityR2: elasticityResult.r2,
1331 elasticityUniquePrices: elasticityResult.uniquePrices,
1332 elasticityDaysUsed: elasticityResult.daysUsed,
1333 explorationPrices: aiResponse.explorationPrices,
1334 competitorData: competitorData,
1335 historicalData: historicalData,
1336 coinvest: coinvest,
1337 drr: drr
1338 };
1339
1340 } catch (error) {
1341 console.error('AI analysis failed:', error);
1342 throw error;
1343 }
1344 }
1345
1346 // Create and inject the analysis widget
1347 function createAnalysisWidget() {
1348 console.log('Creating analysis widget (v2.0.1)...');
1349
1350 if (document.getElementById('bayesian-price-optimizer')) {
1351 console.log('Widget already exists');
1352 return;
1353 }
1354
1355 const widget = document.createElement('div');
1356 widget.id = 'bayesian-price-optimizer';
1357 widget.innerHTML = `
1358 <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1359 color: white;
1360 padding: 15px;
1361 border-radius: 12px;
1362 margin: 15px 0;
1363 box-shadow: 0 4px 15px rgba(0,0,0,0.2);
1364 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1365 width: 100%;
1366 box-sizing: border-box;">
1367 <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
1368 <h3 style="margin: 0; font-size: 16px; font-weight: 600;">
1369 🎯 Оптимизация цены (AI + Bayesian) v2.0.1
1370 </h3>
1371 </div>
1372
1373 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px;">
1374 <div>
1375 <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1376 Соинвест (скидка OZON), %
1377 </label>
1378 <input type="number" id="coinvest-input" value="45" min="0" max="100" step="1"
1379 style="width: 100%; padding: 8px; border: none; border-radius: 6px;
1380 font-size: 14px; box-sizing: border-box; font-weight: 600;">
1381 </div>
1382 <div>
1383 <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1384 ДРР (расходы на рекламу), %
1385 </label>
1386 <input type="number" id="drr-input" value="0" min="0" max="100" step="0.1"
1387 style="width: 100%; padding: 8px; border: none; border-radius: 6px;
1388 font-size: 14px; box-sizing: border-box; font-weight: 600;">
1389 </div>
1390 </div>
1391
1392 <button id="analyze-price-btn" style="background: white;
1393 color: #667eea;
1394 border: none;
1395 padding: 10px 20px;
1396 border-radius: 8px;
1397 cursor: pointer;
1398 font-weight: 600;
1399 font-size: 14px;
1400 transition: all 0.3s;
1401 width: 100%;">
1402 Анализировать
1403 </button>
1404
1405 <div id="analysis-results" style="display: none; margin-top: 15px;">
1406 <div style="background: rgba(255,255,255,0.15);
1407 padding: 12px;
1408 border-radius: 8px;
1409 backdrop-filter: blur(10px);
1410 max-width: 600px;
1411 box-sizing: border-box;">
1412 <div id="results-content" style="overflow-wrap: break-word; word-wrap: break-word;"></div>
1413 </div>
1414 </div>
1415 <div id="loading-indicator" style="display: none; text-align: center; padding: 20px;">
1416 <div style="display: inline-block; width: 30px; height: 30px; border: 3px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; animation: spin 1s linear infinite;"></div>
1417 <p style="margin-top: 10px; font-size: 13px;">Анализируем данные с помощью AI...</p>
1418 </div>
1419 </div>
1420 `;
1421
1422 const style = document.createElement('style');
1423 style.textContent = `
1424 @keyframes spin {
1425 to { transform: rotate(360deg); }
1426 }
1427 #analyze-price-btn:hover {
1428 transform: translateY(-2px);
1429 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1430 }
1431 #bayesian-price-optimizer * {
1432 box-sizing: border-box;
1433 }
1434 `;
1435 document.head.appendChild(style);
1436
1437 const mpsWidget = document.querySelector('.mps-sidebar');
1438 if (mpsWidget) {
1439 mpsWidget.parentElement.insertBefore(widget, mpsWidget.nextSibling);
1440 console.log('Widget inserted after MP Stats');
1441 } else {
1442 document.body.appendChild(widget);
1443 console.log('Widget inserted at body end');
1444 }
1445
1446 const analyzeBtn = document.getElementById('analyze-price-btn');
1447 analyzeBtn.addEventListener('click', performAnalysis);
1448 }
1449
1450 // Perform the price analysis
1451 async function performAnalysis() {
1452 console.log('>>> performAnalysis CALLED (v2.0.1) <<<');
1453
1454 const loadingIndicator = document.getElementById('loading-indicator');
1455 const resultsDiv = document.getElementById('analysis-results');
1456 const resultsContent = document.getElementById('results-content');
1457
1458 loadingIndicator.style.display = 'block';
1459 resultsDiv.style.display = 'none';
1460
1461 try {
1462 // Get user input values
1463 const coinvestInput = document.getElementById('coinvest-input');
1464 const drrInput = document.getElementById('drr-input');
1465
1466 const coinvest = parseFloat(coinvestInput.value) || 45;
1467 const drr = parseFloat(drrInput.value) || 0;
1468
1469 console.log('User inputs - Coinvest:', coinvest, '%, DRR:', drr, '%');
1470
1471 // Validate inputs
1472 if (coinvest < 0 || coinvest > 100) {
1473 throw new Error('Соинвест должен быть от 0 до 100%');
1474 }
1475 if (drr < 0 || drr > 100) {
1476 throw new Error('ДРР должен быть от 0 до 100%');
1477 }
1478
1479 const productId = getProductId();
1480 console.log('Product ID:', productId);
1481
1482 if (!productId) {
1483 throw new Error('Не удалось определить ID товара');
1484 }
1485
1486 const shortSku = getShortSku(productId);
1487 console.log('Short SKU:', shortSku);
1488
1489 if (!shortSku) {
1490 throw new Error('Данные для этого товара не найдены');
1491 }
1492
1493 const productData = PRODUCT_DATA[shortSku];
1494 console.log('Product data:', productData);
1495
1496 if (!productData) {
1497 throw new Error('Данные для этого товара не найдены');
1498 }
1499
1500 console.log('>>> CALLING extractMPStatsData <<<');
1501 const mpStatsData = await extractMPStatsData();
1502 console.log('>>> extractMPStatsData FINISHED <<<');
1503
1504 if (!mpStatsData) {
1505 throw new Error('Не удалось извлечь данные из MP Stats');
1506 }
1507
1508 console.log('>>> CALLING extractCompetitorData <<<');
1509 const competitorData = await extractCompetitorData();
1510 console.log('>>> extractCompetitorData FINISHED <<<');
1511 console.log('Competitor data:', competitorData);
1512
1513 console.log('>>> CALLING bayesianPriceOptimizationWithAI <<<');
1514 const optimization = await bayesianPriceOptimizationWithAI(mpStatsData, productData, competitorData, coinvest, drr);
1515 console.log('>>> bayesianPriceOptimizationWithAI FINISHED <<<');
1516
1517 if (!optimization) {
1518 throw new Error('Ошибка при оптимизации цены');
1519 }
1520
1521 displayResults(optimization, coinvest, drr);
1522
1523 } catch (error) {
1524 console.error('Analysis error:', error);
1525 resultsContent.innerHTML = `
1526 <div style="color: #fee; padding: 10px; text-align: center;">
1527 <strong>⚠️ Ошибка:</strong><br>
1528 ${error.message}
1529 </div>
1530 `;
1531 resultsDiv.style.display = 'block';
1532 } finally {
1533 loadingIndicator.style.display = 'none';
1534 }
1535 }
1536
1537 // Display optimization results
1538 function displayResults(optimization, coinvest, drr) {
1539 const resultsDiv = document.getElementById('analysis-results');
1540 const resultsContent = document.getElementById('results-content');
1541
1542 const { optimal, alternatives, currentPrice, productData, allResults, aiReasoning, competitorData, historicalData } = optimization;
1543
1544 const currentDailySales = historicalData.avgDailySales;
1545
1546 // Calculate actual price from display price using user's coinvest value
1547 const displayPriceMultiplier = (100 - coinvest) / 100;
1548 const currentActualPrice = currentPrice / displayPriceMultiplier;
1549 const currentCommission = currentActualPrice * productData.commission;
1550 const currentAdvertisingCost = currentActualPrice * (drr / 100);
1551 const currentDelivery = productData.delivery;
1552 const currentDailyProfit = Math.round((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) * currentDailySales * 10) / 10;
1553 const currentDailyRevenue = Math.round(currentPrice * currentDailySales * 10) / 10;
1554 const currentMargin = Math.round(((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) / currentActualPrice) * 100 * 10) / 10;
1555 const currentProfitPerUnit = Math.round(currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost);
1556
1557 const optimalDailyRevenue = Math.round(optimal.price * optimal.estimatedDailySales * 10) / 10;
1558 const optimalProfitPerUnit = Math.round(optimal.actualPrice - productData.cost - optimal.commission - optimal.delivery - optimal.advertisingCost);
1559
1560 const priceChange = Math.round(((optimal.price - currentPrice) / currentPrice) * 100);
1561 const priceDiff = optimal.price - currentPrice;
1562 const actualPriceChange = Math.round(((optimal.actualPrice - currentActualPrice) / currentActualPrice) * 100);
1563 const actualPriceDiff = Math.round(optimal.actualPrice - currentActualPrice);
1564 const profitChange = currentDailyProfit > 0 ? Math.round(((optimal.estimatedDailyProfit - currentDailyProfit) / currentDailyProfit) * 100) : 0;
1565 const profitDiff = Math.round((optimal.estimatedDailyProfit - currentDailyProfit) * 10) / 10;
1566 const revenueChange = currentDailyRevenue > 0 ? Math.round(((optimalDailyRevenue - currentDailyRevenue) / currentDailyRevenue) * 100) : 0;
1567 const revenueDiff = Math.round((optimalDailyRevenue - currentDailyRevenue) * 10) / 10;
1568 const salesChange = currentDailySales > 0 ? Math.round(((optimal.estimatedDailySales - currentDailySales) / currentDailySales) * 100) : 0;
1569 const salesDiff = Math.round((optimal.estimatedDailySales - currentDailySales) * 10) / 10;
1570 const marginChange = Math.round((optimal.profitMargin - currentMargin) * 10) / 10;
1571 const profitPerUnitChange = currentProfitPerUnit > 0 ? Math.round(((optimalProfitPerUnit - currentProfitPerUnit) / currentProfitPerUnit) * 100) : 0;
1572 const profitPerUnitDiff = optimalProfitPerUnit - currentProfitPerUnit;
1573
1574 // Format AI reasoning with line breaks
1575 const formattedReasoning = aiReasoning
1576 .replace(/\. /g, '.<br>• ')
1577 .replace(/^/, '• ');
1578
1579 // Determine elasticity reliability color and text
1580 let reliabilityColor = '#ef4444'; // red for bad
1581 let reliabilityText = 'Плохо';
1582 let reliabilityIcon = '⚠️';
1583
1584 if (optimization.elasticityReliability === 'good') {
1585 reliabilityColor = '#10b981'; // green
1586 reliabilityText = 'Хорошо';
1587 reliabilityIcon = '✅';
1588 } else if (optimization.elasticityReliability === 'satisfactory') {
1589 reliabilityColor = '#f59e0b'; // orange
1590 reliabilityText = 'Удовлетворительно';
1591 reliabilityIcon = '⚡';
1592 }
1593
1594 let html = `
1595 <div style="background: rgba(59, 130, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #3b82f6;">
1596 <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">📊 Эластичность спроса:</div>
1597 <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">
1598 <div style="margin-bottom: 4px;">
1599 <strong>Коэффициент:</strong> ${optimization.aiDemandElasticity.toFixed(4)}
1600 <span style="font-size: 13px; opacity: 0.8;">(при изменении цены на 1%, продажи изменятся на ${(optimization.aiDemandElasticity * 100).toFixed(1)}%)</span>
1601 </div>
1602 <div style="margin-bottom: 4px;">
1603 <strong>Достоверность:</strong>
1604 <span style="color: ${reliabilityColor}; font-weight: 600;">${reliabilityIcon} ${reliabilityText}</span>
1605 </div>
1606 <div style="font-size: 12px; opacity: 0.8;">
1607 R² = ${optimization.elasticityR2.toFixed(4)} • ${optimization.elasticityUniquePrices} уникальных цен • ${optimization.elasticityDaysUsed} дней данных
1608 </div>
1609 </div>
1610 </div>
1611
1612 <div style="background: rgba(16, 185, 129, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #10b981;">
1613 <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">🤖 Рекомендация AI:</div>
1614 <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">${formattedReasoning}</div>
1615 </div>
1616 `;
1617
1618 if (competitorData && competitorData.length > 0) {
1619 html += `
1620 <div style="background: rgba(139, 92, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #8b5cf6;">
1621 <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">
1622 🏪 Конкуренты (${competitorData.length} шт):
1623 </div>
1624 `;
1625
1626 competitorData.slice(0, 5).forEach((comp, index) => {
1627 const competitorUrl = comp.sku ? `https://www.ozon.ru/product/${comp.sku}/` : '#';
1628 const salesInfo = comp.sales30days ? ` • ${(comp.sales30days / 30).toFixed(1)} шт/д` : '';
1629
1630 html += `
1631 <div style="font-size: 13px; padding: 4px 0; opacity: 0.9;">
1632 ${index + 1}. <a href="${competitorUrl}" target="_blank" style="color: white; text-decoration: underline;">${comp.price} ₽</a>${salesInfo}
1633 </div>
1634 `;
1635 });
1636
1637 html += '</div>';
1638 }
1639
1640 html += `
1641 <div style="background: #10b981; padding: 5px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; display: inline-block; margin-bottom: 10px;">
1642 ✨ ОПТИМАЛЬНАЯ ЦЕНА
1643 </div>
1644
1645 <table style="width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 14px;">
1646 <thead>
1647 <tr style="border-bottom: 2px solid rgba(255,255,255,0.3);">
1648 <th style="text-align: left; padding: 6px; font-size: 14px; opacity: 0.9;">Показатель</th>
1649 <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Текущая</th>
1650 <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Рекомендуемая</th>
1651 <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Δ</th>
1652 </tr>
1653 </thead>
1654 <tbody>
1655 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1656 <td style="padding: 8px 6px; font-size: 14px;">Цена реализации</td>
1657 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentPrice} ₽</td>
1658 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1659 ${optimal.price} ₽
1660 <span style="color: ${priceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; margin-left: 4px; font-weight: 700;">
1661 (${priceChange >= 0 ? '+' : ''}${priceChange}%)
1662 </span>
1663 </td>
1664 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${priceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1665 ${priceDiff >= 0 ? '+' : ''}${priceDiff} ₽
1666 </td>
1667 </tr>
1668 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1669 <td style="padding: 8px 6px; font-size: 14px;">Фактическая цена</td>
1670 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${Math.round(currentActualPrice)} ₽</td>
1671 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1672 ${Math.round(optimal.actualPrice)} ₽
1673 <span style="color: ${actualPriceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; margin-left: 4px; font-weight: 700;">
1674 (${actualPriceChange >= 0 ? '+' : ''}${actualPriceChange}%)
1675 </span>
1676 </td>
1677 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${actualPriceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1678 ${actualPriceDiff >= 0 ? '+' : ''}${actualPriceDiff} ₽
1679 </td>
1680 </tr>
1681 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1682 <td style="padding: 8px 6px; font-size: 14px;">Прибыль/день</td>
1683 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyProfit} ₽</td>
1684 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1685 ${optimal.estimatedDailyProfit} ₽
1686 <span style="color: ${profitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
1687 (${profitChange >= 0 ? '+' : ''}${profitChange}%)
1688 </span>
1689 </td>
1690 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1691 ${profitDiff >= 0 ? '+' : ''}${profitDiff} ₽
1692 </td>
1693 </tr>
1694 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1695 <td style="padding: 8px 6px; font-size: 14px;">Выручка/день</td>
1696 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyRevenue} ₽</td>
1697 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1698 ${optimalDailyRevenue} ₽
1699 <span style="color: ${revenueChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
1700 (${revenueChange >= 0 ? '+' : ''}${revenueChange}%)
1701 </span>
1702 </td>
1703 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${revenueDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1704 ${revenueDiff >= 0 ? '+' : ''}${revenueDiff} ₽
1705 </td>
1706 </tr>
1707 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1708 <td style="padding: 8px 6px; font-size: 14px;">Продажи/день</td>
1709 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailySales.toFixed(1)} шт</td>
1710 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1711 ${optimal.estimatedDailySales} шт
1712 <span style="color: ${salesChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
1713 (${salesChange >= 0 ? '+' : ''}${salesChange}%)
1714 </span>
1715 </td>
1716 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${salesDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1717 ${salesDiff >= 0 ? '+' : ''}${salesDiff} шт
1718 </td>
1719 </tr>
1720 <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1721 <td style="padding: 8px 6px; font-size: 14px;">Маржа %</td>
1722 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentMargin}%</td>
1723 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1724 ${optimal.profitMargin}%
1725 <span style="color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
1726 (${marginChange >= 0 ? '+' : ''}${marginChange}%)
1727 </span>
1728 </td>
1729 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1730 ${marginChange >= 0 ? '+' : ''}${marginChange}%
1731 </td>
1732 </tr>
1733 <tr>
1734 <td style="padding: 8px 6px; font-size: 14px;">Прибыль/шт</td>
1735 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentProfitPerUnit} ₽</td>
1736 <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
1737 ${optimalProfitPerUnit} ₽
1738 <span style="color: ${profitPerUnitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
1739 (${profitPerUnitChange >= 0 ? '+' : ''}${profitPerUnitChange}%)
1740 </span>
1741 </td>
1742 <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitPerUnitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
1743 ${profitPerUnitDiff >= 0 ? '+' : ''}${profitPerUnitDiff} ₽
1744 </td>
1745 </tr>
1746 </tbody>
1747 </table>
1748 `;
1749
1750 if (alternatives && alternatives.length > 0) {
1751 html += `
1752 <div style="margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px; font-size: 12px; opacity: 0.8;">
1753 💡 Анализ: ${allResults.length} вариантов цен. Уверенность: ${Math.round(optimal.confidence * 100)}%
1754 </div>
1755 `;
1756 }
1757
1758 resultsContent.innerHTML = html;
1759 resultsDiv.style.display = 'block';
1760
1761 setTimeout(() => createPriceChart(optimization), 100);
1762 }
1763
1764 // Create price analysis chart
1765 function createPriceChart(optimization) {
1766 const oldChart = document.getElementById('price-analysis-chart');
1767 if (oldChart) {
1768 oldChart.parentElement.remove();
1769 }
1770
1771 const canvas = document.createElement('canvas');
1772 canvas.id = 'price-analysis-chart';
1773 canvas.style.cssText = 'width: 100% !important; height: 250px !important;';
1774
1775 const chartContainer = document.createElement('div');
1776 chartContainer.style.cssText = 'margin-top: 12px; padding: 12px; background: rgba(255,255,255,0.1); border-radius: 8px; max-width: 600px; box-sizing: border-box;';
1777 chartContainer.innerHTML = `
1778 <div style="font-size: 14px; margin-bottom: 8px; opacity: 0.9; font-weight: 600;">
1779 📈 График зависимости от цены
1780 </div>
1781 `;
1782 chartContainer.appendChild(canvas);
1783
1784 const resultsContent = document.getElementById('results-content');
1785 resultsContent.appendChild(chartContainer);
1786
1787 const sortedResults = [...optimization.allResults].sort((a, b) => a.price - b.price);
1788 const prices = sortedResults.map(r => r.price);
1789 const sales = sortedResults.map(r => r.estimatedDailySales);
1790 const revenue = sortedResults.map(r => Math.round(r.price * r.estimatedDailySales));
1791 const profit = sortedResults.map(r => r.estimatedDailyProfit);
1792
1793 const ctx = canvas.getContext('2d');
1794 window.priceAnalysisChart = new Chart(ctx, {
1795 type: 'line',
1796 data: {
1797 labels: prices,
1798 datasets: [
1799 {
1800 label: 'Продажи (шт/д)',
1801 data: sales,
1802 borderColor: '#10b981',
1803 backgroundColor: 'rgba(16, 185, 129, 0.1)',
1804 yAxisID: 'y',
1805 tension: 0.4,
1806 borderWidth: 2
1807 },
1808 {
1809 label: 'Выручка (₽/д)',
1810 data: revenue,
1811 borderColor: '#f59e0b',
1812 backgroundColor: 'rgba(245, 158, 11, 0.1)',
1813 yAxisID: 'y1',
1814 tension: 0.4,
1815 borderWidth: 2
1816 },
1817 {
1818 label: 'Прибыль (₽/д)',
1819 data: profit,
1820 borderColor: '#ef4444',
1821 backgroundColor: 'rgba(239, 68, 68, 0.1)',
1822 yAxisID: 'y1',
1823 tension: 0.4,
1824 borderWidth: 3
1825 }
1826 ]
1827 },
1828 options: {
1829 responsive: true,
1830 maintainAspectRatio: true,
1831 aspectRatio: 2.2,
1832 interaction: {
1833 mode: 'index',
1834 intersect: false,
1835 },
1836 plugins: {
1837 legend: {
1838 position: 'top',
1839 labels: {
1840 usePointStyle: true,
1841 padding: 12,
1842 font: { size: 12 },
1843 color: 'white',
1844 boxWidth: 8,
1845 boxHeight: 8
1846 }
1847 },
1848 tooltip: {
1849 backgroundColor: 'rgba(0, 0, 0, 0.8)',
1850 padding: 10,
1851 titleFont: { size: 13 },
1852 bodyFont: { size: 12 },
1853 callbacks: {
1854 title: function(context) {
1855 return 'Цена: ' + context[0].label + ' ₽';
1856 },
1857 label: function(context) {
1858 let label = context.dataset.label || '';
1859 if (label) {
1860 label += ': ';
1861 }
1862 if (context.parsed.y !== null) {
1863 if (label.includes('шт')) {
1864 label += context.parsed.y.toFixed(1);
1865 } else {
1866 label += Math.round(context.parsed.y);
1867 }
1868 }
1869 return label;
1870 }
1871 }
1872 }
1873 },
1874 scales: {
1875 x: {
1876 title: {
1877 display: true,
1878 text: 'Цена (₽)',
1879 font: { size: 12, weight: 'bold' },
1880 color: 'white'
1881 },
1882 ticks: {
1883 maxTicksLimit: 8,
1884 font: { size: 11 },
1885 color: 'rgba(255, 255, 255, 0.8)'
1886 },
1887 grid: {
1888 color: 'rgba(255, 255, 255, 0.1)'
1889 }
1890 },
1891 y: {
1892 type: 'linear',
1893 display: true,
1894 position: 'left',
1895 title: {
1896 display: true,
1897 text: 'Продажи',
1898 color: '#10b981',
1899 font: { size: 12 }
1900 },
1901 ticks: {
1902 font: { size: 11 },
1903 color: 'rgba(255, 255, 255, 0.8)'
1904 },
1905 grid: {
1906 color: 'rgba(255, 255, 255, 0.1)'
1907 }
1908 },
1909 y1: {
1910 type: 'linear',
1911 display: true,
1912 position: 'right',
1913 title: {
1914 display: true,
1915 text: 'Выручка/Прибыль',
1916 color: '#f59e0b',
1917 font: { size: 12 }
1918 },
1919 grid: {
1920 drawOnChartArea: false,
1921 },
1922 ticks: {
1923 font: { size: 11 },
1924 color: 'rgba(255, 255, 255, 0.8)'
1925 }
1926 }
1927 }
1928 }
1929 });
1930
1931 console.log('График создан успешно');
1932 }
1933
1934 // Wait for MP Stats widget to load
1935 function waitForMPStats() {
1936 console.log('Waiting for MP Stats widget and page hydration...');
1937
1938 const checkInterval = setInterval(() => {
1939 const mpsWidget = document.querySelector('.mps-sidebar');
1940 const chartSvg = mpsWidget ? mpsWidget.querySelector('.vue-apexcharts svg') : null;
1941 const bars = chartSvg ? chartSvg.querySelectorAll('.apexcharts-bar-area') : null;
1942
1943 if (mpsWidget && chartSvg && bars && bars.length > 0) {
1944 console.log('MP Stats widget and chart found, waiting for hydration to complete...');
1945 clearInterval(checkInterval);
1946 setTimeout(createAnalysisWidget, 3000);
1947 }
1948 }, 1000);
1949
1950 setTimeout(() => {
1951 clearInterval(checkInterval);
1952 console.log('Stopped waiting for MP Stats widget');
1953 }, 30000);
1954 }
1955
1956 // Initialize
1957 function init() {
1958 console.log('OZON Price Optimizer initialized (v2.0.1)');
1959
1960 const productId = getProductId();
1961 if (!productId) {
1962 console.log('Not a product page, skipping...');
1963 return;
1964 }
1965
1966 console.log('Product page detected, waiting for MP Stats widget...');
1967
1968 if (document.readyState === 'loading') {
1969 document.addEventListener('DOMContentLoaded', waitForMPStats);
1970 } else {
1971 waitForMPStats();
1972 }
1973 }
1974
1975 init();
1976})();