/* ===== MODULE: legacy-catalog-v175.js ===== */ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс № 1 Канапе мясные","category":0,"price":3690,"photo":"catalog/001.jpg","weight":"600 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. канапе с мортаделлой и дроблённой фисташкой","5 шт. канапе с салями мадеро","5 шт. канапе с салями парма","5 шт. канапе с прошуто","5 шт. канапе с шейками капоколло с вялеными томатами"],"ingredients":[["канапе с мортаделлой и дроблённой фисташкой",5,"шт."],["канапе с салями мадеро",5,"шт."],["канапе с салями парма",5,"шт."],["канапе с прошуто",5,"шт."],["канапе с шейками капоколло с вялеными томатами",5,"шт."]],"catalogOrder":1},{"id":"2","name":"Фуршетный бокс № 2 Канапе рыбные","category":0,"price":4590,"photo":"catalog/002.jpg","weight":"600 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. тартинка с красной икрой и кремчизом","5 шт. кростини с лососем и кремчизом","5 шт. тартинка с креветкой и соусом цезарь","5 шт. кростини с креветкой и соусом чили","5 шт. кростини с форелью и сливочным соусом"],"ingredients":[["тартинка с красной икрой и кремчизом",5,"шт."],["кростини с лососем и кремчизом",5,"шт."],["тартинка с креветкой и соусом цезарь",5,"шт."],["кростини с креветкой и соусом чили",5,"шт."],["кростини с форелью и сливочным соусом",5,"шт."]],"catalogOrder":2},{"id":"3","name":"Фуршетный бокс № 3 Микс тарталеток","category":0,"price":4590,"photo":"catalog/003.jpg","weight":"790 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. тартинка с креветкой и соусом цезарь","5 шт. тартинка с щучьей икрой и мягким сыром","5 шт. тартинка с красной икрой и взбитым маслом","5 шт. тартинка с прошуто и грушей","5 шт. тартинка с мортаделлой"],"ingredients":[["тартинка с креветкой и соусом цезарь",5,"шт."],["тартинка с щучьей икрой и мягким сыром",5,"шт."],["тартинка с красной икрой и взбитым маслом",5,"шт."],["тартинка с прошуто и грушей",5,"шт."],["тартинка с мортаделлой",5,"шт."]],"catalogOrder":3},{"id":"4","name":"Фуршетный бокс № 4 Премиум морепродукты","category":0,"price":6990,"photo":"catalog/004.jpg","weight":"625 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. тартинка с тунцом","5 шт. канапе с тигровой креветкой с чили","5 шт. ролл из шпината с кремчизом и красной икрой","5 шт. ролл с чернилами каракатицы, лососем и сливочным сыром","5 шт. тартинка с тигровой креветкой и соусом из тунца"],"ingredients":[["тартинка с тунцом",5,"шт."],["канапе с тигровой креветкой с чили",5,"шт."],["ролл из шпината с кремчизом и красной икрой",5,"шт."],["ролл с чернилами каракатицы, лососем и сливочным сыром",5,"шт."],["тартинка с тигровой креветкой и соусом из тунца",5,"шт."]],"catalogOrder":4},{"id":"5","name":"Фуршетный бокс № 5 Брускетты мясные","category":0,"price":3990,"photo":"catalog/005.jpg","weight":"750 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. говядина с печёным перцем и горчицей","5 шт. салями мадеро с оливкой","5 шт. салями парма с маслинами и огурцом","5 шт. прошуто с грушой и кремчизом","5 шт. шейка капоколло с вяленым томатом"],"ingredients":[["говядина с печёным перцем и горчицей",5,"шт."],["салями мадеро с оливкой",5,"шт."],["салями парма с маслинами и огурцом",5,"шт."],["прошуто с грушой и кремчизом",5,"шт."],["шейка капоколло с вяленым томатом",5,"шт."]],"catalogOrder":5},{"id":"6","name":"Фуршетный бокс № 6 Сыры в шотах","category":0,"price":5490,"photo":"catalog/006.jpg","weight":"900 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. моцарелла с томатами и песто","5 шт. дорблю с грушей и малиной","5 шт. бри с миндалём и медовыми сотами","5 шт. пармезан с голубикой и пеканом","5 шт. чеддер с виноградом"],"ingredients":[["моцарелла с томатами и песто",5,"шт."],["дорблю с грушей и малиной",5,"шт."],["бри с миндалём и медовыми сотами",5,"шт."],["пармезан с голубикой и пеканом",5,"шт."],["чеддер с виноградом",5,"шт."]],"catalogOrder":6},{"id":"catalog-007","name":"Фуршетный бокс № 7 Сыр канапе","category":0,"price":3510,"photo":"catalog/007.jpg","weight":"450 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. бри с клубникой","5 шт. эдам с курагой","5 шт. пармезан с инжиром и голубикой","10 шт. чеддер с виноградом","5 шт. камамбер с голубикой"],"ingredients":[["бри с клубникой",5,"шт."],["эдам с курагой",5,"шт."],["пармезан с инжиром и голубикой",5,"шт."],["чеддер с виноградом",10,"шт."],["камамбер с голубикой",5,"шт."]],"catalogOrder":7},{"id":"catalog-008","name":"Фуршетный бокс № 50 Мини-эклеры","category":0,"price":4490,"photo":"catalog/008.jpg","weight":"500 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. мини-эклер с паштетом из куриных жареных печёнок — 20 г","5 шт. мини-эклер с риетом из тунца — 20 г","5 шт. мини-эклер с красной икрой и крем-чизом — 20 г","5 шт. мини-эклер с чёрной структурированной икрой и крем-чизом — 20 г","5 шт. мини-эклер с форелью и крем-чизом — 20 г"],"ingredients":[["мини-эклер с паштетом из куриных жареных печёнок — 20 г",5,"шт."],["мини-эклер с риетом из тунца — 20 г",5,"шт."],["мини-эклер с красной икрой и крем-чизом — 20 г",5,"шт."],["мини-эклер с чёрной структурированной икрой и крем-чизом — 20 г",5,"шт."],["мини-эклер с форелью и крем-чизом — 20 г",5,"шт."]],"catalogOrder":8},{"id":"catalog-009","name":"Фуршетный бокс № 21 Антипасти","category":0,"price":5590,"photo":"catalog/009.jpg","weight":"675 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. перчики греко с мягким сыром","5 шт. канапе с салями мадеро","5 шт. антипасти с оливками, томатами и виноградом","5 шт. ассорти сыров","5 шт. артишоки, вяленые томаты и печёный перец"],"ingredients":[["перчики греко с мягким сыром",5,"шт."],["канапе с салями мадеро",5,"шт."],["антипасти с оливками, томатами и виноградом",5,"шт."],["ассорти сыров",5,"шт."],["артишоки, вяленые томаты и печёный перец",5,"шт."]],"catalogOrder":9},{"id":"catalog-010","name":"Фуршетный бокс № 48 Мини-эклеры","category":0,"price":3790,"photo":"catalog/010.jpg","weight":"500 г","catalogSection":"Канапе и фуршетные закуски","composition":["15 шт. мини-эклер с паштетом из куриных жареных печёнок — 20 г","10 шт. мини-эклер с красной икрой и крем-чизом — 20 г"],"ingredients":[["мини-эклер с паштетом из куриных жареных печёнок — 20 г",15,"шт."],["мини-эклер с красной икрой и крем-чизом — 20 г",10,"шт."]],"catalogOrder":10},{"id":"catalog-011","name":"Фуршетный бокс № 15 Канапе рыбные","category":0,"price":5490,"photo":"catalog/011.jpg","weight":"700 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. крости с тар-таром из креветок","5 шт. канапе с тунцом и юдзу","5 шт. канапе с креветкой в панко и чили-соусом","5 шт. канапе с лососем и мягким сыром","5 шт. канапе с креветкой и соусом Цезарь"],"ingredients":[["крости с тар-таром из креветок",5,"шт."],["канапе с тунцом и юдзу",5,"шт."],["канапе с креветкой в панко и чили-соусом",5,"шт."],["канапе с лососем и мягким сыром",5,"шт."],["канапе с креветкой и соусом Цезарь",5,"шт."]],"catalogOrder":11},{"id":"catalog-012","name":"Фуршетный бокс № 16 Вегетарианский","category":0,"price":3790,"photo":"catalog/012.jpg","weight":"700 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. крости с моцареллой, черри и песто","5 шт. крости с баклажановой икрой и фетой","5 шт. крости с грибной икрой и трюфельной пастой","5 шт. крости с печёным перцем и фетой","5 шт. крости с вялеными томатами"],"ingredients":[["крости с моцареллой, черри и песто",5,"шт."],["крости с баклажановой икрой и фетой",5,"шт."],["крости с грибной икрой и трюфельной пастой",5,"шт."],["крости с печёным перцем и фетой",5,"шт."],["крости с вялеными томатами",5,"шт."]],"catalogOrder":12},{"id":"catalog-013","name":"Фуршетный бокс № 18 Тосты ассорти","category":0,"price":3190,"photo":"catalog/013.jpg","weight":"820 г","catalogSection":"Канапе и фуршетные закуски","composition":["25 шт. тостов ассорти","Тосты с селёдкой на свекольном муссе","Тосты с салом и солёным огурчиком"],"ingredients":[["тостов ассорти",25,"шт."],["Тосты с селёдкой на свекольном муссе",1,"поз."],["Тосты с салом и солёным огурчиком",1,"поз."]],"catalogOrder":13},{"id":"catalog-014","name":"Фуршетный бокс № 43 Тарталетки с икрой","category":0,"price":4890,"photo":"catalog/014.jpg","weight":"625 г","catalogSection":"Канапе и фуршетные закуски","composition":["15 шт. тарталетка с красной икрой и крем-чизом","10 шт. тарталетка с чёрной структурированной икрой и крем-чизом"],"ingredients":[["тарталетка с красной икрой и крем-чизом",15,"шт."],["тарталетка с чёрной структурированной икрой и крем-чизом",10,"шт."]],"catalogOrder":14},{"id":"catalog-015","name":"Фуршетный бокс № 49 Мини-эклеры","category":0,"price":3490,"photo":"catalog/015.jpg","weight":"500 г","catalogSection":"Канапе и фуршетные закуски","composition":["15 шт. мини-эклер с паштетом из куриных жареных печёнок — 20 г","10 шт. мини-эклер с риетом из тунца — 20 г"],"ingredients":[["мини-эклер с паштетом из куриных жареных печёнок — 20 г",15,"шт."],["мини-эклер с риетом из тунца — 20 г",10,"шт."]],"catalogOrder":15},{"id":"catalog-016","name":"Фуршетный бокс № 19 Рулетики ветчина-сыр","category":0,"price":3690,"photo":"catalog/016.jpg","weight":"1000 г","catalogSection":"Канапе и фуршетные закуски","composition":["50 шт. рулетики из ветчины с сыром"],"ingredients":[["рулетики из ветчины с сыром",50,"шт."]],"catalogOrder":16},{"id":"catalog-017","name":"Фуршетный бокс № 51 Брускетты с говядиной и томаты капрезе","category":0,"price":3990,"photo":"catalog/017.jpg","weight":"840 г","catalogSection":"Канапе и фуршетные закуски","composition":["12 шт. брускетта с пастрами из говядины — 35 г","12 шт. брускетта с моцареллой и томатами черри — 35 г"],"ingredients":[["брускетта с пастрами из говядины — 35 г",12,"шт."],["брускетта с моцареллой и томатами черри — 35 г",12,"шт."]],"catalogOrder":17},{"id":"catalog-018","name":"Фуршетный бокс № 27 Брускетты с тунцом и лососем","category":0,"price":4290,"photo":"catalog/018.jpg","weight":"840 г","catalogSection":"Канапе и фуршетные закуски","composition":["12 шт. брускетта с тунцом и апельсином — 35 г","12 шт. брускетта с лососем и крем-чизом — 35 г"],"ingredients":[["брускетта с тунцом и апельсином — 35 г",12,"шт."],["брускетта с лососем и крем-чизом — 35 г",12,"шт."]],"catalogOrder":18},{"id":"catalog-019","name":"Фуршетный бокс № 20 Профитроли","category":0,"price":4890,"photo":"catalog/019.jpg","weight":"700 г","catalogSection":"Канапе и фуршетные закуски","composition":["5 шт. профитроли с говядиной и соусом вителло тонато","5 шт. профитроли с красной икрой и сливочным маслом","5 шт. профитроли с риетом из копчёной форели","5 шт. профитроли с лососем и мягким сыром","5 шт. профитроли с паштетом из жареных куриных печёнок"],"ingredients":[["профитроли с говядиной и соусом вителло тонато",5,"шт."],["профитроли с красной икрой и сливочным маслом",5,"шт."],["профитроли с риетом из копчёной форели",5,"шт."],["профитроли с лососем и мягким сыром",5,"шт."],["профитроли с паштетом из жареных куриных печёнок",5,"шт."]],"catalogOrder":19},{"id":"catalog-020","name":"Фуршетный бокс № 26 Брускетты с креветками и муссом из лосося","category":0,"price":3690,"photo":"catalog/020.jpg","weight":"780 г","catalogSection":"Канапе и фуршетные закуски","composition":["12 шт. брускетта с креветкой и чили-соусом — 35 г","12 шт. брускетта с муссом из копчёного лосося — 30 г"],"ingredients":[["брускетта с креветкой и чили-соусом — 35 г",12,"шт."],["брускетта с муссом из копчёного лосося — 30 г",12,"шт."]],"catalogOrder":20},{"id":"catalog-021","name":"Фуршетный бокс № 28 Брускетты с говядиной и индейкой","category":0,"price":4290,"photo":"catalog/021.jpg","weight":"780 г","catalogSection":"Канапе и фуршетные закуски","composition":["12 шт. брускетта с говядиной — 35 г","12 шт. брускетта с пастрами из индейки — 30 г"],"ingredients":[["брускетта с говядиной — 35 г",12,"шт."],["брускетта с пастрами из индейки — 30 г",12,"шт."]],"catalogOrder":21},{"id":"catalog-022","name":"Фуршетный бокс № 29 Брускетты с мортаделлой и салями мадера","category":0,"price":3690,"photo":"catalog/022.jpg","weight":"720 г","catalogSection":"Канапе и фуршетные закуски","composition":["12 шт. брускетта с мортаделлой — 25 г","12 шт. брускетта с салями мадера — 35 г"],"ingredients":[["брускетта с мортаделлой — 25 г",12,"шт."],["брускетта с салями мадера — 35 г",12,"шт."]],"catalogOrder":22},{"id":"catalog-023","name":"Фуршетный бокс № 9 Салаты Цезарь микс в шотах","category":0,"price":4390,"photo":"catalog/023.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["8 пор. цезарь с цыплёнком в хрустящей корочке — 75 г","8 пор. цезарь с креветкой в темпуре — 75 г"],"ingredients":[["цезарь с цыплёнком в хрустящей корочке — 75 г",8,"пор."],["цезарь с креветкой в темпуре — 75 г",8,"пор."]],"catalogOrder":23},{"id":"catalog-024","name":"Фуршетный бокс № 8 Салат Цезарь с цыплёнком в панировке","category":0,"price":3460,"photo":"catalog/024.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. салата Цезарь: ромэн, черри, пармезан, цыплёнок в панировке, соус Цезарь, кростини — 75 г"],"ingredients":[["салата Цезарь: ромэн, черри, пармезан, цыплёнок в панировке, соус Цезарь, кростини — 75 г",16,"пор."]],"catalogOrder":24},{"id":"catalog-025","name":"Фуршетный бокс № 8 Салат Цезарь с креветкой в темпуре","category":0,"price":3790,"photo":"catalog/025.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. салата Цезарь: ромэн, черри, пармезан, креветка в темпуре, соус Цезарь, кростини — 75 г"],"ingredients":[["салата Цезарь: ромэн, черри, пармезан, креветка в темпуре, соус Цезарь, кростини — 75 г",16,"пор."]],"catalogOrder":25},{"id":"catalog-026","name":"Фуршетный бокс № 8 Салат Мимоза с лососем г/к","category":0,"price":4250,"photo":"catalog/026.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. салата Мимоза с лососем горячего копчения"],"ingredients":[["салата Мимоза с лососем горячего копчения",16,"пор."]],"catalogOrder":26},{"id":"catalog-027","name":"Фуршетный бокс № 8 Салат Греческий","category":0,"price":3290,"photo":"catalog/027.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. салата Греческий — 75 г"],"ingredients":[["салата Греческий — 75 г",16,"пор."]],"catalogOrder":27},{"id":"catalog-028","name":"Фуршетный бокс № 8 Салат Оливье с говядиной","category":0,"price":4690,"photo":"catalog/028.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. Оливье с говядиной — 75 г"],"ingredients":[["Оливье с говядиной — 75 г",16,"пор."]],"catalogOrder":28},{"id":"catalog-029","name":"Фуршетный бокс № 8 Салат Столичный с цыплёнком","category":0,"price":3890,"photo":"catalog/029.jpg","weight":"1200 г","catalogSection":"Салаты","composition":["16 пор. салата Столичный с цыплёнком в креманке — 75 г"],"ingredients":[["салата Столичный с цыплёнком в креманке — 75 г",16,"пор."]],"catalogOrder":29},{"id":"catalog-030","name":"Фуршетный бокс № 45 Салат Столичный в тарталетках","category":0,"price":3190,"photo":"catalog/030.jpg","weight":"900 г","catalogSection":"Салаты","composition":["20 шт. тарталеток","Салат Столичный с цыплёнком в тарталетках из песочного теста — 45 г"],"ingredients":[["тарталеток",20,"шт."],["Салат Столичный с цыплёнком в тарталетках из песочного теста",45,"г"]],"catalogOrder":30},{"id":"catalog-031","name":"Фуршетный бокс № 46 Салат Крабовый в тарталетках","category":0,"price":2790,"photo":"catalog/031.jpg","weight":"900 г","catalogSection":"Салаты","composition":["20 шт. тарталеток","Салат Крабовый классический в тарталетках из песочного теста — 45 г"],"ingredients":[["тарталеток",20,"шт."],["Салат Крабовый классический в тарталетках из песочного теста",45,"г"]],"catalogOrder":31},{"id":"catalog-032","name":"Фуршетный бокс № 47 Салат Оливье в тарталетках","category":0,"price":3890,"photo":"catalog/032.jpg","weight":"900 г","catalogSection":"Салаты","composition":["20 шт. тарталеток","Салат Оливье с говядиной в тарталетках из песочного теста — 45 г"],"ingredients":[["тарталеток",20,"шт."],["Салат Оливье с говядиной в тарталетках из песочного теста",45,"г"]],"catalogOrder":32},{"id":"catalog-033","name":"Фуршетный бокс № 47 Салат Оливье и Крабовый в тарталетках","category":0,"price":4290,"photo":"catalog/033.jpg","weight":"900 г","catalogSection":"Салаты","composition":["10 шт. тарталеток с Оливье и говядиной — 45 г","10 шт. тарталеток с классическим Крабовым салатом — 45 г"],"ingredients":[["тарталеток с Оливье и говядиной — 45 г",10,"шт."],["тарталеток с классическим Крабовым салатом — 45 г",10,"шт."]],"catalogOrder":33},{"id":"catalog-034","name":"Фуршетный бокс № 17 Круассаны с говядиной пастрами","category":0,"price":3500,"photo":"catalog/034.jpg","weight":"1050 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["20 шт. круассаны с говядиной, помидором и огурцом"],"ingredients":[["круассаны с говядиной, помидором и огурцом",20,"шт."]],"catalogOrder":34},{"id":"catalog-035","name":"Фуршетный бокс № 17 Круассаны с лососем","category":0,"price":4390,"photo":"catalog/035.jpg","weight":"1200 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["20 шт. круассаны с лососем с/с, салатом, свежим огурцом и сливочным соусом"],"ingredients":[["круассаны с лососем с/с, салатом, свежим огурцом и сливочным соусом",20,"шт."]],"catalogOrder":35},{"id":"catalog-036","name":"Фуршетный бокс № 10 Мини-бургеры классика","category":0,"price":4590,"photo":"catalog/036.jpg","weight":"1000 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["12 шт. бургеры с говяжьей котлетой","13 шт. бургеры с куриным стрипсом"],"ingredients":[["бургеры с говяжьей котлетой",12,"шт."],["бургеры с куриным стрипсом",13,"шт."]],"catalogOrder":36},{"id":"catalog-037","name":"Фуршетный бокс № 11 Сэндвичи с ветчиной и сыром","category":0,"price":2890,"photo":"catalog/037.jpg","weight":"1200 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["25 шт. сэндвич с ветчиной и сыром — 45 г"],"ingredients":[["сэндвич с ветчиной и сыром — 45 г",25,"шт."]],"catalogOrder":37},{"id":"catalog-038","name":"Фуршетный бокс № 12 Сэндвичи с лососем","category":0,"price":3990,"photo":"catalog/038.jpg","weight":"1200 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["25 шт. сэндвич с огурцом и лососем — 45 г"],"ingredients":[["сэндвич с огурцом и лососем — 45 г",25,"шт."]],"catalogOrder":38},{"id":"catalog-039","name":"Фуршетный бокс № 13 Мини-бургеры ассорти","category":0,"price":5990,"photo":"catalog/039.jpg","weight":"1000 г","catalogSection":"Бургеры, сэндвичи, круассаны","composition":["5 шт. бургер с говяжьей котлетой","5 шт. чизбургер с говяжьей котлетой","5 шт. бургер с креветкой","5 шт. бургер с куриной котлетой","5 шт. чикенбургер"],"ingredients":[["бургер с говяжьей котлетой",5,"шт."],["чизбургер с говяжьей котлетой",5,"шт."],["бургер с креветкой",5,"шт."],["бургер с куриной котлетой",5,"шт."],["чикенбургер",5,"шт."]],"catalogOrder":39},{"id":"catalog-040","name":"Фуршетный бокс № 14 Жюльен","category":0,"price":3290,"photo":"catalog/040.jpg","weight":"625 г","catalogSection":"Тёплые блюда и выпечка","composition":["25 шт. грибной жюльен с сыром пармезан в тарталетках — 25 г"],"ingredients":[["грибной жюльен с сыром пармезан в тарталетках — 25 г",25,"шт."]],"catalogOrder":40},{"id":"catalog-041","name":"Фуршетный бокс № 14 Жюльен с белыми грибами","category":0,"price":5290,"photo":"catalog/041.jpg","weight":"625 г","catalogSection":"Тёплые блюда и выпечка","composition":["25 шт. жюльен: белые грибы 70%, шампиньоны 30%, пармезан, тарталетки — 25 г"],"ingredients":[["жюльен: белые грибы 70%, шампиньоны 30%, пармезан, тарталетки — 25 г",25,"шт."]],"catalogOrder":41},{"id":"catalog-042","name":"Фуршетный бокс № 44 Пирог с сыром","category":0,"price":2690,"photo":"catalog/042.jpg","weight":"450 г","catalogSection":"Тёплые блюда и выпечка","composition":["16 пор. закрытого пирога с сыром"],"ingredients":[["закрытого пирога с сыром",16,"пор."]],"catalogOrder":42},{"id":"catalog-043","name":"Фуршетный бокс № 42 Блинчики с печенью","category":0,"price":2430,"photo":"catalog/043.jpg","weight":"875 г","catalogSection":"Тёплые блюда и выпечка","composition":["25 пор. блины с куриной печенью, луком и крем-чизом"],"ingredients":[["блины с куриной печенью, луком и крем-чизом",25,"пор."]],"catalogOrder":43},{"id":"catalog-044","name":"Фуршетный бокс № 24 Кулебяка и пирожки","category":0,"price":3890,"photo":"catalog/044.jpg","weight":"1070 г","catalogSection":"Тёплые блюда и выпечка","composition":["6 шт. пирожков с картошкой — 60 г","6 шт. пирожков с мясом — 60 г","1 шт. кулебяка с капустой — 350 г"],"ingredients":[["пирожков с картошкой — 60 г",6,"шт."],["пирожков с мясом — 60 г",6,"шт."],["кулебяка с капустой — 350 г",1,"шт."]],"catalogOrder":44},{"id":"catalog-045","name":"Фуршетный бокс № 33 Пирожки","category":0,"price":3690,"photo":"catalog/045.jpg","weight":"1080 г","catalogSection":"Тёплые блюда и выпечка","composition":["6 шт. пирожков с картошкой — 60 г","6 шт. пирожков с мясом — 60 г","6 шт. пирожков с капустой — 60 г"],"ingredients":[["пирожков с картошкой — 60 г",6,"шт."],["пирожков с мясом — 60 г",6,"шт."],["пирожков с капустой — 60 г",6,"шт."]],"catalogOrder":45},{"id":"catalog-046","name":"Фуршетный бокс № 25 Детский","category":0,"price":3690,"photo":"catalog/046.jpg","weight":"1150 г","catalogSection":"Тёплые блюда и выпечка","composition":["10 шт. чизбургеров — 500 г","Наггетсы — 300 г","Картофель фри — 200 г","Сырный соус — 50 г","Кетчуп — 50 г","Соус барбекю — 50 г"],"ingredients":[["чизбургеров — 500 г",10,"шт."],["Наггетсы",300,"г"],["Картофель фри",200,"г"],["Сырный соус",50,"г"],["Кетчуп",50,"г"],["Соус барбекю",50,"г"]],"catalogOrder":46},{"id":"catalog-047","name":"Фуршетный бокс № 42 Блинчики с мясом","category":0,"price":2590,"photo":"catalog/047.jpg","weight":"875 г","catalogSection":"Тёплые блюда и выпечка","composition":["25 пор. блины с мясным фаршем и крем-чизом"],"ingredients":[["блины с мясным фаршем и крем-чизом",25,"пор."]],"catalogOrder":47},{"id":"catalog-048","name":"Фуршетный набор № 30 Куриные шашлычки","category":0,"price":3790,"photo":"catalog/048.jpg","weight":"1120 г","catalogSection":"Тёплые блюда и выпечка","composition":["Куриные шашлычки — 560 г","Картофель бейби — 500 г","Соус — 60 г"],"ingredients":[["Куриные шашлычки",560,"г"],["Картофель бейби",500,"г"],["Соус",60,"г"]],"catalogOrder":48},{"id":"catalog-049","name":"Фуршетный бокс № 31 Свиной шашлычок","category":0,"price":3990,"photo":"catalog/049.jpg","weight":"1120 г","catalogSection":"Тёплые блюда и выпечка","composition":["Свиной шашлык — 560 г","Картофель бейби — 500 г","Соус — 60 г"],"ingredients":[["Свиной шашлык",560,"г"],["Картофель бейби",500,"г"],["Соус",60,"г"]],"catalogOrder":49},{"id":"catalog-050","name":"Фуршетный бокс № 32 Лосось на шпажке","category":0,"price":5690,"photo":"catalog/050.jpg","weight":"1120 г","catalogSection":"Тёплые блюда и выпечка","composition":["Шашлычки из лосося — 560 г","Картофель бейби — 500 г","Соус — 60 г"],"ingredients":[["Шашлычки из лосося",560,"г"],["Картофель бейби",500,"г"],["Соус",60,"г"]],"catalogOrder":50},{"id":"catalog-051","name":"Фуршетный бокс № 22 Фрукты","category":0,"price":3890,"photo":"catalog/051.jpg","weight":"1150 г","catalogSection":"Десерты и фрукты","composition":["16 шт. фрукты в ассортименте в креманке"],"ingredients":[["фрукты в ассортименте в креманке",16,"шт."]],"catalogOrder":51},{"id":"catalog-052","name":"Фуршетный бокс № 23 Слоёные десерты","category":0,"price":5690,"photo":"catalog/052.jpg","weight":"750 г","catalogSection":"Десерты и фрукты","composition":["12 шт. трайфл со сливочным бисквитом «Клубника со сливками»","13 шт. трайфл с шоколадным бисквитом «Сникерс» с орехами и карамелью"],"ingredients":[["трайфл со сливочным бисквитом «Клубника со сливками»",12,"шт."],["трайфл с шоколадным бисквитом «Сникерс» с орехами и карамелью",13,"шт."]],"catalogOrder":52},{"id":"catalog-053","name":"Фуршетный бокс № 35 Десерты","category":0,"price":3500,"photo":"catalog/053.jpg","weight":"750 г","catalogSection":"Десерты и фрукты","composition":["25 десертных порций ассорти","15 шт. одного вида","10 шт. второго вида"],"ingredients":[["25 десертных порций ассорти",1,"поз."],["одного вида",15,"шт."],["второго вида",10,"шт."]],"catalogOrder":53},{"id":"catalog-054","name":"Фуршетный бокс № 41 Сырники","category":0,"price":2690,"photo":"catalog/054.jpg","weight":"750 г","catalogSection":"Десерты и фрукты","composition":["25 шт. творожных сырников"],"ingredients":[["творожных сырников",25,"шт."]],"catalogOrder":54},{"id":"catalog-055","name":"Фуршетный бокс № 36 Десерты","category":0,"price":2990,"photo":"catalog/055.jpg","weight":"750 г","catalogSection":"Десерты и фрукты","composition":["25 десертных порций ассорти","10 шт. первого вида","10 шт. второго вида","5 шт. третьего вида"],"ingredients":[["25 десертных порций ассорти",1,"поз."],["первого вида",10,"шт."],["второго вида",10,"шт."],["третьего вида",5,"шт."]],"catalogOrder":55},{"id":"catalog-056","name":"Фуршетный бокс № 34 Десерты микс","category":0,"price":4690,"photo":"catalog/056.jpg","weight":"750 г","catalogSection":"Десерты и фрукты","composition":["Мафины","Бисквитный рулетик","Шоколадный вафельный торт","Бисквит с орехами и карамелью"],"ingredients":[["Мафины",1,"поз."],["Бисквитный рулетик",1,"поз."],["Шоколадный вафельный торт",1,"поз."],["Бисквит с орехами и карамелью",1,"поз."]],"catalogOrder":56},{"id":"catalog-057","name":"Морс","category":3,"price":450,"photo":"catalog/057.jpg","weight":"1 л","catalogSection":"Напитки","composition":["Морс ягодный"],"ingredients":[["Морс ягодный",1,"поз."]],"catalogOrder":57},{"id":"catalog-058","name":"Компот","category":3,"price":450,"photo":"catalog/058.jpg","weight":"1 л","catalogSection":"Напитки","composition":["Компот фруктовый"],"ingredients":[["Компот фруктовый",1,"поз."]],"catalogOrder":58},{"id":"catalog-059","name":"Готовое меню «Сытный» 15–20 гостей","category":0,"price":19900,"photo":"catalog/059.jpg","weight":"5700 г","catalogSection":"Готовые меню","composition":["Бокс № 5: 25 мясных брускетт","Бокс № 8: 16 пор. Оливье с говядиной","Бокс № 10: 12 бургеров с говядиной и 13 с курицей","Бокс № 11: 25 сэндвичей с ветчиной и сыром","Бокс № 24: 10 пирожков с картошкой, 10 с мясом и кулебяка с капустой"],"ingredients":[["Бокс № 5: 25 мясных брускетт",1,"поз."],["Бокс № 8: 16 пор. Оливье с говядиной",1,"поз."],["Бокс № 10: 12 бургеров с говядиной и 13 с курицей",1,"поз."],["Бокс № 11: 25 сэндвичей с ветчиной и сыром",1,"поз."],["Бокс № 24: 10 пирожков с картошкой, 10 с мясом и кулебяка с капустой",1,"поз."]],"catalogOrder":59},{"id":"catalog-060","name":"Готовое меню «Корпоратив» 50–70 гостей","category":0,"price":71640,"photo":"catalog/060.jpg","weight":"18540 г","catalogSection":"Готовые меню","composition":["Бокс № 1: 50 мясных канапе","Бокс № 2: 50 рыбных канапе","Бокс № 6: 50 сырных закусок в шотах","Бокс № 9: 32 пор. салата Цезарь","Бокс № 8: 32 пор. Мимозы с лососем","Бокс № 8: 32 пор. Оливье с говядиной","Бокс № 11: 25 сэндвичей с ветчиной и сыром","Бокс № 22: 32 пор. фруктов в креманке","Бокс № 23: 50 десертов ассорти"],"ingredients":[["Бокс № 1: 50 мясных канапе",1,"поз."],["Бокс № 2: 50 рыбных канапе",1,"поз."],["Бокс № 6: 50 сырных закусок в шотах",1,"поз."],["Бокс № 9: 32 пор. салата Цезарь",1,"поз."],["Бокс № 8: 32 пор. Мимозы с лососем",1,"поз."],["Бокс № 8: 32 пор. Оливье с говядиной",1,"поз."],["Бокс № 11: 25 сэндвичей с ветчиной и сыром",1,"поз."],["Бокс № 22: 32 пор. фруктов в креманке",1,"поз."],["Бокс № 23: 50 десертов ассорти",1,"поз."]],"catalogOrder":60}]; ; /* ===== MODULE: pdf-viewer-patch.js ===== */ (function(){ 'use strict'; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const IMAGE_DATA=window.SUN_CATALOG_IMAGE_DATA||{}; const LOGO_DATA=window.SUN_LOGO_DATA||''; let lastPdfUrl=''; function toast(message,type){ try{ if(window.SunEnterprise?.toast) return window.SunEnterprise.toast(message,type); }catch(_){} console[type==='warn'?'warn':'log'](message); } function currentCategory(){ const buttons=qa('#new .sun-catalog-top-toolbar .cats button,#new .cats button'); const active=buttons.find(b=>b.style.outline&&b.style.outline!=='none')||buttons.find(b=>b.getAttribute('aria-current')==='true'); if(active?.dataset?.category!=null)return Number(active.dataset.category); const title=document.querySelector('#new .catalog h1')?.textContent?.trim()||''; const names=[['Боксы',0],['Премиум',5],['Посуда',1],['Дополнения',2],['Напитки',3],['Доставка',4]]; return names.find(([name])=>title.startsWith(name))?.[1]??0; } const categoryName=cat=>{try{if(typeof window.sunCatalogCategoryName==='function')return window.sunCatalogCategoryName(cat)}catch(_){}return ({0:'Боксы',1:'Посуда',2:'Дополнения',3:'Напитки',4:'Доставка',5:'Премиум'})[cat]||'Каталог'}; function allBoxes(){ try{if(Array.isArray(boxes))return boxes}catch(_){} try{const saved=JSON.parse(localStorage.getItem('sunBoxes')||'[]');return Array.isArray(saved)?saved:[]}catch(_){return[]} } function ingredientWeight(row){if(!Array.isArray(row))return 0;const direct=Math.max(0,Number(row[3]||0));if(direct)return direct;const m=String(row[0]||'').match(/[—–-]\s*(\d+(?:[.,]\d+)?)\s*г(?:\s*\/\s*шт\.?)?\s*$/i);return m?Math.max(0,Number(String(m[1]).replace(',','.'))):0} function cleanIngredientName(name){return String(name||'').replace(/\s*[—–-]\s*\d+(?:[.,]\d+)?\s*г(?:\s*\/\s*шт\.?)?\s*$/i,'').trim()} function composition(item){ if(Array.isArray(item?.composition)&&item.composition.length)return item.composition.map(x=>String(x||'').trim()).filter(Boolean); if(Array.isArray(item?.ingredients)&&item.ingredients.some(x=>Array.isArray(x)&&x[0]))return item.ingredients.filter(x=>Array.isArray(x)&&x[0]).map(x=>{const q=Math.max(0,Number(x[1]||0)),u=String(x[2]||'').trim(),name=cleanIngredientName(x[0]),w=ingredientWeight(x),shown=Number.isInteger(q)?String(q):q.toLocaleString('ru-RU',{maximumFractionDigits:2});if(/^поз\.?$/i.test(u)&&q<=1)return `${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`;return `${shown} ${u} ${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`.replace(/\s+/g,' ').trim()}); return []; } const money=value=>`${Number(value||0).toLocaleString('ru-RU')} ₽`; const mm=v=>v*5; function roundedRect(ctx,x,y,w,h,r){ const rr=Math.min(r,w/2,h/2); ctx.beginPath();ctx.moveTo(x+rr,y);ctx.arcTo(x+w,y,x+w,y+h,rr);ctx.arcTo(x+w,y+h,x,y+h,rr);ctx.arcTo(x,y+h,x,y,rr);ctx.arcTo(x,y,x+w,y,rr);ctx.closePath(); } function wrapText(ctx,text,maxWidth,maxLines=20){ const words=String(text||'').replace(/\s+/g,' ').trim().split(' ').filter(Boolean), lines=[]; let line=''; for(const word of words){ const test=line?line+' '+word:word; if(ctx.measureText(test).width<=maxWidth||!line) line=test; else {lines.push(line);line=word;if(lines.length>=maxLines-1)break;} } if(line&&lines.length2&&ctx.measureText(last+'…').width>maxWidth)last=last.slice(0,-1); lines[maxLines-1]=last.replace(/[\s,.;:-]+$/,'')+'…'; } return lines; } function drawTextLines(ctx,lines,x,y,lineHeight){lines.forEach((line,i)=>ctx.fillText(line,x,y+i*lineHeight));} function imageSource(src){ src=String(src||'').trim(); if(!src)return LOGO_DATA; if(/^data:image\//i.test(src))return src; return IMAGE_DATA[src]||IMAGE_DATA[src.replace(/^\.\//,'')]||(/^sun-logo\.png$/i.test(src)?LOGO_DATA:src); } function loadImage(src){ return new Promise(resolve=>{ const raw=imageSource(src),img=new Image();let done=false; const finish=value=>{if(done)return;done=true;clearTimeout(timer);resolve(value)}; try{const url=new URL(raw,document.baseURI||location.href);if(/^https?:$/i.test(url.protocol)&&url.origin!==location.origin)img.crossOrigin='anonymous'}catch(_){} img.onload=()=>finish(img); img.onerror=()=>finish(null); const timer=setTimeout(()=>finish(null),15000); img.src=raw; }); } function drawContain(ctx,img,x,y,w,h,pad=0){ if(!img)return; const iw=img.naturalWidth||img.width, ih=img.naturalHeight||img.height; if(!iw||!ih)return; const aw=Math.max(1,w-pad*2),ah=Math.max(1,h-pad*2),scale=Math.min(aw/iw,ah/ih); const dw=iw*scale,dh=ih*scale; ctx.drawImage(img,x+(w-dw)/2,y+(h-dh)/2,dw,dh); } async function renderPageJpeg(item,cat,index,total,dateText){ const W=1050,H=1485,canvas=document.createElement('canvas');canvas.width=W;canvas.height=H; const ctx=canvas.getContext('2d',{alpha:false}); ctx.fillStyle='#f8f4eb';ctx.fillRect(0,0,W,H); ctx.textBaseline='alphabetic';ctx.textAlign='left'; const logo=await loadImage('sun-logo.png'); if(logo)drawContain(ctx,logo,85,50,72,72,1); ctx.fillStyle='#1f1f1d';ctx.font='800 36px Arial, sans-serif';ctx.fillText('СОЛНЦЕ КЕЙТЕРИНГ',177,83); const subtitle=cat===0?'ПОЛНЫЙ КАТАЛОГ ФУРШЕТНЫХ БОКСОВ':`КАТАЛОГ ${categoryName(cat).toUpperCase()}`; ctx.fillStyle='#88827a';ctx.font='600 16px Arial, sans-serif';ctx.fillText(subtitle,178,112); ctx.textAlign='right';ctx.font='500 15px Arial, sans-serif';ctx.fillText(`${String(index+1).padStart(2,'0')} / ${String(total).padStart(2,'0')}`,965,69);ctx.textAlign='left'; ctx.fillStyle='#c99a32';ctx.fillRect(85,143,880,2); const vx=85,vy=178,vw=880,vh=480; ctx.fillStyle='#f0ebdf';roundedRect(ctx,vx,vy,vw,vh,20);ctx.fill(); const photo=await loadImage(item.photo||'sun-logo.png'); if(photo)drawContain(ctx,photo,vx,vy,vw,vh,item.photo?14:165); const section=String(item.catalogSection||categoryName(cat)).toUpperCase(); ctx.font='800 17px Arial, sans-serif'; const sectionW=Math.min(720,Math.max(175,ctx.measureText(section).width+54)); ctx.fillStyle='#191919';roundedRect(ctx,115,201,sectionW,43,22);ctx.fill(); ctx.fillStyle='#fff';ctx.fillText(section,142,229); const titleY=717; ctx.fillStyle='#1f1f1d';ctx.font='800 36px Arial, sans-serif'; const nameLines=wrapText(ctx,item.name||'',650,2);drawTextLines(ctx,nameLines,85,titleY,41); ctx.textAlign='right';ctx.fillStyle='#c99a32';ctx.font='800 37px Arial, sans-serif';ctx.fillText(money(item.price||0),965,titleY);ctx.textAlign='left'; const factsY=820; ctx.fillStyle='#77736d';ctx.font='800 14px Arial, sans-serif';ctx.fillText('ВЕС',85,factsY);ctx.fillText('КОЛ-ВО',525,factsY); ctx.fillStyle='#232321';ctx.font='800 19px Arial, sans-serif';ctx.fillText(String(item.weight||'—').toUpperCase(),85,factsY+31);ctx.fillText(Number(item.pieces||0)>0?`${Math.round(Number(item.pieces))} ШТ.`:'—',525,factsY+31); ctx.fillStyle='#d9d0c2';ctx.fillRect(85,889,880,2); ctx.fillStyle='#1f1f1d';ctx.font='800 23px Arial, sans-serif';ctx.fillText('СОСТАВ',85,939); let lines=composition(item),rendered=[]; ctx.font='400 19px Arial, sans-serif'; for(const raw of lines){ const wrapped=wrapText(ctx,raw,795,2); for(const line of wrapped){if(rendered.length<9)rendered.push(line)} if(rendered.length>=9)break; } if(!rendered.length){ctx.fillStyle='#77736d';ctx.font='400 18px Arial, sans-serif';ctx.fillText('Состав не указан.',85,985)} else{ let y=985;ctx.font='400 19px Arial, sans-serif'; for(const line of rendered){ ctx.fillStyle='#c99a32';ctx.beginPath();ctx.arc(93,y-6,5,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#33312e';ctx.fillText(line,113,y);y+=32; } } ctx.fillStyle='#d9d0c2';ctx.fillRect(85,1400,880,2); ctx.fillStyle='#88827a';ctx.font='400 14px Arial, sans-serif';ctx.fillText('+7 (921) 954-04-40 • solnce-keytering.ru',85,1435); ctx.textAlign='right';ctx.fillText(`Цены актуальны на ${dateText}`,965,1435);ctx.textAlign='left'; let dataUrl; try{dataUrl=canvas.toDataURL('image/jpeg',0.88)}catch(_){dataUrl=''} if(!dataUrl)throw new Error('Не удалось сформировать страницу PDF.'); const binary=atob(dataUrl.split(',')[1]),bytes=new Uint8Array(binary.length); for(let i=0;iwindow.SunPdfEngine.fromJpegs(pages); async function createCatalogPdfBlob(cat,progress){ const items=allBoxes().filter(item=>Number(item.category||0)===Number(cat)); if(!items.length)throw new Error('В этом разделе нет позиций.'); const pages=[],dateText=new Date().toLocaleDateString('ru-RU'); for(let i=0;isetTimeout(resolve,0)); } return buildPdf(pages); } function loadingPage(win,title){ try{ win.document.open(); win.document.write(`${title}
Формируем актуальный PDF-каталог
Подготовка…
`); win.document.close(); }catch(_){} } function updateProgress(win,current,total){try{const p=win.document.getElementById('p');if(p)p.textContent=`Страница ${current} из ${total}`;}catch(_){} } async function openCatalogPdfViewer(){ const cat=currentCategory(); if(cat===4)return; const viewer=window.open('about:blank','_blank'); if(!viewer){toast('Браузер заблокировал новую вкладку. Разрешите всплывающие окна для приложения.','warn');return} loadingPage(viewer,'Каталог — Солнце Кейтеринг'); try{ const blob=await createCatalogPdfBlob(cat,(n,t)=>updateProgress(viewer,n,t)); if(lastPdfUrl)URL.revokeObjectURL(lastPdfUrl); lastPdfUrl=URL.createObjectURL(blob); viewer.location.replace(lastPdfUrl); }catch(err){ try{viewer.document.body.innerHTML=`
Не удалось открыть PDF.

${String(err?.message||err)}

`}catch(_){} toast(err?.message||'Не удалось сформировать PDF.','warn'); } } function installButton(){ const head=document.querySelector('#new .catalog .catalog-head');if(!head)return; const configure=qa('button',head).find(b=>(b.textContent||'').trim()==='Настроить');if(!configure)return; let old=$('sunLiveCatalogPdfButton'),btn; if(old){btn=old.cloneNode(true);old.replaceWith(btn)} else{btn=document.createElement('button');btn.id='sunLiveCatalogPdfButton';btn.type='button';btn.className='outline';configure.insertAdjacentElement('beforebegin',btn)} btn.textContent='PDF'; btn.title='Открыть актуальный PDF-каталог. В просмотрщике браузера можно скачать или распечатать.'; btn.onclick=openCatalogPdfViewer; const hide=currentCategory()===4;btn.hidden=hide;btn.style.display=hide?'none':'inline-flex'; } window.sunOpenCatalogPdfViewer=openCatalogPdfViewer; window.sunBuildCatalogPdfBlob=()=>createCatalogPdfBlob(currentCategory()); window.sunCatalogDebugPdfPages=async(cat=currentCategory(),limit=3)=>{const items=allBoxes().filter(item=>Number(item.category||0)===Number(cat)).slice(0,Math.max(1,Number(limit||3)));const dateText=new Date().toLocaleDateString('ru-RU'),pages=[];for(let i=0;i{if(e.target.closest('#new .cats button,#new .sun-catalog-top-toolbar .cats button'))setTimeout(installButton,30)},true); const catalog=document.querySelector('#new .catalog');if(catalog&&'MutationObserver'in window)new MutationObserver(()=>{const b=$('sunLiveCatalogPdfButton');if(!b||b.textContent!=='PDF'||b.onclick!==openCatalogPdfViewer)queueMicrotask(installButton)}).observe(catalog,{childList:true,subtree:true}); })(); ; /* ===== MODULE: feature-pack-v1.js ===== */ (function(){ 'use strict'; if(window.__sunFeaturePackV1)return; window.__sunFeaturePackV1=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const esc=window.SunSafe.escapeHTML; const money=v=>`${Math.round(Number(v||0)).toLocaleString('ru-RU')} ₽`; const toast=(m,t='success')=>{try{return window.SunEnterprise?.toast?.(m,t)}catch(_){}; if(t==='warn'||t==='error')console.warn(m);}; const style=document.createElement('style'); style.id='sun-feature-pack-v1-style'; style.textContent=` #new .catalog-head{gap:8px;flex-wrap:wrap} #new .sun-catalog-search{height:35px;min-width:180px;width:min(235px,28vw);padding:6px 10px;border:1px solid #d9dde0;border-radius:8px;background:#fff;color:#203040} #new .sun-catalog-tabs-button{white-space:nowrap} #manager .sun-manager-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px} #manager .sun-manager-toolbar .primary{margin:0} #manager .sun-manager-search{flex:1 1 220px;min-width:180px} .sun-category-list{display:grid;gap:8px;margin-top:12px} .sun-category-row{display:grid;grid-template-columns:minmax(180px,1fr) 58px auto auto;gap:8px;align-items:center;padding:9px;border:1px solid #e0e4e8;border-radius:10px;background:#fff} .sun-category-row.is-hidden{opacity:.6;background:#f6f7f8} .sun-category-row input{width:100%}.sun-category-color{display:grid;place-items:center;margin:0}.sun-category-color input{width:42px;height:34px;padding:2px;border:1px solid #d9dde0;border-radius:8px;background:#fff;cursor:pointer} .sun-category-row small{color:#7b858d;white-space:nowrap} .sun-category-row-actions{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end} .sun-category-add{display:grid;grid-template-columns:1fr auto;gap:8px;margin-top:14px;padding-top:12px;border-top:1px solid #e6e8eb} .sun-order-requisites{display:none;margin-top:4px} .sun-order-requisites-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px} .sun-order-requisites-grid .wide{grid-column:1/-1} .sun-order-requisites h3{margin:6px 0 12px;color:#15364c} .sun-order-qr-box{display:grid;grid-template-columns:110px minmax(0,1fr);gap:14px;align-items:center;margin-top:16px;padding:12px;border:1px solid #e1e4e7;border-radius:12px;background:#fafbfc} .sun-order-qr-preview{width:100px;height:100px;border:1px dashed #c7cdd2;border-radius:8px;background:#fff;display:grid;place-items:center;overflow:hidden;color:#8a949b;font-size:11px;text-align:center;padding:5px} .sun-order-qr-preview img{width:100%;height:100%;object-fit:contain} .sun-order-qr-actions{display:flex;gap:7px;flex-wrap:wrap;margin-top:8px} .sun-discount-panel{display:grid;grid-template-columns:1fr;gap:10px;margin-top:10px;padding:11px;border:1px solid #e3e6e9;border-radius:10px;background:#fafbfc} .sun-discount-combo{display:grid;grid-template-columns:minmax(0,1fr) 78px;gap:6px} .sun-promo-select-wrap{display:grid;gap:5px} .sun-promo-select-wrap select{width:100%} .sun-promo-meta{font-size:12px;color:#68717a;line-height:1.35;min-height:16px} .sun-discount-panel label>span{display:block;color:#68717a;font-size:12px;margin-bottom:5px} .sun-order-summary-discount{color:#8a5b00} .sun-order-summary-net{font-weight:800;color:#15364c} .sun-order-summary-promo small{color:#7b858d;margin-left:5px} .sun-doc-qr{width:92px;height:92px;object-fit:contain;border:1px solid #e0e3e5;border-radius:7px;padding:4px;background:#fff} .sun-doc-title-with-qr{display:flex;align-items:flex-start;gap:14px;justify-content:flex-end} .sun-doc-title-with-qr .sun-doc-title{text-align:right} .sun-doc-qr-wrap{display:flex;align-items:center;gap:9px;max-width:295px} .sun-doc-qr-note{min-width:115px;max-width:180px;padding:7px 8px;border:1px dashed #c8cdd2;border-radius:8px;background:#fff;color:#4f5962;font-size:11px;line-height:1.35;text-align:left;white-space:pre-wrap;overflow-wrap:anywhere} .sun-doc-qr-note:empty:before{content:attr(data-placeholder);color:#9aa1a8} .sun-doc-qr-note:focus{outline:2px solid #d8b766;outline-offset:1px;border-color:transparent} @media print{.sun-doc-qr-note{border:0!important;padding:0!important;background:transparent!important;outline:0!important}.sun-doc-qr-note:empty{display:none!important}} .sun-receipt .sun-receipt-party{margin:4px 0;padding:6px 8px;border-radius:6px} .sun-receipt .sun-receipt-party h3{font-size:11px;margin:0 0 4px} .sun-receipt .sun-receipt-party-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:2px 10px;font-size:9.5px} .sun-receipt .sun-receipt-party-grid div{padding:1px 0;border-bottom:0;line-height:1.15} .sun-receipt .sun-receipt-party-grid span{font-size:7.5px;margin-bottom:1px} .sun-receipt .sun-receipt-party-grid b{font-size:9.5px;line-height:1.15} #sunReceiptSettingsCard .sun-buyer-settings-hidden{display:none!important} .sun-default-qr-setting{display:grid;grid-template-columns:100px minmax(0,1fr);gap:14px;align-items:center} .sun-default-qr-setting .preview{width:92px;height:92px;border:1px dashed #cbd1d6;border-radius:8px;background:#fff;display:grid;place-items:center;overflow:hidden;color:#8a949b;font-size:11px;text-align:center;padding:4px} .sun-default-qr-setting .preview img{width:100%;height:100%;object-fit:contain} .sun-default-qr-setting .actions{justify-content:flex-start;margin-top:8px} .sun-promo-stats{margin-top:18px;border:1px solid #e0e4e8;border-radius:12px;background:#fff;padding:14px} .sun-promo-stats h2{margin:0 0 4px;color:#15364c} .sun-promo-stats table{width:100%;border-collapse:collapse;margin-top:12px} .sun-promo-stats th,.sun-promo-stats td{padding:8px;border-bottom:1px solid #e8eaec;text-align:left} .sun-promo-stats th{font-size:12px;color:#68717a;background:#fafbfc}.sun-promo-stats td.num,.sun-promo-stats th.num{text-align:right} .sun-box-weight-field,.sun-box-pieces-field{margin-top:8px}.sun-box-weight-field input,.sun-box-pieces-field input{max-width:220px}.sun-box-pieces-field small{display:block;margin-top:3px;color:#7b858d;line-height:1.3}.sun-ingredient-head,.ingredient.sun-ingredient-v175{display:grid;grid-template-columns:minmax(220px,1fr) 88px 78px 112px 34px;gap:6px;align-items:center}.sun-ingredient-head{margin:8px 0 4px;color:#68717a;font-size:11px;font-weight:700}.sun-ingredient-head span:nth-child(n+2){text-align:center}.ingredient.sun-ingredient-v175 input{text-align:left;min-width:0}.ingredient.sun-ingredient-v175 input[type=number]{text-align:center}.sun-order-line-name small{display:block;margin-top:3px;color:#7b858d;font-size:10px;font-weight:600;line-height:1.25}.sun-order-line-name small b{color:#53616d}.sun-doc .doc-sub.sun-doc-weight{margin-top:2px;color:#66727c;font-weight:600} @media(max-width:850px){.sun-receipt .sun-receipt-party-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} @media(max-width:650px){#new .sun-catalog-search{width:100%;flex:1 1 100%}.sun-order-requisites-grid{grid-template-columns:1fr}.sun-order-qr-box,.sun-default-qr-setting{grid-template-columns:1fr}.sun-category-row{grid-template-columns:1fr}.sun-category-row-actions{justify-content:flex-start}.sun-ingredient-head{display:none}.ingredient.sun-ingredient-v175{grid-template-columns:minmax(0,1fr) 64px 58px 84px 32px}.ingredient.sun-ingredient-v175 input{padding:7px 5px;font-size:12px}} @media print{.sun-doc-title-with-qr{gap:8mm}.sun-doc-qr{width:25mm;height:25mm}.sun-receipt .sun-receipt-party{padding:1.5mm 2mm;margin:1mm 0}.sun-receipt .sun-receipt-party-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:.5mm 2mm}} `; document.head.appendChild(style); // ---------------- Catalog categories + search ---------------- const CAT_KEY='sunCatalogCategoriesV2'; const defaultCats=[ {id:0,name:'Боксы',accent:'#d49a2a',prep:true,hidden:false,order:0}, {id:5,name:'Премиум',accent:'#7a5aa6',prep:true,hidden:false,order:1}, {id:3,name:'Напитки',accent:'#4f9bd8',prep:false,hidden:false,order:2}, {id:2,name:'Дополнения',accent:'#56a889',prep:false,hidden:false,order:3}, {id:1,name:'Посуда',accent:'#a78bfa',prep:false,hidden:false,order:4}, {id:4,name:'Доставка',accent:'#cf9f83',prep:false,hidden:false,order:5} ]; function readCats(){ let saved=[];try{saved=JSON.parse(localStorage.getItem(CAT_KEY)||'[]');if(!Array.isArray(saved))saved=[]}catch(_){saved=[]} const map=new Map(saved.filter(x=>x&&Number.isFinite(Number(x.id))).map(x=>[Number(x.id),x])); defaultCats.forEach(d=>{if(!map.has(d.id))map.set(d.id,d);else map.set(d.id,{...d,...map.get(d.id),id:d.id})}); try{(Array.isArray(boxes)?boxes:[]).forEach(item=>{const id=Number(item?.category||0);if(Number.isFinite(id)&&!map.has(id))map.set(id,{id,name:`Вкладка ${id}`,accent:'#708090',prep:true,hidden:false,order:map.size})})}catch(_){} const arr=[...map.values()].map((c,i)=>({id:Number(c.id),name:String(c.name||`Вкладка ${i+1}`).trim()||`Вкладка ${i+1}`,accent:c.accent||'#708090',prep:c.prep!==false,hidden:Boolean(c.hidden),order:Number.isFinite(Number(c.order))?Number(c.order):i})); arr.sort((a,b)=>a.order-b.order||a.id-b.id);arr.forEach((c,i)=>c.order=i);return arr; } let catalogCats=readCats(); const CAT_LAYOUT_VERSION_KEY='sunCatalogCategoryLayoutVersion'; const CAT_LAYOUT_VERSION='2026-09-02-premium-between-boxes-and-drinks'; if(localStorage.getItem(CAT_LAYOUT_VERSION_KEY)!==CAT_LAYOUT_VERSION){const desired=[0,5,3,2,1,4];const rank=new Map(desired.map((id,i)=>[id,i]));catalogCats.sort((a,b)=>(rank.has(a.id)?rank.get(a.id):100+a.order)-(rank.has(b.id)?rank.get(b.id):100+b.order));catalogCats.forEach((c,i)=>c.order=i);try{localStorage.setItem(CAT_KEY,JSON.stringify(catalogCats));localStorage.setItem(CAT_LAYOUT_VERSION_KEY,CAT_LAYOUT_VERSION)}catch(_){}} function saveCats(){catalogCats.sort((a,b)=>a.order-b.order||a.id-b.id).forEach((c,i)=>c.order=i);try{localStorage.setItem(CAT_KEY,JSON.stringify(catalogCats))}catch(_){}window.dispatchEvent(new CustomEvent('sun:catalog-categories-changed'));} function tabTextColor(value){const hex=String(value||'').trim();const m=/^#([0-9a-f]{6})$/i.exec(hex);if(!m)return '#fff';const n=parseInt(m[1],16),r=(n>>16)&255,g=(n>>8)&255,b=n&255;return (r*299+g*587+b*114)>160000?'#15364c':'#fff'} const catById=id=>catalogCats.find(c=>Number(c.id)===Number(id)); const catName=id=>catById(id)?.name||'Каталог'; const visibleCats=()=>catalogCats.filter(c=>!c.hidden).sort((a,b)=>a.order-b.order); let activeCat=visibleCats()[0]?.id??0; let catalogQuery=''; let managerQuery=''; window.sunCatalogCategoryName=catName; window.sunCatalogCategories=()=>catalogCats.map(c=>({...c})); window.sunCurrentCatalogCategory=()=>activeCat; function ensureCategoryModal(){ if($('sunCategoryManager'))return; const modal=document.createElement('div');modal.id='sunCategoryManager';modal.className='modal'; modal.innerHTML=`

Вкладки каталога

Скрытая вкладка и её товары не удаляются — её можно вернуть.

`; document.body.appendChild(modal); $('sunAddCategoryBtn').onclick=()=>{ const name=$('sunNewCategoryName').value.trim();if(!name)return; const nextId=Math.max(4,...catalogCats.map(c=>Number(c.id)||0))+1; catalogCats.push({id:nextId,name,accent:'#708090',prep:true,hidden:false,order:catalogCats.length});saveCats();$('sunNewCategoryName').value='';renderCategoryManager();renderCategoryTabs();syncEditorCategoryOptions(); }; } function renderCategoryManager(){ ensureCategoryModal();const root=$('sunCategoryRows');if(!root)return; root.innerHTML=catalogCats.slice().sort((a,b)=>a.order-b.order).map(c=>{ const count=(typeof boxes!=='undefined'?boxes:[]).filter(b=>Number(b.category||0)===Number(c.id)).length; return `
${count} поз.
`; }).join(''); qa('[data-cat-name]',root).forEach(input=>input.onchange=()=>{const c=catById(input.dataset.catName);if(!c)return;c.name=input.value.trim()||c.name;saveCats();renderCategoryTabs();syncEditorCategoryOptions();renderCatalogV5();renderCategoryManager();}); qa('[data-cat-color]',root).forEach(input=>{input.oninput=()=>{const c=catById(input.dataset.catColor);if(!c)return;c.accent=input.value||c.accent;renderCategoryTabs();};input.onchange=()=>{const c=catById(input.dataset.catColor);if(!c)return;c.accent=input.value||c.accent;saveCats();renderCategoryTabs();};}); qa('[data-cat-toggle]',root).forEach(btn=>btn.onclick=()=>{const c=catById(btn.dataset.catToggle);if(!c)return;c.hidden=!c.hidden;if(c.hidden&&Number(activeCat)===Number(c.id))activeCat=visibleCats().find(x=>Number(x.id)!==Number(c.id))?.id??0;saveCats();renderCategoryTabs();syncEditorCategoryOptions();renderCatalogV5();renderCategoryManager();}); const move=(id,dir)=>{const arr=catalogCats.slice().sort((a,b)=>a.order-b.order),i=arr.findIndex(c=>Number(c.id)===Number(id)),j=i+dir;if(i<0||j<0||j>=arr.length)return;[arr[i],arr[j]]=[arr[j],arr[i]];arr.forEach((c,k)=>c.order=k);catalogCats=arr;saveCats();renderCategoryTabs();renderCategoryManager();}; qa('[data-cat-up]',root).forEach(btn=>btn.onclick=()=>move(btn.dataset.catUp,-1));qa('[data-cat-down]',root).forEach(btn=>btn.onclick=()=>move(btn.dataset.catDown,1)); } window.sunOpenCategoryManager=()=>{renderCategoryManager();window.modal?.('sunCategoryManager');}; function renderCategoryTabs(){ const panel=document.querySelector('#new .cats');if(!panel)return; const visible=visibleCats();if(!visible.some(c=>Number(c.id)===Number(activeCat)))activeCat=visible[0]?.id??0; panel.innerHTML=visible.map(c=>``).join('')+'

Выберите раздел. Любую позицию можно добавить, изменить или удалить.

'; qa('button',panel).forEach(btn=>{const c=catById(btn.dataset.category),on=Number(btn.dataset.category)===Number(activeCat);btn.style.background=c?.accent||'#708090';btn.style.color=tabTextColor(c?.accent||'#708090');btn.style.opacity=on?'1':'.72';btn.style.outline=on?'2px solid #15364c':'none';btn.style.outlineOffset=on?'2px':'0';btn.onclick=()=>{activeCat=Number(btn.dataset.category);catalogQuery='';const search=$('sunCatalogSearch');if(search)search.value='';renderCategoryTabs();renderCatalogV5();};}); } function syncEditorCategoryOptions(){ const select=$('itemCategory');if(!select)return;const current=select.value; select.innerHTML=catalogCats.slice().sort((a,b)=>a.order-b.order).map(c=>``).join(''); if([...select.options].some(o=>o.value===current))select.value=current; } function ensureCatalogTools(){ const head=document.querySelector('#new .catalog .catalog-head');if(!head)return; const configure=qa('button',head).find(b=>(b.textContent||'').trim()==='Настроить');if(!configure)return; let search=$('sunCatalogSearch');if(!search){search=document.createElement('input');search.id='sunCatalogSearch';search.className='sun-catalog-search';search.type='search';search.placeholder='Поиск по № бокса';search.inputMode='numeric';search.oninput=()=>{catalogQuery=search.value;renderCatalogV5();};configure.insertAdjacentElement('beforebegin',search)} let tabs=$('sunCatalogTabsButton');if(!tabs){tabs=document.createElement('button');tabs.id='sunCatalogTabsButton';tabs.className='outline sun-catalog-tabs-button';tabs.type='button';tabs.textContent='Вкладки';tabs.onclick=window.sunOpenCategoryManager;configure.insertAdjacentElement('beforebegin',tabs)} } function lineUnitPrice(line){const direct=Number(line?.price);if(Number.isFinite(direct)&&direct>=0)return direct;const item=boxes.find(x=>String(x.id)===String(line?.id));return Math.max(0,Number(item?.price||0));} function baseTotal(order){return (order?.lines||[]).reduce((s,l)=>s+lineUnitPrice(l)*Math.max(0,Number(l.qty||0)),0)} window.sunBaseOrderTotal=baseTotal; function parseWeightGrams(value){const raw=String(value??'').trim().toLowerCase().replace(',','.');if(!raw)return 0;const m=raw.match(/(\d+(?:\.\d+)?)/);if(!m)return 0;let n=Math.max(0,Number(m[1]||0));if(/кг/.test(raw))n*=1000;return Math.round(n)} const pieceUnitRe=/^(?:шт\.?|пор\.?|кус\.?|шарик(?:а|ов|и)?|креманк(?:а|и|е)?)$/i; function ingredientUnitWeight(row){if(!Array.isArray(row))return 0;const direct=Math.max(0,Number(row[3]||0));if(direct)return direct;const m=String(row[0]||'').match(/[—–-]\s*(\d+(?:[.,]\d+)?)\s*г(?:\s*\/\s*шт\.?)?\s*$/i);return m?Math.max(0,Number(String(m[1]).replace(',','.'))):0} function cleanIngredientName(name){return String(name||'').replace(/\s*[—–-]\s*\d+(?:[.,]\d+)?\s*г(?:\s*\/\s*шт\.?)?\s*$/i,'').trim()} function inferBoxPieces(item){const explicit=Math.max(0,Number(item?.pieces||0));if(explicit)return Math.round(explicit);let sum=0;for(const row of item?.ingredients||[]){if(!Array.isArray(row))continue;const unit=String(row[2]||'').trim().toLowerCase();if(pieceUnitRe.test(unit))sum+=Math.max(0,Number(row[1]||0));}return Math.round(sum)} function ingredientDisplayLine(row){if(!Array.isArray(row)||!String(row[0]||'').trim())return'';const name=cleanIngredientName(row[0]),qty=Math.max(0,Number(row[1]||0)),unit=String(row[2]||'').trim(),w=ingredientUnitWeight(row);if(/^поз\.?$/i.test(unit)&&qty<=1)return `${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`;const q=Number.isInteger(qty)?String(qty):qty.toLocaleString('ru-RU',{maximumFractionDigits:2});return `${q} ${unit} ${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`.replace(/\s+/g,' ').trim()} function normalizeBoxItem(item,{cleanup=false}={}){if(!item||![0,5].includes(Number(item.category||0)))return item;const legacyComposition=Array.isArray(item.composition)?item.composition.slice():[];item.ingredients=Array.isArray(item.ingredients)?item.ingredients.filter(r=>Array.isArray(r)&&String(r[0]||'').trim()).map((r,index)=>{const row=[String(r[0]||'').trim(),Math.max(0,Number(r[1]||0)),String(r[2]||'').trim()||'шт.',Math.max(0,Number(r[3]||0))];if(!row[3])row[3]=ingredientUnitWeight(r)||ingredientUnitWeight([legacyComposition[index]||'',0,'',0]);return row;}):[]; // Box №18 had a total row "25 шт. тостов ассорти" mixed into two real varieties. The total belongs in pieces, not in composition. if(String(item.id)==='catalog-013'||/№\s*18\b.*тосты\s+ассорти/i.test(String(item.name||''))){const idx=item.ingredients.findIndex(r=>/тостов?\s+ассорти/i.test(String(r[0]||''))&&pieceUnitRe.test(String(r[2]||''))&&Number(r[1]||0)>1);if(idx>=0){item.pieces=Math.max(Number(item.pieces||0),Number(item.ingredients[idx][1]||0));item.ingredients.splice(idx,1);}} if(!Number(item.pieces||0))item.pieces=inferBoxPieces(item); if((!Array.isArray(item.composition)||!item.composition.filter(Boolean).length)&&item.ingredients.length)item.composition=item.ingredients.map(ingredientDisplayLine).filter(Boolean); return item;} function weightText(item,prefix=true){const raw=String(item?.weight||'').trim();if(!raw)return'';return prefix?`Вес бокса: ${raw}`:raw} function piecesText(item,prefix=true){const n=inferBoxPieces(item);if(!n)return'';return prefix?`Количество: ${n.toLocaleString('ru-RU')} шт.`:`${n.toLocaleString('ru-RU')} шт.`} function ensureBoxWeightEditor(){ const price=$('boxPrice'),dialog=document.querySelector('#editor .dialog');if(!price||!dialog)return null; let label=$('sunBoxWeightLabel'); if(!label){label=document.createElement('label');label.id='sunBoxWeightLabel';label.className='sun-box-weight-field';label.innerHTML='Вес бокса, г';price.closest('label')?.insertAdjacentElement('afterend',label)} return label; } function ensureBoxPiecesEditor(){const weight=ensureBoxWeightEditor(),dialog=document.querySelector('#editor .dialog');if(!dialog)return null;let label=$('sunBoxPiecesLabel');if(!label){label=document.createElement('label');label.id='sunBoxPiecesLabel';label.className='sun-box-pieces-field';label.innerHTML='Количество канапе / шт. в боксеЭто общее количество готовых единиц в одном боксе. Не добавляйте его отдельной строкой в «Состав / ТТК».';weight?.insertAdjacentElement('afterend',label)}return label} function syncBoxWeightEditor(category,item){const label=ensureBoxWeightEditor(),input=$('boxWeightGrams'),piecesLabel=ensureBoxPiecesEditor(),piecesInput=$('boxPiecesCount');if(!label||!input)return;const isBox=[0,5].includes(Number(category));label.style.display=isBox?'flex':'none';if(piecesLabel)piecesLabel.style.display=isBox?'flex':'none';if(isBox){input.value=parseWeightGrams(item?.weight)||'';if(piecesInput)piecesInput.value=inferBoxPieces(item)||''}} function installIngredientEditorV175(){window.renderIngredients=()=>{if(!edited)return;normalizeBoxItem(edited);const root=$('ingredients');if(!root)return;const head='
Вид / названиеКол-воЕд.Вес 1 шт., г
';root.innerHTML=head+edited.ingredients.map((row,i)=>{const w=ingredientUnitWeight(row);return `
`}).join('')};window.addIngredient=()=>{if(!edited)return;if(!Array.isArray(edited.ingredients))edited.ingredients=[];edited.ingredients.push(['Новая позиция',1,'шт.',0]);window.renderIngredients();};} installIngredientEditorV175(); function renderOrderLines(){ if(!$('lines'))return; if(!(draft.lines||[]).length){$('lines').innerHTML='

Выберите позиции из каталога слева.

';return} const rows=draft.lines.map((line,index)=>{const item=boxes.find(x=>String(x.id)===String(line.id));if(!item)return'';const qty=Math.max(1,Number(line.qty||1)),price=lineUnitPrice(line),isBox=[0,5].includes(Number(item.category||0));return `
${esc(String(item.name||'').replace(/^(?:Фуршетный\s+)?бокс\s*№\s*(\d+)\s*(?:[—–-]\s*)?/i,'№ $1 '))}${isBox&&(item.weight||inferBoxPieces(item))?`${item.weight?`Вес: ${esc(item.weight)}`:''}${item.weight&&inferBoxPieces(item)?' · ':''}${inferBoxPieces(item)?`Количество: ${inferBoxPieces(item)} шт.`:''}`:''}
${money(price*qty)}
`}).join(''); $('lines').innerHTML=`
НаименованиеКол.ЦенаСтоимость
${rows}
Стоимость позиций${money(baseTotal(draft))}
`; } window.sunOrderLinePriceChanged=(index,input)=>{const line=draft.lines?.[index];if(!line)return;line.price=Math.max(0,Math.round(Number(input.value||0)));const row=input.closest('.sun-order-line-row'),sum=row?.querySelector('.sun-order-line-sum b');if(sum)sum.textContent=money(line.price*Math.max(0,Number(line.qty||0)));const total=$('lines')?.querySelector('.sun-order-line-total b');if(total)total.textContent=money(baseTotal(draft));updateOrderSummary();}; function boxNumber(item){const explicit=Number(item?.boxNumber);if(Number.isInteger(explicit)&&explicit>=0)return explicit;const name=String(item?.name||'');const match=name.match(/(?:бокс\s*)?№\s*0*(\d+)/i)||name.match(/^\s*№\s*0*(\d+)/i);return match?Number(match[1]):null} function wantedBoxNumber(query){const raw=String(query||'').trim();if(!raw)return null;const match=raw.match(/^(?:бокс\s*)?(?:№\s*)?0*(\d+)\s*$/i);return match?Number(match[1]):null} function itemMatches(item,query){if(!query)return true;if(Number(activeCat)===0){const wanted=wantedBoxNumber(query);return wanted!==null&&boxNumber(item)===wanted}const q=query.trim().toLowerCase();const parts=[item.name,item.catalogSection,item.weight,...(Array.isArray(item.composition)?item.composition:[]),...(Array.isArray(item.ingredients)?item.ingredients.map(x=>x?.[0]):[])];return parts.join(' ').toLowerCase().includes(q)} function renderCatalogV5(){ renderCategoryTabs();ensureCatalogTools();const catalogSearch=$('sunCatalogSearch');if(catalogSearch){const boxMode=[0,5].includes(Number(activeCat));catalogSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';catalogSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#new .catalog h1');if(title)title.textContent=catName(activeCat); const all=boxes.filter(item=>Number(item.category||0)===Number(activeCat)),items=all.filter(item=>itemMatches(item,catalogQuery));const cat=catById(activeCat)||{name:'Каталог',prep:true}; const cards=items.map(item=>``).join(''); const addText=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию'); const empty=items.length?'':`
${catalogQuery?'По вашему запросу ничего не найдено.':`В разделе «${esc(cat.name)}» пока нет позиций.`}
`; $('tiles').innerHTML=`${cards}${empty}`; renderOrderLines();updateOrderSummary(); } window.render=renderCatalogV5; window.add=id=>{const item=boxes.find(x=>String(x.id)===String(id));if(!item)return;let line=(draft.lines||[]).find(x=>String(x.id)===String(id));if(line)line.qty=Math.max(0,Number(line.qty||0))+1;else{if(!Array.isArray(draft.lines))draft.lines=[];draft.lines.push({id:item.id,qty:1,price:Math.max(0,Number(item.price||0))})}renderCatalogV5();}; window.qty=(id,n)=>{if(!Array.isArray(draft.lines))draft.lines=[];const next=Math.max(0,Number(n||0));if(next<1)draft.lines=draft.lines.filter(x=>String(x.id)!==String(id));else{const line=draft.lines.find(x=>String(x.id)===String(id));if(line)line.qty=next}renderCatalogV5();}; function ensureManagerToolbar(){ const dialog=document.querySelector('#manager .dialog');if(!dialog)return;let bar=dialog.querySelector('.sun-manager-toolbar');const add=qa(':scope > .primary',dialog)[0]||qa('.primary',dialog).find(b=>(b.textContent||'').includes('Добавить')); if(!bar&&add){bar=document.createElement('div');bar.className='sun-manager-toolbar';add.parentNode.insertBefore(bar,add);bar.appendChild(add);const input=document.createElement('input');input.id='sunManagerSearch';input.className='sun-manager-search';input.type='search';input.placeholder=Number(activeCat)===0?'Поиск по № бокса':'Поиск по позиции';input.inputMode=Number(activeCat)===0?'numeric':'search';input.oninput=()=>{managerQuery=input.value;renderManagerV5();};bar.appendChild(input);} } function renderManagerV5(){ ensureManagerToolbar();const managerSearch=$('sunManagerSearch');if(managerSearch){const boxMode=[0,5].includes(Number(activeCat));managerSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';managerSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#manager .dialog-head h2'),add=document.querySelector('#manager .sun-manager-toolbar .primary')||document.querySelector('#manager .primary');if(title)title.textContent=catName(activeCat);if(add){add.textContent=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию');add.onclick=()=>window.editBox(null)} const items=boxes.filter(i=>Number(i.category||0)===Number(activeCat)&&itemMatches(i,managerQuery)),cat=catById(activeCat)||{prep:true}; $('managerList').innerHTML=items.length?items.map(item=>``).join(''):'

Ничего не найдено.

'; } window.openManager=()=>{managerQuery='';ensureManagerToolbar();if($('sunManagerSearch'))$('sunManagerSearch').value='';renderManagerV5();window.modal?.('manager');}; window.editBox=id=>{ edited=id?structuredClone(boxes.find(x=>String(x.id)===String(id))):{id:'',name:Number(activeCat)===0?'Новый бокс':(Number(activeCat)===5?'Новая премиум позиция':'Новая позиция'),category:Number(activeCat),price:0,oldPrice:0,ingredients:[]};if(!edited)return; if(!Array.isArray(edited.ingredients))edited.ingredients=[];normalizeBoxItem(edited);syncEditorCategoryOptions();$('itemCategory').value=String(edited.category??activeCat);$('boxName').value=edited.name||'';$('boxPrice').value=Number(edited.price||0);if($('boxOldPrice'))$('boxOldPrice').value=Number(edited.oldPrice||0);if($('boxCompositionText'))$('boxCompositionText').value=(Array.isArray(edited.composition)?edited.composition:[]).join('\n');syncBoxWeightEditor(edited.category??activeCat,edited);$('editPhoto').style.display=edited.photo?'block':'none';$('editPhoto').src=edited.photo||'';$('deleteBox').style.display=edited.id?'block':'none'; const cat=catById(edited.category)||{name:'Каталог',prep:true};$('editTitle').textContent=edited.id?`Изменить: ${cat.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=cat.prep?'block':'none';window.renderIngredients?.();window.modal?.('editor'); }; if($('itemCategory'))$('itemCategory').onchange=function(){if(!edited)return;edited.category=Number(this.value);const c=catById(edited.category)||{name:'Каталог',prep:true};const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=c.prep?'block':'none';syncBoxWeightEditor(edited.category,edited);$('editTitle').textContent=edited.id?`Изменить: ${c.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));}; window.saveBox=()=>{if(!edited)return;edited.name=$('boxName').value.trim();edited.price=Math.max(0,Number($('boxPrice').value||0));edited.oldPrice=Math.max(0,Number($('boxOldPrice')?.value||0));if(!(edited.oldPrice>edited.price))delete edited.oldPrice;edited.sale=Boolean(edited.oldPrice&&edited.oldPrice>edited.price);edited.category=Number($('itemCategory').value);if([0,5].includes(edited.category)){const grams=Math.max(0,Math.round(Number($('boxWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';edited.pieces=Math.max(0,Math.round(Number($('boxPiecesCount')?.value||0)));}edited.ingredients=Array.isArray(edited.ingredients)?edited.ingredients:[];if([0,5].includes(edited.category)&&$('boxCompositionText')){const next=$('boxCompositionText').value.split(/\r?\n/).map(x=>x.trim()).filter(Boolean);const before=JSON.stringify(Array.isArray(edited.composition)?edited.composition:[]);edited.composition=next;if(JSON.stringify(next)!==before)edited.compositionSource='manual';}normalizeBoxItem(edited,{cleanup:true});if(!edited.name)return alert('Введите название.');if(!edited.id){edited.id=(typeof sunUUID==='function'?sunUUID():`item-${Date.now()}`);boxes.push(edited)}else{const i=boxes.findIndex(x=>String(x.id)===String(edited.id));if(i>=0)boxes[i]=edited}if(!catById(edited.category)?.hidden)activeCat=edited.category;persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();window.sunClientOfferCatalogChanged?.(edited.id);}; window.removeBox=()=>{if(!edited?.id||!confirm(`Удалить «${edited.name}» из каталога?`))return;boxes=boxes.filter(x=>String(x.id)!==String(edited.id));draft.lines=(draft.lines||[]).filter(x=>String(x.id)!==String(edited.id));persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();}; function fileAsDataUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onerror=()=>reject(reader.error||new Error('FileReader error'));reader.onload=()=>resolve(String(reader.result||''));reader.readAsDataURL(file)})} function compactCatalogPhotoData(dataUrl,{maxSide=900,maxChars=130000,quality=.78,force=false}={}){return new Promise(resolve=>{if(!/^data:image\//i.test(String(dataUrl||'')))return resolve(dataUrl);const image=new Image();image.onerror=()=>resolve(dataUrl);image.onload=()=>{const iw=Math.max(1,image.naturalWidth||image.width||1),ih=Math.max(1,image.naturalHeight||image.height||1);if(!force&&String(dataUrl).length<=maxChars&&Math.max(iw,ih)<=maxSide)return resolve(dataUrl);let scale=Math.min(1,maxSide/Math.max(iw,ih)),q=quality,best=dataUrl;for(let attempt=0;attempt<5;attempt++){const canvas=document.createElement('canvas');canvas.width=Math.max(1,Math.round(iw*scale));canvas.height=Math.max(1,Math.round(ih*scale));const ctx=canvas.getContext('2d');if(!ctx)break;ctx.fillStyle='#fff';ctx.fillRect(0,0,canvas.width,canvas.height);ctx.drawImage(image,0,0,canvas.width,canvas.height);try{best=canvas.toDataURL('image/jpeg',q)||best}catch(_){break}if(best.length<=maxChars)break;scale*=.78;q=Math.max(.52,q-.07)}resolve(best)};image.src=dataUrl})} window.sunCompactCatalogPhotoData=compactCatalogPhotoData; window.readPhoto=async input=>{const file=input?.files?.[0];if(!file||!edited)return;try{const original=await fileAsDataUrl(file);const optimized=await compactCatalogPhotoData(original);edited.photo=optimized;$('editPhoto').src=optimized;$('editPhoto').style.display='block';if(optimized.length+5000({name:'',inn:'',kpp:'',ogrn:'',legalAddress:'',phone:'',email:'',bank:'',bik:'',account:'',corrAccount:'',contact:''}); function legacyBuyer(){try{const s=JSON.parse(localStorage.getItem('sunReceiptSettingsV2')||'{}');return {name:s.buyerName||'',inn:s.buyerInn||'',kpp:s.buyerKpp||'',ogrn:s.buyerOgrn||'',legalAddress:s.buyerLegalAddress||'',phone:s.buyerPhone||'',email:s.buyerEmail||'',bank:s.buyerBank||'',bik:s.buyerBik||'',account:s.buyerAccount||'',corrAccount:s.buyerCorrAccount||'',contact:s.buyerContact||''}}catch(_){return buyerDefaults()}} function ensureRequisitesTab(){ const sub=document.querySelector('#new .subnav');if(!sub)return; let btn=$('requisitesTab');if(!btn){btn=document.createElement('button');btn.id='requisitesTab';btn.type='button';btn.textContent='Реквизиты';sub.appendChild(btn)} let panel=$('orderRequisites');if(!panel){panel=document.createElement('div');panel.id='orderRequisites';panel.className='sun-order-requisites';panel.innerHTML=`

Реквизиты покупателя

`;$('details').insertAdjacentElement('afterend',panel)} $('orderTab').onclick=()=>setOrderPane('order');$('detailTab').onclick=()=>setOrderPane('details');btn.onclick=()=>setOrderPane('requisites'); qa('#orderRequisites input:not([type=file])').forEach(input=>input.addEventListener('input',captureBuyerFromFields)); } function setOrderPane(tab){ensureRequisitesTab();$('orderForm').style.display=tab==='order'?'block':'none';$('details').style.display=tab==='details'?'block':'none';$('orderRequisites').style.display=tab==='requisites'?'block':'none';$('orderTab').classList.toggle('on',tab==='order');$('detailTab').classList.toggle('on',tab==='details');$('requisitesTab').classList.toggle('on',tab==='requisites');if(tab==='requisites')syncBuyerFields();} window.details=on=>setOrderPane(on?'details':'order'); function buyerObject(){return {name:$('orderBuyerName')?.value.trim()||'',contact:$('orderBuyerContact')?.value.trim()||'',inn:$('orderBuyerInn')?.value.trim()||'',kpp:$('orderBuyerKpp')?.value.trim()||'',ogrn:$('orderBuyerOgrn')?.value.trim()||'',phone:$('orderBuyerPhone')?.value.trim()||'',legalAddress:$('orderBuyerLegalAddress')?.value.trim()||'',email:$('orderBuyerEmail')?.value.trim()||'',bank:$('orderBuyerBank')?.value.trim()||'',bik:$('orderBuyerBik')?.value.trim()||'',account:$('orderBuyerAccount')?.value.trim()||'',corrAccount:$('orderBuyerCorrAccount')?.value.trim()||''}} function captureBuyerFromFields(){if(typeof draft==='undefined'||!draft)return;draft.buyerRequisites=buyerObject();} function syncBuyerFields(){ensureRequisitesTab();let b=draft?.buyerRequisites;if(!b){const legacy=legacyBuyer(),hasLegacy=Object.values(legacy).some(Boolean);b=hasLegacy?legacy:buyerDefaults();draft.buyerRequisites={...b}};const map={orderBuyerName:'name',orderBuyerContact:'contact',orderBuyerInn:'inn',orderBuyerKpp:'kpp',orderBuyerOgrn:'ogrn',orderBuyerPhone:'phone',orderBuyerLegalAddress:'legalAddress',orderBuyerEmail:'email',orderBuyerBank:'bank',orderBuyerBik:'bik',orderBuyerAccount:'account',orderBuyerCorrAccount:'corrAccount'};Object.entries(map).forEach(([id,key])=>{if($(id))$(id).value=b?.[key]||''});} // ---------------- QR default + image handling ---------------- const QR_KEY='sunDefaultOrderQrV1'; const defaultQr=()=>{try{return localStorage.getItem(QR_KEY)||''}catch(_){return''}}; function imageData(file,max=512){return new Promise((resolve,reject)=>{const r=new FileReader();r.onerror=reject;r.onload=()=>{const img=new Image();img.onerror=reject;img.onload=()=>{const scale=Math.min(1,max/Math.max(img.width||1,img.height||1)),c=document.createElement('canvas');c.width=Math.max(1,Math.round(img.width*scale));c.height=Math.max(1,Math.round(img.height*scale));const ctx=c.getContext('2d');ctx.fillStyle='#fff';ctx.fillRect(0,0,c.width,c.height);ctx.drawImage(img,0,0,c.width,c.height);resolve(c.toDataURL('image/png'))};img.src=r.result};r.readAsDataURL(file)})} function ensureDefaultQrSetting(){ const grid=document.querySelector('#enterprise-settings .enterprise-grid');if(!grid)return;let card=$('sunDefaultQrCard');if(!card){card=document.createElement('section');card.id='sunDefaultQrCard';card.className='enterprise-card wide';card.innerHTML=`

QR-код для бланка заказа

Загрузите QR-код один раз. Он будет автоматически использоваться во всех бланках заказов, пока вы не загрузите другой.

QR не загружен
`;const audit=qa(':scope > .enterprise-card',grid).find(x=>(x.querySelector('h2')?.textContent||'').trim()==='История изменений');window.SunSafe.insertBefore(grid,card,audit||null);$('sunDefaultQrUpload').onclick=()=>$('sunDefaultQrFile').click();$('sunDefaultQrFile').onchange=async()=>{const f=$('sunDefaultQrFile').files?.[0];if(!f)return;try{localStorage.setItem(QR_KEY,await imageData(f));renderDefaultQr();toast('QR-код для бланков сохранён.')}catch(_){toast('Не удалось загрузить QR-код.','warn')}};} renderDefaultQr();const audit=qa(':scope > .enterprise-card',grid).find(x=>(x.querySelector('h2')?.textContent||'').trim()==='История изменений');if(audit&&grid.lastElementChild!==audit)grid.appendChild(audit); } function renderDefaultQr(){const root=$('sunDefaultQrPreview');if(!root)return;const src=defaultQr();root.innerHTML=src?`QR`:'QR не загружен';} // ---------------- Discounts + promo tracking ---------------- const PROMO_KEY='sunPromoCodesV1'; const localDateIso=()=>{const d=new Date(),p=n=>String(n).padStart(2,'0');return `${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`}; function promoCodes(){try{const list=JSON.parse(localStorage.getItem(PROMO_KEY)||'[]');return Array.isArray(list)?list:[]}catch(_){return[]}} function promoActive(p,date=localDateIso()){if(!p||p.enabled===false)return false;const start=String(p.startDate||''),end=String(p.endDate||'');return (!start||start<=date)&&(!end||end>=date)} function promoDiscountText(p){const value=Math.max(0,Number(p?.discountValue||0));return p?.discountType==='amount'?money(value):`${value.toLocaleString('ru-RU',{maximumFractionDigits:2})}%`} function promoById(id){return promoCodes().find(p=>String(p.id)===String(id))||null} function promoByCode(code){const key=String(code||'').trim().toLowerCase();return promoCodes().find(p=>String(p.code||'').trim().toLowerCase()===key)||null} function ensureDiscountUI(){ const form=document.querySelector('#new .money-form');if(!form)return; if(!$('deliveryCost')){ const label=document.createElement('label');label.id='deliveryCostLabel';label.innerHTML='Доставка, ₽'; const prepay=$('prepayment')?.closest('label');if(prepay)prepay.insertAdjacentElement('beforebegin',label);else form.appendChild(label); $('deliveryCost')?.addEventListener('input',()=>{captureDelivery();updateOrderSummary()}); } let panel=$('sunDiscountPanel'); const desired=``; if(!panel){panel=document.createElement('div');panel.id='sunDiscountPanel';panel.className='sun-discount-panel';panel.innerHTML=desired;form.insertAdjacentElement('afterend',panel)} else if(!$('promoCodeSelect'))panel.innerHTML=desired; if(panel.dataset.promoBound!=='1'){ panel.dataset.promoBound='1'; $('manualDiscountValue')?.addEventListener('input',()=>{captureDiscounts();updateOrderSummary()}); $('manualDiscountType')?.addEventListener('change',()=>{captureDiscounts();updateOrderSummary()}); $('promoCodeSelect')?.addEventListener('change',()=>{captureDiscounts();updateOrderSummary()}); } const summary=document.querySelector('#new .order-summary');if(summary&&!$('summaryNetTotal'))summary.innerHTML=`

Стоимость позиций0 ₽

Скидка− 0 ₽

Промокод − 0 ₽

Доставка0 ₽

Итого0 ₽

Предоплата0 ₽

К оплате0 ₽

`; } function renderPromoSelect(){ ensureDiscountUI();const select=$('promoCodeSelect');if(!select)return; const active=promoCodes().filter(p=>promoActive(p)).sort((a,b)=>String(a.code||'').localeCompare(String(b.code||''),'ru')); const currentId=String(draft?.promoId||''),currentCode=String(draft?.promoCode||'').trim(); let selected=''; const opts=['']; active.forEach(p=>{opts.push(``);if(currentId&&String(p.id)===currentId)selected=String(p.id)}); if(currentCode&&!selected){ const saved=promoById(currentId)||promoByCode(currentCode),label=saved?(promoActive(saved)?'активен':'срок истёк / отключён'):'сохранён в заказе'; opts.push(``);selected='__snapshot__'; } select.innerHTML=opts.join('');select.value=selected; updatePromoMeta(); } function updatePromoMeta(){const meta=$('promoCodeMeta'),select=$('promoCodeSelect');if(!meta||!select)return;const id=select.value;if(!id){meta.textContent='Выберите активный промокод из раздела «Рассылки».';return}if(id==='__snapshot__'){meta.textContent=`Условия сохранены в заказе: ${draft?.promoCode||''} · ${draft?.promoDiscountType==='amount'?money(draft?.promoDiscountValue||0):`${Number(draft?.promoDiscountValue||0).toLocaleString('ru-RU',{maximumFractionDigits:2})}%`}.`;return}const p=promoById(id);meta.textContent=p?`${p.code} · скидка ${promoDiscountText(p)} · действует ${p.startDate||'без даты'} — ${p.endDate||'без даты'}`:'Промокод недоступен.';} function captureDiscounts(){ if(!draft)return;draft.manualDiscountValue=Math.max(0,Number($('manualDiscountValue')?.value||0));draft.manualDiscountType=$('manualDiscountType')?.value==='amount'?'amount':'percent'; const select=$('promoCodeSelect');if(!select)return;const id=String(select.value||''); if(!id){draft.promoId='';draft.promoCode='';draft.promoDiscountValue=0;draft.promoDiscountType='percent';draft.promoStartDate='';draft.promoEndDate='';return} if(id==='__snapshot__'){updatePromoMeta();return} const p=promoById(id);if(!p||!promoActive(p)){renderPromoSelect();return} draft.promoId=String(p.id||'');draft.promoCode=String(p.code||'').trim();draft.promoDiscountValue=Math.max(0,Number(p.discountValue||0));draft.promoDiscountType=p.discountType==='amount'?'amount':'percent';draft.promoStartDate=String(p.startDate||'');draft.promoEndDate=String(p.endDate||'');updatePromoMeta(); } function captureDelivery(){if(!draft)return;draft.deliveryCost=Math.max(0,Number($('deliveryCost')?.value||0));} function syncDeliveryField(){ensureDiscountUI();if($('deliveryCost'))$('deliveryCost').value=Math.max(0,Number(draft?.deliveryCost||0));} function discountAmount(value,type,base){const n=Math.max(0,Number(value||0));return Math.min(base,type==='amount'?n:base*Math.min(100,n)/100)} function pricing(order=draft){const base=baseTotal(order),manual=discountAmount(order?.manualDiscountValue,order?.manualDiscountType,base),afterManual=Math.max(0,base-manual),promo=discountAmount(order?.promoDiscountValue,order?.promoDiscountType,afterManual),itemsTotal=Math.max(0,afterManual-promo),delivery=Math.max(0,Number(order?.deliveryCost||0)),total=itemsTotal+delivery,paid=Math.max(0,Number(order===draft?($('prepayment')?.value||order?.prepayment||0):(order?.prepayment||0))),balance=Math.max(0,total-paid);return {base,manual,promo,itemsTotal,delivery,total,paid,balance,discount:manual+promo}} window.sunOrderPricing=pricing; window.calcOrderTotal=()=>pricing(draft).total; window.orderTotalValue=order=>pricing(order).total; window.updateOrderSummary=()=>{ensureDiscountUI();captureDiscounts();const p=pricing(draft);if($('orderTotal'))$('orderTotal').value=Math.round(p.total);if($('balance'))$('balance').value=Math.round(p.balance);if($('summaryTotal'))$('summaryTotal').textContent=money(p.base);if($('summaryManualDiscount'))$('summaryManualDiscount').textContent=`− ${money(p.manual)}`;if($('summaryPromoDiscount'))$('summaryPromoDiscount').textContent=`− ${money(p.promo)}`;if($('summaryPromoCode'))$('summaryPromoCode').textContent=draft.promoCode?`(${draft.promoCode})`:'';if($('summaryDelivery'))$('summaryDelivery').textContent=money(p.delivery);if($('summaryNetTotal'))$('summaryNetTotal').textContent=money(p.total);if($('summaryPrepayment'))$('summaryPrepayment').textContent=money(p.paid);if($('summaryBalance'))$('summaryBalance').textContent=money(p.balance);updatePromoMeta();}; function syncDiscountFields(){ensureDiscountUI();$('manualDiscountValue').value=Number(draft?.manualDiscountValue||0);$('manualDiscountType').value=draft?.manualDiscountType==='amount'?'amount':'percent';syncDeliveryField();renderPromoSelect();updateOrderSummary();} window.sunRefreshOrderPromos=()=>{renderPromoSelect();updateOrderSummary();}; // ---------------- Seller settings only ---------------- function simplifySellerSettings(){ const card=$('sunReceiptSettingsCard');if(!card||card.dataset.sunSellerOnly==='1')return; const sections=qa('.sun-receipt-settings-section',card);sections.forEach(s=>{if((s.querySelector('h3')?.textContent||'').includes('Покупатель'))s.classList.add('sun-buyer-settings-hidden')}); const buyerCheck=$('receiptIncludeBuyer');buyerCheck?.closest('label')?.classList.add('sun-buyer-settings-hidden'); const h=card.querySelector('h2');if(h&&(h.textContent||'').trim()!=='Реквизиты компании')h.textContent='Реквизиты компании'; const hint=card.querySelector(':scope > .hint'),hintText='Реквизиты продавца для товарного чека. Реквизиты покупателя вводятся отдельно в каждом заказе во вкладке «Реквизиты».';if(hint&&hint.textContent!==hintText)hint.textContent=hintText; card.dataset.sunSellerOnly='1'; } function readSeller(){const d={includeSeller:true,sellerName:'Солнце Кейтеринг',sellerLegalName:'',sellerInn:'',sellerKpp:'',sellerOgrn:'',sellerLegalAddress:'',sellerPhone:'',sellerEmail:'',sellerBank:'',sellerBik:'',sellerAccount:'',sellerCorrAccount:''};try{return {...d,...JSON.parse(localStorage.getItem('sunReceiptSettingsV2')||'{}')}}catch(_){return d}} function party(title,rows){const list=rows.filter(([,v])=>String(v||'').trim());if(!list.length)return'';return `

${esc(title)}

${list.map(([k,v])=>`
${esc(k)}${esc(v)}
`).join('')}
`} // ---------------- Order blank + compact receipt ---------------- function currentRows(){return (draft.lines||[]).map((line,index)=>{const item=boxes.find(x=>String(x.id)===String(line.id)),price=lineUnitPrice(line),qty=Math.max(0,Number(line.qty||0)),categoryId=Number(item?.category??line.category??0);return{index:index+1,name:item?.name||line.name||`Позиция ${line.id||''}`,category:catName(categoryId),categoryId,weight:[0,5].includes(categoryId)?String(item?.weight||''):'',pieces:[0,5].includes(categoryId)?inferBoxPieces(item):0,price,qty,sum:price*qty}}).filter(r=>r.qty>0)} const docDate=raw=>{if(!raw)return'—';const d=new Date(`${raw}T00:00:00`);return Number.isNaN(d.getTime())?raw:d.toLocaleDateString('ru-RU')}; const docActions=()=>`
`; function showOrderBlank(){ captureBuyerFromFields();captureDiscounts();const rows=currentRows(),p=pricing(draft),qr=defaultQr(),b=draft.buyerRequisites||buyerDefaults(),dialog=document.querySelector('#preview .dialog');if(!dialog)return;const number=draft.id||'черновик',qrNote=String(draft.blankQrText||'').trim(); dialog.innerHTML=`
Солнце Кейтеринг
Солнце КейтерингСанкт-Петербург · кейтеринг и выездные мероприятия

Заказ № ${esc(number)}

${esc($('event')?.value||'Новое мероприятие')}

${draft.status?`${esc(draft.status)}`:''}
${qr?`
QR-код
${esc(qrNote)}
`:''}
Клиент${esc($('contact')?.value||'—')}
Телефон${esc($('phone')?.value||'—')}
Дата и время выдачи${esc(docDate($('date')?.value))} · ${esc($('time')?.value||'—')}
Адрес доставки${esc($('address')?.value||'—')}
${b.name?`
Компания покупателя${esc(b.name)}
`:''}
${rows.length?rows.map(r=>``).join(''):''}
ПозицияЦенаКол.Сумма
${r.index}${esc(r.name)}${esc(r.category)}${(r.weight||r.pieces)?`${r.weight?`Вес бокса: ${esc(r.weight)}`:''}${r.weight&&r.pieces?' · ':''}${r.pieces?`Количество: ${esc(r.pieces)} шт.`:''}`:''}${money(r.price)}${r.qty}${money(r.sum)}
В заказе пока нет позиций.

Стоимость позиций${money(p.base)}

${p.manual?`

Скидка− ${money(p.manual)}

`:''}${p.promo?`

Промокод ${esc(draft.promoCode||'')}− ${money(p.promo)}

`:''}

Доставка${money(p.delivery)}

Итого${money(p.total)}

Предоплата${money(p.paid)}

Остаток к оплате${money(p.balance)}

${$('note')?.value?`
Комментарий к заказу${esc($('note').value)}
`:''}${docActions()}
`;window.modal?.('preview');const noteEl=$('sunBlankQrText');if(noteEl){const save=()=>{const text=String(noteEl.innerText||noteEl.textContent||'').replace(/\u00a0/g,' ').trim();draft.blankQrText=text;if(draft.id){const saved=(orders||[]).find(o=>String(o.id)===String(draft.id));if(saved){saved.blankQrText=text;try{persist()}catch(_){}}}};noteEl.addEventListener('input',save);noteEl.addEventListener('blur',save);} } function showReceipt(){ captureBuyerFromFields();captureDiscounts();const rows=currentRows(),p=pricing(draft),s=readSeller(),b=draft.buyerRequisites||buyerDefaults(),dialog=document.querySelector('#preview .dialog');if(!dialog)return;const seller=s.includeSeller!==false?party('Продавец',[['Наименование',s.sellerLegalName||s.sellerName],['ИНН',s.sellerInn],['КПП',s.sellerKpp],['ОГРН / ОГРНИП',s.sellerOgrn],['Адрес',s.sellerLegalAddress],['Телефон',s.sellerPhone],['E-mail',s.sellerEmail],['Банк',s.sellerBank],['БИК',s.sellerBik],['Расч. счёт',s.sellerAccount],['Корр. счёт',s.sellerCorrAccount]]):'';const buyer=party('Покупатель',[['Компания / ИП',b.name],['ИНН',b.inn],['КПП',b.kpp],['ОГРН / ОГРНИП',b.ogrn],['Адрес',b.legalAddress],['Контакт',b.contact],['Телефон',b.phone],['E-mail',b.email],['Банк',b.bank],['БИК',b.bik],['Расч. счёт',b.account],['Корр. счёт',b.corrAccount]]); dialog.innerHTML=`
Солнце Кейтеринг
${esc(s.sellerName||'Солнце Кейтеринг')}${esc(s.sellerLegalName||'')}

Товарный чек № ${esc(draft.id||'—')}

${esc(docDate($('date')?.value||draft.date))} · ${esc($('time')?.value||draft.time||'')}

${seller}${buyer}${rows.length?rows.map(r=>``).join(''):''}
НаименованиеЦенаКол.Сумма
${r.index}${esc(r.name)}${(r.weight||r.pieces)?`${r.weight?`Вес бокса: ${esc(r.weight)}`:''}${r.weight&&r.pieces?' · ':''}${r.pieces?`Количество: ${esc(r.pieces)} шт.`:''}`:''}${money(r.price)}${r.qty}${money(r.sum)}
В заказе нет позиций.

Стоимость позиций${money(p.base)}

${p.manual?`

Скидка− ${money(p.manual)}

`:''}${p.promo?`

Промокод ${esc(draft.promoCode||'')}− ${money(p.promo)}

`:''}

Доставка${money(p.delivery)}

Итого${money(p.total)}

Оплачено${money(p.paid)}

К оплате${money(p.balance)}

${$('note')?.value?`
Примечание${esc($('note').value)}
`:''}${docActions()}
`;window.modal?.('preview'); } window.sunShowConfiguredReceipt=showReceipt;window.sunShowOrderBlankV5=showOrderBlank; function patchDocButtons(){qa('#new .actions button').forEach(b=>{const text=(b.textContent||'').trim();if(text==='Товарный чек')b.onclick=showReceipt;if(text==='Бланк заказа')b.onclick=showOrderBlank;});} // ---------------- Promo statistics ---------------- function renderPromoStats(){ const view=$('stats');if(!view)return;let root=$('sunPromoStats');if(!root){root=document.createElement('section');root.id='sunPromoStats';root.className='sun-promo-stats';view.appendChild(root)} const groups=new Map();(orders||[]).filter(o=>o.status!=='Отменён'&&String(o.promoCode||'').trim()).forEach(o=>{const code=String(o.promoCode).trim(),p=pricing(o),key=code.toLowerCase(),client=(String(o.phone||'').replace(/\D/g,'')||String(o.contact||'').trim().toLowerCase()||`order:${o.id}`);if(!groups.has(key))groups.set(key,{code,orders:0,clients:new Set(),sales:0,discount:0});const g=groups.get(key);g.orders++;g.clients.add(client);g.sales+=p.total;g.discount+=p.promo;});const list=[...groups.values()].sort((a,b)=>b.sales-a.sales); root.innerHTML=`

Промокоды

Отслеживание заказов, клиентов, продаж и предоставленной скидки по промокодам.

${list.length?`
${list.map(g=>``).join('')}
ПромокодЗаказовКлиентовПродажиСкидка
${esc(g.code)}${g.orders}${g.clients.size}${money(g.sales)}${money(g.discount)}
`:'

Заказов с промокодами пока нет.

'}`; } // ---------------- Lifecycle wrappers ---------------- const previousSave=window.saveOrder; if(typeof previousSave==='function')window.saveOrder=function(...args){captureBuyerFromFields();captureDiscounts();captureDelivery();const result=previousSave.apply(this,args);renderPromoStats();return result}; const previousOpen=window.openOrder; if(typeof previousOpen==='function')window.openOrder=function(...args){const r=previousOpen.apply(this,args);setTimeout(()=>{syncBuyerFields();syncDiscountFields();syncDeliveryField();setOrderPane('order');patchDocButtons();renderCatalogV5();},0);return r}; const previousReset=window.resetDraft; if(typeof previousReset==='function')window.resetDraft=function(...args){const r=previousReset.apply(this,args);draft.buyerRequisites=buyerDefaults();draft.manualDiscountValue=0;draft.manualDiscountType='percent';draft.promoId='';draft.promoCode='';draft.promoDiscountValue=0;draft.promoDiscountType='percent';draft.promoStartDate='';draft.promoEndDate='';draft.deliveryCost=0;delete draft.qrImage;setTimeout(()=>{syncBuyerFields();syncDiscountFields();syncDeliveryField();setOrderPane('order');renderCatalogV5();},0);return r}; const previousStats=window.renderStats; window.renderStats=function(...args){const r=typeof previousStats==='function'?previousStats.apply(this,args):undefined;setTimeout(renderPromoStats,0);return r}; function onSettings(){setTimeout(()=>{simplifySellerSettings();ensureDefaultQrSetting();},80);setTimeout(()=>{simplifySellerSettings();ensureDefaultQrSetting();},250)} document.addEventListener('click',e=>{const nav=e.target.closest('header nav button');if(nav&&String(nav.dataset.navLabel||nav.textContent||'').trim()==='Настройки')onSettings();},true); (()=>{let queued=false;const run=()=>{if(queued)return;queued=true;setTimeout(()=>{queued=false;if($('sunReceiptSettingsCard'))simplifySellerSettings();patchDocButtons();},50);};[$('new'),$('enterprise-settings')].filter(Boolean).forEach(root=>new MutationObserver(run).observe(root,{childList:true,subtree:true}));})(); // Initial install. Populate the new piece-count field without overwriting manually edited prices/weights. try{let changed=false;(Array.isArray(boxes)?boxes:[]).forEach(item=>{if(![0,5].includes(Number(item?.category||0)))return;const before=JSON.stringify([item.pieces,item.ingredients,item.composition]);normalizeBoxItem(item,{cleanup:true});if(before!==JSON.stringify([item.pieces,item.ingredients,item.composition]))changed=true;});if(changed)persist();}catch(err){console.warn('v17.5 catalog normalization skipped',err)} ensureCategoryModal();renderCategoryTabs();syncEditorCategoryOptions();ensureCatalogTools();ensureBoxWeightEditor();ensureBoxPiecesEditor();ensureRequisitesTab();ensureDiscountUI();syncBuyerFields();syncDiscountFields();syncDeliveryField();patchDocButtons();renderCatalogV5();renderPromoStats();if($('enterprise-settings')?.classList.contains('on'))onSettings(); })(); ; /* ===== MODULE: client-offer-settings.js ===== */ /* Sun Catering: editable client-offer content and metric settings */ (()=>{ 'use strict'; if(window.__sunClientOfferSettingsV1)return; window.__sunClientOfferSettingsV1=true; const KEY='sunClientOfferSettingsV1'; const DEFAULTS={ version:3, metricMode:'weight', showAmountPerGuest:true, showBoxCount:true, showPriceBreakdown:true, showDiscountBadge:true, showGallery:true, showControl:true, showExtras:true, showFinalPhoto:true, showClientName:true, showDate:true, showGuests:true, showFooterNote:true, texts:{ proposalLabel:'Индивидуальное предложение', menuTitle:'Меню', summaryTitle:'Итого', totalPriceTitle:'Итоговая стоимость', heroNote:'Фирменные боксы с закусками — готово к подаче на стол.', salesTitle:'Почему с нами удобно', salesNote:'Меню составлено специально под ваше событие. Закуски приезжают в фирменных боксах, их удобно поставить на стол и подать без сложной сервировки. Мы готовим заказ в день доставки, используем свежие ингредиенты и контролируем детали до передачи заказа.', finalGalleryTitle:'Как это выглядит на вашем столе', weightMetricLabel:'Вес еды на гостя', piecesMetricLabel:'Канапе на гостя', amountPerGuestLabel:'Сумма на гостя', boxCountLabel:'Количество боксов', pricingTitle:'Расчёт стоимости', priceItemsLabel:'Стоимость позиций', discountLabel:'Скидка', promoLabel:'Промокод', menuAfterDiscountLabel:'Меню после скидок', deliveryLabel:'Доставка', totalLabel:'Итого', controlTitle:'Всё под контролем команды Солнца', extrasTitle:'Дополнительно к заказу рекомендуем', footerNote:'Доставка считается отдельно от меню и не участвует в скидках.' }, controlLines:[ 'Фирменная упаковка', 'Уточняем детали доставки', 'Стоимость заказа не изменится', 'Готовим закуски в день мероприятия', 'Контролируем заказ до момента передачи', 'Привозим заказ вовремя и передаём вам лично', 'Всё организованно! Вы просто встречаете гостей!' ], extraServices:['Напитки','Десерты','Фрукты','Одноразовая посуда'] }; const clone=v=>JSON.parse(JSON.stringify(v)); const esc=window.SunSafe.escapeHTML; const bool=(v,d)=>typeof v==='boolean'?v:d; const lines=(value,fallback)=>{ const arr=Array.isArray(value)?value:String(value??'').split(/\r?\n/); const clean=arr.map(x=>String(x||'').trim()).filter(Boolean).slice(0,20); return clean.length?clean:[...fallback]; }; function normalize(raw={}){ const d=clone(DEFAULTS),t=raw&&typeof raw==='object'?raw:{}; d.metricMode=t.metricMode==='pieces'?'pieces':'weight'; ['showAmountPerGuest','showBoxCount','showPriceBreakdown','showDiscountBadge','showGallery','showControl','showExtras','showFinalPhoto','showClientName','showDate','showGuests','showFooterNote'].forEach(k=>d[k]=bool(t[k],d[k])); if(t.texts&&typeof t.texts==='object')Object.keys(d.texts).forEach(k=>{if(t.texts[k]!=null)d.texts[k]=String(t.texts[k]).trim()||d.texts[k]}); // v3 separates the short first-screen note from the longer selling copy. // Preserve any custom v2 hero text by moving it into the new selling block. if(Number(t.version||0)<3&&t.texts&&typeof t.texts==='object'&&!String(t.texts.salesNote||'').trim()){ const legacyHero=String(t.texts.heroNote||'').trim(); if(legacyHero)d.texts.salesNote=legacyHero; d.texts.heroNote=DEFAULTS.texts.heroNote; } d.controlLines=lines(t.controlLines,d.controlLines); d.extraServices=lines(t.extraServices,d.extraServices); // Since v17.5.17 table photos are automatic whitespace fillers, not an optional section. d.showFinalPhoto=true; return d; } function read(){try{return normalize(JSON.parse(localStorage.getItem(KEY)||'{}'))}catch(_){return clone(DEFAULTS)}} let state=read(); function save(next){state=normalize(next);localStorage.setItem(KEY,JSON.stringify(state));window.dispatchEvent(new CustomEvent('sunclientoffersettingschange',{detail:clone(state)}));return clone(state)} function reset(){return save(DEFAULTS)} const style=document.createElement('style'); style.id='sun-client-offer-settings-style'; style.textContent=` .sun-client-offer-settings-card{grid-column:1/-1!important} .sun-client-offer-settings-head{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap} .sun-client-offer-settings-head>div:first-child{flex:1;min-width:250px} .sun-client-offer-settings-card details{border:1px solid #e4e7ea;border-radius:14px;background:#fff;margin-top:10px;overflow:hidden} .sun-client-offer-settings-card summary{cursor:pointer;padding:13px 15px;font-weight:800;color:#2a3138;list-style:none;display:flex;align-items:center;justify-content:space-between;gap:10px} .sun-client-offer-settings-card summary::-webkit-details-marker{display:none} .sun-client-offer-settings-card summary:after{content:'+';font-size:20px;font-weight:500;color:#7a828a}.sun-client-offer-settings-card details[open] summary:after{content:'−'} .sun-client-offer-settings-body{border-top:1px solid #eceff1;padding:14px 15px 16px} .sun-client-offer-settings-grid{display:grid;grid-template-columns:repeat(2,minmax(220px,1fr));gap:12px} .sun-client-offer-settings-grid label,.sun-client-offer-settings-body>label{display:grid;gap:6px;font-size:12px;color:#59636d;font-weight:700} .sun-client-offer-settings-grid input,.sun-client-offer-settings-grid select,.sun-client-offer-settings-body textarea{width:100%;border:1px solid #d9dee3;border-radius:10px;background:#fff;color:#20262c;padding:10px 11px;font:inherit} .sun-client-offer-settings-body textarea{min-height:135px;resize:vertical;line-height:1.5} .sun-client-offer-switches{display:grid;grid-template-columns:repeat(3,minmax(170px,1fr));gap:9px} .sun-client-offer-switch{display:flex!important;grid-template-columns:none!important;align-items:center;gap:9px!important;border:1px solid #e2e6e9;border-radius:11px;padding:10px 11px;color:#303941!important;background:#fafbfb} .sun-client-offer-switch input{width:17px!important;height:17px;margin:0;accent-color:var(--sun-brand-sun,#FFC107)} .sun-client-offer-settings-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-top:14px;padding-top:14px;border-top:1px solid #eceff1} .sun-client-offer-settings-actions .hint{margin:0 0 0 auto} @media(max-width:760px){.sun-client-offer-settings-grid,.sun-client-offer-switches{grid-template-columns:1fr}.sun-client-offer-settings-actions .hint{width:100%;margin:0}} `; document.head.appendChild(style); function html(){ const s=state,t=s.texts; return `

Настройки предложения клиенту

Тексты и состав блоков применяются ко всем шаблонам и к PDF. Внутренний номер заказа клиенту не показывается.

Показатели в блоке «Итого»

Вес и количество боксов считаются только из раздела «Боксы». Напитки, посуда и дополнения в эти показатели не попадают. В составе предложения количество канапе/закусок каждого вида показывается итогом с учётом количества заказанных боксов.

Основные тексты
Продающий блок после первого экрана

Текст не обрезается: блок увеличивается и при необходимости переносится на следующую страницу PDF.

Тексты расчёта стоимости
Блок «Всё под контролем»
Дополнительно к заказу
Что показывать клиенту
Фото на столе: авто, только в свободное место

Изменения применятся к следующему открытию предложения; открытое предложение обновится автоматически.

`; } function collect(card){ const next=clone(state); card.querySelectorAll('[data-offer-setting]').forEach(el=>{const k=el.dataset.offerSetting;if(el.type==='checkbox')next[k]=el.checked;else next[k]=el.value}); next.texts={...next.texts}; card.querySelectorAll('[data-offer-text]').forEach(el=>{next.texts[el.dataset.offerText]=String(el.value||'').trim()}); card.querySelectorAll('[data-offer-list]').forEach(el=>{next[el.dataset.offerList]=String(el.value||'').split(/\r?\n/).map(x=>x.trim()).filter(Boolean)}); return normalize(next); } function bind(card){ card.querySelector('[data-offer-settings-save]')?.addEventListener('click',()=>{save(collect(card));card.innerHTML=html();bind(card);try{window.SunEnterprise?.toast?.('Настройки предложения сохранены.')}catch(_){}}); card.querySelector('[data-offer-settings-reset]')?.addEventListener('click',()=>{reset();card.innerHTML=html();bind(card);try{window.SunEnterprise?.toast?.('Стандартные настройки предложения восстановлены.')}catch(_){}}); } function ensureCard(){ const view=document.getElementById('enterprise-settings');if(!view)return; const grid=view.querySelector('.enterprise-grid');if(!grid)return; let card=document.getElementById('sunClientOfferSettingsCard'); if(card&&grid.contains(card))return; card=document.createElement('section');card.id='sunClientOfferSettingsCard';card.className='enterprise-card wide sun-client-offer-settings-card';card.innerHTML=html(); const templates=document.getElementById('sunOfferTemplateSettingsCard'); if(templates&&templates.parentElement===grid)templates.insertAdjacentElement('afterend',card);else{ const brand=document.getElementById('sunBrandThemeSettingsCard'); if(brand&&brand.parentElement===grid)brand.insertAdjacentElement('afterend',card);else grid.appendChild(card); } bind(card); } function boot(){ ensureCard(); const settings=document.getElementById('enterprise-settings');if(settings)new MutationObserver(()=>queueMicrotask(ensureCard)).observe(settings,{childList:true,subtree:true}); document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const label=(b.dataset.navLabel||b.textContent||'').trim();if(label==='Настройки')setTimeout(ensureCard,35)},true); window.addEventListener('storage',e=>{if(e.key===KEY){state=read();setTimeout(()=>{const card=document.getElementById('sunClientOfferSettingsCard');if(card){card.innerHTML=html();bind(card)}},20);window.dispatchEvent(new CustomEvent('sunclientoffersettingschange',{detail:clone(state)}));}}); window.addEventListener('sun:cloud-state-applied',()=>{state=read();setTimeout(()=>{const card=document.getElementById('sunClientOfferSettingsCard');if(card){card.innerHTML=html();bind(card)}},30)}); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); window.SunClientOfferSettings={key:KEY,defaults:()=>clone(DEFAULTS),get:()=>clone(state),set:save,reset}; })(); ; /* ===== MODULE: client-offer.js ===== */ (function(){ 'use strict'; if(window.__sunClientOfferV2)return; window.__sunClientOfferV2=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const esc=window.SunSafe.escapeHTML; const money=v=>`${Math.round(Number(v||0)).toLocaleString('ru-RU')} ₽`; const num=v=>Math.max(0,Number(v||0)); const toast=(m,t='success')=>{try{return window.SunEnterprise?.toast?.(m,t)}catch(_){} if(t==='error'||t==='warn')console.warn(m);}; const EMBEDDED_LOGO='data:image/png;base64,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'; const style=document.createElement('style'); style.id='sun-client-offer-style'; style.textContent=` #sunClientOfferModal{z-index:100050} #sunClientOfferModal .dialog{width:min(1180px,calc(100vw - 28px));max-height:94vh;padding:0;overflow:hidden;border-radius:16px;background:#fffaf2} .sun-offer-modal-head{display:flex;align-items:center;gap:10px;padding:13px 15px;background:#fffdf9;border-bottom:1px solid #e8d9bf;flex-wrap:wrap} .sun-offer-modal-head h2{margin:0;color:#28533a;font-size:19px}.sun-offer-modal-head .hint{margin:0;color:#73808a;font-size:12px} .sun-offer-modal-head .spacer{flex:1}.sun-offer-modal-actions{display:flex;gap:7px;flex-wrap:wrap}.sun-offer-modal-actions button{min-height:36px} .sun-offer-editor{display:none;padding:12px 15px;background:#fff;border-bottom:1px solid #e8d9bf}.sun-offer-editor.on{display:block}.sun-offer-editor-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}.sun-offer-editor label{display:grid;gap:4px;font-size:10px;font-weight:700;color:#607068}.sun-offer-editor label.wide{grid-column:span 2}.sun-offer-editor input,.sun-offer-editor textarea{width:100%;box-sizing:border-box;border:1px solid #d9d2c7;border-radius:9px;padding:8px 9px;background:#fff;font:12px/1.35 Arial;color:#1d2b24}.sun-offer-editor textarea{min-height:62px;resize:vertical}.sun-offer-editor-note{margin:8px 0 0;color:#778178;font-size:10px}.sun-offer-editor-gallery{display:grid;grid-template-columns:minmax(0,1fr) 190px;gap:12px;align-items:center;border:1px solid #e7dfd2;border-radius:10px;padding:9px;background:#fffdf9}.sun-offer-editor-gallery b{display:block;font-size:11px;color:#425248}.sun-offer-editor-gallery small{display:block;margin-top:4px;font-size:10px;line-height:1.4;color:#7b827d}.sun-offer-editor-gallery-images{display:grid;grid-template-columns:1fr 1fr;gap:5px}.sun-offer-editor-gallery-images img{width:100%;height:70px;object-fit:cover;border-radius:7px;border:1px solid #e5ded3} .sun-offer-frame-wrap{height:min(78vh,900px);background:#eee9e0;padding:12px;overflow:auto} #sunClientOfferPreview{display:grid;gap:14px;justify-items:center;min-height:100%}.sun-offer-page-canvas{display:block;width:min(100%,794px);height:auto;background:#fff;box-shadow:0 5px 24px #4a38272b}.sun-offer-rendering{align-self:center;justify-self:center;margin:70px 20px;padding:14px 18px;border-radius:12px;background:#fff;color:#526159;font-size:12px;box-shadow:0 4px 18px #00000012} .sun-offer-stale{display:none;padding:7px 12px;background:#fff6df;color:#8b6213;border-radius:8px;font-size:12px}.sun-offer-stale.on{display:block} #new .actions #sunClientOfferButton{background:#fff8e9;border-color:#c99b47;color:#28533a} @media(max-width:900px){.sun-offer-editor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} @media(max-width:700px){.sun-offer-editor-gallery{grid-template-columns:1fr}.sun-offer-editor-gallery-images img{height:95px}#sunClientOfferModal{padding:0}#sunClientOfferModal .dialog{width:100vw;height:100vh;max-height:none;border-radius:0}.sun-offer-frame-wrap{height:calc(100vh - 112px);padding:5px}.sun-offer-modal-head{padding:9px}.sun-offer-modal-head h2{font-size:16px}.sun-offer-modal-head .hint{display:none}.sun-offer-modal-actions{width:100%;display:grid;grid-template-columns:1.15fr 1fr 1fr 1fr}.sun-offer-modal-actions button{padding:8px 4px;font-size:10px}.sun-offer-editor{padding:9px}.sun-offer-editor-grid{grid-template-columns:1fr}.sun-offer-editor label.wide{grid-column:auto}} `; document.head.appendChild(style); const getBoxes=()=>{try{if(typeof boxes!=='undefined'&&Array.isArray(boxes))return boxes}catch(_){}try{const v=JSON.parse(localStorage.getItem('sunBoxes')||'[]');return Array.isArray(v)?v:[]}catch(_){return[]}}; const getLegacyBoxes=()=>Array.isArray(window.SUN_LEGACY_CATALOG_V175)?window.SUN_LEGACY_CATALOG_V175:[]; const normalizedCatalogName=value=>String(value||'').toLowerCase().replace(/ё/g,'е').replace(/[^a-zа-я0-9]+/gi,' ').trim().replace(/\s+/g,' '); function resolveCatalogLine(line,all=getBoxes()){ const id=String(line?.id??''); let item=(all||[]).find(x=>String(x.id)===id); if(item)return item; const legacy=getLegacyBoxes(); item=legacy.find(x=>String(x.id)===id); if(item)return item; const name=normalizedCatalogName(line?.name||line?.catalogName||''); if(name){ item=(all||[]).find(x=>normalizedCatalogName(x?.name)===name)||legacy.find(x=>normalizedCatalogName(x?.name)===name); if(item)return item; } return null; } const getOrders=()=>{try{if(typeof orders!=='undefined'&&Array.isArray(orders))return orders}catch(_){}try{const v=JSON.parse(localStorage.getItem('sunOrders')||'[]');return Array.isArray(v)?v:[]}catch(_){return[]}}; const getDraft=()=>{try{return typeof draft!=='undefined'?draft:null}catch(_){return null}}; const catName=id=>{try{return window.sunCatalogCategoryName?.(id)||({0:'Боксы',1:'Посуда и упаковка',2:'Дополнительно',3:'Напитки',4:'Доставка',5:'Премиум'}[Number(id)]||'Каталог')}catch(_){return 'Каталог'}}; function linePrice(line,item){const p=Number(line?.price);return Number.isFinite(p)&&p>=0?p:num(item?.price)} function discountAmount(value,type,base){const n=num(value);return Math.min(base,type==='amount'?n:base*Math.min(100,n)/100)} function priceCalc(order){ const all=getBoxes(); const base=(order?.lines||[]).reduce((sum,line)=>{const item=resolveCatalogLine(line,all);return sum+linePrice(line,item)*num(line.qty)},0); const manual=discountAmount(order?.manualDiscountValue,order?.manualDiscountType,base); const afterManual=Math.max(0,base-manual); const promo=discountAmount(order?.promoDiscountValue,order?.promoDiscountType,afterManual); const itemsTotal=Math.max(0,afterManual-promo); const delivery=num(order?.deliveryCost); return {base,manual,promo,itemsTotal,delivery,total:itemsTotal+delivery,discount:manual+promo}; } function parseMeasure(text){ const s=String(text||'').toLowerCase().replace(/,/g,'.'); const m=s.match(/(\d+(?:\.\d+)?)\s*(кг|kg|мл|ml|л|l|г|g)(?:\s|$|[^a-zа-яё])/iu)||s.match(/(\d+(?:\.\d+)?)\s*(кг|kg|мл|ml|л|l|г|g)$/iu); if(!m)return null;const value=Number(m[1]),u=m[2];if(!Number.isFinite(value))return null; if(u==='кг'||u==='kg')return {kind:'food',value:value*1000,unit:'г'}; if(u==='г'||u==='g')return {kind:'food',value,unit:'г'}; if(u==='л'||u==='l')return {kind:'drink',value:value*1000,unit:'мл'}; if(u==='мл'||u==='ml')return {kind:'drink',value,unit:'мл'}; return null; } function ingredientWeight(row){if(!Array.isArray(row))return 0;const direct=Math.max(0,num(row[3]));if(direct)return direct;const m=String(row[0]||'').match(/[—–-]\s*(\d+(?:[.,]\d+)?)\s*г(?:\s*\/\s*шт\.?)?\s*$/i);return m?Math.max(0,num(String(m[1]).replace(',','.'))):0} function cleanIngredientName(name){return String(name||'').replace(/\s*[—–-]\s*\d+(?:[.,]\d+)?\s*г(?:\s*\/\s*шт\.?)?\s*$/i,'').trim()} function ingredientLine(row){if(!Array.isArray(row)||!String(row[0]||'').trim())return'';const name=cleanIngredientName(row[0]),qty=Math.max(0,num(row[1])),unit=String(row[2]||'').trim(),w=ingredientWeight(row);if(/^поз\.?$/i.test(unit)&&qty<=1)return `${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`;const shown=Number.isInteger(qty)?String(qty):qty.toLocaleString('ru-RU',{maximumFractionDigits:2});return `${shown} ${unit} ${name}${w?` — ${w.toLocaleString('ru-RU')} г/шт.`:''}`.replace(/\s+/g,' ').trim()} function composition(item){ // Client-facing composition is independent from kitchen TTK ingredients. if(Array.isArray(item?.composition)&&item.composition.length)return item.composition.map(x=>String(x||'').trim()).filter(Boolean); if(Array.isArray(item?.ingredients)&&item.ingredients.some(x=>Array.isArray(x)&&x[0]))return item.ingredients.map(ingredientLine).filter(Boolean); return []; } function orderSignature(order){ const clean={id:String(order?.id??''),event:order?.event||'',date:order?.date||'',time:order?.time||'',contact:order?.contact||'',guestsCount:num(order?.guestsCount),deliveryCost:num(order?.deliveryCost),manualDiscountValue:num(order?.manualDiscountValue),manualDiscountType:order?.manualDiscountType||'percent',promoId:order?.promoId||'',promoCode:order?.promoCode||'',promoDiscountValue:num(order?.promoDiscountValue),promoDiscountType:order?.promoDiscountType||'percent',lines:(order?.lines||[]).map(l=>({id:String(l.id),qty:num(l.qty),price:Number.isFinite(Number(l.price))?Number(l.price):null}))}; return JSON.stringify(clean); } function currentSavedOrder(id){return getOrders().find(o=>String(o.id)===String(id))||null} function currentOfferSourceOrder(id,preferDraft=false){ const saved=currentSavedOrder(id),d=getDraft(); if(preferDraft&&d&&String(d.id)===String(id))return d; return saved; } function snapshotIsStale(order,snapshot){ if(!snapshot||Number(snapshot.version||0)<7||snapshot.sourceSignature!==orderSignature(order))return true; const all=getBoxes(); return (snapshot.items||[]).some(item=>{ const missingName=!String(item?.name||'').trim()||String(item?.name||'').trim()==='Позиция'; const missingPhoto=!String(item?.photo||'').trim(); return (missingName||missingPhoto)&&Boolean(resolveCatalogLine(item,all)); }); } function sectionTitle(item){const s=String(item?.catalogSection||'').trim();return s||String(item?.categoryName||'Меню')} function canapePieces(item){ // v17.5.1: any food box may contain countable ready-to-serve pieces, not only sections named "canape". if(![0,5].includes(Number(item?.category??item?.categoryId??0)))return 0; const explicit=Math.max(0,num(item?.pieces)); if(explicit>0)return explicit; let total=0; if(Array.isArray(item?.ingredients)){ for(const row of item.ingredients){ if(!Array.isArray(row))continue; const value=num(row[1]),unit=String(row[2]||'').toLowerCase().replace(/\s+/g,''); if(/^(шт\.?|пор\.?|кус\.?|шарик(?:а|ов|и)?|креманк(?:а|и|е)?)$/i.test(unit))total+=value; } } if(total>0)return total; for(const text of Array.isArray(item?.composition)?item.composition:[]){ const re=/(\d+(?:[.,]\d+)?)\s*(?:шт\.?|пор\.?|кус\.?)/ig;let m;while((m=re.exec(String(text||''))))total+=num(String(m[1]).replace(',','.')); } return total; } function multiplyLeadingPieces(text,qty){ const raw=String(text||'').trim(),q=Math.max(0,num(qty));if(!raw||q<=0)return raw; return raw.replace(/^(\d+(?:[.,]\d+)?)\s*(шт\.?|пор\.?|кус\.?)\s+/i,(m,n,u)=>{ const total=Number(String(n).replace(',','.'))*q; const shown=Number.isInteger(total)?String(total):total.toLocaleString('ru-RU',{maximumFractionDigits:2}); return `${shown} ${u} `; }); } function totalComposition(item,qty,categoryId){ const list=composition(item);return [0,5].includes(Number(categoryId))?list.map(x=>multiplyLeadingPieces(x,qty)):list; } function offerComposition(item){ const list=Array.isArray(item?.compositionTotal)&&item.compositionTotal.length?item.compositionTotal:(Array.isArray(item?.composition)?item.composition:[]); return list.map(x=>String(x||'').trim()).filter(Boolean); } function roundUp(value,step=1){const n=Math.max(0,Number(value||0)),s=Math.max(1,Number(step||1));return Math.ceil((n-1e-9)/s)*s} function guestRangeLabel(raw){ const value=String(raw||'').trim().replace(/(\d)\s*[-–—]\s*(\d)/g,'$1–$2'); if(!value)return'';return /(?:гост|чел)/i.test(value)?value:`${value} гостей`; } function boxQuantityLabel(qty){const n=Math.max(0,Math.round(num(qty)));return n?`${n} ${plural(n,'бокс','бокса','боксов')}`:''} function totalMeasureLabel(item){ const raw=String(item?.weight||'').trim(),qty=Math.max(0,num(item?.qty));if(!raw||!qty)return''; const measure=parseMeasure(raw);if(!measure)return qty===1?`Вес бокса: ${raw}`:`Вес бокса: ${raw} × ${qty}`; const total=measure.value*qty,shown=(Number.isInteger(total)?total:Math.round(total*100)/100).toLocaleString('ru-RU',{maximumFractionDigits:2}); return `Общий ${measure.kind==='drink'?'объём':'вес'}: ${shown} ${measure.unit}`; } function weightLabel(item){ const raw=String(item?.weight||'').trim(),isBox=[0,5].includes(Number(item?.categoryId??item?.category??0)),pieces=isBox?Math.max(0,num(item?.pieces)):0,qty=Math.max(0,num(item?.qty)); if(isBox){ const parts=[]; const totalWeight=totalMeasureLabel(item);if(totalWeight)parts.push(totalWeight);else if(raw)parts.push(`Общий вес: ${raw}`); if(pieces&&qty)parts.push(`Всего: ${(pieces*qty).toLocaleString('ru-RU',{maximumFractionDigits:2})} шт.`); return parts.join(' · ') } return raw?`Вес / объём: ${raw}`:''; } async function createSnapshot(order){ const all=getBoxes(),p=priceCalc(order),guests=num(order?.guestsCount)||num($('eventGuests')?.value),selected=new Set((order?.lines||[]).map(l=>String(l.id))); let foodGrams=0,drinkMl=0,foodPieces=0; const items=(order?.lines||[]).map(line=>{ const item=resolveCatalogLine(line,all)||{};const qty=num(line.qty),price=linePrice(line,item),measure=parseMeasure(item.weight),rawItemCategory=item.category,rawLineCategory=line.category,itemCategory=rawItemCategory!==undefined&&rawItemCategory!==null&&rawItemCategory!==''?Number(rawItemCategory):NaN,lineCategory=rawLineCategory!==undefined&&rawLineCategory!==null&&rawLineCategory!==''?Number(rawLineCategory):NaN,categoryId=Number.isFinite(itemCategory)?itemCategory:(Number.isFinite(lineCategory)?lineCategory:-1),pieces=canapePieces(item),comp=composition(item),compositionTotal=[0,5].includes(Number(categoryId))?comp.map(x=>multiplyLeadingPieces(x,qty)):comp; if(measure){if(measure.kind==='drink'||categoryId===3)drinkMl+=measure.value*qty;else if([0,5].includes(categoryId))foodGrams+=measure.value*qty;} if([0,5].includes(categoryId)&&pieces>0)foodPieces+=pieces*qty; return {id:String(item.id??line.id??''),name:String(item.name||line.name||'Позиция'),categoryId,categoryName:catName(categoryId),catalogSection:String(item.catalogSection||''),qty,unitPrice:price,sum:price*qty,weight:String(item.weight||''),boxGuests:String(item.guests||''),photo:String(item.photo||''),composition:comp,compositionTotal,pieces}; }).filter(x=>x.qty>0); const extras=all.filter(item=>[1,2,3].includes(Number(item.category))&&!selected.has(String(item.id))&&!item.hidden).slice(0,6).map(item=>({name:String(item.name||''),categoryName:catName(item.category)})).filter(x=>x.name); return {version:8,createdAt:new Date().toISOString(),orderId:order?.id||'',sourceSignature:orderSignature(order),event:String(order?.event||''),date:String(order?.date||''),time:String(order?.time||''),client:String(order?.contact||''),guests,foodGrams,foodPieces,drinkMl,pricing:p,promoCode:String(order?.promoCode||''),items,extras,offerOverrides:structuredClone(order?.clientOfferSnapshot?.offerOverrides||{})}; } function persistSnapshot(orderId,snapshot){ let list=getOrders(),i=list.findIndex(o=>String(o.id)===String(orderId));if(i<0)return false; list[i].clientOfferSnapshot=snapshot;list[i].clientOfferUpdatedAt=snapshot.createdAt; try{if(typeof orders!=='undefined'&&Array.isArray(orders)){const j=orders.findIndex(o=>String(o.id)===String(orderId));if(j>=0){orders[j].clientOfferSnapshot=snapshot;orders[j].clientOfferUpdatedAt=snapshot.createdAt;}}}catch(_){} const d=getDraft();if(d&&String(d.id)===String(orderId)){d.clientOfferSnapshot=snapshot;d.clientOfferUpdatedAt=snapshot.createdAt;} try{if(typeof persist==='function')persist();else localStorage.setItem('sunOrders',JSON.stringify(list));return true}catch(err){console.error(err);toast('Не удалось сохранить предложение: возможно, переполнено локальное хранилище.','error');return false} } function ensureModal(){ if($('sunClientOfferModal'))return; const modal=document.createElement('div');modal.id='sunClientOfferModal';modal.className='modal';modal.innerHTML=`

Предложение клиенту

Заказ изменён — предложение будет автоматически обновлено из текущих данных.

Изменения относятся только к этому предложению. Просмотр ниже — те же страницы, которые попадут в скачанный PDF.

`;document.body.appendChild(modal); $('sunOfferClose').onclick=()=>window.closeModal?.('sunClientOfferModal'); $('sunOfferRefresh').onclick=refreshCurrentOffer;$('sunOfferPdf').onclick=downloadCurrentOfferPdf;$('sunOfferEdit').onclick=toggleOfferEditor;bindOfferEditor(); } function dateText(raw){if(!raw)return'Дата уточняется';const d=new Date(`${raw}T00:00:00`);return Number.isNaN(d.getTime())?raw:d.toLocaleDateString('ru-RU',{day:'numeric',month:'long'})} function perGuest(value,guests){return guests>0?value/guests:0} function metricValue(value,unit,guests){if(!guests||!value)return'—';const per=value/guests,rounded=unit==='г'?roundUp(per,5):roundUp(per,1);return `${rounded.toLocaleString('ru-RU')} ${unit}`} function itemPerGuest(item,guests){const measure=parseMeasure(item?.weight);if(!guests||!measure)return'—';const per=measure.value*num(item.qty)/guests,rounded=measure.kind==='drink'?roundUp(per,1):roundUp(per,5);return `${rounded.toLocaleString('ru-RU')} ${measure.kind==='drink'?'мл':'г'}`} const EXTRA_SERVICES=[ ['Напитки',''], ['Десерты',''], ['Фрукты',''], ['Одноразовая посуда',''] ]; const DELIVERY_CONTROL=[ 'Фирменная упаковка', 'Уточняем детали доставки', 'Стоимость заказа не изменится', 'Готовим закуски в день мероприятия', 'Контролируем заказ до момента передачи', 'Привозим заказ вовремя и передаём вам лично', 'Всё организованно! Вы просто встречаете гостей!' ]; const FINAL_GALLERY_PATHS=[...(Array.isArray(window.SUN_OFFER_GALLERY_DATA)?window.SUN_OFFER_GALLERY_DATA.filter(Boolean).slice(0,2):[])];if(FINAL_GALLERY_PATHS.length<2)FINAL_GALLERY_PATHS.push(...Array.from({length:2-FINAL_GALLERY_PATHS.length},(_,i)=>`offer-gallery/${String(FINAL_GALLERY_PATHS.length+i+1).padStart(3,'0')}.jpg`)); function plural(n,one,few,many){const x=Math.abs(Number(n||0))%100,y=x%10;return x>10&&x<20?many:y>1&&y<5?few:y===1?one:many} const SAFE_PIXEL='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9Zwv8AAAAASUVORK5CYII='; const isSafeRasterDataUrl=src=>/^data:image\/(?!svg\+xml)[a-z0-9.+-]+;/i.test(String(src||'')); async function asDataUrlOne(src){ if(!src)return''; const raw=String(src).trim(); if(isSafeRasterDataUrl(raw))return raw; if(/^data:/i.test(raw))return''; try{ const url=new URL(raw,document.baseURI||location.href); if(!['http:','https:','blob:'].includes(url.protocol))return''; const sameOrigin=url.protocol==='blob:'||url.origin===location.origin; const res=await fetch(url,{mode:'cors',credentials:sameOrigin?'same-origin':'omit',cache:'force-cache'}); if(!res.ok)throw new Error(`HTTP ${res.status}`); const blob=await res.blob(); if(!/^image\/(?!svg\+xml)[a-z0-9.+-]+$/i.test(String(blob.type||'')))throw new Error('Неподдерживаемый формат изображения'); const data=await new Promise((resolve,reject)=>{const r=new FileReader();r.onload=()=>resolve(String(r.result||''));r.onerror=()=>reject(r.error||new Error('FileReader'));r.readAsDataURL(blob)}); return isSafeRasterDataUrl(data)?data:''; }catch(err){return''} } async function asDataUrl(src){ const list=window.SunCatalogPhoto?.candidates?.(src)||[src]; for(const candidate of list){const data=await asDataUrlOne(candidate);if(data)return data;} console.warn('PDF image unavailable after all fallbacks:',src); return''; } async function preparedSnapshot(snapshot){ const copy=structuredClone(snapshot),liveCatalog=getBoxes(),legacyCatalog=getLegacyBoxes(); // Preview uses normal image URLs. Expensive Base64 conversion is deferred until PDF download. copy.logo=EMBEDDED_LOGO||'sun-logo.png'; copy.finalPhoto=''; copy.finalGallery=FINAL_GALLERY_PATHS.slice(0,2); const dataOverrides=copy.offerOverrides?.data&&typeof copy.offerOverrides.data==='object'?copy.offerOverrides.data:{}; if(Object.prototype.hasOwnProperty.call(dataOverrides,'event'))copy.event=String(dataOverrides.event??''); if(Object.prototype.hasOwnProperty.call(dataOverrides,'client'))copy.client=String(dataOverrides.client??''); if(Object.prototype.hasOwnProperty.call(dataOverrides,'date'))copy.date=String(dataOverrides.date??''); if(Object.prototype.hasOwnProperty.call(dataOverrides,'guests'))copy.guests=Math.max(0,num(dataOverrides.guests)); for(const item of copy.items){ // Quantity and price come from the order snapshot; catalog presentation data is always current. const live=liveCatalog.find(x=>String(x.id)===String(item.id))||legacyCatalog.find(x=>String(x.id)===String(item.id)); if(live){ item.name=String(live.name||item.name||'Позиция'); if(Number.isFinite(Number(live.category)))item.categoryId=Number(live.category); item.categoryName=catName(item.categoryId); item.photo=String(live.photo||'');item.weight=String(live.weight||'');item.boxGuests=String(live.guests||'');item.catalogSection=String(live.catalogSection||item.catalogSection||''); const comp=composition(live);item.composition=comp;item.compositionTotal=[0,5].includes(Number(item.categoryId))?comp.map(x=>multiplyLeadingPieces(x,item.qty)):comp;item.pieces=canapePieces(live); }else item.compositionTotal=[0,5].includes(Number(item.categoryId))?(item.composition||[]).map(x=>multiplyLeadingPieces(x,item.qty)):(item.composition||[]); item.photoData=item.photo||copy.logo; } copy.foodGrams=0;copy.drinkMl=0;copy.foodPieces=0; for(const item of copy.items){const measure=parseMeasure(item.weight);if(measure){if(measure.kind==='drink'||Number(item.categoryId)===3)copy.drinkMl+=measure.value*num(item.qty);else if([0,5].includes(Number(item.categoryId)))copy.foodGrams+=measure.value*num(item.qty);}if([0,5].includes(Number(item.categoryId))&&num(item.pieces)>0)copy.foodPieces+=num(item.pieces)*num(item.qty)} return copy; } async function preparedPdfSnapshot(prepared){ const copy=structuredClone(prepared),cache=new Map(); const resolve=src=>{const key=String(src||'');if(!key)return Promise.resolve('');if(!cache.has(key))cache.set(key,asDataUrl(key));return cache.get(key);}; copy.logo=(await resolve(copy.logo||'sun-logo.png'))||SAFE_PIXEL; copy.finalGallery=(await Promise.all((copy.finalGallery||[]).map(resolve))).filter(Boolean); await Promise.all((copy.items||[]).map(async item=>{item.photoData=(await resolve(item.photoData||item.photo||''))||copy.logo;})); return copy; } const OFFER_TEMPLATE_KEY='sunOfferTemplateV1'; const OFFER_TEMPLATE_IDS=new Set(['light','midnight-glass','editorial-grid','warm-sun','bento-cards','event-story','black-gold','personal-letter','event-ticket','solar-experience','midnight-compact','emerald-gold','neon-emerald']); function offerTemplateId(){ try{ const api=window.SunOfferTemplate?.get?.(); if(api?.id&&OFFER_TEMPLATE_IDS.has(api.id))return api.id; const raw=JSON.parse(localStorage.getItem(OFFER_TEMPLATE_KEY)||'{}')||{}; if(raw.id&&OFFER_TEMPLATE_IDS.has(raw.id))return raw.id; }catch(_){} return 'light'; } const CLIENT_OFFER_SETTINGS_KEY='sunClientOfferSettingsV1'; const CLIENT_OFFER_DEFAULTS={metricMode:'weight',showAmountPerGuest:true,showBoxCount:true,showPriceBreakdown:true,showDiscountBadge:true,showGallery:true,showControl:true,showExtras:true,showFinalPhoto:true,showClientName:true,showDate:true,showGuests:true,showFooterNote:true,texts:{proposalLabel:'Индивидуальное предложение',menuTitle:'Меню',summaryTitle:'Итого',totalPriceTitle:'Итоговая стоимость',heroNote:'Фирменные боксы с закусками — готово к подаче на стол.',salesTitle:'Почему с нами удобно',salesNote:'Меню составлено специально под ваше событие. Закуски приезжают в фирменных боксах, их удобно поставить на стол и подать без сложной сервировки. Мы готовим заказ в день доставки, используем свежие ингредиенты и контролируем детали до передачи заказа.',finalGalleryTitle:'Как это выглядит на вашем столе',weightMetricLabel:'Вес еды на гостя',piecesMetricLabel:'Канапе на гостя',amountPerGuestLabel:'Сумма на гостя',boxCountLabel:'Количество боксов',pricingTitle:'Расчёт стоимости',priceItemsLabel:'Стоимость позиций',discountLabel:'Скидка',promoLabel:'Промокод',menuAfterDiscountLabel:'Меню после скидок',deliveryLabel:'Доставка',totalLabel:'Итого',controlTitle:'Всё под контролем команды Солнца',extrasTitle:'Дополнительно к заказу рекомендуем',footerNote:'Доставка считается отдельно от меню и не участвует в скидках.'},controlLines:[...DELIVERY_CONTROL],extraServices:EXTRA_SERVICES.map(x=>x[0])}; function offerSettings(){ try{const api=window.SunClientOfferSettings?.get?.();if(api)return api}catch(_){} try{ const raw=JSON.parse(localStorage.getItem(CLIENT_OFFER_SETTINGS_KEY)||'{}')||{},d=structuredClone(CLIENT_OFFER_DEFAULTS); Object.keys(d).forEach(k=>{if(k!=='texts'&&k!=='controlLines'&&k!=='extraServices'&&raw[k]!=null)d[k]=raw[k]}); if(raw.texts&&typeof raw.texts==='object')d.texts={...d.texts,...raw.texts}; if(Array.isArray(raw.controlLines)&&raw.controlLines.length)d.controlLines=raw.controlLines; if(Array.isArray(raw.extraServices)&&raw.extraServices.length)d.extraServices=raw.extraServices; return d; }catch(_){return structuredClone(CLIENT_OFFER_DEFAULTS)} } function offerSettingsForSnapshot(s){ const cfg=offerSettings(),textOverrides=s?.offerOverrides?.texts; if(textOverrides&&typeof textOverrides==='object')cfg.texts={...cfg.texts,...textOverrides}; if(Array.isArray(s?.offerOverrides?.controlLines))cfg.controlLines=s.offerOverrides.controlLines.map(x=>String(x||'').trim()).filter(Boolean).slice(0,20); // Table photos are automatic: they are shown only when the final page has free space. cfg.showFinalPhoto=true; return cfg; } function offerBoxCount(items){return (items||[]).filter(item=>[0,5].includes(Number(item.categoryId??0))).reduce((n,item)=>n+num(item.qty),0)} function offerPrimaryMetric(s,cfg,g){ if(cfg.metricMode==='pieces')return {value:g&&num(s.foodPieces)?`${roundUp(num(s.foodPieces)/g,1).toLocaleString('ru-RU')} шт.`:'—',label:cfg.texts?.piecesMetricLabel||'Канапе на гостя'}; return {value:metricValue(s.foodGrams,'г',g),label:cfg.texts?.weightMetricLabel||'Вес еды на гостя'}; } function offerIconSvg(title=''){ const t=String(title).toLowerCase(); if(/рыб|мор|лосос|кревет/.test(t))return ''; if(/мяс|ростбиф|бургер|ветчин|салям/.test(t))return ''; if(/вег|овощ|салат/.test(t))return ''; if(/десерт|слад|макарон|торт/.test(t))return ''; return ''; } function offerGroups(items){ const map=new Map(); (items||[]).forEach(item=>{const k=sectionTitle(item)||'Меню';if(!map.has(k))map.set(k,[]);map.get(k).push(item)}); return [...map.entries()].map(([name,list])=>({name,list})); } function editorialGroups(items){ return offerGroups(items).map(group=>{ const weights=group.list.map(item=>parseMeasure(item.weight)).filter(m=>m&&m.kind!=='drink').map(m=>Math.round(m.value)).filter(v=>v>0); const minW=weights.length?Math.min(...weights):0,maxW=weights.length?Math.max(...weights):0; const qty=group.list.reduce((n,item)=>n+Math.max(0,num(item.qty)),0); const weightText=minW?(minW===maxW?`${minW} г`:`${minW}-${maxW} г`):''; const positions=`${group.list.length} ${plural(group.list.length,'блюдо','блюда','блюд')}`; return {...group,qty,weightText,positions,meta:[weightText,positions].filter(Boolean).join(' · ')}; }); } function offerHtml(s){ const templateId=OFFER_TEMPLATE_IDS.has(s.offerTemplateId)?s.offerTemplateId:offerTemplateId(); const themeClass=`theme-${templateId}`; const cfg=offerSettingsForSnapshot(s),p=s.pricing||{},g=num(s.guests),menuPer=perGuest(p.itemsTotal,g); const items=s.items||[],boxCount=offerBoxCount(items),positionCount=items.length,groups=offerGroups(items),heroPhoto=items.find(item=>item.photoData)?.photoData||s.finalGallery?.[0]||s.logo||''; const primaryMetric=offerPrimaryMetric(s,cfg,g),eventName=String(s.event||'Персональное предложение').trim(),clientName=cfg.showClientName?String(s.client||'').trim():''; const visibleDate=cfg.showDate?dateText(s.date):'',visibleGuests=cfg.showGuests&&g?`${g} ${plural(g,'гость','гостя','гостей')}`:''; const discountPct=p.base>0?Math.round((p.discount/p.base)*100):0; const compositionText=(item,sep=' · ')=>offerComposition(item).join(sep); const itemMeta=item=>[weightLabel(item),compositionText(item)].filter(Boolean).join(' · '); const photo=(item,i,cls='')=>`
${i+1}${esc(item.name)}
${esc(item.name)}
`; const row=item=>`
${offerIconSvg(sectionTitle(item))}
${esc(item.name)}${itemMeta(item)?`${esc(itemMeta(item))}`:''}
× ${Math.round(num(item.qty))}
`; const groupTable=group=>`

${esc(group.name)}

Итого по позицииКоличество
${group.list.map(item=>{const comp=compositionText(item);return `
${esc(item.name)}${comp?`${esc(comp)}`:''}
${esc(weightLabel(item)||item.weight||'—')}× ${Math.round(num(item.qty))}
`}).join('')}
`; const gallery=items.map((item,i)=>photo(item,i)).join(''); const controlLines=Array.isArray(cfg.controlLines)&&cfg.controlLines.length?cfg.controlLines:DELIVERY_CONTROL; const extrasList=Array.isArray(cfg.extraServices)&&cfg.extraServices.length?cfg.extraServices:EXTRA_SERVICES.map(x=>x[0]); const deliveryControl=controlLines.map(item=>`
  • ${esc(item)}
  • `).join(''); const deliveryControlShort=controlLines.slice(0,5).map(item=>`
  • ${esc(item)}
  • `).join(''); const extraServices=extrasList.map(name=>`
    +${esc(name)}
    `).join(''); const manual=p.manual?`
    ${esc(cfg.texts.discountLabel||'Скидка')}- ${money(p.manual)}
    `:''; const promo=p.promo?`
    ${esc(cfg.texts.promoLabel||'Промокод')}${s.promoCode?` ${esc(s.promoCode)}`:''}- ${money(p.promo)}
    `:''; const breakdown=cfg.showPriceBreakdown?`
    ${esc(cfg.texts.priceItemsLabel||'Стоимость позиций')}${money(p.base)}
    ${manual}${promo}
    ${esc(cfg.texts.menuAfterDiscountLabel||'Меню после скидок')}${money(p.itemsTotal)}
    ${esc(cfg.texts.deliveryLabel||'Доставка')}${money(p.delivery)}
    ${esc(cfg.texts.totalLabel||'Итого')}${money(p.total)}
    `:''; const metricCards=[`
    ${esc(primaryMetric.value)}${esc(primaryMetric.label)}
    `,cfg.showAmountPerGuest?`
    ${g?money(menuPer):'—'}${esc(cfg.texts.amountPerGuestLabel||'Сумма на гостя')}
    `:'',cfg.showBoxCount?`
    ${Math.round(boxCount)}${esc(cfg.texts.boxCountLabel||'Количество боксов')}
    `:''].filter(Boolean); const metrics=`
    ${metricCards.join('')}
    `; const infoParts=[]; if(cfg.showControl)infoParts.push(`

    ${esc(cfg.texts.controlTitle)}

      ${deliveryControl}
    `); if(cfg.showExtras)infoParts.push(`

    ${esc(cfg.texts.extrasTitle)}

    ${extraServices}
    `); const info=infoParts.length?`
    ${infoParts.join('')}
    `:''; const actions=''; const brand=`
    ${visibleDate?`
    ${esc(visibleDate)}
    `:''}
    `; const heroStats=[visibleDate?`${esc(visibleDate)}`:'',visibleGuests?`${esc(visibleGuests)}`:''].filter(Boolean).join(''); const standardHero=`
    ${esc(cfg.texts.proposalLabel)}

    ${esc(eventName)}

    ${clientName?`
    ${esc(clientName)}
    `:''}${heroStats?`
    ${heroStats}
    `:''}

    ${esc(cfg.texts.heroNote)}

    ${esc(eventName)}
    `; const sellingBlock=(String(cfg.texts.salesTitle||'').trim()||String(cfg.texts.salesNote||'').trim())?`
    ${String(cfg.texts.salesTitle||'').trim()?`

    ${esc(cfg.texts.salesTitle)}

    `:''}${String(cfg.texts.salesNote||'').trim()?`

    ${esc(cfg.texts.salesNote)}

    `:''}
    `:''; const identityLine=[clientName,visibleDate,visibleGuests].filter(Boolean).join(' · '); const blackControl=cfg.showControl?`

    ${esc(cfg.texts.controlTitle)}

      ${deliveryControlShort}
    `:''; const blackExtras=cfg.showExtras?`

    ${esc(cfg.texts.extrasTitle)}

    ${extraServices}
    `:''; const egSideParts=[cfg.showControl?`

    ${esc(cfg.texts.controlTitle)}

      ${deliveryControlShort}
    `:'',cfg.showExtras?`

    ${esc(cfg.texts.extrasTitle)}

    ${extraServices}
    `:''].filter(Boolean); const egSide=egSideParts.length?``:''; const egFacts=[visibleDate,clientName,visibleGuests].filter(Boolean); const footerNote=cfg.showFooterNote?`
    ${esc(cfg.texts.footerNote)}
    `:''; let body=''; if(templateId==='editorial-grid'){ const editorial=editorialGroups(items); const editorialRows=editorial.map((group,gi)=>`
    ${String(gi+1).padStart(2,'0')}
    ${esc(group.name)}${esc(group.meta)}
    × ${Math.round(group.qty)}
    `).join(''); const editorialGallery=items.slice(0,8).map((item,i)=>photo(item,i,'ed-photo')).join(''); body=`${brand}
    ${esc(cfg.texts.proposalLabel)}

    ${esc(eventName)}

    ${clientName?`
    ${esc(clientName)}
    `:''}
    ${visibleDate?`◷ ${esc(visibleDate)}`:''}${visibleGuests?`○ ${esc(visibleGuests)}`:''}

    ${esc(cfg.texts.heroNote)}

    ${esc(eventName)}
    ${sellingBlock}
    ${esc(cfg.texts.menuTitle)}
    ${editorialRows}
    ${cfg.showGallery?`
    ${editorialGallery}
    `:''}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}${g?`на гостя: ${money(menuPer)}`:'Финальная сумма'}${cfg.showDiscountBadge&&discountPct?`-${discountPct}% учтено`:''}
    ${breakdown}${info}${actions}`; }else if(templateId==='light'){ body=`${brand}${standardHero}${sellingBlock}
    ${esc(cfg.texts.menuTitle)}
    ${cfg.showGallery?``:''}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}${g?`на гостя: ${money(menuPer)}`:'Финальная сумма'}${cfg.showDiscountBadge&&discountPct?`-${discountPct}% учтено`:''}
    ${breakdown}
    ${info}${actions}`; }else if(templateId==='midnight-glass'){ body=`${brand}
    ${esc(cfg.texts.proposalLabel)}

    ${esc(cfg.texts.menuTitle)} на ваше событие

    ${esc(eventName)}${identityLine?` · ${esc(identityLine)}`:''}

    ${esc(cfg.texts.heroNote)}

    Разнообразие блюдСвежие ингредиентыПремиальное качество
    ${sellingBlock}

    ${esc(cfg.texts.menuTitle)}

    ${items.map(row).join('')}
    ${cfg.showGallery?``:''}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}${g?`на гостя: ${money(menuPer)}`:'Финальная сумма'}${cfg.showDiscountBadge&&discountPct?`-${discountPct}% учтено`:''}
    ${breakdown}
    ${info}${actions}`; }else if(templateId==='midnight-compact'){ body=`${brand}
    ${esc(cfg.texts.proposalLabel)}

    ${esc(eventName)}

    ${identityLine?`

    ${esc(identityLine)}

    `:''}
    ${esc(cfg.texts.heroNote)}
    ${groups.map(groupTable).join('')}
    ${cfg.showGallery?``:''}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}${cfg.showDiscountBadge&&discountPct?`-${discountPct}%`:''}
    ${info}${breakdown}${actions}`; }else if(templateId==='black-gold'){ body=`${brand}
    ${esc(cfg.texts.proposalLabel)}

    Кейтеринг
    для вашего события

    ${esc(eventName)}${identityLine?`
    ${esc(identityLine)}`:''}

    ${esc(cfg.texts.menuTitle)} для вашего мероприятия
    ${items.map((item,i)=>`
    ${esc(item.name)}${String(i+1).padStart(2,'0')}×${Math.round(num(item.qty))}

    ${esc(item.name)}

    ${esc([weightLabel(item)].filter(Boolean).join(' · ')||sectionTitle(item))}

    ${compositionText(item,', ')?`${esc(compositionText(item,', '))}`:''}
    `).join('')}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${money(p.total)}${g?`на гостя: ${money(menuPer)}`:''}
    ${blackControl}
    ${blackExtras}${breakdown}${actions}`; }else if(templateId==='emerald-gold'){ body=`${brand}
    ${esc(cfg.texts.proposalLabel)}

    ${esc(eventName)}

    ${esc(cfg.texts.heroNote)}

    ${egFacts.length?`
    ${egFacts.map(x=>`${esc(x)}`).join('')}
    `:''}
    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}
    ${items[1]?``:''}
    ${sellingBlock}

    ${esc(cfg.texts.menuTitle)}

    ${items.map(row).join('')}
    ${egSide}
    ${breakdown}${actions}`; }else{ body=`${brand}
    ${visibleDate?`${esc(visibleDate)}`:''}

    ${esc(eventName)}

    ${esc(cfg.texts.heroNote)}

    ${visibleGuests?`${g}гостей`:''}

    ${esc(cfg.texts.proposalLabel)}

    Свежие ингредиентыАвторские рецептыКонтроль качества
    ${groups.map(groupTable).join('')}

    ${esc(cfg.texts.summaryTitle)}

    ${metrics}
    ${esc(cfg.texts.totalPriceTitle)}${money(p.total)}${cfg.showDiscountBadge&&discountPct?`-${discountPct}%`:''}
    ${info}${breakdown}${actions}`; } const finalGalleryItems=cfg.showFinalPhoto&&Array.isArray(s.finalGallery)?s.finalGallery.filter(Boolean).slice(0,2):[]; const finalPhoto=finalGalleryItems.length?``:''; return `Предложение клиенту
    ${body}${footerNote}${finalPhoto}
    Солнце Кейтеринг · Санкт-Петербург+7 (921) 954-04-40 · solnce-keytering.ru
    `; } let offerRenderSeq=0; let currentOffer={orderId:null,snapshot:null,prepared:null,pdfPrepared:null,pages:null,pdfBlob:null,pdfPromise:null,renderToken:0,preferDraft:false,transient:false,editTimer:null}; function renderOfferPages(pages){const host=$('sunClientOfferPreview');if(!host)return;host.innerHTML='';for(const page of (pages||[])){page.classList.add('sun-offer-page-canvas');page.setAttribute('aria-label','Страница предложения');host.appendChild(page)}} function offerRenderMessage(text='Обновляю предложение…'){const host=$('sunClientOfferPreview');if(host)host.innerHTML=`
    ${esc(text)}
    `} async function renderOffer(snapshot){ const renderToken=++offerRenderSeq;currentOffer.snapshot=snapshot;currentOffer.pdfBlob=null;currentOffer.pdfPromise=null;currentOffer.pages=null;offerRenderMessage();const pdfBtn=$('sunOfferPdf');if(pdfBtn){pdfBtn.disabled=true;pdfBtn.textContent='Готовлю просмотр…'} const prepared=await preparedSnapshot(snapshot);const explicitTemplate=String(snapshot?.offerTemplateId||prepared?.offerTemplateId||'').trim();prepared.offerTemplateId=OFFER_TEMPLATE_IDS.has(explicitTemplate)?explicitTemplate:offerTemplateId(); const pdfPrepared=await preparedPdfSnapshot(prepared),pages=await renderOfferPdfPages(pdfPrepared); if(renderToken!==offerRenderSeq)return null; currentOffer.snapshot=snapshot;currentOffer.prepared=prepared;currentOffer.pdfPrepared=pdfPrepared;currentOffer.pages=pages;currentOffer.renderToken=renderToken; renderOfferPages(pages);syncOfferEditor(); if(pdfBtn){pdfBtn.disabled=false;pdfBtn.textContent='Скачать PDF'} return pages; } function toggleOfferEditor(){const panel=$('sunOfferEditor'),btn=$('sunOfferEdit');if(!panel)return;const on=!panel.classList.contains('on');panel.classList.toggle('on',on);if(btn)btn.textContent=on?'Скрыть редактор':'Редактировать';if(on)syncOfferEditor()} function offerOverrideTextValue(key){const over=currentOffer.snapshot?.offerOverrides?.texts||{},cfg=offerSettings();return Object.prototype.hasOwnProperty.call(over,key)?String(over[key]??''):String(cfg.texts?.[key]??'')} function offerOverrideDataValue(key){const over=currentOffer.snapshot?.offerOverrides?.data||{},snap=currentOffer.snapshot||{};if(Object.prototype.hasOwnProperty.call(over,key))return over[key]??'';return key==='guests'?(snap.guests??''):(snap[key]??'')} function syncOfferEditor(){const panel=$('sunOfferEditor');if(!panel||!currentOffer.snapshot)return;panel.querySelectorAll('[data-offer-text]').forEach(el=>{if(document.activeElement!==el)el.value=offerOverrideTextValue(el.dataset.offerText)});panel.querySelectorAll('[data-offer-data]').forEach(el=>{if(document.activeElement!==el)el.value=offerOverrideDataValue(el.dataset.offerData)});panel.querySelectorAll('[data-offer-list="controlLines"]').forEach(el=>{if(document.activeElement!==el){const over=currentOffer.snapshot?.offerOverrides?.controlLines;const lines=Array.isArray(over)?over:offerSettings().controlLines;el.value=(lines||[]).join('\n')}})} function saveOfferOverrides(){if(!currentOffer.snapshot)return;currentOffer.snapshot.createdAt=new Date().toISOString();if(!currentOffer.transient&¤tOffer.orderId)persistSnapshot(currentOffer.orderId,currentOffer.snapshot);const meta=$('sunOfferMeta');if(meta)meta.textContent=`Изменено ${new Date(currentOffer.snapshot.createdAt).toLocaleString('ru-RU')}`} function scheduleOfferEditRender(){clearTimeout(currentOffer.editTimer);currentOffer.editTimer=setTimeout(()=>{if(currentOffer.snapshot)renderOffer(currentOffer.snapshot).catch(err=>{console.error(err);toast('Не удалось обновить предпросмотр.','error')})},500)} function bindOfferEditor(){const panel=$('sunOfferEditor');if(!panel||panel.dataset.bound)return;panel.dataset.bound='1';panel.addEventListener('input',e=>{const el=e.target.closest('[data-offer-text],[data-offer-data],[data-offer-list]');if(!el||!currentOffer.snapshot)return;currentOffer.snapshot.offerOverrides=currentOffer.snapshot.offerOverrides||{};if(el.dataset.offerText){currentOffer.snapshot.offerOverrides.texts=currentOffer.snapshot.offerOverrides.texts||{};currentOffer.snapshot.offerOverrides.texts[el.dataset.offerText]=el.value}else if(el.dataset.offerList==='controlLines'){currentOffer.snapshot.offerOverrides.controlLines=String(el.value||'').split(/\r?\n/).map(x=>x.trim()).filter(Boolean).slice(0,20)}else{currentOffer.snapshot.offerOverrides.data=currentOffer.snapshot.offerOverrides.data||{};currentOffer.snapshot.offerOverrides.data[el.dataset.offerData]=el.dataset.offerData==='guests'?Math.max(0,Number(el.value||0)):el.value}currentOffer.pdfBlob=null;currentOffer.pages=null;scheduleOfferEditRender()});panel.addEventListener('change',saveOfferOverrides);panel.addEventListener('focusout',e=>{if(e.target.matches?.('[data-offer-text],[data-offer-data],[data-offer-list]'))saveOfferOverrides()})} function setMeta(order,snapshot,{transient=false,autoRefreshed=false}={}){ const stale=snapshotIsStale(order,snapshot),notice=$('sunOfferStale'); if(notice){ notice.classList.toggle('on',Boolean(stale||transient)); notice.textContent=transient ?'В предложении учтены текущие изменения заказа. Сохраните заказ, чтобы закрепить их.' :(stale?'Заказ изменён. Предложение обновляется по актуальным данным…':''); } if($('sunOfferMeta'))$('sunOfferMeta').textContent=`Версия от ${new Date(snapshot.createdAt).toLocaleString('ru-RU')}${autoRefreshed?' · обновлено автоматически':''}`; } async function openOfferForOrder(orderId,{forceRefresh=false,preferDraft=false}={}){ ensureModal(); const saved=currentSavedOrder(orderId);if(!saved)return toast('Заказ не найден.','error'); const order=currentOfferSourceOrder(orderId,preferDraft)||saved; const draftDiff=order!==saved&&orderSignature(order)!==orderSignature(saved); let snapshot=saved.clientOfferSnapshot,autoRefreshed=false; const stale=snapshotIsStale(order,snapshot); if(stale||forceRefresh){ if(forceRefresh)toast('Обновляю предложение…'); snapshot=await createSnapshot(order);autoRefreshed=stale&&!forceRefresh; // Never freeze an unsaved draft into the saved order. Saved orders, however, // always receive the fresh snapshot so every template/PDF opens consistently. if(!draftDiff&&!persistSnapshot(saved.id,snapshot))return; } currentOffer={orderId:saved.id,snapshot,prepared:null,pdfPrepared:null,pages:null,pdfBlob:null,pdfPromise:null,renderToken:0,preferDraft:Boolean(preferDraft),transient:draftDiff,editTimer:null}; setMeta(order,snapshot,{transient:draftDiff,autoRefreshed}); window.modal?.('sunClientOfferModal');await renderOffer(snapshot); if(autoRefreshed)toast('Предложение автоматически обновлено по текущему заказу.'); } async function openCurrentDraftOffer(){ const d=getDraft();if(!d?.id)return alert('Сначала сохраните заказ. После сохранения появится предложение клиенту.'); const saved=currentSavedOrder(d.id);if(!saved)return alert('Сначала сохраните заказ.'); return openOfferForOrder(saved.id,{preferDraft:true}); } async function refreshCurrentOffer(){ if(!currentOffer.orderId)return; await openOfferForOrder(currentOffer.orderId,{forceRefresh:true,preferDraft:currentOffer.preferDraft}); toast('Предложение обновлено.'); } async function ensureCurrentOfferFresh(){ if(!currentOffer.orderId)return false; const saved=currentSavedOrder(currentOffer.orderId);if(!saved)return false; const order=currentOfferSourceOrder(currentOffer.orderId,currentOffer.preferDraft)||saved; if(!snapshotIsStale(order,currentOffer.snapshot))return true; await openOfferForOrder(currentOffer.orderId,{forceRefresh:true,preferDraft:currentOffer.preferDraft}); return true; } function filename(ext){const d=currentOffer.prepared?.date||currentOffer.snapshot?.date||'';return `predlozhenie-klientu${d?'-'+d:''}.${ext}`} function pdfRoundRect(ctx,x,y,w,h,r,fill,stroke){ const rr=Math.min(r,w/2,h/2);ctx.beginPath();ctx.moveTo(x+rr,y);ctx.arcTo(x+w,y,x+w,y+h,rr);ctx.arcTo(x+w,y+h,x,y+h,rr);ctx.arcTo(x,y+h,x,y,rr);ctx.arcTo(x,y,x+w,y,rr);ctx.closePath();if(fill){ctx.fillStyle=fill;ctx.fill()}if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=2;ctx.stroke()} } function pdfWrap(ctx,text,maxWidth){ const input=String(text||'').replace(/\s+/g,' ').trim();if(!input)return[]; const words=input.split(' '),lines=[];let line=''; const pushLong=word=>{let chunk='';for(const ch of word){const next=chunk+ch;if(ctx.measureText(next).width>maxWidth&&chunk){lines.push(chunk);chunk=ch}else chunk=next}return chunk}; for(const word of words){ if(ctx.measureText(word).width>maxWidth){if(line){lines.push(line);line=''}line=pushLong(word);continue} const test=line?`${line} ${word}`:word; if(ctx.measureText(test).width<=maxWidth)line=test;else{if(line)lines.push(line);line=word} } if(line)lines.push(line);return lines; } function pdfText(ctx,text,x,y,maxWidth,lineHeight,opts={}){ ctx.save();ctx.font=opts.font||'28px Arial';ctx.fillStyle=opts.color||'#1a1a1a';ctx.textAlign=opts.align||'left';ctx.textBaseline='top'; let lines=pdfWrap(ctx,text,maxWidth);const maxLines=Math.max(0,Number(opts.maxLines||0)); if(maxLines&&lines.length>maxLines){lines=lines.slice(0,maxLines);let last=lines[lines.length-1]||'';while(last&&ctx.measureText(last+'...').width>maxWidth)last=last.slice(0,-1);lines[lines.length-1]=last+'...'} const lh=Math.max(lineHeight||0,Math.ceil(parseFloat(String(ctx.font).match(/([0-9.]+)px/)?.[1]||16)*1.18)); lines.forEach((line,i)=>ctx.fillText(line,x,y+i*lh));ctx.restore();return lines.length*lh; } function pdfDrawCheck(ctx,x,y,r,fill,stroke){ctx.save();ctx.fillStyle=fill;ctx.beginPath();ctx.arc(x,y,r,0,Math.PI*2);ctx.fill();ctx.strokeStyle=stroke;ctx.lineWidth=Math.max(2,r*.22);ctx.lineCap='round';ctx.lineJoin='round';ctx.beginPath();ctx.moveTo(x-r*.45,y);ctx.lineTo(x-r*.1,y+r*.34);ctx.lineTo(x+r*.52,y-r*.38);ctx.stroke();ctx.restore()} function pdfLoadImage(src){return new Promise(resolve=>{const safe=isSafeRasterDataUrl(src)?String(src):'';if(!safe)return resolve(null);const img=new Image();let done=false;const finish=v=>{if(done)return;done=true;clearTimeout(timer);resolve(v)};const timer=setTimeout(()=>finish(null),4500);img.onload=()=>finish(img);img.onerror=()=>finish(null);img.src=safe})} function pdfDrawCover(ctx,img,x,y,w,h,r=24){ if(!img)return;const scale=Math.max(w/img.naturalWidth,h/img.naturalHeight),sw=w/scale,sh=h/scale,sx=(img.naturalWidth-sw)/2,sy=(img.naturalHeight-sh)/2; ctx.save();pdfRoundRect(ctx,x,y,w,h,r);ctx.clip();ctx.drawImage(img,sx,sy,sw,sh,x,y,w,h);ctx.restore(); } function pdfDrawContain(ctx,img,x,y,w,h){ if(!img)return;const scale=Math.min(w/img.naturalWidth,h/img.naturalHeight),dw=img.naturalWidth*scale,dh=img.naturalHeight*scale;ctx.drawImage(img,x+(w-dw)/2,y+(h-dh)/2,dw,dh); } const pdfFromJpegs=images=>window.SunPdfEngine.fromJpegs(images); function pdfCanvasJpeg(canvas){ return new Promise((resolve,reject)=>{ let done=false;const finish=(err,value)=>{if(done)return;done=true;clearTimeout(timer);err?reject(err):resolve(value)}; const fromDataUrl=()=>{try{const data=canvas.toDataURL('image/jpeg',0.94),base64=String(data).split(',')[1]||'';if(!base64)throw new Error('Пустое изображение страницы');const raw=atob(base64),bytes=new Uint8Array(raw.length);for(let i=0;i{if(done)return;if(!blob)return fromDataUrl();try{finish(null,{width:canvas.width,height:canvas.height,bytes:new Uint8Array(await blob.arrayBuffer())})}catch(err){fromDataUrl()}},'image/jpeg',0.94); }catch(_){fromDataUrl()} }) } function pdfThemeFor(id){ const themes={ light:{BG:'#ffffff',PANEL:'#ffffff',LINE:'#e7d8bd',TEXT:'#1d211d',MUTED:'#6f746e',GOLD:'#c99b47',GOLD2:'#e2c28b',GREEN:'#476f4d',GREEN_DEEP:'#28533a',GREEN_SOFT:'#f1f5ef',FOOT:'#ffffff'}, 'editorial-grid':{BG:'#fbfaf6',PANEL:'#fffefb',LINE:'#e8dfcf',TEXT:'#163127',MUTED:'#776f62',GOLD:'#b99355',GOLD2:'#d8c4a2',GREEN:'#245f46',GREEN_DEEP:'#1f5a42',GREEN_SOFT:'#e9f1eb',FOOT:'#fbfaf6'}, 'midnight-glass':{BG:'#061521',PANEL:'#0b2230',LINE:'#315263',TEXT:'#f4f1e8',MUTED:'#9aaeb8',GOLD:'#d4a64b',GOLD2:'#765f35',GREEN:'#24a98f',GREEN_DEEP:'#d7ad58',GREEN_SOFT:'#123d38',FOOT:'#04111b'}, 'midnight-compact':{BG:'#03131c',PANEL:'#0a1b25',LINE:'#3a4d57',TEXT:'#f4f3ef',MUTED:'#9daab1',GOLD:'#e0b751',GOLD2:'#5e5231',GREEN:'#62a868',GREEN_DEEP:'#f1c96c',GREEN_SOFT:'#264b37',FOOT:'#06141c'}, 'black-gold':{BG:'#0c0c0b',PANEL:'#151513',LINE:'#453d2e',TEXT:'#f2eee6',MUTED:'#aaa49b',GOLD:'#c99a3c',GOLD2:'#57451f',GREEN:'#b98a31',GREEN_DEEP:'#d2a650',GREEN_SOFT:'#342c1d',FOOT:'#090908'}, 'emerald-gold':{BG:'#061318',PANEL:'#0b2023',LINE:'#3b4f50',TEXT:'#f2efe7',MUTED:'#a7b0ae',GOLD:'#d7ac55',GOLD2:'#6a5930',GREEN:'#1c765d',GREEN_DEEP:'#d9b466',GREEN_SOFT:'#123b35',FOOT:'#07171a'}, 'neon-emerald':{BG:'#020e12',PANEL:'#06191d',LINE:'#277b4d',TEXT:'#effff5',MUTED:'#9cb3aa',GOLD:'#d0a841',GOLD2:'#665322',GREEN:'#39f07c',GREEN_DEEP:'#67ff91',GREEN_SOFT:'#0c3f27',FOOT:'#020b0e'} }; return themes[id]||themes.light; } async function renderOfferPdfPagesBase(s){ const id=s.offerTemplateId||offerTemplateId(),W=1000,H=1414,SCALE=1.6,M=52,T=pdfThemeFor(id),{BG,PANEL,LINE,TEXT,MUTED,GOLD,GOLD2,GREEN,GREEN_DEEP,GREEN_SOFT,FOOT}=T; const cfg=offerSettingsForSnapshot(s),items=s.items||[],imageMap=new Map(); for(const item of items)imageMap.set(item.id,await pdfLoadImage(item.photoData||s.logo||'')); const logo=await pdfLoadImage(s.logo||''); const finalGallery=cfg.showFinalPhoto?(await Promise.all((Array.isArray(s.finalGallery)?s.finalGallery:[]).map(pdfLoadImage))).filter(Boolean):[]; const heroImg=items.map(i=>imageMap.get(i.id)).find(Boolean)||finalGallery[0]||logo,p=s.pricing||{},g=num(s.guests),menuPer=perGuest(p.itemsTotal,g),boxCount=offerBoxCount(items),discountPct=p.base>0?Math.round((p.discount/p.base)*100):0; const primaryMetric=offerPrimaryMetric(s,cfg,g),visibleDate=cfg.showDate?dateText(s.date):'',visibleClient=cfg.showClientName?String(s.client||'').trim():'',visibleGuests=cfg.showGuests&&g?`${g} ${plural(g,'гость','гостя','гостей')}`:''; const identity=[visibleClient,visibleDate,visibleGuests].filter(Boolean).join(' · '),control=Array.isArray(cfg.controlLines)&&cfg.controlLines.length?cfg.controlLines:DELIVERY_CONTROL,extras=Array.isArray(cfg.extraServices)&&cfg.extraServices.length?cfg.extraServices:EXTRA_SERVICES.map(x=>x[0]); const canvases=[];let canvas,ctx,y;const bottom=H-78; function newPage(){canvas=document.createElement('canvas');canvas.width=Math.round(W*SCALE);canvas.height=Math.round(H*SCALE);ctx=canvas.getContext('2d',{alpha:false});ctx.setTransform(SCALE,0,0,SCALE,0,0);ctx.fillStyle=BG;ctx.fillRect(0,0,W,H);y=M;canvases.push(canvas);return ctx} function space(h){if(y+h>bottom)newPage()} function fitBlockHeight(natural,minHeight=natural,gap=0,softRatio=.84){ const h=Math.max(1,Number(natural||0)),minH=Math.min(h,Math.max(1,Number(minHeight||h))),available=Math.max(0,bottom-y-gap); if(h<=available)return h; if(available>=minH&&available>=h*softRatio)return available; newPage();return h; } function card(x,yy,w,h,r=20,fill=PANEL,stroke=LINE){pdfRoundRect(ctx,x,yy,w,h,r,fill,stroke)} function line(x1,yy1,x2,yy2,color=LINE,width=1){const snap=v=>width===1?Math.round(v)+.5:v;ctx.save();ctx.strokeStyle=color;ctx.lineWidth=width;ctx.beginPath();ctx.moveTo(snap(x1),snap(yy1));ctx.lineTo(snap(x2),snap(yy2));ctx.stroke();ctx.restore()} function wrapCount(text,width,font){ctx.save();ctx.font=font;const n=Math.max(1,pdfWrap(ctx,String(text||''),width).length);ctx.restore();return n} function wrappedLines(text,width,font){ctx.save();ctx.font=font;const out=pdfWrap(ctx,String(text||''),width);ctx.restore();return out} function drawWrappedLines(lines,x,yy,lineHeight,{font='12px Arial',color=TEXT,align='left'}={}){ctx.save();ctx.font=font;ctx.fillStyle=color;ctx.textAlign=align;ctx.textBaseline='top';lines.forEach((line,i)=>ctx.fillText(line,x,yy+i*lineHeight));ctx.restore()} function compositionTextPdf(item,sep=' · '){return offerComposition(item).join(sep)} function brandHeader(){space(82);if(logo)pdfDrawContain(ctx,logo,M,y,195,62);if(visibleDate)pdfText(ctx,visibleDate,W-M,y+24,300,24,{font:'14px Arial',color:MUTED,align:'right',maxLines:1});y+=78} function hero(){ const event=s.event||'Персональное предложение'; if(id==='black-gold'){ space(425);const h=405;card(M,y,W-2*M,h,24,'#0c0c0b',LINE);if(heroImg)pdfDrawCover(ctx,heroImg,M,y,W-2*M,h,24);const grad=ctx.createLinearGradient(M,y,M+650,y);grad.addColorStop(0,'rgba(0,0,0,.94)');grad.addColorStop(.68,'rgba(0,0,0,.48)');grad.addColorStop(1,'rgba(0,0,0,0)');ctx.save();pdfRoundRect(ctx,M,y,W-2*M,h,24);ctx.clip();ctx.fillStyle=grad;ctx.fillRect(M,y,W-2*M,h);ctx.restore();pdfText(ctx,cfg.texts.proposalLabel,M+34,y+36,430,22,{font:'700 12px Arial',color:GOLD,maxLines:1});pdfText(ctx,'Кейтеринг для вашего события',M+34,y+78,500,56,{font:'500 43px Georgia',color:'#ffffff',maxLines:3});pdfText(ctx,[event,identity].filter(Boolean).join(' · '),M+34,y+273,510,28,{font:'16px Arial',color:'#ded8cd',maxLines:3});y+=h+18;return; } if(id==='editorial-grid'){ const leftW=386,rightX=M+leftW,rightW=W-M-rightX,leftTextW=leftW-56,eventLines=wrappedLines(event,leftTextW,'500 34px Georgia'),noteLines=wrappedLines(cfg.texts.heroNote,leftTextW,'12px Arial'); const h=Math.max(350,94+eventLines.length*43+(visibleClient?31:0)+([visibleDate,visibleGuests].filter(Boolean).length?42:0)+Math.max(52,noteLines.length*19+18)); space(h+18);card(M,y,W-2*M,h,18,PANEL,LINE);if(heroImg)pdfDrawCover(ctx,heroImg,rightX+1,y+1,rightW-1,h-2,17); pdfText(ctx,cfg.texts.proposalLabel,M+26,y+26,leftTextW,20,{font:'700 11px Arial',color:GOLD,maxLines:2}); drawWrappedLines(eventLines,M+26,y+62,43,{font:'500 34px Georgia',color:TEXT});let ty=y+62+eventLines.length*43+12; if(visibleClient){pdfText(ctx,visibleClient,M+26,ty,leftTextW,25,{font:'500 17px Georgia',color:GREEN_DEEP,maxLines:1});ty+=31} const facts=[visibleDate,visibleGuests].filter(Boolean).join(' · ');if(facts){pdfText(ctx,facts,M+26,ty,leftTextW,22,{font:'12px Arial',color:TEXT,maxLines:2});ty+=38} line(M+26,ty,M+26+leftTextW,ty,GOLD2,1);ty+=15;if(noteLines.length)drawWrappedLines(noteLines,M+26,ty,19,{font:'12px Arial',color:MUTED}); y+=h+18;return; } if(id==='midnight-compact'){ const innerX=M+28,innerW=W-2*M-56,leftW=510,gap=28,rightX=innerX+leftW+gap,rightW=innerW-leftW-gap; const eventLines=wrapCount(event,leftW,'700 31px Arial'),noteLines=wrapCount(cfg.texts.heroNote,rightW,'15px Arial'),h=Math.max(228,138+Math.max(eventLines*42,noteLines*21));space(h+20);card(M,y,W-2*M,h,20,PANEL,LINE); pdfText(ctx,cfg.texts.proposalLabel,innerX,y+24,leftW,22,{font:'700 12px Arial',color:GOLD,maxLines:1}); pdfText(ctx,event,innerX,y+57,leftW,42,{font:'700 31px Arial',color:TEXT,maxLines:3}); line(rightX-gap/2,y+28,rightX-gap/2,y+h-28,LINE,1); pdfText(ctx,cfg.texts.heroNote,rightX,y+55,rightW,21,{font:'15px Arial',color:GREEN_DEEP,maxLines:7}); if(identity)pdfText(ctx,identity,innerX,y+h-39,leftW,23,{font:'13px Arial',color:MUTED,maxLines:1}); y+=h+18;return; } const left=id==='neon-emerald'?500:425,rightX=M+left,rightW=W-M-rightX,leftTextW=left-56; const eventFont=id==='neon-emerald'?'700 34px Arial':'500 38px Georgia',eventLH=48,noteFont='12px Arial',noteLH=20; const eventLines=wrappedLines(event,leftTextW,eventFont),noteLines=wrappedLines(cfg.texts.heroNote,leftTextW,noteFont); const identityRows=(visibleClient?31:0)+([visibleDate,visibleGuests].filter(Boolean).length?52:0); const textNeed=68+Math.max(1,eventLines.length)*eventLH+24+identityRows+(noteLines.length?Math.max(54,noteLines.length*noteLH+14):0)+22; const h=Math.max(id==='emerald-gold'?380:335,textNeed);space(h+20);card(M,y,W-2*M,h,24,PANEL,LINE);if(heroImg)pdfDrawCover(ctx,heroImg,rightX+1,y+1,rightW-1,h-2,22); pdfText(ctx,cfg.texts.proposalLabel,M+28,y+29,leftTextW,22,{font:'700 12px Arial',color:id==='neon-emerald'?GREEN:GOLD,maxLines:2}); drawWrappedLines(eventLines,M+28,y+68,eventLH,{font:eventFont,color:TEXT}); let ty=y+68+Math.max(1,eventLines.length)*eventLH+20;if(visibleClient){pdfText(ctx,visibleClient,M+28,ty,leftTextW,27,{font:'500 18px Georgia',color:GREEN_DEEP,maxLines:1});ty+=31} const facts=[visibleDate,visibleGuests].filter(Boolean).join(' · ');if(facts){pdfText(ctx,facts,M+28,ty,leftTextW,26,{font:'14px Arial',color:TEXT,maxLines:2});ty+=48} if(noteLines.length){line(M+28,ty-8,M+28+leftTextW,ty-8,GOLD2,1);drawWrappedLines(noteLines,M+28,ty+6,noteLH,{font:noteFont,color:MUTED})} y+=h+18; } function sellingBlock(){ const title=String(cfg.texts.salesTitle||'').trim(),body=String(cfg.texts.salesNote||'').trim();if(!title&&!body)return; const x=M,w=W-2*M,padX=30,titleFont='500 22px Georgia',bodyFont='14px Arial',titleLH=30,bodyLH=23,innerW=w-padX*2-12; let bodyLines=wrappedLines(body,innerW,bodyFont),first=true; do{ const titleLines=first&&title?wrappedLines(title,innerW,titleFont):[]; const headingH=titleLines.length?titleLines.length*titleLH+12:0; const minRows=Math.min(3,Math.max(1,bodyLines.length||1)); let minH=30+headingH+(bodyLines.length?minRows*bodyLH:0)+24; if(bottom-y{ const nameLines=Math.max(1,wrapCount(item.name,cw-32,'500 17px Georgia')); const meta=[weightLabel(item),compositionTextPdf(item,', ')].filter(Boolean).join(' · '); const metaLines=meta?Math.max(1,wrapCount(meta,cw-32,'10px Arial')):0; const minH=252+nameLines*24+(metaLines?8+metaLines*19:0)+18; return {item,nameLines,meta,metaLines,minH,h:Math.max(340,minH)}; }); const naturalRh=Math.max(...measured.map(v=>v.h),340),minRh=Math.max(...measured.map(v=>v.minH)),rh=fitBlockHeight(naturalRh,minRh,14,.88); measured.forEach((v,j)=>{ const {item,nameLines,meta,metaLines}=v,x=M+j*(cw+gap); card(x,y,cw,rh,16,PANEL,LINE);const img=imageMap.get(item.id)||logo;if(img)pdfDrawCover(ctx,img,x+1,y+1,cw-2,205,15); pdfText(ctx,String(i+j+1).padStart(2,'0'),x+12,y+12,38,20,{font:'700 11px Arial',color:GOLD,maxLines:1}); pdfText(ctx,`x${Math.round(num(item.qty))}`,x+cw-13,y+12,40,20,{font:'700 11px Arial',color:'#ffffff',align:'right',maxLines:1}); pdfText(ctx,item.name,x+16,y+222,cw-32,24,{font:'500 17px Georgia',color:TEXT,maxLines:nameLines}); if(meta)pdfText(ctx,meta,x+16,y+222+nameLines*24+8,cw-32,19,{font:'10px Arial',color:MUTED,maxLines:metaLines}); }); y+=rh+14 } return; } if(id==='editorial-grid'){ const groups=editorialGroups(items),gap=10,cw=(W-2*M-gap)/2; for(let i=0;i{ const x=M+j*(cw+gap);card(x,y,cw,rh,13,PANEL,LINE); ctx.save();ctx.fillStyle=GREEN_DEEP;ctx.beginPath();ctx.arc(x+31,y+39,20,0,Math.PI*2);ctx.fill();ctx.restore(); pdfText(ctx,String(i+j+1).padStart(2,'0'),x+31,y+30,30,18,{font:'700 10px Arial',color:'#ffffff',align:'center',maxLines:1}); pdfText(ctx,group.name,x+62,y+15,cw-150,24,{font:'500 16px Georgia',color:TEXT,maxLines:2}); if(group.meta)pdfText(ctx,group.meta,x+62,y+48,cw-150,18,{font:'10px Arial',color:GOLD,maxLines:1}); card(x+cw-68,y+24,48,28,14,PANEL,LINE);pdfText(ctx,`x${Math.round(group.qty)}`,x+cw-44,y+29,40,18,{font:'11px Arial',color:TEXT,align:'center',maxLines:1}); }); y+=rh+10; } if(cfg.showGallery)drawGallery(4,126,false);return; } if(id==='midnight-compact'){ const groups=offerGroups(items); for(const group of groups){ const titleLines=wrapCount(group.name,600,'700 16px Arial'),headerH=Math.max(45,18+titleLines*24);space(headerH+20); card(M,y,W-2*M,headerH,13,PANEL,LINE);pdfText(ctx,group.name,M+18,y+12,650,24,{font:'700 16px Arial',color:GREEN_DEEP,maxLines:titleLines});y+=headerH; for(const item of group.list){ const nameLines=Math.max(1,wrapCount(item.name,535,'14px Arial')); const comp=compositionTextPdf(item); const compLines=comp?Math.max(1,wrapCount(comp,535,'10px Arial')):0; const minH=28+nameLines*21+(compLines?5+compLines*17:0)+10,naturalH=Math.max(64,minH),h=fitBlockHeight(naturalH,minH,0,.88); line(M,y,W-M,y,LINE,1); pdfText(ctx,item.name,M+18,y+14,535,21,{font:'14px Arial',color:TEXT,maxLines:nameLines}); if(comp)pdfText(ctx,comp,M+18,y+14+nameLines*21+5,535,17,{font:'10px Arial',color:MUTED,maxLines:compLines}); pdfText(ctx,weightLabel(item)||item.weight||'—',M+588,y+14,188,36,{font:'11px Arial',color:MUTED,align:'center',maxLines:2}); pdfText(ctx,`x${Math.round(num(item.qty))}`,W-M-25,y+14,80,21,{font:'700 13px Arial',color:TEXT,align:'right',maxLines:1}); y+=h } y+=10 } if(cfg.showGallery)drawGallery(5,118,true);return; } if(id==='neon-emerald'){ const gap=12,cw=(W-2*M-gap)/2; for(let i=0;i{ const nameLines=Math.max(1,wrapCount(item.name,cw-202,'700 15px Arial')); const meta=[weightLabel(item),compositionTextPdf(item)].filter(Boolean).join(' · '); const metaLines=meta?Math.max(1,wrapCount(meta,cw-202,'10px Arial')):0; const minH=38+nameLines*22+(metaLines?6+metaLines*18:0)+20; return {item,nameLines,meta,metaLines,minH,h:Math.max(124,minH)}; }); const naturalRh=Math.max(...measured.map(v=>v.h)),minRh=Math.max(...measured.map(v=>v.minH)),rh=fitBlockHeight(naturalRh,minRh,12,.88); measured.forEach((v,j)=>{ const {item,nameLines,meta,metaLines}=v,x=M+j*(cw+gap);card(x,y,cw,rh,16,PANEL,LINE); const img=imageMap.get(item.id)||logo;if(img)pdfDrawCover(ctx,img,x+8,y+8,102,rh-16,12); pdfText(ctx,item.name,x+122,y+17,cw-202,22,{font:'700 15px Arial',color:TEXT,maxLines:nameLines}); if(meta)pdfText(ctx,meta,x+122,y+17+nameLines*22+6,cw-202,18,{font:'10px Arial',color:GREEN,maxLines:metaLines}); pdfText(ctx,`x${Math.round(num(item.qty))}`,x+cw-18,y+18,55,20,{font:'700 12px Arial',color:GREEN,align:'right',maxLines:1}); }); y+=rh+12 } return; } if(id==='emerald-gold'){ for(const item of items){ const nameLines=Math.max(1,wrapCount(item.name,W-2*M-220,'500 18px Georgia')); const meta=[weightLabel(item),compositionTextPdf(item)].filter(Boolean).join(' · '); const metaLines=meta?Math.max(1,wrapCount(meta,W-2*M-240,'10px Arial')):0; const minH=38+nameLines*27+(metaLines?8+metaLines*19:0)+20,naturalH=Math.max(130,minH),h=fitBlockHeight(naturalH,minH,10,.88); card(M,y,W-2*M,h,18,PANEL,LINE);const img=imageMap.get(item.id)||logo;if(img)pdfDrawCover(ctx,img,W-M-160,y+8,150,h-16,12); pdfText(ctx,item.name,M+22,y+18,W-2*M-220,27,{font:'500 18px Georgia',color:TEXT,maxLines:nameLines}); if(meta)pdfText(ctx,meta,M+22,y+18+nameLines*27+8,W-2*M-240,19,{font:'10px Arial',color:MUTED,maxLines:metaLines}); pdfText(ctx,`x${Math.round(num(item.qty))}`,W-M-176,y+18,58,22,{font:'700 12px Arial',color:GOLD,align:'right',maxLines:1});y+=h+10 } return; } const gap=14,cw=(W-2*M-gap)/2; for(let i=0;i{ const meta=[weightLabel(item),compositionTextPdf(item)].filter(Boolean).join(' · '); const nameLines=Math.max(1,wrapCount(item.name,cw-224,'500 18px Georgia')); const metaLines=meta?Math.max(1,wrapCount(meta,cw-230,'11px Arial')):0,minH=36+nameLines*27+(metaLines?8+metaLines*20:0); return {minH,h:Math.max(150,minH)}; }),naturalRh=Math.max(...measured.map(v=>v.h)),minRh=Math.max(...measured.map(v=>v.minH)),rh=fitBlockHeight(naturalRh,minRh,14,.88); row.forEach((item,j)=>itemCardLight(item,M+j*(cw+gap),y,cw,rh));y+=rh+14 } // PDF cards already contain the position photo; a second gallery duplicated the same images and created extra sparse pages. } function drawGallery(cols=6,h=120,boxesOnly=false){const galleryItems=boxesOnly?items.filter(i=>[0,5].includes(Number(i.categoryId))):items;if(!galleryItems.length)return;const gap=8,shown=Math.min(galleryItems.length,cols*2),rows=Math.ceil(shown/cols),natural=rows*h+(rows-1)*gap,minCell=Math.min(h,96),minTotal=rows*minCell+(rows-1)*gap,total=fitBlockHeight(natural,minTotal,20,.86),cellH=Math.max(minCell,(total-(rows-1)*gap)/rows),w=(W-2*M-gap*(cols-1))/cols;for(let i=0;i{const x=M+22+i*mw;pdfText(ctx,it[0],x+mw/2,metricsY,mw-20,34,{font:'500 23px Georgia',color:TEXT,align:'center',maxLines:1});pdfText(ctx,it[1],x+mw/2,metricsY+43,mw-20,38,{font:'10px Arial',color:MUTED,align:'center',maxLines:2});if(isum+Math.max(minRow,wrapCount(t,width,font)*lineH+9),0)} function drawControlCard(x,yy,w,h){card(x,yy,w,h,18,PANEL,LINE);const titleLines=wrapCount(cfg.texts.controlTitle,w-40,'500 18px Georgia');pdfText(ctx,cfg.texts.controlTitle,x+w/2,yy+20,w-40,27,{font:'500 18px Georgia',color:GREEN_DEEP,align:'center',maxLines:3});let cy=yy+34+titleLines*27;for(const t of control){const lines=wrapCount(t,w-78,'12px Arial'),rowH=Math.max(31,lines*20+9);pdfDrawCheck(ctx,x+29,cy+9,8,GREEN_SOFT,GREEN_DEEP);pdfText(ctx,t,x+48,cy,w-70,rowH,{font:'12px Arial',color:TEXT,maxLines:5});cy+=rowH}} function drawExtrasCard(x,yy,w,h){card(x,yy,w,h,18,PANEL,LINE);const titleLines=wrapCount(cfg.texts.extrasTitle,w-40,'500 18px Georgia');pdfText(ctx,cfg.texts.extrasTitle,x+w/2,yy+20,w-40,27,{font:'500 18px Georgia',color:GREEN_DEEP,align:'center',maxLines:3});let cy=yy+36+titleLines*27;for(const name of extras){const lines=wrapCount(name,w-70,'12px Arial'),rowH=Math.max(37,lines*20+9);ctx.save();ctx.fillStyle=GREEN_SOFT;ctx.beginPath();ctx.arc(x+31,cy+8,8,0,Math.PI*2);ctx.fill();ctx.restore();pdfText(ctx,'+',x+31,cy+1,16,16,{font:'700 11px Arial',color:GOLD,align:'center',maxLines:1});pdfText(ctx,name,x+50,cy,w-70,rowH,{font:'12px Arial',color:TEXT,maxLines:4});cy+=rowH}} function infoCards(){ if(!cfg.showControl&&!cfg.showExtras)return;const gap=14,count=(cfg.showControl?1:0)+(cfg.showExtras?1:0),cw=count===1?W-2*M:(W-2*M-gap)/2; const heights=[];if(cfg.showControl){const title=wrapCount(cfg.texts.controlTitle,cw-40,'500 18px Georgia');heights.push(50+title*27+measureListHeight(control,cw-78))}if(cfg.showExtras){const title=wrapCount(cfg.texts.extrasTitle,cw-40,'500 18px Georgia');heights.push(58+title*27+measureListHeight(extras,cw-70,'12px Arial',20,37))}const minH=Math.max(1,...heights),naturalH=Math.max(230,minH),h=fitBlockHeight(naturalH,minH,18,.9);let x=M;if(cfg.showControl){drawControlCard(x,y,cw,h);x+=cw+gap}if(cfg.showExtras)drawExtrasCard(x,y,cw,h);y+=h+18; } function footerNoteNaturalHeight(){if(!cfg.showFooterNote||!String(cfg.texts.footerNote||'').trim())return 0;const lines=wrapCount(cfg.texts.footerNote,W-2*M-34,'11px Arial');return Math.max(44,22+lines*18)+12} function pricing(){if(!cfg.showPriceBreakdown)return;const rows=[[cfg.texts.priceItemsLabel||'Стоимость позиций',p.base],...(p.manual?[[cfg.texts.discountLabel||'Скидка',-p.manual]]:[]),...(p.promo?[[`${cfg.texts.promoLabel||'Промокод'}${s.promoCode?' '+s.promoCode:''}`,-p.promo]]:[]),[cfg.texts.menuAfterDiscountLabel||'Меню после скидок',p.itemsTotal],[cfg.texts.deliveryLabel||'Доставка',p.delivery],[cfg.texts.totalLabel||'Итого',p.total]],title=cfg.texts.pricingTitle||'Расчёт стоимости',titleLines=wrapCount(title,420,'500 18px Georgia'),naturalH=48+titleLines*27+rows.length*31,minH=44+titleLines*27+rows.length*26,footerReserve=footerNoteNaturalHeight(); if(y+naturalH+16<=bottom&&footerReserve&&y+naturalH+16+footerReserve>bottom)newPage(); const h=fitBlockHeight(naturalH,minH,16,.88),rowStep=Math.max(26,Math.min(31,(h-44-titleLines*27)/Math.max(1,rows.length)));card(M,y,W-2*M,h,16,PANEL,LINE);pdfText(ctx,title,M+20,y+16,420,27,{font:'500 18px Georgia',color:GREEN_DEEP,maxLines:2});let yy=y+24+titleLines*27;for(const [label,val] of rows){const grand=label===(cfg.texts.totalLabel||'Итого');pdfText(ctx,label,M+20,yy,490,21,{font:grand?'700 13px Arial':'12px Arial',color:grand?GREEN_DEEP:MUTED,maxLines:1});pdfText(ctx,(val<0?'- ':'')+money(Math.abs(val)),W-M-20,yy,250,21,{font:grand?'700 14px Arial':'12px Arial',color:grand?GREEN_DEEP:TEXT,align:'right',maxLines:1});yy+=rowStep}y+=h+16} function footerNoteBlock(){if(!cfg.showFooterNote||!String(cfg.texts.footerNote||'').trim())return;const lines=wrapCount(cfg.texts.footerNote,W-2*M-34,'11px Arial'),naturalH=Math.max(44,22+lines*18),minH=Math.max(36,18+lines*16),h=fitBlockHeight(naturalH,minH,12,.82);card(M,y,W-2*M,h,12,PANEL,LINE);pdfText(ctx,cfg.texts.footerNote,W/2,y+Math.max(8,(h-lines*18)/2),W-2*M-34,18,{font:'11px Arial',color:MUTED,align:'center',maxLines:6});y+=h+12} function finalGalleryFill(){ if(!finalGallery.length)return; const title=cfg.texts.finalGalleryTitle||'Как это выглядит на вашем столе',gap=12; const titleLines=wrappedLines(title,W-2*M,'500 21px Georgia'),titleH=Math.max(36,titleLines.length*28+8); const free=Math.max(0,bottom-y),minPhotoH=92; // This block may consume only the whitespace already left on the current last page. // It never calls newPage() and never creates an extra page. if(free=205&&finalGallery.length>=2?2:1; if(count===1){const img=finalGallery[1]||finalGallery[0];if(img)pdfDrawCover(ctx,img,M,y,W-2*M,available,14)} else{const imgs=finalGallery.slice(0,2),cellW=(W-2*M-gap)/2;if(imgs[0])pdfDrawCover(ctx,imgs[0],M,y,cellW,available,14);if(imgs[1])pdfDrawCover(ctx,imgs[1],M+cellW+gap,y,cellW,available,14)} y=bottom; } newPage(); if(id==='editorial-grid'){brandHeader();hero();drawItems();summary();pricing();sellingBlock();infoCards();finalGalleryFill();footerNoteBlock();} else if(id==='midnight-glass'){brandHeader();hero();sellingBlock();summary();infoCards();drawItems();pricing();finalGalleryFill();footerNoteBlock();} else if(id==='emerald-gold'){brandHeader();hero();summary();sellingBlock();infoCards();pricing();drawItems();footerNoteBlock();finalGalleryFill();} else{brandHeader();hero();sellingBlock();drawItems();summary();infoCards();pricing();footerNoteBlock();finalGalleryFill();} canvases.forEach((c,i)=>{const x=c.getContext('2d');x.setTransform(SCALE,0,0,SCALE,0,0);x.save();x.fillStyle=FOOT;x.fillRect(0,H-52,W,52);x.strokeStyle=LINE;x.lineWidth=1;x.beginPath();x.moveTo(0,H-52.5);x.lineTo(W,H-52.5);x.stroke();pdfText(x,'Солнце Кейтеринг · Санкт-Петербург',M,H-36,620,22,{font:'12px Arial',color:MUTED,maxLines:1});pdfText(x,`${i+1} / ${canvases.length}`,W-M,H-36,100,22,{font:'12px Arial',color:MUTED,align:'right',maxLines:1});x.restore()}); return canvases; } async function renderOfferPdfPages(s){ const classic=window.SunClassicOfferPDFV1767; if(classic?.renderPages)return classic.renderPages(s,renderOfferPdfPagesBase); return renderOfferPdfPagesBase(s); } async function pdfBlobFromPages(canvases){const jpeg=[];for(const c of (canvases||[]))jpeg.push(await pdfCanvasJpeg(c));return pdfFromJpegs(jpeg)} async function buildOfferPdfBlob(s){return pdfBlobFromPages(await renderOfferPdfPages(s))} async function triggerPdfDownload(blob,name){ const isAppleTouch=/iP(?:ad|hone|od)/i.test(navigator.userAgent||'')||(navigator.platform==='MacIntel'&&Number(navigator.maxTouchPoints||0)>1); if(isAppleTouch&&typeof File==='function'&&navigator.share&&navigator.canShare){ try{const file=new File([blob],name,{type:'application/pdf'});if(navigator.canShare({files:[file]})){await navigator.share({files:[file],title:'Предложение клиенту'});return 'share'}}catch(err){if(err?.name==='AbortError')return 'cancel';console.warn('PDF share fallback:',err)} } const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;a.style.display='none';a.rel='noopener';document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),120000);return 'download'; } function withTimeout(promise,ms,label='Операция'){return Promise.race([promise,new Promise((_,reject)=>setTimeout(()=>reject(new Error(label+' превысила время ожидания')),ms))])} function prepareCurrentOfferPdf(prepared,renderToken=currentOffer.renderToken){ const btn=$('sunOfferPdf');if(btn){btn.disabled=true;btn.textContent='Готовлю PDF…'} let promise; const source=currentOffer.pages?.length?pdfBlobFromPages(currentOffer.pages):preparedPdfSnapshot(prepared).then(buildOfferPdfBlob); promise=withTimeout(source,60000,'Подготовка PDF').then(blob=>{if(currentOffer.renderToken===renderToken){currentOffer.pdfBlob=blob;if(btn){btn.disabled=false;btn.textContent='Скачать PDF'}}return blob}).catch(err=>{console.error(err);if(currentOffer.renderToken===renderToken){currentOffer.pdfBlob=null;if(btn){btn.disabled=false;btn.textContent='Скачать PDF'}}toast(`Не удалось подготовить PDF: ${err?.message||'неизвестная ошибка'}. Нажмите «Скачать PDF», чтобы повторить.`,'error');return null}).finally(()=>{if(currentOffer.pdfPromise===promise)currentOffer.pdfPromise=null});currentOffer.pdfPromise=promise;return promise; } async function downloadCurrentOfferPdf(){ if(!currentOffer.prepared&&!currentOffer.pdfBlob){toast('Сначала откройте предложение клиенту.','error');return} const btn=$('sunOfferPdf');if(btn){btn.disabled=true;btn.textContent='Готовлю PDF…'} try{ if(currentOffer.editTimer){clearTimeout(currentOffer.editTimer);currentOffer.editTimer=null;saveOfferOverrides();await renderOffer(currentOffer.snapshot)} else if(!currentOffer.pages?.length&¤tOffer.snapshot)await renderOffer(currentOffer.snapshot); await ensureCurrentOfferFresh(); let blob=currentOffer.pdfBlob; if(!blob&¤tOffer.pdfPromise)blob=await currentOffer.pdfPromise; if(!blob&¤tOffer.prepared)blob=await prepareCurrentOfferPdf(currentOffer.prepared); // One automatic retry after a failed background preparation. if(!blob&¤tOffer.prepared)blob=await prepareCurrentOfferPdf(currentOffer.prepared); if(!blob)throw new Error('PDF не удалось сформировать'); currentOffer.pdfBlob=blob; const mode=await triggerPdfDownload(blob,filename('pdf')); if(mode==='share')toast('PDF готов. Выберите «Сохранить в Файлы» или нужное приложение.'); else if(mode!=='cancel')toast('PDF скачивается.'); }catch(err){console.error(err);toast(`Не удалось скачать PDF: ${err?.message||'неизвестная ошибка'}. Попробуйте ещё раз.`,'error')} finally{if(btn){btn.disabled=false;btn.textContent='Скачать PDF'}} } function ensureButton(){ const actions=document.querySelector('#new .actions');if(!actions)return;let b=$('sunClientOfferButton');if(!b){b=document.createElement('button');b.id='sunClientOfferButton';b.type='button';b.className='outline';b.textContent='Предложение клиенту';b.onclick=openCurrentDraftOffer;const del=$('deleteOrderBtn');if(del)window.SunSafe.insertBefore(actions,b,del);else actions.appendChild(b);}const d=getDraft();b.title=d?.id?'Открыть клиентское предложение':'Сначала сохраните заказ'; } function patchOrderViewer(){qa('.sun-order-view-actions').forEach(actions=>{if(actions.querySelector('[data-sun-offer-id]'))return;const edit=actions.querySelector('[data-viewer-action="edit"]');const id=edit?.dataset?.id;if(!id)return;const b=document.createElement('button');b.className='outline';b.type='button';b.textContent='Предложение';b.dataset.sunOfferId=id;b.onclick=()=>openOfferForOrder(id);const spacer=actions.querySelector('.spacer');window.SunSafe.insertBefore(actions,b,spacer||null);});} async function catalogPhotoChanged(itemId){ if(!currentOffer.snapshot||!currentOffer.orderId)return; if(!$('sunClientOfferModal')?.classList.contains('on'))return; if(!currentOffer.snapshot.items?.some(item=>String(item.id)===String(itemId)))return; await renderOffer(currentOffer.snapshot); } const refreshOpenOffer=()=>{if(currentOffer.snapshot&¤tOffer.orderId)renderOffer(currentOffer.snapshot).catch(err=>console.warn('Offer refresh:',err))}; window.addEventListener('sunoffertemplatechange',refreshOpenOffer); window.addEventListener('sunclientoffersettingschange',refreshOpenOffer); window.sunOpenClientOffer=openOfferForOrder;window.sunOpenCurrentClientOffer=openCurrentDraftOffer;window.sunGetClientOfferPdfBlob=()=>currentOffer.pdfBlob;window.sunClientOfferDownload=downloadCurrentOfferPdf;window.sunClientOfferCatalogChanged=catalogPhotoChanged;window.sunClientOfferDebugHtml=offerHtml;window.sunClientOfferDebugPdf=async prepared=>buildOfferPdfBlob(await preparedPdfSnapshot(prepared));window.sunClientOfferDebugPdfPages=async prepared=>renderOfferPdfPages(await preparedPdfSnapshot(prepared));window.sunClientOfferDebugCreateSnapshot=createSnapshot;window.sunClientOfferDebugBoxCount=offerBoxCount; (()=>{let queued=false;const run=()=>{if(queued)return;queued=true;setTimeout(()=>{queued=false;ensureButton();patchOrderViewer();},50);};[$('new'),$('orders')].filter(Boolean).forEach(root=>new MutationObserver(run).observe(root,{childList:true,subtree:true}));})(); document.addEventListener('click',e=>{const b=e.target.closest('[data-sun-offer-id]');if(b){e.preventDefault();e.stopPropagation();openOfferForOrder(b.dataset.sunOfferId)}},true); ensureModal();ensureButton();patchOrderViewer();setTimeout(ensureButton,150);setTimeout(patchOrderViewer,300); })(); ; /* ===== MODULE: auto-offer.js ===== */ (function(){ 'use strict'; if(window.__sunAutoOfferV1)return;window.__sunAutoOfferV1=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const esc=window.SunSafe.escapeHTML; const money=v=>`${Math.round(Number(v||0)).toLocaleString('ru-RU')} \u20bd`; const txt={ gen:'\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435', title:'\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0443', hint:'\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0433\u043e\u0441\u0442\u0435\u0439. \u0411\u044e\u0434\u0436\u0435\u0442 \u0438 \u0432\u0435\u0441 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c.', guests:'\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0433\u043e\u0441\u0442\u0435\u0439', budget:'\u0411\u044e\u0434\u0436\u0435\u0442 \u043d\u0430 \u0433\u043e\u0441\u0442\u044f, \u20bd', weight:'\u0412\u0435\u0441 \u043d\u0430 \u0433\u043e\u0441\u0442\u044f, \u0433', optional:'\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e', close:'\u0417\u0430\u043a\u0440\u044b\u0442\u044c', regen:'\u041f\u0435\u0440\u0435\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c', apply:'\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043a \u0437\u0430\u043a\u0430\u0437\u0443', total:'\u041c\u0435\u043d\u044e',per:'\u041d\u0430 \u0433\u043e\u0441\u0442\u044f',weightPer:'\u0412\u0435\u0441 / \u0433\u043e\u0441\u0442\u044f',piecesPer:'\u0417\u0430\u043a\u0443\u0441\u043e\u043a / \u0433\u043e\u0441\u0442\u044f', empty:'\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0433\u043e\u0441\u0442\u0435\u0439 \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u00ab\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u00bb.', lowBudget:'\u0417\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u0431\u044e\u0434\u0436\u0435\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043d\u0438\u0437\u043a\u0438\u0439 \u0434\u043b\u044f \u043f\u043e\u0434\u0431\u043e\u0440\u0430 \u043c\u0435\u043d\u044e.', applied:'\u041f\u043e\u0434\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u043c\u0435\u043d\u044e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u0437\u0430\u043a\u0430\u0437. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0435\u0433\u043e \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u00ab\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c\u00bb.', noEvent:'\u2014 \u041d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u2014',custom:'\u0421\u0432\u043e\u0451\u2026',customPh:'\u041d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442' }; const toast=(m,t='success')=>{try{window.SunEnterprise?.toast?.(m,t)}catch(_){};}; const getBoxes=()=>{try{if(Array.isArray(boxes))return boxes}catch(_){}try{return JSON.parse(localStorage.getItem('sunBoxes')||'[]')}catch(_){return[]}}; const getOrders=()=>{try{if(Array.isArray(orders))return orders}catch(_){}try{return JSON.parse(localStorage.getItem('sunOrders')||'[]')}catch(_){return[]}}; const getDraft=()=>{try{return draft}catch(_){return null}}; const parseWeight=v=>{const s=String(v||'').toLowerCase().replace(/,/g,'.'),m=s.match(/(\d+(?:\.\d+)?)\s*(\u043a\u0433|kg|\u0433|g)(?:\s|$)/);if(!m)return 0;const n=Number(m[1]);return m[2]==='\u043a\u0433'||m[2]==='kg'?n*1000:n}; const guestMax=v=>{const a=String(v||'').match(/\d+/g)?.map(Number)||[];return a.length?Math.max(...a):0}; function portions(item){ const explicit=Math.max(0,Number(item?.pieces||0));if(explicit>0)return explicit; let sum=0; for(const x of item?.ingredients||[]){if(!Array.isArray(x))continue;const q=Math.max(0,Number(x[1]||0)),u=String(x[2]||'').toLowerCase();if(/\u0448\u0442|\u043f\u043e\u0440|\u043a\u0443\u0441/.test(u))sum+=q;} if(sum>=5)return sum; return Math.max(sum,guestMax(item?.guests),10); } function popularityMap(){ const stats=new Map();let maxOrders=0,maxQty=0; for(const o of getOrders()){ if(String(o?.status||'').toLowerCase()==='отменён')continue; const seen=new Set(); for(const l of o?.lines||[]){const id=String(l?.id??'');if(!id)continue;let st=stats.get(id);if(!st){st={orders:0,qty:0};stats.set(id,st)}st.qty+=Math.max(0,Number(l?.qty||0));if(!seen.has(id)){st.orders+=1;seen.add(id)}} } for(const st of stats.values()){maxOrders=Math.max(maxOrders,st.orders);maxQty=Math.max(maxQty,st.qty)} const out=new Map();for(const [id,st] of stats)out.set(id,(maxOrders?st.orders/maxOrders:0)*.78+(maxQty?st.qty/maxQty:0)*.22);return out; } function foodCandidates(){const pop=popularityMap();return getBoxes().filter(x=>Number(x?.category||0)===0&&x?.hidden!==true&&Number(x?.price||0)>0&&parseWeight(x?.weight)>0&&!/\u0433\u043e\u0442\u043e\u0432\u044b\u0435\s+\u043c\u0435\u043d\u044e/i.test(String(x?.catalogSection||''))).map(x=>({raw:x,id:String(x.id),name:String(x.name||''),section:String(x.catalogSection||'\u0411\u043e\u043a\u0441\u044b'),price:Number(x.price||0),grams:parseWeight(x.weight),portions:portions(x),photo:String(x.photo||'sun-logo.png'),popularity:Number(pop.get(String(x.id))||0)}));} function hashNoise(text,seed){let h=2166136261^(seed*2654435761);for(const c of String(text)){h^=c.charCodeAt(0);h=Math.imul(h,16777619)}return ((h>>>0)%10000)/10000;} function stateKey(s){return [...s.q.entries()].sort((a,b)=>a[0].localeCompare(b[0])).map(([id,q])=>id+':'+q).join('|')} function score(s,t,seed){ const pg=s.portions/t.targetPortions,pp=pg<1?(1-pg)*5:(pg-1)*1.15; let wp=0;if(t.targetWeight){const r=s.grams/t.targetWeight;wp=r<1?(1-r)*4:(r-1)*1.1;} let bp=0;if(t.budget){if(s.cost>t.budget)return 100+(s.cost-t.budget)/t.budget*20;bp=Math.max(0,(t.budget-s.cost)/t.budget)*.72}else bp=(s.cost/Math.max(1,t.guests*5000))*.04; const boxes=[...s.q.values()].reduce((a,b)=>a+b,0),unique=s.q.size,sections=s.sections.size; const minPositions=t.guests>=15?4:(t.guests>=8?3:2);const diversity=(boxes-unique)*.08+Math.max(0,Math.min(boxes,4)-sections)*.055-Math.min(sections,4)*.025+Math.max(0,minPositions-unique)*.24; const popularityBonus=boxes?Math.min(.22,(Number(s.popularity||0)/boxes)*.18):0; return pp+wp+bp+diversity-popularityBonus+hashNoise(stateKey(s),seed)*.012; } function generateMenu(t,seed){ const cand=foodCandidates();if(!cand.length)return null; const empty={q:new Map(),portions:0,grams:0,cost:0,sections:new Set(),popularity:0}; let beam=[empty],all=[empty]; const maxBoxes=Math.min(30,Math.max(4,Math.ceil(t.targetPortions/20)+4,t.targetWeight?Math.ceil(t.targetWeight/700)+4:0)); for(let step=0;step=4)continue; const cost=st.cost+c.price;if(t.budget&&cost>t.budget)continue; const q=new Map(st.q);q.set(c.id,old+1);const sections=new Set(st.sections);sections.add(c.section); const ns={q,portions:st.portions+c.portions,grams:st.grams+c.grams,cost,sections,popularity:Number(st.popularity||0)+Number(c.popularity||0)};const key=stateKey(ns),prev=map.get(key); if(!prev||score(ns,t,seed)score(a,t,seed)-score(b,t,seed)).slice(0,130);beam=next;all.push(...next.slice(0,60)); const best=next[0];if(best&&best.portions>=t.targetPortions*1.05&&(!t.targetWeight||best.grams>=t.targetWeight*1.03)&&step>=3)break; } const useful=all.filter(s=>s.q.size>0&&( !t.budget || s.cost<=t.budget));if(!useful.length)return null; const best=useful.sort((a,b)=>score(a,t,seed)-score(b,t,seed))[0]; const items=[...best.q.entries()].map(([id,qty])=>{const c=cand.find(x=>x.id===id);return {...c,qty,sum:c.price*qty,totalGrams:c.grams*qty,totalPortions:c.portions*qty}}).sort((a,b)=>a.section.localeCompare(b.section,'ru')||a.name.localeCompare(b.name,'ru')); return {...best,items}; } function ensureStyle(){if($('sun-auto-offer-style'))return;const st=document.createElement('style');st.id='sun-auto-offer-style';st.textContent=` #sunAutoOfferModal{z-index:100060}#sunAutoOfferModal .dialog{width:min(980px,calc(100vw - 28px));max-height:94vh;padding:0;overflow:auto;border-radius:18px;background:#f5f3fa}.sun-auto-head{position:sticky;top:0;z-index:3;display:flex;align-items:flex-start;gap:12px;padding:15px 17px;background:#fff;border-bottom:1px solid #e4e0ef}.sun-auto-head h2{margin:0;color:#241d45;font-size:20px}.sun-auto-head p{margin:4px 0 0;color:#7b748d;font-size:12px}.sun-auto-head .spacer{flex:1}.sun-auto-form{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;padding:16px 17px 5px}.sun-auto-form label{display:grid;gap:6px;color:#5d5670;font-size:11px;font-weight:800}.sun-auto-form small{font-weight:500;color:#9b94aa}.sun-auto-form input{width:100%;border:1px solid #d9d2e9;border-radius:11px;padding:10px 11px;background:#fff;color:#29243d}.sun-auto-generate{margin:10px 17px 2px}.sun-auto-result{padding:12px 17px 18px}.sun-auto-placeholder{padding:30px;text-align:center;border:1px dashed #cbc2df;border-radius:16px;color:#827a95;background:#fff}.sun-auto-summary{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px;margin-bottom:12px}.sun-auto-kpi{background:#241d45;color:#fff;border-radius:14px;padding:13px}.sun-auto-kpi small{display:block;color:#c9c2db;font-size:10px}.sun-auto-kpi b{display:block;margin-top:5px;font-size:18px}.sun-auto-warning{margin:0 0 12px;padding:10px 12px;border-radius:11px;background:#fff4d9;color:#77550c;font-size:12px}.sun-auto-items{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.sun-auto-item{display:grid;grid-template-columns:82px minmax(0,1fr);gap:10px;padding:9px;background:#fff;border:1px solid #e1dceb;border-radius:14px}.sun-auto-item img{width:82px;height:82px;object-fit:cover;border-radius:10px;background:#eeeaf7}.sun-auto-item h3{margin:2px 0 5px;color:#302a45;font-size:13px;line-height:1.25}.sun-auto-item p{margin:3px 0;color:#827b92;font-size:10px}.sun-auto-item b{color:#5b48a6}.sun-auto-foot{display:flex;justify-content:flex-end;gap:8px;padding:13px 17px;background:#fff;border-top:1px solid #e4e0ef;position:sticky;bottom:0}.sun-event-custom-input{display:none!important;margin-top:6px!important}.sun-event-custom-input.on{display:block!important}#sunOrderCards .sun-order-card.sun-has-prepayment .sun-order-card-date{background:linear-gradient(145deg,#238b57,#36ad72)!important;border-color:#238b57!important;box-shadow:0 5px 14px rgba(35,139,87,.24)!important} @media(max-width:700px){#sunAutoOfferModal{padding:0}#sunAutoOfferModal .dialog{width:100vw;height:100vh;max-height:none;border-radius:0}.sun-auto-form{grid-template-columns:1fr}.sun-auto-summary{grid-template-columns:1fr 1fr}.sun-auto-items{grid-template-columns:1fr}.sun-auto-head h2{font-size:17px}} `;document.head.appendChild(st)} let generationSeed=1,currentResult=null,currentTargets=null; function ensureModal(){if($('sunAutoOfferModal'))return;const m=document.createElement('div');m.className='modal';m.id='sunAutoOfferModal';m.innerHTML=`

    ${txt.title}

    ${txt.hint}

    ${txt.empty}
    `;document.body.appendChild(m);$('sunAutoClose').onclick=closeGenerator;$('sunAutoGenerate').onclick=()=>runGenerator(false);$('sunAutoRegen').onclick=()=>runGenerator(true);$('sunAutoApply').onclick=applyGenerated;} function openGenerator(){ensureStyle();ensureModal();const d=getDraft()||{},g=Number($('eventGuests')?.value||d.guestsCount||0);$('sunAutoGuests').value=g||'';$('sunAutoResult').innerHTML=`
    ${txt.empty}
    `;$('sunAutoFoot').style.display='none';currentResult=null;$('sunAutoOfferModal').classList.add('on');} function closeGenerator(){$('sunAutoOfferModal')?.classList.remove('on')} function runGenerator(regen){ const guests=Math.max(0,Math.round(Number($('sunAutoGuests')?.value||0))),perBudget=Math.max(0,Number($('sunAutoBudget')?.value||0)),perWeight=Math.max(0,Number($('sunAutoWeight')?.value||0)); if(!guests){toast(txt.guests,'warn');$('sunAutoGuests')?.focus();return} if(regen)generationSeed++;const targets={guests,targetPortions:guests*5,targetWeight:perWeight?guests*perWeight:0,budget:perBudget?guests*perBudget:0,perBudget,perWeight};const result=generateMenu(targets,generationSeed);currentTargets=targets;currentResult=result;renderGenerated(result,targets); } function renderGenerated(r,t){const root=$('sunAutoResult'),foot=$('sunAutoFoot');if(!r){root.innerHTML=`
    ${txt.lowBudget}
    `;foot.style.display='none';return} const pp=r.cost/t.guests,wp=r.grams/t.guests,pieces=r.portions/t.guests;const warns=[];if(r.portions
    ${txt.total}${money(r.cost)}
    ${txt.per}${money(pp)}
    ${txt.weightPer}${Math.round(wp).toLocaleString('ru-RU')} \u0433
    ${txt.piecesPer}${pieces.toFixed(1)}
    ${warns.length?`
    ${warns.join('
    ')}
    `:''}
    ${r.items.map(i=>`

    ${esc(i.name)}

    ${esc(i.section)} \u00b7 \u00d7${i.qty}

    ${money(i.sum)} \u00b7 ${Math.round(i.totalGrams).toLocaleString('ru-RU')} \u0433 \u00b7 ${Math.round(i.totalPortions)} \u043f\u043e\u0440\u0446.

    `).join('')}
    `;foot.style.display='flex';} function applyGenerated(){if(!currentResult||!currentTargets)return;const d=getDraft();if(!d)return;d.lines=currentResult.items.map(i=>({id:i.id,qty:i.qty}));d.guestsCount=currentTargets.guests;const g=$('eventGuests');if(g){g.value=currentTargets.guests;g.dispatchEvent(new Event('input',{bubbles:true}))}try{window.render?.();window.updateOrderSummary?.()}catch(_){}closeGenerator();toast(txt.applied,'success');} function ensureGeneratorButton(){const actions=document.querySelector('#new .actions');if(!actions)return;let b=$('sunAutoOfferButton');if(!b){b=document.createElement('button');b.id='sunAutoOfferButton';b.type='button';b.className='outline';b.textContent=txt.gen;b.onclick=openGenerator;const offer=$('sunClientOfferButton');if(offer)offer.insertAdjacentElement('afterend',b);else actions.appendChild(b)}} function decoratePaidCards(){const map=new Map(getOrders().map(o=>[String(o.id),o]));qa('#sunOrderCards .sun-order-card').forEach(card=>{const o=map.get(String(card.dataset.orderId||''));card.classList.toggle('sun-has-prepayment',Number(o?.prepayment||0)>0)})} function ensureEventOptions(){ const s=$('event');if(!s||s.tagName!=='SELECT')return;const keep=String(s.value||''); qa('option',s).filter(o=>(o.textContent||'').trim()==='Новое мероприятие'||o.dataset.sunCustom==='1').forEach(o=>o.remove()); $('sunEventCustomInput')?.remove(); let blank=qa('option',s).find(o=>o.dataset.sunBlank==='1'||o.value===''); if(!blank){blank=document.createElement('option');blank.value='';blank.textContent=txt.noEvent;blank.dataset.sunBlank='1';s.insertBefore(blank,s.firstChild)}else{blank.value='';if(blank.textContent!==txt.noEvent)blank.textContent=txt.noEvent;blank.dataset.sunBlank='1';if(s.firstElementChild!==blank)s.insertBefore(blank,s.firstChild)} const opts=qa('option',s);s.value=opts.some(o=>o.value===keep)?keep:''; if(s.dataset.sunPersistentEventBound!=='1'){s.dataset.sunPersistentEventBound='1';s.addEventListener('change',()=>{const d=getDraft();if(d)d.event=s.value||''})} } function syncEventFromDraft(){ensureEventOptions();const s=$('event'),d=getDraft();if(!s||!d)return;const value=String(d.event||'').trim();if(!value){s.value='';return}let opt=qa('option',s).find(o=>o.value===value);if(!opt){opt=document.createElement('option');opt.value=value;opt.textContent=value;opt.dataset.sunLegacy='1';s.appendChild(opt)}s.value=value;} function prepareEventForSave(){ensureEventOptions();const s=$('event'),d=getDraft();if(s&&d)d.event=s.value||'';} const oldSave=window.saveOrder;if(typeof oldSave==='function')window.saveOrder=function(...a){prepareEventForSave();const r=oldSave.apply(this,a);setTimeout(()=>{syncEventFromDraft();decoratePaidCards()},0);return r}; const oldOpen=window.openOrder;if(typeof oldOpen==='function')window.openOrder=function(...a){const r=oldOpen.apply(this,a);setTimeout(syncEventFromDraft,0);setTimeout(syncEventFromDraft,80);return r}; const oldReset=window.resetDraft;if(typeof oldReset==='function')window.resetDraft=function(...a){const r=oldReset.apply(this,a);setTimeout(syncEventFromDraft,0);return r}; ensureStyle();ensureModal();ensureGeneratorButton();ensureEventOptions();syncEventFromDraft();decoratePaidCards(); (()=>{let queued=false;const run=()=>{if(queued)return;queued=true;setTimeout(()=>{queued=false;ensureGeneratorButton();ensureEventOptions();decoratePaidCards();},50);};[$('new'),$('orders')].filter(Boolean).forEach(root=>new MutationObserver(run).observe(root,{childList:true,subtree:true}));})(); setTimeout(()=>{ensureGeneratorButton();syncEventFromDraft();decoratePaidCards()},180);setTimeout(()=>{ensureGeneratorButton();syncEventFromDraft();decoratePaidCards()},700); })(); ; /* ===== MODULE: mobile-pwa.js ===== */ /* Solnce Catering classic PWA/sync layer - keeps the original application UI */ (()=>{ 'use strict'; if(window.__sunClassicPwaV1)return; window.__sunClassicPwaV1=true; const q=(s,r=document)=>r.querySelector(s); const qa=(s,r=document)=>[...r.querySelectorAll(s)]; const esc=window.SunSafe.escapeHTML; /* PWA only. No alternate mobile chrome or mobile home is created here. */ function initPwa(){ if('serviceWorker' in navigator && /^https?:$/.test(location.protocol)){ navigator.serviceWorker.register('./service-worker.js').then(reg=>reg.update()).catch(()=>{}); } } /* Cross-device sync. This is deliberately UI-neutral. */ const SYNC_META='sunCloudSyncMetaV1'; const SYNC_TOKEN='sunCloudSyncTokenV1'; const SYNC_WORKSPACE='sunCloudSyncWorkspaceV1'; const sync={busy:false,status:'local',timer:null,lastError:''}; const excludedKey=k=>k===SYNC_META||k===SYNC_TOKEN||k===SYNC_WORKSPACE||k.startsWith('sunCloudSyncTransient'); function hash(s){ s=String(s??''); let h=2166136261; for(let i=0;i>>0).toString(16); } function getMeta(){try{return JSON.parse(localStorage.getItem(SYNC_META)||'{}')||{}}catch(_){return{}}} function setMeta(m){localStorage.setItem(SYNC_META,JSON.stringify(m))} function syncWorkspace(){return localStorage.getItem(SYNC_WORKSPACE)||'main'} function syncHeaders(){return {'Content-Type':'application/json','X-Sun-Token':localStorage.getItem(SYNC_TOKEN)||''}} function captureSyncQuery(){ try{ const u=new URL(location.href); const token=u.searchParams.get('syncToken'); const workspace=u.searchParams.get('workspace'); let changed=false; if(token){localStorage.setItem(SYNC_TOKEN,token);u.searchParams.delete('syncToken');changed=true} if(workspace){localStorage.setItem(SYNC_WORKSPACE,workspace);u.searchParams.delete('workspace');changed=true} if(changed)history.replaceState(null,'',u.pathname+u.search+u.hash); }catch(_){ } } function setSyncStatus(status,msg=''){ sync.status=status; sync.lastError=msg; const statusEl=q('#sunSyncSettingsStatus'); if(statusEl){ statusEl.textContent=status==='ok'?'Синхронизация активна':status==='error'?`Ошибка: ${msg||'нет связи'}`:'Локальный режим'; } } async function pullRemote(){ const token=localStorage.getItem(SYNC_TOKEN); if(!token||!/^https?:$/.test(location.protocol))return {entries:{}}; const r=await fetch(`/api/sync?workspace=${encodeURIComponent(syncWorkspace())}`,{headers:syncHeaders(),cache:'no-store'}); if(!r.ok)throw new Error(`HTTP ${r.status}`); return r.json(); } function scanLocalChanges(meta,force=false){ const changes={}; const now=Date.now(); for(let i=0;iv.id)||null} function refreshActiveView(){ const active=document.activeElement; const editing=active&&/^(INPUT|TEXTAREA|SELECT)$/.test(active.tagName); if(editing||qa('.modal.on').length)return; const view=activeView(); if(!view)return; const map={orders:'Заказы',calendar:'Календарь',shopping:'Закупки',stock:'Склад',clients:'Клиенты',mailings:'Рассылки',money:'Деньги',team:'Команда',suppliers:'Поставщики',stats:'Статистика','sun-print-center':'Печать','sun-routes-view':'Маршруты','enterprise-settings':'Настройки'}; const label=map[view.id]; if(!label)return; const button=qa('header nav button').find(b=>String(b.textContent||'').trim()===label||String(b.textContent||'').trim()===(label==='Закупки'?'Закупка':label)); if(button){try{HTMLElement.prototype.click.call(button)}catch(_){}} } async function syncNow(){ if(sync.busy)return; const token=localStorage.getItem(SYNC_TOKEN); if(!token||!/^https?:$/.test(location.protocol)){setSyncStatus('local');ensureSyncSettings();return} sync.busy=true; try{ const meta=getMeta(); const remote=await pullRemote(); let remoteChanged=false; const entries=remote.entries||{}; Object.entries(entries).forEach(([key,item])=>{ if(excludedKey(key)||!item)return; const rt=Number(item.updatedAt||0),lt=Number(meta[key]?.t||0); if(rt>lt){ localStorage.setItem(key,String(item.value??'')); meta[key]={h:hash(item.value??''),t:rt}; remoteChanged=true; } }); const changes=scanLocalChanges(meta,Object.keys(entries).length===0); setMeta(meta); await pushChanges(changes); setSyncStatus('ok'); ensureSyncSettings(); if(remoteChanged){ window.dispatchEvent(new CustomEvent('suncloudsync',{detail:{remoteChanged:true}})); refreshActiveView(); } }catch(e){ setSyncStatus('error',e?.message||'нет связи'); ensureSyncSettings(); }finally{sync.busy=false} } window.sunSyncNow=syncNow; function ensureSyncSettings(){ const settings=q('#enterprise-settings'); if(!settings||q('#sunSyncSettingsCard'))return; const card=document.createElement('section'); card.id='sunSyncSettingsCard'; card.className='settings-card'; card.style.cssText='margin-top:14px;border:1px solid #e2e4e9;border-radius:12px;background:#fff;padding:14px'; const token=localStorage.getItem(SYNC_TOKEN)||''; card.innerHTML=`

    Синхронизация устройств

    Одна база для компьютера и телефона. Интерфейс приложения остаётся одинаковым на всех устройствах.

    ${token?'Подключение…':'Локальный режим'}

    ${token?'':'

    Чтобы включить общую базу, запускайте приложение через server.js и открывайте на телефоне ссылку сервера.

    '}`; const audit=[...settings.children].find(el=>(el.querySelector?.(':scope > h2')?.textContent||'').trim()==='История изменений'); if(audit)window.SunSafe.insertBefore(settings,card,audit);else settings.appendChild(card); q('#sunSyncWorkspaceInput',card)?.addEventListener('change',e=>{localStorage.setItem(SYNC_WORKSPACE,String(e.target.value||'main').trim()||'main');syncNow()}); const now=q('#sunSyncNowBtn',card);if(now)now.onclick=()=>syncNow(); const forget=q('#sunSyncForgetBtn',card);if(forget)forget.onclick=()=>{if(confirm('Отключить синхронизацию на этом устройстве? Локальные данные останутся.')){localStorage.removeItem(SYNC_TOKEN);setSyncStatus('local');card.remove();ensureSyncSettings()}}; setSyncStatus(sync.status,sync.lastError); } function initSync(){ // Legacy same-Wi-Fi server sync is intentionally disabled in Cloud v2 builds. // Supabase synchronization is handled by cloud-sync-v2.js. setSyncStatus('local'); } function init(){ initPwa(); initSync(); document.documentElement.classList.add('sun-classic-mobile-ready'); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init,{once:true});else init(); })(); ; /* ===== MODULE: batch-update.js ===== */ (function(){ 'use strict'; if(window.__sunBatchUpdate20260828)return;window.__sunBatchUpdate20260828=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const orderList=()=>{try{if(typeof orders!=='undefined'&&Array.isArray(orders))return orders}catch(_){}try{return JSON.parse(localStorage.getItem('sunOrders')||'[]')}catch(_){return[]}}; const localToday=()=>{const d=new Date();return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`}; const dateKey=o=>/^\d{4}-\d{2}-\d{2}$/.test(String(o?.date||''))?String(o.date):''; const timeKey=o=>/^\d{2}:\d{2}$/.test(String(o?.time||''))?String(o.time):'23:59'; let ordersMode='current'; function splitOrders(all){ const today=localToday(); const current=[],done=[]; all.forEach(o=>{const d=dateKey(o);(d&&d{const ad=dateKey(a)||'9999-12-31',bd=dateKey(b)||'9999-12-31';return (ad+timeKey(a)).localeCompare(bd+timeKey(b))||Number(a.id||0)-Number(b.id||0)}); done.sort((a,b)=>{const ad=dateKey(a)||'0000-00-00',bd=dateKey(b)||'0000-00-00';return (bd+timeKey(b)).localeCompare(ad+timeKey(a))||Number(b.id||0)-Number(a.id||0)}); return {current,done}; } function ensureOrdersTabs(){ const view=$('orders');if(!view)return; let bar=$('sunOrdersPeriodTabs'); if(!bar){bar=document.createElement('div');bar.id='sunOrdersPeriodTabs';bar.className='sun-orders-period-tabs';bar.innerHTML='';const anchor=view.querySelector('.sun-orders-viewbar')||view.querySelector('.head')||view.firstElementChild?.nextSibling;const h=view.querySelector('h1');if(h)h.insertAdjacentElement('afterend',bar);else view.prepend(bar);bar.addEventListener('click',e=>{const b=e.target.closest('[data-orders-period]');if(!b)return;ordersMode=b.dataset.ordersPeriod==='done'?'done':'current';window.renderOrders?.();});} const split=splitOrders(orderList()); qa('[data-orders-period]',bar).forEach(b=>{const key=b.dataset.ordersPeriod;b.classList.toggle('on',key===ordersMode);const text=key==='current'?`Текущие · ${split.current.length}`:`Завершённые · ${split.done.length}`;if(b.textContent!==text)b.textContent=text}); } const previousRenderOrders=window.renderOrders; if(typeof previousRenderOrders==='function')window.renderOrders=function(...args){ ensureOrdersTabs(); let ref=null,backup=null; try{if(typeof orders!=='undefined'&&Array.isArray(orders)){ref=orders;backup=orders.slice();const split=splitOrders(backup),show=ordersMode==='done'?split.done:split.current;orders.length=0;orders.push(...show)}}catch(_){} let result; try{result=previousRenderOrders.apply(this,args)}finally{if(ref&&backup){ref.length=0;ref.push(...backup)}} setTimeout(()=>{ensureOrdersTabs();compactSettingsLists();setDeliverySteps()},0); return result; }; let backupExpanded=false,auditExpanded=false; function compactList(host,rowSelector,kind){ if(!host)return;const rows=qa(rowSelector,host);const expanded=kind==='backup'?backupExpanded:auditExpanded; rows.forEach((r,i)=>{r.style.display=(expanded||i<4)?'':'none'}); let b=host.querySelector(':scope > .sun-compact-toggle'); if(rows.length<=4){b?.remove();return} if(!b){b=document.createElement('button');b.type='button';b.className='outline sun-compact-toggle';b.onclick=()=>{if(kind==='backup')backupExpanded=!backupExpanded;else auditExpanded=!auditExpanded;compactSettingsLists()};host.appendChild(b)} const text=expanded?'Скрыть':`Показать ещё (${rows.length-4})`;if(b.textContent!==text)b.textContent=text; } function compactSettingsLists(){compactList($('backupList'),'.backup-row','backup');compactList($('auditList'),'.audit-row','audit')} function setDeliverySteps(){ const delivery=$('deliveryCost');if(delivery)delivery.step='100'; const transport=$('orderDeliveryCost');if(transport)transport.step='100'; } function ensureCss(){if($('sun-batch-update-style'))return;const st=document.createElement('style');st.id='sun-batch-update-style';st.textContent=` .sun-orders-period-tabs{display:flex;gap:7px;align-items:center;margin:10px 0 13px;padding:4px;width:max-content;max-width:100%;border-radius:12px;background:#f1eff8;border:1px solid #e1dced}.sun-orders-period-tabs button{border:0;background:transparent;color:#716a84;border-radius:9px;padding:7px 12px;font-size:11px;font-weight:800;cursor:pointer}.sun-orders-period-tabs button.on{background:#241d45;color:#fff;box-shadow:0 4px 12px rgba(36,29,69,.18)}.sun-compact-toggle{margin-top:9px!important}.sun-extra-services-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:8px}.sun-extra-service{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;border:1px solid #d9d2e9;border-radius:14px;background:#fff;color:#4e4961}.sun-extra-service:before{content:'✓';display:grid;place-items:center;flex:0 0 24px;height:24px;border-radius:8px;background:#241d45;color:#f2c85f;font-weight:900}.sun-extra-service b{display:block;color:#241d45;font-size:14px}.sun-extra-service small{display:block;color:#817a94;margin-top:2px;line-height:1.3}@media(max-width:620px){.sun-orders-period-tabs{width:100%}.sun-orders-period-tabs button{flex:1}.sun-extra-services-grid{grid-template-columns:1fr}} `;document.head.appendChild(st)} function maintain(){ensureCss();ensureOrdersTabs();compactSettingsLists();setDeliverySteps()} (()=>{let queued=false;const run=()=>{if(queued)return;queued=true;setTimeout(()=>{queued=false;maintain();},60);};[$('new'),$('orders'),$('enterprise-settings')].filter(Boolean).forEach(root=>new MutationObserver(run).observe(root,{childList:true,subtree:true}));})(); document.addEventListener('click',e=>{const nav=e.target.closest('header nav button');if(nav&&String(nav.dataset.navLabel||nav.textContent||'').trim()==='Настройки')setTimeout(compactSettingsLists,80)},true); maintain();setTimeout(maintain,200);setTimeout(maintain,900); })(); ; /* ===== MODULE: cloud-sync-v2.js ===== */ (() => { 'use strict'; if (window.SunCloudV2) return; const VERSION = '2026.09.05-cloud-rbac-v7-developer-support'; const CONFIG_KEY = 'sunCloudV2Config'; const CLIENT_ID_KEY = 'sunCloudClientIdV2'; const DB_NAME = 'SunCloudV2'; const DB_VERSION = 1; const BUCKET = 'sun-media'; const SUPABASE_JS = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.112.4'; const MEDIA_PREFIX = '__sun_media__:'; const SYNC_DEBOUNCE = 1800; const $ = id => document.getElementById(id); const esc=window.SunSafe.escapeHTML; const clone = value => value == null ? value : (typeof structuredClone === 'function' ? structuredClone(value) : JSON.parse(JSON.stringify(value))); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); const toast = (text, type='info', timeout=4500) => { try { if (window.SunEnterprise?.toast) return window.SunEnterprise.toast(text, type, timeout); } catch (_) {} console[type === 'error' ? 'error' : 'log']('[SunCloud]', text); }; const DEFAULT_SUPABASE_URL = 'https://cksuehzcimitsxmeloes.supabase.co'; const DEFAULT_SUPABASE_KEY = 'sb_publishable_v8Z3hEBnu7zsDwAb5KCWcg_T96IejsM'; let config = loadConfig(); let client = null; let clientSignature = ''; let session = null; let memberships = []; let workspace = null; let supportMode = null; let membershipsLoading = false; let membershipsLoaded = false; let realtimeChannel = null; let syncTimer = null; let isSyncing = false; let dirty = false; const CLOUD_RPC_TIMEOUT_MS=12000; const CLOUD_CONFLICT_MAX_RETRIES=4; async function sunCloudAwait(promise,label='Облачный запрос',timeout=CLOUD_RPC_TIMEOUT_MS){ let timer=0; try{return await Promise.race([Promise.resolve(promise),new Promise((_,reject)=>{timer=setTimeout(()=>reject(new Error(label+': превышено время ожидания ('+Math.round(timeout/1000)+' сек.)')),timeout)})]);} finally{if(timer)clearTimeout(timer)} } let suppressStorageTracking = false; let observedSignature = ''; let lastStatus = 'local'; let lastError = ''; function loadConfig() { let value = {}; try { value = JSON.parse(localStorage.getItem(CONFIG_KEY) || '{}') || {}; } catch (_) {} if (!value.url || !value.key) { try { const legacy = JSON.parse(localStorage.getItem('sunEnterpriseSettingsV1') || '{}') || {}; const cloud = legacy.cloud || {}; value.url ||= String(cloud.supabaseUrl || '').trim(); value.key ||= String(cloud.anonKey || '').trim(); } catch (_) {} } return { url: String(value.url || DEFAULT_SUPABASE_URL || '').trim().replace(/\/$/, ''), key: String(value.key || DEFAULT_SUPABASE_KEY || '').trim(), autoSync: value.autoSync !== false, workspaceId: String(value.workspaceId || ''), migrated: value.migrated && typeof value.migrated === 'object' ? value.migrated : {}, lastSync: String(value.lastSync || ''), localWorkspaceId: String(value.localWorkspaceId || ''), tenantStorageReady: value.tenantStorageReady === true, legacyLocalWorkspaceId: String(value.legacyLocalWorkspaceId || (value.tenantStorageReady === true ? '' : (value.workspaceId || ''))) }; } function saveConfig() { localStorage.setItem(CONFIG_KEY, JSON.stringify(config)); } function disableLegacyCloud() { try { const raw = localStorage.getItem('sunEnterpriseSettingsV1'); if (!raw) return; const data = JSON.parse(raw); if (!data || typeof data !== 'object') return; data.cloud = Object.assign({}, data.cloud || {}, {enabled:false, autoSync:false, lastSync:data.cloud?.lastSync || ''}); localStorage.setItem('sunEnterpriseSettingsV1', JSON.stringify(data)); } catch (_) {} } function clientId() { let id = localStorage.getItem(CLIENT_ID_KEY); if (!id) { id = crypto.randomUUID ? crypto.randomUUID() : `client-${Date.now()}-${Math.random().toString(36).slice(2)}`; localStorage.setItem(CLIENT_ID_KEY, id); } return id; } function workspaceMigrated() { return Boolean(workspace?.id && config.migrated?.[workspace.id]); } const ROLE_LABELS = {admin:'Администратор',manager:'Менеджер',kitchen:'Кухня',courier:'Курьер',viewer:'Только просмотр'}; function hasPermission(permission) { if (!workspace || workspace.is_active === false) return false; const value=workspace.permissions?.[permission]; if (typeof value === 'boolean') return value; return workspace.role === 'admin'; } function canWrite() { if (supportMode) return false; if (!workspace || workspace.is_active === false) return false; const permissions=workspace.permissions || {}; const entries=Object.entries(permissions); if (entries.length) return entries.some(([key,value]) => value === true && (key.endsWith('.edit') || key.endsWith('.create') || key.endsWith('.delete') || key === 'users.manage' || key === 'backups.manage')); return workspace.role === 'admin'; } function roleLabel(role) { return ROLE_LABELS[role] || role || '—'; } function shouldSyncKey(key) { key = String(key || ''); if (!key.startsWith('sun')) return false; if (key === CONFIG_KEY || key === CLIENT_ID_KEY) return false; if (key === 'sunUsersV1' || key === 'sunSessionUserV1') return false; if (key === 'sunFallbackBackupsV1') return false; if (key === 'sunStaticMapGeocodeCacheV2') return false; if (key === 'sunCloudSyncMetaV1' || key === 'sunCloudSyncTokenV1' || key === 'sunCloudSyncWorkspaceV1') return false; if (key === 'sunOrdersView' || key === 'sunCalendarMode' || key === 'sunCatalogViewModeV1' || key === 'sunNewOrderSplitRatioV5') return false; if (key.startsWith('sunRecoveryCorrupt.')) return false; return true; } function sanitizeEnterpriseSettings(raw) { try { const data = JSON.parse(raw); if (!data || typeof data !== 'object') return raw; data.rolesEnabled = false; if (data.cloud) data.cloud = {enabled:false,supabaseUrl:'',anonKey:'',workspaceId:'',autoSync:false,lastSync:''}; return JSON.stringify(data); } catch (_) { return raw; } } function openDb() { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onupgradeneeded = () => { const db = request.result; if (!db.objectStoreNames.contains('meta')) db.createObjectStore('meta', {keyPath:'key'}); if (!db.objectStoreNames.contains('media')) db.createObjectStore('media', {keyPath:'path'}); }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async function idbGet(store, key) { try { const db = await openDb(); return await new Promise((resolve, reject) => { const request = db.transaction(store, 'readonly').objectStore(store).get(key); request.onsuccess = () => resolve(request.result || null); request.onerror = () => reject(request.error); }); } catch (_) { return null; } } async function idbPut(store, value) { try { const db = await openDb(); await new Promise((resolve, reject) => { const tx = db.transaction(store, 'readwrite'); tx.objectStore(store).put(value); tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); tx.onabort = () => reject(tx.error || new Error('IndexedDB transaction aborted')); }); return true; } catch (_) { return false; } } // Keep the browser working copy isolated by cloud workspace. The live app still // reads the historical unprefixed sun* keys, so before changing workspace we // snapshot those keys to IndexedDB, clear them, and restore only the target // workspace. This prevents orders/clients/finance/etc. from leaking between // accounts while avoiding a second large copy inside localStorage. function isTenantLocalKey(key) { key=String(key||''); if(!key.startsWith('sun'))return false; if(key===CONFIG_KEY||key===CLIENT_ID_KEY)return false; if(key.startsWith('sunCloud'))return false; if(key==='sunStaticMapGeocodeCacheV2')return false; return true; } function tenantLocalKeys() { const out=[]; for(let i=0;ilocalStorage.removeItem(key)); } async function restoreTenantLocal(workspaceId) { const id=String(workspaceId||'').trim(); if(!id)return false; const row=await idbGet('meta',`tenant-local:${id}`),storage=row?.value?.storage; if(!storage||typeof storage!=='object')return false; for(const [key,value] of Object.entries(storage)){ if(isTenantLocalKey(key))localStorage.setItem(key,String(value??'')); } return true; } async function switchTenantLocal(nextWorkspaceId) { const next=String(nextWorkspaceId||'').trim(); // One-time upgrade adoption. If the old config already named a workspace, // current local data belongs to that legacy workspace only. This prevents a // signed-out old database from being accidentally attached to a different // account on the first login after upgrading. if(!config.tenantStorageReady){ const legacy=String(config.legacyLocalWorkspaceId||'').trim(); if(legacy&&legacy!==next){ await captureTenantLocal(legacy); clearTenantLocal(); config.tenantStorageReady=true; config.localWorkspaceId=next; config.legacyLocalWorkspaceId=''; let restored=false; if(next)restored=await restoreTenantLocal(next); if(next&&!restored)config.migrated[next]=false; saveConfig(); return {changed:true,restored,legacyCaptured:true}; } if(next){ config.tenantStorageReady=true; config.localWorkspaceId=next; config.legacyLocalWorkspaceId=''; saveConfig(); await captureTenantLocal(next); return {changed:false,restored:true,adopted:true}; } // A purely local pre-cloud installation has no workspace id yet. Keep it // untouched until the first company is selected, so migration stays safe. return {changed:false,restored:false}; } const prev=String(config.localWorkspaceId||'').trim(); if(prev===next)return {changed:false,restored:Boolean(next)}; if(prev)await captureTenantLocal(prev); clearTenantLocal(); config.localWorkspaceId=next; let restored=false; if(next)restored=await restoreTenantLocal(next); // If this device has no saved working copy for the target workspace, force a // clean cloud pull on reload instead of merging an empty browser state. if(next&&!restored)config.migrated[next]=false; saveConfig(); return {changed:true,restored}; } async function adoptCurrentLocalAsWorkspace(workspaceId) { const id=String(workspaceId||'').trim(); if(!id)return false; config.tenantStorageReady=true; config.localWorkspaceId=id; config.legacyLocalWorkspaceId=''; config.workspaceId=id; config.migrated[id]=false; saveConfig(); await captureTenantLocal(id); return true; } function seedOfficialCatalogForFreshWorkspace() { clearTenantLocal(); let seed=[]; try{if(Array.isArray(window.SUN_OFFICIAL_CATALOG))seed=clone(window.SUN_OFFICIAL_CATALOG)}catch(_){} localStorage.setItem('sunBoxes',JSON.stringify(Array.isArray(seed)?seed:[])); localStorage.setItem('sunOrders','[]'); if(window.SUN_OFFICIAL_CATALOG_VERSION)localStorage.setItem('sunOfficialCatalogVersion',String(window.SUN_OFFICIAL_CATALOG_VERSION)); } let signOutInProgress=false; function clearLocalSupabaseSessionFallback() { // Supabase normally clears its own persisted auth token. If the network call // is blocked or hangs, remove only this project's auth keys so the user can // still leave the account on the current device without touching app data. let projectRef=''; try{projectRef=new URL(config.url).hostname.split('.')[0]||'';}catch(_){} const prefixes=projectRef?[`sb-${projectRef}-auth-token`]:[]; for(const storage of [localStorage,sessionStorage]){ try{ const remove=[]; for(let i=0;ikey===prefix||key.startsWith(prefix+'.')||key.startsWith(prefix+'-')))remove.push(key); } remove.forEach(key=>storage.removeItem(key)); }catch(_){} } } function setSignOutUiBusy(busy) { const selectors=['#sunCloudSignOutV2','#sunLogoutBtn','#sunGateSignOutV3','#sunCloudUsePasswordV3','[data-signout]','[data-saas-signout]']; document.querySelectorAll(selectors.join(',')).forEach(btn=>{ if(!(btn instanceof HTMLButtonElement))return; if(busy){btn.dataset.sunOldText=btn.textContent||'';btn.disabled=true;btn.textContent='Выходим…';} else{btn.disabled=false;if(btn.dataset.sunOldText){btn.textContent=btn.dataset.sunOldText;delete btn.dataset.sunOldText;}} }); } async function signOutAndReload() { if(signOutInProgress)return; signOutInProgress=true; setSignOutUiBusy(true); clearTimeout(syncTimer); setStatus('syncing','Выходим из аккаунта…'); try{ // Preserve the company working copy first. Do not block logout on a cloud // sync: the workspace snapshot remains available and will sync after the // next login if there were unsent changes. const snapshot=Promise.resolve().then(async()=>{if(supportMode){clearTenantLocal();supportMode=null;config.localWorkspaceId='';saveConfig();return {changed:true};}return switchTenantLocal('');}); await Promise.race([snapshot,sleep(2200).then(()=>{throw new Error('Tenant snapshot timeout');})]); }catch(error){ console.warn('[SunCloud] tenant snapshot before sign-out failed',error); try{clearTenantLocal();config.localWorkspaceId='';saveConfig();}catch(_){} } try{ if(client?.auth){ const result=await Promise.race([ client.auth.signOut({scope:'local'}), sleep(2500).then(()=>{throw new Error('Supabase local sign-out timeout');}) ]); if(result?.error)throw result.error; }else clearLocalSupabaseSessionFallback(); }catch(error){ console.warn('[SunCloud] Supabase sign-out fallback',error); try{client?.auth.stopAutoRefresh?.();}catch(_){} clearLocalSupabaseSessionFallback(); } session=null;workspace=null;memberships=[];membershipsLoading=false;membershipsLoaded=true;unsubscribeRealtime(); try{window.dispatchEvent(new CustomEvent('sun:cloud-permissions-changed'));}catch(_){} // Reload regardless of network state so a blocked logout endpoint can never // leave the user trapped in the previous account screen. location.reload(); } async function getBaseline() { if (!workspace?.id) return null; const row = await idbGet('meta', `baseline:${workspace.id}`); return row?.value || null; } async function setBaseline(row) { if (!workspace?.id || !row) return; await idbPut('meta', {key:`baseline:${workspace.id}`, value:{payload:clone(row.payload),revision:Number(row.revision || 0),updated_at:row.updated_at || '',client_id:row.client_id || ''}}); } function stable(value) { if (value === undefined) return '__undefined__'; if (value === null || typeof value !== 'object') return JSON.stringify(value); if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`; return `{${Object.keys(value).sort().map(k => `${JSON.stringify(k)}:${stable(value[k])}`).join(',')}}`; } function equal(a, b) { return stable(a) === stable(b); } function isPlainObject(value) { return Boolean(value && typeof value === 'object' && !Array.isArray(value)); } function idArray(value) { return Array.isArray(value) && value.every(item => isPlainObject(item) && item.id != null); } function mergeById(base, local, remote, conflicts, path) { const bm = new Map((base || []).map(x => [String(x.id), x])); const lm = new Map((local || []).map(x => [String(x.id), x])); const rm = new Map((remote || []).map(x => [String(x.id), x])); const order = []; [...(remote || []), ...(local || []), ...(base || [])].forEach(x => { const id=String(x.id); if (!order.includes(id)) order.push(id); }); const out = []; for (const id of order) { const b = bm.get(id), l = lm.get(id), r = rm.get(id); if (l === undefined && r === undefined) continue; if (l === undefined) { if (b !== undefined && !equal(r,b)) conflicts.push(`${path}[${id}]: удалено локально, изменено в облаке`); if (b === undefined || !equal(r,b)) out.push(clone(r)); continue; } if (r === undefined) { if (b !== undefined && !equal(l,b)) { conflicts.push(`${path}[${id}]: изменено локально, удалено в облаке`); out.push(clone(l)); } else if (b === undefined) out.push(clone(l)); continue; } out.push(mergeNode(b, l, r, conflicts, `${path}[${id}]`)); } return out; } function mergeNode(base, local, remote, conflicts, path='state') { if (equal(local, remote)) return clone(local); if (equal(local, base)) return clone(remote); if (equal(remote, base)) return clone(local); if (idArray(local) && idArray(remote) && (!base || idArray(base))) { return mergeById(Array.isArray(base)?base:[], local, remote, conflicts, path); } if (isPlainObject(local) && isPlainObject(remote) && (base == null || isPlainObject(base))) { const out = {}; const keys = new Set([...Object.keys(base || {}), ...Object.keys(local), ...Object.keys(remote)]); for (const key of keys) { const b = base?.[key], l = local[key], r = remote[key]; if (!(key in local) && !(key in remote)) continue; if (!(key in local)) { if (b !== undefined && !equal(r,b)) conflicts.push(`${path}.${key}: удалено локально, изменено в облаке`); if (b === undefined || !equal(r,b)) out[key] = clone(r); continue; } if (!(key in remote)) { if (b !== undefined && !equal(l,b)) { conflicts.push(`${path}.${key}: изменено локально, удалено в облаке`); out[key]=clone(l); } else if (b === undefined) out[key]=clone(l); continue; } out[key] = mergeNode(b, l, r, conflicts, `${path}.${key}`); } return out; } conflicts.push(path); return clone(local); } function mergePayloads(basePayload, localPayload, remotePayload) { const conflicts = []; const base = basePayload?.storage || {}; const local = localPayload?.storage || {}; const remote = remotePayload?.storage || {}; const merged = {}; const keys = new Set([...Object.keys(base), ...Object.keys(local), ...Object.keys(remote)]); for (const key of keys) { const b = base[key], l = local[key], r = remote[key]; if (l === undefined && r === undefined) continue; if (l === undefined) { if (b !== undefined && !equal(r,b)) conflicts.push(key); if (b === undefined || !equal(r,b)) merged[key] = clone(r); continue; } if (r === undefined) { if (b !== undefined && !equal(l,b)) { conflicts.push(key); merged[key] = clone(l); } else if (b === undefined) merged[key] = clone(l); continue; } merged[key] = mergeNode(b, l, r, conflicts, key); } return {payload:{format:'sun-cloud-v2',version:2,storage:merged}, conflicts:[...new Set(conflicts)]}; } function dataUrlToBlob(dataUrl) { const match = /^data:([^;,]+)?(;base64)?,(.*)$/s.exec(dataUrl || ''); if (!match) throw new Error('Invalid data URL'); const mime = match[1] || 'application/octet-stream'; const binary = match[2] ? atob(match[3]) : decodeURIComponent(match[3]); const bytes = new Uint8Array(binary.length); for (let i=0;i { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result || '')); reader.onerror = () => reject(reader.error || new Error('FileReader error')); reader.readAsDataURL(blob); }); } async function shrinkImageIfNeeded(dataUrl, blob) { if (blob.size <= 12 * 1024 * 1024) return blob; const image = new Image(); image.src = dataUrl; await new Promise((resolve, reject) => { image.onload=resolve; image.onerror=reject; }); const max = 2400; const scale = Math.min(1, max / Math.max(image.naturalWidth || 1, image.naturalHeight || 1)); const canvas = document.createElement('canvas'); canvas.width = Math.max(1, Math.round((image.naturalWidth || 1) * scale)); canvas.height = Math.max(1, Math.round((image.naturalHeight || 1) * scale)); const ctx = canvas.getContext('2d'); ctx.fillStyle = '#fff'; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.drawImage(image,0,0,canvas.width,canvas.height); return await new Promise(resolve => canvas.toBlob(value => resolve(value || blob), 'image/jpeg', .9)); } async function sha256(blob) { const digest = await crypto.subtle.digest('SHA-256', await blob.arrayBuffer()); return [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2,'0')).join(''); } function extensionFor(type) { return ({'image/jpeg':'jpg','image/png':'png','image/webp':'webp','image/gif':'gif'})[String(type||'').toLowerCase()] || 'bin'; } async function uploadDataUrl(dataUrl) { if (!client || !workspace?.id) return dataUrl; let blob = dataUrlToBlob(dataUrl); blob = await shrinkImageIfNeeded(dataUrl, blob); const hash = await sha256(blob); const ext = extensionFor(blob.type); const path = `${workspace.id}/media/${hash.slice(0,2)}/${hash}.${ext}`; const {error} = await client.storage.from(BUCKET).upload(path, blob, {upsert:false,contentType:blob.type || 'application/octet-stream',cacheControl:'31536000'}); if (error && !/exist|duplicate|409/i.test(`${error.message || ''} ${error.statusCode || ''}`)) throw error; await idbPut('media', {path, blob, cachedAt:new Date().toISOString()}); return MEDIA_PREFIX + path; } async function encodeMedia(value) { if (typeof value === 'string') { if (/^data:image\//i.test(value)) return await uploadDataUrl(value); return value; } if (Array.isArray(value)) { const out = []; for (const item of value) out.push(await encodeMedia(item)); return out; } if (isPlainObject(value)) { const out = {}; for (const [key,item] of Object.entries(value)) out[key] = await encodeMedia(item); return out; } return value; } async function downloadMedia(path) { const cached = await idbGet('media', path); if (cached?.blob) return await blobToDataUrl(cached.blob); const {data, error} = await client.storage.from(BUCKET).download(path); if (error) throw error; await idbPut('media', {path, blob:data, cachedAt:new Date().toISOString()}); return await blobToDataUrl(data); } async function decodeMedia(value) { if (typeof value === 'string' && value.startsWith(MEDIA_PREFIX)) return await downloadMedia(value.slice(MEDIA_PREFIX.length)); if (Array.isArray(value)) { const out=[]; for (const item of value) out.push(await decodeMedia(item)); return out; } if (isPlainObject(value)) { const out={}; for (const [key,item] of Object.entries(value)) out[key]=await decodeMedia(item); return out; } return value; } function quotaExceeded(error) {return error?.name==='QuotaExceededError'||/quota|exceeded/i.test(String(error?.message||error||''));} function compactLocalImageData(dataUrl,{maxSide=900,maxChars=130000,quality=.78,force=false}={}) { return new Promise(resolve => { if (!/^data:image\//i.test(String(dataUrl || ''))) return resolve(dataUrl); const image = new Image(); image.onerror = () => resolve(dataUrl); image.onload = () => { const iw=Math.max(1,image.naturalWidth||image.width||1), ih=Math.max(1,image.naturalHeight||image.height||1); if (!force && String(dataUrl).length<=maxChars && Math.max(iw,ih)<=maxSide) return resolve(dataUrl); let scale=Math.min(1,maxSide/Math.max(iw,ih)), q=quality, best=dataUrl; for (let attempt=0; attempt<5; attempt++) { const canvas=document.createElement('canvas'); canvas.width=Math.max(1,Math.round(iw*scale)); canvas.height=Math.max(1,Math.round(ih*scale)); const ctx=canvas.getContext('2d'); if(!ctx) break; ctx.fillStyle='#fff'; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.drawImage(image,0,0,canvas.width,canvas.height); try { best=canvas.toDataURL('image/jpeg',q)||best; } catch (_) { break; } if (best.length<=maxChars) break; scale*=.78; q=Math.max(.52,q-.07); } resolve(best); }; image.src=dataUrl; }); } async function compactSunBoxesForStorage(value, options={}) { if (!Array.isArray(value)) return value; const out=[]; for (const item of value) { if (!isPlainObject(item)) { out.push(item); continue; } const copy={...item}; if (typeof copy.photo==='string' && /^data:image\//i.test(copy.photo)) copy.photo=await compactLocalImageData(copy.photo,options); out.push(copy); } return out; } async function collectLocalPayload() { const storage = {}; for (let i=0;i { if (!remoteKeys.has(key)) localStorage.removeItem(key); }); } for (const [key,entry] of Object.entries(payload.storage)) { if (!shouldSyncKey(key) || !entry) continue; let decoded = await decodeMedia(entry.v); if (key === 'sunBoxes' && entry.t === 'j') decoded = await compactSunBoxesForStorage(decoded,{maxSide:900,maxChars:130000,quality:.78}); let raw = entry.t === 'j' ? JSON.stringify(decoded) : String(decoded ?? ''); try { localStorage.setItem(key, raw); } catch (error) { if (key !== 'sunBoxes' || entry.t !== 'j' || !quotaExceeded(error)) throw error; decoded = await compactSunBoxesForStorage(decoded,{maxSide:640,maxChars:80000,quality:.66,force:true}); raw = JSON.stringify(decoded); try { localStorage.setItem(key, raw); } catch (retryError) { if (quotaExceeded(retryError)) throw new Error('Каталог с фотографиями все еще превышает локальный лимит браузера даже после оптимизации фото.'); throw retryError; } toast('Фотографии каталога оптимизированы, чтобы не превышать лимит браузера.','info',5200); } } } finally { suppressStorageTracking = false; } refreshRuntime(); } function refreshRuntime() { try { if (typeof boxes !== 'undefined') boxes = JSON.parse(localStorage.getItem('sunBoxes') || '[]'); } catch (_) {} try { if (typeof orders !== 'undefined') orders = JSON.parse(localStorage.getItem('sunOrders') || '[]'); } catch (_) {} for (const name of ['render','renderOrders','renderStats','renderClients','renderStock','renderManager']) { try { if (typeof window[name] === 'function') window[name](); } catch (_) {} } try { window.dispatchEvent(new CustomEvent('sun:cloud-state-applied')); } catch (_) {} } function payloadEmpty(payload) { return !payload?.storage || Object.keys(payload.storage).length === 0; } async function fetchRemoteRow() { if (!client || !workspace?.id) return null; const {data,error} = await sunCloudAwait(client.rpc('sun_fetch_app_state',{p_workspace:workspace.id}),'Загрузка облачной базы'); if (error) throw error; return Array.isArray(data) ? (data[0] || null) : (data || null); } async function upsertPayload(payload, expectedRevision=null) { const args={p_workspace:workspace.id,p_payload:payload,p_client_id:clientId(),p_expected_revision:expectedRevision==null?null:Number(expectedRevision)}; const {data,error} = await sunCloudAwait(client.rpc('sun_save_app_state_v17',args),'Сохранение облачной базы'); if (error) throw error; return Array.isArray(data) ? data[0] : data; } async function backupBeforeCloud(reason) { try { await window.SunEnterprise?.createBackup?.(reason); } catch (_) {} } async function migrateLocalToCloud() { if (!canWrite()) return toast('Для переноса данных нужны права на изменение рабочей базы.','warn'); if (!navigator.onLine) return toast('Нет подключения к интернету. Локальные данные сохранены и никуда не пропадут.','warn'); setStatus('syncing','Создаю первую облачную копию…'); try { await backupBeforeCloud('Перед первым переносом в Supabase'); const remote = await fetchRemoteRow(); if (remote && !payloadEmpty(remote.payload)) { if (!confirm('В этой рабочей базе уже есть облачные данные. Заменить их текущими данными с этого устройства?')) { setStatus('ready','Перенос отменён.'); return; } } const localPayload = await collectLocalPayload(); const row = await upsertPayload(localPayload, remote?.revision ?? null); await setBaseline(row); config.migrated[workspace.id] = true; config.lastSync = row.updated_at || new Date().toISOString(); config.autoSync = true; saveConfig(); dirty=false; setStatus('ready','Все текущие данные перенесены в облако.'); toast('Данные и загруженные фотографии перенесены в Supabase. Автосинхронизация включена.','success',6500); subscribeRealtime(); try{window.dispatchEvent(new CustomEvent('sun:cloud-sync-complete',{detail:{row:clone(row),payload:clone(localPayload),kind:'migrate'}}));}catch(_){} renderCloudUI(); } catch (error) { handleError(error, 'Не удалось перенести данные в облако.'); } } async function pullRemote({replace=false,quiet=false}={}) { if (!client || !workspace?.id) return; setStatus('syncing','Загружаю облачные данные…'); try { const row = await fetchRemoteRow(); if (!row || payloadEmpty(row.payload)) { setStatus('ready','В облаке пока нет данных.'); return; } if (!quiet) await backupBeforeCloud('Перед загрузкой данных из Supabase'); await applyPayload(row.payload, replace); await setBaseline(row); config.migrated[workspace.id] = true; config.lastSync = row.updated_at || new Date().toISOString(); saveConfig(); dirty=false; setStatus('ready','Облачные данные загружены.'); if (!quiet) toast('Данные загружены из облака.','success'); try{window.dispatchEvent(new CustomEvent('sun:cloud-sync-complete',{detail:{row:clone(row),payload:clone(row.payload),kind:'pull'}}));}catch(_){} renderCloudUI(); } catch (error) { handleError(error,'Не удалось загрузить облачные данные.'); } } async function syncNow({quiet=false,retryCount=0}={}) { if (isSyncing || !client || !session || !workspace?.id || !workspaceMigrated()) return; if (!navigator.onLine) { setStatus('offline','Офлайн — изменения ждут подключения.'); return; } isSyncing = true; setStatus('syncing','Синхронизация…'); try { const [baseline, remote, localPayload] = await Promise.all([getBaseline(), fetchRemoteRow(), collectLocalPayload()]); if (!remote || payloadEmpty(remote.payload)) { if (!canWrite()) throw new Error('В облаке нет базы, а у пользователя нет прав на её создание.'); const row = await upsertPayload(localPayload, remote?.revision ?? null); await setBaseline(row); dirty=false; config.lastSync=row.updated_at||new Date().toISOString();saveConfig(); setStatus('ready','Синхронизировано.'); if(!quiet)toast('Синхронизация завершена.','success'); return; } if (!baseline) { await applyPayload(remote.payload, true); await setBaseline(remote); dirty=false; config.lastSync=remote.updated_at||new Date().toISOString();saveConfig(); setStatus('ready','Подключена существующая облачная база.'); if(!quiet)toast('Загружена актуальная облачная база.','success'); return; } const merged = mergePayloads(baseline.payload, localPayload, remote.payload); let finalRow = remote; const changedVsRemote = !equal(merged.payload, remote.payload); const changedVsLocal = !equal(merged.payload, localPayload); if (changedVsRemote) { if (!canWrite()) { await applyPayload(remote.payload, true); finalRow = remote; } else { finalRow = await upsertPayload(merged.payload, remote.revision); if (changedVsLocal) await applyPayload(merged.payload, true); } } else if (changedVsLocal) { await applyPayload(remote.payload, true); } await setBaseline(finalRow); dirty=false; config.lastSync=finalRow.updated_at||new Date().toISOString();saveConfig(); setStatus('ready', merged.conflicts.length ? `Синхронизировано, объединено конфликтов: ${merged.conflicts.length}.` : 'Синхронизировано.'); if (merged.conflicts.length) toast(`Изменения с двух устройств объединены. Проверено конфликтов: ${merged.conflicts.length}.`,'warn',6500); else if (!quiet) toast('Синхронизация завершена.','success'); try{window.dispatchEvent(new CustomEvent('sun:cloud-sync-complete',{detail:{row:clone(finalRow),payload:clone(finalRow.payload),kind:'sync',conflicts:merged.conflicts.length}}));}catch(_){} window.SunStabilityV17?.markSynced?.(finalRow?.revision); renderCloudUI(); } catch (error) { const msg=String(error?.message||''); if(msg.includes('SUN_CONFLICT')){ const nextRetry=Number(retryCount||0)+1; try{window.SunStabilityV17?.recordConflict?.(msg);}catch(_){} if(nextRetry>CLOUD_CONFLICT_MAX_RETRIES){handleError(error,'Не удалось синхронизировать после нескольких безопасных повторов.');} else{const delay=Math.min(5000,400*Math.pow(2,nextRetry-1));setStatus('pending','Облачная версия изменилась. Повтор '+nextRetry+'/'+CLOUD_CONFLICT_MAX_RETRIES+' через '+(Math.round(delay/100)/10)+' сек.…');setTimeout(()=>syncNow({quiet:true,retryCount:nextRetry}),delay);} }else handleError(error,'Ошибка синхронизации.'); } finally { isSyncing=false; } } async function handleRealtimeRow(row) { if (!row || row.client_id === clientId() || isSyncing || !workspaceMigrated()) return; try { const baseline = await getBaseline(); if (!baseline) { await applyPayload(row.payload,true);await setBaseline(row);setStatus('ready','Получены данные с другого устройства.');return; } const localPayload = await collectLocalPayload(); const merged = mergePayloads(baseline.payload, localPayload, row.payload); await applyPayload(merged.payload, true); if (!equal(merged.payload,row.payload) && canWrite()) { const saved=await upsertPayload(merged.payload,row.revision);await setBaseline(saved); } else await setBaseline(row); dirty=false;config.lastSync=row.updated_at||new Date().toISOString();saveConfig(); setStatus('ready','Получены изменения с другого устройства.'); toast(merged.conflicts.length?'Получены облачные изменения; параллельные правки объединены.':'Данные обновлены с другого устройства.','success',3500); renderCloudUI(); } catch (error) { handleError(error,'Не удалось применить изменения с другого устройства.'); } } function scheduleSync(reason='change') { dirty = true; try{window.SunStabilityV17?.markPending?.(reason);}catch(_){} if (!config.autoSync || !workspaceMigrated() || !session || !workspace || !canWrite()) { updatePill(); return; } clearTimeout(syncTimer); syncTimer = setTimeout(() => syncNow({quiet:true}), SYNC_DEBOUNCE); if (!navigator.onLine) setStatus('offline','Офлайн — изменения сохранены локально.'); else setStatus('pending',`Изменения ожидают синхронизации (${reason}).`); } function storageSignature() { const parts=[]; for(let i=0;i>>0}`); } return parts.sort().join('|'); } function installStorageTracking() { if (Storage.prototype.__sunCloudV2Tracked) return; const nativeSet = Storage.prototype.setItem; const nativeRemove = Storage.prototype.removeItem; Object.defineProperty(Storage.prototype,'__sunCloudV2Tracked',{value:true,configurable:true}); Storage.prototype.setItem=function(key,value){ const old = this===localStorage ? this.getItem(key) : null; const result = nativeSet.call(this,key,value); if(this===localStorage&&!suppressStorageTracking&&shouldSyncKey(key)&&old!==String(value))scheduleSync(key); return result; }; Storage.prototype.removeItem=function(key){ const had=this===localStorage&&this.getItem(key)!==null; const result=nativeRemove.call(this,key); if(this===localStorage&&!suppressStorageTracking&&had&&shouldSyncKey(key))scheduleSync(key); return result; }; observedSignature=storageSignature(); setInterval(()=>{ if(document.hidden||suppressStorageTracking)return; const next=storageSignature(); if(next!==observedSignature){observedSignature=next;scheduleSync('данные приложения');} },9000); ['sun:catalog-categories-changed','sun:client-offer-catalog-changed','sun:cloud-dirty'].forEach(name=>window.addEventListener(name,()=>scheduleSync(name))); } function setStatus(kind, text='') { lastStatus=kind;lastError=kind==='error'?text:''; const el=$('sunCloudV2Status'); if(el){el.textContent=text||statusText();el.dataset.kind=kind;} updatePill(); } function statusText() { if(lastStatus==='error')return lastError||'Ошибка облака'; if(!config.url||!config.key)return 'Облако не подключено'; if(!navigator.onLine)return 'Офлайн — работаем с локальной копией'; if(!session)return 'Нужно войти в облачный аккаунт'; if(supportMode)return `Режим поддержки · ${supportMode.name||'Компания'} · только просмотр`; if(!workspace)return 'Нужно выбрать или создать рабочую базу'; if(!workspaceMigrated())return 'Нужен первый перенос данных в облако'; if(lastStatus==='syncing')return 'Синхронизация…'; if(dirty)return 'Есть несинхронизированные изменения'; return config.lastSync?`Синхронизировано ${new Date(config.lastSync).toLocaleString('ru-RU')}`:'Облако готово'; } // Облачный статус больше не висит поверх всех разделов. // Управление облаком доступно только в «Настройки → Облако Supabase». function ensurePill() { const pill=$('sunCloudPillV2'); if(pill) pill.remove(); return null; } function updatePill() { ensurePill(); } function injectStyles() { if($('sunCloudV2Styles'))return; const style=document.createElement('style');style.id='sunCloudV2Styles';style.textContent=` .sun-cloud-v2-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.sun-cloud-v2-grid .wide{grid-column:1/-1}.sun-cloud-v2-box{border:1px solid #e0e4e6;border-radius:9px;padding:12px;background:#fbfcfc}.sun-cloud-v2-box h3{margin:0 0 8px;color:#15364c;font-size:14px}.sun-cloud-v2-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}.sun-cloud-v2-status{margin-top:10px;border-radius:8px;padding:9px 10px;background:#edf4f6;color:#365161;font-size:12px}.sun-cloud-v2-status[data-kind="error"]{background:#fff0ee;color:#943d3d}.sun-cloud-v2-status[data-kind="ready"]{background:#eef8f2;color:#347154}.sun-cloud-v2-status[data-kind="offline"]{background:#fff7e6;color:#8b6b25}.sun-cloud-v2-note{font-size:12px;color:#68717a;margin:6px 0}.sun-cloud-v2-user{font-weight:800;color:#15364c}.sun-cloud-v2-code{font:700 13px/1.2 ui-monospace,monospace;background:#f2f4f5;border-radius:7px;padding:8px;word-break:break-all}.sun-cloud-v2-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.sun-cloud-v2-row label{flex:1;min-width:170px}.sun-cloud-v2-small{font-size:11px;color:#7b8388} @media(max-width:760px){.sun-cloud-v2-grid{grid-template-columns:1fr}.sun-cloud-v2-grid .wide{grid-column:auto}} `;document.head.appendChild(style); } function findCloudCard() { const cards=[...document.querySelectorAll('#enterprise-settings .enterprise-card')]; return cards.find(card=>(card.querySelector('h2')?.textContent||'').trim()==='Облачная синхронизация') || $('sunCloudV2Card'); } function ensureCloudCard() { const card=findCloudCard();if(!card)return null; if(card.id!=='sunCloudV2Card'){card.id='sunCloudV2Card';card.classList.add('wide');renderCloudUI();} return card; } function renderCloudUI() { const card=findCloudCard();if(!card)return; card.id='sunCloudV2Card';card.classList.add('wide'); const connected=Boolean(config.url&&config.key); const signed=Boolean(session?.user); const selected=Boolean(workspace); card.innerHTML=`

    Профиль и аккаунт

    Вход, выход, рабочая компания и пользователи компании.

    ${connected&&!signed?`

    Войти в профиль

    `:''} ${!connected?`

    Подключение недоступно

    Техническое подключение настраивается только из кабинета разработчика.

    `:''} ${signed?`

    Профиль

    ${esc(session.user.email||session.user.id)}
    `:''} ${signed&&!selected?`

    Рабочая компания

    ${membershipsLoading?'Загружаю доступные рабочие базы…':'У этого аккаунта пока нет доступной рабочей базы.'}

    `:''} ${signed&&selected?`

    Рабочая компания

    ${esc(workspace.name)}${supportMode?'· поддержка, только просмотр':''}
    Роль: ${supportMode?'Разработчик · поддержка':esc(roleLabel(workspace.role))}${workspace.display_name?` · ${esc(workspace.display_name)}`:''}
    ${!supportMode&&memberships.length>1?``:''}
    `:''} ${signed&&selected&&!supportMode&&hasPermission('users.manage')?`

    Пользователи

    Управление сотрудниками и правами внутри этой компании.

    `:''}
    ${esc(statusText())}
    `; bindCloudUI(); } function bindCloudUI() { $('sunCloudConnectV2')?.addEventListener('click', async()=>{ config.url=String($('sunCloudUrlV2')?.value||'').trim().replace(/\/$/,'');config.key=String($('sunCloudKeyV2')?.value||'').trim();saveConfig(); if(!config.url||!config.key)return toast('Введите Project URL и Publishable key.','warn'); client=null;session=null;workspace=null;memberships=[];await connectFromConfig(false);renderCloudUI(); }); $('sunCloudSignInV2')?.addEventListener('click',()=>signIn(false)); $('sunCloudSignUpV2')?.addEventListener('click',()=>signIn(true)); $('sunCloudSignOutV2')?.addEventListener('click',signOutAndReload); $('sunCloudCreateWorkspaceV2')?.addEventListener('click',createWorkspace); $('sunCloudReloadMembershipsV2')?.addEventListener('click',async()=>{const tenantSwitched=await loadMemberships();if(tenantSwitched){location.reload();return;}renderCloudUI();if(workspace){subscribeRealtime();await pullRemote({replace:true,quiet:true});}}); $('sunCloudMigrateV2')?.addEventListener('click',migrateLocalToCloud); $('sunCloudSyncNowV2')?.addEventListener('click',()=>syncNow({quiet:false})); $('sunCloudPullV2')?.addEventListener('click',async()=>{if(confirm('Заменить локальную рабочую копию актуальными данными из облака? Перед загрузкой будет создана резервная копия.'))await pullRemote({replace:true,quiet:false});}); $('sunCloudAutoV2')?.addEventListener('change',e=>{config.autoSync=e.target.checked;saveConfig();if(config.autoSync)scheduleSync('автосинхронизация включена');renderCloudUI();}); $('sunCloudWorkspaceSelectV2')?.addEventListener('change',async e=>{const next=String(e.target.value||'');config.workspaceId=next;saveConfig();const switched=await switchTenantLocal(next);if(switched.changed){location.reload();return;}selectWorkspace();subscribeRealtime();renderCloudUI();if(workspaceMigrated())await syncNow({quiet:true});else await pullRemote({replace:true,quiet:true});}); $('sunCloudManageUsersV3')?.addEventListener('click',()=>window.dispatchEvent(new CustomEvent('sun:open-cloud-users'))); } async function loadSupabaseLibrary() { if(window.supabase?.createClient)return; const existing=$('sunSupabaseJsV2'); if(existing){for(let i=0;i<80&&!window.supabase?.createClient;i++)await sleep(100);if(window.supabase?.createClient)return;} await new Promise((resolve,reject)=>{ const script=document.createElement('script');script.id='sunSupabaseJsV2';script.src=SUPABASE_JS;script.async=true;script.onload=resolve;script.onerror=()=>reject(new Error('Не удалось загрузить библиотеку Supabase. Проверьте интернет.'));document.head.appendChild(script); }); if(!window.supabase?.createClient)throw new Error('Supabase SDK не загрузился.'); } async function connectFromConfig(silent=true) { if(!config.url||!config.key){setStatus('local','Облако не подключено.');return;} setStatus('syncing','Подключаю Supabase…'); try{ await loadSupabaseLibrary(); const signature=`${config.url}|${config.key}`; if(!client||signature!==clientSignature){ client=window.supabase.createClient(config.url,config.key,{auth:{persistSession:true,autoRefreshToken:true,detectSessionInUrl:true}});clientSignature=signature; client.auth.onAuthStateChange((_event,next)=>{session=next;membershipsLoading=Boolean(next?.user);membershipsLoaded=!next?.user;setTimeout(async()=>{try{if(!next?.user){const sw=await switchTenantLocal('');if(sw.changed){location.reload();return;}}else{const sw=await loadMemberships();if(sw){location.reload();return;}}}finally{renderCloudUI();updatePill();}},0);}); } const {data,error}=await client.auth.getSession();if(error)throw error;session=data.session||null; const tenantSwitched=session?await loadMemberships():(await switchTenantLocal('')).changed; if(tenantSwitched){location.reload();return;} if(session&&workspace){ subscribeRealtime(); if(workspaceMigrated())await syncNow({quiet:true}); else { const remote=await fetchRemoteRow(); if(remote&&!payloadEmpty(remote.payload)){ await backupBeforeCloud('Перед автоматическим подключением к существующей облачной базе'); await applyPayload(remote.payload,true);await setBaseline(remote);config.migrated[workspace.id]=true;config.lastSync=remote.updated_at||new Date().toISOString();saveConfig();dirty=false;setStatus('ready','Подключена существующая облачная база.'); } else setStatus('setup','Готово к первому переносу данных.'); } } else if(session)setStatus('setup',membershipsLoading?'Загружаю рабочую базу…':'Для этого аккаунта рабочая база не найдена.'); else setStatus('auth','Подключено. Войдите в аккаунт.'); if(!silent)toast('Supabase подключён.','success'); }catch(error){handleError(error,'Не удалось подключиться к Supabase.');} finally{renderCloudUI();} } async function signIn(signUp) { const email=String($('sunCloudEmailV2')?.value||'').trim();const password=String($('sunCloudPasswordV2')?.value||''); if(!email||password.length<6)return toast('Введите email и пароль не короче 6 символов.','warn'); setStatus('syncing',signUp?'Создаю аккаунт…':'Выполняю вход…'); try{ const result=signUp?await client.auth.signUp({email,password,options:{data:{registration_source:'caterium_public_signup'}}}):await client.auth.signInWithPassword({email,password}); if(result.error)throw result.error;session=result.data.session||null; if(signUp&&!session){const retry=await client.auth.signInWithPassword({email,password});if(retry.error)throw retry.error;session=retry.data.session||null;} {const tenantSwitched=await loadMemberships();if(tenantSwitched){location.reload();return;}setStatus('setup','Вход выполнен.');toast('Вход выполнен.','success');} renderCloudUI(); }catch(error){handleError(error,signUp?'Не удалось создать аккаунт.':'Не удалось войти.');} } async function loadMemberships() { memberships=[];workspace=null;membershipsLoaded=false; if(!client||!session?.user)return false; membershipsLoading=true; try{ let rows=[]; const rpc=await client.rpc('sun_my_workspaces'); if(!rpc.error&&Array.isArray(rpc.data)){ rows=rpc.data.map(x=>({workspace_id:x.id,name:x.name,role:x.role,display_name:x.display_name,is_active:x.is_active,permissions:x.permissions})); }else{ // Compatibility fallback for an older server schema. const direct=await client.from('sun_workspace_members').select('workspace_id,role,display_name,is_active,permissions').eq('user_id',session.user.id); if(direct.error)throw rpc.error||direct.error; const active=(direct.data||[]).filter(x=>x.is_active!==false); if(active.length){ const ids=active.map(x=>x.workspace_id), names={}; const w=await client.from('sun_workspaces').select('id,name').in('id',ids);if(w.error)throw w.error;(w.data||[]).forEach(x=>names[x.id]=x.name); rows=active.map(x=>({...x,name:names[x.workspace_id]||'Рабочая база'})); } } memberships=rows.filter(x=>x.is_active!==false).map(x=>({id:x.workspace_id,name:x.name||'Рабочая база',role:x.role,display_name:x.display_name||'',is_active:x.is_active!==false,permissions:x.permissions||{}})); if(memberships.length&&!memberships.some(x=>x.id===config.workspaceId))config.workspaceId=memberships[0].id; if(!memberships.length)config.workspaceId=''; saveConfig();selectWorkspace(); const switched=await switchTenantLocal(workspace?.id||''); membershipsLoaded=true; if(switched.changed)return true; try{window.dispatchEvent(new CustomEvent('sun:cloud-permissions-changed',{detail:{workspace:clone(workspace),user:clone(session.user)}}));}catch(_){} return false; }finally{membershipsLoading=false;} } function selectWorkspace(){workspace=memberships.find(x=>x.id===config.workspaceId)||memberships[0]||null;if(workspace&&config.workspaceId!==workspace.id){config.workspaceId=workspace.id;saveConfig();}} async function createTrialWorkspace(companyName='Новая компания'){ if(!client||!session?.user)throw new Error('Сначала войдите в аккаунт.'); const name=String(companyName||'').trim()||'Новая компания'; await loadMemberships(); if(workspace)return clone(workspace); setStatus('syncing','Создаю компанию и включаю 14-дневный Полный тариф…'); const {data,error}=await client.rpc('sun_create_workspace',{p_name:name});if(error)throw error; const newId=String(data||'');if(!newId)throw new Error('Сервер не вернул ID новой компании.'); await switchTenantLocal(newId); seedOfficialCatalogForFreshWorkspace(); try{localStorage.setItem('sunCompanyProfileV1',JSON.stringify({name,createdAt:new Date().toISOString()}));}catch(_){} await adoptCurrentLocalAsWorkspace(newId); await loadMemberships(); if(!workspace||String(workspace.id)!==newId){config.workspaceId=newId;saveConfig();selectWorkspace();} if(!workspace)throw new Error('Компания создана, но не появилась в списке доступных компаний.'); const remote=await fetchRemoteRow(); const localPayload=await collectLocalPayload(); const row=await upsertPayload(localPayload,remote?.revision??null); await setBaseline(row); config.migrated[newId]=true;config.lastSync=row?.updated_at||new Date().toISOString();config.autoSync=true;saveConfig();dirty=false; try{await client.rpc('sun_v17_mirror_legacy',{p_workspace:newId,p_payload:localPayload,p_client_id:clientId()});}catch(_){} subscribeRealtime(); setStatus('ready','Компания создана · Полный тариф бесплатно 14 дней.'); renderCloudUI(); return clone(workspace); } async function createWorkspace(){ const name=String($('sunCloudWorkspaceNameV2')?.value||'Новая компания').trim()||'Новая компания'; try{await createTrialWorkspace(name);toast('Компания создана: Полный тариф на 14 дней, каталог готов, заказы и клиенты пустые.','success',7000);} catch(error){handleError(error,'Не удалось создать рабочую базу.');} } async function acceptInviteToken(rawToken){ const token=String(rawToken||'').trim();if(!token)throw new Error('Приглашение не найдено.'); if(!client||!session?.user)throw new Error('Сначала войдите в Caterium.'); setStatus('syncing','Подключаю компанию по приглашению…'); const {data,error}=await client.rpc('sun_accept_invite',{p_token:token});if(error)throw error; config.workspaceId=String(data||'');saveConfig(); await loadMemberships(); subscribeRealtime(); const remote=await fetchRemoteRow(); if(remote&&!payloadEmpty(remote.payload)){ await backupBeforeCloud('Перед подключением к компании по приглашению'); await applyPayload(remote.payload,true);await setBaseline(remote); config.migrated[workspace.id]=true;config.lastSync=remote.updated_at||new Date().toISOString();saveConfig(); } setStatus('ready','Вы присоединились к компании.');renderCloudUI(); try{window.dispatchEvent(new CustomEvent('sun:cloud-permissions-changed',{detail:{workspace:clone(workspace)}}));}catch(_){} return clone(workspace); } async function joinWorkspace(){ const token=String($('sunCloudInviteCodeV2')?.value||'').trim();if(!token)return toast('Введите код приглашения.','warn'); try{await acceptInviteToken(token);toast('Вы присоединились к компании.','success',6000);} catch(error){handleError(error,'Не удалось принять приглашение. Возможно, ссылка истекла или уже использована.');} } async function createInvite(){ const role=String($('sunCloudInviteRoleV2')?.value||'manager'); try{const {data,error}=await client.rpc('sun_create_invite',{p_workspace:workspace.id,p_role:role});if(error)throw error;const token=String(data||'');const host=$('sunCloudInviteResultV2');if(host)host.innerHTML=`

    Передайте сотруднику этот одноразовый код (действует 7 дней):

    ${esc(token)}
    `;$('sunCloudCopyInviteV2')?.addEventListener('click',async()=>{try{await navigator.clipboard.writeText(token);toast('Код скопирован.','success');}catch(_){toast('Скопируйте код вручную.','warn');}});} catch(error){handleError(error,'Не удалось создать приглашение.');} } function unsubscribeRealtime(){if(realtimeChannel&&client){try{client.removeChannel(realtimeChannel);}catch(_){}}realtimeChannel=null;} function subscribeRealtime(){ unsubscribeRealtime();if(!client||!session||!workspace?.id)return; realtimeChannel=client.channel(`sun-state-${workspace.id}-${clientId()}`).on('postgres_changes',{event:'INSERT',schema:'public',table:'sun_sync_events',filter:`workspace_id=eq.${workspace.id}`},async payload=>{ if(payload?.new?.client_id===clientId())return; try{const row=await fetchRemoteRow();if(row)await handleRealtimeRow(row);}catch(error){handleError(error,'Не удалось получить изменения с другого устройства.');} }).subscribe(status=>{if(status==='CHANNEL_ERROR')setStatus('error','Realtime не подключился. Обычная синхронизация продолжит работать.');}); } function handleError(error, message) { console.error('[SunCloudV2]',error);const detail=String(error?.message||error||'Неизвестная ошибка');setStatus('error',`${message} ${detail}`);toast(`${message} ${detail}`,'error',7500);renderCloudUI(); } function observeSettings() { const settingsRoot=$('enterprise-settings');if(settingsRoot){const observer=new MutationObserver(()=>{if(findCloudCard()&&!$('sunCloudV2Card'))ensureCloudCard();});observer.observe(settingsRoot,{childList:true,subtree:true});} document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const name=String(b.dataset.navLabel||b.textContent||'').trim();if(name==='Настройки')setTimeout(()=>{ensureCloudCard();renderCloudUI();},80);},true); setTimeout(()=>{ensureCloudCard();renderCloudUI();},250); } function hookEnterpriseSchedule() { const timer=setInterval(()=>{if(window.SunEnterprise){window.SunEnterprise.scheduleCloudPush=()=>scheduleSync('сохранение приложения');clearInterval(timer);}},250); setTimeout(()=>clearInterval(timer),10000); } window.addEventListener('online',()=>{setStatus('pending','Интернет восстановлен. Синхронизирую…');if(workspaceMigrated())syncNow({quiet:true});}); window.addEventListener('offline',()=>setStatus('offline','Офлайн — изменения сохраняются на этом устройстве.')); async function enterSupportWorkspace(workspaceId,name='Компания') { const id=String(workspaceId||'').trim();if(!id)throw new Error('Не выбрана компания.'); if(!client||!session?.user)throw new Error('Сначала войдите в аккаунт разработчика.'); const admin=await sunCloudAwait(client.rpc('sun_is_platform_admin'),'Проверка доступа разработчика',8000);if(admin.error)throw admin.error;if(admin.data!==true)throw new Error('Требуется аккаунт разработчика.'); const previousWorkspaceId=String(config.workspaceId||''); const previousLocalWorkspaceId=String(config.localWorkspaceId||workspace?.id||''); if(previousLocalWorkspaceId)await captureTenantLocal(previousLocalWorkspaceId); clearTenantLocal();config.localWorkspaceId='';saveConfig();unsubscribeRealtime(); const result=await sunCloudAwait(client.rpc('sun_dev_support_snapshot',{p_workspace:id}),'Загрузка компании в режиме поддержки',12000);if(result.error)throw result.error; const row=Array.isArray(result.data)?result.data[0]:result.data;if(!row?.payload)throw new Error('У компании нет облачной рабочей копии.'); await applyPayload(row.payload,true); supportMode={workspaceId:id,name:String(name||'Компания'),previousWorkspaceId,previousLocalWorkspaceId,enteredAt:new Date().toISOString()}; workspace={id,name:String(name||'Компания'),role:'platform_support',display_name:'Разработчик · поддержка',is_active:true,permissions:{}}; dirty=false;setStatus('ready',`Режим поддержки · ${name||'Компания'} · только просмотр`); try{window.dispatchEvent(new CustomEvent('sun:cloud-permissions-changed',{detail:{workspace:clone(workspace),support:true}}));window.dispatchEvent(new CustomEvent('sun:cloud-state-applied',{detail:{workspaceId:id,support:true}}));}catch(_){} renderCloudUI();return clone(supportMode); } async function refreshSupportWorkspace(){ if(!supportMode||!client||!session?.user)return false; const id=String(supportMode.workspaceId||workspace?.id||'').trim();if(!id)return false; const result=await sunCloudAwait(client.rpc('sun_dev_support_snapshot',{p_workspace:id}),'Обновление данных компании',12000);if(result.error)throw result.error; const row=Array.isArray(result.data)?result.data[0]:result.data;if(!row?.payload)throw new Error('У компании нет облачной рабочей копии.'); await applyPayload(row.payload,true);dirty=false;config.lastSync=new Date().toISOString();saveConfig(); setStatus('ready','Режим поддержки · '+(supportMode.name||'Компания')+' · только просмотр'); try{window.dispatchEvent(new CustomEvent('sun:cloud-state-applied',{detail:{workspaceId:id,support:true,refresh:true}}));}catch(_){} renderCloudUI();return true; } async function exitSupportWorkspace() { if(!supportMode)return false; clearTenantLocal();supportMode=null;workspace=null;config.localWorkspaceId='';saveConfig(); const switched=await loadMemberships();renderCloudUI(); if(switched||workspace){location.reload();return true;} return true; } async function setTechnicalConnection(url,key) { const admin=client&&session?.user?await client.rpc('sun_is_platform_admin'):null; if(!admin||admin.error||admin.data!==true)throw new Error('Техническое подключение доступно только разработчику.'); config.url=String(url||'').trim().replace(/\/$/,'');config.key=String(key||'').trim();saveConfig(); if(!config.url||!config.key)throw new Error('Введите Project URL и Publishable key.'); client=null;clientSignature='';session=null;workspace=null;memberships=[];supportMode=null; await connectFromConfig(false);return true; } function setAutoSyncDeveloper(enabled){config.autoSync=enabled!==false;saveConfig();if(config.autoSync&&workspace&&!supportMode)scheduleSync('автосинхронизация включена');renderCloudUI();return config.autoSync;} window.SunCloudV2={ VERSION, signOut:signOutAndReload, adoptCurrentLocalAsWorkspace, createTrialWorkspace, acceptInvite:acceptInviteToken, syncNow:()=>syncNow({quiet:false}), pull:()=>pullRemote({replace:true,quiet:false}), migrate:migrateLocalToCloud, hasPermission, roleLabel, getClient:()=>client, getSession:()=>session?clone(session):null, getWorkspace:()=>workspace?clone(workspace):null, getClientId:()=>clientId(), enterSupportWorkspace, refreshSupportWorkspace, exitSupportWorkspace, isSupportMode:()=>Boolean(supportMode), getSupportMode:()=>supportMode?clone(supportMode):null, getTechnicalConfig:()=>({url:config.url,key:config.key,autoSync:config.autoSync,lastSync:config.lastSync,workspaceId:config.workspaceId,localWorkspaceId:config.localWorkspaceId}), setTechnicalConnection, setAutoSyncDeveloper, snapshotLocal:()=>collectLocalPayload(), reloadMemberships:async()=>{await loadMemberships();renderCloudUI();return workspace?clone(workspace):null;}, status:()=>({connected:Boolean(client),signedIn:Boolean(session),supportMode:supportMode?clone(supportMode):null,workspace:workspace?clone(workspace):null,membershipsLoading,membershipsLoaded,membershipCount:memberships.length,dirty,lastStatus,lastError}) }; async function boot(){ injectStyles();disableLegacyCloud();installStorageTracking();hookEnterpriseSchedule();observeSettings();updatePill(); if(config.url&&config.key)await connectFromConfig(true);else setStatus('local','Облако не подключено. Откройте Настройки → Облако Supabase.'); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); ; /* ===== MODULE: admin-rbac-v3.js ===== */ (() => { 'use strict'; if (window.SunAdminRBACV3) return; const VERSION = '2026.09.06-admin-rbac-v7-granular-admins'; const $ = id => document.getElementById(id); const qa = (s,r=document) => [...r.querySelectorAll(s)]; const esc=window.SunSafe.escapeHTML; const toast = (text,type='info',timeout=4500) => { try { if (window.SunEnterprise?.toast) return window.SunEnterprise.toast(text,type,timeout); } catch (_) {} alert(text); }; const ROLE_LABELS = {admin:'Администратор',manager:'Менеджер',kitchen:'Кухня',courier:'Курьер',viewer:'Только просмотр'}; const GROUPS = [ {title:'Заказы', items:[['orders.view','Просмотр заказов'],['orders.create','Создание заказов'],['orders.edit','Изменение заказов'],['orders.delete','Удаление заказов'],['calendar.view','Календарь'],['map.view','Карта']]}, {title:'Клиенты и каталог', items:[['clients.view','Просмотр клиентов'],['clients.edit','Изменение клиентов'],['catalog.view','Просмотр каталога'],['catalog.edit','Изменение каталога']]}, {title:'Производство и доставка', items:[['production.view','Просмотр производства'],['production.edit','Изменение производства'],['shopping.view','Просмотр закупок'],['shopping.edit','Изменение закупок'],['stock.view','Просмотр склада'],['stock.edit','Изменение склада'],['routes.view','Просмотр маршрутов'],['routes.edit','Изменение маршрутов']]}, {title:'Управление', items:[['mailings.view','Просмотр рассылок'],['mailings.edit','Изменение рассылок'],['money.view','Просмотр денег'],['money.edit','Изменение денег'],['stats.view','Статистика'],['team.view','Просмотр команды'],['team.edit','Изменение команды'],['suppliers.view','Просмотр поставщиков'],['suppliers.edit','Изменение поставщиков'],['print.view','Печать']]}, {title:'Администрирование', items:[['settings.view','Просмотр настроек'],['settings.edit','Изменение настроек'],['users.manage','Пользователи и права'],['audit.view','История изменений'],['backups.manage','Резервные копии']]} ]; const PRESETS = { admin: Object.fromEntries(GROUPS.flatMap(g=>g.items).map(([k])=>[k,true])), manager: { 'orders.view':true,'orders.create':true,'orders.edit':true,'orders.delete':false,'calendar.view':true,'map.view':true, 'clients.view':true,'clients.edit':true,'catalog.view':true,'catalog.edit':false, 'production.view':false,'production.edit':false,'shopping.view':false,'shopping.edit':false,'stock.view':false,'stock.edit':false,'routes.view':true,'routes.edit':false, 'mailings.view':true,'mailings.edit':true,'money.view':false,'money.edit':false,'stats.view':true,'team.view':true,'team.edit':false,'suppliers.view':false,'suppliers.edit':false,'print.view':true, 'settings.view':false,'settings.edit':false,'users.manage':false,'audit.view':false,'backups.manage':false }, kitchen: { 'orders.view':true,'orders.create':false,'orders.edit':false,'orders.delete':false,'calendar.view':true,'map.view':false, 'clients.view':false,'clients.edit':false,'catalog.view':true,'catalog.edit':false, 'production.view':true,'production.edit':true,'shopping.view':true,'shopping.edit':false,'stock.view':true,'stock.edit':true,'routes.view':false,'routes.edit':false, 'mailings.view':false,'mailings.edit':false,'money.view':false,'money.edit':false,'stats.view':false,'team.view':true,'team.edit':false,'suppliers.view':false,'suppliers.edit':false,'print.view':true, 'settings.view':false,'settings.edit':false,'users.manage':false,'audit.view':false,'backups.manage':false }, courier: { 'orders.view':true,'orders.create':false,'orders.edit':false,'orders.delete':false,'calendar.view':true,'map.view':true, 'clients.view':false,'clients.edit':false,'catalog.view':false,'catalog.edit':false, 'production.view':false,'production.edit':false,'shopping.view':false,'shopping.edit':false,'stock.view':false,'stock.edit':false,'routes.view':true,'routes.edit':true, 'mailings.view':false,'mailings.edit':false,'money.view':false,'money.edit':false,'stats.view':false,'team.view':false,'team.edit':false,'suppliers.view':false,'suppliers.edit':false,'print.view':false, 'settings.view':false,'settings.edit':false,'users.manage':false,'audit.view':false,'backups.manage':false }, viewer: { 'orders.view':true,'orders.create':false,'orders.edit':false,'orders.delete':false,'calendar.view':true,'map.view':true, 'clients.view':true,'clients.edit':false,'catalog.view':true,'catalog.edit':false, 'production.view':false,'production.edit':false,'shopping.view':false,'shopping.edit':false,'stock.view':false,'stock.edit':false,'routes.view':false,'routes.edit':false, 'mailings.view':false,'mailings.edit':false,'money.view':false,'money.edit':false,'stats.view':true,'team.view':false,'team.edit':false,'suppliers.view':false,'suppliers.edit':false,'print.view':true, 'settings.view':false,'settings.edit':false,'users.manage':false,'audit.view':false,'backups.manage':false } }; let members = []; let editing = null; let inviting = false; let applying = false; let lastWorkspaceId = ''; function cloud(){ return window.SunCloudV2 || null; } function workspace(){ return cloud()?.getWorkspace?.() || null; } function session(){ return cloud()?.getSession?.() || null; } function client(){ return cloud()?.getClient?.() || null; } function has(p){ const c=cloud(); return c?.hasPermission ? c.hasPermission(p) : false; } function currentPermissions(){ return workspace()?.permissions || {}; } function normalizeLegacyLocalAuth(){ try{ const raw=localStorage.getItem('sunEnterpriseSettingsV1'); if(!raw)return; const s=JSON.parse(raw)||{}; if(s.rolesEnabled){s.rolesEnabled=false;localStorage.setItem('sunEnterpriseSettingsV1',JSON.stringify(s));} }catch(_){} } function installStyle(){ if($('sun-admin-rbac-style'))return; const style=document.createElement('style');style.id='sun-admin-rbac-style';style.textContent=` #sun-cloud-users-modal .dialog{max-width:980px;width:min(980px,calc(100vw - 24px));max-height:92vh;overflow:auto} .sun-rbac-toolbar{display:flex;gap:8px;align-items:center;justify-content:space-between;flex-wrap:wrap;margin:8px 0 12px} .sun-rbac-members{display:grid;gap:8px}.sun-rbac-member{display:grid;grid-template-columns:minmax(220px,1.4fr) minmax(150px,.7fr) auto;gap:10px;align-items:center;border:1px solid #dfe5e8;border-radius:10px;padding:10px 12px;background:#fff} .sun-rbac-member small{display:block;color:#75808a;margin-top:3px}.sun-rbac-off{opacity:.58}.sun-rbac-perm-groups{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:12px}.sun-rbac-group{border:1px solid #dfe5e8;border-radius:10px;padding:10px;background:#fafcfc}.sun-rbac-group h4{margin:0 0 8px;color:#17384d}.sun-rbac-check{display:flex!important;flex-direction:row!important;align-items:center!important;gap:8px!important;margin:6px 0!important}.sun-rbac-check input{width:17px!important;height:17px!important;flex:0 0 auto}.sun-rbac-role-line{display:grid;grid-template-columns:1.2fr 1fr auto;gap:10px;align-items:end}.sun-rbac-danger{margin-left:auto}.sun-rbac-section-title{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:18px 0 8px}.sun-rbac-section-title h3{margin:0;color:#17384d;font-size:15px}.sun-rbac-invite{display:grid;grid-template-columns:minmax(190px,1.2fr) minmax(130px,.65fr) auto;gap:10px;align-items:center;border:1px dashed #cfd9df;border-radius:10px;padding:10px 12px;background:#fbfcfc}.sun-rbac-invite small{display:block;color:#75808a;margin-top:3px}.sun-rbac-invite-form{border:1px solid #dfe5e8;border-radius:12px;padding:14px;background:#fbfcfc}.sun-rbac-invite-grid{display:grid;grid-template-columns:1.2fr 1.5fr 1fr;gap:10px}.sun-rbac-linkbox{margin-top:12px;padding:10px;border-radius:9px;background:#f1f5f6;word-break:break-all;font:600 12px/1.45 ui-monospace,monospace}.sun-rbac-lock-note{font-size:12px;color:#6e7880;margin-top:6px}.sun-cloud-identity-v3{font-size:12px;color:#adc0cc;padding:3px 7px}.sun-cloud-pin-card{border-top:1px solid #e2e7e9;margin-top:10px;padding-top:10px} body.sun-cloud-auth-required .view,body.sun-cloud-auth-required header{filter:blur(2px);pointer-events:none;user-select:none}.sun-cloud-auth-gate{position:fixed;inset:0;z-index:10000;background:#132f44eb;display:grid;place-items:center;padding:20px}.sun-cloud-auth-card{width:min(430px,100%);background:#fff;border-radius:16px;padding:22px;box-shadow:0 24px 80px #0005}.sun-cloud-auth-brand{display:flex;align-items:center;gap:12px;margin-bottom:16px}.sun-cloud-auth-brand img{width:58px;height:58px;object-fit:contain}.sun-cloud-auth-card h2{margin:0;color:#17384d}.sun-cloud-auth-card label{display:block;margin:10px 0}.sun-cloud-auth-card input{width:100%}.sun-auth-password{position:relative}.sun-auth-password input{padding-right:46px}.sun-auth-eye{position:absolute;right:7px;bottom:6px;width:34px;height:34px;border:0;background:transparent;border-radius:8px;cursor:pointer;font-size:17px;color:#536674}.sun-auth-eye:hover{background:#eef2f3}.sun-auth-switch{margin:14px 0 0;text-align:center;font-size:13px}.sun-auth-switch button{border:0;background:transparent;color:#245c7c;font-weight:800;cursor:pointer;text-decoration:underline;text-underline-offset:3px}.sun-cloud-auth-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}.sun-cloud-auth-error{color:#9a3838;font-size:12px;margin-top:8px;min-height:18px}.sun-auth-mode-tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px;background:#f2f4f5;border-radius:11px;padding:4px;margin:10px 0 14px}.sun-auth-mode-tabs button{border:0;border-radius:8px;padding:9px 10px;background:transparent;font-weight:800;cursor:pointer}.sun-auth-mode-tabs button.on{background:#fff;box-shadow:0 2px 10px #0001;color:#17384d}.sun-auth-trial{background:#eef8f2;color:#286447;border-radius:10px;padding:10px 11px;font-size:12px;font-weight:700;margin:10px 0}.sun-auth-success{background:#eef8f2;color:#286447;border-radius:10px;padding:10px 11px;font-size:12px;margin-top:10px} @media(max-width:760px){.sun-rbac-perm-groups{grid-template-columns:1fr}.sun-rbac-member,.sun-rbac-invite{grid-template-columns:1fr}.sun-rbac-role-line,.sun-rbac-invite-grid{grid-template-columns:1fr}} `;document.head.appendChild(style); } function navPermission(label){ const map={ 'Главная':'app.read','Новый заказ':'orders.create','Заказы':'orders.view','Календарь':'calendar.view','Карта':'map.view', 'Производство':'production.view','Закупки':'shopping.view','Склад':'stock.view','Клиенты':'clients.view','Рассылки':'mailings.view', 'Деньги':'money.view','Команда':'team.view','Поставщики':'suppliers.view','Статистика':'stats.view','Печать':'print.view','Маршруты':'routes.view','Настройки':'settings.view' }; return map[label] || null; } function canSeeSettings(){return has('settings.view')||has('users.manage')||has('backups.manage')||has('audit.view');} function applyNavPermissions(){ const ws=workspace(), ss=session(); if(!ws||!ss?.user)return; qa('header nav button').forEach(btn=>{ const label=String(btn.dataset.navLabel||btn.textContent||'').trim(); let allowed=true; if(label==='Настройки')allowed=canSeeSettings(); else {const perm=navPermission(label);if(perm)allowed=has(perm);} btn.hidden=!allowed;btn.style.display=allowed?'':'none'; }); const label=$('sunCurrentUserLabel'); if(label)label.textContent=`${ws.display_name||ss.user.email||'Пользователь'} · ${ROLE_LABELS[ws.role]||ws.role}`; const logout=$('sunLogoutBtn'); if(logout){logout.style.display='flex';logout.onclick=async()=>{if(window.SunCloudV2?.signOut)return window.SunCloudV2.signOut();try{await client()?.auth.signOut();}catch(_){}location.reload();};} applyActionPermissions(); purgeSensitiveLocalData(); } function applyActionPermissions(){ const del=$('deleteOrderBtn');if(del)del.style.display=(del.style.display==='none'&&!draftIdSafe())?'none':(has('orders.delete')?'inline-block':'none'); qa('#orders [data-sun-delete-order],#orders button').forEach(b=>{if(/удал/i.test(b.textContent||''))b.style.display=has('orders.delete')?'':'none';}); const save=qa('#new button').find(b=>(b.textContent||'').trim()==='Сохранить');if(save){const existing=draftIdSafe();save.disabled=existing?!has('orders.edit'):!has('orders.create');save.title=save.disabled?'Недостаточно прав':'';} qa('#new .catalog-head button').forEach(b=>{if((b.textContent||'').trim()==='Настроить')b.style.display=has('catalog.edit')?'':'none';}); qa('#manager .primary,#editor .primary,#editor .danger').forEach(b=>{b.disabled=!has('catalog.edit');}); } function draftIdSafe(){try{return Boolean(window.draft?.id||draft?.id);}catch(_){return false;}} function purgeSensitiveLocalData(){ const rules=[ ['sunFinanceRecordsV2',()=>has('money.view')||has('money.edit')], ['sunAuditLogV1',()=>has('audit.view')], ['sunSuppliers',()=>has('suppliers.view')||has('suppliers.edit')||has('shopping.view')], ['sunStockMoves',()=>has('stock.view')||has('stock.edit')||has('shopping.view')||has('production.view')], ['sunStock',()=>has('stock.view')||has('stock.edit')||has('shopping.view')||has('production.view')], ['sunEmployees',()=>has('team.view')||has('team.edit')||has('production.view')||has('routes.view')], ['sunClientCommunicationV1',()=>has('clients.view')||has('clients.edit')||has('orders.create')||has('orders.edit')], ['sunClientLoyaltyV1',()=>has('clients.view')||has('clients.edit')||has('orders.create')||has('orders.edit')] ]; for(const [key,ok] of rules){if(!ok())try{localStorage.removeItem(key);}catch(_){}} } function guardGlobal(name, permission, mode){ const fn=window[name];if(typeof fn!=='function'||fn.__sunRbacGuard)return; const wrapped=function(...args){ let perm=permission; if(typeof permission==='function')perm=permission(...args); if(perm&&!has(perm)){toast('У вас нет прав для этого действия.','warn');return;} return fn.apply(this,args); }; wrapped.__sunRbacGuard=true;wrapped.__sunOriginal=fn;window[name]=wrapped; } function installGuards(){ guardGlobal('saveOrder',()=>draftIdSafe()?'orders.edit':'orders.create'); guardGlobal('deleteOrder','orders.delete'); guardGlobal('deleteOrderById','orders.delete'); guardGlobal('saveBox','catalog.edit'); guardGlobal('removeBox','catalog.edit'); guardGlobal('editBox','catalog.edit'); guardGlobal('writeOffOrderStock','stock.edit'); guardGlobal('sunEditSupplier','suppliers.edit'); guardGlobal('editStockProduct','stock.edit'); } function hideLegacyRoleCard(){ const view=$('enterprise-settings');if(!view)return; qa('section',view).filter(s=>(s.querySelector(':scope > h2')?.textContent||'').trim()==='Пользователи и роли').forEach(s=>s.remove()); if(!has('backups.manage'))qa('section',view).filter(s=>(s.querySelector(':scope > h2')?.textContent||'').includes('Резервное копирование')).forEach(s=>s.style.display='none'); if(!has('audit.view'))qa('section',view).filter(s=>(s.querySelector(':scope > h2')?.textContent||'').includes('История изменений')).forEach(s=>s.style.display='none'); } function ensureModal(){ if($('sun-cloud-users-modal'))return; const modal=document.createElement('div');modal.id='sun-cloud-users-modal';modal.className='modal';modal.innerHTML=`

    Пользователи и права

    `;document.body.appendChild(modal); modal.addEventListener('click',e=>{if(e.target===modal||e.target.closest('[data-rbac-close]'))closeModal();}); } function openModal(){ensureModal();$('sun-cloud-users-modal').classList.add('on');loadMembers();} function closeModal(){$('sun-cloud-users-modal')?.classList.remove('on');editing=null;inviting=false;} async function loadMembers(){ const c=client(),ws=workspace(),body=$('sunRbacBody');if(!c||!ws||!body)return; body.innerHTML='

    Загружаю сотрудников…

    '; try{ const memberRes=await c.rpc('sun_list_workspace_members',{p_workspace:ws.id}); if(memberRes.error)throw memberRes.error; members=memberRes.data||[];renderMembers(); }catch(e){body.innerHTML=`

    ${esc(e.message||e)}

    `;} } async function copyText(value,success='Данные скопированы.'){ try{await navigator.clipboard.writeText(String(value||''));toast(success,'success');} catch(_){prompt('Скопируйте данные:',String(value||''));} } function renderMembers(){ const body=$('sunRbacBody');if(!body)return; if(editing){renderEditor();return;}if(inviting){renderEmployeeForm();return;} const active=members.map(m=>`
    ${esc(m.display_name||m.email||'Сотрудник')}${esc(m.email||'')} · ${m.is_active?'активен':'доступ отключён'}
    ${esc(ROLE_LABELS[m.role]||m.role)}
    `).join('')||'

    Сотрудников пока нет.

    '; body.innerHTML=`
    ${esc(workspace()?.name||'Рабочая база')}
    Создайте сотрудника здесь. Новый сотрудник получит временный пароль для первого входа.

    Сотрудники

    ${members.filter(m=>m.is_active).length}
    ${active}
    `; $('sunRbacAddUser').onclick=()=>{inviting=true;renderEmployeeForm();};$('sunRbacReload').onclick=loadMembers; qa('[data-rbac-edit]',body).forEach(b=>b.onclick=()=>{editing=members.find(m=>String(m.user_id)===String(b.dataset.rbacEdit));renderEditor();}); } function renderEmployeeForm(){ const body=$('sunRbacBody');if(!body)return; body.innerHTML=`
    Сотруднику не нужна отдельная ссылка-приглашение.

    Добавить сотрудника

    Если аккаунта ещё нет, Caterium создаст его и покажет временный пароль. Если аккаунт уже существует, он просто будет добавлен в эту компанию.

    `; const back=()=>{inviting=false;renderMembers();};$('sunRbacEmployeeBack').onclick=back;$('sunRbacEmployeeCancel').onclick=back;$('sunRbacCreateEmployee').onclick=createEmployeeV28; } async function createEmployeeV28(){ const c=client(),ws=workspace(),btn=$('sunRbacCreateEmployee');if(!c||!ws||!btn)return; const name=String($('sunRbacEmployeeName')?.value||'').trim(),email=String($('sunRbacEmployeeEmail')?.value||'').trim(),role=String($('sunRbacEmployeeRole')?.value||'manager'); if(!name)return toast('Введите имя сотрудника.','warn'); if(!email)return toast('Введите email сотрудника.','warn'); btn.disabled=true;btn.textContent='Создаю…'; try{ const prep=await c.rpc('sun_employee_prepare_v28',{p_workspace:ws.id,p_email:email,p_display_name:name,p_role:role});if(prep.error)throw prep.error; let result=prep.data||{}; if(result.status==='already_member'){ toast('Этот пользователь уже добавлен в компанию.','warn');btn.disabled=false;btn.textContent='Создать сотрудника';return; } if(result.status==='existing'){ const fin=await c.rpc('sun_employee_finalize_v28',{p_workspace:ws.id,p_user_id:result.user_id,p_display_name:name,p_role:role});if(fin.error)throw fin.error; result={...(fin.data||{}),created:false}; }else{ const call=await c.functions.invoke('caterium-create-employee',{body:{workspace_id:ws.id,email,display_name:name,role}});if(call.error)throw call.error; if(call.data?.error)throw new Error(call.data.error); result=call.data||{}; if(result.status==='existing'&&result.user_id){ const fin=await c.rpc('sun_employee_finalize_v28',{p_workspace:ws.id,p_user_id:result.user_id,p_display_name:name,p_role:role});if(fin.error)throw fin.error; result={...(fin.data||{}),created:false}; } } const host=$('sunRbacEmployeeResult'); if(result.created&&result.temporary_password){ const credentials=`Caterium\nEmail: ${email}\nВременный пароль: ${result.temporary_password}`; host.innerHTML=`
    Сотрудник создан.
    Передайте ему данные для первого входа:

    При первом входе Caterium попросит сотрудника придумать свой новый пароль.

    `; $('sunRbacCopyEmployee').onclick=()=>copyText(credentials,'Логин и временный пароль скопированы.'); }else{ host.innerHTML=`
    Сотрудник добавлен.
    Аккаунт ${esc(email)} уже существовал в Caterium. Сотрудник входит своим обычным паролем.
    `; } $('sunRbacEmployeeDone').onclick=async()=>{inviting=false;await loadMembers();}; toast('Сотрудник добавлен.','success'); }catch(e){toast(e.message||String(e),'error',7000);btn.disabled=false;btn.textContent='Создать сотрудника';} } function permissionHtml(perms, role){ return GROUPS.map(g=>`

    ${esc(g.title)}

    ${g.items.map(([key,label])=>{const checked=typeof perms?.[key]==='boolean'?perms[key]:(role==='admin');return ``;}).join('')}
    `).join(''); } function renderEditor(){ const body=$('sunRbacBody'),m=editing;if(!body||!m)return; const perms=Object.assign({},PRESETS[m.role]||PRESETS.viewer,m.permissions||{}); const adminCount=members.filter(x=>x.role==='admin'&&x.is_active).length; body.innerHTML=`
    ${esc(m.email||'')}
    ${permissionHtml(perms,m.role)}

    Активных администраторов: ${adminCount}. Ограничение срабатывает только если после изменения не останется ни одного активного администратора. Хотя бы у одного активного администратора должно оставаться право «Пользователи и права».

    `; $('sunRbacBack').onclick=()=>{editing=null;renderMembers();}; $('sunRbacRole').onchange=()=>{ const role=$('sunRbacRole').value; $('sunRbacPerms').innerHTML=permissionHtml(PRESETS[role]||PRESETS.viewer,role); }; $('sunRbacSave').onclick=saveMember; $('sunRbacRemove').onclick=removeMember; } function readEditorPermissions(){ const out={'app.read':true}; qa('[data-rbac-perm]',$('sunRbacPerms')).forEach(i=>out[i.dataset.rbacPerm]=i.checked); return out; } async function saveMember(){ const c=client(),ws=workspace(),m=editing;if(!c||!ws||!m)return; const btn=$('sunRbacSave');btn.disabled=true; try{ const {error}=await c.rpc('sun_admin_update_member',{p_workspace:ws.id,p_user:m.user_id,p_display_name:$('sunRbacName').value.trim(),p_role:$('sunRbacRole').value,p_is_active:$('sunRbacActive').checked,p_permissions:readEditorPermissions()}); if(error)throw error; toast('Права пользователя сохранены.','success');editing=null; await cloud()?.reloadMemberships?.(); applyNavPermissions(); if(has('users.manage'))await loadMembers();else closeModal(); }catch(e){toast(e.message||String(e),'error',7000);}finally{if(btn)btn.disabled=false;} } async function removeMember(){ const c=client(),ws=workspace(),m=editing;if(!c||!ws||!m)return; if(!confirm(`Удалить доступ пользователю ${m.display_name||m.email||''}?`))return; try{const {error}=await c.rpc('sun_admin_remove_member',{p_workspace:ws.id,p_user:m.user_id});if(error)throw error;toast('Доступ удалён.','success');editing=null;await cloud()?.reloadMemberships?.();applyNavPermissions();if(has('users.manage'))await loadMembers();else closeModal();} catch(e){toast(e.message||String(e),'error',7000);} } const hex=bytes=>[...bytes].map(x=>x.toString(16).padStart(2,'0')).join(''); const unhex=value=>new Uint8Array(String(value||'').match(/.{1,2}/g)?.map(x=>parseInt(x,16))||[]); async function pinDigest(pin,salt){ const raw=new TextEncoder().encode(String(pin||'')); if(crypto?.subtle){ const key=await crypto.subtle.importKey('raw',raw,'PBKDF2',false,['deriveBits']); const bits=await crypto.subtle.deriveBits({name:'PBKDF2',hash:'SHA-256',salt,iterations:120000},key,256); return hex(new Uint8Array(bits)); } let v=2166136261;for(let n=0;n<5000;n++)for(const b of [...raw,...salt]){v^=b;v=Math.imul(v,16777619);}return String(v>>>0); } async function makePinRecord(pin){const salt=crypto.getRandomValues(new Uint8Array(16));return `v1:${hex(salt)}:${await pinDigest(pin,salt)}`;} async function verifyPin(pin,record){const parts=String(record||'').split(':');if(parts.length!==3||parts[0]!=='v1')return false;const salt=unhex(parts[1]);return (await pinDigest(pin,salt))===parts[2];} function pinKey(){const id=session()?.user?.id;return id?`sunCloudQuickPinV3:${id}`:'';} function pinUnlockKey(){const id=session()?.user?.id;return id?`sunCloudQuickPinUnlockedV3:${id}`:'';} async function setQuickPin(){ const id=session()?.user?.id;if(!id)return; const p1=prompt('Введите новый PIN (4–8 цифр):','');if(p1===null)return;if(!/^\d{4,8}$/.test(p1))return toast('PIN должен содержать 4–8 цифр.','warn'); const p2=prompt('Повторите PIN:','');if(p1!==p2)return toast('PIN-коды не совпадают.','warn'); localStorage.setItem(pinKey(),await makePinRecord(p1));sessionStorage.setItem(pinUnlockKey(),'1');toast('Быстрый PIN включён на этом устройстве.','success');injectQuickPinCard(); } function removeQuickPin(){const key=pinKey();if(!key)return;localStorage.removeItem(key);sessionStorage.removeItem(pinUnlockKey());toast('Быстрый PIN отключён.','success');injectQuickPinCard();} function injectQuickPinCard(){ const card=$('sunCloudV2Card');if(!card||!session()?.user)return; let box=$('sunCloudQuickPinCardV3');if(!box){box=document.createElement('div');box.id='sunCloudQuickPinCardV3';box.className='sun-cloud-v2-box wide sun-cloud-pin-card';card.appendChild(box);} const enabled=Boolean(pinKey()&&localStorage.getItem(pinKey())); box.innerHTML=`

    Быстрый вход на этом устройстве

    Основной аккаунт — email и пароль. PIN только быстро разблокирует уже авторизованное устройство и не меняет облачные права.

    ${enabled?'':''}
    `; $('sunSetQuickPinV3').onclick=setQuickPin;$('sunRemoveQuickPinV3')?.addEventListener('click',removeQuickPin); } function showPinLockIfNeeded(){ const ss=session(),ws=workspace();if(!ss?.user||!ws)return; const key=pinKey(), unlock=pinUnlockKey();if(!key||!localStorage.getItem(key)||sessionStorage.getItem(unlock)==='1'||$('sunCloudPinLockV3'))return; const overlay=document.createElement('div');overlay.id='sunCloudPinLockV3';overlay.className='sun-cloud-auth-gate';overlay.innerHTML=`
    Caterium

    Caterium

    ${esc(ws.display_name||ss.user.email||'Пользователь')} · ${esc(ROLE_LABELS[ws.role]||ws.role)}
    `;document.body.appendChild(overlay); const unlockFn=async()=>{const v=$('sunCloudPinInputV3').value;if(await verifyPin(v,localStorage.getItem(key))){sessionStorage.setItem(unlock,'1');overlay.remove();applyNavPermissions();}else $('sunCloudPinErrorV3').textContent='Неверный PIN.';}; $('sunCloudPinUnlockV3').onclick=unlockFn;$('sunCloudPinInputV3').addEventListener('keydown',e=>{if(e.key==='Enter')unlockFn();});$('sunCloudUsePasswordV3').onclick=async()=>{if(window.SunCloudV2?.signOut)return window.SunCloudV2.signOut();try{await client()?.auth.signOut();}catch(_){}location.reload();};setTimeout(()=>$('sunCloudPinInputV3')?.focus(),50); } const PENDING_REGISTRATION_KEY='sunPendingRegistrationV23'; let registrationProvisioning=false; function savePendingRegistration(email,companyName){try{localStorage.setItem(PENDING_REGISTRATION_KEY,JSON.stringify({email:String(email||'').trim().toLowerCase(),companyName:String(companyName||'').trim()||'Новая компания',createdAt:new Date().toISOString()}));}catch(_){}} function getPendingRegistration(email=''){try{const raw=JSON.parse(localStorage.getItem(PENDING_REGISTRATION_KEY)||'null');if(!raw?.email)return null;if(email&&String(raw.email).toLowerCase()!==String(email).trim().toLowerCase())return null;return raw}catch(_){return null}} function clearPendingRegistration(){try{localStorage.removeItem(PENDING_REGISTRATION_KEY)}catch(_){}} async function finishPendingRegistration(gate,email){ const pending=getPendingRegistration(email);if(!pending||registrationProvisioning)return false; registrationProvisioning=true;const err=gate?.querySelector('#sunGateErrorV3');if(err)err.textContent='Создаю вашу компанию…'; try{const ws=await cloud()?.createTrialWorkspace?.(pending.companyName||'Новая компания');if(!ws)throw new Error('Не удалось создать компанию.');clearPendingRegistration();if(err)err.textContent='Готово. Открываю Caterium…';setTimeout(async()=>{gate?.remove();document.body.classList.remove('sun-cloud-auth-required');try{await cloud()?.pull?.()}catch(_){}applyNavPermissions();},350);return true;} catch(e){if(err)err.textContent=String(e?.message||e||'Не удалось завершить регистрацию.');return false} finally{registrationProvisioning=false} } const INVITE_QUERY_KEY='invite'; let invitePreviewCache=null; let invitePreviewLoading=false; function currentInviteToken(){try{return String(new URL(location.href).searchParams.get(INVITE_QUERY_KEY)||'').trim()}catch(_){return ''}} function clearInviteFromUrl(){try{const u=new URL(location.href);u.searchParams.delete(INVITE_QUERY_KEY);history.replaceState(null,'',u.toString())}catch(_){}} function passwordField(id,label,autocomplete='current-password'){ return ``; } function bindPasswordEyes(root){qa('[data-toggle-password]',root).forEach(b=>b.onclick=()=>{const i=root.querySelector(`#${b.dataset.togglePassword}`);if(!i)return;i.type=i.type==='password'?'text':'password';b.textContent=i.type==='password'?'◉':'×';b.setAttribute('aria-label',i.type==='password'?'Показать пароль':'Скрыть пароль');});} async function getInvitePreview(token){ if(!token)return null;if(invitePreviewCache?.token===token)return invitePreviewCache.data;if(invitePreviewLoading)return null; invitePreviewLoading=true;try{const c=client();if(!c)return null;const {data,error}=await c.rpc('sun_invite_preview_v27',{p_token:token});if(error)throw error;const row=Array.isArray(data)?data[0]:data;invitePreviewCache={token,data:row||null};return row||null;}finally{invitePreviewLoading=false;} } async function finishInvite(token,gate){ const err=gate?.querySelector('#sunGateErrorV3');if(err)err.textContent='Добавляю вас в компанию…'; try{const ws=await cloud()?.acceptInvite?.(token);if(!ws)throw new Error('Не удалось присоединиться к компании.');clearInviteFromUrl();invitePreviewCache=null;gate?.remove();document.body.classList.remove('sun-cloud-auth-required');try{await cloud()?.pull?.()}catch(_){}applyNavPermissions();toast(`Вы присоединились к компании «${ws.name||'Компания'}».`,'success',6500);return true;} catch(e){if(err)err.textContent=String(e?.message||e||'Не удалось принять приглашение.');return false;} } async function renderInviteGate(gate,token){ let preview; try{preview=await getInvitePreview(token);}catch(e){gate.innerHTML=`
    Caterium

    Приглашение недоступно

    Caterium

    ${esc(e?.message||e||'Не удалось проверить приглашение.')}

    `;gate.querySelector('#sunInviteGoHome').onclick=()=>{clearInviteFromUrl();gate.remove();ensureAuthGate();};return;} if(!preview||!preview.is_valid){gate.innerHTML=`
    Caterium

    Приглашение недействительно

    Ссылка истекла, отменена или уже использована.
    `;gate.querySelector('#sunInviteGoHome').onclick=()=>{clearInviteFromUrl();gate.remove();ensureAuthGate();};return;} const ss=session(),signedEmail=String(ss?.user?.email||'').toLowerCase(),inviteEmail=String(preview.email||'').toLowerCase(); if(ss?.user){ if(signedEmail===inviteEmail){gate.innerHTML=`
    Caterium

    Приглашение в ${esc(preview.workspace_name||'компанию')}

    ${esc(preview.display_name||preview.email||'Сотрудник')} · ${esc(ROLE_LABELS[preview.role]||preview.role)}

    Вы вошли как ${esc(ss.user.email||'')}. Нажмите кнопку, чтобы добавить эту компанию в ваш аккаунт.

    `;gate.querySelector('#sunInviteAcceptSigned').onclick=()=>finishInvite(token,gate);gate.querySelector('#sunInviteSignOut').onclick=async()=>{try{await window.SunCloudV2?.signOut?.()}catch(_){}};return;} gate.innerHTML=`
    Caterium

    Приглашение в ${esc(preview.workspace_name||'компанию')}

    Для ${esc(preview.email||'другого email')}

    Сейчас вы вошли как ${esc(ss.user.email||'')}. Для принятия приглашения нужно войти под адресом ${esc(preview.email||'')}.

    `;gate.querySelector('#sunInviteSignOut').onclick=async()=>{try{await window.SunCloudV2?.signOut?.()}catch(_){}};return; } gate.innerHTML=`
    Caterium

    Вас пригласили в ${esc(preview.workspace_name||'компанию')}

    Роль: ${esc(ROLE_LABELS[preview.role]||preview.role)}
    ${passwordField('sunInvitePasswordV27','Пароль','new-password')}${passwordField('sunInvitePassword2V27','Подтвердите пароль','new-password')}

    Если аккаунт с этим email уже есть — введите его пароль. Если аккаунта ещё нет — придумайте новый пароль и повторите его.

    `; bindPasswordEyes(gate);const btn=gate.querySelector('#sunInviteJoinV27');const run=async()=>{const c=client(),email=String(preview.email||'').trim(),name=String(gate.querySelector('#sunInviteNameV27')?.value||'').trim(),password=String(gate.querySelector('#sunInvitePasswordV27')?.value||''),password2=String(gate.querySelector('#sunInvitePassword2V27')?.value||''),err=gate.querySelector('#sunGateErrorV3');if(password.length<6){err.textContent='Пароль должен содержать минимум 6 символов.';return;}if(password!==password2){err.textContent='Пароли не совпадают.';return;}btn.disabled=true;err.textContent='Проверяю аккаунт…';try{let r=await c.auth.signInWithPassword({email,password});if(r.error){r=await c.auth.signUp({email,password,options:{data:{name,registration_source:'caterium_invite_signup'}}});if(r.error)throw r.error;if(!r.data.session){const retry=await c.auth.signInWithPassword({email,password});if(retry.error)throw new Error('Этот email уже зарегистрирован. Введите пароль от существующего аккаунта.');r=retry;}}const userId=r.data.user?.id||r.data.session?.user?.id||'';if(userId)sessionStorage.setItem(`sunCloudQuickPinUnlockedV3:${userId}`,'1');err.textContent='Аккаунт готов. Подключаю компанию…';setTimeout(()=>finishInvite(token,gate),180);}catch(e){err.textContent=String(e?.message||e||'Не удалось войти или создать аккаунт.');btn.disabled=false;}};btn.onclick=run;gate.querySelector('#sunInvitePassword2V27').addEventListener('keydown',e=>{if(e.key==='Enter')run()}); } function mustChangePassword(user){return Boolean(user?.user_metadata?.must_change_password);} function showPasswordChangeGate(gate,c,user,onDone){ gate.innerHTML=`
    Caterium

    Создайте новый пароль

    Первый вход сотрудника

    Временный пароль сработал. Теперь придумайте свой постоянный пароль.

    ${passwordField('sunEmployeeNewPasswordV28','Новый пароль','new-password')}${passwordField('sunEmployeeNewPassword2V28','Подтвердите пароль','new-password')}
    `; bindPasswordEyes(gate); const run=async()=>{const p1=String(gate.querySelector('#sunEmployeeNewPasswordV28')?.value||''),p2=String(gate.querySelector('#sunEmployeeNewPassword2V28')?.value||''),err=gate.querySelector('#sunGateErrorV3'),btn=gate.querySelector('#sunEmployeeSavePasswordV28');if(p1.length<8){err.textContent='Новый пароль должен содержать минимум 8 символов.';return;}if(p1!==p2){err.textContent='Пароли не совпадают.';return;}btn.disabled=true;err.textContent='Сохраняю пароль…';try{const nextData={...(user?.user_metadata||{}),must_change_password:false};const r=await c.auth.updateUser({password:p1,data:nextData});if(r.error)throw r.error;err.textContent='Пароль сохранён.';setTimeout(()=>onDone?.(),120);}catch(e){err.textContent=String(e?.message||e||'Не удалось изменить пароль.');btn.disabled=false;}}; gate.querySelector('#sunEmployeeSavePasswordV28').onclick=run;gate.querySelector('#sunEmployeeNewPassword2V28').addEventListener('keydown',e=>{if(e.key==='Enter')run();}); } function ensureAuthGate(){ const st=cloud()?.status?.();if(!st?.connected)return; const ws=workspace(),ss=session(),inviteToken=currentInviteToken(); if(inviteToken){ let gate=$('sunCloudAuthGateV3');if(!gate){document.body.classList.add('sun-cloud-auth-required');gate=document.createElement('div');gate.id='sunCloudAuthGateV3';gate.className='sun-cloud-auth-gate';gate.innerHTML='

    Проверяю приглашение…

    ';document.body.appendChild(gate);renderInviteGate(gate,inviteToken);}return; } if(st.signedIn&&ws){$('sunCloudAuthGateV3')?.remove();document.body.classList.remove('sun-cloud-auth-required');return;} if($('sunCloudAuthGateV3')){if(st.signedIn&&st.membershipsLoading){const e=$('sunGateErrorV3');if(e)e.textContent='Загружаю рабочую базу…';}return;} document.body.classList.add('sun-cloud-auth-required'); const gate=document.createElement('div');gate.id='sunCloudAuthGateV3';gate.className='sun-cloud-auth-gate'; if(st.signedIn&&ss?.user&&!ws){ const pending=getPendingRegistration(ss.user.email||''); gate.innerHTML=`
    Caterium

    ${pending?'Создаю компанию':st.membershipsLoading?'Загружаю рабочую базу':'Аккаунт готов'}

    ${esc(ss.user.email||'Аккаунт авторизован')}

    ${pending?'Регистрация завершена. Сейчас подготовим вашу рабочую компанию.':st.membershipsLoading?'Проверяю доступы этого аккаунта на сервере.':'У этого аккаунта пока нет компании. Укажите название, чтобы создать её.'}

    ${!pending&&!st.membershipsLoading?'':''}
    ${pending?'Подготавливаю компанию…':st.membershipsLoading?'Загружаю рабочую базу…':''}
    `; document.body.appendChild(gate);if(pending&&!st.membershipsLoading)setTimeout(()=>finishPendingRegistration(gate,ss.user.email||''),80); gate.querySelector('#sunGateRetryWorkspaceV3').onclick=async()=>{const e=gate.querySelector('#sunGateErrorV3');if(getPendingRegistration(ss.user.email||''))return finishPendingRegistration(gate,ss.user.email||'');if(!st.membershipsLoading){const companyName=String(gate.querySelector('#sunGateRecoveryCompanyV25')?.value||'').trim();if(!companyName){e.textContent='Введите название компании.';return;}savePendingRegistration(ss.user.email||'',companyName);return finishPendingRegistration(gate,ss.user.email||'');}e.textContent='Проверяю доступ…';try{const found=await cloud()?.reloadMemberships?.();if(found){gate.remove();document.body.classList.remove('sun-cloud-auth-required');await cloud()?.pull?.();setTimeout(applyNavPermissions,100);}else e.textContent='Рабочая база для этого аккаунта не найдена.';}catch(err){e.textContent=String(err?.message||err||'Не удалось проверить доступ.');}}; gate.querySelector('#sunGateSignOutV3').onclick=async()=>{if(window.SunCloudV2?.signOut)return window.SunCloudV2.signOut();try{await client()?.auth.signOut();}catch(_){}location.reload();};return; } gate.innerHTML=`
    Caterium

    Вход в Caterium

    Введите данные своего аккаунта
    ${passwordField('sunGatePasswordV3','Пароль','current-password')}

    Нет аккаунта?

    `;document.body.appendChild(gate);bindPasswordEyes(gate); const emailInput=gate.querySelector('#sunGateEmailV3'),passwordInput=gate.querySelector('#sunGatePasswordV3'),password2Input=gate.querySelector('#sunGatePassword2V27'),companyInput=gate.querySelector('#sunGateCompanyV3'),submitBtn=gate.querySelector('#sunGateSubmitV3'),gateError=gate.querySelector('#sunGateErrorV3');let registerMode=false; const setMode=(registration)=>{registerMode=Boolean(registration);gate.querySelector('#sunGateRegisterFieldsV27').hidden=!registerMode;gate.querySelector('#sunGateConfirmWrapV27').hidden=!registerMode;gate.querySelector('#sunGateTitleV3').textContent=registerMode?'Создать аккаунт Caterium':'Вход в Caterium';gate.querySelector('#sunGateSubtitleV3').textContent=registerMode?'Заполните данные — после регистрации Caterium откроется автоматически':'Введите данные своего аккаунта';submitBtn.textContent=registerMode?'Создать аккаунт':'Войти';gate.querySelector('#sunGateSwitchTextV27').textContent=registerMode?'Уже есть аккаунт?':'Нет аккаунта?';gate.querySelector('#sunGateSwitchV27').textContent=registerMode?'Войти':'Создать аккаунт';passwordInput.autocomplete=registerMode?'new-password':'current-password';gateError.textContent='';if(registerMode)setTimeout(()=>companyInput.focus(),30);else setTimeout(()=>emailInput.focus(),30)}; async function auth(){const c=client(),email=emailInput.value.trim(),password=passwordInput.value,password2=password2Input.value,companyName=String(companyInput.value||'').trim();if(!c){gateError.textContent='Облачный сервис не подключён.';return;}if(registerMode&&!companyName){gateError.textContent='Введите название компании.';return;}if(!email||password.length<6){gateError.textContent='Введите email и пароль минимум из 6 символов.';return;}if(registerMode&&password!==password2){gateError.textContent='Пароли не совпадают.';return;}submitBtn.disabled=true;gateError.textContent=registerMode?'Создаю аккаунт…':'Выполняю вход…';try{let r;if(registerMode){savePendingRegistration(email,companyName);const existing=await c.auth.signInWithPassword({email,password});if(!existing.error&&existing.data.session){r=existing;}else{r=await c.auth.signUp({email,password,options:{data:{company_name:companyName,registration_source:'caterium_public_signup'}}});if(r.error)throw r.error;if(!r.data.session){const retry=await c.auth.signInWithPassword({email,password});if(retry.error){clearPendingRegistration();throw new Error('Этот email уже зарегистрирован. Войдите в аккаунт или восстановите пароль.');}r=retry;}}}else r=await c.auth.signInWithPassword({email,password});if(r.error)throw r.error;const authUser=r.data.user||r.data.session?.user||null;const userId=authUser?.id||'';if(userId)sessionStorage.setItem(`sunCloudQuickPinUnlockedV3:${userId}`,'1');if(!registerMode&&mustChangePassword(authUser)){showPasswordChangeGate(gate,c,authUser,()=>{gate.remove();document.body.classList.remove('sun-cloud-auth-required');setTimeout(()=>ensureAuthGate(),80);});return;}gateError.textContent=registerMode?'Аккаунт готов. Создаю компанию…':'Вход выполнен. Загружаю рабочую базу…';setTimeout(async()=>{await cloud()?.reloadMemberships?.();if(registerMode&&workspace()){clearPendingRegistration();gate.remove();document.body.classList.remove('sun-cloud-auth-required');await cloud()?.pull?.();applyNavPermissions();return;}if(getPendingRegistration(email)&&!workspace()){await finishPendingRegistration(gate,email);return;}if(workspace()){gate.remove();document.body.classList.remove('sun-cloud-auth-required');await cloud()?.pull?.();applyNavPermissions();}else{gate.remove();ensureAuthGate();}},180);}catch(err){gateError.textContent=String(err?.message||err||'Не удалось выполнить операцию.')}finally{submitBtn.disabled=false}} gate.querySelector('#sunGateSwitchV27').onclick=()=>setMode(!registerMode);submitBtn.onclick=auth;passwordInput.addEventListener('keydown',e=>{if(e.key==='Enter'&&!registerMode)auth()});password2Input.addEventListener('keydown',e=>{if(e.key==='Enter'&®isterMode)auth()});setMode(false); } function onCloudChanged(){ if(applying)return;applying=true; try{ const ws=workspace();if(ws?.id!==lastWorkspaceId){lastWorkspaceId=ws?.id||'';} ensureAuthGate();normalizeLegacyLocalAuth();installGuards();applyNavPermissions();hideLegacyRoleCard();injectQuickPinCard();showPinLockIfNeeded(); }finally{applying=false;} } window.addEventListener('sun:open-cloud-users',openModal); window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(onCloudChanged,0)); document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(b&&String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки')setTimeout(()=>{hideLegacyRoleCard();injectQuickPinCard();},120);},true); (()=>{let queued=false;const run=()=>{if(queued||applying)return;queued=true;setTimeout(()=>{queued=false;if(!applying){applyNavPermissions();hideLegacyRoleCard();}},60);};[document.querySelector('header'),document.getElementById('enterprise-settings')].filter(Boolean).forEach(root=>new MutationObserver(run).observe(root,{childList:true,subtree:true}));})(); installStyle();normalizeLegacyLocalAuth();ensureModal(); let tries=0;const boot=setInterval(()=>{tries++;if(window.SunCloudV2){clearInterval(boot);setTimeout(onCloudChanged,80);}else if(tries>80)clearInterval(boot);},100); setInterval(()=>{if(document.hidden)return;try{ensureAuthGate();if(workspace()&&session()?.user){applyNavPermissions();injectQuickPinCard();showPinLockIfNeeded();}}catch(_){}},5000); window.SunAdminRBACV3={VERSION,openUsers:openModal,apply:applyNavPermissions,hasPermission:has}; })(); ; /* ===== MODULE: order-payment-ui-v1.js ===== */ (()=>{ 'use strict'; if(window.__sunOrderPaymentUIV1)return; window.__sunOrderPaymentUIV1=true; const KEY='sunOrderPaymentColorsV1'; const DEFAULTS={ unpaid:'#d84a4a', prepaid:'#35a46b', paid:'#3b82f6', cancelled:'#9aa0aa' }; const LABELS={ unpaid:'Без предоплаты', prepaid:'Предоплата внесена', paid:'Оплачен полностью', cancelled:'Отменён' }; const $=id=>document.getElementById(id); const hex=value=>/^#[0-9a-f]{6}$/i.test(String(value||''))?String(value).toLowerCase():null; const readColors=()=>{ let saved={}; try{saved=JSON.parse(localStorage.getItem(KEY)||'{}')||{}}catch(_){saved={}} const next={}; Object.keys(DEFAULTS).forEach(key=>next[key]=hex(saved[key])||DEFAULTS[key]); return next; }; const saveColors=colors=>{ const safe={};Object.keys(DEFAULTS).forEach(key=>safe[key]=hex(colors[key])||DEFAULTS[key]); localStorage.setItem(KEY,JSON.stringify(safe)); decorateOrders(); return safe; }; const liveOrders=()=>{try{return Array.isArray(orders)?orders:JSON.parse(localStorage.getItem('sunOrders')||'[]')}catch(_){return[]}}; const byId=id=>liveOrders().find(order=>String(order?.id)===String(id)); const orderTotal=order=>{ try{if(typeof window.orderTotalValue==='function'){const value=Number(window.orderTotalValue(order));if(Number.isFinite(value))return Math.max(0,value)}}catch(_){} const direct=Number(order?.total);return Number.isFinite(direct)?Math.max(0,direct):0; }; function paymentState(order){ if(String(order?.status||'').trim()==='Отменён')return'cancelled'; const paid=Math.max(0,Number(order?.prepayment||0)); const total=orderTotal(order); if(total>0&&paid>=total-0.5)return'paid'; if(paid>0)return'prepaid'; return'unpaid'; } window.sunOrderPaymentState=paymentState; window.sunOrderPaymentColors=()=>({...readColors()}); function readableText(color){ const value=hex(color)||'#000000'; const r=parseInt(value.slice(1,3),16),g=parseInt(value.slice(3,5),16),b=parseInt(value.slice(5,7),16); return ((r*299+g*587+b*114)/1000)>168?'#252a32':'#ffffff'; } function shadowColor(color,alpha=.24){ const value=hex(color)||'#000000'; const r=parseInt(value.slice(1,3),16),g=parseInt(value.slice(3,5),16),b=parseInt(value.slice(5,7),16); return `rgba(${r},${g},${b},${alpha})`; } function paintDateTile(tile,order){ if(!tile||!order)return; const state=paymentState(order),colors=readColors(),color=colors[state],text=readableText(color); tile.dataset.paymentState=state; tile.title=LABELS[state]; tile.setAttribute('aria-label',`${tile.textContent.trim()}: ${LABELS[state]}`); tile.style.setProperty('background',color,'important'); tile.style.setProperty('border-color',color,'important'); tile.style.setProperty('box-shadow',`0 5px 14px ${shadowColor(color)}`,'important'); tile.style.setProperty('color',text,'important'); tile.querySelectorAll('strong,span,small').forEach(node=>node.style.setProperty('color',text,'important')); } function decorateOrders(){ document.querySelectorAll('#ordersList .sun-order-payment-marker,#sunOrderCards .sun-order-payment-marker').forEach(marker=>marker.remove()); document.querySelectorAll('#ordersList .sun-order-number-cell').forEach(cell=>cell.classList.remove('sun-order-number-cell')); document.querySelectorAll('#sunOrderCards .sun-order-number-with-payment').forEach(host=>host.classList.remove('sun-order-number-with-payment')); document.querySelectorAll('#sunOrderCards .sun-order-card').forEach(card=>{ const order=byId(card.dataset.orderId),tile=card.querySelector('.sun-order-card-date'); if(order&&tile)paintDateTile(tile,order); }); } let decorateQueued=false; function queueDecorate(){if(decorateQueued)return;decorateQueued=true;requestAnimationFrame(()=>{decorateQueued=false;decorateOrders()})} const priorRenderOrders=window.renderOrders; if(typeof priorRenderOrders==='function')window.renderOrders=function(...args){const result=priorRenderOrders.apply(this,args);queueDecorate();return result}; // One authoritative deletion path for list, cards and the current order form. window.deleteOrderById=function(id){ const list=liveOrders(); const order=list.find(item=>String(item?.id)===String(id)); if(!order)return false; if(!confirm(`Удалить заказ №${order.id}${order.event?` «${order.event}»`:''}?`))return false; try{ if(Array.isArray(orders)){ const index=orders.findIndex(item=>String(item?.id)===String(id)); if(index>=0)orders.splice(index,1); }else{ localStorage.setItem('sunOrders',JSON.stringify(list.filter(item=>String(item?.id)!==String(id)))); } if(typeof persist==='function')persist(); else localStorage.setItem('sunOrders',JSON.stringify(Array.isArray(orders)?orders:list.filter(item=>String(item?.id)!==String(id)))); }catch(error){ console.error('Order deletion failed',error); window.SunEnterprise?.toast?.('Не удалось удалить заказ.','error',5000); return false; } try{window.SunEnterprise?.recordAudit?.('Удалён заказ',`№${order.id} · ${order.event||'Заказ'}`)}catch(_){} const currentId=(()=>{try{return draft?.id}catch(_){return null}})(); if(String(currentId)===String(id)&&typeof window.resetDraft==='function')window.resetDraft(); try{window.renderOrders?.()}catch(_){} try{window.renderStats?.()}catch(_){} try{window.sunRenderOrderCards?.()}catch(_){} window.dispatchEvent(new CustomEvent('sun:order-deleted',{detail:{id:order.id}})); window.SunEnterprise?.toast?.(`Заказ №${order.id} удалён.`,'success'); return true; }; window.deleteOrder=function(){ const id=(()=>{try{return draft?.id}catch(_){return null}})(); if(!id)return false; const deleted=window.deleteOrderById(id); if(!deleted)return false; const button=[...document.querySelectorAll('header nav button')].find(btn=>String(btn.dataset.navLabel||btn.textContent||'').trim()==='Заказы'); if(button)button.click(); else if(typeof window.show==='function')try{window.show('orders',document.querySelectorAll('header nav button')[1])}catch(_){} return true; }; function settingsCard(){ const view=$('enterprise-settings'),grid=view?.querySelector('.enterprise-grid'); if(!grid)return null; let card=$('sunOrderPaymentColorsCard'); if(card)return card; card=document.createElement('section'); card.className='enterprise-card';card.id='sunOrderPaymentColorsCard'; grid.appendChild(card); renderSettingsCard(card); return card; } function renderSettingsCard(card=settingsCard()){ if(!card)return; const colors=readColors(); card.innerHTML=`

    Цвета оплаты заказов

    Цвет плашки с датой в разделе «Заказы» показывает состояние оплаты. Цвет каждого состояния можно выбрать самостоятельно.

    ${Object.keys(DEFAULTS).map(key=>``).join('')}

    Правила: 0 ₽ предоплаты — «Без предоплаты»; предоплата меньше суммы — «Предоплата внесена»; оплачена вся сумма — «Оплачен полностью»; статус «Отменён» — отдельный цвет.

    `; card.querySelectorAll('[data-payment-color]').forEach(input=>input.addEventListener('input',()=>{ const next=readColors();next[input.dataset.paymentColor]=input.value;saveColors(next); const dot=input.closest('label')?.querySelector('.sun-payment-settings-dot');if(dot)dot.style.background=input.value; })); $('sunResetPaymentColors')?.addEventListener('click',()=>{localStorage.setItem(KEY,JSON.stringify(DEFAULTS));renderSettingsCard(card);decorateOrders();window.SunEnterprise?.toast?.('Стандартные цвета восстановлены.','success')}); } function ensureSettingsCard(){const card=settingsCard();if(card)renderSettingsCard(card)} const style=document.createElement('style');style.id='sun-order-payment-ui-v1-style';style.textContent=` #orderForm .sun-order-line-price input{width:100%!important;max-width:104px!important;min-width:78px!important;padding:2px 7px!important;font-variant-numeric:tabular-nums!important;letter-spacing:.01em!important} .sun-payment-color-settings{display:grid;gap:8px;margin-top:10px} .sun-payment-color-settings label{display:grid;grid-template-columns:minmax(0,1fr) 52px;gap:10px;align-items:center;padding:8px 9px;border:1px solid #e3e6e9;border-radius:9px;background:#fafbfc} .sun-payment-color-settings label>span{display:flex;align-items:center;gap:8px;color:#3d4652;font-weight:700;font-size:12.5px} .sun-payment-color-settings input[type="color"]{width:48px;height:32px;padding:2px;border:1px solid #cfd5da;border-radius:7px;background:#fff;cursor:pointer} .sun-payment-settings-dot{display:inline-block;width:13px;height:13px;border-radius:3px;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12)} `;document.head.appendChild(style); document.addEventListener('click',event=>{ const nav=event.target.closest('header nav button'); if(nav&&String(nav.dataset.navLabel||nav.textContent||'').trim()==='Настройки')setTimeout(ensureSettingsCard,60); },true); const ordersHost=$('orders');if(ordersHost)new MutationObserver(queueDecorate).observe(ordersHost,{childList:true,subtree:true}); const settingsHost=$('enterprise-settings');if(settingsHost)new MutationObserver(()=>{if(settingsHost.classList.contains('on'))setTimeout(()=>{if(!$('sunOrderPaymentColorsCard'))ensureSettingsCard()},0)}).observe(settingsHost,{childList:true,subtree:true}); window.addEventListener('sun:cloud-state-applied',()=>{queueDecorate();if($('enterprise-settings')?.classList.contains('on'))setTimeout(ensureSettingsCard,0)}); window.addEventListener('storage',event=>{if(event.key===KEY)queueDecorate()}); queueDecorate(); setTimeout(()=>{queueDecorate();if($('enterprise-settings')?.classList.contains('on'))ensureSettingsCard()},140); })(); ; /* ===== MODULE: order-crm-v1.js ===== */ (()=>{ 'use strict'; if(window.__sunOrderCrmV1)return;window.__sunOrderCrmV1=true; const $=id=>document.getElementById(id),qa=(s,r=document)=>[...r.querySelectorAll(s)]; const esc=window.SunSafe.escapeHTML; const SOURCE_KEY='sunLeadSourcesV1'; const DEFAULT_SOURCES=['Заявка с сайта','CaterMe','Avito','Рекомендация','Повторный клиент','Соцсети','Другое']; const getDraft=()=>{try{return draft}catch(_){return null}}; const getOrders=()=>{try{return Array.isArray(orders)?orders:[]}catch(_){try{const x=JSON.parse(localStorage.getItem('sunOrders')||'[]');return Array.isArray(x)?x:[]}catch(__){return[]}}}; const money=v=>typeof window.money==='function'?window.money(v):`${Math.round(Number(v||0)).toLocaleString('ru-RU')} ₽`; const toast=(m,t='success')=>{try{if(window.SunEnterprise?.toast)return window.SunEnterprise.toast(m,t)}catch(_){} if(t==='warn'||t==='error')console.warn(m)}; const style=document.createElement('style');style.id='sun-order-crm-v1-style';style.textContent=` /* The precise-address fields existed in an older module but were hidden by a later polish layer. */ #details .sun-address-precision-title{display:block!important;grid-column:1/-1;margin:10px 0 0;font-size:13px;font-weight:850;color:#241d45} #details .sun-delivery-region,#details .sun-delivery-locality,#details .sun-delivery-district{display:flex!important} #details .sun-delivery-district{grid-column:1/-1!important} #details .sun-lead-source-field,#details .sun-known-addresses-field{grid-column:1/-1} #details .sun-client-match{grid-column:1/-1;display:none;padding:9px 11px;border:1px solid #d7d0e7;border-radius:11px;background:#f7f5fb;color:#514b68;font-size:12px;line-height:1.35} #details .sun-client-match.on{display:block} #details .sun-geo-confirm{display:none;margin-top:10px;padding:11px;border:1px solid #dfd9eb;border-radius:12px;background:#faf9fd} #details .sun-geo-confirm.on{display:block} #details .sun-geo-confirm strong{display:block;color:#241d45;font-size:12px;margin-bottom:5px} #details .sun-geo-confirm p{margin:0 0 9px;color:#666078;font-size:11px;line-height:1.4} #details .sun-geo-confirm .actions{display:flex;gap:7px;flex-wrap:wrap;margin:0} #details .sun-geo-confirm.ok{border-color:#b8dcc4;background:#f3fbf5} #details .sun-geo-confirm.ok strong{color:#28683d} .sun-crm-stats-table{width:100%;border-collapse:collapse;font-size:12px} .sun-crm-stats-table th,.sun-crm-stats-table td{padding:9px 8px;border-bottom:1px solid #ece9f2;text-align:right;white-space:nowrap} .sun-crm-stats-table th:first-child,.sun-crm-stats-table td:first-child{text-align:left;white-space:normal} .sun-crm-stats-table th{color:#817a94;font-size:10px;text-transform:uppercase;letter-spacing:.04em} .sun-crm-stats-table td b{color:#241d45} .sun-lead-settings-list{display:grid;gap:7px;margin:10px 0} .sun-lead-settings-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px} @media(max-width:700px){.sun-crm-stats-table{font-size:10px}.sun-crm-stats-table th,.sun-crm-stats-table td{padding:7px 4px}.sun-crm-hide-mobile{display:none}} `;document.head.appendChild(style); function readSources(){ try{const a=JSON.parse(localStorage.getItem(SOURCE_KEY)||'null');if(Array.isArray(a)){const clean=a.map(x=>String(x||'').trim()).filter(Boolean);if(clean.length)return [...new Set(clean)]}}catch(_){} return DEFAULT_SOURCES.slice(); } function saveSources(list){ const clean=[...new Set((list||[]).map(x=>String(x||'').trim()).filter(Boolean))]; localStorage.setItem(SOURCE_KEY,JSON.stringify(clean.length?clean:DEFAULT_SOURCES)); refreshSourceSelect();renderCrmStats(); } function setSelectOptions(select,values,current=''){ if(!select)return;const cur=String(current||select.value||''); const all=values.slice();if(cur&&!all.includes(cur))all.push(cur); select.innerHTML=``+all.map(v=>``).join('');select.value=cur; } function ensureSourceField(){ const grid=document.querySelector('#details .sun-delivery-details');if(!grid)return null; let select=$('orderLeadSource');if(!select){ const label=document.createElement('label');label.className='sun-lead-source-field';label.innerHTML='Узнали из'; const loyalty=$('orderLoyaltyCard')?.closest('label'),phone=$('phone')?.closest('label'); (loyalty||phone)?.insertAdjacentElement('afterend',label);if(!label.isConnected)window.SunSafe.insertBefore(grid,label,grid.firstChild); select=label.querySelector('select');select.addEventListener('change',()=>{const d=getDraft();if(d)d.leadSource=select.value}); } setSelectOptions(select,readSources(),getDraft()?.leadSource||select.value);return select; } function refreshSourceSelect(){const s=ensureSourceField();if(s)setSelectOptions(s,readSources(),getDraft()?.leadSource||s.value)} function ensureSettingsCard(){ const grid=document.querySelector('#enterprise-settings .enterprise-grid');if(!grid)return; let card=$('sunLeadSourcesSettingsCard'); if(!card){card=document.createElement('section');card.id='sunLeadSourcesSettingsCard';card.className='enterprise-card';card.innerHTML=`

    Источники клиентов

    Список для поля «Узнали из» в деталях заказа. Эти данные используются в статистике.

    `; const eventCard=$('sunEventTypesSettingsCard');if(eventCard)eventCard.insertAdjacentElement('afterend',card);else grid.appendChild(card); $('sunLeadSourceAdd').onclick=()=>addSourceSettingsRow('');$('sunLeadSourcesSave').onclick=()=>saveSources(qa('#sunLeadSourcesRows input').map(x=>x.value)); } const rows=$('sunLeadSourcesRows');if(rows&&!rows.dataset.ready){rows.dataset.ready='1';renderSourceSettingsRows()} } function addSourceSettingsRow(value=''){ const rows=$('sunLeadSourcesRows');if(!rows)return;const row=document.createElement('div');row.className='sun-lead-settings-row';row.innerHTML=``;row.querySelector('button').onclick=()=>row.remove();rows.appendChild(row);row.querySelector('input').focus(); } function renderSourceSettingsRows(){const rows=$('sunLeadSourcesRows');if(!rows)return;rows.innerHTML='';readSources().forEach(addSourceSettingsRow)} function normalizePhone(raw){ let d=String(raw||'').replace(/\D/g,'');if(d.length===11&&d[0]==='8')d='7'+d.slice(1);else if(d.length===10)d='7'+d;return d; } function orderStamp(o){return `${o?.date||''}T${o?.time||''}|${String(o?.id||'').padStart(12,'0')}`} function structuredAddress(o){ const keys=['deliveryRegion','deliveryLocality','deliveryDistrict','deliveryStreet','deliveryHouse','deliveryCorpus','deliveryEntrance','deliveryFloor','deliveryApartment','deliveryOffice']; const data={};keys.forEach(k=>data[k]=String(o?.[k]||'').trim());data.address=String(o?.address||'').trim(); data.structured=keys.some(k=>data[k]);return data; } function profileFromOrders(list){ const sorted=list.slice().sort((a,b)=>orderStamp(b).localeCompare(orderStamp(a)));if(!sorted.length)return null; const latest=sorted[0],seen=new Set(),addresses=[]; sorted.forEach(o=>{const a=structuredAddress(o),key=a.structured?JSON.stringify(a):a.address;if(key&&!seen.has(key)){seen.add(key);addresses.push(a)}}); return {name:String(latest.contact||''),phone:String(latest.phone||''),ordersCount:sorted.length,latest,addresses}; } function profileByPhone(raw){const n=normalizePhone(raw);if(n.length<10)return null;return profileFromOrders(getOrders().filter(o=>normalizePhone(o.phone)===n))} function readLoyaltyStore(){try{const v=JSON.parse(localStorage.getItem('sunClientLoyaltyV1')||'{}');return v&&typeof v==='object'?v:{}}catch(_){return{}}} function profileByCard(raw){ const card=String(raw||'').trim().toLowerCase();if(!card)return null; let direct=getOrders().filter(o=>String(o.loyaltyCardNumber||o.loyaltyCard||'').trim().toLowerCase()===card);if(direct.length)return profileFromOrders(direct); const store=readLoyaltyStore(),entry=Object.entries(store).find(([,v])=>String(v?.cardNumber||'').trim().toLowerCase()===card);if(!entry)return null; const key=entry[0];if(key.startsWith('p:'))return profileByPhone(key.slice(2)); if(key.startsWith('n:')){const name=key.slice(2).trim().toLowerCase();return profileFromOrders(getOrders().filter(o=>String(o.contact||'').trim().toLowerCase()===name))} return null; } const addrIds=['deliveryRegion','deliveryLocality','deliveryDistrict','deliveryStreet','deliveryHouse','deliveryCorpus','deliveryEntrance','deliveryFloor','deliveryApartment','deliveryOffice']; function setSelectValue(el,value){if(!el)return;const v=String(value||'');if(v&&el.tagName==='SELECT'&&![...el.options].some(o=>o.value===v))el.add(new Option(v,v));el.value=v} function composeFullAddress(){ const val=id=>String($(id)?.value||'').trim();const address=$('address');if(!address)return''; const parts=[val('deliveryRegion'),val('deliveryLocality'),val('deliveryDistrict'),val('deliveryStreet'),val('deliveryHouse')?`д. ${val('deliveryHouse')}`:'',val('deliveryCorpus')?`корп. ${val('deliveryCorpus')}`:'',val('deliveryEntrance')?`подъезд ${val('deliveryEntrance')}`:'',val('deliveryFloor')?`этаж ${val('deliveryFloor')}`:'',val('deliveryApartment')?`кв. ${val('deliveryApartment')}`:'',val('deliveryOffice')?`офис ${val('deliveryOffice')}`:''].filter(Boolean); const full=parts.join(', ');address.value=full;const d=getDraft();if(d){addrIds.forEach(id=>d[id]=val(id));d.address=full}return full; } window.sunComposePreciseDeliveryAddress=composeFullAddress; function fillAddress(a){ if(!a)return;const has=Boolean(a.structured); addrIds.forEach(id=>{const el=$(id);if(!el)return;const v=has?String(a[id]||''):(id==='deliveryStreet'?String(a.address||''):'');if(id==='deliveryRegion')setSelectValue(el,v);else el.value=v}); composeFullAddress();resetGeoConfirmation(true); } function ensureClientUi(){ const grid=document.querySelector('#details .sun-delivery-details');if(!grid)return; if(!$('sunClientMatch')){const box=document.createElement('div');box.id='sunClientMatch';box.className='sun-client-match';const lead=$('orderLeadSource')?.closest('label');(lead||grid.firstElementChild)?.insertAdjacentElement('afterend',box);if(!box.isConnected)window.SunSafe.insertBefore(grid,box,grid.firstChild)} if(!$('sunKnownAddresses')){const label=document.createElement('label');label.className='sun-known-addresses-field';label.style.display='none';label.innerHTML='Предыдущие адреса клиента';const office=$('deliveryOffice')?.closest('label');office?.insertAdjacentElement('afterend',label);if(!label.isConnected)grid.appendChild(label);label.querySelector('select').onchange=e=>{const a=e.target._addresses?.[Number(e.target.value)];if(a)fillAddress(a)}} } function showProfile(profile,reason){ ensureClientUi();const box=$('sunClientMatch'),known=$('sunKnownAddresses'),knownLabel=known?.closest('label');if(!profile){box?.classList.remove('on');if(knownLabel)knownLabel.style.display='none';return false} const contact=$('contact'),phone=$('phone');if(contact&&profile.name)contact.value=profile.name;if(phone&&profile.phone)phone.value=profile.phone; if(profile.addresses[0])fillAddress(profile.addresses[0]); if(known&&knownLabel){known._addresses=profile.addresses;known.innerHTML=profile.addresses.map((a,i)=>``).join('');knownLabel.style.display=profile.addresses.length>1?'flex':'none'} if(box){box.innerHTML=`Клиент найден по ${reason}: ${esc(profile.name||profile.phone||'клиент')} · заказов: ${profile.ordersCount}${profile.addresses.length>1?` · сохранено адресов: ${profile.addresses.length}`:''}. Данные заполнены автоматически, адрес можно изменить.`;box.classList.add('on')} const d=getDraft();if(d){d.contact=contact?.value||'';d.phone=phone?.value||''}return true; } let lookupTimer=0; function schedulePhoneLookup(){clearTimeout(lookupTimer);lookupTimer=setTimeout(()=>{const d=getDraft();if(d?.id)return;const p=profileByPhone($('phone')?.value);if(p)showProfile(p,'телефону')},260)} function lookupCard(){const d=getDraft();if(d?.id)return;const field=$('orderLoyaltyCard'),p=profileByCard(field?.value);if(p)showProfile(p,'карте лояльности')} function totalFor(o){if(Number.isFinite(Number(o?.total))&&Number(o.total)>0)return Number(o.total);try{return typeof window.orderTotalValue==='function'?Number(window.orderTotalValue(o)||0):0}catch(_){return 0}} function statsPeriodOrders(){ const period=$('statsPeriod')?.value||'year',now=new Date();now.setHours(12,0,0,0);let from=null,to=null; if(period==='month'){from=new Date(now.getFullYear(),now.getMonth(),1,12);to=new Date(now.getFullYear(),now.getMonth()+1,1,12)} else if(period==='90'){from=new Date(now);from.setDate(from.getDate()-89);to=new Date(now);to.setDate(to.getDate()+1)} else if(period==='year'){from=new Date(now.getFullYear(),now.getMonth()-11,1,12);to=new Date(now.getFullYear(),now.getMonth()+1,1,12)} return getOrders().filter(o=>{if(String(o.status||'Новый')==='Отменён')return false;if(!from)return true;const d=o.date?new Date(`${o.date}T12:00:00`):null;return d&&!Number.isNaN(d.getTime())&&d>=from&&d{const name=String(keyFn(o)||'').trim()||'Не указано',r=m.get(name)||{name,count:0,sum:0};r.count++;r.sum+=totalFor(o);m.set(name,r)});return [...m.values()].map(r=>({...r,avg:r.count?r.sum/r.count:0,share:list.length?r.count/list.length*100:0})).sort((a,b)=>b.count-a.count||b.sum-a.sum||a.name.localeCompare(b.name,'ru')); } function statTable(rows){return rows.length?`
    ${rows.map(r=>``).join('')}
    КатегорияЗаказовДоляВыручкаСредний чек
    ${esc(r.name)}${r.count}${r.share.toLocaleString('ru-RU',{maximumFractionDigits:1})}%${esc(money(r.sum))}${esc(money(r.avg))}
    `:'
    Данных пока нет.
    '} function renderCrmStats(){ const grid=$('statsList')?.querySelector('.stats-grid');if(!grid)return;grid.querySelectorAll('.sun-crm-stats-panel').forEach(x=>x.remove());const list=statsPeriodOrders(); const eventPanel=document.createElement('section');eventPanel.className='stats-panel wide sun-crm-stats-panel';eventPanel.innerHTML=`

    Типы мероприятий

    количество · доля · выручка · средний чек
    ${statTable(groupedStats(list,o=>o.event))}`; const sourcePanel=document.createElement('section');sourcePanel.className='stats-panel wide sun-crm-stats-panel';sourcePanel.innerHTML=`

    Откуда приходят заказы

    по полю «Узнали из»
    ${statTable(groupedStats(list,o=>o.leadSource))}`; grid.append(eventPanel,sourcePanel); } function resetGeoConfirmation(clear=false){const d=getDraft();if(d?.geo){if(clear)d.geo=null;else{delete d.geo.confirmed;delete d.geo.confirmedAt}}syncGeoConfirmUi()} function ensureGeoConfirmUi(){ const box=$('orderGeoBox');if(!box)return null;let ui=$('sunGeoConfirm');if(!ui){ui=document.createElement('div');ui.id='sunGeoConfirm';ui.className='sun-geo-confirm';ui.innerHTML='Найденный адрес

    ';box.appendChild(ui);$('sunGeoConfirmOk').onclick=()=>{const d=getDraft();if(!d?.geo)return;d.geo.confirmed=true;d.geo.confirmedAt=new Date().toISOString();if(d.id){const saved=getOrders().find(o=>String(o.id)===String(d.id));if(saved)saved.geo=structuredClone(d.geo);try{persist()}catch(_){}}syncGeoConfirmUi();toast('Адрес подтверждён.','success')};$('sunGeoConfirmEdit').onclick=()=>{const d=getDraft();if(d)d.geo=null;const locality=$('deliveryLocality')||$('deliveryStreet');locality?.focus();syncGeoConfirmUi()}} return ui; } function syncGeoConfirmUi(){ const ui=ensureGeoConfirmUi(),d=getDraft();if(!ui)return;const geo=d?.geo;if(!geo||!Number.isFinite(Number(geo.lat))||!Number.isFinite(Number(geo.lon))){ui.classList.remove('on','ok');return}ui.classList.add('on');ui.classList.toggle('ok',geo.confirmed===true);$('sunGeoFoundTitle').textContent=geo.confirmed?'Адрес подтверждён':'Проверьте найденный адрес';$('sunGeoFoundText').textContent=String(geo.formatted||d.address||'');$('sunGeoConfirmOk').style.display=geo.confirmed?'none':''; } function persistPreciseSaved(){ const d=getDraft();if(!d)return;const full=composeFullAddress();if(!d.id)return;const saved=getOrders().find(o=>String(o.id)===String(d.id));if(!saved)return;addrIds.forEach(id=>saved[id]=String($(id)?.value||'').trim());saved.address=full;saved.leadSource=$('orderLeadSource')?.value||'';if(d.geo)saved.geo=structuredClone(d.geo);try{persist()}catch(_){try{localStorage.setItem('sunOrders',JSON.stringify(getOrders()))}catch(__){}} } function init(){ ensureSourceField();ensureClientUi();ensureGeoConfirmUi(); const mapSensitive=new Set(['deliveryRegion','deliveryLocality','deliveryDistrict','deliveryStreet','deliveryHouse','deliveryCorpus']); addrIds.forEach(id=>$(id)?.addEventListener('input',()=>setTimeout(()=>{composeFullAddress();if(mapSensitive.has(id))resetGeoConfirmation(true)},0))); $('deliveryRegion')?.addEventListener('change',()=>setTimeout(()=>{composeFullAddress();resetGeoConfirmation(true)},0)); $('phone')?.addEventListener('input',schedulePhoneLookup);$('phone')?.addEventListener('blur',schedulePhoneLookup); $('orderLoyaltyCard')?.addEventListener('input',()=>{clearTimeout(lookupTimer);lookupTimer=setTimeout(lookupCard,260)});$('orderLoyaltyCard')?.addEventListener('blur',lookupCard); $('orderGeoCreate')?.addEventListener('click',()=>setTimeout(syncGeoConfirmUi,200)); const geoBox=$('orderGeoBox');if(geoBox)new MutationObserver(()=>setTimeout(syncGeoConfirmUi,0)).observe(geoBox,{childList:true,subtree:true,characterData:true}); const stats=$('statsList');if(stats)new MutationObserver(()=>setTimeout(renderCrmStats,0)).observe(stats,{childList:true,subtree:false}); $('statsPeriod')?.addEventListener('change',()=>setTimeout(renderCrmStats,0));renderCrmStats(); } const priorSave=window.saveOrder; if(typeof priorSave==='function')window.saveOrder=function(...args){ const d=getDraft(),source=ensureSourceField();if(d&&source)d.leadSource=source.value;composeFullAddress(); const street=String($('deliveryStreet')?.value||'').trim(),house=String($('deliveryHouse')?.value||'').trim(),locality=String($('deliveryLocality')?.value||'').trim(); if(street&&house&&!locality&&!confirm('Не указан город / населённый пункт. Похожие адреса могут существовать в разных местах. Сохранить заказ без уточнения?'))return false; if(street&&house&&d?.geo&&d.geo.confirmed!==true&&!confirm('Точка уже найдена на карте, но адрес не подтверждён. Сохранить без подтверждения?'))return false; const r=priorSave.apply(this,args),finish=()=>{persistPreciseSaved();renderCrmStats();syncGeoConfirmUi();return undefined};if(r&&typeof r.then==='function')return r.then(v=>{finish();return v});finish();return r; }; const priorOpen=window.openOrder; if(typeof priorOpen==='function')window.openOrder=function(...args){const r=priorOpen.apply(this,args);setTimeout(()=>{const s=ensureSourceField();if(s)s.value=String(getDraft()?.leadSource||'');composeFullAddress();ensureClientUi();syncGeoConfirmUi();$('sunClientMatch')?.classList.remove('on');const l=$('sunKnownAddresses')?.closest('label');if(l)l.style.display='none'},0);return r}; const priorReset=window.resetDraft; if(typeof priorReset==='function')window.resetDraft=function(...args){const r=priorReset.apply(this,args);setTimeout(()=>{const s=ensureSourceField();if(s)s.value='';$('sunClientMatch')?.classList.remove('on');const l=$('sunKnownAddresses')?.closest('label');if(l)l.style.display='none';syncGeoConfirmUi()},0);return r}; const priorStats=window.renderStats; if(typeof priorStats==='function')window.renderStats=function(...args){const r=priorStats.apply(this,args);setTimeout(renderCrmStats,0);return r}; document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const label=String(b.dataset.navLabel||b.textContent||'').trim();if(label==='Настройки')setTimeout(()=>{ensureSettingsCard();renderSourceSettingsRows()},90);if(label==='Статистика')setTimeout(renderCrmStats,80)},true); const settings=$('enterprise-settings');if(settings)new MutationObserver(()=>{if(settings.classList.contains('on'))setTimeout(ensureSettingsCard,0)}).observe(settings,{childList:true,subtree:true}); window.addEventListener('sun:cloud-state-applied',()=>setTimeout(()=>{refreshSourceSelect();renderCrmStats()},50)); init();setTimeout(()=>{if($('enterprise-settings')?.classList.contains('on'))ensureSettingsCard();syncGeoConfirmUi()},200); })(); ; /* ===== MODULE: brand-theme-v1.js ===== */ /* Sun Catering theme editor v4: simple color presets, staged preview, reliable sidebar apply */ (()=>{ 'use strict'; if(window.__sunBrandThemeV4)return;window.__sunBrandThemeV4=true; const KEY='sunBrandThemeV1'; const BRAND={sun:'#FFC107',accent:'#FF8A00',text:'#1A1A1A',background:'#FFF7E6',surface:'#F3E8D3',fresh:'#A8C783',success:'#6D8F6A',trust:'#6C7A89',warm:'#C7744D',border:'#E7E7E7'}; const UI_FIRM={background:'#FFF7E6',card:'#FFFFFF',primary:'#1A1A1A',accent:'#FFC107',text:'#1A1A1A',muted:'#6C7A89',border:'#E7E7E7',input:'#FFFFFF',buttonText:'#FFFFFF'}; const UI_STANDARD={background:'#F5F6FA',card:'#FFFFFF',primary:'#15364C',accent:'#C99A32',text:'#203040',muted:'#68717A',border:'#D9DDE0',input:'#FFFFFF',buttonText:'#FFFFFF'}; const SIDEBAR_STANDARD={background:'#32255D',background2:'#171D38',glow:'#9574FF',border:'#4B3C77',icons:'#E9E8F6',iconBackground:'#3A2F68',text:'#E9E8F6',muted:'#A9A8C6',activeBackground:'#463A74',activeText:'#FFFFFF',activeIcon:'#FFE48D',indicator:'#E4B844',toolsBackground:'#3A315F',toolsBorder:'#544A7B',collapseBackground:'#FFFFFF',collapseText:'#433D68',badgeBackground:'#FF6C7C',badgeText:'#FFFFFF'}; const SIDEBAR_FIRM={background:'#1A1A1A',background2:'#2A2A2A',glow:'#FFC107',border:'#3A372F',icons:'#FFC107',iconBackground:'#2A281D',text:'#FFF7E6',muted:'#C9B98E',activeBackground:'#34301F',activeText:'#FFC107',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#242424',toolsBorder:'#414141',collapseBackground:'#FFFFFF',collapseText:'#1A1A1A',badgeBackground:'#C7744D',badgeText:'#FFFFFF'}; const SIDEBAR_LIGHT={background:'#FFF7E6',background2:'#F3E8D3',glow:'#FFC107',border:'#E2D5BC',icons:'#C7744D',iconBackground:'#FFFDF9',text:'#1A1A1A',muted:'#6C7A89',activeBackground:'#FFFFFF',activeText:'#C7744D',activeIcon:'#C7744D',indicator:'#FF8A00',toolsBackground:'#FFFFFF',toolsBorder:'#E2D5BC',collapseBackground:'#1A1A1A',collapseText:'#FFFFFF',badgeBackground:'#C7744D',badgeText:'#FFFFFF'}; const SIDEBAR_EMERALD={background:'#123C30',background2:'#071F19',glow:'#FFC107',border:'#285849',icons:'#FFC107',iconBackground:'#173E33',text:'#FFF7E6',muted:'#A8C783',activeBackground:'#1C4C3D',activeText:'#FFF7E6',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#16382F',toolsBorder:'#2B5A4B',collapseBackground:'#FFF7E6',collapseText:'#123C30',badgeBackground:'#C7744D',badgeText:'#FFFFFF'}; const SIDEBAR_SUNSET={background:'#49301B',background2:'#1A1A1A',glow:'#FF8A00',border:'#69462A',icons:'#FFC107',iconBackground:'#3A2C1E',text:'#FFF7E6',muted:'#D6BD91',activeBackground:'#62401D',activeText:'#FFF7E6',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#34281F',toolsBorder:'#5A4632',collapseBackground:'#FFF7E6',collapseText:'#49301B',badgeBackground:'#C7744D',badgeText:'#FFFFFF'}; const UI_LABELS={background:'Фон приложения',card:'Карточки и окна',primary:'Основные кнопки',accent:'Акцент / обводка',text:'Основной текст',muted:'Вторичный текст',border:'Границы',input:'Поля ввода',buttonText:'Текст основных кнопок'}; const SIDE_LABELS={background:'Основной цвет панели',background2:'Второй цвет / низ панели',glow:'Свечение панели',border:'Граница панели',icons:'Цвет значков',iconBackground:'Фон значков',text:'Основной текст панели',muted:'Подписи групп',activeBackground:'Фон активного пункта',activeText:'Текст активного пункта',activeIcon:'Активный значок',indicator:'Полоса активного пункта',toolsBackground:'Поиск / уведомления',toolsBorder:'Граница служебных кнопок',collapseBackground:'Кнопка свернуть',collapseText:'Стрелка сворачивания',badgeBackground:'Уведомление',badgeText:'Текст уведомления'}; const BRAND_LABELS={sun:'Солнечный',accent:'Оранжевый',text:'Графит',background:'Кремовый фон',surface:'Бежевый',fresh:'Свежий зелёный',success:'Фирменный зелёный',trust:'Серо-синий',warm:'Терракота',border:'Светлая граница'}; const esc=window.SunSafe.escapeHTML; const clone=o=>JSON.parse(JSON.stringify(o)); const isHex=v=>/^#[0-9a-f]{6}$/i.test(String(v||'').trim()); const norm=(v,f)=>isHex(v)?String(v).toUpperCase():f; const hexRgba=(hex,a=.25)=>{const h=norm(hex,'#000000').slice(1);return `rgba(${parseInt(h.slice(0,2),16)},${parseInt(h.slice(2,4),16)},${parseInt(h.slice(4,6),16)},${a})`}; const defaults=()=>({version:4,palette:{...BRAND},ui:{...UI_FIRM},sidebar:{...SIDEBAR_FIRM}}); const standardState=()=>({version:4,palette:{...BRAND},ui:{...UI_STANDARD},sidebar:{...SIDEBAR_STANDARD}}); const presetState=name=>{ if(name==='standard')return standardState(); const sidebar=name==='light'?SIDEBAR_LIGHT:name==='emerald'?SIDEBAR_EMERALD:name==='sunset'?SIDEBAR_SUNSET:SIDEBAR_FIRM; return{version:4,palette:{...BRAND},ui:{...UI_FIRM},sidebar:{...sidebar}}; }; function read(){ let raw={};try{raw=JSON.parse(localStorage.getItem(KEY)||'{}')||{}}catch(_){raw={}} const base=defaults(),palette={...base.palette,...(raw.palette||{})},ui={...base.ui,...(raw.ui||{})},sidebar={...base.sidebar,...(raw.sidebar||{})}; Object.keys(BRAND).forEach(k=>palette[k]=norm(palette[k],BRAND[k])); Object.keys(UI_FIRM).forEach(k=>ui[k]=norm(ui[k],UI_FIRM[k])); Object.keys(SIDEBAR_FIRM).forEach(k=>sidebar[k]=norm(sidebar[k],SIDEBAR_FIRM[k])); if(String(ui.buttonText).toUpperCase()===String(ui.primary).toUpperCase())ui.buttonText='#FFFFFF'; return{version:4,palette,ui,sidebar}; } let savedState=read(),previewState=clone(savedState),dirty=false; const persist=()=>localStorage.setItem(KEY,JSON.stringify(savedState)); const style=document.createElement('style');style.id='sun-brand-theme-style-v4';style.textContent=` :root{--sun-ui-bg:#FFF7E6;--sun-ui-card:#fff;--sun-ui-primary:#1A1A1A;--sun-ui-accent:#FFC107;--sun-ui-text:#1A1A1A;--sun-ui-muted:#6C7A89;--sun-ui-border:#E7E7E7;--sun-ui-input:#fff;--sun-ui-button-text:#fff;--sun-sidebar-bg:#32255D;--sun-sidebar-bg2:#171D38;--sun-sidebar-glow:#9574FF;--sun-sidebar-border:#4B3C77;--sun-sidebar-icons:#E9E8F6;--sun-sidebar-icon-bg:#3A2F68;--sun-sidebar-text:#E9E8F6;--sun-sidebar-muted:#A9A8C6;--sun-sidebar-active-bg:#463A74;--sun-sidebar-active-text:#fff;--sun-sidebar-active-icon:#FFE48D;--sun-sidebar-indicator:#E4B844;--sun-sidebar-tools-bg:#3A315F;--sun-sidebar-tools-border:#544A7B;--sun-sidebar-collapse-bg:#fff;--sun-sidebar-collapse-text:#433D68;--sun-sidebar-badge-bg:#FF6C7C;--sun-sidebar-badge-text:#fff} body{background:var(--sun-ui-bg)!important;color:var(--sun-ui-text)!important}:root{--n:var(--sun-ui-primary)!important;--g:var(--sun-ui-accent)!important;--p:var(--sun-ui-bg)!important;--l:var(--sun-ui-border)!important} .card,.page,.enterprise-card,.dialog,.sun-order-lines-table,.dash3-panel{background:var(--sun-ui-card)!important;color:var(--sun-ui-text)!important;border-color:var(--sun-ui-border)!important}.page h1,.catalog h1,.enterprise-card h2,.enterprise-card h3{color:var(--sun-ui-primary)!important}.hint,label,.enterprise-card .hint{color:var(--sun-ui-muted)!important}input,select,textarea{background:var(--sun-ui-input)!important;color:var(--sun-ui-text)!important;border-color:var(--sun-ui-border)!important} button.primary,.primary{background:var(--sun-ui-primary)!important;border-color:var(--sun-ui-primary)!important;color:var(--sun-ui-button-text)!important}.primary svg,.primary *{color:inherit!important}.outline{border-color:var(--sun-ui-accent)!important;color:var(--sun-ui-primary)!important;background:var(--sun-ui-card)!important} @media(min-width:901px){.sun-enterprise-sidebar header .brand{color:var(--sun-sidebar-text)!important;border-bottom-color:color-mix(in srgb,var(--sun-sidebar-text) 12%,transparent)!important}.sun-enterprise-sidebar .sun-nav-group{border-bottom-color:color-mix(in srgb,var(--sun-sidebar-text) 10%,transparent)!important}.sun-enterprise-sidebar .sun-nav-group::before{color:var(--sun-sidebar-muted)!important}.sun-enterprise-sidebar header nav .sun-nav-button{color:var(--sun-sidebar-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button::before{background:var(--sun-sidebar-icons)!important;color:var(--sun-sidebar-icons)!important}.sun-enterprise-sidebar header nav .sun-nav-button:hover{background:color-mix(in srgb,var(--sun-sidebar-active-bg) 72%,transparent)!important;color:var(--sun-sidebar-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button.on{background:var(--sun-sidebar-active-bg)!important;color:var(--sun-sidebar-active-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button.on::before{background:var(--sun-sidebar-active-icon)!important;color:var(--sun-sidebar-active-icon)!important}.sun-enterprise-sidebar header nav .sun-nav-button.on::after{background:var(--sun-sidebar-indicator)!important;box-shadow:0 0 10px color-mix(in srgb,var(--sun-sidebar-indicator) 42%,transparent)!important}.sun-side-tools .sun-side-action{color:var(--sun-sidebar-text)!important;border-color:var(--sun-sidebar-tools-border)!important;background:var(--sun-sidebar-tools-bg)!important}.sun-current-user,#sunLogoutBtn{color:var(--sun-sidebar-muted)!important}.sun-sidebar-collapse{background:var(--sun-sidebar-collapse-bg)!important;color:var(--sun-sidebar-collapse-text)!important;border-color:var(--sun-sidebar-border)!important}#sunNotificationsBtn .badge{background:var(--sun-sidebar-badge-bg)!important;color:var(--sun-sidebar-badge-text)!important;border-color:var(--sun-sidebar-bg)!important}} @media(max-width:900px){.sun-enterprise-sidebar header,.sun-enterprise-sidebar header nav{background:linear-gradient(165deg,var(--sun-sidebar-bg),var(--sun-sidebar-bg2))!important;color:var(--sun-sidebar-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button{color:var(--sun-sidebar-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button::before{background:var(--sun-sidebar-icons)!important}.sun-enterprise-sidebar header nav .sun-nav-button.on{background:var(--sun-sidebar-active-bg)!important;color:var(--sun-sidebar-active-text)!important}.sun-enterprise-sidebar header nav .sun-nav-button.on::before{background:var(--sun-sidebar-active-icon)!important}} .sun-brand-settings-card{overflow:hidden}.sun-theme-toolbar{display:flex;gap:8px;flex-wrap:wrap;margin:11px 0 14px}.sun-theme-sections{display:grid;gap:13px}.sun-theme-box{border:1px solid var(--sun-ui-border);border-radius:12px;padding:13px;background:color-mix(in srgb,var(--sun-ui-card) 96%,var(--sun-ui-bg))}.sun-theme-box h3{margin:0 0 9px}.sun-theme-panel-main{display:grid;grid-template-columns:minmax(250px,.8fr) minmax(340px,1.2fr);gap:14px;align-items:start}.sun-theme-preview{min-height:190px;border-radius:16px;background:radial-gradient(circle at 10% 0,color-mix(in srgb,var(--sun-sidebar-glow) 35%,transparent),transparent 35%),linear-gradient(150deg,var(--sun-sidebar-bg),var(--sun-sidebar-bg2));padding:15px;color:var(--sun-sidebar-text);border:1px solid var(--sun-sidebar-border)}.sun-theme-preview-head{display:flex;align-items:center;gap:10px;padding-bottom:12px;border-bottom:1px solid color-mix(in srgb,var(--sun-sidebar-text) 13%,transparent)}.sun-theme-preview-logo{width:35px;height:35px;border-radius:50%;background:var(--sun-sidebar-icons);box-shadow:0 0 18px color-mix(in srgb,var(--sun-sidebar-glow) 45%,transparent)}.sun-theme-preview-menu{display:grid;gap:7px;margin-top:13px}.sun-theme-preview-row{height:38px;border-radius:10px;display:flex;align-items:center;gap:10px;padding:0 10px;color:var(--sun-sidebar-text)}.sun-theme-preview-row.on{background:var(--sun-sidebar-active-bg);color:var(--sun-sidebar-active-text);box-shadow:inset 3px 0 0 var(--sun-sidebar-indicator)}.sun-theme-preview-row i{width:25px;height:25px;display:grid;place-items:center;color:var(--sun-sidebar-icons);font-style:normal}.sun-theme-preview-row.on i{color:var(--sun-sidebar-active-icon)}.sun-theme-preview small{color:var(--sun-sidebar-muted)} .sun-sidebar-core-colors{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-bottom:12px}.sun-brand-setting-grid{display:grid;grid-template-columns:repeat(3,minmax(185px,1fr));gap:8px}.sun-brand-color-field{display:grid;grid-template-columns:34px minmax(0,1fr) 82px;gap:7px;align-items:center;padding:7px 8px;border:1px solid var(--sun-ui-border);border-radius:9px;background:var(--sun-ui-card)}.sun-brand-color-field label{font-size:10.5px;line-height:1.2}.sun-brand-color-field input[type=color]{width:32px!important;height:30px!important;padding:2px!important;border:1px solid var(--sun-ui-border)!important;border-radius:7px!important}.sun-brand-color-field input[type=text]{width:82px!important;height:30px!important;padding:4px 6px!important;border-radius:7px!important;font:700 10px ui-monospace,monospace!important;text-transform:uppercase} .sun-brand-palette-toggle{margin-top:10px}.sun-brand-palette-toggle summary{cursor:pointer;font-weight:750;color:var(--sun-ui-primary)}.sun-brand-palette{display:grid;grid-template-columns:repeat(5,minmax(90px,1fr));gap:8px;margin-top:10px}.sun-brand-swatch{border:1px solid var(--sun-ui-border);border-radius:10px;background:var(--sun-ui-card);overflow:hidden}.sun-brand-swatch-top{height:38px;background:var(--swatch)}.sun-brand-swatch-body{padding:6px 7px}.sun-brand-swatch-body b{display:block;font-size:10px}.sun-brand-swatch-body small{font:700 9px ui-monospace,monospace;color:var(--sun-ui-muted)}.sun-theme-savebar{position:sticky;bottom:0;z-index:3;display:flex;align-items:center;justify-content:space-between;gap:10px;margin:15px -13px -13px;padding:12px 13px;background:color-mix(in srgb,var(--sun-ui-card) 94%,transparent);border-top:1px solid var(--sun-ui-border);backdrop-filter:blur(10px)}.sun-theme-savebar .actions{display:flex;gap:8px;flex-wrap:wrap}.sun-theme-dirty{font-size:11px;color:var(--sun-ui-muted)}.sun-theme-dirty strong{color:var(--sun-ui-accent)} header .brand.sun-brand-home-link{cursor:pointer!important;border-radius:10px;transition:background .15s ease}.sun-enterprise-sidebar header .brand.sun-brand-home-link:hover{background:rgba(255,255,255,.06)!important}.sun-brand-home-link:focus-visible{outline:2px solid var(--sun-sidebar-indicator);outline-offset:2px} @media(max-width:1100px){.sun-brand-setting-grid{grid-template-columns:repeat(2,minmax(180px,1fr))}}@media(max-width:760px){.sun-theme-panel-main,.sun-sidebar-core-colors,.sun-brand-setting-grid{grid-template-columns:1fr}.sun-brand-palette{grid-template-columns:repeat(2,1fr)}.sun-theme-savebar{align-items:flex-start;flex-direction:column}} `;document.head.appendChild(style); function applyActual(s=savedState){ document.body.classList.remove('sun-custom-sidebar-icons'); const root=document.documentElement.style; Object.entries(s.palette).forEach(([k,v])=>root.setProperty(`--sun-brand-${k}`,v)); Object.entries(s.ui).forEach(([k,v])=>root.setProperty(`--sun-ui-${k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase())}`,v)); const map={background:'--sun-sidebar-bg',background2:'--sun-sidebar-bg2',glow:'--sun-sidebar-glow',border:'--sun-sidebar-border',icons:'--sun-sidebar-icons',iconBackground:'--sun-sidebar-icon-bg',text:'--sun-sidebar-text',muted:'--sun-sidebar-muted',activeBackground:'--sun-sidebar-active-bg',activeText:'--sun-sidebar-active-text',activeIcon:'--sun-sidebar-active-icon',indicator:'--sun-sidebar-indicator',toolsBackground:'--sun-sidebar-tools-bg',toolsBorder:'--sun-sidebar-tools-border',collapseBackground:'--sun-sidebar-collapse-bg',collapseText:'--sun-sidebar-collapse-text',badgeBackground:'--sun-sidebar-badge-bg',badgeText:'--sun-sidebar-badge-text'}; Object.entries(map).forEach(([k,v])=>root.setProperty(v,s.sidebar[k])); const header=document.querySelector('header'); if(header){ header.style.setProperty('background',`radial-gradient(circle at 12% 0%,${hexRgba(s.sidebar.glow,.30)},transparent 31%),linear-gradient(165deg,${s.sidebar.background} 0%,${s.sidebar.background2} 100%)`,'important'); header.style.setProperty('border-right',`1px solid ${s.sidebar.border}`,'important'); header.style.setProperty('box-shadow',`9px 0 34px ${hexRgba(s.sidebar.background,.22)}`,'important'); } const nav=document.querySelector('header nav'); if(nav&&matchMedia('(max-width:900px)').matches)nav.style.setProperty('background',`linear-gradient(165deg,${s.sidebar.background},${s.sidebar.background2})`,'important'); else nav?.style.removeProperty('background'); window.dispatchEvent(new CustomEvent('sunbrandthemechange',{detail:clone(s)})); } function markDirty(){dirty=JSON.stringify(previewState)!==JSON.stringify(savedState);const el=document.querySelector('[data-theme-dirty]');if(el)el.innerHTML=dirty?'Есть несохранённые изменения · пока меняется только предпросмотр':'Все изменения сохранены'} function field(scope,key,label,value){return`
    `} function paletteHtml(){return Object.keys(BRAND).map(k=>`
    ${esc(BRAND_LABELS[k])}${esc(BRAND[k])}
    `).join('')} function updatePreviewNode(card){ const p=card.querySelector('.sun-theme-preview');if(!p)return; const s=previewState.sidebar; const vars={background:'--sun-sidebar-bg',background2:'--sun-sidebar-bg2',glow:'--sun-sidebar-glow',border:'--sun-sidebar-border',icons:'--sun-sidebar-icons',iconBackground:'--sun-sidebar-icon-bg',text:'--sun-sidebar-text',muted:'--sun-sidebar-muted',activeBackground:'--sun-sidebar-active-bg',activeText:'--sun-sidebar-active-text',activeIcon:'--sun-sidebar-active-icon',indicator:'--sun-sidebar-indicator'}; Object.entries(vars).forEach(([k,v])=>p.style.setProperty(v,s[k])); } function cardHtml(){ return`

    Цвета интерфейса

    Выберите готовый вариант или настройте цвета вручную. Изменения сначала видны в примере. Реальная левая панель меняется только после «Сохранить настройки».

    Левая панель

    СолнцеПредпросмотр боковой панели
    Главная
    Заказы
    Настройки

    Главные цвета панели

    ${field('sidebar','background','Основной цвет панели',previewState.sidebar.background)}${field('sidebar','background2','Низ / второй цвет',previewState.sidebar.background2)}${field('sidebar','icons','Цвет значков',previewState.sidebar.icons)}

    Основной цвет — это фон всей большой левой панели. Для однотонной панели поставьте одинаковый цвет в первых двух полях.

    Дополнительные цвета панели
    ${Object.keys(SIDEBAR_FIRM).filter(k=>!['background','background2','icons'].includes(k)).map(k=>field('sidebar',k,SIDE_LABELS[k],previewState.sidebar[k])).join('')}

    Основной интерфейс

    ${Object.keys(UI_FIRM).map(k=>field('ui',k,UI_LABELS[k],previewState.ui[k])).join('')}
    Показать фирменные цвета «Солнца»
    ${paletteHtml()}
    ${dirty?'Есть несохранённые изменения · пока меняется только предпросмотр':'Все изменения сохранены'}
    `; } function rerender(card){card.innerHTML=cardHtml();bind(card);updatePreviewNode(card)} function bind(card){ card.querySelectorAll('[data-color-scope]').forEach(row=>{const scope=row.dataset.colorScope,key=row.dataset.colorKey,c=row.querySelector('input[type=color]'),t=row.querySelector('input[type=text]');const applyValue=v=>{const fallback=scope==='ui'?UI_FIRM[key]:SIDEBAR_FIRM[key];const val=norm(v,fallback);previewState[scope][key]=val;if(c)c.value=val;if(t)t.value=val;updatePreviewNode(card);markDirty()};c?.addEventListener('input',()=>applyValue(c.value));t?.addEventListener('input',()=>{if(isHex(t.value))applyValue(t.value)});t?.addEventListener('blur',()=>{if(!isHex(t.value))t.value=previewState[scope][key]})}); card.querySelectorAll('[data-theme-preset]').forEach(b=>b.addEventListener('click',()=>{previewState=presetState(b.dataset.themePreset);markDirty();rerender(card)})); card.querySelector('[data-theme-save]')?.addEventListener('click',()=>{savedState=clone(previewState);savedState.version=4;persist();dirty=false;applyActual(savedState);rerender(card);window.SunEnterprise?.toast?.('Настройки цветов сохранены.','success')}); card.querySelector('[data-theme-cancel]')?.addEventListener('click',()=>{previewState=clone(savedState);dirty=false;rerender(card)}); card.querySelector('[data-reset-standard]')?.addEventListener('click',()=>{if(!confirm('Вернуть стандартную фиолетовую панель и стандартные цвета интерфейса?'))return;savedState=standardState();previewState=clone(savedState);dirty=false;persist();applyActual(savedState);rerender(card);window.SunEnterprise?.toast?.('Стандартная версия восстановлена.','success')}); } function ensureCard(){const view=document.getElementById('enterprise-settings'),grid=view?.querySelector('.enterprise-grid');if(!grid)return;let card=document.getElementById('sunBrandThemeSettingsCard');if(card&&grid.contains(card)){if(!card.dataset.bound){rerender(card);card.dataset.bound='1'}return}card=document.createElement('section');card.id='sunBrandThemeSettingsCard';card.className='enterprise-card wide sun-brand-settings-card';card.innerHTML=cardHtml();const history=[...grid.children].find(el=>(el.querySelector(':scope > h2')?.textContent||'').trim()==='История изменений');if(history)window.SunSafe.insertBefore(grid,card,history);else grid.appendChild(card);bind(card);updatePreviewNode(card);card.dataset.bound='1'} function bindBrandHome(){const brand=document.querySelector('header .brand');if(!brand||brand.dataset.sunHomeBound)return;brand.dataset.sunHomeBound='1';brand.classList.add('sun-brand-home-link');brand.setAttribute('role','link');brand.setAttribute('tabindex','0');brand.setAttribute('title','Новый заказ');const go=()=>{const btn=[...document.querySelectorAll('header nav button')].find(b=>String(b.dataset.navLabel||b.textContent||'').trim()==='Новый заказ')||document.querySelector('header nav .nav-new');btn?.click()};brand.addEventListener('click',go);brand.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();go()}})} function syncFromStorage(){savedState=read();if(!dirty)previewState=clone(savedState);applyActual(savedState);const card=document.getElementById('sunBrandThemeSettingsCard');if(card&&!dirty)rerender(card)} applyActual(savedState);previewState=clone(savedState); const boot=()=>{applyActual(savedState);ensureCard();bindBrandHome();const settings=document.getElementById('enterprise-settings');if(settings)new MutationObserver(()=>queueMicrotask(()=>{if(settings.classList.contains('on')&&!document.getElementById('sunBrandThemeSettingsCard'))ensureCard();bindBrandHome()})).observe(settings,{childList:true,subtree:true});document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const name=String(b.dataset.navLabel||b.textContent||'').trim();if(name!=='Настройки'&&dirty){previewState=clone(savedState);dirty=false;const card=document.getElementById('sunBrandThemeSettingsCard');if(card)rerender(card)}},true);window.addEventListener('resize',()=>applyActual(savedState));window.addEventListener('storage',e=>{if(e.key===KEY)syncFromStorage()});window.addEventListener('suncloudsync',syncFromStorage);window.addEventListener('sun:cloud-state-applied',syncFromStorage)}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); window.SunBrandTheme={get:()=>clone(savedState),preview:()=>clone(previewState),save:()=>{savedState=clone(previewState);persist();dirty=false;applyActual(savedState)},resetStandard:()=>{savedState=standardState();previewState=clone(savedState);persist();dirty=false;applyActual(savedState);ensureCard()},applyPreset:name=>{previewState=presetState(name);dirty=true;ensureCard()}}; })(); ; /* ===== MODULE: offer-template-v1.js ===== */ /* Sun Catering: selectable client-offer templates */ (()=>{ 'use strict'; if(window.__sunOfferTemplateV1)return; window.__sunOfferTemplateV1=true; const KEY='sunOfferTemplateV1'; const DEFAULT_ID='light'; const TEMPLATES=[ {id:'light',name:'Минимализм',desc:'Светлая премиальная классика: крупная обложка, фотография, факты события и чистая сетка.',thumb:'offer-templates/thumb-light.jpg'}, {id:'midnight-glass',name:'Luxury Dark',desc:'Тёмная ресторанная презентация с золотыми акцентами и крупной food-фотографией.',thumb:'offer-templates/thumb-midnight-glass.jpg'}, {id:'editorial-grid',name:'Editorial Magazine',desc:'Редакционный журнальный макет с нумерацией разделов, крупной типографикой и фотополосой.',thumb:'offer-templates/thumb-editorial-grid.jpg'}, {id:'warm-sun',name:'Warm Sun',desc:'Тёплый фирменный дизайн в солнечной палитре с мягкими формами и сценарием подготовки.',thumb:'offer-templates/thumb-light.jpg'}, {id:'bento-cards',name:'Bento Cards',desc:'Современная карточная композиция: метрики, фото, преимущества и итог собраны в bento-сетку.',thumb:'offer-templates/thumb-light.jpg'}, {id:'event-story',name:'Event Story',desc:'Предложение как история события: таймлайн от заявки до готового стола и большая фотография.',thumb:'offer-templates/thumb-editorial-grid.jpg'}, {id:'black-gold',name:'Food First',desc:'Максимальный акцент на еде: полноэкранное фото, чёрный фон и золотая ресторанная подача.',thumb:'offer-templates/thumb-midnight-glass.jpg'}, {id:'personal-letter',name:'Personal Letter',desc:'Персональное предложение в форме красивого письма клиенту с мягкой типографикой.',thumb:'offer-templates/thumb-light.jpg'}, {id:'event-ticket',name:'Event Ticket',desc:'Дизайн приглашения/билета: данные события, меню, итог и декоративный ticket-блок.',thumb:'offer-templates/thumb-editorial-grid.jpg'}, {id:'solar-experience',name:'Solar Experience',desc:'Яркий фирменный солнечный макет с орбитальной композицией и сильным первым экраном.',thumb:'offer-templates/thumb-light.jpg'}, {id:'midnight-compact',name:'Midnight Compact · архив',desc:'Возвращённый скрытый компактный тёмный шаблон.',thumb:'offer-templates/thumb-midnight-glass.jpg'}, {id:'emerald-gold',name:'Emerald Gold · архив',desc:'Возвращённый премиальный изумрудно-золотой шаблон.',thumb:'offer-templates/thumb-emerald-gold.jpg'}, {id:'neon-emerald',name:'Neon Emerald · архив',desc:'Возвращённый скрытый неоново-изумрудный шаблон.',thumb:'offer-templates/thumb-midnight-glass.jpg'} ]; const esc=window.SunSafe.escapeHTML; function parse(){ try{ const raw=JSON.parse(localStorage.getItem(KEY)||'{}')||{}; const id=TEMPLATES.some(x=>x.id===raw.id)?raw.id:DEFAULT_ID; return {version:1,id}; }catch(_){return {version:1,id:DEFAULT_ID}} } let state=parse(); function selected(){return TEMPLATES.find(x=>x.id===state.id)||TEMPLATES[0]} function save(id){ if(!TEMPLATES.some(x=>x.id===id))id=DEFAULT_ID; state={version:1,id}; localStorage.setItem(KEY,JSON.stringify(state)); window.dispatchEvent(new CustomEvent('sunoffertemplatechange',{detail:{...state,template:selected()}})); } const style=document.createElement('style'); style.id='sun-offer-template-settings-style'; style.textContent=` .sun-offer-template-card{grid-column:1/-1!important} .sun-offer-template-card .hint{max-width:980px} .sun-offer-template-grid{display:grid;grid-template-columns:repeat(4,minmax(200px,1fr));gap:14px;margin-top:14px} .sun-offer-template-option{position:relative;border:1px solid #e3e6e9;border-radius:16px;background:#fff;padding:10px;cursor:pointer;transition:.16s ease;overflow:hidden;box-shadow:0 4px 16px rgba(30,35,40,.035)} .sun-offer-template-option:hover{transform:translateY(-1px);box-shadow:0 8px 22px rgba(30,35,40,.08)} .sun-offer-template-option.on{border-color:var(--sun-brand-sun,#FFC107);box-shadow:0 0 0 2px color-mix(in srgb,var(--sun-brand-sun,#FFC107) 30%,transparent),0 9px 24px rgba(30,35,40,.09)} .sun-offer-template-thumb{display:block;width:100%;height:245px;object-fit:cover;object-position:top center;border-radius:11px;background:#eef0f2;border:1px solid #eceef0} .sun-offer-template-info{padding:10px 3px 2px;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px 10px;align-items:start} .sun-offer-template-info strong{font-size:14px;color:#24282d}.sun-offer-template-info p{grid-column:1/-1;margin:0;color:#6c737c;font-size:11px;line-height:1.42} .sun-offer-template-check{width:25px;height:25px;border-radius:50%;border:1px solid #d8dde2;display:grid;place-items:center;color:transparent;font-weight:900;background:#fff} .sun-offer-template-option.on .sun-offer-template-check{background:var(--sun-brand-sun,#FFC107);border-color:var(--sun-brand-sun,#FFC107);color:#1a1a1a} .sun-offer-template-toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:14px;padding-top:12px;border-top:1px solid #eceef1} .sun-offer-template-toolbar .current{font-size:12px;color:#66707a}.sun-offer-template-toolbar .current b{color:#263238} @media(max-width:1100px){.sun-offer-template-grid{grid-template-columns:repeat(2,minmax(210px,1fr))}} @media(max-width:680px){.sun-offer-template-grid{grid-template-columns:1fr}.sun-offer-template-thumb{height:290px}} `; document.head.appendChild(style); function offerTemplateMini(id){ if(id==='editorial-grid')return ''; if(id==='midnight-glass')return ''; if(id==='emerald-gold')return ''; return ''; } function cardHtml(){ const cur=selected(); return `

    Шаблон предложения клиенту

    Выберите внешний вид, который будет использоваться в «Предложении клиенту» и в PDF. Реальные фотографии боксов и данные заказа остаются одинаковыми — меняется только дизайн.

    ${TEMPLATES.map(t=>``).join('')}
    Сейчас выбран: ${esc(cur.name)}
    `; } function bind(card){ const choose=(el)=>{ const id=el?.dataset?.offerTemplate;if(!id)return; save(id);card.innerHTML=cardHtml();bind(card); try{window.SunEnterprise?.toast?.(`Шаблон «${selected().name}» выбран.`)}catch(_){ } }; card.querySelectorAll('[data-offer-template]').forEach(el=>{ el.addEventListener('click',()=>choose(el)); el.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();choose(el)}}); }); card.querySelector('[data-offer-template-reset]')?.addEventListener('click',()=>{save(DEFAULT_ID);card.innerHTML=cardHtml();bind(card)}); } function ensureCard(){ const view=document.getElementById('enterprise-settings');if(!view)return; const grid=view.querySelector('.enterprise-grid');if(!grid)return; let card=document.getElementById('sunOfferTemplateSettingsCard'); if(card&&grid.contains(card))return; card=document.createElement('section');card.id='sunOfferTemplateSettingsCard';card.className='enterprise-card wide sun-offer-template-card';card.innerHTML=cardHtml(); const brand=document.getElementById('sunBrandThemeSettingsCard'); if(brand&&brand.parentElement===grid)brand.insertAdjacentElement('afterend',card);else{ const history=[...grid.children].find(el=>(el.querySelector(':scope > h2')?.textContent||'').trim()==='История изменений'); if(history)window.SunSafe.insertBefore(grid,card,history);else grid.appendChild(card); } bind(card); } function boot(){ ensureCard(); const settings=document.getElementById('enterprise-settings'); if(settings)new MutationObserver(()=>queueMicrotask(ensureCard)).observe(settings,{childList:true,subtree:true}); document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const label=(b.dataset.navLabel||b.textContent||'').trim();if(label==='Настройки')setTimeout(ensureCard,30)},true); window.addEventListener('storage',e=>{if(e.key===KEY){state=parse();ensureCard();window.dispatchEvent(new CustomEvent('sunoffertemplatechange',{detail:{...state,template:selected()}}));}}); window.addEventListener('suncloudsync',()=>{state=parse();setTimeout(ensureCard,25);window.dispatchEvent(new CustomEvent('sunoffertemplatechange',{detail:{...state,template:selected()}}));}); window.addEventListener('sun:cloud-state-applied',()=>{state=parse();setTimeout(ensureCard,25);window.dispatchEvent(new CustomEvent('sunoffertemplatechange',{detail:{...state,template:selected()}}));}); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); window.SunOfferTemplate={ key:KEY, list:()=>TEMPLATES.map(x=>({...x})), get:()=>({...state,template:{...selected()}}), set:id=>save(id) }; })(); ; /* ===== MODULE: stability-v17.js ===== */ (() => { 'use strict'; if (window.SunStabilityV17) return; const VERSION = '17.7.1'; const RELEASE = 'v17.7.1 Data Layer Adoption'; const DB_NAME = 'SunStabilityV17'; const DB_VERSION = 1; const DAILY_KEY = 'sunV17DailyBackup'; const ERROR_DEDUPE_MS=5*60*1000; const STABILITY_RPC_TIMEOUT_MS=10000; const NETWORK_BACKOFF_MAX_MS=5*60*1000; const errorSeen=new Map(); let flushBusy=false,mirrorBusy=false,backupBusy=false,initialBusy=false,networkFailures=0,nextNetworkAttemptAt=0; const $ = id => document.getElementById(id); const networkish=e=>/failed to fetch|networkerror|load failed|network|timeout|время ожидания/i.test(String(e?.message||e||'')); function noteNetworkFailure(){networkFailures=Math.min(networkFailures+1,8);nextNetworkAttemptAt=Date.now()+Math.min(NETWORK_BACKOFF_MAX_MS,5000*Math.pow(2,networkFailures-1));} function noteNetworkSuccess(){networkFailures=0;nextNetworkAttemptAt=0;} function networkReady(){return navigator.onLine&&Date.now()>=nextNetworkAttemptAt;} async function stabilityRpc(promise,label){let timer=0;try{return await Promise.race([Promise.resolve(promise),new Promise((_,reject)=>{timer=setTimeout(()=>reject(new Error(label+': timeout')),STABILITY_RPC_TIMEOUT_MS)})]);}finally{if(timer)clearTimeout(timer)}} const esc=window.SunSafe.escapeHTML; const toast=(t,k='info',ms=4500)=>{try{return window.SunEnterprise?.toast?.(t,k,ms)}catch(_){} console.log('[V17]',t)}; const cloud=()=>window.SunCloudV2; const client=()=>cloud()?.getClient?.()||null; const workspace=()=>cloud()?.getWorkspace?.()||null; const clientId=()=>cloud()?.getClientId?.()||'local'; let lastMirrorAt=''; let conflictCount=0; let booted=false; function openDb(){ return new Promise((resolve,reject)=>{ const r=indexedDB.open(DB_NAME,DB_VERSION); r.onupgradeneeded=()=>{ const db=r.result; if(!db.objectStoreNames.contains('outbox'))db.createObjectStore('outbox',{keyPath:'key'}); if(!db.objectStoreNames.contains('errors'))db.createObjectStore('errors',{keyPath:'id'}); if(!db.objectStoreNames.contains('meta'))db.createObjectStore('meta',{keyPath:'key'}); }; r.onsuccess=()=>resolve(r.result);r.onerror=()=>reject(r.error); }); } async function idbPut(store,value){try{const db=await openDb();await new Promise((res,rej)=>{const tx=db.transaction(store,'readwrite');tx.objectStore(store).put(value);tx.oncomplete=res;tx.onerror=()=>rej(tx.error)});return true}catch(_){return false}} async function idbGet(store,key){try{const db=await openDb();return await new Promise((res,rej)=>{const r=db.transaction(store,'readonly').objectStore(store).get(key);r.onsuccess=()=>res(r.result||null);r.onerror=()=>rej(r.error)})}catch(_){return null}} async function idbDelete(store,key){try{const db=await openDb();await new Promise((res,rej)=>{const tx=db.transaction(store,'readwrite');tx.objectStore(store).delete(key);tx.oncomplete=res;tx.onerror=()=>rej(tx.error)});return true}catch(_){return false}} async function idbAll(store){try{const db=await openDb();return await new Promise((res,rej)=>{const r=db.transaction(store,'readonly').objectStore(store).getAll();r.onsuccess=()=>res(r.result||[]);r.onerror=()=>rej(r.error)})}catch(_){return[]}} async function markPending(reason='change'){ const ws=workspace()?.id||'local'; const old=await idbGet('outbox',`sync:${ws}`); await idbPut('outbox',{key:`sync:${ws}`,workspaceId:ws,reason:String(reason),createdAt:old?.createdAt||Date.now(),updatedAt:Date.now(),attempts:Number(old?.attempts||0)+1}); refreshCardSoon(); } async function markSynced(revision){ const ws=workspace()?.id||'local'; await idbDelete('outbox',`sync:${ws}`); await idbPut('meta',{key:`lastSync:${ws}`,at:Date.now(),revision:Number(revision||0)}); refreshCardSoon(); } async function recordConflict(message){ conflictCount++; await idbPut('meta',{key:'lastConflict',at:Date.now(),message:String(message||''),count:conflictCount}); refreshCardSoon(); } function context(){ return {url:location.href,online:navigator.onLine,userAgent:navigator.userAgent,release:RELEASE,cloudStatus:cloud()?.status?.()||null}; } async function queueError(message,stack='',level='error',extra={}){ const text=String(message||'Unknown error').slice(0,4000),wid=workspace()?.id||null,key=level+'|'+(wid||'')+'|'+text,now=Date.now(); const seen=errorSeen.get(key)||0;if(now-seen{if(e?.error?.__sunV17Reported)return;queueError(e?.message||e?.error?.message||'Window error',e?.error?.stack||'', 'error',{source:e?.filename||'',line:e?.lineno||0,column:e?.colno||0});}); window.addEventListener('unhandledrejection',e=>{const r=e.reason;queueError(`Unhandled promise: ${r?.message||r||'unknown'}`,r?.stack||'','error');}); } async function diagnostics(){ const ws=workspace(),c=client();const outbox=await idbGet('outbox',`sync:${ws?.id||'local'}`);const errors=(await idbAll('errors')).length; let normalized=null,backups=[]; if(c&&ws?.id&&navigator.onLine){ try{const r=await c.rpc('sun_v17_entity_snapshot',{p_workspace:ws.id});if(!r.error)normalized=r.data}catch(_){} try{const r=await c.rpc('sun_v17_list_backups',{p_workspace:ws.id,p_limit:30});if(!r.error)backups=r.data||[]}catch(_){} } let localOrders=0,localCatalog=0;try{localOrders=JSON.parse(localStorage.getItem('sunOrders')||'[]').length}catch(_){}try{localCatalog=JSON.parse(localStorage.getItem('sunBoxes')||'[]').length}catch(_){} return {ws,c,outbox,errors,normalized,backups,localOrders,localCatalog,cloudStatus:cloud()?.status?.()||{}}; } async function createManualBackup(){ const c=client(),ws=workspace();if(!c||!ws?.id)return toast('Сначала войдите в облачную рабочую базу.','warn'); try{const {error}=await c.rpc('sun_v17_create_backup',{p_workspace:ws.id,p_kind:'manual',p_label:`Ручная копия · ${new Date().toLocaleString('ru-RU')}`});if(error)throw error;toast('Резервная копия создана.','success');await renderCard()}catch(e){toast(e.message||String(e),'error')} } async function restoreBackup(id){ const c=client(),ws=workspace();if(!c||!ws?.id||!id)return; if(!confirm('Восстановить выбранную резервную копию? Перед восстановлением будет автоматически создана ещё одна копия текущего состояния.'))return; try{const {error}=await c.rpc('sun_v17_restore_backup',{p_workspace:ws.id,p_backup:id});if(error)throw error;toast('Копия восстановлена. Загружаю данные…','success');await cloud()?.pull?.();setTimeout(()=>location.reload(),500)}catch(e){toast(e.message||String(e),'error')} } function emergencyExport(){ const data={format:'sun-v17-emergency-local',version:17,createdAt:new Date().toISOString(),storage:{}}; for(let i=0;iURL.revokeObjectURL(a.href),1000); } function findSettingsGrid(){return document.querySelector('#enterprise-settings .enterprise-grid')} function installStyle(){if($('sunV17Style'))return;const s=document.createElement('style');s.id='sunV17Style';s.textContent=` .sun-v17-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}.sun-v17-stat{border:1px solid #e1e6e8;border-radius:10px;padding:10px;background:#fbfcfc}.sun-v17-stat small{display:block;color:#77838b;margin-bottom:4px}.sun-v17-stat b{font-size:15px;color:#15364c}.sun-v17-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}.sun-v17-backups{margin-top:12px;border-top:1px solid #e4e8ea;padding-top:10px}.sun-v17-backup{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center;padding:7px 0;border-bottom:1px dashed #e5e8ea}.sun-v17-backup small{display:block;color:#7a858c}.sun-v17-health{font-weight:800}.sun-v17-health.good{color:#347154}.sun-v17-health.warn{color:#9a7016}.sun-v17-health.bad{color:#a64040} @media(max-width:900px){.sun-v17-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){.sun-v17-grid{grid-template-columns:1fr}} `;document.head.appendChild(s)} async function renderCard(){ // Backup/stability controls are intentionally hidden from ordinary Settings. $('sunV17StabilityCard')?.remove(); } let refreshTimer=null;function refreshCardSoon(){clearTimeout(refreshTimer);refreshTimer=setTimeout(()=>{if($('enterprise-settings')?.classList.contains('on'))renderCard()},250)} function observeSettings(){ document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;if(String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки')setTimeout(renderCard,120)},true); const root=$('enterprise-settings');if(root)new MutationObserver(()=>{if(root.classList.contains('on')&&!$('sunV17StabilityCard'))setTimeout(renderCard,80)}).observe(root,{childList:true,subtree:true,attributes:true,attributeFilter:['class']}); } async function initialMirrorIfPossible(){ const c=client(),ws=workspace();if(initialBusy||!c||!ws?.id||!networkReady())return;initialBusy=true; try{const payload=await cloud()?.snapshotLocal?.();if(payload)await mirror(payload);await ensureDailyBackup();await flushErrors()}catch(e){await queueError(e.message||String(e),e.stack||'','warn')} finally{initialBusy=false} } function boot(){if(booted)return;booted=true;installStyle();installErrorHooks();observeSettings();window.addEventListener('sun:cloud-sync-complete',onCloudSync);window.addEventListener('online',()=>{noteNetworkSuccess();flushErrors();setTimeout(initialMirrorIfPossible,900)});window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(initialMirrorIfPossible,900));setTimeout(initialMirrorIfPossible,2600);setInterval(()=>{if(networkReady())flushErrors()},60000)} window.SunStabilityV17={VERSION,RELEASE,markPending,markSynced,recordConflict,queueError,renderCard,diagnostics,createBackup:createManualBackup,emergencyExport}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); ; /* ===== MODULE: saas-v16.js ===== */ /* Sun Catering SaaS subscriptions, plan entitlements and platform admin v16 */ (()=>{ 'use strict'; if(window.SunSaaSV16)return; const VERSION='2026.08.30-saas-v16'; const $=id=>document.getElementById(id); const qa=(s,r=document)=>[...r.querySelectorAll(s)]; const esc=window.SunSafe.escapeHTML; const cloud=()=>window.SunCloudV2||null; const client=()=>cloud()?.getClient?.()||null; const workspace=()=>cloud()?.getWorkspace?.()||null; const session=()=>cloud()?.getSession?.()||null; const toast=(text,type='info',timeout=4500)=>{try{return window.SunEnterprise?.toast?.(text,type,timeout)}catch(_){console.log('[SaaS]',text)}}; const PLAN_LABELS={basic:'Базовый',professional:'Профессиональный',full:'Полный'}; const FEATURE_LABELS={ orders:'Заказы',calendar:'Календарь',map:'Карта',clients:'Клиенты',catalog_view:'Каталог',catalog_edit:'Редактирование боксов', production:'Производство',shopping:'Закупки',stock:'Склад',routes:'Маршруты',mailings:'Рассылки',money:'Деньги', stats_basic:'Статистика',stats_advanced:'Расширенная статистика',team:'Команда',suppliers:'Поставщики',print:'Печать',settings:'Настройки', branding:'Фирменное оформление',client_offers:'Предложения клиенту',offer_templates:'Шаблоны предложений',backups:'Резервные копии',audit:'История изменений',users_manage:'Сотрудники и права' }; const NAV_FEATURE={ 'Главная':'orders','Новый заказ':'orders','Заказы':'orders','Календарь':'calendar','Карта':'map','Производство':'production','Закупки':'shopping','Закупка':'shopping', 'Склад':'stock','Клиенты':'clients','Рассылки':'mailings','Деньги':'money','Команда':'team','Поставщики':'suppliers','Статистика':'stats_basic','Печать':'print','Маршруты':'routes','Настройки':'settings' }; const WRITE_FN_FEATURE={ saveBox:'catalog_edit',removeBox:'catalog_edit',editBox:'catalog_edit',openManager:'catalog_edit', sunOpenClientOffer:'client_offers',sunOpenCurrentClientOffer:'client_offers' }; const PLATFORM_FEATURES=['client_offers','offer_templates','catalog_edit','branding','users_manage','money','stock','production','routes','mailings','suppliers','audit','backups']; let snapshot=null; let lastWorkspaceId=''; let loading=false; let guardedFns=new Map(); let adminRows=[]; function hasFeature(key){ if(!key)return true; if(!snapshot)return true; // do not flash-lock before the server snapshot arrives return snapshot.features?.[key]===true; } function isWritable(){if(cloud()?.isSupportMode?.())return false;return !snapshot||snapshot.access_mode==='full';} function accessLabel(mode){return mode==='full'?'Активен':mode==='read_only'?'Только просмотр':'Заблокирован';} function statusLabel(status){return ({trialing:'Пробный период',active:'Активна',past_due:'Оплата просрочена',canceled:'Отменена',expired:'Истекла'})[status]||status||'—';} function formatDate(v){if(!v)return 'без срока';const d=new Date(v);if(Number.isNaN(d.getTime()))return '—';return d.toLocaleDateString('ru-RU');} function endDate(){return snapshot?.status==='trialing'?snapshot?.trial_ends_at:snapshot?.current_period_end;} function daysLeft(){const end=endDate();if(!end)return null;return Math.ceil((new Date(end).getTime()-Date.now())/86400000);} async function refreshSnapshot(force=false){ const c=client(),ws=workspace(); if(!c||!ws?.id){snapshot=null;lastWorkspaceId='';removeSubscriptionUi();return null;} if(loading)return snapshot; if(!force&&lastWorkspaceId===ws.id&&snapshot)return snapshot; loading=true; try{ const {data,error}=await c.rpc('sun_subscription_snapshot',{p_workspace:ws.id}); if(error)throw error; snapshot=Array.isArray(data)?(data[0]||null):data; lastWorkspaceId=ws.id; applyAll(); window.dispatchEvent(new CustomEvent('sun:subscription-changed',{detail:snapshot})); return snapshot; }catch(err){console.error('[SaaS] subscription snapshot',err);snapshot=null;} finally{loading=false;} return snapshot; } function installStyle(){ if($('sunSaaSV16Style'))return; const s=document.createElement('style');s.id='sunSaaSV16Style';s.textContent=` .sun-plan-locked{position:relative!important;opacity:.62!important;filter:saturate(.65)} header nav button.sun-plan-locked::after{content:'🔒';font-size:10px;margin-left:auto;padding-left:6px} .sun-side-collapsed #sunSaaSBadgeV16{display:none!important} .sun-saas-plan-card-locked{position:relative;opacity:.62} .sun-saas-plan-card-locked::after{content:'Доступно на другом тарифе';position:absolute;inset:auto 12px 12px auto;background:#241f3b;color:#fff;border-radius:999px;padding:5px 9px;font-size:11px;font-weight:800;z-index:4} .sun-saas-badge{margin:8px 10px 0;border:1px solid #ffffff24;border-radius:11px;padding:8px 9px;color:#fff;background:#ffffff10;font-size:11px;line-height:1.35} .sun-saas-badge b{display:block;font-size:12px}.sun-saas-badge .warn{color:#ffd36b} .sun-saas-readonly-banner{position:fixed;top:10px;left:50%;transform:translateX(-50%);z-index:9800;background:#fff6df;border:1px solid #e2bd55;color:#6a5216;border-radius:12px;padding:9px 14px;box-shadow:0 8px 30px #0002;font-weight:800;max-width:min(680px,calc(100vw - 24px));text-align:center} .sun-saas-blocked{position:fixed;inset:0;z-index:12000;background:#122b3cf2;display:grid;place-items:center;padding:20px}.sun-saas-blocked-card{width:min(520px,100%);background:#fff;border-radius:18px;padding:24px;box-shadow:0 30px 90px #0007;text-align:center}.sun-saas-blocked-card img{width:72px;height:72px;object-fit:contain}.sun-saas-blocked-card h2{margin:8px 0;color:#17384d}.sun-saas-blocked-card p{color:#596773;line-height:1.5} .sun-saas-modal{position:fixed;inset:0;z-index:11500;background:#0d2130c9;display:grid;place-items:center;padding:18px}.sun-saas-modal-card{width:min(900px,100%);max-height:92vh;overflow:auto;background:#fff;border-radius:18px;padding:20px;box-shadow:0 30px 90px #0007}.sun-saas-modal-head{display:flex;align-items:center;justify-content:space-between;gap:10px}.sun-saas-modal-head h2{margin:0;color:#17384d}.sun-saas-modal-head button{border:0;background:#eef1f2;border-radius:50%;width:34px;height:34px;font-size:20px}.sun-saas-plans{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:16px}.sun-saas-plan{border:1px solid #dfe5e8;border-radius:14px;padding:15px;background:#fafcfc}.sun-saas-plan.current{border:2px solid #ffb400;background:#fffaf0}.sun-saas-plan h3{margin:0 0 5px;color:#18384b}.sun-saas-plan ul{padding-left:18px;color:#4f5b64;font-size:12px;line-height:1.55}.sun-saas-plan .muted{color:#89939a}.sun-saas-upgrade{margin-top:12px;background:#eef4f6;border-radius:12px;padding:12px;color:#52606a} .sun-saas-settings-card .sun-saas-status-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px;margin-top:12px}.sun-saas-kpi{border:1px solid #e2e7ea;border-radius:11px;padding:10px;background:#fafcfc}.sun-saas-kpi small{display:block;color:#7a858d;margin-bottom:4px}.sun-saas-kpi b{color:#203846} #sun-saas-admin{padding:20px}.sun-saas-admin-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap}.sun-saas-admin-table{display:grid;gap:10px;margin-top:16px}.sun-saas-company{border:1px solid #dfe5e8;border-radius:14px;padding:14px;background:#fff}.sun-saas-company-top{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;flex-wrap:wrap}.sun-saas-company h3{margin:0;color:#18384b}.sun-saas-company small{color:#78828a}.sun-saas-company-actions{display:grid;grid-template-columns:1fr 110px auto auto;gap:8px;margin-top:11px;align-items:end}.sun-saas-company-actions label{font-size:11px;color:#64717a}.sun-saas-company-actions select{width:100%}.sun-saas-company-meta{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}.sun-saas-pill{border-radius:999px;padding:5px 8px;background:#eef3f5;font-size:11px}.sun-saas-pill.good{background:#eaf7ef;color:#347153}.sun-saas-pill.warn{background:#fff5dc;color:#8a681b}.sun-saas-pill.bad{background:#ffebe9;color:#993f3d} .sun-saas-onboarding-tabs{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}.sun-saas-onboarding-choice{border:1px solid #dfe5e8;background:#fafcfc;border-radius:12px;padding:12px;text-align:left}.sun-saas-onboarding-choice b{display:block;color:#17384d;margin-bottom:3px}.sun-saas-onboarding-choice small{color:#6f7980;line-height:1.35} @media(max-width:760px){.sun-saas-plans{grid-template-columns:1fr}.sun-saas-settings-card .sun-saas-status-grid{grid-template-columns:1fr 1fr}.sun-saas-company-actions{grid-template-columns:1fr 1fr}.sun-saas-company-actions button{width:100%}} `;document.head.appendChild(s); } function removeSubscriptionUi(){ $('sunSaaSBadgeV16')?.remove();$('sunSaaSReadonlyV16')?.remove();$('sunSaaSBlockedV16')?.remove();$('sunSaaSSettingsCardV16')?.remove(); qa('[data-sun-plan-locked]').forEach(el=>{el.removeAttribute('data-sun-plan-locked');el.classList.remove('sun-plan-locked')}); } function featureForNav(btn){return NAV_FEATURE[String(btn.dataset.navLabel||btn.textContent||'').trim()]||null;} function markElement(el,feature){ if(!el)return; if(feature&&!hasFeature(feature)){el.dataset.sunPlanLocked=feature;el.classList.add('sun-plan-locked');el.title=`${FEATURE_LABELS[feature]||feature} недоступно на тарифе «${snapshot?.plan_name||''}»`;} else{el.removeAttribute('data-sun-plan-locked');el.classList.remove('sun-plan-locked');} } function applyFeatureGates(){ if(!snapshot)return; qa('header nav button').forEach(btn=>{if(btn.id==='sunSaaSAdminNavV16')return;markElement(btn,featureForNav(btn));}); markElement($('sunClientOfferButton'),'client_offers');markElement($('sunAutoOfferButton'),'client_offers');markElement($('sunCloudManageUsersV3'),'users_manage');markElement($('sunCloudCreateInviteV2'),'users_manage'); qa('#new .catalog-head button,#new .tile.add').forEach(el=>markElement(el,'catalog_edit')); const cards=[ ['sunClientOfferSettingsCard','client_offers'],['sunOfferTemplateSettingsCard','offer_templates'],['sunBrandThemeSettingsCard','branding'] ]; cards.forEach(([id,feature])=>{const el=$(id);if(!el)return;el.dataset.sunFeature=feature;el.classList.toggle('sun-saas-plan-card-locked',!hasFeature(feature));}); qa('#enterprise-settings section').forEach(card=>{ const h=(card.querySelector(':scope > h2')?.textContent||'').trim();let f=null; if(/Резервн/i.test(h))f='backups';else if(/История изменений/i.test(h))f='audit'; if(f){card.dataset.sunFeature=f;card.classList.toggle('sun-saas-plan-card-locked',!hasFeature(f));} }); } function guardFunctions(){ Object.entries(WRITE_FN_FEATURE).forEach(([name,feature])=>{ const fn=window[name];if(typeof fn!=='function')return; if(fn.__sunSaasGuard)return; const wrapped=function(...args){ if(!isWritable())return showUpgrade(feature,'Подписка сейчас работает в режиме просмотра.'); if(!hasFeature(feature))return showUpgrade(feature); return fn.apply(this,args); }; wrapped.__sunSaasGuard=true;wrapped.__sunSaasOriginal=fn;window[name]=wrapped;guardedFns.set(name,wrapped); }); } function injectBadge(){ if(!snapshot)return; let badge=$('sunSaaSBadgeV16'); const brand=document.querySelector('header .brand'); if(!brand)return; if(!badge){badge=document.createElement('div');badge.id='sunSaaSBadgeV16';badge.className='sun-saas-badge';brand.insertAdjacentElement('afterend',badge);} const d=daysLeft(), trial=snapshot.status==='trialing'; badge.innerHTML=`${esc(snapshot.plan_name||PLAN_LABELS[snapshot.plan_id]||'Тариф')}${trial?`Пробный период${d!=null?` · ${Math.max(0,d)} дн.`:''}`:accessLabel(snapshot.access_mode)}`; badge.onclick=()=>showPlans();badge.title='Тариф и подписка';badge.style.cursor='pointer'; } function applyAccessMode(){ $('sunSaaSReadonlyV16')?.remove();$('sunSaaSBlockedV16')?.remove(); if(!snapshot)return; applyReadOnlyControls(); if(snapshot.access_mode==='read_only'){ const b=document.createElement('div');b.id='sunSaaSReadonlyV16';b.className='sun-saas-readonly-banner';b.textContent=`Подписка закончилась. До ${formatDate(snapshot.grace_until)} база доступна только для просмотра.`;document.body.appendChild(b); }else if(snapshot.access_mode==='blocked'){ const x=document.createElement('div');x.id='sunSaaSBlockedV16';x.className='sun-saas-blocked';x.innerHTML=`

    Доступ к компании приостановлен

    Подписка закончилась. Все данные сохранены и будут доступны сразу после продления.

    `;document.body.appendChild(x); x.querySelector('[data-saas-show-plans]').onclick=()=>showPlans();x.querySelector('[data-saas-signout]').onclick=async()=>{if(window.SunCloudV2?.signOut)return window.SunCloudV2.signOut();try{await client()?.auth.signOut()}catch(_){}location.reload();}; } } function applyReadOnlyControls(){ qa('[data-saas-readonly-disabled]').forEach(el=>{el.disabled=false;el.removeAttribute('data-saas-readonly-disabled')}); if(snapshot?.access_mode!=='read_only'&&!cloud()?.isSupportMode?.())return; qa('#new input,#new textarea,#new select,#manager input,#manager textarea,#manager select,#editor input,#editor textarea,#editor select,#orders select,#enterprise-settings input,#enterprise-settings textarea,#enterprise-settings select').forEach(el=>{if(!el.disabled){el.disabled=true;el.dataset.saasReadonlyDisabled='1';}}); } function showPlans(feature=null,note=''){ $('sunSaaSPlansModalV16')?.remove(); const m=document.createElement('div');m.id='sunSaaSPlansModalV16';m.className='sun-saas-modal'; const cards=[ {id:'basic',name:'Базовый',members:'1 пользователь',inc:['Заказы, календарь и клиенты','Каталог для работы с заказом','Базовая статистика и печать'],out:['Редактирование боксов','Предложения клиенту','Финансы и склад']}, {id:'professional',name:'Профессиональный',members:'до 3 пользователей',inc:['Всё из Базового','Производство, склад и закупки','Финансы, поставщики и маршруты','Фирменное оформление'],out:['Редактирование боксов','Предложения клиенту']}, {id:'full',name:'Полный',members:'без лимита',inc:['Все функции приложения','Редактирование каталога и боксов','Предложения клиенту и шаблоны','Команда, права и расширенные настройки'],out:[]} ]; m.innerHTML=`

    Тарифы

    ${feature?`Для функции «${esc(FEATURE_LABELS[feature]||feature)}» нужен другой тариф.`:'Выберите набор функций для компании.'}
    ${note?`
    ${esc(note)}
    `:''}
    ${cards.map(p=>`

    ${p.name}

    ${p.members}
      ${p.inc.map(x=>`
    • ${esc(x)}
    • `).join('')}${p.out.map(x=>`
    • — ${esc(x)}
    • `).join('')}
    ${snapshot?.plan_id===p.id?'Текущий тариф':'Подключение оплаты добавим на следующем этапе.'}
    `).join('')}
    Сейчас тариф можно изменить из вашего SaaS-кабинета. Автоматическую оплату подключим отдельным этапом.
    `; document.body.appendChild(m);m.onclick=e=>{if(e.target===m||e.target.closest('[data-close]'))m.remove();}; } function injectSettingsCard(){ if(!snapshot)return; const settings=$('enterprise-settings');if(!settings)return; let card=$('sunSaaSSettingsCardV16');if(!card){card=document.createElement('section');card.id='sunSaaSSettingsCardV16';card.className='enterprise-card wide sun-saas-settings-card';const first=settings.querySelector('.enterprise-grid')||settings;first.prepend(card);} const end=endDate(),d=daysLeft(); card.innerHTML=`

    Тариф и подписка

    Подписка относится ко всей компании. Данные этой рабочей базы изолированы от других компаний.

    Тариф${esc(snapshot.plan_name||PLAN_LABELS[snapshot.plan_id])}
    Статус${esc(statusLabel(snapshot.status))}
    ${snapshot.status==='trialing'?'Пробный период до':'Оплачено до'}${formatDate(end)}${d!=null&&d>=0?` · ${d} дн.`:''}
    Сотрудники${Number(snapshot.member_count||0)} / ${snapshot.max_members==null?'∞':snapshot.max_members}
    ${snapshot.platform_admin?'':''}
    `; card.querySelector('[data-saas-plans]').onclick=()=>showPlans();card.querySelector('[data-saas-admin]')?.addEventListener('click',openPlatformAdmin); } function ensureAdminView(){ if($('sun-saas-admin'))return $('sun-saas-admin'); const v=document.createElement('section');v.id='sun-saas-admin';v.className='view page';document.body.appendChild(v);return v; } function ensureAdminNav(){ const nav=document.querySelector('header nav');if(!nav||!snapshot?.platform_admin)return; if(window.SunDeveloperV22){$('sunSaaSAdminNavV16')?.remove();window.SunDeveloperV22.ensureNav?.();return;} let b=$('sunSaaSAdminNavV16');if(!b){b=document.createElement('button');b.id='sunSaaSAdminNavV16';b.type='button';b.dataset.navLabel='SaaS';b.textContent='SaaS';nav.appendChild(b);b.onclick=()=>openPlatformAdmin(b);} b.hidden=false;b.style.display=''; } async function openPlatformAdmin(btn=null){ if(window.SunDeveloperV22?.open)return window.SunDeveloperV22.open(btn); if(!snapshot?.platform_admin)return; const v=ensureAdminView();qa('.view').forEach(x=>x.classList.remove('on'));v.classList.add('on');qa('header nav button').forEach(x=>x.classList.remove('on'));(btn||$('sunSaaSAdminNavV16'))?.classList.add('on'); v.innerHTML='

    SaaS · компании

    Тарифы, сроки и доступы всех компаний.

    Загружаю компании…

    '; v.querySelector('[data-reload]').onclick=()=>loadAdminRows();await loadAdminRows(); } async function loadAdminRows(){ const v=ensureAdminView(),c=client();if(!c)return; const keepHead=v.querySelector('.sun-saas-admin-head')?.outerHTML||'';v.innerHTML=keepHead+'

    Загружаю компании…

    ';v.querySelector('[data-reload]')?.addEventListener('click',loadAdminRows); const {data,error}=await c.rpc('sun_dev_list_companies');if(error){v.insertAdjacentHTML('beforeend',`

    ${esc(error.message)}

    `);return;} adminRows=data||[]; const list=document.createElement('div');list.className='sun-saas-admin-table';list.innerHTML=adminRows.map(r=>adminRowHtml(r)).join('')||'

    Компаний пока нет.

    ';v.appendChild(list);bindAdminRows(list); } function adminRowHtml(r){ const access=r.access_mode,cls=access==='full'?'good':access==='read_only'?'warn':'bad'; return `

    ${esc(r.workspace_name)}

    ${esc(r.workspace_id)}
    ${esc(accessLabel(access))}${esc(PLAN_LABELS[r.plan_id]||r.plan_name||'—')}${Number(r.member_count||0)} / ${r.max_members==null?'∞':r.max_members} сотрудниковдо ${formatDate(r.trial_ends_at||r.current_period_end)}
    Индивидуальная функция
    `; } function bindAdminRows(root){ qa('.sun-saas-company',root).forEach(row=>{ const ws=row.dataset.ws; row.querySelector('[data-activate]').onclick=async()=>{const plan=row.querySelector('[data-plan]').value,days=Number(row.querySelector('[data-days]').value);await setSubscription(ws,plan,days,'active');}; row.querySelector('[data-expire]').onclick=async()=>{if(!confirm('Заблокировать доступ этой компании? Данные не удалятся.'))return;await setSubscription(ws,row.querySelector('[data-plan]').value,0,'expired');}; row.querySelector('[data-feature-enable]').onclick=async()=>{const feature=row.querySelector('[data-feature]').value,days=Number(row.querySelector('[data-feature-days]').value);const r=await client().rpc('sun_dev_set_feature_override',{p_workspace:ws,p_feature:feature,p_enabled:true,p_days:days,p_note:'Выдано из SaaS-кабинета'});if(r.error)return toast(r.error.message,'error');toast('Индивидуальный доступ выдан.','success');}; }); } async function setSubscription(ws,plan,days,status){ const {error}=await client().rpc('sun_dev_set_subscription',{p_workspace:ws,p_plan:plan,p_days:days,p_status:status});if(error)return toast(error.message,'error');toast('Подписка обновлена.','success');await loadAdminRows();if(workspace()?.id===ws)await refreshSnapshot(true); } function clearWorkspaceLocalData(){ const preserve=new Set(['sunCloudV2Config','sunCloudClientIdV2','sunStaticMapGeocodeCacheV2']); const keys=[];for(let i=0;ilocalStorage.removeItem(k)); } function seedWorkspace(mode){ clearWorkspaceLocalData(); if(mode==='demo'){ const demoBoxes=[ {id:'demo-box-1',name:'Демо · Рыбные канапе',category:0,catalogSection:'Боксы',price:4500,weight:520,guests:10,photo:'catalog/001.jpg',composition:['лосось','креветка','крем-чиз'],ingredients:[['Канапе рыбные',30,'шт.']]}, {id:'demo-box-2',name:'Демо · Мясные закуски',category:0,catalogSection:'Боксы',price:4200,weight:500,guests:10,photo:'catalog/002.jpg',composition:['ростбиф','пастрами','овощи'],ingredients:[['Канапе мясные',30,'шт.']]}, {id:'demo-box-3',name:'Демо · Десертный бокс',category:0,catalogSection:'Боксы',price:3900,weight:430,guests:10,photo:'catalog/003.jpg',composition:['мини-десерты','ягоды'],ingredients:[['Мини-десерты',20,'шт.']]} ]; const demoOrders=[{id:1,event:'Демо · День рождения',date:new Date(Date.now()+7*86400000).toISOString().slice(0,10),time:'18:00',contact:'Анна',phone:'+7 900 000-00-00',address:'Демо-адрес',status:'Новый',guestsCount:20,prepayment:0,lines:[{id:'demo-box-1',qty:2},{id:'demo-box-2',qty:2}]}]; localStorage.setItem('sunBoxes',JSON.stringify(demoBoxes));localStorage.setItem('sunOrders',JSON.stringify(demoOrders)); }else{ let starter=[];try{if(Array.isArray(window.SUN_OFFICIAL_CATALOG))starter=structuredClone(window.SUN_OFFICIAL_CATALOG)}catch(_){} localStorage.setItem('sunBoxes',JSON.stringify(starter));localStorage.setItem('sunOrders','[]'); if(window.SUN_OFFICIAL_CATALOG_VERSION)localStorage.setItem('sunOfficialCatalogVersion',String(window.SUN_OFFICIAL_CATALOG_VERSION)); } } function enhanceOnboardingGate(){ const gate=$('sunCloudAuthGateV3'),ss=session(),ws=workspace(),st=cloud()?.status?.();if(window.SunDeveloperV22?.isPlatformAdmin?.())return;if(!gate||!ss?.user||ws||st?.membershipsLoading||st?.membershipsLoaded===false||gate.dataset.saasEnhanced==='1')return; gate.dataset.saasEnhanced='1';const card=gate.querySelector('.sun-cloud-auth-card');if(!card)return; card.innerHTML=`

    Создайте компанию

    ${esc(ss.user.email||'Аккаунт авторизован')} · 14 дней Полного тарифа бесплатно

    У этого аккаунта пока нет рабочей базы. Приглашения временно отключены на период локального тестирования.

    `; const err=$('sunSaaSGateErrorV16'); qa('[data-create]',card).forEach(b=>b.onclick=async()=>{ const name=String($('sunSaaSCompanyNameV16')?.value||'').trim();if(!name){err.textContent='Введите название компании.';return;}b.disabled=true;err.textContent='Создаю рабочую базу…'; try{ const r=await client().rpc('sun_create_workspace',{p_name:name});if(r.error)throw r.error; const workspaceId=String(r.data||''); seedWorkspace(b.dataset.create);await cloud().adoptCurrentLocalAsWorkspace?.(workspaceId);await cloud().reloadMemberships();err.textContent='Загружаю стартовую базу…';await cloud().migrate();location.reload(); }catch(e){err.textContent=e?.message||String(e);b.disabled=false;} }); card.querySelector('[data-signout]').onclick=async()=>{if(window.SunCloudV2?.signOut)return window.SunCloudV2.signOut();try{await client()?.auth.signOut()}catch(_){}location.reload();}; } function applyAll(){installStyle();injectBadge();applyAccessMode();applyFeatureGates();guardFunctions();injectSettingsCard();ensureAdminNav();} document.addEventListener('click',e=>{ const locked=e.target.closest('[data-sun-plan-locked]');if(locked){e.preventDefault();e.stopImmediatePropagation();return showUpgrade(locked.dataset.sunPlanLocked);} const card=e.target.closest('.sun-saas-plan-card-locked');if(card){e.preventDefault();e.stopImmediatePropagation();return showUpgrade(card.dataset.sunFeature);} if(snapshot?.access_mode==='read_only'||cloud()?.isSupportMode?.()){ const t=e.target.closest('button');if(!t)return; const text=(t.textContent||'').trim();const safe=/^(Закрыть|Обновить|Предварительный просмотр|Печать|Скачать|Сравнить тарифы|Выйти|Назад|Фильтр|Поиск)/i.test(text); const mutating=/Сохран|Удал|Добав|Создать|Измен|Настро|Списать|Отправ|Активир|Заблокир|Выдать|Примен/i.test(text); if(mutating&&!safe){e.preventDefault();e.stopImmediatePropagation();showUpgrade(null,cloud()?.isSupportMode?.()?'Режим поддержки: данные компании доступны только для просмотра.':'Льготный период: база доступна только для просмотра.');} } },true); function showUpgrade(feature,note=''){showPlans(feature,note);} function boot(){ installStyle(); const timer=setInterval(async()=>{ if(document.hidden)return; // v17.5.27: onboarding is handled by the unified Caterium auth gate. const ws=workspace(); if(ws?.id&&(ws.id!==lastWorkspaceId||!snapshot))await refreshSnapshot(true); else if(ws?.id&&snapshot){applyFeatureGates();guardFunctions();injectSettingsCard();ensureAdminNav();} else if(!ws){snapshot=null;lastWorkspaceId='';} },5000); window.addEventListener('sun:cloud-state-applied',()=>refreshSnapshot(true)); window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(()=>{applyFeatureGates();guardFunctions();},50)); document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(b&&String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки')setTimeout(()=>{injectSettingsCard();applyFeatureGates();},100);},true); setTimeout(()=>refreshSnapshot(true),1200); } window.SunSaaSV16={VERSION,getSnapshot:()=>snapshot?structuredClone(snapshot):null,refresh:()=>refreshSnapshot(true),hasFeature,isWritable,showPlans,openAdmin:openPlatformAdmin}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); ; /* ===== MODULE: settings-polish-v1.js ===== */ /* Sun Catering v17.5.4: settings layout polish */ (()=>{ 'use strict'; if(window.__sunSettingsPolishV1)return; window.__sunSettingsPolishV1=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const style=document.createElement('style'); style.id='sun-settings-polish-v1-style'; style.textContent=` #enterprise-settings>.catalog-head{ position:sticky;top:0;z-index:45; margin:0 -4px 14px;padding:11px 4px 12px; background:linear-gradient(180deg,rgba(255,255,255,.99) 0%,rgba(255,255,255,.96) 80%,rgba(255,255,255,0) 100%); backdrop-filter:blur(9px); } #enterprise-settings .sun-settings-cloud-tail{grid-column:1/-1!important} `; document.head.appendChild(style); function settingsNavButton(){ return qa('header nav button').find(b=>String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки')||null; } function scrollSettingsTop(){ const view=$('enterprise-settings'); try{window.scrollTo({top:0,left:0,behavior:'auto'})}catch(_){window.scrollTo(0,0)} try{document.scrollingElement&&(document.scrollingElement.scrollTop=0)}catch(_){} try{view&&(view.scrollTop=0)}catch(_){} view?.querySelector('.catalog-head')?.scrollIntoView?.({block:'start',inline:'nearest'}); } function auditCard(grid){ return qa(':scope > .enterprise-card',grid).find(card=>(card.querySelector(':scope > h2')?.textContent||'').trim()==='История изменений')||null; } function cloudCard(grid){ return $('sunCloudV2Card')||qa(':scope > .enterprise-card',grid).find(card=>/^(Облачная синхронизация|Облако Supabase)$/.test((card.querySelector(':scope > h2')?.textContent||'').trim()))||null; } function moveBefore(node,anchor){ if(!node||!anchor||node===anchor||node.parentElement!==anchor.parentElement)return false; if(node.nextElementSibling===anchor)return false; window.SunSafe.insertBefore(anchor.parentElement,node,anchor);return true; } let ordering=false; function orderSettingsCards(){ if(ordering)return; const grid=document.querySelector('#enterprise-settings .enterprise-grid');if(!grid)return; ordering=true; try{ const audit=auditCard(grid); if(!audit)return; const requisites=$('sunReceiptSettingsCard'); const qr=$('sunDefaultQrCard'); const blank=$('sunBlankSettingsCardV3'); const cloud=cloudCard(grid); if(cloud)cloud.classList.add('sun-settings-cloud-tail','wide'); // Bottom operational block: company requisites -> QR -> order blank -> cloud -> history. // Reinsert in the desired order so dynamically injected cards settle into one stable tail block. [requisites,qr,blank,cloud].forEach(card=>{if(card&&grid.contains(card))moveBefore(card,audit)}); }finally{ordering=false;} } let timer=0; function scheduleOrder(delay=40){clearTimeout(timer);timer=setTimeout(orderSettingsCards,delay)} function boot(){ const btn=settingsNavButton(); btn?.addEventListener('click',()=>{ scrollSettingsTop(); setTimeout(scrollSettingsTop,0); setTimeout(scrollSettingsTop,100); scheduleOrder(160); scheduleOrder(420); },true); const view=$('enterprise-settings'); if(view){ new MutationObserver(()=>scheduleOrder(30)).observe(view,{childList:true,subtree:true}); if(view.classList.contains('on')){scrollSettingsTop();scheduleOrder(120)} } window.addEventListener('sun:cloud-state-applied',()=>scheduleOrder(80)); window.addEventListener('suncloudsync',()=>scheduleOrder(80)); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); ; /* ===== MODULE: address-verify-v1.js ===== */ /* Sun Catering v17.5.4: explicit precise-address verification */ (()=>{ 'use strict'; if(window.__sunAddressVerifyV1)return; window.__sunAddressVerifyV1=true; const $=id=>document.getElementById(id); const esc=window.SunSafe.escapeHTML; const val=id=>String($(id)?.value||'').trim(); const CACHE_KEY='sunPreciseAddressSearchCacheV1'; let lastRequest=0,selected=null,searchSeq=0,applying=false; const style=document.createElement('style'); style.id='sun-address-verify-v1-style'; style.textContent=` .sun-address-verify{margin-top:10px;border-top:1px solid #e5e8eb;padding-top:10px} .sun-address-verify-note{font-size:11px;line-height:1.45;color:#6d7782;margin:0 0 9px} .sun-address-candidates{display:grid;gap:7px} .sun-address-candidate{width:100%;text-align:left;border:1px solid #dfe4e8;border-radius:10px;background:#fff;padding:9px 10px;cursor:pointer;color:#2a3541} .sun-address-candidate:hover{border-color:#b9c7d0;background:#fbfcfd} .sun-address-candidate.on{border-color:#d2a438;box-shadow:0 0 0 2px rgba(210,164,56,.15);background:#fffdf7} .sun-address-candidate b{display:block;font-size:12px;line-height:1.35}.sun-address-candidate small{display:block;margin-top:3px;color:#75808a;line-height:1.35} .sun-address-candidate .sun-address-chips{display:flex;gap:5px;flex-wrap:wrap;margin-top:6px}.sun-address-candidate .sun-address-chips span{font-size:9px;font-weight:800;padding:3px 6px;border-radius:999px;background:#eef2f4;color:#53616c} .sun-address-selected{margin-top:9px;padding:9px 10px;border:1px solid #e4e7e9;border-radius:10px;background:#fafbfc;font-size:11px;color:#59656f;line-height:1.45} #orderGeoConfirm{display:none;margin-top:9px;width:100%;justify-content:center}.sun-address-verify.busy{opacity:.7;pointer-events:none} `; document.head.appendChild(style); function readCache(){try{return JSON.parse(localStorage.getItem(CACHE_KEY)||'{}')||{}}catch(_){return{}}} function writeCache(cache){try{localStorage.setItem(CACHE_KEY,JSON.stringify(cache))}catch(_){} } function cleanAddressParts(a={}){ return { region:String(a.state||a.region||'').trim(), locality:String(a.city||a.town||a.village||a.municipality||a.hamlet||a.isolated_dwelling||'').trim(), district:String(a.city_district||a.state_district||a.county||a.borough||a.suburb||'').trim(), street:String(a.road||a.pedestrian||a.residential||a.footway||a.path||'').trim(), house:String(a.house_number||'').trim(), postcode:String(a.postcode||'').trim() }; } function queryParts(){ const region=val('deliveryRegion')==='Другой регион'?'':val('deliveryRegion'); return [region,val('deliveryLocality'),val('deliveryDistrict'),val('deliveryStreet'),val('deliveryHouse')?`д. ${val('deliveryHouse')}`:'',val('deliveryCorpus')?`корп. ${val('deliveryCorpus')}`:''].filter(Boolean); } function queryText(){return queryParts().join(', ')} function mapAddress(){return queryText()} async function fetchJson(url,timeout=6500){ const controller=new AbortController(),timer=setTimeout(()=>controller.abort(),timeout); try{const r=await fetch(url,{method:'GET',mode:'cors',credentials:'omit',cache:'default',signal:controller.signal});if(!r.ok)throw new Error(`HTTP ${r.status}`);return await r.json();} finally{clearTimeout(timer)} } async function searchNominatim(query){ const wait=Math.max(0,1100-(Date.now()-lastRequest));if(wait)await new Promise(r=>setTimeout(r,wait));lastRequest=Date.now(); const region=val('deliveryRegion'); const params=new URLSearchParams({format:'jsonv2',addressdetails:'1',limit:'5',countrycodes:'ru','accept-language':'ru',q:query}); if(region==='Санкт-Петербург'||region==='Ленинградская область'){ params.set('viewbox','27.3,61.4,34.5,58.0');params.set('bounded','1'); }else if(!region){params.set('viewbox','27.3,61.4,34.5,58.0');} const data=await fetchJson(`https://nominatim.openstreetmap.org/search?${params.toString()}`); return (Array.isArray(data)?data:[]).filter(r=>Number.isFinite(Number(r.lat))&&Number.isFinite(Number(r.lon))).map(r=>({ lat:Number(r.lat),lon:Number(r.lon),formatted:String(r.display_name||query),provider:'nominatim',address:r.address||{},parts:cleanAddressParts(r.address||{}),importance:Number(r.importance||0) })); } async function searchPhoton(query){ const data=await fetchJson(`https://photon.komoot.io/api/?limit=5&lang=ru&q=${encodeURIComponent(query)}`); return (Array.isArray(data?.features)?data.features:[]).map(f=>{ const c=f?.geometry?.coordinates,p=f?.properties||{};if(!Array.isArray(c)||!Number.isFinite(Number(c[0]))||!Number.isFinite(Number(c[1])))return null; const address={state:p.state||'',city:p.city||'',town:p.city||'',county:p.county||'',road:p.street||p.name||'',house_number:p.housenumber||'',postcode:p.postcode||''}; return {lat:Number(c[1]),lon:Number(c[0]),formatted:[p.name,p.housenumber,p.street,p.district,p.city,p.county,p.state,p.postcode].filter(Boolean).join(', ')||query,provider:'photon',address,parts:cleanAddressParts(address),importance:0}; }).filter(Boolean); } async function searchCandidates(query){ const key=query.toLowerCase(),cache=readCache(); if(Array.isArray(cache[key])&&cache[key].length)return cache[key]; let rows=[];try{rows=await searchNominatim(query)}catch(_){rows=[]} if(!rows.length){try{rows=await searchPhoton(query)}catch(_){rows=[]}} if(rows.length){cache[key]=rows.slice(0,5);const keys=Object.keys(cache);if(keys.length>80)keys.slice(0,keys.length-80).forEach(k=>delete cache[k]);writeCache(cache)} return rows.slice(0,5); } function candidateTitle(c){ const p=c.parts||{}; return [p.street,p.house?`д. ${p.house}`:'',p.locality].filter(Boolean).join(', ')||c.formatted; } function candidateMeta(c){ const p=c.parts||{}; return [p.district,p.region,p.postcode].filter(Boolean).join(' · ')||c.formatted; } function renderCandidates(rows){ const host=$('sunAddressCandidates');if(!host)return; if(!rows.length){host.innerHTML='
    Точный вариант не найден. Добавьте населённый пункт или район и попробуйте ещё раз.
    ';return} host.innerHTML=rows.map((c,i)=>``).join(''); host.querySelectorAll('[data-address-candidate]').forEach(btn=>btn.addEventListener('click',()=>selectCandidate(rows[Number(btn.dataset.addressCandidate)],btn))); } function setExistingStatus(text,kind='warn'){ const s=$('orderGeoStatus');if(s){s.className=`geo-order-status ${kind}`;const span=s.querySelector('span');if(span)span.textContent=text} } function selectCandidate(candidate,button){ selected=candidate; document.querySelectorAll('.sun-address-candidate').forEach(x=>x.classList.toggle('on',x===button)); const confirm=$('orderGeoConfirm');if(confirm){confirm.style.display='inline-flex';confirm.disabled=false} const selectedBox=$('sunAddressSelected');if(selectedBox)selectedBox.innerHTML=`Выбран вариант:
    ${esc(candidate.formatted)}
    Проверьте точку ниже и нажмите «Адрес верный — использовать».`; const mini=$('orderGeoMini');if(mini&&window.SunStaticMap?.mediaHtml)mini.innerHTML=window.SunStaticMap.mediaHtml(candidate,'Проверка точного адреса')+'
    © OpenStreetMap contributors
    '; const precision=$('orderGeoPrecision');if(precision)precision.textContent=`${candidate.lat.toFixed(5)}, ${candidate.lon.toFixed(5)}`; setExistingStatus('Проверьте выбранную точку','warn'); } function setField(id,value,{onlyIf=false}={}){const el=$(id);if(!el||!value)return;if(onlyIf&&String(el.value||'').trim())return;el.value=value;el.dispatchEvent(new Event(el.tagName==='SELECT'?'change':'input',{bubbles:true}))} function normalizeRegion(region){ if(/санкт[- ]?петербург/i.test(region))return 'Санкт-Петербург'; if(/ленинград/i.test(region))return 'Ленинградская область'; return region||''; } function composeFullAddress(){ if(typeof window.sunComposeDeliveryAddress==='function')return window.sunComposeDeliveryAddress(); const parts=[val('deliveryRegion'),val('deliveryLocality'),val('deliveryDistrict'),val('deliveryStreet'),val('deliveryHouse')?`д. ${val('deliveryHouse')}`:'',val('deliveryCorpus')?`корп. ${val('deliveryCorpus')}`:'',val('deliveryEntrance')?`подъезд ${val('deliveryEntrance')}`:'',val('deliveryFloor')?`этаж ${val('deliveryFloor')}`:'',val('deliveryApartment')?`кв. ${val('deliveryApartment')}`:'',val('deliveryOffice')?`офис ${val('deliveryOffice')}`:''].filter(Boolean); const a=parts.join(', ');if($('address'))$('address').value=a;return a; } function getDraft(){try{return draft}catch(_){return null}} function getOrders(){try{return orders}catch(_){return[]}} function confirmCandidate(){ if(!selected)return; const candidate=selected,p=candidate.parts||{}; applying=true; const region=normalizeRegion(p.region); if(region){ const regionSelect=$('deliveryRegion'); if(regionSelect&&[...regionSelect.options].some(o=>o.value===region||o.text===region)){regionSelect.value=region;regionSelect.dispatchEvent(new Event('change',{bubbles:true}))} else if(regionSelect){const option=new Option(region,region);regionSelect.add(option);regionSelect.value=region;regionSelect.dispatchEvent(new Event('change',{bubbles:true}))} } const localityValue=(region==='Санкт-Петербург'&&/санкт[- ]?петербург/i.test(p.locality||''))?'':(p.locality||''); const localityEl=$('deliveryLocality');if(localityEl){localityEl.value=localityValue;localityEl.dispatchEvent(new Event('input',{bubbles:true}))} setField('deliveryDistrict',p.district||'',{onlyIf:false}); setField('deliveryStreet',p.street||val('deliveryStreet'),{onlyIf:false}); setField('deliveryHouse',p.house||val('deliveryHouse'),{onlyIf:false}); const full=composeFullAddress(); const d=getDraft(); if(d){ d.deliveryRegion=val('deliveryRegion');d.deliveryLocality=val('deliveryLocality');d.deliveryDistrict=val('deliveryDistrict');d.deliveryStreet=val('deliveryStreet');d.deliveryHouse=val('deliveryHouse');d.deliveryCorpus=val('deliveryCorpus');d.address=full; d.geo={lat:candidate.lat,lon:candidate.lon,formatted:candidate.formatted,sourceMapAddress:mapAddress(),sourceAddress:full,verifiedAt:new Date().toISOString(),confirmedAt:new Date().toISOString(),confirmed:true,provider:candidate.provider||'nominatim',geoVersion:3}; if(d.id){const saved=getOrders().find(o=>String(o.id)===String(d.id));if(saved){Object.assign(saved,{deliveryRegion:d.deliveryRegion,deliveryLocality:d.deliveryLocality,deliveryDistrict:d.deliveryDistrict,deliveryStreet:d.deliveryStreet,deliveryHouse:d.deliveryHouse,deliveryCorpus:d.deliveryCorpus,address:full,geo:structuredClone(d.geo)});try{persist()}catch(_){}}} } applying=false; if($('address'))$('address').dispatchEvent(new Event('input',{bubbles:true})); setTimeout(()=>{ setExistingStatus('Адрес подтверждён','ok'); const precision=$('orderGeoPrecision');if(precision)precision.textContent=candidate.formatted; const confirm=$('orderGeoConfirm');if(confirm){confirm.textContent='Адрес подтверждён ✓';confirm.disabled=true} const create=$('orderGeoCreate');if(create)create.textContent='Проверить другой адрес'; try{window.SunEnterprise?.toast?.('Точка доставки подтверждена.','success')}catch(_){} },20); } async function runSearch(){ const query=queryText(); if(!val('deliveryStreet')||!val('deliveryHouse')){try{window.SunEnterprise?.toast?.('Для точной проверки укажите улицу и дом.','warn')}catch(_){alert('Для точной проверки укажите улицу и дом.')}return} const root=$('sunAddressVerify');if(root)root.classList.add('busy'); const seq=++searchSeq;selected=null; const confirm=$('orderGeoConfirm');if(confirm){confirm.style.display='none';confirm.disabled=false;confirm.textContent='Адрес верный — использовать'} const host=$('sunAddressCandidates');if(host)host.innerHTML='
    Ищу подходящие адреса…
    '; setExistingStatus('Идёт поиск точного адреса','warn'); try{ const rows=await searchCandidates(query);if(seq!==searchSeq)return;renderCandidates(rows);setExistingStatus(rows.length?'Выберите точный вариант':'Адрес не найден',rows.length?'warn':'warn'); }finally{root?.classList.remove('busy')} } function resetVerification(){ if(applying)return; selected=null;searchSeq++; const host=$('sunAddressCandidates');if(host)host.innerHTML=''; const box=$('sunAddressSelected');if(box)box.innerHTML=''; const confirm=$('orderGeoConfirm');if(confirm){confirm.style.display='none';confirm.disabled=false;confirm.textContent='Адрес верный — использовать'} const d=getDraft();if(d?.geo?.confirmed){d.geo=null} } function boot(){ const geo=$('orderGeoBox'),create=$('orderGeoCreate');if(!geo||!create)return; let root=$('sunAddressVerify'); if(!root){ root=document.createElement('div');root.id='sunAddressVerify';root.className='sun-address-verify'; root.innerHTML='

    Чтобы не перепутать одинаковые улицы в разных населённых пунктах, нажмите «Проверить адрес», выберите полный вариант и подтвердите точку на карте.

    Поиск адреса: OpenStreetMap/Nominatim. © OpenStreetMap contributors.
    '; const mini=$('orderGeoMini');if(mini)window.SunSafe.insertBefore(geo,root,mini);else geo.appendChild(root); const selectedBox=$('sunAddressSelected');new MutationObserver(()=>{selectedBox.style.display=selectedBox.textContent.trim()?'block':'none'}).observe(selectedBox,{childList:true,subtree:true,characterData:true}); } let confirm=$('orderGeoConfirm'); if(!confirm){confirm=document.createElement('button');confirm.id='orderGeoConfirm';confirm.type='button';confirm.className='primary';confirm.textContent='Адрес верный — использовать';$('orderGeoMini')?.insertAdjacentElement('afterend',confirm);confirm.addEventListener('click',confirmCandidate)} create.textContent='Проверить адрес'; // Capture before the legacy handler so the app no longer silently accepts the first geocoder result. create.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();runSearch()},true); ['deliveryRegion','deliveryLocality','deliveryDistrict','deliveryStreet','deliveryHouse','deliveryCorpus'].forEach(id=>$(id)?.addEventListener(id==='deliveryRegion'?'change':'input',resetVerification)); $('address')?.addEventListener('input',()=>setTimeout(()=>{const d=getDraft();if(create&&!d?.geo?.confirmed)create.textContent='Проверить адрес'},0)); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',()=>setTimeout(boot,50),{once:true});else setTimeout(boot,50); })(); ; /* ===== MODULE: catalog-photo-resolver-v17.5.14.js ===== */ (function(){ 'use strict'; if(window.__sunCatalogPhotoResolver17514)return;window.__sunCatalogPhotoResolver17514=true; const SOURCE_URLS=["https://static.tildacdn.com/stor3131-6532-4762-a534-353638663730/11f4ce48f250257ec824a12e1c541150.jpg","https://static.tildacdn.com/stor6634-3466-4635-a164-386637346334/e94521aba11d1824218728cee4312c03.jpg","https://static.tildacdn.com/stor3034-3036-4334-b233-303363326236/d72f45ce6d6a044d8d892a0718f29d89.jpg","https://static.tildacdn.com/stor3662-3435-4561-b031-663437646233/efd5e71d2a8654b0afa26a6dd7a0595a.jpg","https://static.tildacdn.com/stor6133-6537-4533-a166-666430373166/014bff38be088e524c0a4fd2ee1daab3.jpg","https://static.tildacdn.com/stor6161-3163-4032-b338-363935363839/7b9abb2bc27c854236e234383f044c20.jpg","https://static.tildacdn.com/stor3065-6462-4666-b134-376564613831/527188ad5747060eaa88cdd6b033e1b7.jpg","https://static.tildacdn.com/stor6238-3635-4936-a361-343062343130/6c2841340110a32dee16481cf5776858.jpg","https://static.tildacdn.com/stor6231-3837-4666-b564-656661306534/a9b0efe3696fa0cd6530e3100cce2447.jpg","https://static.tildacdn.com/stor3162-6131-4337-b731-376266363535/6998754c49e80fca1df239d01e91b239.jpg","https://static.tildacdn.com/stor6264-3139-4939-b331-623963306665/c62d84a2c9de7fd115f9878617709a99.jpg","https://static.tildacdn.com/stor3134-6638-4635-b032-623233383830/413674a63540f26bbcded51a2f37c3a7.jpg","https://static.tildacdn.com/stor6438-6236-4831-b038-346437643037/b7305f8e759e161407a9996e0218cf83.jpg","https://static.tildacdn.com/stor3134-6638-4635-b032-623233383830/413674a63540f26bbcded51a2f37c3a7.jpg","https://static.tildacdn.com/stor3536-6463-4535-a135-653763366634/3b6eec9a6310eea531c8cb70b00955a9.jpg","https://static.tildacdn.com/stor3339-6634-4634-b537-363366353636/7ef8a4de7cfc055f633ab29ad7e5fca4.jpg","https://static.tildacdn.com/stor3030-3766-4661-b364-313536363731/f7a5bb4329e864b12eb5aed656c13c2b.jpg","https://static.tildacdn.com/stor3865-3463-4832-a531-326663623661/0ab2f6a1959adeb68f6c64e21fc52e6c.jpg","https://static.tildacdn.com/stor3834-6339-4234-a638-656236303531/d70c6ff9606b8f29f4d0a334643c6fa5.jpg","https://static.tildacdn.com/stor3038-3736-4564-a635-333961643763/ae631a3930ee087c993f0eb5ae477388.jpg","https://static.tildacdn.com/stor3638-3139-4562-b430-356363633431/a0eae79a99b4f1ca59be8a445d975f94.jpg","https://static.tildacdn.com/stor3536-3766-4033-b235-643062373262/1e521931b938e17b0ebe397a447067bb.jpg","https://static.tildacdn.com/stor3966-6635-4139-b965-666363393466/df421e8c29457bb6a660810c14d4dbca.jpg","https://static.tildacdn.com/stor3133-6661-4839-b565-376433313839/471052a775dfa8fae813f1b043171e21.jpg","https://static.tildacdn.com/stor3539-3831-4031-b532-323963396137/235a566973dc035faa18ef9a57b4bef6.jpg","https://static.tildacdn.com/stor6362-6234-4063-b636-373636373465/6c868c53823c2c2799bacbef8b7ec5dc.jpg","https://static.tildacdn.com/stor3439-6237-4364-a566-666531346532/a368a54d5dd3ef381bdb587f81dd3953.jpg","https://static.tildacdn.com/stor6664-6363-4635-b632-383362383935/f5779eef4eaff67dec0cb8a9868fe912.jpg","https://static.tildacdn.com/stor6166-3066-4535-b333-356263356363/25951fa13b57555854635d8fe1a1ecc9.jpg","https://static.tildacdn.com/stor3131-3637-4837-b039-386331346435/c4fd5306cc629e81fe974d0e1238eb06.jpg","https://static.tildacdn.com/stor3235-3535-4639-b164-663664323936/c3dc9dc2931b0f950034495dd8cc6b46.jpg","https://static.tildacdn.com/stor3235-3661-4038-b035-613032303361/6f2c3ac522ad9d7e73d14f3fc4c47630.jpg","https://static.tildacdn.com/stor6166-3066-4535-b333-356263356363/25951fa13b57555854635d8fe1a1ecc9.jpg","https://static.tildacdn.com/stor3836-3438-4835-a132-663962396637/fac8bc386bd98959d75c6b71cd83471b.jpg","https://static.tildacdn.com/stor3334-6361-4633-a266-643132323266/74b63ae226e1ebfbd116a822be4f642e.jpg","https://static.tildacdn.com/stor3136-3834-4562-b037-396264363263/e8c1bbdff0574f52a2184a33d6f2115c.jpg","https://static.tildacdn.com/stor6334-3534-4266-a664-356162323565/c13d0896543e32d12ccad0c0a108dac5.jpg","https://static.tildacdn.com/stor3364-6237-4561-b432-326230363433/3233d197bebae6174651a7732ec8ca3e.jpg","https://static.tildacdn.com/stor3239-6231-4130-a363-643732356464/1a72939cda10b9fc447157193a2c69cf.jpg","https://static.tildacdn.com/stor3832-3732-4635-b732-636135393265/3e414b433c0aab18c0a1131d256c92e5.jpg","https://static.tildacdn.com/stor6431-3634-4935-a638-323064343638/8d7c3b547b6e5abd09fe498c2e0b3853.jpg","https://static.tildacdn.com/stor3362-3331-4631-b738-646138333763/b3932c942568e83ab0babc98b77ee5c3.jpg","https://static.tildacdn.com/stor3565-6565-4739-b638-343639336130/ce325e928513a5c7ad2a5c9328927bd0.jpg","https://static.tildacdn.com/stor3131-3335-4135-b962-356338643761/dabf8e59f8b405c2998cc725627a832a.jpg","https://static.tildacdn.com/stor6365-6464-4263-b066-653333643438/eba899d7b96c0e9f077467bb4076cf56.jpg","https://static.tildacdn.com/stor3064-6631-4061-b231-393166393931/2e792a2bd15012a2c134a17213d64706.jpg","https://static.tildacdn.com/stor3936-6435-4438-a564-643362376266/c0d42f2444a396f1b836f4f5e2d2a2b8.jpg","https://static.tildacdn.com/stor6635-6661-4361-b031-303465633437/9c824de9c9ad08c435f64d62876ca8f2.jpg","https://static.tildacdn.com/stor6530-6533-4235-b631-613831393533/2651153cdc6a396acfe9c7c1f1ffa6e3.jpg","https://static.tildacdn.com/stor3566-6437-4361-b137-343366323736/8f1f58eb858f669ca4acea85ad8bbbce.jpg","https://static.tildacdn.com/stor3363-3539-4532-b731-343434323163/3d114d5bd96795183d342a37ef5bacb7.jpg","https://static.tildacdn.com/stor3234-6630-4664-b230-616165303866/a350de68077dc437a4a7c0d1f07db97b.jpg","https://static.tildacdn.com/stor6566-6236-4038-b038-326331333761/acfb6d855c780c92c4cd6e667229a9d7.jpg","https://static.tildacdn.com/stor3662-3963-4031-b065-646235373965/f8f3bd5b10fe9142e453766305684126.jpg","https://static.tildacdn.com/stor3461-3363-4063-a530-336136633338/951f5c4bcaa35b878fd8f0d4cdf5812a.jpg","https://static.tildacdn.com/stor6335-3638-4432-b230-393163396334/d08deb92d2102c1e81002f0ff5b1cd18.jpg","https://static.tildacdn.com/stor3163-3035-4466-b435-303832663162/2a85461ba4c7132af333c481f6974334.jpg","https://static.tildacdn.com/stor3132-6233-4466-b164-376530633465/a5159b1de5f6bd3d2dde7609c1853f82.jpg","https://static.tildacdn.com/stor3165-6138-4663-b433-393039653034/4ad56410ecf6a163824061d08cb297da.jpg","https://static.tildacdn.com/stor6437-6361-4833-a537-623832376136/29ff2e5084a5f816954ea5621004b0c0.jpg","https://static.tildacdn.com/stor3765-3765-4663-a333-623738326235/02eaafb2bae5cef3edaa761aa7cea142.jpg","https://static.tildacdn.com/stor6365-3039-4931-a333-623061333865/ceb789e801d358ff78f2a4800f79f78c.jpg","https://static.tildacdn.com/stor6262-6636-4563-b332-383166313034/73a699e67040500f90edd197152cb0b9.jpg","https://static.tildacdn.com/stor3366-3663-4664-a136-633432326530/8a056937be29f8f531767a565fc2fb45.jpg","https://static.tildacdn.com/stor3566-3862-4334-b465-376164633737/7ad059a9bf198827dfd142008f81bb28.jpg","https://static.tildacdn.com/stor3532-6333-4432-b037-373031393364/3f233fc73a9932953876810c2530779b.jpg","https://static.tildacdn.com/stor6461-6235-4134-a630-393261313034/f00b5038885f425bf4463b0f070416b2.jpg","https://static.tildacdn.com/stor3963-3634-4262-b363-393536623037/7f3160b562bdb81243fcca8b07ea73ca.jpg","https://static.tildacdn.com/stor6134-6534-4032-b863-326334303439/b6299036af0105e24b66b92fc149fceb.jpg","https://static.tildacdn.com/stor6330-3331-4534-a431-616637323265/cc72f08366e2b3bb3b2cec181fcfb6b2.jpg","https://static.tildacdn.com/stor3864-6138-4939-a263-323633343831/e41074621630fb64c6551fde54a0491a.jpg","https://static.tildacdn.com/stor3530-3337-4465-a331-393235636139/6bed2df48d65e7dfdf673cc6ab1d66f0.jpg","https://static.tildacdn.com/stor3132-6432-4637-b930-353763333565/0e6665f2fddcdc6a2538ff0e4d6714e3.jpg","https://static.tildacdn.com/stor3063-6361-4562-b864-386439643866/5a0a9e8680146e4af16b0b3a71e5e344.jpg","https://static.tildacdn.com/stor3864-3766-4132-a362-336565363634/331d7a3cb423efad3851318ebc243503.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3661-6362-4365-a166-396432366336/b3461ed10ad1d21ba6f327e14f87561a.jpg","https://static.tildacdn.com/stor6136-3763-4363-b632-613035666139/b89d5f88da96f52526ccba83cfb1e631.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3764-3435-4336-a638-386530643039/b66c7fb8fba795f74358798f008ff284.jpg","https://static.tildacdn.com/stor3530-3337-4465-a331-393235636139/6bed2df48d65e7dfdf673cc6ab1d66f0.jpg","https://static.tildacdn.com/stor3535-3432-4638-b763-636162616233/f392e1f738f4ec51be28ac85ff7f34d1.jpg","https://static.tildacdn.com/stor6263-6138-4433-a639-386465356138/915334ed7ec0a973fc528d5b1bcddeb9.jpg","https://static.tildacdn.com/stor6161-3666-4430-b437-303230613863/b6c27133c86b74e669c4d8d14cddaa98.jpg","https://static.tildacdn.com/stor6433-6530-4938-a264-366133396635/26c04c584ac3ce62893f86e3f21ef6a4.jpg","https://static.tildacdn.com/stor3438-3336-4038-b563-636464663765/26624b9790a69468292e752308984af1.jpg","https://static.tildacdn.com/stor3430-3734-4935-a666-616161393566/92e1260daf92944a35c6ce5a64ca38f3.jpg","https://static.tildacdn.com/stor3937-3731-4331-a333-333266353435/018e8f56c6b0053168f0d0cf73872966.jpg","https://static.tildacdn.com/stor3939-3434-4061-a231-636661616561/607dc1f31bc1ca66fb1a611d49407aa5.jpg","https://static.tildacdn.com/stor3836-3436-4239-a536-353332396264/232fcd6e93bf0abc918ef73529cded4b.jpg","https://static.tildacdn.com/stor3065-3632-4533-b333-636566613663/7979f348481e979905836febdf7933a6.jpg","https://static.tildacdn.com/stor3761-3162-4461-b966-323139613763/08d95a9c71b402415f9479b3f9520892.jpg","https://static.tildacdn.com/stor3033-3137-4930-b264-666532373134/69925db7e39c25877ac58869c15037a6.jpg","https://static.tildacdn.com/stor3333-3839-4537-a236-623030313665/4130c8f6bd2b58b41c4edd83eee922a9.jpg","https://static.tildacdn.com/stor6230-3133-4564-b237-646535613637/a2a99a4eeb22cb33b5b5cea2a79a17cb.jpg","https://static.tildacdn.com/stor3137-6538-4132-b739-653932333233/15a1c8db984c5e68f357b2ee12a18c2a.jpg","https://static.tildacdn.com/stor3031-6132-4334-b330-633933383437/7e711a925bef78f54c6417cfed424f7b.jpg","https://static.tildacdn.com/stor6565-3862-4536-a531-396336343530/94e933aa7cb2ca8cc2f9a6975508c69b.jpg","https://static.tildacdn.com/stor3130-6665-4166-a562-346464663365/1ace83e57a93e4bd15c4117e6ebd10f4.jpg","https://static.tildacdn.com/stor6666-6336-4235-b437-663731323432/f733be8a64d1186ac1153c3eba271d59.jpg","https://static.tildacdn.com/stor6561-6664-4163-a232-323236383637/1b4aa616a89592851de475a7633530b2.jpg","https://static.tildacdn.com/stor3364-3366-4961-a230-393136633735/bd16ccb4240c13b0408fcd3cdb263c7f.jpg","https://static.tildacdn.com/stor3133-3966-4466-a633-353062663934/19cfdd0803e1252edb0a229fe8cc10e1.jpg","https://static.tildacdn.com/stor3862-3737-4631-a637-656265333935/be0ca89c31666c8d357814c69f0c1527.jpg","https://static.tildacdn.com/stor3730-3136-4137-b861-393762656436/9b8faf6a48cff9bc8b16cef36396d144.jpg","https://static.tildacdn.com/stor6137-3965-4334-a432-316165313635/7e2aebaffa009dfc1b7a580ceac8a640.jpg","https://static.tildacdn.com/stor3937-3432-4537-a233-646339376631/d0ca8846eba6810423c5421e7060c567.jpg","https://static.tildacdn.com/stor3437-6365-4139-b134-326232643133/8d0a33ea4f3ace73aa73679aa8ac3b4d.jpg","https://static.tildacdn.com/stor6334-3463-4166-b330-643438393235/49f88576b7fb7573735b20dc4161de96.jpg","https://static.tildacdn.com/stor3139-3866-4633-a234-663139643733/5c7060058669060670ed95fb719078c3.jpg"]; const pad=n=>String(Math.max(1,Math.min(113,Number(n)||0))).padStart(3,'0'); const indexFrom=value=>{ const s=String(value||''); let m=s.match(/current-(\d{3})\.jpg/i);if(m)return Number(m[1]); m=s.match(/catalog-20260902-(\d{3})/i);if(m)return Number(m[1]); const clean=s.split(/[?#]/)[0],remoteIndex=SOURCE_URLS.findIndex(url=>url===clean); return remoteIndex>=0?remoteIndex+1:0; }; function indexFor(itemOrPath){ if(itemOrPath&&typeof itemOrPath==='object'){ const byPhoto=indexFrom(itemOrPath.photo);if(byPhoto)return byPhoto; const byId=indexFrom(itemOrPath.id);if(byId)return byId; const byOrder=Number(itemOrPath.catalogOrder||0);if(byOrder>=1&&byOrder<=113)return byOrder; } return indexFrom(itemOrPath); } function candidates(itemOrPath){ const idx=indexFor(itemOrPath); if(!idx)return [String(itemOrPath&&typeof itemOrPath==='object'?itemOrPath.photo||'':itemOrPath||'')].filter(Boolean); const local=`catalog/current-${pad(idx)}.jpg`; const api=(location.protocol==='http:'||location.protocol==='https:')?`/api/catalog-photo?i=${idx}`:''; const remote=SOURCE_URLS[idx-1]||''; const requested=String(itemOrPath&&typeof itemOrPath==='object'?itemOrPath.photo||'':itemOrPath||''); return [...new Set([requested,local,api,remote,'sun-logo.png'].filter(Boolean))]; } function fallbackImage(img){ if(!(img instanceof HTMLImageElement))return; let idx=Number(img.dataset.sunCatalogPhotoIndex||0)||indexFor(img.getAttribute('src')||img.src); if(!idx)return; img.dataset.sunCatalogPhotoIndex=String(idx); const list=candidates(`catalog/current-${pad(idx)}.jpg`); let step=Number(img.dataset.sunCatalogPhotoStep||0); const currentAbs=(()=>{try{return new URL(img.getAttribute('src')||img.src,document.baseURI).href}catch(_){return String(img.src||'')}})(); while(step{const img=event.target;if(img instanceof HTMLImageElement)fallbackImage(img)},true); function repairExisting(){document.querySelectorAll('img').forEach(img=>{if(indexFor(img.getAttribute('src')||'')&&img.complete&&img.naturalWidth===0)fallbackImage(img)})} setTimeout(repairExisting,60);setTimeout(repairExisting,650); window.SunCatalogPhoto={sourceUrls:SOURCE_URLS,indexFor,candidates,fallbackImage,repairExisting}; })(); /* ===== MODULE: settings-tabs-v21.js ===== */ /* Sun Catering v17.5.21: grouped Settings tabs without rewriting existing settings cards. */ (()=>{ 'use strict'; if(window.__sunSettingsTabsV21)return; window.__sunSettingsTabsV21=true; const $=id=>document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const TAB_KEY='sunSettingsActiveTabV1'; const TABS=[ {id:'account',label:'Аккаунт',hint:'Профиль, компания, тариф, пользователи и история изменений.'}, {id:'appearance',label:'Оформление',hint:'Цвета интерфейса, боковой панели и готовые цветовые варианты.'}, {id:'offer',label:'Предложение',hint:'Шаблон и содержимое предложения клиенту.'}, {id:'orders',label:'Заказы',hint:'Статусы заказов и цвета состояния оплаты.'}, {id:'references',label:'Справочники',hint:'Типы мероприятий, источники клиентов и вкладки каталога.'}, {id:'documents',label:'Документы',hint:'Реквизиты чека, QR-код и бланк заказа.'} ]; const VALID=new Set(TABS.map(x=>x.id)); let active=(()=>{try{const v=localStorage.getItem(TAB_KEY);return VALID.has(v)?v:'account'}catch(_){return'account'}})(); let scheduled=0; const style=document.createElement('style'); style.id='sun-settings-tabs-v21-style'; style.textContent=` #enterprise-settings .sun-settings-tabs-wrap{margin:0 0 14px;min-width:0} #enterprise-settings .sun-settings-tabs{display:flex;gap:6px;overflow-x:auto;overscroll-behavior-inline:contain;scrollbar-width:thin;padding:3px 2px 7px;white-space:nowrap} #enterprise-settings .sun-settings-tab{flex:1 1 0;min-width:118px;border:1px solid #dce2e6;border-radius:10px;background:#fff;color:#53616c;padding:10px 12px;font-size:13px;font-weight:800;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease,box-shadow .15s ease} #enterprise-settings .sun-settings-tab:hover{background:#f7f9fa;border-color:#c8d1d7} #enterprise-settings .sun-settings-tab.on{background:#15364c;color:#fff;border-color:#15364c;box-shadow:0 5px 14px rgba(21,54,76,.13)} #enterprise-settings .sun-settings-tab:focus-visible{outline:3px solid rgba(212,154,42,.28);outline-offset:2px} #enterprise-settings .sun-settings-tab-context{display:flex;gap:7px;align-items:baseline;flex-wrap:wrap;padding:2px 4px 0;color:#6a7680;font-size:12px;line-height:1.4} #enterprise-settings .sun-settings-tab-context b{color:#15364c;font-size:13px} #enterprise-settings .enterprise-card{order:var(--sun-settings-order,50)} #enterprise-settings .enterprise-card[hidden]{display:none!important} #enterprise-settings.on #sunBlankSettingsCardV3[hidden]{display:none!important} #enterprise-settings .enterprise-grid{align-items:start} #enterprise-settings #sunCatalogTabsSettingsCardV21 .sun-settings-catalog-summary{display:flex;gap:7px;flex-wrap:wrap;margin:10px 0 2px} #enterprise-settings #sunCatalogTabsSettingsCardV21 .sun-settings-catalog-chip{display:inline-flex;align-items:center;border-radius:999px;background:#f2f5f6;color:#52616c;padding:5px 8px;font-size:11px;font-weight:800} @media(max-width:900px){ #enterprise-settings .sun-settings-tabs{margin-right:-4px;padding-right:16px} #enterprise-settings .sun-settings-tab{flex:0 0 auto;min-width:126px} #enterprise-settings .sun-settings-tab-context{padding-right:8px} } @media(max-width:520px){ #enterprise-settings .sun-settings-tabs-wrap{margin-bottom:11px} #enterprise-settings .sun-settings-tab{min-width:116px;padding:9px 11px;font-size:12px} #enterprise-settings .sun-settings-tab-context span{display:block;width:100%} } `; document.head.appendChild(style); function heading(card){return String(card?.querySelector(':scope > h2')?.textContent||card?.querySelector('h2')?.textContent||'').trim()} function classify(card){ const id=String(card?.id||''),h=heading(card); if(id==='sunCloudV2Card'||id==='sunSaaSSettingsCardV16'||/^(Профиль и аккаунт|Облачная синхронизация|Тариф и подписка|Пользователи и роли|История изменений)$/.test(h)){ const order=id==='sunCloudV2Card'||/^(Профиль и аккаунт|Облачная синхронизация)$/.test(h)?10:id==='sunSaaSSettingsCardV16'||h==='Тариф и подписка'?20:h==='Пользователи и роли'?30:90; return['account',order]; } if(id==='sunBrandThemeSettingsCard'||/^(Цвета интерфейса|Настройки интерфейса|Оформление интерфейса)$/.test(h))return['appearance',10]; if(id==='sunOfferTemplateSettingsCard'||h==='Шаблон предложения клиенту')return['offer',10]; if(id==='sunClientOfferSettingsCard'||h==='Настройки предложения клиенту')return['offer',20]; if(id==='sunOrderPaymentColorsCard'||h==='Цвета оплаты заказов')return['orders',10]; if(id==='sunOrderStatusFeatureCard'||h==='Статусы заказов')return['orders',20]; if(id==='sunEventTypesSettingsCard'||h==='Типы мероприятий')return['references',10]; if(id==='sunLeadSourcesSettingsCard'||h==='Источники клиентов')return['references',20]; if(id==='sunCatalogTabsSettingsCardV21'||h==='Вкладки каталога')return['references',30]; if(id==='sunReceiptSettingsCard'||h==='Настройки реквизитов товарного чека')return['documents',10]; if(id==='sunDefaultQrCard'||h==='QR-код для бланка заказа')return['documents',20]; if(id==='sunBlankSettingsCardV3'||h==='Настройки бланка')return['documents',30]; // Any future/unrecognised settings remain reachable instead of disappearing. return['account',60]; } function ensureCatalogTabsCard(){ const view=$('enterprise-settings'),grid=view?.querySelector('.enterprise-grid'); if(!grid||typeof window.sunOpenCategoryManager!=='function')return; let card=$('sunCatalogTabsSettingsCardV21'); if(!card){ card=document.createElement('section'); card.id='sunCatalogTabsSettingsCardV21'; card.className='enterprise-card wide'; grid.appendChild(card); } const cats=typeof window.sunCatalogCategories==='function'?window.sunCatalogCategories():[]; const total=Array.isArray(cats)?cats.length:0,visible=Array.isArray(cats)?cats.filter(x=>!x.hidden).length:0; card.innerHTML=`

    Вкладки каталога

    Название, порядок, цвет и видимость разделов каталога. Скрытые разделы и их товары не удаляются.

    Всего: ${total}Видимых: ${visible}
    `; $('sunSettingsCatalogTabsBtnV21')?.addEventListener('click',()=>window.sunOpenCategoryManager?.()); } function ensureBar(){ const view=$('enterprise-settings');if(!view)return null; let wrap=$('sunSettingsTabsWrapV21'); if(!wrap){ wrap=document.createElement('div');wrap.id='sunSettingsTabsWrapV21';wrap.className='sun-settings-tabs-wrap'; wrap.innerHTML=`
    ${TABS.map(t=>``).join('')}
    `; const head=view.querySelector(':scope > .catalog-head'); if(head)head.insertAdjacentElement('afterend',wrap);else view.prepend(wrap); qa('[data-settings-tab-target]',wrap).forEach(btn=>btn.addEventListener('click',()=>activate(btn.dataset.settingsTabTarget,true))); } return wrap; } function applyCards(){ const view=$('enterprise-settings'),grid=view?.querySelector('.enterprise-grid');if(!grid)return; qa(':scope > .enterprise-card',grid).forEach(card=>{ const [tab,order]=classify(card); card.dataset.settingsTab=tab; card.style.setProperty('--sun-settings-order',String(order)); card.hidden=tab!==active; card.setAttribute('aria-hidden',tab===active?'false':'true'); }); } function renderBar(){ const wrap=ensureBar();if(!wrap)return; const meta=TABS.find(x=>x.id===active)||TABS[0]; qa('[data-settings-tab-target]',wrap).forEach(btn=>{ const on=btn.dataset.settingsTabTarget===active; btn.classList.toggle('on',on);btn.setAttribute('aria-selected',on?'true':'false');btn.tabIndex=on?0:-1; if(on&&wrap.dataset.lastActive!==active)setTimeout(()=>btn.scrollIntoView?.({block:'nearest',inline:'nearest',behavior:'smooth'}),0); }); wrap.dataset.lastActive=active; const context=$('sunSettingsTabContextV21');if(context)context.innerHTML=`${meta.label}${meta.hint}`; } function activate(tab,persist=false){ if(!VALID.has(tab))tab='account';active=tab; if(persist){try{localStorage.setItem(TAB_KEY,active)}catch(_){}} renderBar();applyCards(); const view=$('enterprise-settings');if(view?.classList.contains('on')){ try{view.querySelector('.sun-settings-tabs-wrap')?.scrollIntoView({block:'nearest',inline:'nearest'})}catch(_){} } window.dispatchEvent(new CustomEvent('sun:settings-tab-changed',{detail:{tab:active}})); } function refresh(){ const view=$('enterprise-settings');if(!view)return; ensureCatalogTabsCard();ensureBar();applyCards();renderBar(); } function schedule(delay=30){clearTimeout(scheduled);scheduled=setTimeout(refresh,delay)} function boot(){ const view=$('enterprise-settings');if(!view)return; const observer=new MutationObserver(()=>schedule(20));observer.observe(view,{childList:true,subtree:true}); document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(b&&String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки'){schedule(0);schedule(90);schedule(240)}},true); window.addEventListener('sun:catalog-categories-changed',()=>schedule(20)); window.addEventListener('sun:cloud-state-applied',()=>schedule(40)); window.addEventListener('suncloudsync',()=>schedule(40)); refresh(); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); /* ===== MODULE: developer-console-v22.js ===== */ (()=>{ 'use strict'; if(window.SunDeveloperV22)return; const VERSION='2026.09.06-developer-console-v25-auth-mfa-logo'; const $=id=>String(id||'').startsWith('#')?document.querySelector(id):document.getElementById(id); const qa=(sel,root=document)=>[...root.querySelectorAll(sel)]; const esc=window.SunSafe.escapeHTML; const clone=v=>v==null?v:(typeof structuredClone==='function'?structuredClone(v):JSON.parse(JSON.stringify(v))); const cloud=()=>window.SunCloudV2||null; const client=()=>cloud()?.getClient?.()||null; const session=()=>cloud()?.getSession?.()||null; const toast=(t,k='info',ms=4600)=>{try{return window.SunEnterprise?.toast?.(t,k,ms)}catch(_){};alert(t)}; const fmtDate=v=>{if(!v)return '—';try{return new Date(v).toLocaleString('ru-RU',{dateStyle:'short',timeStyle:'short'})}catch(_){return String(v)}}; const fmtDay=v=>{if(!v)return '—';try{return new Date(v).toLocaleDateString('ru-RU')}catch(_){return String(v)}}; const TAB_KEY='sunDeveloperActiveTabV22'; const TABS=[['overview','Обзор'],['companies','Компании'],['accounts','Аккаунты'],['plans','Тарифы'],['features','Функции'],['system','Система'],['backups','Резервные копии'],['journal','Журнал']]; const FEATURES={orders:'Заказы',calendar:'Календарь',map:'Карта',clients:'Клиенты',catalog_view:'Каталог · просмотр',catalog_edit:'Каталог · редактирование',production:'Производство',shopping:'Закупки',stock:'Склад',routes:'Маршруты',mailings:'Рассылки',money:'Финансы',stats_basic:'Статистика',stats_advanced:'Расширенная статистика',team:'Команда',suppliers:'Поставщики',print:'Печать',settings:'Настройки',branding:'Фирменное оформление',client_offers:'Предложение клиенту',offer_templates:'Шаблоны предложения',backups:'Резервные копии',audit:'Журнал',users_manage:'Пользователи и права'}; const PLANS={basic:'Базовый',professional:'Профессиональный',full:'Полный'}; let platformAdmin=false,checking=false,activeTab=localStorage.getItem(TAB_KEY)||'overview',lastCompanies=[],lastAdminCheckAt=0; const DEV_ADMIN_TTL_MS=30000,DEV_ADMIN_TIMEOUT_MS=8000; function installStyle(){if($('sunDeveloperV22Style'))return;const st=document.createElement('style');st.id='sunDeveloperV22Style';st.textContent=` #sunDeveloperNavV22{font-weight:800}.sun-dev-view{max-width:1460px;margin:0 auto;padding:24px}.sun-dev-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:14px}.sun-dev-head h1{margin:0}.sun-dev-head-actions{display:flex;gap:8px;flex-wrap:wrap}.sun-dev-tabs{display:flex;gap:7px;overflow-x:auto;padding:4px 2px 12px;scrollbar-width:thin;border-bottom:1px solid #e7e8ec;margin-bottom:18px}.sun-dev-tabs button{white-space:nowrap;border:1px solid #d8dbe2;background:#fff;border-radius:999px;padding:9px 14px;font-weight:750;cursor:pointer}.sun-dev-tabs button.on{background:#171815;color:#fff;border-color:#171815}.sun-dev-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.sun-dev-kpi,.sun-dev-card{background:#fff;border:1px solid #e2e4e9;border-radius:16px;padding:16px;box-shadow:0 8px 28px rgba(30,32,36,.04)}.sun-dev-kpi small{color:#6f7480;display:block;margin-bottom:7px}.sun-dev-kpi b{font-size:24px}.sun-dev-card h2,.sun-dev-card h3{margin:0 0 10px}.sun-dev-toolbar{display:flex;gap:8px;align-items:end;flex-wrap:wrap;margin-bottom:12px}.sun-dev-toolbar label{min-width:180px}.sun-dev-toolbar input,.sun-dev-toolbar select,.sun-dev-card input,.sun-dev-card select,.sun-dev-card textarea{width:100%;box-sizing:border-box;padding:9px 10px;border:1px solid #d6d9df;border-radius:9px;background:#fff}.sun-dev-table-wrap{overflow:auto;border:1px solid #e2e4e9;border-radius:14px;background:#fff}.sun-dev-table{width:100%;border-collapse:collapse;min-width:900px}.sun-dev-table th,.sun-dev-table td{text-align:left;padding:11px 12px;border-bottom:1px solid #eceef2;vertical-align:top;font-size:13px}.sun-dev-table th{background:#f7f8fa;position:sticky;top:0;z-index:1}.sun-dev-actions{display:flex;gap:6px;flex-wrap:wrap}.sun-dev-pill{display:inline-flex;padding:4px 8px;border-radius:999px;background:#f0f2f5;font-size:11px;font-weight:750;margin:2px}.sun-dev-pill.ok{background:#e8f7ef;color:#14653b}.sun-dev-pill.warn{background:#fff3d9;color:#7d5300}.sun-dev-pill.bad{background:#fde8e8;color:#9d2424}.sun-dev-muted{color:#777d88;font-size:12px}.sun-dev-section-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.sun-dev-modal{position:fixed;inset:0;background:rgba(20,22,26,.52);z-index:100000;display:flex;align-items:center;justify-content:center;padding:18px}.sun-dev-modal-card{background:#fff;border-radius:18px;max-width:620px;width:min(620px,100%);max-height:90vh;overflow:auto;padding:20px;box-shadow:0 24px 80px rgba(0,0,0,.28)}.sun-dev-modal-head{display:flex;justify-content:space-between;gap:12px;align-items:center}.sun-dev-modal-head h2{margin:0}.sun-dev-modal-close{border:0;background:#f1f2f4;border-radius:10px;width:36px;height:36px;font-size:22px;cursor:pointer}.sun-dev-mfa-qr{max-width:220px;width:100%;display:block;margin:12px auto;border:10px solid #fff}.sun-dev-support-banner{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:99995;background:#171815;color:#fff;border-radius:14px;padding:10px 12px;box-shadow:0 12px 36px rgba(0,0,0,.28);display:flex;align-items:center;gap:10px;max-width:calc(100vw - 30px)}.sun-dev-support-banner b{white-space:nowrap}.sun-dev-support-banner button{background:#fff;color:#171815;border:0;border-radius:9px;padding:7px 10px;font-weight:800;cursor:pointer}.sun-dev-danger{border:1px solid #efc8c8!important;color:#9f2424!important;background:#fff!important}.sun-dev-code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;background:#f5f6f8;border-radius:8px;padding:7px;overflow-wrap:anywhere}.sun-dev-empty{padding:26px;text-align:center;color:#747a84}.sun-dev-check{display:flex;align-items:center;gap:8px}.sun-dev-check input{width:18px!important;height:18px}.sun-dev-pre{white-space:pre-wrap;word-break:break-word;font:12px/1.45 ui-monospace,SFMono-Regular,Consolas,monospace;background:#f7f8fa;padding:12px;border-radius:10px;max-height:340px;overflow:auto} @media(max-width:950px){.sun-dev-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.sun-dev-section-grid{grid-template-columns:1fr}.sun-dev-view{padding:15px}.sun-dev-head{flex-direction:column}.sun-dev-head-actions{width:100%}} @media(max-width:540px){.sun-dev-grid{grid-template-columns:1fr}.sun-dev-support-banner{left:15px;right:15px;transform:none;flex-wrap:wrap}.sun-dev-support-banner b{white-space:normal}} `;document.head.appendChild(st)} async function rpc(name,args={}){const c=client();if(!c)throw new Error('Supabase не подключён.');const r=await c.rpc(name,args);if(r.error)throw r.error;return r.data} async function log(action,workspace=null,user=null,details={}){try{await rpc('sun_dev_log_event',{p_action:action,p_workspace:workspace,p_user:user,p_details:details})}catch(_){}} async function checkPlatformAdmin(force=false){ if(checking)return platformAdmin;const now=Date.now();if(!force&&lastAdminCheckAt&&now-lastAdminCheckAt{timer=setTimeout(()=>reject(new Error('Developer access timeout')),DEV_ADMIN_TIMEOUT_MS)})]);platformAdmin=!r.error&&r.data===true;} catch(_){platformAdmin=false}finally{clearTimeout(timer);lastAdminCheckAt=Date.now();checking=false;syncChrome()}return platformAdmin } function isPlatformAdmin(){return platformAdmin===true} function ensureNav(){installStyle();const nav=document.querySelector('header nav');if(!nav||!platformAdmin)return null;$('sunSaaSAdminNavV16')?.remove();let b=$('sunDeveloperNavV22');if(!b){b=document.createElement('button');b.id='sunDeveloperNavV22';b.type='button';b.dataset.navLabel='Разработчик';b.textContent='Разработчик';nav.appendChild(b);b.addEventListener('click',()=>open(b))}b.hidden=false;b.style.display='';return b} function ensureView(){let v=$('sun-developer-console-v22');if(!v){v=document.createElement('section');v.id='sun-developer-console-v22';v.className='view page sun-dev-view';document.body.appendChild(v)}return v} function showDevView(btn=null){const v=ensureView();qa('.view').forEach(x=>x.classList.remove('on'));v.classList.add('on');qa('header nav button').forEach(x=>x.classList.remove('on'));(btn||$('sunDeveloperNavV22'))?.classList.add('on');window.scrollTo({top:0,behavior:'instant'});return v} function shell(){const v=ensureView();v.innerHTML=`

    Кабинет разработчика

    Управление платформой, компаниями и техническим состоянием приложения.

    Developer${esc(session()?.user?.email||'')}
    ${TABS.map(([id,label])=>``).join('')}
    Загрузка…
    `;qa('[data-dev-tab]',v).forEach(b=>b.onclick=()=>activateTab(b.dataset.devTab));$('sunDevRefresh').onclick=()=>activateTab(activeTab,true)} async function open(btn=null){if(!await checkPlatformAdmin(true))return toast('Этот аккаунт не имеет прав разработчика.','error');if(!await ensureDeveloperMfa())return;ensureNav();showDevView(btn);shell();await activateTab(activeTab,true)} async function activateTab(tab,force=false){if(!TABS.some(x=>x[0]===tab))tab='overview';activeTab=tab;localStorage.setItem(TAB_KEY,tab);qa('[data-dev-tab]').forEach(b=>b.classList.toggle('on',b.dataset.devTab===tab));const body=$('sunDevBody');if(!body)return;body.innerHTML='
    Загрузка…
    ';try{if(tab==='overview')await renderOverview(body);else if(tab==='companies')await renderCompanies(body);else if(tab==='accounts')await renderAccounts(body);else if(tab==='plans')await renderPlans(body);else if(tab==='features')await renderFeatures(body);else if(tab==='system')await renderSystem(body);else if(tab==='backups')await renderBackups(body);else if(tab==='journal')await renderJournal(body)}catch(e){body.innerHTML=`

    Не удалось загрузить раздел

    ${esc(e?.message||e)}

    `}} function modal(title,html){$('sunDevModalV22')?.remove();const m=document.createElement('div');m.className='sun-dev-modal';m.id='sunDevModalV22';m.innerHTML=`

    ${esc(title)}

    ${html}
    `;document.body.appendChild(m);const close=()=>m.remove();m.addEventListener('click',e=>{if(e.target===m||e.target.closest('[data-close]'))close()});return {m,body:$('#sunDevModalBody'),close}} function confirmDanger(text){return confirm(text)} async function ensureDeveloperMfa(){ const c=client();if(!c?.auth?.mfa)throw new Error('Supabase MFA недоступна.'); const readAal=async()=>{const a=await c.auth.mfa.getAuthenticatorAssuranceLevel();if(a.error)throw a.error;return a.data||{}}; const waitAal2=async()=>{for(let i=0;i<12;i++){const a=await readAal();if(a.currentLevel==='aal2')return true;await new Promise(r=>setTimeout(r,180))}return false}; const initial=await readAal();if(initial.currentLevel==='aal2')return true; const listed=await c.auth.mfa.listFactors();if(listed.error)throw listed.error; let factor=(listed.data?.totp||[]).find(f=>f.status==='verified');let enrollment=null; if(!factor){ for(const f of (listed.data?.totp||[]).filter(x=>x.status!=='verified')){ try{const u=await c.auth.mfa.unenroll({factorId:f.id});if(u.error&&!/not found/i.test(String(u.error.message||'')))throw u.error}catch(e){console.warn('[Developer MFA] reset factor',e)} } const enr=await c.auth.mfa.enroll({factorType:'totp',friendlyName:'Caterium Developer'});if(enr.error)throw enr.error;factor=enr.data;enrollment=enr.data; } const firstSetup=Boolean(enrollment),qr=enrollment?.totp?.qr_code||'',secret=enrollment?.totp?.secret||''; const ui=modal(firstSetup?'Подключение 2FA разработчика':'Подтверждение разработчика',firstSetup?`

    Отсканируйте этот QR-код приложением-аутентификатором. Затем введите текущие 6 цифр и нажмите Подтвердить и открыть.

    ${qr?`QR для 2FA`:''}${secret?`

    Если QR не сканируется, добавьте ключ вручную:

    ${esc(secret)}
    `:''}
    `:`

    Введите текущий 6-значный код из приложения-аутентификатора.

    `); return await new Promise(resolve=>{ let settled=false,busy=false; const finish=v=>{if(settled)return;settled=true;try{ui.close()}catch(_){}resolve(v)}; const showError=(e,notify=true)=>{const msg=e?.message||String(e||'Не удалось подтвердить код.');const box=$('sunDevMfaError');if(box)box.textContent=msg;if(notify)toast(msg,'error',6500)}; const verify=async()=>{ if(busy)return; const code=String(document.getElementById('sunDevMfaCode')?.value||'').replace(/\D/g,''); if(code.length!==6){showError(new Error('Введите ровно 6 цифр из приложения-аутентификатора.'),false);return} busy=true;const btn=$('sunDevMfaVerify');if(btn){btn.disabled=true;btn.textContent='Проверяю…'};const box=$('sunDevMfaError');if(box)box.textContent='Проверяю код…'; try{ let vr; if(typeof c.auth.mfa.challengeAndVerify==='function') vr=await c.auth.mfa.challengeAndVerify({factorId:factor.id,code}); else {const ch=await c.auth.mfa.challenge({factorId:factor.id});if(ch.error)throw ch.error;vr=await c.auth.mfa.verify({factorId:factor.id,challengeId:ch.data.id,code})} if(vr?.error)throw vr.error; if(!await waitAal2()){ try{await c.auth.refreshSession()}catch(_){} if(!await waitAal2())throw new Error('Код принят, но сессия разработчика не получила AAL2. Выйдите из аккаунта и войдите снова, затем повторите код.'); } toast('2FA подтверждена. Открываю кабинет разработчика…','success',2800); finish(true); }catch(e){busy=false;if(btn){btn.disabled=false;btn.textContent='Подтвердить и открыть'};showError(e)} }; const b=document.getElementById('sunDevMfaVerify'),inp=document.getElementById('sunDevMfaCode');if(b)b.addEventListener('click',verify);if(inp)inp.addEventListener('keydown',e=>{if(e.key==='Enter'){e.preventDefault();verify()}}); ui.m.addEventListener('click',e=>{if((e.target===ui.m||e.target.closest('[data-close]'))&&!busy)finish(false)}); setTimeout(()=>inp?.focus(),60); }) } async function renderOverview(body){const d=await rpc('sun_dev_dashboard');body.innerHTML=`
    Компании${Number(d.companies||0)}
    Аккаунты${Number(d.accounts||0)}
    Активные подписки${Number(d.active_subscriptions||0)}
    Ограниченные компании${Number(d.restricted_companies||0)}
    Ошибки за 24 ч.${Number(d.errors_24h||0)}
    Копии за 24 ч.${Number(d.backups_24h||0)}
    Участники компаний${Number(d.memberships||0)}
    Размер БД${esc(d.database_size||'—')}

    Платформа

    Версия приложения: 17.6.0

    PostgreSQL: ${esc(d.postgres_version||'—')}

    Последнее изменение рабочей базы: ${fmtDate(d.last_state_at)}

    Безопасность

    MFA AAL2 Кабинет разработчика защищён двухфакторной авторизацией.

    Права разработчика проверяются сервером через sun_platform_admins.

    `;try{const r=await fetch('release-manifest.json',{cache:'no-store'});if(r.ok){const m=await r.json();$('#sunDevReleaseVersion').textContent=m.version||'17.6.0'}}catch(_){} } async function getCompanies(){let rows=[];try{rows=await rpc('sun_dev_list_companies')}catch(_){rows=await rpc('sun_dev_list_companies')}lastCompanies=Array.isArray(rows)?rows:[];return lastCompanies} function companyOptions(rows,selected=''){return `${rows.map(r=>``).join('')}`} async function renderCompanies(body){const rows=await getCompanies();body.innerHTML=`
    КомпанияВладелецТарифДоступСотрудникиСозданаДействия
    `;const draw=()=>{const q=String($('#sunDevCompanySearch').value||'').trim().toLowerCase();const filtered=rows.filter(r=>`${r.workspace_name||''} ${r.owner_email||''}`.toLowerCase().includes(q));$('#sunDevCompaniesTbody').innerHTML=filtered.map(r=>`${esc(r.workspace_name)}
    ${esc(r.workspace_id)}
    ${esc(r.owner_email||r.pending_owner_email||'—')}${r.pending_owner_email?'
    ожидает регистрации
    ':''}${esc(PLANS[r.plan_id]||r.plan_name||r.plan_id||'—')}
    до ${fmtDay(r.trial_ends_at||r.current_period_end)}
    ${esc(r.access_mode||r.status||'—')}${Number(r.member_count||0)} / ${r.max_members==null?'∞':r.max_members}${fmtDay(r.created_at)}
    `).join('')||'Компаний не найдено.';bindCompanyRows()};draw();$('#sunDevCompanySearch').oninput=draw;$('#sunDevCreateCompany').onclick=openCreateCompany} function bindCompanyRows(){qa('#sunDevCompaniesTbody tr[data-ws]').forEach(tr=>{const ws=tr.dataset.ws,row=lastCompanies.find(x=>String(x.workspace_id)===ws);tr.querySelector('[data-support]').onclick=()=>enterSupport(row);tr.querySelector('[data-diag]').onclick=()=>showDiagnostics(row);tr.querySelector('[data-plan]').onclick=()=>showCompanyPlan(row);tr.querySelector('[data-block]').onclick=async()=>{const blocked=row.access_mode==='blocked';if(!blocked&&!confirmDanger(`Заблокировать компанию «${row.workspace_name}»? Данные не удалятся.`))return;await rpc('sun_dev_set_subscription',{p_workspace:ws,p_plan:row.plan_id||'full',p_days:blocked?30:0,p_status:blocked?'active':'expired'});await log(blocked?'company.unblock':'company.block',ws,null,{company:row.workspace_name});toast(blocked?'Компания разблокирована.':'Компания заблокирована.','success');activateTab('companies',true)}})} function openCreateCompany(){const ui=modal('Создать компанию',`

    Компания получит текущий стартовый каталог (${Number(window.SUN_OFFICIAL_CATALOG?.length||0)} позиций), а заказы и клиенты будут пустыми.

    `);$('#sunDevNewCreate').onclick=async()=>{const name=String($('#sunDevNewCompanyName').value||'').trim(),email=String($('#sunDevNewOwnerEmail').value||'').trim(),plan=$('#sunDevNewPlan').value,days=Number($('#sunDevNewDays').value||30);if(!name)return $('#sunDevNewError').textContent='Введите название.';const btn=$('#sunDevNewCreate');btn.disabled=true;$('#sunDevNewError').textContent='Создаю…';try{const data=await rpc('sun_dev_create_company',{p_name:name,p_owner_email:email||null,p_plan:plan,p_days:days,p_boxes:Array.isArray(window.SUN_OFFICIAL_CATALOG)?window.SUN_OFFICIAL_CATALOG:[],p_catalog_version:String(window.SUN_OFFICIAL_CATALOG_VERSION||'')});ui.body.innerHTML=`

    Компания создана: ${esc(data.workspace_name||name)}

    Каталог: ${Number(data.catalog_count||0)} позиций.

    ${data.owner_status==='invite'?`

    Владелец ещё не зарегистрирован. Код приглашения сохранён на сервере.

    `:''}
    `;setTimeout(()=>activateTab('companies',true),400)}catch(e){btn.disabled=false;$('#sunDevNewError').textContent=e?.message||String(e)}}} function showCompanyPlan(row){const ui=modal(`Тариф · ${row.workspace_name}`,`
    `);$('#sunDevPlanSave').onclick=async()=>{await rpc('sun_dev_set_subscription',{p_workspace:row.workspace_id,p_plan:$('#sunDevPlanSelect').value,p_days:Number($('#sunDevPlanDays').value),p_status:'active'});await log('company.subscription.set',row.workspace_id,null,{plan:$('#sunDevPlanSelect').value,days:Number($('#sunDevPlanDays').value)});ui.close();toast('Тариф обновлён.','success');activateTab('companies',true)}} async function showDiagnostics(row){const d=await rpc('sun_dev_workspace_diagnostics',{p_workspace:row.workspace_id});modal(`Диагностика · ${row.workspace_name}`,`
    Заказы${Number(d.orders||0)}
    Клиенты${Number(d.clients||0)}
    Каталог${Number(d.catalog_items||0)}
    Ошибки 24 ч.${Number(d.errors_24h||0)}

    Revision: ${Number(d.revision||0)}

    Обновлено: ${fmtDate(d.state_updated_at)}

    Последняя копия: ${fmtDate(d.latest_backup)}

    Режим доступа: ${esc(d.access_mode||'—')}

    `)} async function enterSupport(row){if(!row)return;await cloud().enterSupportWorkspace(row.workspace_id,row.workspace_name);await log('support.ui_enter',row.workspace_id,null,{company:row.workspace_name});ensureSupportBanner();try{window.render?.();window.renderOrders?.();window.renderStats?.()}catch(_){}const orders=qa('header nav button').find(b=>String(b.dataset.navLabel||b.textContent||'').trim()==='Заказы');if(orders)orders.click();else{qa('.view').forEach(v=>v.classList.remove('on'));$('orders')?.classList.add('on')}toast('Режим поддержки открыт. Изменения не будут сохранены.','info',6500)} function ensureSupportBanner(){let b=$('sunDevSupportBannerV22');const sm=cloud()?.getSupportMode?.();if(!sm){b?.remove();return}if(!b){b=document.createElement('div');b.id='sunDevSupportBannerV22';b.className='sun-dev-support-banner';document.body.appendChild(b)}b.innerHTML=`Поддержка:${esc(sm.name||'Компания')}только просмотр`;b.querySelector('button').onclick=async()=>{try{await log('support.exit',sm.workspaceId,null,{company:sm.name});await cloud().exitSupportWorkspace()}catch(e){toast(e?.message||String(e),'error')}}} async function fetchAccounts(){const rows=await rpc('sun_dev_list_users');const map=new Map();for(const r of rows||[]){const id=String(r.user_id);if(!map.has(id))map.set(id,{id,email:r.email,created_at:r.created_at,last_sign_in_at:r.last_sign_in_at,email_confirmed_at:'',is_platform_admin:r.is_platform_admin===true,is_banned:false,authAdminActions:false,workspaces:[]});if(r.workspace_id)map.get(id).workspaces.push({id:r.workspace_id,name:r.workspace_name,role:r.role,is_active:r.is_active!==false})}return [...map.values()]} async function renderAccounts(body){const users=await fetchAccounts();body.innerHTML=`
    ${users.length} аккаунтов
    АккаунтКомпанииРегистрацияПоследний входСтатусДействия
    `;const draw=()=>{const q=String($('#sunDevUserSearch').value||'').trim().toLowerCase();const arr=users.filter(u=>`${u.email||''} ${(u.workspaces||[]).map(w=>w.name).join(' ')}`.toLowerCase().includes(q));$('#sunDevUsersTbody').innerHTML=arr.map(u=>`${esc(u.email||'—')}${u.is_platform_admin?'
    Разработчик
    ':''}
    ${esc(u.id)}
    ${(u.workspaces||[]).length?(u.workspaces||[]).map(w=>`${esc(w.name)} · ${esc(w.role||'')}`).join(''):'—'}${fmtDate(u.created_at)}${fmtDate(u.last_sign_in_at)}${u.is_banned?'заблокирован':'активен'}${u.email_confirmed_at?'
    email подтверждён
    ':''}${u.authAdminActions?`
    ${u.is_platform_admin?'':``}
    `:'Просмотр аккаунта доступен. Глобальная блокировка Auth и письмо восстановления требуют защищённой backend-функции.'}`).join('')||'Ничего не найдено.';qa('#sunDevUsersTbody tr[data-user]').forEach(tr=>{const u=users.find(x=>String(x.id)===tr.dataset.user);tr.querySelector('[data-recovery]')?.addEventListener('click',()=>authAdminAction('send_recovery',u));tr.querySelector('[data-ban]')?.addEventListener('click',()=>authAdminAction('set_ban',u,{banned:!u.is_banned}))})};draw();$('#sunDevUserSearch').oninput=draw} async function authAdminAction(action,u,extra={}){if(action==='set_ban'&&extra.banned&&!confirmDanger(`Заблокировать вход для ${u.email}?`))return;const r=await client().functions.invoke('caterium-platform-auth-admin',{body:{action,user_id:u.id,...extra}});if(r.error)throw r.error;if(r.data?.error)throw new Error(r.data.error);toast(action==='send_recovery'?'Письмо восстановления отправлено.':extra.banned?'Аккаунт заблокирован.':'Аккаунт разблокирован.','success');activateTab('accounts',true)} async function renderPlans(body){const c=client();const [plansR,featuresR]=await Promise.all([c.from('sun_plans').select('id,name,description,max_members,is_active,sort_order').order('sort_order'),c.from('sun_plan_features').select('plan_id,feature_key,enabled')]);if(plansR.error)throw plansR.error;if(featuresR.error)throw featuresR.error;const plans=plansR.data||[],features=featuresR.data||[];body.innerHTML=`
    ${plans.map(p=>`

    ${esc(p.name)}

    ${esc(p.description||'')}

    Функции

    ${Object.keys(FEATURES).map(f=>{const row=features.find(x=>x.plan_id===p.id&&x.feature_key===f);return ``}).join('')}
    `).join('')}
    `;qa('[data-plan-card]').forEach(card=>{const plan=card.dataset.planCard;card.querySelector('[data-save-max]').onclick=async()=>{const raw=card.querySelector('[data-max]').value;await rpc('sun_dev_set_plan_max_members',{p_plan:plan,p_max_members:raw===''?null:Number(raw)});toast('Лимит сохранён.','success')};qa('[data-feature]',card).forEach(ch=>ch.onchange=async()=>{ch.disabled=true;try{await rpc('sun_dev_set_plan_feature',{p_plan:plan,p_feature:ch.dataset.feature,p_enabled:ch.checked});toast('Матрица тарифа обновлена.','success')}catch(e){ch.checked=!ch.checked;toast(e?.message||String(e),'error')}finally{ch.disabled=false}})})} async function renderFeatures(body){const rows=lastCompanies.length?lastCompanies:await getCompanies();body.innerHTML=`
    Выберите компанию.
    `;const load=async()=>{const ws=$('#sunDevFeatureCompany').value;if(!ws)return;const data=await rpc('sun_dev_list_workspace_features',{p_workspace:ws});const root=$('sunDevFeatureBody');root.className='sun-dev-table-wrap';root.innerHTML=`${(data||[]).map(f=>``).join('')}
    ФункцияПо тарифуИндивидуальноИтогДействия
    ${esc(FEATURES[f.feature_key]||f.feature_key)}${f.plan_enabled?'✓':'—'}${f.override_enabled==null?'нет':f.override_enabled?'включено':'выключено'}
    ${f.override_expires_at?`до ${fmtDay(f.override_expires_at)}`:''}
    ${f.effective_enabled?'доступна':'закрыта'}
    `;qa('tr[data-feature]',root).forEach(tr=>{const f=tr.dataset.feature;tr.querySelector('[data-enable]').onclick=()=>setOverride(ws,f,true,30,load);tr.querySelector('[data-disable]').onclick=()=>setOverride(ws,f,false,30,load);tr.querySelector('[data-reset]').onclick=async()=>{await rpc('sun_dev_reset_feature_override',{p_workspace:ws,p_feature:f});toast('Индивидуальное правило сброшено.','success');load()}})};$('#sunDevFeatureLoad').onclick=load;$('#sunDevFeatureCompany').onchange=load} async function setOverride(ws,f,en,days,refresh){await rpc('sun_dev_set_feature_override',{p_workspace:ws,p_feature:f,p_enabled:en,p_days:days,p_note:'Developer console v17.6.0'});await log('feature.override.set',ws,null,{feature:f,enabled:en,days});toast('Индивидуальная функция обновлена.','success');await refresh()} async function renderSystem(body){const cfg=cloud()?.getTechnicalConfig?.()||{},d=await rpc('sun_dev_dashboard');let stability=null;try{stability=await window.SunStabilityV17?.diagnostics?.()}catch(_){}const rows=lastCompanies.length?lastCompanies:await getCompanies();body.innerHTML=`

    Подключение Supabase

    Эти параметры скрыты от обычных пользователей.

    Состояние

    База: ${esc(d.database_size||'—')}

    PostgreSQL: ${esc(d.postgres_version||'—')}

    Последняя синхронизация: ${fmtDate(cfg.lastSync)}

    Ошибки 24 ч.: ${Number(d.errors_24h||0)}

    Client ID: ${esc(cloud()?.getClientId?.()||'')}

    Стартовый каталог

    ${Number(window.SUN_OFFICIAL_CATALOG?.length||0)} позиций · версия ${esc(window.SUN_OFFICIAL_CATALOG_VERSION||'—')}

    Новые компании получают этот каталог автоматически. Существующие компании не меняются без явной команды.

    Диагностика клиента

    ${esc(stability?JSON.stringify(stability,null,2):'Диагностика stability-модуля недоступна.')}
    `;$('#sunDevAutoSync').onchange=e=>cloud().setAutoSyncDeveloper?.(e.target.checked);$('#sunDevReconnect').onclick=async()=>{if(!confirmDanger('Переподключить приложение к указанному Supabase? Неверные данные могут временно лишить приложение облака.'))return;await cloud().setTechnicalConnection($('#sunDevSupabaseUrl').value,$('#sunDevSupabaseKey').value);toast('Подключение обновлено.','success')};$('#sunDevForceCatalog').onclick=async()=>{const ws=$('#sunDevCatalogCompany').value;if(!ws)return toast('Выберите компанию.','warn');const row=rows.find(r=>r.workspace_id===ws);if(!confirmDanger(`ЗАМЕНИТЬ каталог компании «${row?.workspace_name||ws}» текущим стартовым каталогом? Собственный каталог компании будет перезаписан.`))return;const n=await rpc('sun_dev_seed_workspace_catalog',{p_workspace:ws,p_boxes:window.SUN_OFFICIAL_CATALOG||[],p_catalog_version:String(window.SUN_OFFICIAL_CATALOG_VERSION||''),p_replace:true});toast(`Каталог заменён: ${n} позиций.`,'success',6500)}} async function renderBackups(body){const rows=lastCompanies.length?lastCompanies:await getCompanies();body.innerHTML=`
    Выберите компанию.
    `;const load=async()=>{const ws=$('#sunDevBackupCompany').value;if(!ws)return;const data=await rpc('sun_v17_list_backups',{p_workspace:ws,p_limit:60});const root=$('sunDevBackupBody');root.className='sun-dev-table-wrap';root.innerHTML=`${(data||[]).map(b=>``).join('')||''}
    ДатаТипМеткаIDДействия
    ${fmtDate(b.created_at)}${esc(b.kind)}${esc(b.label||'—')}${esc(b.id)}
    Копий нет.
    `;qa('tr[data-backup]',root).forEach(tr=>tr.querySelector('[data-restore]').onclick=async()=>{if(!confirmDanger('Восстановить эту резервную копию? Перед восстановлением автоматически создастся новая копия текущего состояния.'))return;await rpc('sun_v17_restore_backup',{p_workspace:ws,p_backup:tr.dataset.backup});await log('backup.restore',ws,null,{backup_id:tr.dataset.backup});toast('Резервная копия восстановлена.','success',6500);load()})};$('#sunDevBackupLoad').onclick=load;$('#sunDevBackupCompany').onchange=load;$('#sunDevBackupCreate').onclick=async()=>{const ws=$('#sunDevBackupCompany').value;if(!ws)return toast('Выберите компанию.','warn');const id=await rpc('sun_v17_create_backup',{p_workspace:ws,p_kind:'manual',p_label:'Создано из кабинета разработчика'});await log('backup.create',ws,null,{backup_id:id});toast('Резервная копия создана.','success');load()}} async function renderJournal(body){const [activity,errors]=await Promise.all([rpc('sun_dev_list_activity',{p_limit:150}),rpc('sun_dev_list_errors',{p_workspace:null,p_limit:100})]);body.innerHTML=`

    Действия разработчика

    ${(activity||[]).map(a=>``).join('')||''}
    ДатаДействиеКомпания / аккаунтДетали
    ${fmtDate(a.created_at)}${esc(a.action)}
    ${esc(a.actor_email||'')}
    ${esc(a.workspace_name||a.target_email||'—')}${esc(JSON.stringify(a.details||{}))}
    Записей пока нет.

    Ошибки приложения

    ${(errors||[]).map(e=>``).join('')||''}
    ДатаКомпанияВерсияОшибка
    ${fmtDate(e.created_at)}${esc(e.workspace_name||'—')}${esc(e.app_version||'—')}${esc(e.level||'error')}
    ${esc(e.message||'')}
    Ошибок нет.
    `} function enhanceDeveloperGate(){const gate=$('sunCloudAuthGateV3'),ss=session(),ws=cloud()?.getWorkspace?.(),st=cloud()?.status?.();if(!platformAdmin||!gate||!ss?.user||ws||st?.membershipsLoading||st?.membershipsLoaded===false)return;const card=gate.querySelector('.sun-cloud-auth-card');if(!card||card.dataset.devEnhanced==='1')return;card.dataset.devEnhanced='1';gate.dataset.saasEnhanced='1';card.innerHTML=`
    Caterium

    Аккаунт разработчика

    ${esc(ss.user.email||'')}

    Этот аккаунт управляет платформой и не обязан иметь собственную рабочую компанию.

    `;card.querySelector('[data-open-dev]').onclick=()=>open();card.querySelector('[data-signout]').onclick=()=>cloud()?.signOut?.()} function syncChrome(){if(platformAdmin){ensureNav();enhanceDeveloperGate()}else{$('sunDeveloperNavV22')?.remove()}ensureSupportBanner()} function boot(){installStyle();let tries=0;const timer=setInterval(async()=>{tries++;if(document.hidden)return;if(client()&&session()?.user){await checkPlatformAdmin(false);enhanceDeveloperGate();ensureSupportBanner()}else if(!session()?.user){platformAdmin=false;syncChrome()}if(tries>40)clearInterval(timer)},3000);window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(()=>checkPlatformAdmin(true),120));window.addEventListener('sun:cloud-state-applied',()=>ensureSupportBanner());document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;if(String(b.dataset.navLabel||b.textContent||'').trim()==='Настройки'&&platformAdmin)setTimeout(()=>{$('sunSaaSSettingsCardV16')?.querySelector('[data-saas-admin]')?.remove()},120)},true);setTimeout(()=>checkPlatformAdmin(true),900)} window.SunDeveloperV22={VERSION,open,isPlatformAdmin,checkPlatformAdmin,ensureNav,activateTab,ensureSupportBanner}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })(); /* ===== MODULE: chat-v31.js ===== */ (() => { 'use strict'; if (window.SunChatV31) return; const VERSION = '2026.09.06-chat-v31'; const $ = id => document.getElementById(id); const qa = (s,r=document) => [...r.querySelectorAll(s)]; const esc=window.SunSafe.escapeHTML; const toast = (text,type='info',timeout=4500) => { try { if(window.SunEnterprise?.toast) return window.SunEnterprise.toast(text,type,timeout); } catch (_) {} alert(text); }; const ROLE_LABELS = {admin:'Администратор',manager:'Менеджер',kitchen:'Кухня',courier:'Курьер',viewer:'Просмотр'}; let threads = []; let members = []; let messages = []; let activeThread = null; let workspaceChannel = null; let threadChannel = null; let workspaceChannelId = ''; let threadChannelId = ''; let online = new Set(); let pendingFiles = []; let loadingThreads = false; let loadingMessages = false; let typingStopTimer = null; let lastTypingSent = 0; let typingUsers = new Map(); let sidebarMode = 'general'; let chatDock = 'global'; let bootRetryTimer = null; function cloud(){ return window.SunCloudV2 || null; } function client(){ return cloud()?.getClient?.() || null; } function session(){ return cloud()?.getSession?.() || null; } function workspace(){ return cloud()?.getWorkspace?.() || null; } function supportMode(){ return Boolean(cloud()?.isSupportMode?.()); } function available(){ return Boolean(client() && session()?.user && workspace()?.id && !supportMode()); } function me(){ return session()?.user?.id || ''; } function meName(){ const ws=workspace();return ws?.display_name || session()?.user?.email?.split('@')[0] || 'Сотрудник'; } async function rpc(name,args={}){ const c=client();if(!c)throw new Error('Supabase не подключён.');const r=await c.rpc(name,args);if(r.error)throw r.error;return r.data; } function fmtTime(v){ if(!v)return '';try{return new Intl.DateTimeFormat('ru-RU',{hour:'2-digit',minute:'2-digit'}).format(new Date(v))}catch(_){return ''} } function fmtDay(v){ if(!v)return '';try{return new Intl.DateTimeFormat('ru-RU',{day:'numeric',month:'long'}).format(new Date(v))}catch(_){return ''} } function sameDay(a,b){ try{const x=new Date(a),y=new Date(b);return x.getFullYear()===y.getFullYear()&&x.getMonth()===y.getMonth()&&x.getDate()===y.getDate()}catch(_){return false} } function bytes(n){ n=Number(n||0);if(n<1024)return `${n} Б`;if(n<1024*1024)return `${Math.round(n/1024)} КБ`;return `${(n/1024/1024).toFixed(1)} МБ`; } function safeName(name){ return String(name||'file').replace(/[\\/:*?"<>|\u0000-\u001f]+/g,'-').replace(/\s+/g,' ').trim().slice(0,120)||'file'; } function uid(){ try{return window.sunUUID?.() || crypto.randomUUID()}catch(_){return `${Date.now()}-${Math.random().toString(36).slice(2)}`} } function currentOrderId(){ try{return typeof draft!=='undefined'&&draft?.id?String(draft.id):''}catch(_){return ''} } function savedOrders(){ try{return Array.isArray(orders)?orders.slice():[]}catch(_){return []} } function installStyle(){ if($('sun-chat-style-v31'))return; $('sun-chat-style-v29')?.remove(); const s=document.createElement('style');s.id='sun-chat-style-v31';s.textContent=` #sunChatNavV29{position:relative}.sun-chat-nav-badge{display:none;position:absolute;right:5px;top:5px;min-width:18px;height:18px;border-radius:999px;padding:0 5px;background:#d83b35;color:#fff;font:800 10px/18px Arial;text-align:center;box-shadow:0 0 0 2px var(--sun-sidebar-bg,#32255d)}.sun-chat-nav-badge.on{display:block} #sun-chat-view{padding:16px;min-height:calc(100vh - 70px);background:#f3f4f7}.sun-chat-shell{max-width:1420px;margin:0 auto;height:calc(100vh - 102px);min-height:620px;background:#fff;border:1px solid #e0e4e9;border-radius:18px;overflow:hidden;display:grid;grid-template-columns:330px minmax(0,1fr);box-shadow:0 12px 40px rgba(30,40,60,.07)} .sun-chat-side{border-right:1px solid #e6e9ed;background:#fafbfc;display:flex;flex-direction:column;min-width:0}.sun-chat-side-head{padding:17px 17px 12px;border-bottom:1px solid #e8ebef}.sun-chat-side-head h1{font-size:22px;margin:0;color:#17384d}.sun-chat-side-head p{margin:5px 0 11px;color:#7a838d;font-size:12px}.sun-chat-section-tabs{display:grid;grid-template-columns:repeat(3,1fr);gap:5px}.sun-chat-section-tab{position:relative;border:1px solid #dfe4e8;background:#fff;color:#53616d;border-radius:10px;min-height:34px;padding:6px 5px;font-size:10.5px;font-weight:850;cursor:pointer}.sun-chat-section-tab.on{background:#17384d;color:#fff;border-color:#17384d}.sun-chat-section-badge{display:none;position:absolute;right:3px;top:2px;min-width:15px;height:15px;padding:0 4px;border-radius:999px;background:#d83b35;color:#fff;font:800 8px/15px Arial}.sun-chat-section-badge.on{display:block}.sun-chat-side-scroll{overflow:auto;padding:10px;flex:1}.sun-chat-group-title{display:flex;align-items:center;justify-content:space-between;padding:10px 8px 6px;color:#8a919a;font-size:10px;text-transform:uppercase;letter-spacing:.08em;font-weight:900}.sun-chat-list{display:grid;gap:3px}.sun-chat-thread{width:100%;border:0;background:transparent;border-radius:11px;padding:9px 10px;text-align:left;display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:9px;align-items:center;cursor:pointer;color:#223342}.sun-chat-thread:hover{background:#f0f3f5}.sun-chat-thread.on{background:#eaf1f4}.sun-chat-avatar{width:36px;height:36px;border-radius:12px;background:#e3eaee;display:grid;place-items:center;font-weight:900;color:#36566b;position:relative;flex:none}.sun-chat-avatar.company{background:#1e4057;color:#fff}.sun-chat-avatar.order{background:#f3ead3;color:#7b5d1f}.sun-chat-presence-dot{position:absolute;width:10px;height:10px;border-radius:50%;right:-2px;bottom:-2px;background:#aeb5bb;border:2px solid #fff}.sun-chat-presence-dot.on{background:#28a568}.sun-chat-thread-main{min-width:0}.sun-chat-thread-title{font-size:13px;font-weight:850;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sun-chat-thread-preview{font-size:10.5px;color:#838b94;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sun-chat-unread{min-width:20px;height:20px;padding:0 6px;border-radius:999px;background:#17384d;color:#fff;font:800 10px/20px Arial;text-align:center}.sun-chat-role{font-size:9px;color:#9299a1;margin-top:2px} .sun-chat-main{display:flex;flex-direction:column;min-width:0;min-height:0;background:#fff}.sun-chat-head{min-height:68px;border-bottom:1px solid #e7eaee;padding:10px 16px;display:flex;align-items:center;gap:12px}.sun-chat-head-back{border:0;background:#f0f2f4;border-radius:10px;padding:8px 10px;cursor:pointer;font-weight:800}.sun-chat-head-text{min-width:0;flex:1}.sun-chat-head-title{font-size:16px;font-weight:900;color:#213649;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sun-chat-head-sub{font-size:11px;color:#808891;margin-top:3px}.sun-chat-online-text{color:#22845a}.sun-chat-body{flex:1;min-height:0;overflow:auto;background:linear-gradient(#f8f9fb,#f5f7f9);padding:18px}.sun-chat-empty{height:100%;display:grid;place-items:center;text-align:center;color:#858d96;padding:30px}.sun-chat-empty b{display:block;color:#52616d;font-size:18px;margin-bottom:5px}.sun-chat-day{text-align:center;margin:10px 0 14px}.sun-chat-day span{display:inline-block;background:#e7ebee;color:#707a83;border-radius:999px;padding:4px 9px;font-size:10px}.sun-chat-msg{max-width:min(680px,82%);margin:6px 0;display:flex;gap:8px;align-items:flex-end}.sun-chat-msg.own{margin-left:auto;flex-direction:row-reverse}.sun-chat-bubble{border:1px solid #e1e5e9;background:#fff;border-radius:15px 15px 15px 4px;padding:9px 11px;box-shadow:0 3px 12px rgba(20,30,40,.035);min-width:100px}.sun-chat-msg.own .sun-chat-bubble{background:#e8f1f4;border-color:#d8e6eb;border-radius:15px 15px 4px 15px}.sun-chat-sender{font-size:10px;font-weight:850;color:#47667a;margin-bottom:4px}.sun-chat-text{font-size:13px;line-height:1.42;color:#253642;overflow-wrap:anywhere;white-space:pre-wrap}.sun-chat-meta{display:flex;gap:7px;justify-content:flex-end;align-items:center;margin-top:5px;font-size:9px;color:#8c949c}.sun-chat-read{font-weight:750;color:#718693}.sun-chat-files{display:grid;gap:6px;margin-top:7px}.sun-chat-file{border:1px solid #dfe4e8;border-radius:10px;background:rgba(255,255,255,.7);overflow:hidden;display:block;color:#2d536a;text-decoration:none;max-width:360px}.sun-chat-file-img{width:100%;max-height:260px;display:block;object-fit:cover;background:#eef1f3}.sun-chat-file-line{display:flex;align-items:center;gap:8px;padding:8px 9px}.sun-chat-file-icon{font-size:20px}.sun-chat-file-name{font-size:11px;font-weight:750;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sun-chat-file-size{font-size:9px;color:#8a929a;margin-top:2px} .sun-chat-typing{height:22px;padding:3px 16px;color:#71808a;font-size:10px;background:#f8f9fb}.sun-chat-composer{border-top:1px solid #e4e8eb;padding:10px 12px;background:#fff}.sun-chat-pending{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 8px}.sun-chat-pending:empty{display:none}.sun-chat-pending-chip{display:flex;align-items:center;gap:6px;background:#eef2f4;border-radius:9px;padding:5px 7px;max-width:260px}.sun-chat-pending-chip span{font-size:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sun-chat-pending-chip button{border:0;background:transparent;cursor:pointer;font-size:15px}.sun-chat-compose-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:8px;align-items:end}.sun-chat-attach,.sun-chat-send{border:0;border-radius:11px;height:40px;cursor:pointer;font-weight:850}.sun-chat-attach{width:42px;background:#eef2f4;color:#476170;font-size:20px}.sun-chat-send{padding:0 17px;background:#17384d;color:#fff}.sun-chat-send:disabled{opacity:.55;cursor:default}.sun-chat-input{width:100%;min-height:40px;max-height:130px;resize:none;border:1px solid #d7dde1;border-radius:12px;padding:10px 12px;line-height:1.35;outline:none}.sun-chat-input:focus{border-color:#7896a9;box-shadow:0 0 0 3px rgba(70,110,135,.08)} .sun-chat-order-tab{position:relative}.sun-chat-order-tab .sun-chat-mini-badge{position:absolute;top:-2px;right:-3px;background:#d83b35;color:#fff;border-radius:999px;min-width:16px;height:16px;padding:0 4px;font:800 9px/16px Arial}.sun-order-chat-panel{display:none;min-height:570px;height:min(68vh,760px);border:1px solid #e1e5e9;border-radius:14px;overflow:hidden;margin-top:10px;background:#fff}.sun-order-chat-panel.on{display:block}.sun-order-chat-panel .sun-chat-main{height:100%;min-height:0}.sun-chat-offline-note{padding:14px;border-radius:12px;background:#fff6e2;color:#85631c;margin:18px} @media(max-width:850px){#sun-chat-view{padding:0}.sun-chat-shell{height:calc(100vh - 94px);min-height:0;border-radius:0;border-left:0;border-right:0;grid-template-columns:1fr}.sun-chat-side{display:flex}.sun-chat-main{display:none}.sun-chat-shell.thread-open .sun-chat-side{display:none}.sun-chat-shell.thread-open .sun-chat-main{display:flex}.sun-chat-msg{max-width:92%}.sun-chat-body{padding:12px}.sun-chat-section-tab{font-size:10px}.sun-order-chat-panel{height:62vh;min-height:460px}.sun-order-chat-panel .sun-chat-main{display:flex!important}.sun-order-chat-panel .sun-chat-head{min-height:58px}} `;document.head.appendChild(s); } function ensureView(){ installStyle(); let v=$('sun-chat-view'); if(!v){ v=document.createElement('section');v.id='sun-chat-view';v.className='view';v.innerHTML=`
    Выберите чатОбщий чат компании, сотрудника или обсуждение заказа.
    `; const firstModal=document.querySelector('body > .modal');if(firstModal)firstModal.before(v);else document.body.appendChild(v); $('sunChatAttachV29').onclick=()=>$('sunChatFilesV29').click(); $('sunChatFilesV29').onchange=e=>addPendingFiles(e.target.files); $('sunChatSendV29').onclick=sendMessage; $('sunChatInputV29').addEventListener('keydown',e=>{if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage();}}); $('sunChatInputV29').addEventListener('input',()=>{autoGrowInput();sendTyping(true);}); qa('[data-chat-section]',v).forEach(b=>b.addEventListener('click',()=>switchSidebarMode(b.dataset.chatSection))); } return v; } function ensureNav(){ const nav=document.querySelector('header nav');if(!nav)return null; let b=$('sunChatNavV29'); if(!available()){b?.remove();return null;} if(!b){ b=document.createElement('button');b.id='sunChatNavV29';b.type='button';b.dataset.navLabel='Чат';b.className='nav-chat';b.innerHTML=`Чат `; b.addEventListener('click',()=>openMain({mode:'general'})); } if(typeof window.sunRegisterNavButton==='function'){ window.sunRegisterNavButton({button:b,group:'management',beforeLabel:'Настройки',navLabel:'Чат',className:'nav-chat'}); }else{ const group=nav.querySelector('.sun-nav-management')||nav; if(b.parentElement!==group)group.appendChild(b); b.classList.add('sun-nav-button','nav-chat'); } return b; } function setNavBadge(n){ const b=$('sunChatNavBadgeV29');if(!b)return;n=Number(n||0);b.textContent=n>99?'99+':String(n);b.classList.toggle('on',n>0); } function setSectionBadge(mode,n){const b=document.querySelector(`[data-chat-section-badge="${mode}"]`);if(!b)return;n=Number(n||0);b.textContent=n>99?'99+':String(n);b.classList.toggle('on',n>0);} function setActiveNav(){qa('header nav button').forEach(x=>x.classList.remove('on'));$('sunChatNavV29')?.classList.add('on');qa('.view').forEach(x=>x.classList.remove('on'));ensureView().classList.add('on');} function threadIcon(t){if(t.kind==='company')return ['КО','company'];if(t.kind==='order')return ['№','order'];return [String(t.title||'?').trim().slice(0,1).toUpperCase(),''];} function threadById(id){return threads.find(t=>String(t.thread_id)===String(id))||null;} function directByUser(id){return threads.find(t=>t.kind==='direct'&&String(t.other_user_id)===String(id))||null;} function orderThreadByOrder(id){return threads.find(t=>t.kind==='order'&&String(t.order_id)===String(id))||null;} function memberById(id){return members.find(m=>String(m.user_id)===String(id))||null;} function switchSidebarMode(mode){ sidebarMode=['general','direct','orders'].includes(mode)?mode:'general'; qa('[data-chat-section]').forEach(b=>b.classList.toggle('on',b.dataset.chatSection===sidebarMode)); renderSidebar(); if(sidebarMode==='general'){ const t=threads.find(x=>x.kind==='company'); if(t&&(!activeThread||activeThread.kind!=='company'))openThread(t); }else if(activeThread&&((sidebarMode==='direct'&&activeThread.kind!=='direct')||(sidebarMode==='orders'&&activeThread.kind!=='order'))){ activeThread=null;messages=[];unsubscribeThread();$('sunChatShellV29')?.classList.remove('thread-open');$('sunChatComposerV29').hidden=true;renderHead();renderMessages(); } } function renderSidebar(){ const root=$('sunChatSidebarV29');if(!root)return; $('sunChatCompanyNameV29').textContent=workspace()?.name||'Компания'; qa('[data-chat-section]').forEach(b=>b.classList.toggle('on',b.dataset.chatSection===sidebarMode)); const general=threads.find(t=>t.kind==='company'); const others=members.filter(m=>String(m.user_id)!==String(me())); const localOrders=savedOrders().sort((a,b)=>Number(b?.id||0)-Number(a?.id||0)); const row=t=>{const [letter,cls]=threadIcon(t);const isOn=activeThread&&String(activeThread.thread_id)===String(t.thread_id);return ``}; const memberRow=m=>{const t=directByUser(m.user_id);if(t)return row(t);const isOnline=online.has(String(m.user_id));return ``}; const orderRow=o=>{const t=orderThreadByOrder(o.id);if(t)return row({...t,title:`№${o.id}${o.event?` · ${o.event}`:''}`});return ``}; if(sidebarMode==='general')root.innerHTML=`
    Общий чат компании
    ${general?row(general):'
    Загружаю общий чат…
    '}
    `; if(sidebarMode==='direct')root.innerHTML=`
    Сотрудники${others.length}
    ${others.length?others.map(memberRow).join(''):'
    Добавьте сотрудников — здесь появятся личные чаты.
    '}
    `; if(sidebarMode==='orders')root.innerHTML=`
    Чаты заказов${localOrders.length}
    ${localOrders.length?localOrders.map(orderRow).join(''):'
    Сохранённых заказов пока нет.
    '}
    `; qa('[data-chat-thread]',root).forEach(b=>b.onclick=()=>openThread(threadById(b.dataset.chatThread))); qa('[data-chat-user]',root).forEach(b=>b.onclick=()=>openDirect(b.dataset.chatUser)); qa('[data-chat-order]',root).forEach(b=>b.onclick=()=>openOrderGlobal(b.dataset.chatOrder)); updateUnreadBadges(); } function updateUnreadBadges(){ const general=threads.filter(t=>t.kind==='company').reduce((n,t)=>n+Number(t.unread_count||0),0); const direct=threads.filter(t=>t.kind==='direct').reduce((n,t)=>n+Number(t.unread_count||0),0); const order=threads.filter(t=>t.kind==='order').reduce((n,t)=>n+Number(t.unread_count||0),0); setSectionBadge('general',general);setSectionBadge('direct',direct);setSectionBadge('orders',order);setNavBadge(general+direct+order);updateOrderChatBadge(); } function activeSubtitle(t){ if(!t)return ''; if(t.kind==='direct'){const m=memberById(t.other_user_id);return online.has(String(t.other_user_id))?'онлайн':esc(ROLE_LABELS[m?.role]||'сотрудник');} if(t.kind==='company'){const count=members.length,on=members.filter(m=>online.has(String(m.user_id))).length;return `${count} сотрудников · ${on} онлайн`;} return 'Обсуждение заказа'; } function renderHead(){ const h=$('sunChatHeadV29');if(!h)return; if(!activeThread){h.innerHTML='';return;} const mobileBack=chatDock==='global'?``:''; const orderBack=chatDock==='order'?``:''; h.innerHTML=`${orderBack||mobileBack}
    ${esc(activeThread.title||'Чат')}
    ${activeSubtitle(activeThread)}
    `; h.querySelector('[data-chat-mobile-back]')?.addEventListener('click',()=>{activeThread=null;messages=[];unsubscribeThread();$('sunChatShellV29')?.classList.remove('thread-open');renderSidebar();renderHead();renderMessages();$('sunChatComposerV29').hidden=true;}); h.querySelector('[data-chat-order-back]')?.addEventListener('click',()=>$('orderTab')?.click()); } function renderMessages(){ const root=$('sunChatBodyV29');if(!root)return; if(!activeThread){root.innerHTML='
    Выберите чатОбщий чат компании, сотрудника или обсуждение заказа.
    ';return;} if(loadingMessages){root.innerHTML='
    Загружаю сообщения…
    ';return;} if(!messages.length){root.innerHTML='
    Пока нет сообщенийНапишите первое сообщение.
    ';return;} let prev=null,html=''; for(const m of messages){ if(!prev||!sameDay(prev,m.created_at))html+=`
    ${esc(fmtDay(m.created_at))}
    `; prev=m.created_at;const own=String(m.sender_user_id)===String(me());const atts=Array.isArray(m.attachments)?m.attachments:[]; const files=atts.length?``:''; const read=own?(Number(m.read_by_count||0)>0?(activeThread.kind==='direct'?'Прочитано':`Прочитали: ${Number(m.read_by_count)}`):'Доставлено'):''; html+=`
    ${!own&&activeThread.kind!=='direct'?`
    ${esc(m.sender_name||m.sender_email||'Сотрудник')}
    `:''}${m.body?`
    ${esc(m.body)}
    `:''}${files}
    ${esc(fmtTime(m.created_at))}${read?`${esc(read)}`:''}
    `; } root.innerHTML=html;hydrateAttachments();requestAnimationFrame(()=>{root.scrollTop=root.scrollHeight}); } async function hydrateAttachments(){ const c=client();if(!c)return; const links=qa('[data-chat-attachment]',$('sunChatBodyV29')); for(const a of links){const path=a.dataset.chatAttachment;if(!path)continue;try{const r=await c.storage.from('sun-chat').createSignedUrl(path,3600);if(r.error)throw r.error;const url=r.data?.signedUrl;if(!url)continue;a.href=url;const type=a.dataset.chatType||'';if(type.startsWith('image/')){const p=a.querySelector('.sun-chat-file-preview');if(p)p.innerHTML=`Вложение`;}}catch(e){a.onclick=ev=>{ev.preventDefault();toast('Не удалось открыть вложение.','error')}}} } function renderTyping(){const root=$('sunChatTypingV29');if(!root)return;const names=[...typingUsers.values()].filter(x=>x&&x.user_id!==me()&&Date.now()-x.at<3500).map(x=>x.name||'Сотрудник');root.textContent=names.length?`${names.slice(0,2).join(', ')} ${names.length>1?'печатают':'печатает'}…`:'';} function renderPending(){const root=$('sunChatPendingV29');if(!root)return;root.innerHTML=pendingFiles.map((f,i)=>`
    ${esc(f.name)} · ${esc(bytes(f.size))}
    `).join('');qa('[data-remove-file]',root).forEach(b=>b.onclick=()=>{pendingFiles.splice(Number(b.dataset.removeFile),1);renderPending()});} function autoGrowInput(){const x=$('sunChatInputV29');if(!x)return;x.style.height='auto';x.style.height=Math.min(130,x.scrollHeight)+'px';} async function loadThreads({quiet=false}={}){ if(!available()||loadingThreads)return; loadingThreads=true; try{ const ws=workspace();await rpc('sun_chat_get_company_thread_v29',{p_workspace:ws.id}); const [t,m]=await Promise.all([rpc('sun_chat_list_threads_v29',{p_workspace:ws.id}),rpc('sun_chat_list_members_v29',{p_workspace:ws.id})]); threads=Array.isArray(t)?t:[];members=Array.isArray(m)?m:[]; if(activeThread){const fresh=threadById(activeThread.thread_id);if(fresh)activeThread={...activeThread,...fresh};} renderSidebar();renderHead();updateUnreadBadges(); }catch(e){if(!quiet)toast(e.message||String(e),'error',6500)}finally{loadingThreads=false;} } async function loadMessages({mark=true,quiet=false}={}){ if(!activeThread||!available()||loadingMessages)return; loadingMessages=true;renderMessages(); try{ const data=await rpc('sun_chat_list_messages_v29',{p_thread:activeThread.thread_id,p_limit:120,p_before:null});messages=Array.isArray(data)?data:[]; if(mark){const t=threadById(activeThread.thread_id);if(Number(t?.unread_count||0)>0){await rpc('sun_chat_mark_read_v29',{p_thread:activeThread.thread_id});await loadThreads({quiet:true});}} }catch(e){if(!quiet)toast(e.message||String(e),'error',6500)}finally{loadingMessages=false;renderMessages();} } async function openThread(t){ if(!t)return;activeThread=t;messages=[];pendingFiles=[];$('sunChatShellV29')?.classList.add('thread-open');$('sunChatComposerV29').hidden=false;$('sunChatInputV29').value='';renderPending();renderSidebar();renderHead();renderMessages();await subscribeThread(t.thread_id);await loadMessages({mark:true});setTimeout(()=>$('sunChatInputV29')?.focus(),80); } async function openDirect(userId){ if(!available())return;try{sidebarMode='direct';const id=await rpc('sun_chat_get_direct_thread_v29',{p_workspace:workspace().id,p_other_user:userId});await loadThreads({quiet:true});const t=threadById(id)||{thread_id:id,kind:'direct',other_user_id:userId,title:memberById(userId)?.display_name||'Сотрудник',unread_count:0};await openThread(t);}catch(e){toast(e.message||String(e),'error',6500)} } async function getOrderThread(orderId){ const id=await rpc('sun_chat_get_order_thread_v29',{p_workspace:workspace().id,p_order_id:String(orderId)});await loadThreads({quiet:true});return threadById(id)||{thread_id:id,kind:'order',order_id:String(orderId),title:`Заказ №${orderId}`,unread_count:0}; } async function openOrderGlobal(orderId){ if(!available())return toast('Войдите в Caterium, чтобы открыть обсуждение заказа.','warn');if(!orderId)return toast('Сначала сохраните заказ.','warn'); try{dockMainGlobal();setActiveNav();sidebarMode='orders';await ensureWorkspaceChannel();const t=await getOrderThread(orderId);renderSidebar();await openThread(t);}catch(e){toast(e.message||String(e),'error',6500)} } function ensureOrderChatPanel(){ const sub=document.querySelector('#new .subnav');if(!sub)return null; let p=$('sunOrderChatPanelV31'); if(!p){p=document.createElement('div');p.id='sunOrderChatPanelV31';p.className='sun-order-chat-panel';sub.after(p);} return p; } function dockMainGlobal(){ const main=$('sunChatMainV29'),shell=$('sunChatShellV29');if(main&&shell&&main.parentElement!==shell)shell.appendChild(main);chatDock='global'; } function dockMainOrder(){ const main=$('sunChatMainV29'),panel=ensureOrderChatPanel();if(main&&panel&&main.parentElement!==panel)panel.appendChild(main);chatDock='order'; } function setOrderChatMode(on){ const sub=document.querySelector('#new .subnav'),card=sub?.closest('.card'),panel=ensureOrderChatPanel(),chatTab=$('sunOrderChatTabV31');if(!card||!panel)return; const money=card.querySelector(':scope > .money-form'),summary=card.querySelector(':scope > .order-summary'),actions=card.querySelector(':scope > .actions'); if(on){ $('orderForm')?.style.setProperty('display','none');$('details')?.style.setProperty('display','none'); if(money)money.style.display='none';if(summary)summary.style.display='none';if(actions)actions.style.display='none'; panel.classList.add('on');panel.hidden=false;$('orderTab')?.classList.remove('on');$('detailTab')?.classList.remove('on');chatTab?.classList.add('on');dockMainOrder(); }else{ panel.classList.remove('on');panel.hidden=true;if(money)money.style.display='';if(summary)summary.style.display='';if(actions)actions.style.display='';chatTab?.classList.remove('on');dockMainGlobal(); } } async function openOrderInline(orderId){ if(!available())return toast('Войдите в Caterium, чтобы открыть обсуждение заказа.','warn');if(!orderId)return toast('Сначала сохраните заказ — после этого появится чат.','warn'); try{ensureView();ensureOrderDiscussionTab();setOrderChatMode(true);await ensureWorkspaceChannel();sidebarMode='orders';const t=await getOrderThread(orderId);await openThread(t);}catch(e){setOrderChatMode(false);toast(e.message||String(e),'error',6500)} } async function openMain({threadId=null,mode='general'}={}){ if(!available())return toast('Чат доступен после входа в рабочую компанию.','warn');ensureView();dockMainGlobal();ensureNav();setActiveNav();sidebarMode=['general','direct','orders'].includes(mode)?mode:'general';await ensureWorkspaceChannel();await loadThreads();let t=threadId?threadById(threadId):null;if(!t&&sidebarMode==='general')t=threads.find(x=>x.kind==='company')||null;if(t)await openThread(t);else{activeThread=null;messages=[];unsubscribeThread();$('sunChatShellV29')?.classList.remove('thread-open');$('sunChatComposerV29').hidden=true;renderSidebar();renderHead();renderMessages();} } async function addPendingFiles(fileList){ const files=[...(fileList||[])];$('sunChatFilesV29').value=''; for(const f of files){if(pendingFiles.length>=5){toast('Можно отправить не более 5 файлов за раз.','warn');break}if(f.size>15*1024*1024){toast(`Файл «${f.name}» больше 15 МБ.`,'warn');continue}pendingFiles.push(f)}renderPending(); } async function uploadPending(){ const c=client(),ws=workspace();if(!c||!ws||!activeThread)return []; const result=[]; for(const f of pendingFiles){const path=`${ws.id}/${activeThread.thread_id}/${uid()}-${safeName(f.name)}`;const up=await c.storage.from('sun-chat').upload(path,f,{contentType:f.type||'application/octet-stream',upsert:false});if(up.error)throw up.error;result.push({path,name:f.name,type:f.type||'application/octet-stream',size:f.size});} return result; } async function sendMessage(){ if(!activeThread||!available())return;const input=$('sunChatInputV29'),btn=$('sunChatSendV29');const text=String(input?.value||'').trim();if(!text&&!pendingFiles.length)return; btn.disabled=true;btn.textContent='…'; try{const attachments=await uploadPending();await rpc('sun_chat_send_message_v29',{p_thread:activeThread.thread_id,p_body:text,p_attachments:attachments});input.value='';input.style.height='auto';pendingFiles=[];renderPending();sendTyping(false);await Promise.all([loadThreads({quiet:true}),loadMessages({mark:false,quiet:true})]);} catch(e){toast(e.message||String(e),'error',7000)}finally{btn.disabled=false;btn.textContent='Отправить';input?.focus();} } async function ensureWorkspaceChannel(){ if(!available())return unsubscribeWorkspace();const c=client(),ws=workspace(),ss=session();if(!c||!ws||!ss)return; if(workspaceChannel&&workspaceChannelId===ws.id)return; unsubscribeWorkspace();workspaceChannelId=ws.id; try{if(c.realtime?.setAuth)await c.realtime.setAuth(ss.access_token);}catch(_){} const ch=c.channel(`sun-chat-workspace:${ws.id}`,{config:{private:true,presence:{key:me()},broadcast:{ack:true}}});workspaceChannel=ch; ch.on('broadcast',{event:'chat_changed'},async()=>{await loadThreads({quiet:true});if(activeThread){const fresh=threadById(activeThread.thread_id);if(fresh&&Number(fresh.unread_count||0)>0)await loadMessages({mark:true,quiet:true});else renderMessages();}}) .on('presence',{event:'sync'},()=>{online=new Set(Object.keys(ch.presenceState()||{}));renderSidebar();renderHead();}) .on('presence',{event:'join'},()=>{online=new Set(Object.keys(ch.presenceState()||{}));renderSidebar();renderHead();}) .on('presence',{event:'leave'},()=>{online=new Set(Object.keys(ch.presenceState()||{}));renderSidebar();renderHead();}) .subscribe(async(status)=>{if(status==='SUBSCRIBED'){try{await ch.track({user_id:me(),name:meName(),at:new Date().toISOString()})}catch(_){}await loadThreads({quiet:true});}}); } function unsubscribeWorkspace(){if(workspaceChannel){try{client()?.removeChannel?.(workspaceChannel)}catch(_){}workspaceChannel=null;}workspaceChannelId='';online=new Set();unsubscribeThread();} async function subscribeThread(id){ if(!available()||!id)return;const c=client(),ss=session();if(threadChannel&&threadChannelId===id)return;unsubscribeThread();threadChannelId=id; try{if(c.realtime?.setAuth)await c.realtime.setAuth(ss.access_token);}catch(_){} const ch=c.channel(`sun-chat-thread:${id}`,{config:{private:true,broadcast:{ack:false,self:false}}});threadChannel=ch; ch.on('broadcast',{event:'message'},()=>loadMessages({mark:true,quiet:true})) .on('broadcast',{event:'read'},()=>loadMessages({mark:false,quiet:true})) .on('broadcast',{event:'typing'},payload=>{const p=payload?.payload||{};if(!p.user_id||String(p.user_id)===String(me()))return;if(p.typing)typingUsers.set(String(p.user_id),{user_id:p.user_id,name:p.name||'Сотрудник',at:Date.now()});else typingUsers.delete(String(p.user_id));renderTyping();setTimeout(()=>renderTyping(),3600)}) .subscribe(); } function unsubscribeThread(){if(threadChannel){try{client()?.removeChannel?.(threadChannel)}catch(_){}threadChannel=null;}threadChannelId='';typingUsers.clear();renderTyping();} async function sendTyping(flag){ if(!threadChannel||!activeThread)return;const now=Date.now();if(flag&&now-lastTypingSent<700){clearTimeout(typingStopTimer);typingStopTimer=setTimeout(()=>sendTyping(false),1800);return}lastTypingSent=now; try{await threadChannel.send({type:'broadcast',event:'typing',payload:{user_id:me(),name:meName(),typing:Boolean(flag)}})}catch(_){} clearTimeout(typingStopTimer);if(flag)typingStopTimer=setTimeout(()=>sendTyping(false),1800); } function updateOrderChatBadge(){ const b=$('sunOrderChatTabV31');if(!b)return;const id=currentOrderId(),t=id?orderThreadByOrder(id):null,n=Number(t?.unread_count||0);let badge=b.querySelector('.sun-chat-mini-badge');if(n>0){if(!badge){badge=document.createElement('span');badge.className='sun-chat-mini-badge';b.appendChild(badge);}badge.textContent=n>99?'99+':String(n);}else badge?.remove(); } function ensureOrderDiscussionTab(){ const sub=document.querySelector('#new .subnav');if(!sub)return; ensureOrderChatPanel(); let b=$('sunOrderChatTabV31'); $('sunOrderChatTabV29')?.remove(); if(!b){ b=document.createElement('button');b.id='sunOrderChatTabV31';b.type='button';b.className='sun-chat-order-tab';b.textContent='Чат';sub.appendChild(b); b.addEventListener('click',e=>{e.preventDefault();const id=currentOrderId();if(!id)return toast('Сначала сохраните заказ — после этого появится чат.','warn');openOrderInline(id);}); } b.title=currentOrderId()?'Чат этого заказа':'Сначала сохраните заказ';b.style.opacity=currentOrderId()?'1':'.55'; ['orderTab','detailTab'].forEach(id=>{const x=$(id);if(x&&!x.dataset.sunChatCloseBound){x.dataset.sunChatCloseBound='1';x.addEventListener('click',()=>setOrderChatMode(false));}}); updateOrderChatBadge(); } function openOrderFromCard(id){ if(!id)return; try{if(typeof window.openOrder==='function')window.openOrder(Number(id));}catch(e){return toast(e.message||String(e),'error')} setTimeout(()=>openOrderInline(String(id)),60); } function decorateOrderCards(){ qa('#sunOrderCards .sun-order-card').forEach(card=>{const actions=card.querySelector('.sun-order-card-actions');if(!actions||actions.querySelector('[data-card-chat]'))return;const b=document.createElement('button');b.className='mini';b.type='button';b.dataset.cardChat=card.dataset.orderId;b.textContent='Чат';b.onclick=e=>{e.stopPropagation();openOrderFromCard(b.dataset.cardChat)};actions.prepend(b);}); } function safeStateChanged(){ try{ installStyle();ensureView();ensureOrderDiscussionTab();decorateOrderCards(); if(available()){ensureNav();ensureWorkspaceChannel();loadThreads({quiet:true});} else{setNavBadge(0);$('sunChatNavV29')?.remove();unsubscribeWorkspace();activeThread=null;threads=[];members=[];messages=[];setOrderChatMode(false);} }catch(e){console.error('[Caterium Chat] state refresh failed',e);} } function boot(){ installStyle();ensureView();ensureOrderDiscussionTab(); const priorOpen=window.openOrder; if(typeof priorOpen==='function'&&!priorOpen.__sunChatV31){const wrapped=function(...args){setOrderChatMode(false);const r=priorOpen.apply(this,args);setTimeout(()=>{ensureOrderDiscussionTab();decorateOrderCards();},0);return r};wrapped.__sunChatV31=true;window.openOrder=wrapped;} const priorRenderOrders=window.renderOrders; if(typeof priorRenderOrders==='function'&&!priorRenderOrders.__sunChatV31){const wrapped=function(...args){const r=priorRenderOrders.apply(this,args);setTimeout(decorateOrderCards,0);return r};wrapped.__sunChatV31=true;window.renderOrders=wrapped;} document.addEventListener('click',e=>{const nav=e.target.closest('header nav button');if(!nav)return;if(nav.id!=='sunChatNavV29')setOrderChatMode(false);setTimeout(()=>{ensureOrderDiscussionTab();decorateOrderCards();},20);},true); window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(safeStateChanged,60)); window.addEventListener('sun:cloud-state-applied',()=>setTimeout(safeStateChanged,60)); window.addEventListener('online',()=>{if(available())ensureWorkspaceChannel()}); window.addEventListener('beforeunload',()=>{try{workspaceChannel?.untrack?.()}catch(_){}}); let tries=0;bootRetryTimer=setInterval(()=>{tries++;safeStateChanged();if(available()||tries>=24){clearInterval(bootRetryTimer);bootRetryTimer=null;}},750);setTimeout(safeStateChanged,250); } window.SunChatV29={VERSION,open:openMain,openOrder:openOrderInline,openDirect,refresh:()=>loadThreads(),getThreads:()=>threads.slice(),getMembers:()=>members.slice()}; window.SunChatV31=window.SunChatV29; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot(); })();