From 47d6b0cdb1f7c1b212bff189965ae3e54a5f7cf9 Mon Sep 17 00:00:00 2001 From: Dollerino Date: Tue, 24 Jun 2025 13:55:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-968=20-=20=D0=94=D0=BE?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BB=D0=B8=20"=D0=9F=D1=80=D0=BE=D0=B8=D0=B7=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mech_rec_cost_prod_plans.js | 334 +++++++++++++----- db/PKG_P8PANELS_MECHREC.pck | 139 +++++++- 2 files changed, 367 insertions(+), 106 deletions(-) diff --git a/app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js b/app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js index 13c6940..c65679a 100644 --- a/app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js +++ b/app/panels/mech_rec_cost_prod_plans/mech_rec_cost_prod_plans.js @@ -36,7 +36,8 @@ import { Card, CardHeader, CardContent, - CardActions + CardActions, + Tooltip } from "@mui/material"; //Интерфейсные элементы import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений @@ -55,19 +56,34 @@ import { IncomFromDepsDataGrid } from "./datagrids/incomefromdeps"; //Табли //--------- //Склонения для документов -const DECLINATIONS = ["план", "плана", "планов"]; +const PLANS_DECLINATIONS = ["план", "плана", "планов"]; +const SPEC_DECLINATIONS = ["элемент", "элемента", "элементов"]; //Поля сортировки const SORT_REP_DATE = "DREP_DATE"; const SORT_REP_DATE_TO = "DREP_DATE_TO"; +//Максимальное количество элементов +const MAX_TASKS = 10000; + //Стили const STYLES = { PLANS_FINDER: { marginTop: "10px", marginLeft: "10px", width: "93%" }, PLANS_CHECKBOX_HAVEDOCS: { alignContent: "space-around" }, + PLANS_LIST_CONTAINER: { height: "100%", display: "flex", flexDirection: "column", justifyContent: "space-between" }, PLANS_LIST_ITEM_ZERODOCS: { backgroundColor: "#ebecec" }, PLANS_LIST_ITEM_PRIMARY: { wordWrap: "break-word" }, PLANS_LIST_ITEM_SECONDARY: { wordWrap: "break-word", fontSize: "0.6rem", textTransform: "uppercase" }, + PLANS_LIST_ITEM_PLAN: { + backgroundColor: "#c7e7f1", + "&:hover": { backgroundColor: `#c7e7f1`, filter: "brightness(0.92) !important" } + }, + PLANS_LIST_ITEM_PLAN_FIELD: { + marginLeft: "15px" + }, + PLANS_LIST_FILTER_CONTAINER: { height: "calc(100% - 55px)", overflowY: "auto" }, + PLANS_LIST_BUTTONS_CONTAINER: { display: "flex", justifyContent: "space-around", paddingBottom: "10px", height: "45px" }, + PLANS_LIST_BUTTON: { minWidth: "125px", height: "35px" }, PLANS_BUTTON: { position: "absolute", top: `calc(${APP_BAR_HEIGHT} + 16px)`, left: "16px" }, PLANS_DRAWER: { width: "350px", @@ -121,7 +137,9 @@ const parseProdPlanSpXML = async xmlDoc => { }; //Форматирование для отображения количества документов -const formatCountDocs = nCountDocs => { +const formatCountDocs = (nCountDocs, nType = 0) => { + //Склонение документов + let DECLINATIONS = nType === 0 ? PLANS_DECLINATIONS : SPEC_DECLINATIONS; //Получаем последнюю цифру в значении let num = (nCountDocs % 100) % 10; //Документов @@ -134,55 +152,146 @@ const formatCountDocs = nCountDocs => { return `${nCountDocs} ${DECLINATIONS[2]}`; }; +//Изменение информации об отмеченных планах +const updateCtlgPlanInfo = (selectedPlans, plan) => { + //Результат изменений + let res = { selectedPlans: [...selectedPlans] || [], selectedPlansElements: plan.NCOUNT_DOCS }; + //Определяем наличие в отмеченных планах + let selectedIndex = res.selectedPlans.indexOf(plan.NRN); + //Если уже есть в отмеченных - удаляем, нет - добавляем + if (selectedIndex > -1) { + //Удаляем план из выбранных + res.selectedPlans.splice(selectedIndex, 1); + //Переворачиваем сумму документов + res.selectedPlansElements = res.selectedPlansElements * -1; + } else { + //Добавляем план в выбранные + res.selectedPlans.push(plan.NRN); + } + //Возвращаем результат + return res; +}; + //Список каталогов планов -const PlanCtlgsList = ({ planCtlgs = [], selectedPlanCtlg, filter, setFilter, onClick } = {}) => { +const PlanCtlgsList = ({ + planCtlgs = [], + selectedPlans = [], + selectedPlanCtlg, + selectedPlansElements, + filter, + setFilter, + onCtlgClick, + onCtlgPlanClick, + onCtlgPlansOk, + onCtlgPlansCancel +} = {}) => { //Генерация содержимого return ( -
- { - setFilter(pv => ({ ...pv, ctlgName: event.target.value })); - }} - > - - setFilter(pv => ({ ...pv, haveDocs: event.target.checked }))} />} - label="Только с планами" - labelPlacement="end" - /> - - - {planCtlgs.map(p => ( - (onClick ? onClick(p) : null)} - > - {p.SNAME}} - secondary={{formatCountDocs(p.NCOUNT_DOCS)}} - /> - - ))} - -
+ + + { + setFilter(pv => ({ ...pv, ctlgName: event.target.value })); + }} + > + + setFilter(pv => ({ ...pv, haveDocs: event.target.checked }))} /> + } + label="Только с планами" + labelPlacement="end" + /> + + + {planCtlgs.map(ctlg => ( + + (onCtlgClick ? onCtlgClick(ctlg) : null)} + disabled={ctlg.NCOUNT_DOCS == 0} + > + {ctlg.SNAME}} + secondary={{formatCountDocs(ctlg.NCOUNT_DOCS, 0)}} + /> + + {ctlg.NRN === selectedPlanCtlg && ctlg.XCRN_PLANS.length > 1 + ? ctlg.XCRN_PLANS.map(plan => ( + (onCtlgPlanClick ? onCtlgPlanClick(plan) : null)} + > + {plan.SNAME}} + secondary={ + + {formatCountDocs(plan.NCOUNT_DOCS, 1)} + + } + /> + {plan.NCOUNT_DOCS !== 0 ? : null} + + )) + : null} + + ))} + + + + MAX_TASKS + ? `Выбранные планы превышают максимум элементов (выбрано: ${selectedPlansElements}, максимум: ${MAX_TASKS})` + : null + } + > + + + + + + + ); }; //Контроль свойств - Список каталогов планов PlanCtlgsList.propTypes = { planCtlgs: PropTypes.array, + selectedPlans: PropTypes.array, selectedPlanCtlg: PropTypes.number, - onClick: PropTypes.func, + selectedPlansElements: PropTypes.number, + onCtlgClick: PropTypes.func, + onCtlgPlanClick: PropTypes.func, filter: PropTypes.object, - setFilter: PropTypes.func + setFilter: PropTypes.func, + onCtlgPlansOk: PropTypes.func, + onCtlgPlansCancel: PropTypes.func }; //Генерация диалога задачи @@ -251,6 +360,8 @@ const MechRecCostProdPlans = () => { showPlanList: false, planCtlgs: [], planCtlgsLoaded: false, + selectedPlans: [], + selectedPlansElements: 0, selectedPlanCtlgSpecsLoaded: false, selectedPlanCtlg: null, selectedPlanCtlgMaxLevel: null, @@ -258,6 +369,9 @@ const MechRecCostProdPlans = () => { selectedPlanCtlgOutOfLimit: 0, selectedPlanCtlgSort: null, selectedPlanCtlgMenuItems: null, + loadedCtlg: null, + loadedPlans: [], + loadedElements: 0, gantt: {}, selectedTaskDetail: null, selectedTaskDetailType: null, @@ -273,7 +387,7 @@ const MechRecCostProdPlans = () => { const { InlineMsgInfo } = useContext(MessagingСtx); //Подключение к контексту взаимодействия с сервером - const { executeStored } = useContext(BackEndСtx); + const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx); //Подключение к контексту навигации const { getNavigationSearch } = useContext(NavigationCtx); @@ -288,54 +402,28 @@ const MechRecCostProdPlans = () => { stored: "PKG_P8PANELS_MECHREC.FCPRODPLAN_PP_CTLG_INIT", args: {}, respArg: "COUT", - isArray: name => name === "XFCPRODPLAN_CRNS" + isArray: name => ["XFCPRODPLAN_CRNS", "XCRN_PLANS"].includes(name) }); setState(pv => ({ ...pv, init: true, planCtlgs: [...(data?.XFCPRODPLAN_CRNS || [])], planCtlgsLoaded: true })); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [state.init, executeStored]); - //Выбор каталога планов - const selectPlan = project => { - setState(pv => ({ - ...pv, - selectedPlanCtlg: project, - selectedPlanCtlgSpecsLoaded: false, - selectedPlanCtlgMaxLevel: null, - selectedPlanCtlgLevel: null, - selectedPlanCtlgOutOfLimit: 0, - selectedPlanCtlgSort: null, - selectedPlanCtlgMenuItems: null, - gantt: {}, - showPlanList: false, - selectedTaskDetail: null, - selectedTaskDetailType: null - })); - }; - - //Сброс выбора каталога планов - const unselectPlan = () => - setState(pv => ({ - ...pv, - selectedPlanCtlgSpecsLoaded: false, - selectedPlanCtlg: null, - selectedPlanCtlgMaxLevel: null, - selectedPlanCtlgLevel: null, - selectedPlanCtlgOutOfLimit: 0, - selectedPlanCtlgSort: null, - selectedPlanCtlgMenuItems: null, - gantt: {}, - showPlanList: false, - selectedTaskDetail: null, - selectedTaskDetailType: null - })); - //Загрузка списка спецификаций каталога планов const loadPlanCtglSpecs = useCallback( async (level = null, sort = null) => { const data = await executeStored({ stored: "PKG_P8PANELS_MECHREC.FCPRODPLANSP_GET", - args: { NCRN: state.selectedPlanCtlg, NLEVEL: level, SSORT_FIELD: sort, NFCPRODPLANSP: state.planSpec } + args: { + NCRN: state.selectedPlanCtlg, + CFCPRODPLANS: { + VALUE: state.selectedPlans.length > 0 ? state.selectedPlans.join(";") : null, + SDATA_TYPE: SERV_DATA_TYPE_CLOB + }, + NLEVEL: level, + SSORT_FIELD: sort, + NFCPRODPLANSP: state.planSpec + } }); let doc = await parseProdPlanSpXML(data.COUT); setState(pv => ({ @@ -344,21 +432,71 @@ const MechRecCostProdPlans = () => { selectedPlanCtlgLevel: level || level === 0 ? level : data.NMAX_LEVEL, selectedPlanCtlgOutOfLimit: data.NOUT_OF_LIMIT, selectedPlanCtlgSort: sort, - selectedPlanCtlgMenuItems: state.selectedPlanCtlgMenuItems - ? state.selectedPlanCtlgMenuItems - : [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1), + selectedPlanCtlgMenuItems: [...Array(data.NMAX_LEVEL).keys()].map(el => el + 1), selectedPlanCtlgSpecsLoaded: true, - gantt: { ...doc, tasks: [...(doc?.tasks || [])] } + gantt: { ...doc, tasks: [...(doc?.tasks || [])] }, + loadedCtlg: state.selectedPlanCtlg, + loadedPlans: [...state.selectedPlans], + loadedElements: state.selectedPlansElements, + showPlanList: false })); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [executeStored, state.ident, state.selectedPlanCtlg, state.planSpec] + [executeStored, state.selectedPlanCtlg, state.selectedPlans, state.planSpec] ); //Обработка нажатия на элемент в списке каталогов планов - const handleProjectClick = project => { - if (state.selectedPlanCtlg != project.NRN) selectPlan(project.NRN); - else unselectPlan(); + const handleCtlgClick = project => { + //Если этот каталог не был выбран + if (state.selectedPlanCtlg != project.NRN) { + //Если выбран уже загруженный - укажем информацию о том, как он загружен + if (project.NRN === state.loadedCtlg) { + setState(pv => ({ + ...pv, + selectedPlanCtlg: project.NRN, + selectedPlans: [...pv.loadedPlans], + selectedPlansElements: pv.loadedElements + })); + } else { + setState(pv => ({ + ...pv, + selectedPlanCtlg: project.NRN, + selectedPlans: project.XCRN_PLANS.length === 1 ? [project.XCRN_PLANS[0].NRN] : [], + selectedPlansElements: 0 + })); + } + } else { + setState(pv => ({ ...pv, selectedPlanCtlg: null, selectedPlans: [], selectedPlansElements: 0 })); + } + }; + + //Обработка нажатия на элемент в списке планов каталога + const handleCtlgPlanClick = plan => { + //Считываем обновленную информацию об отмеченных планах + let newPlansInfo = updateCtlgPlanInfo(state.selectedPlans, plan); + //Обновляем список отмеченных планов + setState(pv => ({ + ...pv, + selectedPlans: [...newPlansInfo.selectedPlans], + selectedPlansElements: pv.selectedPlansElements + newPlansInfo.selectedPlansElements + })); + }; + + //Обработка нажатия "ОК" при отборе планов + const handleSelectedPlansOk = () => { + //Загружаем диаграмму + loadPlanCtglSpecs(null, SORT_REP_DATE_TO); + }; + + //Обработка нажатия "Отмена" при отборе планов + const handleSelectedPlansCancel = () => { + setState(pv => ({ + ...pv, + selectedPlanCtlg: pv.loadedCtlg, + selectedPlans: [...pv.loadedPlans] || [], + selectedPlansElements: pv.loadedElements, + showPlanList: false + })); }; //При подключении компонента к странице @@ -371,8 +509,8 @@ const MechRecCostProdPlans = () => { //При смене выбранного каталога плана или при явном указании позиции спецификации плана useEffect(() => { - if (state.selectedPlanCtlg || state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO); - }, [state.selectedPlanCtlg, state.planSpec, loadPlanCtglSpecs]); + if (state.planSpec) loadPlanCtglSpecs(null, SORT_REP_DATE_TO); + }, [state.planSpec, loadPlanCtglSpecs]); //Выбор уровня const handleChangeSelectLevel = selectedLevel => { @@ -415,18 +553,18 @@ const MechRecCostProdPlans = () => { setState(pv => ({ ...pv, showPlanList: !pv.showPlanList }))}> Каталоги планов - setState(pv => ({ ...pv, showPlanList: false }))} - sx={STYLES.PLANS_DRAWER} - > + @@ -508,14 +646,14 @@ const MechRecCostProdPlans = () => { /> ) - ) : !state.selectedPlanCtlg ? ( + ) : !state.loadedCtlg ? ( diff --git a/db/PKG_P8PANELS_MECHREC.pck b/db/PKG_P8PANELS_MECHREC.pck index facfc0c..e352e59 100644 --- a/db/PKG_P8PANELS_MECHREC.pck +++ b/db/PKG_P8PANELS_MECHREC.pck @@ -81,6 +81,7 @@ create or replace package PKG_P8PANELS_MECHREC as procedure FCPRODPLANSP_GET ( NCRN in number, -- Рег. номер каталога + CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";") NFCPRODPLANSP in number, -- Рег. номер позиции спецификации NLEVEL in number := null, -- Уровень отбора SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки @@ -513,6 +514,28 @@ create or replace package body PKG_P8PANELS_MECHREC as end; end UTL_FCROUTLST_GET; + /* Иницализация выбранных планов */ + procedure UTL_FCPRODPLAN_IDENT_INIT + ( + CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";") + NIDENT out number -- Идентификатор отмеченных записей + ) + is + NFCPRODPLAN PKG_STD.TREF; -- Рег. номер плана + NTMP PKG_STD.TREF; -- Буфер + begin + /* Генерируем идентификатор */ + NIDENT := GEN_IDENT(); + /* Обходим исполнителей */ + for I in 1 .. STRCNT(source => CFCPRODPLANS, DELIMETER => ';') + loop + /* Считываем рег. номер плана */ + NFCPRODPLAN := TO_NUMBER(STRTOK(source => CFCPRODPLANS, DELIMETER => ';', ITEM => I)); + /* Добавляем в селектлист */ + P_SELECTLIST_INSERT(NIDENT => NIDENT, NDOCUMENT => NFCPRODPLAN, SUNITCODE => 'CostProductPlans', NRN => NTMP); + end loop; + end UTL_FCPRODPLAN_IDENT_INIT; + /* Считывания рег. номера подразделения пользователя */ function UTL_SUBDIV_RN_GET ( @@ -2259,6 +2282,7 @@ create or replace package body PKG_P8PANELS_MECHREC as procedure FCPRODPLANSP_GET ( NCRN in number, -- Рег. номер каталога + CFCPRODPLANS in clob, -- Список отмеченных планов (разделитель - ";") NFCPRODPLANSP in number, -- Рег. номер позиции спецификации NLEVEL in number := null, -- Уровень отбора SSORT_FIELD in varchar2 := 'DREP_DATE_TO', -- Поле сортировки @@ -2284,6 +2308,7 @@ create or replace package body PKG_P8PANELS_MECHREC as NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса NTASK_CLASS PKG_STD.TNUMBER; -- Класс задачи (см. константы NCLASS_*) NLEVEL_FILTER PKG_STD.TNUMBER; -- Уровень для фильтра + NPLANS_IDENT PKG_STD.TREF; -- Идентификатор отмеченных планов /* Объединение значений в строковое представление */ function MAKE_INFO @@ -2308,6 +2333,7 @@ create or replace package body PKG_P8PANELS_MECHREC as procedure PRODPLAN_MAX_LEVEL_GET ( NCRN in number, -- Рег. номер каталога планов + NPLANS_IDENT in number, -- Идентификатор отмеченных планов NFCPRODPLANSP in number, -- Рег. номер позиции спецификации NMAX_LEVEL out number, -- Максимальный уровень иерархии NOUT_OF_LIMIT out number -- Признак превышения лимита (0 - нет, 1 - да) @@ -2328,6 +2354,12 @@ create or replace package body PKG_P8PANELS_MECHREC as FCPRODPLANSP T, FINSTATE FS where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN))) + and ((NPLANS_IDENT is null) or + ((NPLANS_IDENT is not null) and + (P.RN in (select SL.DOCUMENT + from SELECTLIST SL + where SL.IDENT = NPLANS_IDENT + and SL.UNITCODE = 'CostProductPlans')))) and ((NFCPRODPLANSP is null) or ((NFCPRODPLANSP is not null) and (P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP)))) @@ -2711,12 +2743,18 @@ create or replace package body PKG_P8PANELS_MECHREC as begin /* Определяем заголовок плана */ if (NCRN is not null) then + /* Считываем каталог */ FIND_ACATALOG_RN(NFLAG_SMART => 0, NCOMPANY => NCOMPANY, NVERSION => null, SUNITCODE => 'CostProductPlans', NRN => NCRN, SNAME => SPLAN_TITLE); + /* Если есть выбранные планы */ + if (CFCPRODPLANS is not null) then + /* Инициализируем отмеченные планы в селектлисте */ + UTL_FCPRODPLAN_IDENT_INIT(CFCPRODPLANS => CFCPRODPLANS, NIDENT => NPLANS_IDENT); + end if; else if (NFCPRODPLANSP is not null) then begin @@ -2750,9 +2788,10 @@ create or replace package body PKG_P8PANELS_MECHREC as /* Инициализируем описания цветов */ TASK_COLORS_INIT(RG => RG); /* Определяем максимальный уровень иерархии */ - PRODPLAN_MAX_LEVEL_GET(NCRN => NCRN, - NFCPRODPLANSP => NFCPRODPLANSP, - NMAX_LEVEL => NMAX_LEVEL, + PRODPLAN_MAX_LEVEL_GET(NCRN => NCRN, + NPLANS_IDENT => NPLANS_IDENT, + NFCPRODPLANSP => NFCPRODPLANSP, + NMAX_LEVEL => NMAX_LEVEL, NOUT_OF_LIMIT => NOUT_OF_LIMIT); /* Определяем уровень фильтра */ NLEVEL_FILTER := COALESCE(NLEVEL, NMAX_LEVEL); @@ -2797,6 +2836,12 @@ create or replace package body PKG_P8PANELS_MECHREC as DICNOMNS D, DICMUNTS DM where ((NCRN is null) or ((NCRN is not null) and (P.CRN = NCRN))) + and ((NPLANS_IDENT is null) or + ((NPLANS_IDENT is not null) and + (P.RN in (select SL.DOCUMENT + from SELECTLIST SL + where SL.IDENT = NPLANS_IDENT + and SL.UNITCODE = 'CostProductPlans')))) and ((NFCPRODPLANSP is null) or ((NFCPRODPLANSP is not null) and (P.RN = (select PRN from FCPRODPLANSP where RN = NFCPRODPLANSP)))) @@ -2917,14 +2962,48 @@ create or replace package body PKG_P8PANELS_MECHREC as end loop; /* Формируем список */ COUT := PKG_P8PANELS_VISUAL.TGANTT_TO_XML(RGANTT => RG); + /* Очищаем отмеченные планы */ + P_SELECTLIST_CLEAR(NIDENT => NPLANS_IDENT); + exception + when others then + /* Очищаем отмеченные планы */ + P_SELECTLIST_CLEAR(NIDENT => NPLANS_IDENT); + raise; end FCPRODPLANSP_GET; /* Инициализация каталогов раздела "Планы и отчеты производства изделий" для панели "Производственная программа" */ procedure FCPRODPLAN_PP_CTLG_INIT ( - COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий" + COUT out clob -- Список каталогов раздела "Планы и отчеты производства изделий" ) is + NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса + + /* Считывание количества спецификаций плана */ + function FCPRODPLANSP_COUNT_GET + ( + NFCPRODPLAN in number -- Рег. номер плана + ) return number -- Количество документов спецификации плана + is + NRESULT PKG_STD.TNUMBER; -- Количество документов спецификации плана + begin + /* Считываем количество спецификаций */ + begin + select count(T.RN) + into NRESULT + from FCPRODPLAN P, + FCPRODPLANSP T, + FINSTATE FS + where P.RN = NFCPRODPLAN + and T.PRN = P.RN + and T.MAIN_QUANT > 0; + exception + when others then + NRESULT := 0; + end; + /* Возвращаем результат */ + return NRESULT; + end FCPRODPLANSP_COUNT_GET; begin /* Начинаем формирование XML */ PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_); @@ -2939,7 +3018,7 @@ create or replace package body PKG_P8PANELS_MECHREC as where P.CRN = T.RN and P.CATEGORY = NFCPRODPLAN_CATEGORY and P.STATUS = NFCPRODPLAN_STATUS - and P.COMPANY = GET_SESSION_COMPANY() + and P.COMPANY = NCOMPANY and FS.RN = P.TYPE and FS.CODE = SFCPRODPLAN_TYPE and exists (select PSP.RN @@ -2967,7 +3046,7 @@ create or replace package body PKG_P8PANELS_MECHREC as where T.DOCNAME = 'CostProductPlans' and T.SIGNS = 1 and T.DOCNAME = UL.UNITCODE - and T.COMPANY = GET_SESSION_COMPANY() + and T.COMPANY = NCOMPANY and (UL.SHOW_INACCESS_CTLG = 1 or exists (select null from V_USERPRIV UP where UP.CATALOG = T.RN) or exists (select null @@ -2977,12 +3056,56 @@ create or replace package body PKG_P8PANELS_MECHREC as start with T1.CRN = T.RN)) order by T.NAME asc) loop - /* Открываем план */ + /* Открываем каталог плана */ PKG_XFAST.DOWN_NODE(SNAME => 'XFCPRODPLAN_CRNS'); - /* Описываем план */ + /* Описываем каталог */ PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => REC.NRN); PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => REC.SNAME); PKG_XFAST.ATTR(SNAME => 'NCOUNT_DOCS', NVALUE => REC.NCOUNT_DOCS); + /* Если содержит планы */ + if (REC.NCOUNT_DOCS <> 0) then + /* Цикл по планам каталога */ + for PLN in (select T.RN NRN, + trim(T.PREFIX) || '-' || trim(T.NUMB) SNAME + from FCPRODPLAN T, + FINSTATE FS + where T.CRN = REC.NRN + and T.CATEGORY = NFCPRODPLAN_CATEGORY + and T.STATUS = NFCPRODPLAN_STATUS + and T.COMPANY = NCOMPANY + and FS.RN = T.TYPE + and FS.CODE = SFCPRODPLAN_TYPE + and exists (select PSP.RN + from FCPRODPLANSP PSP + where PSP.PRN = T.RN + and PSP.MAIN_QUANT > 0) + and exists (select /*+ INDEX(UP I_USERPRIV_JUR_PERS_ROLEID) */ + null + from USERPRIV UP + where UP.JUR_PERS = T.JUR_PERS + and UP.UNITCODE = 'CostProductPlans' + and UP.ROLEID in (select /*+ INDEX(UR I_USERROLES_AUTHID_FK) */ + UR.ROLEID + from USERROLES UR + where UR.AUTHID = UTILIZER()) + union all + select /*+ INDEX(UP I_USERPRIV_JUR_PERS_AUTHID) */ + null + from USERPRIV UP + where UP.JUR_PERS = T.JUR_PERS + and UP.UNITCODE = 'CostProductPlans' + and UP.AUTHID = UTILIZER())) + loop + /* Открываем описание документов каталога */ + PKG_XFAST.DOWN_NODE(SNAME => 'XCRN_PLANS'); + /* Описываем план */ + PKG_XFAST.ATTR(SNAME => 'NRN', NVALUE => PLN.NRN); + PKG_XFAST.ATTR(SNAME => 'SNAME', SVALUE => PLN.SNAME); + PKG_XFAST.ATTR(SNAME => 'NCOUNT_DOCS', NVALUE => FCPRODPLANSP_COUNT_GET(NFCPRODPLAN => PLN.NRN)); + /* Закрываем документы каталога */ + PKG_XFAST.UP(); + end loop; + end if; /* Закрываем план */ PKG_XFAST.UP(); end loop;