OAF-компоненты. Attachments
1. Динамическое создание компонента attachmentTable
import oracle.apps.fnd.framework.webui.beans.layout.OAAttachmentTableBean; import oracle.apps.fnd.framework.webui.OAWebBeanConstants; import java.util.Hashtable; import java.util.Dictionary; ... OAAttachmentTableBean attTable = (OAAttachmentTableBean)pageContext.getWebBeanFactory().createWebBean(pageContext, OAWebBeanConstants.ATTACHMENT_TABLE_BEAN, null, null); attTable.setID("xxTestAttachmentId"); attTable.setViewUsageName("ApplicantAssignmentVO"); attTable.setSearchRegionDisplayed(false); attTable.setDocumentCatalogEnabled(true); attTable.setText("Сводка дополнений"); Hashtable<String, Object> entity = new Hashtable<String, Object>(); entity.put("entityId", "PER_ASSIGNMENTS_F"); // entity entity.put("showAll", Boolean.FALSE); entity.put("insertAllowed", Boolean.TRUE); entity.put("deleteAllowed", Boolean.TRUE); entity.put("updateAllowed", Boolean.TRUE); String[] pkAttrNames = new String[1]; pkAttrNames[0] = "AssignmentId"; entity.put("pkColumns", pkAttrNames); Dictionary[] entityMaps = new Dictionary[1]; entityMaps[0] = entity; attTable.setEntityMappings(entityMaps); webBean.addIndexedChild(attTable);
https://community.oracle.com/thread/2249676
https://community.oracle.com/thread/2404025
2. Не появляются всплывающие popup-ы (Inline Attachments)
В некоторых невыясненных ситуациях, при добавлении компонента attachmentTable на стандартную форму динамически или через персонализацию, не работают popup-ы для просмотра/добавления/редактирования/удаления вложений (Inline Attachments). Было обнаружено, как минимум, 2 условия, которые влияют на эту ситуацию (полный список условий выяснить не удалось):
- Страница открывается 1-й раз
- У компонента attachmentTable отключен регион поиска (
searchRegionRendered="false"
)
Для устранения этого неудобства удалось найти workaround. Нужно добавить в контроллер (processRequest) следующий код:
// Тут важен процесс создания компонента, оказывающий положительное влияние на popup-ы, если они не хотят всплывать. // На форме компонент показывать не нужно. OAMessageChoiceBean akAttachmentCategory = (OAMessageChoiceBean)createWebBean(pageContext, "MESSAGE_POPLIST", null, "XxTmp"); akAttachmentCategory.setPickListViewObjectDefinitionName("oracle.apps.fnd.server.FndCategoryNameVO"); akAttachmentCategory.setValue(pageContext, "1");
3. Изменения в модели данных
Если форма работает с вложениями (attachmentLink, attachmentTable), то в модели данных происходят следующие динамические изменения:
- Добавляется дочерний Application Module с именем oracle_apps_fnd_server_OAAttachmentsAM
- В этом AM, для каждого компонента, работающего с вложениями, создается набор ViewObject-ов. Наиболее интересные — VO, связанные с таблицами fnd_documents и fnd_attached_documents. Именуются они по шаблону Attach_<num>_FndDocumentsDomExtensionVO и Attach_<num>_FndAttachedDocumentsDomExtensionVO. Например, Attach_0_FndAttachedDocumentsDomExtensionVO.
Перед проходом по строкам VO, нужно обязательно проверить, что заданы bind-переменные. Это наиболее вероятная ситуация, но попадались случаи, когда для объекта нет привязанных вложений, и bind-переменные в Attach…VO были не установлены. Попытка сделать проход по строкам VO, в такой ситуации, приведет к тому, что SQL-запрос вернет данные из таблиц без фильтра (например, все записи из fnd_attached_documents). Cтраница зависнет, а потом упадет по timeout-у.
Пример кода.
OAApplicationModule am = pageContext.getApplicationModule(webBean); // Опорные имена, по которым ищем AM и VO с вложениями String attachmentsAMName = "oracle_apps_fnd_server_OAAttachmentsAM"; String attachDocsVOFlag = "FndAttachedDocumentsDomExtensionVO"; String docsVOFlag = "FndDocumentsDomExtensionVO"; // Application Module, в котором содержатся ViewObject-ы, имеющие отношения к вложениям (attachemnts) OAApplicationModule amA = (OAApplicationModule)am.findApplicationModule(attachmentsAMName); if (amA != null) { writeDiag(pageContext, "AM = " + amA.getDefFullName()); String[] voNames = amA.getViewObjectNames(); writeDiag(pageContext, "viewobjectNames Length = " + voNames.length); for (int j = 0; j < voNames.length; j++) { // Обрабатываем ViewObject-ы (их может быть несколько - свой для каждого претендентства), в которых находятся данные по fnd_attached_documents if (voNames[j].lastIndexOf(attachDocsVOFlag) > 0) if (voNames[j].lastIndexOf(attachDocsVOFlag) > 0) { String voDName = voNames[j].substring(0, voNames[j].indexOf("_", 8) + 1) + docsVOFlag; // "Attach__" writeDiag(pageContext, " AttachedDocuments ViewObject Name = " + voNames[j]); writeDiag(pageContext, " Documents ViewObject Name = " + voDName); OAViewObject voA = (OAViewObject)amA.findViewObject(voNames[j]); // ОБЯЗАТЕЛЬНО!!! Проверяем, чтобы были заданы bind-переменные. if (voA.getWhereClauseParams().length > 1) { Object[] params = voA.getWhereClauseParams(); for(int p = 0; p < params.length; p++) writeDiag(pageContext, "params[" + p + "] = " + params[p].toString()); for (Row rowA = voA.first(); rowA != null; rowA = voA.next()) { writeDiag(pageContext, "DocumentId = " + rowA.getAttribute("DocumentId")); writeDiag(pageContext, "LastUpdateDate = " + rowA.getAttribute("LastUpdateDate")); writeDiag(pageContext, "newRowState = " + ((ViewRowImpl)rowA).getNewRowState()); } } } } }
OAF-компоненты. AdvancedTable
1. Использование элементов ввода в области tableActions
Для элементов области tableActions, в которые предполагается ввод данных пользователем (например, MessageChoice или MessageTextInput), была замечена особенность: если ViewObject, связанный c AdvancedTable, не инициализирован, тогда нет доступа к новым значениям элементов, введенных на форме. Признаком того, что ViewObject не инициализирован, является надпись в табличной части «Поиск не выполнен». Если ViewObject инициализирован, но в нем нет строк, то надпись будет «Нет результатов поиска». В контроллере этот факт можно проверить с помощью функции VO isPreparedForExecution. Для кнопок таких проблем не возникает — с точки зрения обработки, важен только сам факт нажатия кнопки, который всегда можно отследить и обработать в контроллере.
Если есть необходимость работать с элементами, допускающими ввод данных пользователем в tableActions, то нужно чтобы VO был в инициализированном состоянии. Например, в контроллере processRequest, можно написать следующий код (чтобы состояние «VO НЕ инициализирован, строк нет» перевести в состояние «VO инициализирован, строк нет»)
if (!vo.isPreparedForExecution()) { vo.setWhereClause("1=0"); vo.setWhereClauseParams(null); vo.executeQuery(); vo.setWhereClause(null); }
2. Доступ к элементам, находящимся в tableActions или tableSelection
Для доступа к элементам из областей tableActions или tableSelection, нужно сначала получить саму область, а потом искать элемент внутри нее
OAAdvancedTableBean tableBean = (OAAdvancedTableBean)webBean.findIndexedChildRecursive("invoicesTable"); OARowLayoutBean actionsBean = (OARowLayoutBean)tableBean.getTableActions(); // или OAFlowLayoutBean OAMessageChoiceBean pt = (OAMessageChoiceBean)actionsBean.findIndexedChildRecursive("prepaymentTypesItem"); pt.setValue(pageContext, pageContext.getProfile("XXAP001_INVOICE_PREPAYMENT_DEFAULT"));
3. Связывание свойств с атрибутами VO для элементов внутри Столбца
Для некоторых элементов, являющихся дочерними по отношению к столбцу AdvancedTable, не удалось связать свойства с атрибутами VO. Такая особенность наблюдалась для любого региона (flowLayout, tableLayout и т.п.) и для компонента spacer. Например, свойство Rendered не получилось связать ни с использованием EL, ни через OADataBoundValueViewObject. Для spacer-а можно применить workaround:
- вместо компонента spacer использовать компонент rawText
- в свойстве Text указать HTML-код, который генерится компонентом spacer (задать нужные значения в атрибутах width и height):
<img src="/OA_HTML/cabo/images/skyros/t.gif" width="10" height="10">
- свойство Rendered связать с атрибутом VO
Регулярные выражения. Удаление последней буквы или цифры в строке.
Используем регулярное выражение с REGEXP_LIKE для удаления последней буквы в строке:
with t as ( select 'H18.DHSHJ7' as str from dual union all select 'H18.AAA1A' from dual union all select 'H18.AAA10' from dual union all select 'H18.AAAB4B' from dual ) select t.str, regexp_replace(str, '[[:alpha:]]$','') from t SQL> STR REGEXP_REPLACE(STR,'[[:ALPHA:] ---------- ------------------------------------------------------------------ H18.DHSHJ7 H18.DHSHJ7 H18.AAA1A H18.AAA1 H18.AAA10 H18.AAA10 H18.AAAB4B H18.AAAB4
Для удаления последней цифры заменяем [[:alpha:]] на [[:digit:]]
with t as ( select 'H18.DHSHJ7' as str from dual union all select 'H18.AAA1A' from dual union all select 'H18.AAA10' from dual union all select 'H18.AAAB4B' from dual ) select t.str, regexp_replace(str, '[[:digit:]]$','') from t SQL> STR REGEXP_REPLACE(STR,'[[:DIGIT:] ---------- ------------------------------------------------------------------- H18.DHSHJ7 H18.DHSHJ H18.AAA1A H18.AAA1A H18.AAA10 H18.AAA1 H18.AAAB4B H18.AAAB4B
JSP страница для входа в OEBS с логином и паролем
Весьма полезная JSP страница для авто входа в OEBS с логином и паролем:
http://host:port/OA_HTML/fndvald.jsp?username=!login&password=!pwd
Пример ссылки:
Читать дальше про “JSP страница для входа в OEBS с логином и паролем” »
Ассоциативный массив: цикл по коллекции с ключом varchar2
Пример заполнения ассоциативного массива и цикл для вывода данных.
Ключом является строка varchar2(1):
declare -- объявление типа TYPE resultRec is record ( ready varchar2(1), cnt number ); type resultTab is table of resultRec INDEX BY VARCHAR2(1); -- p_iter varchar2(1); -- итератор p_validation_res_tbl resultTab; -- экземпляр коллекции -- -- запись данных в коллекцию procedure put_result(p_ready varchar2) is begin if (p_validation_res_tbl.exists(p_ready)) then p_validation_res_tbl(p_ready).cnt := p_validation_res_tbl(p_ready).cnt + 1; else p_validation_res_tbl(p_ready).ready := p_ready; p_validation_res_tbl(p_ready).cnt := 1; end if; end; begin -- запись данных в коллекцию через вспомогательную процедуру put_result('E'); put_result('E'); put_result('S'); put_result('W'); -- первичное выставление итератора коллекции p_iter := p_validation_res_tbl.FIRST; -- проверка, на то, что коллекция не пустая if (p_iter is null) then dbms_output.put_line('p_validation_res_tbl is null'); else -- цикл по коллекции WHILE p_iter IS NOT NULL LOOP -- Пример оращения к данным p_validation_res_tbl(p_iter).cnt, где -- p_validation_res_tbl: экземпляр коллекции -- p_iter : текущий итератор -- cnt : поле из record resultRec dbms_output.put_line(p_validation_res_tbl(p_iter).ready ||':' ||p_validation_res_tbl(p_iter).cnt ||' row(s)'); -- получение следующей записи p_iter := p_validation_res_tbl.NEXT(p_iter); END LOOP; end if; end; > E:2 row(s) S:1 row(s) W:1 row(s)
Список полномочий и групп запросов для отчета
Запрос для вывода списка полномочий и групп запросов по коду или имени отчета/параллельной программы:
with params as ( select 'FNDATREP' as short_name ,'' as long_name ,'RU' as lang /* RU;US */ from dual ) select p1.concurrent_program_name ,pt.user_concurrent_program_name ,fa.application_short_name as appl_resp ,r.responsibility_key ,rt.responsibility_name ,fa1.application_short_name as appl_request_group ,g.request_group_name from fnd_request_groups g, fnd_request_group_units u, fnd_application fa, fnd_application fa1, fnd_concurrent_programs_tl pt, fnd_concurrent_programs p1, fnd_responsibility r, fnd_responsibility_tl rt, params where 1=1 and u.application_id = g.application_id and u.request_group_id = g.request_group_id and (u.request_unit_id = pt.concurrent_program_id or u.request_unit_type = 'A') and u.unit_application_id = pt.application_id and pt.application_id = fa.application_id and pt.concurrent_program_id = p1.concurrent_program_id and g.application_id = fa1.application_id and r.request_group_id = g.request_group_id and r.responsibility_id = rt.responsibility_id and rt.language = params.lang and pt.language = params.lang and ( (p1.concurrent_program_name like '%'||params.short_name||'%' and params.short_name is not null ) or (pt.user_concurrent_program_name like '%'||params.long_name||'%' and params.long_name is not null and params.short_name is null ) ) order by 1,2;
Список полномочий где используется форма + путь для вызова
Скрипт для вывода списка полномочий, в которых используется форма.
Так же добавлен путь внутри полномочий для вызова формы.
Желаемый язык для вывода данных вынесен в параметры.
with params as ( select 'FNDSCRSP' as form_name ,'' as user_form_name ,'' as description_form ,'RU' as lang /* RU;US */ from dual ) select (select rt.responsibility_name from fnd_responsibility_tl rt , params where rt.responsibility_id = r.responsibility_id and rt.application_id = r.application_id and rt.language = params.lang ) as responsibility_name ,(select ltrim(sys_connect_by_path(me.prompt, ' --> '),' --> ') from (select b.menu_id,b.entry_sequence,b.sub_menu_id,b.function_id, t.prompt from fnd_menu_entries_tl t, fnd_menu_entries b, params where b.menu_id = t.menu_id and b.entry_sequence = t.entry_sequence and t.language = params.lang) me where me.prompt is not null and me.function_id = ff1.function_id and rownum=1 start with me.menu_id = r.menu_id connect by prior me.sub_menu_id = me.menu_id and prior me.prompt is not null ) path_to_form ,r.application_id ,r.responsibility_id ,r.responsibility_key ,r.menu_id ,(select mt.user_menu_name from fnd_menus_tl mt, params where mt.menu_id = r.menu_id and mt.language = params.lang) as user_menu_name ,ff1.function_id ,(select fft.user_function_name from fnd_form_functions_tl fft, params where fft.function_id = ff1.function_id and fft.language = params.lang) as user_function_name ,ff1.form_id ,(select ff.form_name from fnd_form ff where ff.form_id = ff1.form_id ) as form_name ,(select ftl.user_form_name from fnd_form_tl ftl, params where ftl.form_id = ff1.form_id and ftl.language = params.lang) as user_form_name from fnd_responsibility r ,(select ff.function_id, ff.form_id from fnd_form_functions ff where ff.form_id in (select f.form_id from fnd_form f, fnd_form_tl ft, params where f.form_id = ft.form_id and ( f.form_name = params.form_name or (ft.user_form_name like '%'||params.user_form_name||'%' and params.user_form_name is not null) or (ft.description like '%'||params.description_form||'%' and params.description_form is not null) ) ) ) ff1 where 1=1 and sysdate between r.start_date and nvl(r.end_date, sysdate+1) and r.menu_id in (select me.menu_id from fnd_menu_entries me start with me.function_id = ff1.function_id connect by prior me.menu_id = me.sub_menu_id )
SQL Склонение количества ошибок
Пример SQL запроса для склонения слова «ошибка» для вывода количества ошибок: «Найдена 1 ошибка»; «Найдено 3 ошибки»; «Найдено 5 ошибок» :
select val ,case when mod(val,10) between 2 and 4 then 'Найдено '||val||' ошибки' when val between 11 and 14 or mod(val,10) between 5 and 9 or mod(val,10) = 0 then 'Найдено '||val||' ошибок' when mod(val,10) = 1 then 'Найдена '||val||' ошибка' end str from ( select level val from dual connect by level<=25 ) VAL STR ---------- ------------------------------------------------------- 1 Найдена 1 ошибка 2 Найдено 2 ошибки 3 Найдено 3 ошибки 4 Найдено 4 ошибки 5 Найдено 5 ошибок 6 Найдено 6 ошибок 7 Найдено 7 ошибок 8 Найдено 8 ошибок 9 Найдено 9 ошибок 10 Найдено 10 ошибок 11 Найдено 11 ошибок 12 Найдено 12 ошибки 13 Найдено 13 ошибки 14 Найдено 14 ошибки 15 Найдено 15 ошибок 16 Найдено 16 ошибок 17 Найдено 17 ошибок 18 Найдено 18 ошибок 19 Найдено 19 ошибок 20 Найдено 20 ошибок 21 Найдена 21 ошибка 22 Найдено 22 ошибки 23 Найдено 23 ошибки 24 Найдено 24 ошибки 25 Найдено 25 ошибок 25 rows selected
Riga DevDay 2016
Уважаемые посетители моего блога,
обращаю ваше внимание на ежегодную конференцию для разработчиков Riga DevDay 2016, которая пройдёт со 2 по 4 марта в Риге.
Стоимость, расписание сессий, другие подробности по ссылке
www.rigadevday.lv и www.facebook.com/rigadevday
OEBS API INV: Создание заказа на перемещение
Пример использования API для создания заказа на перемещение
declare lx_doc_hdr inv_move_order_pub.Trohdr_Rec_Type; lx_doc_lines inv_move_order_pub.Trolin_Tbl_Type; -- lx_doc_hdr_vals inv_move_order_pub.Trohdr_Val_Rec_Type; lx_doc_lines_vals inv_move_order_pub.Trolin_Val_Tbl_Type; lx_return_status varchar2(1); lx_msg_data varchar2(4000); lx_msg_count number; begin -- тип заказа на перемещение = заявка lx_doc_hdr.move_order_type := inv_globals.G_MOVE_ORDER_REQUISITION; lx_doc_hdr.organization_id := 1775; lx_doc_hdr.date_required := sysdate; lx_doc_hdr.operation := inv_globals.G_OPR_CREATE; lx_doc_hdr.header_status := inv_globals.G_TO_STATUS_PREAPPROVED; -- создание заголовка заказа на перемещение inv_move_order_pub.create_move_order_header( p_api_version_number => 1, p_init_msg_list => fnd_api.G_TRUE, p_return_values => fnd_api.G_TRUE, p_commit => fnd_api.G_FALSE, x_return_status => lx_return_status, x_msg_count => lx_msg_count, x_msg_data => lx_msg_data, p_trohdr_rec => lx_doc_hdr, p_trohdr_val_rec => lx_doc_hdr_vals, x_trohdr_rec => lx_doc_hdr, x_trohdr_val_rec => lx_doc_hdr_vals ); dbms_output.put_line('create_move_order_header='||lx_return_status); dbms_output.put_line('header_id='||lx_doc_hdr.header_id); if (lx_return_status!='S') then FOR j IN 1 .. lx_msg_count LOOP dbms_output.put_line('error('||j||')= ' ||fnd_msg_pub.get(j,fnd_api.g_false)); END LOOP; else lx_doc_lines(1).header_id := lx_doc_hdr.header_id; lx_doc_lines(1).operation := inv_globals.G_OPR_CREATE; lx_doc_lines(1).line_status := inv_globals.G_TO_STATUS_PREAPPROVED; lx_doc_lines(1).date_required := sysdate; lx_doc_lines(1).status_date := sysdate; -- 64 Перенос заказа на перемещение lx_doc_lines(1).transaction_type_id := inv_globals.g_type_transfer_order_subxfr; -- lx_doc_lines(1).from_subinventory_code := 'ttttttt'; lx_doc_lines(1).organization_id := 1775; lx_doc_lines(1).to_subinventory_code := 'fffffff'; lx_doc_lines(1).to_organization_id := 1775; lx_doc_lines(1).inventory_item_id := 57878; lx_doc_lines(1).uom_code := 'шт'; lx_doc_lines(1).quantity := 5; -- создание строки заказа на перемещение inv_move_order_pub.create_move_order_lines( p_api_version_number => 1, p_init_msg_list => fnd_api.G_TRUE, p_return_values => fnd_api.G_TRUE, p_commit => fnd_api.G_FALSE, x_return_status => lx_return_status, x_msg_count => lx_msg_count, x_msg_data => lx_msg_data, p_trolin_tbl => lx_doc_lines, p_trolin_val_tbl => lx_doc_lines_vals, x_trolin_tbl => lx_doc_lines, x_trolin_val_tbl => lx_doc_lines_vals ); dbms_output.put_line('create_move_order_lines='||lx_return_status); if (lx_return_status!='S') then FOR j IN 1 .. lx_msg_count LOOP dbms_output.put_line('error('||j||')='||fnd_msg_pub.get(j,fnd_api.g_false)); END LOOP; else dbms_output.put_line('line_id='||lx_doc_lines(1).line_id); end if; end if; end;
Последние комментарии